void recipe_dictionary::finalize() { if( !DynamicDataLoader::get_instance().load_deferred( deferred ) ) { debugmsg( "JSON contains circular dependency: discarded %i recipes", deferred.size() ); } finalize_internal( recipe_dict.recipes ); finalize_internal( recipe_dict.uncraft ); for( auto &e : recipe_dict.recipes ) { auto &r = e.second; for( const auto &bk : r.booksets ) { islot_book::recipe_with_description_t desc{ &r, bk.second, item::nname( r.result ), false }; item::find_type( bk.first )->book->recipes.insert( desc ); } if( r.contained && r.container == "null" ) { r.container = item::find_type( r.result )->default_container; } if( r.autolearn ) { r.autolearn_requirements = r.required_skills; if( r.skill_used ) { r.autolearn_requirements[ r.skill_used ] = r.difficulty; } } // add recipe to category and component caches recipe_dict.category[r.category].insert( &r ); for( const auto &opts : r.requirements().get_components() ) { for( const item_comp &comp : opts ) { recipe_dict.component[comp.type].insert( &r ); } } // if reversible and no specific uncraft recipe exists use this recipe if( r.reversible && !recipe_dict.uncraft.count( r.result ) ) { recipe_dict.uncraft[ r.result ] = r; } } // add pseudo uncrafting recipes for( const auto &e : item_controller->get_all_itypes() ) { // books that don't alreay have an uncrafting recipe if( e.second->book && !recipe_dict.uncraft.count( e.first ) && e.second->volume > 0 ) { int pages = e.second->volume / units::from_milliliter( 12.5 ); auto &bk = recipe_dict.uncraft[ e.first ]; bk.ident_ = e.first; bk.result = e.first; bk.reversible = true; bk.requirements_ = *requirement_id( "uncraft_book" ) * pages; bk.time = pages * 10; // @todo allow specifying time in requirement_data } } }
recipe &recipe_dictionary::load( JsonObject &jo, const std::string &src, std::map<std::string, recipe> &dest ) { recipe r; // defer entries dependent upon as-yet unparsed definitions if( jo.has_string( "copy-from" ) ) { auto base = jo.get_string( "copy-from" ); if( !dest.count( base ) ) { deferred.emplace_back( jo.str(), src ); return null_recipe; } r = dest[ base ]; } r.load( jo, src ); dest[ r.ident() ] = std::move( r ); return dest[ r.ident() ]; }
/** * Reads in a vehicle part from a JsonObject. */ void vpart_info::load( JsonObject &jo, const std::string &src ) { vpart_info def; if( jo.has_string( "copy-from" ) ) { auto const base = vpart_info_all.find( vpart_id( jo.get_string( "copy-from" ) ) ); auto const ab = abstract_parts.find( vpart_id( jo.get_string( "copy-from" ) ) ); if( base != vpart_info_all.end() ) { def = base->second; } else if( ab != abstract_parts.end() ) { def = ab->second; } else { deferred.emplace_back( jo.str(), src ); return; } } if( jo.has_string( "abstract" ) ) { def.id = vpart_id( jo.get_string( "abstract" ) ); } else { def.id = vpart_id( jo.get_string( "id" ) ); } assign( jo, "name", def.name_ ); assign( jo, "item", def.item ); assign( jo, "location", def.location ); assign( jo, "durability", def.durability ); assign( jo, "damage_modifier", def.dmg_mod ); assign( jo, "power", def.power ); assign( jo, "epower", def.epower ); assign( jo, "fuel_type", def.fuel_type ); assign( jo, "default_ammo", def.default_ammo ); assign( jo, "folded_volume", def.folded_volume ); assign( jo, "size", def.size ); assign( jo, "difficulty", def.difficulty ); assign( jo, "bonus", def.bonus ); assign( jo, "flags", def.flags ); if( jo.has_member( "requirements" ) ) { auto reqs = jo.get_object( "requirements" ); parse_vp_reqs( reqs, def.id.str(), "install", def.install_reqs, def.install_skills, def.install_moves ); parse_vp_reqs( reqs, def.id.str(), "removal", def.removal_reqs, def.removal_skills, def.removal_moves ); parse_vp_reqs( reqs, def.id.str(), "repair", def.repair_reqs, def.repair_skills, def.repair_moves ); def.legacy = false; } if( jo.has_member( "symbol" ) ) { def.sym = jo.get_string( "symbol" )[ 0 ]; } if( jo.has_member( "broken_symbol" ) ) { def.sym_broken = jo.get_string( "broken_symbol" )[ 0 ]; } if( jo.has_member( "color" ) ) { def.color = color_from_string( jo.get_string( "color" ) ); } if( jo.has_member( "broken_color" ) ) { def.color_broken = color_from_string( jo.get_string( "broken_color" ) ); } if( jo.has_member( "breaks_into" ) ) { JsonIn& stream = *jo.get_raw( "breaks_into" ); def.breaks_into_group = item_group::load_item_group( stream, "collection" ); } auto qual = jo.get_array( "qualities" ); if( !qual.empty() ) { def.qualities.clear(); while( qual.has_more() ) { auto pair = qual.next_array(); def.qualities[ quality_id( pair.get_string( 0 ) ) ] = pair.get_int( 1 ); } } if( jo.has_member( "damage_reduction" ) ) { JsonObject dred = jo.get_object( "damage_reduction" ); def.damage_reduction = load_damage_array( dred ); } else { def.damage_reduction.fill( 0.0f ); } if( jo.has_string( "abstract" ) ) { abstract_parts[def.id] = def; } else { vpart_info_all[def.id] = def; } }
void recipe_dictionary::load( JsonObject &jo, const std::string &src, bool uncraft ) { bool strict = src == "core"; recipe r; // defer entries dependent upon as-yet unparsed definitions if( jo.has_string( "copy-from" ) ) { auto base = jo.get_string( "copy-from" ); if( uncraft ) { if( !recipe_dict.uncraft.count( base ) ) { deferred.emplace_back( jo.str(), src ); return; } r = recipe_dict.uncraft[ base ]; } else { if( !recipe_dict.recipes.count( base ) ) { deferred.emplace_back( jo.str(), src ); return; } r = recipe_dict.recipes[ base ]; } } if( jo.has_string( "abstract" ) ) { r.ident_ = jo.get_string( "abstract" ); r.abstract = true; } else { r.ident_ = r.result = jo.get_string( "result" ); r.abstract = false; } if( !uncraft ) { if( jo.has_string( "id_suffix" ) ) { if( r.abstract ) { jo.throw_error( "abstract recipe cannot specify id_suffix", "id_suffix" ); } r.ident_ += "_" + jo.get_string( "id_suffix" ); } assign( jo, "category", r.category, strict ); assign( jo, "subcategory", r.subcategory, strict ); assign( jo, "reversible", r.reversible, strict ); } else { r.reversible = true; } assign( jo, "time", r.time, strict, 0 ); assign( jo, "difficulty", r.difficulty, strict, 0, MAX_SKILL ); assign( jo, "flags", r.flags ); // automatically set contained if we specify as container assign( jo, "contained", r.contained, strict ); r.contained |= assign( jo, "container", r.container, strict ); if( jo.has_array( "batch_time_factors" ) ) { auto batch = jo.get_array( "batch_time_factors" ); r.batch_rscale = batch.get_int( 0 ) / 100.0; r.batch_rsize = batch.get_int( 1 ); } assign( jo, "charges", r.charges ); assign( jo, "result_mult", r.result_mult ); assign( jo, "skill_used", r.skill_used, strict ); if( jo.has_member( "skills_required" ) ) { auto sk = jo.get_array( "skills_required" ); r.required_skills.clear(); if( sk.empty() ) { // clear all requirements } else if( sk.has_array( 0 ) ) { // multiple requirements while( sk.has_more() ) { auto arr = sk.next_array(); r.required_skills[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 ); } } else { // single requirement r.required_skills[skill_id( sk.get_string( 0 ) )] = sk.get_int( 1 ); } } // simplified autolearn sets requirements equal to required skills at finalization if( jo.has_bool( "autolearn" ) ) { assign( jo, "autolearn", r.autolearn ); } else if( jo.has_array( "autolearn" ) ) { r.autolearn = true; auto sk = jo.get_array( "autolearn" ); while( sk.has_more() ) { auto arr = sk.next_array(); r.autolearn_requirements[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 ); } } if( jo.has_member( "decomp_learn" ) ) { r.learn_by_disassembly.clear(); if( jo.has_int( "decomp_learn" ) ) { if( !r.skill_used ) { jo.throw_error( "decomp_learn specified with no skill_used" ); } assign( jo, "decomp_learn", r.learn_by_disassembly[r.skill_used] ); } else if( jo.has_array( "decomp_learn" ) ) { auto sk = jo.get_array( "decomp_learn" ); while( sk.has_more() ) { auto arr = sk.next_array(); r.learn_by_disassembly[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 ); } } } if( !uncraft && jo.has_member( "byproducts" ) ) { auto bp = jo.get_array( "byproducts" ); r.byproducts.clear(); while( bp.has_more() ) { auto arr = bp.next_array(); r.byproducts[ arr.get_string( 0 ) ] += arr.size() == 2 ? arr.get_int( 1 ) : 1; } } if( jo.has_member( "book_learn" ) ) { auto bk = jo.get_array( "book_learn" ); r.booksets.clear(); while( bk.has_more() ) { auto arr = bk.next_array(); r.booksets.emplace( arr.get_string( 0 ), arr.get_int( 1 ) ); } } // recipes not specifying any external requirements inherit from their parent recipe (if any) if( jo.has_string( "using" ) ) { r.reqs_external = { { requirement_id( jo.get_string( "using" ) ), 1 } }; } else if( jo.has_array( "using" ) ) { auto arr = jo.get_array( "using" ); r.reqs_external.clear(); while( arr.has_more() ) { auto cur = arr.next_array(); r.reqs_external.emplace_back( requirement_id( cur.get_string( 0 ) ), cur.get_int( 1 ) ); } } // inline requirements are always replaced (cannot be inherited) auto req_id = string_format( "inline_%s_%s", uncraft ? "uncraft" : "recipe", r.ident_.c_str() ); requirement_data::load_requirement( jo, req_id ); r.reqs_internal = { { requirement_id( req_id ), 1 } }; if( uncraft ) { recipe_dict.uncraft[ r.ident_ ] = r; } else { recipe_dict.recipes[ r.ident_ ] = r; } }
void vpart_info::finalize() { if( !DynamicDataLoader::get_instance().load_deferred( deferred ) ) { debugmsg( "JSON contains circular dependency: discarded %i vehicle parts", deferred.size() ); } for( auto& e : vpart_info_all ) { // if part name specified ensure it is translated // otherwise the name of the base item will be used if( !e.second.name_.empty() ) { e.second.name_ = _( e.second.name_.c_str() ); } if( e.second.folded_volume > 0 ) { e.second.set_flag( "FOLDABLE" ); } for( const auto& f : e.second.flags ) { auto b = vpart_bitflag_map.find( f ); if( b != vpart_bitflag_map.end() ) { e.second.bitflags.set( b->second ); } } e.second.power = hp_to_watt( e.second.power ); // Calculate and cache z-ordering based off of location // list_order is used when inspecting the vehicle if( e.second.location == "on_roof" ) { e.second.z_order = 9; e.second.list_order = 3; } else if( e.second.location == "on_cargo" ) { e.second.z_order = 8; e.second.list_order = 6; } else if( e.second.location == "center" ) { e.second.z_order = 7; e.second.list_order = 7; } else if( e.second.location == "under" ) { // Have wheels show up over frames e.second.z_order = 6; e.second.list_order = 10; } else if( e.second.location == "structure" ) { e.second.z_order = 5; e.second.list_order = 1; } else if( e.second.location == "engine_block" ) { // Should be hidden by frames e.second.z_order = 4; e.second.list_order = 8 ; } else if( e.second.location == "on_battery_mount" ){ // Should be hidden by frames e.second.z_order = 3; e.second.list_order = 10; } else if( e.second.location == "fuel_source" ) { // Should be hidden by frames e.second.z_order = 3; e.second.list_order = 9; } else if( e.second.location == "roof" ) { // Shouldn't be displayed e.second.z_order = -1; e.second.list_order = 4; } else if( e.second.location == "armor" ) { // Shouldn't be displayed (the color is used, but not the symbol) e.second.z_order = -2; e.second.list_order = 2; } else { // Everything else e.second.z_order = 0; e.second.list_order = 5; } } }