1 #include "itype.h"
2 
3 #include <cstdlib>
4 #include <utility>
5 
6 #include "debug.h"
7 #include "item.h"
8 #include "make_static.h"
9 #include "player.h"
10 #include "recipe.h"
11 #include "ret_val.h"
12 #include "translations.h"
13 
14 struct tripoint;
15 
name() const16 std::string gunmod_location::name() const
17 {
18     // Yes, currently the name is just the translated id.
19     return _( _id );
20 }
21 
name() const22 std::string islot_book::recipe_with_description_t::name() const
23 {
24     if( optional_name ) {
25         return optional_name->translated();
26     } else {
27         return recipe->result_name();
28     }
29 }
30 
31 namespace io
32 {
33 template<>
enum_to_string(condition_type data)34 std::string enum_to_string<condition_type>( condition_type data )
35 {
36     switch( data ) {
37         case condition_type::FLAG:
38             return "FLAG";
39         case condition_type::COMPONENT_ID:
40             return "COMPONENT_ID";
41         case condition_type::num_condition_types:
42             break;
43     }
44     debugmsg( "Invalid condition_type" );
45     abort();
46 }
47 } // namespace io
48 
nname(unsigned int quantity) const49 std::string itype::nname( unsigned int quantity ) const
50 {
51     // Always use singular form for liquids.
52     // (Maybe gases too?  There are no gases at the moment)
53     if( phase == phase_id::LIQUID ) {
54         quantity = 1;
55     }
56     return name.translated( quantity );
57 }
58 
charges_per_volume(const units::volume & vol) const59 int itype::charges_per_volume( const units::volume &vol ) const
60 {
61     if( volume == 0_ml ) {
62         // TODO: items should not have 0 volume at all!
63         return item::INFINITE_CHARGES;
64     }
65     return ( count_by_charges() ? stack_size : 1 ) * vol / volume;
66 }
67 
68 // Members of iuse struct, which is slowly morphing into a class.
has_use() const69 bool itype::has_use() const
70 {
71     return !use_methods.empty();
72 }
73 
has_flag(const flag_id & flag) const74 bool itype::has_flag( const flag_id &flag ) const
75 {
76     return item_tags.count( flag );
77 }
78 
get_flags() const79 const itype::FlagsSetType &itype::get_flags() const
80 {
81     return item_tags;
82 }
83 
can_use(const std::string & iuse_name) const84 bool itype::can_use( const std::string &iuse_name ) const
85 {
86     return get_use( iuse_name ) != nullptr;
87 }
88 
get_use(const std::string & iuse_name) const89 const use_function *itype::get_use( const std::string &iuse_name ) const
90 {
91     const auto iter = use_methods.find( iuse_name );
92     return iter != use_methods.end() ? &iter->second : nullptr;
93 }
94 
tick(player & p,item & it,const tripoint & pos) const95 int itype::tick( player &p, item &it, const tripoint &pos ) const
96 {
97     // Note: can go higher than current charge count
98     // Maybe should move charge decrementing here?
99     int charges_to_use = 0;
100     for( const auto &method : use_methods ) {
101         const int val = method.second.call( p, it, true, pos ).value_or( 0 );
102         if( charges_to_use < 0 || val < 0 ) {
103             charges_to_use = -1;
104         } else {
105             charges_to_use += val;
106         }
107     }
108 
109     return charges_to_use;
110 }
111 
invoke(player & p,item & it,const tripoint & pos) const112 cata::optional<int> itype::invoke( player &p, item &it, const tripoint &pos ) const
113 {
114     if( !has_use() ) {
115         return 0;
116     }
117     return invoke( p, it, pos, use_methods.begin()->first );
118 }
119 
invoke(player & p,item & it,const tripoint & pos,const std::string & iuse_name) const120 cata::optional<int> itype::invoke( player &p, item &it, const tripoint &pos,
121                                    const std::string &iuse_name ) const
122 {
123     const use_function *use = get_use( iuse_name );
124     if( use == nullptr ) {
125         debugmsg( "Tried to invoke %s on a %s, which doesn't have this use_function",
126                   iuse_name, nname( 1 ) );
127         return 0;
128     }
129 
130     p.invalidate_weight_carried_cache();
131     const auto ret = use->can_call( p, it, false, pos );
132 
133     if( !ret.success() ) {
134         p.add_msg_if_player( m_info, ret.str() );
135         return 0;
136     }
137 
138     return use->call( p, it, false, pos );
139 }
140 
name() const141 std::string gun_type_type::name() const
142 {
143     return pgettext( "gun_type_type", name_.c_str() );
144 }
145 
can_have_charges() const146 bool itype::can_have_charges() const
147 {
148     if( count_by_charges() ) {
149         return true;
150     }
151     if( tool && tool->max_charges > 0 ) {
152         return true;
153     }
154     if( gun && gun->clip > 0 ) {
155         return true;
156     }
157     if( has_flag( STATIC( flag_id( "CAN_HAVE_CHARGES" ) ) ) ) {
158         return true;
159     }
160     return false;
161 }
162