1 #include "butchery_requirements.h"
2 
3 #include <cstddef>
4 #include <functional>
5 #include <iterator>
6 #include <set>
7 #include <string>
8 
9 #include "activity_handlers.h"
10 #include "creature.h"
11 #include "debug.h"
12 #include "enum_conversions.h"
13 #include "generic_factory.h"
14 #include "item.h"
15 #include "json.h"
16 #include "requirements.h"
17 
18 namespace
19 {
20 generic_factory<butchery_requirements> butchery_req_factory( "butchery_requirements" );
21 } // namespace
22 
23 template<>
obj() const24 const butchery_requirements &string_id<butchery_requirements>::obj() const
25 {
26     return butchery_req_factory.obj( *this );
27 }
28 
29 template<>
is_valid() const30 bool string_id<butchery_requirements>::is_valid() const
31 {
32     return butchery_req_factory.is_valid( *this );
33 }
34 
load_butchery_req(const JsonObject & jo,const std::string & src)35 void butchery_requirements::load_butchery_req( const JsonObject &jo, const std::string &src )
36 {
37     butchery_req_factory.load( jo, src );
38 }
39 
get_all()40 const std::vector<butchery_requirements> &butchery_requirements::get_all()
41 {
42     return butchery_req_factory.get_all();
43 }
44 
reset_all()45 void butchery_requirements::reset_all()
46 {
47     butchery_req_factory.reset();
48 }
49 
is_valid() const50 bool butchery_requirements::is_valid() const
51 {
52     return butchery_req_factory.is_valid( this->id );
53 }
54 
load(const JsonObject & jo,const std::string &)55 void butchery_requirements::load( const JsonObject &jo, const std::string & )
56 {
57     mandatory( jo, was_loaded, "id", id );
58 
59     for( const JsonMember member : jo.get_object( "requirements" ) ) {
60         float modifier = std::stof( member.name() );
61         requirements.emplace( modifier, std::map<creature_size, std::map<butcher_type, requirement_id>> {} );
62 
63         int critter_size = 1;
64         for( JsonObject butcher_jo : member.get_array() ) {
65             if( critter_size == creature_size::num_sizes ) {
66                 debugmsg( "ERROR: %s has too many creature sizes.  must have exactly %d",
67                           id.c_str(), creature_size::num_sizes - 1 );
68                 break;
69             }
70             requirements[modifier].emplace( static_cast<creature_size>( critter_size ),
71                                             std::map<butcher_type, requirement_id> {} );
72 
73             for( int i_butchery_type = 0; i_butchery_type < static_cast<int>( butcher_type::NUM_TYPES );
74                  i_butchery_type++ ) {
75                 butcher_type converted = static_cast<butcher_type>( i_butchery_type );
76                 requirements[modifier][static_cast<creature_size>( critter_size )][converted] =
77                     requirement_id( butcher_jo.get_string( io::enum_to_string( converted ) ) );
78             }
79 
80             critter_size++;
81         }
82     }
83 }
84 
check_consistency()85 void butchery_requirements::check_consistency()
86 {
87     for( const butchery_requirements &req : get_all() ) {
88         for( const auto &size_req : req.requirements ) {
89             if( size_req.second.size() != static_cast<size_t>( creature_size::num_sizes - 1 ) ) {
90                 debugmsg( "ERROR: %s needs exactly %d entries to cover all creature sizes",
91                           req.id.c_str(), static_cast<int>( creature_size::num_sizes ) - 1 );
92             }
93             for( const auto &butcher_req : size_req.second ) {
94                 if( butcher_req.second.size() != static_cast<size_t>( butcher_type::NUM_TYPES ) ) {
95                     debugmsg( "ERROR: %s needs exactly %d entries to cover all butchery types",
96                               req.id.c_str(), static_cast<int>( butcher_type::NUM_TYPES ) );
97                 }
98             }
99         }
100     }
101 }
102 
get_fastest_requirements(const read_only_visitable & crafting_inv,creature_size size,butcher_type butcher) const103 std::pair<float, requirement_id> butchery_requirements::get_fastest_requirements(
104     const read_only_visitable &crafting_inv, creature_size size, butcher_type butcher ) const
105 {
106     for( const std::pair<const float, std::map<creature_size, std::map<butcher_type, requirement_id>>>
107          &riter : requirements ) {
108         if( riter.second.at( size ).at( butcher )->can_make_with_inventory( crafting_inv,
109                 is_crafting_component ) ) {
110             return std::make_pair( riter.first, riter.second.at( size ).at( butcher ) );
111         }
112     }
113     // we didn't find anything we could "craft", so return the requirement that's the fastest
114     const auto first = requirements.rbegin();
115     return std::make_pair( first->first, first->second.at( size ).at( butcher ) );
116 }
117