static void parse_vp_reqs( JsonObject &obj, const std::string &id, const std::string &key, std::vector<std::pair<requirement_id, int>> &reqs, std::map<skill_id, int> &skills, int &moves ) { if( !obj.has_object( key ) ) { return; } auto src = obj.get_object( key ); auto sk = src.get_array( "skills" ); if( !sk.empty() ) { skills.clear(); } while( sk.has_more() ) { auto cur = sk.next_array(); skills.emplace( skill_id( cur.get_string( 0 ) ), cur.size() >= 2 ? cur.get_int( 1 ) : 1 ); } assign( src, "time", moves ); if( src.has_string( "using" ) ) { reqs = { { requirement_id( src.get_string( "using" ) ), 1 } }; } else if( src.has_array( "using" ) ) { auto arr = src.get_array( "using" ); while( arr.has_more() ) { auto cur = arr.next_array(); reqs.emplace_back( requirement_id( cur.get_string( 0 ) ), cur.get_int( 1 ) ); } } else { const requirement_id req_id( string_format( "inline_%s_%s", key.c_str(), id.c_str() ) ); requirement_data::load_requirement( src, req_id ); reqs = { { req_id, 1 } }; } }
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 recipe::load( JsonObject &jo, const std::string &src ) { bool strict = src == "dda"; abstract = jo.has_string( "abstract" ); if( abstract ) { ident_ = recipe_id( jo.get_string( "abstract" ) ); } else { result_ = jo.get_string( "result" ); ident_ = recipe_id( result_ ); } assign( jo, "time", time, strict, 0 ); assign( jo, "difficulty", difficulty, strict, 0, MAX_SKILL ); assign( jo, "flags", flags ); // automatically set contained if we specify as container assign( jo, "contained", contained, strict ); contained |= assign( jo, "container", container, strict ); if( jo.has_array( "batch_time_factors" ) ) { auto batch = jo.get_array( "batch_time_factors" ); batch_rscale = batch.get_int( 0 ) / 100.0; batch_rsize = batch.get_int( 1 ); } assign( jo, "charges", charges ); assign( jo, "result_mult", result_mult ); assign( jo, "skill_used", skill_used, strict ); if( jo.has_member( "skills_required" ) ) { auto sk = jo.get_array( "skills_required" ); 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(); required_skills[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 ); } } else { // single requirement 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", autolearn ); } else if( jo.has_array( "autolearn" ) ) { autolearn = true; auto sk = jo.get_array( "autolearn" ); while( sk.has_more() ) { auto arr = sk.next_array(); autolearn_requirements[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 ); } } if( jo.has_member( "decomp_learn" ) ) { learn_by_disassembly.clear(); if( jo.has_int( "decomp_learn" ) ) { if( !skill_used ) { jo.throw_error( "decomp_learn specified with no skill_used" ); } assign( jo, "decomp_learn", learn_by_disassembly[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(); learn_by_disassembly[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 ); } } } if( jo.has_member( "book_learn" ) ) { auto bk = jo.get_array( "book_learn" ); booksets.clear(); while( bk.has_more() ) { auto arr = bk.next_array(); booksets.emplace( arr.get_string( 0 ), arr.size() > 1 ? arr.get_int( 1 ) : -1 ); } } // recipes not specifying any external requirements inherit from their parent recipe (if any) if( jo.has_string( "using" ) ) { reqs_external = { { requirement_id( jo.get_string( "using" ) ), 1 } }; } else if( jo.has_array( "using" ) ) { auto arr = jo.get_array( "using" ); reqs_external.clear(); while( arr.has_more() ) { auto cur = arr.next_array(); reqs_external.emplace_back( requirement_id( cur.get_string( 0 ) ), cur.get_int( 1 ) ); } } const std::string type = jo.get_string( "type" ); if( type == "recipe" ) { if( jo.has_string( "id_suffix" ) ) { if( abstract ) { jo.throw_error( "abstract recipe cannot specify id_suffix", "id_suffix" ); } ident_ = recipe_id( ident_.str() + "_" + jo.get_string( "id_suffix" ) ); } assign( jo, "category", category, strict ); assign( jo, "subcategory", subcategory, strict ); assign( jo, "reversible", reversible, strict ); if( jo.has_member( "byproducts" ) ) { auto bp = jo.get_array( "byproducts" ); byproducts.clear(); while( bp.has_more() ) { auto arr = bp.next_array(); byproducts[ arr.get_string( 0 ) ] += arr.size() == 2 ? arr.get_int( 1 ) : 1; } } } else if( type == "uncraft" ) { reversible = true; } else { jo.throw_error( "unknown recipe type", "type" ); } // inline requirements are always replaced (cannot be inherited) const auto req_id = string_format( "inline_%s_%s", type.c_str(), ident_.c_str() ); requirement_data::load_requirement( jo, req_id ); reqs_internal = { { requirement_id( req_id ), 1 } }; }
/** * 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 = vehicle_part_types.find( vpart_str_id( jo.get_string( "copy-from" ) ) ); auto const ab = abstract_parts.find( vpart_str_id( jo.get_string( "copy-from" ) ) ); if( base != vehicle_part_types.end() ) { def = base->second; } else if( ab != abstract_parts.end() ) { def = ab->second; } else { deferred.emplace_back( jo.str(), src ); } } if( jo.has_string( "abstract" ) ) { def.id = vpart_str_id( jo.get_string( "abstract" ) ); } else { def.id = vpart_str_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, "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 ); auto reqs = jo.get_object( "requirements" ); if( reqs.has_object( "install" ) ) { auto ins = reqs.get_object( "install" ); auto sk = ins.get_array( "skills" ); if( !sk.empty() ) { def.install_skills.clear(); } while( sk.has_more() ) { auto cur = sk.next_array(); def.install_skills.emplace( skill_id( cur.get_string( 0 ) ) , cur.size() >= 2 ? cur.get_int( 1 ) : 1 ); } assign( ins, "time", def.install_moves ); if( ins.has_string( "using" ) ) { def.install_reqs = { { requirement_id( ins.get_string( "using" ) ), 1 } }; } else if( ins.has_array( "using" ) ) { auto arr = ins.get_array( "using" ); while( arr.has_more() ) { auto cur = arr.next_array(); def.install_reqs.emplace_back( requirement_id( cur.get_string( 0 ) ), cur.get_int( 1 ) ); } } else { auto req_id = std::string( "inline_vehins_" ) += def.id.str(); requirement_data::load_requirement( ins, req_id ); def.install_reqs = { { requirement_id( req_id ), 1 } }; } def.legacy = false; } if( reqs.has_object( "removal" ) ) { auto rem = reqs.get_object( "removal" ); auto sk = rem.get_array( "skills" ); if( !sk.empty() ) { def.removal_skills.clear(); } while( sk.has_more() ) { auto cur = sk.next_array(); def.removal_skills.emplace( skill_id( cur.get_string( 0 ) ) , cur.size() >= 2 ? cur.get_int( 1 ) : 1 ); } assign( rem, "time", def.removal_moves ); if( rem.has_string( "using" ) ) { def.removal_reqs = { { requirement_id( rem.get_string( "using" ) ), 1 } }; } else if( rem.has_array( "using" ) ) { auto arr = rem.get_array( "using" ); while( arr.has_more() ) { auto cur = arr.next_array(); def.removal_reqs.emplace_back( requirement_id( cur.get_string( 0 ) ), cur.get_int( 1 ) ); } } else { auto req_id = std::string( "inline_vehins_" ) += def.id.str(); requirement_data::load_requirement( rem, req_id ); def.removal_reqs = { { requirement_id( req_id ), 1 } }; } 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; return; } auto const iter = vehicle_part_types.find( def.id ); if( iter != vehicle_part_types.end() ) { // Entry in the map already exists, so the pointer in the vector is already correct // and does not need to be changed, only the int-id needs to be taken from the old entry. def.loadid = iter->second.loadid; iter->second = def; } else { // The entry is new, "generate" a new int-id and link the new entry from the vector. def.loadid = vpart_id( vehicle_part_int_types.size() ); vpart_info &new_entry = vehicle_part_types[ def.id ]; new_entry = def; vehicle_part_int_types.push_back( &new_entry ); } }