void load_mutation_category(JsonObject &jsobj) { mutation_category_trait new_category; std::string id = jsobj.get_string("id"); new_category.id=id; new_category.name =_(jsobj.get_string("name").c_str()); new_category.category =jsobj.get_string("category").c_str(); new_category.mutagen_message = _(jsobj.get_string("mutagen_message", "You drink your mutagen").c_str()); new_category.mutagen_hunger = jsobj.get_int("mutagen_hunger", 10); new_category.mutagen_thirst = jsobj.get_int("mutagen_thirst", 10); new_category.mutagen_pain = jsobj.get_int("mutagen_pain", 2); new_category.mutagen_fatigue = jsobj.get_int("mutagen_fatigue", 5); new_category.mutagen_morale = jsobj.get_int("mutagen_morale", 0); new_category.iv_message = _(jsobj.get_string("iv_message", "You inject yourself").c_str()); new_category.iv_min_mutations = jsobj.get_int("iv_min_mutations", 1); new_category.iv_additional_mutations = jsobj.get_int("iv_additional_mutations", 2); new_category.iv_additional_mutations_chance = jsobj.get_int("iv_additional_mutations_chance", 3); new_category.iv_hunger = jsobj.get_int("iv_hunger", 10); new_category.iv_thirst = jsobj.get_int("iv_thirst", 10); new_category.iv_pain = jsobj.get_int("iv_pain", 2); new_category.iv_fatigue = jsobj.get_int("iv_fatigue", 5); new_category.iv_morale = jsobj.get_int("iv_morale", 0); new_category.iv_morale_max = jsobj.get_int("iv_morale_max", 0); new_category.iv_sound = jsobj.get_bool("iv_sound", false); new_category.iv_sound_message = _(jsobj.get_string("iv_sound_message", "You inject yoursel-arRGH!").c_str()); new_category.iv_noise = jsobj.get_int("iv_noise", 0); new_category.iv_sleep = jsobj.get_bool("iv_sleep", false); new_category.iv_sleep_message =_(jsobj.get_string("iv_sleep_message", "Fell asleep").c_str()); new_category.iv_sleep_dur = jsobj.get_int("iv_sleep_dur", 0); new_category.memorial_message = _(jsobj.get_string("memorial_message", "Crossed a threshold").c_str()); new_category.junkie_message = _(jsobj.get_string("junkie_message", "Oh, yeah! That's the stuff!").c_str()); mutation_category_traits[id] = new_category; }
void MonsterGroupManager::LoadMonsterGroup(JsonObject &jo) { MonsterGroup g; g.name = mongroup_id( jo.get_string("name") ); g.defaultMonster = mtype_id( jo.get_string("default") ); if (jo.has_array("monsters")) { JsonArray monarr = jo.get_array("monsters"); while (monarr.has_more()) { JsonObject mon = monarr.next_object(); const mtype_id name = mtype_id( mon.get_string("monster") ); int freq = mon.get_int("freq"); int cost = mon.get_int("cost_multiplier"); int pack_min = 1; int pack_max = 1; if(mon.has_member("pack_size")) { JsonArray packarr = mon.get_array("pack_size"); pack_min = packarr.next_int(); pack_max = packarr.next_int(); } int starts = 0; int ends = 0; if(mon.has_member("starts")) { if (ACTIVE_WORLD_OPTIONS["MONSTER_UPGRADE_FACTOR"] > 0) { starts = mon.get_int("starts") * ACTIVE_WORLD_OPTIONS["MONSTER_UPGRADE_FACTOR"]; } else { // Default value if the monster upgrade factor is set to 0.0 - off starts = mon.get_int("starts"); } } if(mon.has_member("ends")) { if (ACTIVE_WORLD_OPTIONS["MONSTER_UPGRADE_FACTOR"] > 0) { ends = mon.get_int("ends") * ACTIVE_WORLD_OPTIONS["MONSTER_UPGRADE_FACTOR"]; } else { // Default value if the monster upgrade factor is set to 0.0 - off ends = mon.get_int("ends"); } } MonsterGroupEntry new_mon_group = MonsterGroupEntry(name, freq, cost, pack_min, pack_max, starts, ends); if(mon.has_member("conditions")) { JsonArray conditions_arr = mon.get_array("conditions"); while(conditions_arr.has_more()) { new_mon_group.conditions.push_back(conditions_arr.next_string()); } } g.monsters.push_back(new_mon_group); } } g.replace_monster_group = jo.get_bool("replace_monster_group", false); g.new_monster_group = mongroup_id( jo.get_string("new_monster_group_id", mongroup_id::NULL_ID.str() ) ); g.monster_group_time = jo.get_int("replacement_time", 0); g.is_safe = jo.get_bool( "is_safe", false ); monsterGroupMap[g.name] = g; }
mon_effect_data load_mon_effect_data( JsonObject &e ) { return mon_effect_data( efftype_id( e.get_string( "id" ) ), e.get_int( "duration", 0 ), e.get_bool( "affect_hit_bp", false ), get_body_part_token( e.get_string( "bp", "NUM_BP" ) ), e.get_bool( "permanent", false ), e.get_int( "chance", 100 ) ); }
void load_technique(JsonObject &jo) { ma_technique tec; tec.id = jo.get_string("id"); tec.name = jo.get_string("name", ""); if (!tec.name.empty()) { tec.name = _(tec.name.c_str()); } JsonArray jsarr = jo.get_array("messages"); while (jsarr.has_more()) { tec.messages.push_back(_(jsarr.next_string().c_str())); } tec.reqs.unarmed_allowed = jo.get_bool("unarmed_allowed", false); tec.reqs.melee_allowed = jo.get_bool("melee_allowed", false); tec.reqs.min_melee = jo.get_int("min_melee", 0); tec.reqs.min_unarmed = jo.get_int("min_unarmed", 0); tec.reqs.min_bashing = jo.get_int("min_bashing", 0); tec.reqs.min_cutting = jo.get_int("min_cutting", 0); tec.reqs.min_stabbing = jo.get_int("min_stabbing", 0); tec.reqs.min_bashing_damage = jo.get_int("min_bashing_damage", 0); tec.reqs.min_cutting_damage = jo.get_int("min_cutting_damage", 0); tec.reqs.req_buffs = jo.get_tags("req_buffs"); tec.reqs.req_flags = jo.get_tags("req_flags"); tec.crit_tec = jo.get_bool("crit_tec", false); tec.defensive = jo.get_bool("defensive", false); tec.disarms = jo.get_bool("disarms", false); tec.dodge_counter = jo.get_bool("dodge_counter", false); tec.block_counter = jo.get_bool("block_counter", false); tec.miss_recovery = jo.get_bool("miss_recovery", false); tec.grab_break = jo.get_bool("grab_break", false); tec.flaming = jo.get_bool("flaming", false); tec.hit = jo.get_int("pain", 0); tec.bash = jo.get_int("bash", 0); tec.cut = jo.get_int("cut", 0); tec.pain = jo.get_int("pain", 0); tec.weighting = jo.get_int("weighting", 1); tec.bash_mult = jo.get_float("bash_mult", 1.0); tec.cut_mult = jo.get_float("cut_mult", 1.0); tec.speed_mult = jo.get_float("speed_mult", 1.0); tec.down_dur = jo.get_int("down_dur", 0); tec.stun_dur = jo.get_int("stun_dur", 0); tec.knockback_dist = jo.get_int("knockback_dist", 0); tec.knockback_spread = jo.get_int("knockback_spread", 0); tec.aoe = jo.get_string("aoe", ""); tec.flags = jo.get_tags("flags"); ma_techniques[tec.id] = tec; }
void mutation_branch::load( JsonObject &jsobj ) { const std::string id = jsobj.get_string( "id" ); mutation_branch &new_mut = mutation_data[id]; JsonArray jsarr; new_mut.name = _(jsobj.get_string("name").c_str()); new_mut.description = _(jsobj.get_string("description").c_str()); new_mut.points = jsobj.get_int("points"); new_mut.visibility = jsobj.get_int("visibility", 0); new_mut.ugliness = jsobj.get_int("ugliness", 0); new_mut.startingtrait = jsobj.get_bool("starting_trait", false); new_mut.mixed_effect = jsobj.get_bool("mixed_effect", false); new_mut.activated = jsobj.get_bool("active", false); new_mut.cost = jsobj.get_int("cost", 0); new_mut.cooldown = jsobj.get_int("time",0); new_mut.hunger = jsobj.get_bool("hunger",false); new_mut.thirst = jsobj.get_bool("thirst",false); new_mut.fatigue = jsobj.get_bool("fatigue",false); new_mut.valid = jsobj.get_bool("valid", true); new_mut.purifiable = jsobj.get_bool("purifiable", true); new_mut.initial_ma_styles = jsobj.get_string_array( "initial_ma_styles" ); new_mut.threshold = jsobj.get_bool("threshold", false); new_mut.profession = jsobj.get_bool("profession", false); load_mutation_mods(jsobj, "passive_mods", new_mut.mods); /* Not currently supported due to inability to save active mutation state load_mutation_mods(jsobj, "active_mods", new_mut.mods); */ new_mut.prereqs = jsobj.get_string_array( "prereqs" ); // Helps to be able to have a trait require more than one other trait // (Individual prereq-lists are "OR", not "AND".) // Traits shoud NOT appear in both lists for a given mutation, unless // you want that trait to satisfy both requirements. // These are additional to the first list. new_mut.prereqs2 = jsobj.get_string_array( "prereqs2" ); // Dedicated-purpose prereq slot for Threshold mutations // Stuff like Huge might fit in more than one mutcat post-threshold, so yeah new_mut.threshreq = jsobj.get_string_array( "threshreq" ); new_mut.cancels = jsobj.get_string_array( "cancels" ); new_mut.replacements = jsobj.get_string_array( "changes_to" ); new_mut.additions = jsobj.get_string_array( "leads_to" ); jsarr = jsobj.get_array("category"); while (jsarr.has_more()) { std::string s = jsarr.next_string(); new_mut.category.push_back(s); mutations_category[s].push_back(id); } jsarr = jsobj.get_array("wet_protection"); while (jsarr.has_more()) { JsonObject jo = jsarr.next_object(); std::string part_id = jo.get_string("part"); int ignored = jo.get_int("ignored", 0); int neutral = jo.get_int("neutral", 0); int good = jo.get_int("good", 0); tripoint protect = tripoint(ignored, neutral, good); new_mut.protection[part_id] = mutation_wet(body_parts[part_id], protect); } }
bool map_bash_info::load(JsonObject &jsobj, std::string member, bool isfurniture) { if( !jsobj.has_object(member) ) { return false; } JsonObject j = jsobj.get_object(member); str_min = j.get_int("str_min", 0); str_max = j.get_int("str_max", 0); str_min_blocked = j.get_int("str_min_blocked", -1); str_max_blocked = j.get_int("str_max_blocked", -1); str_min_supported = j.get_int("str_min_supported", -1); str_max_supported = j.get_int("str_max_supported", -1); str_min_roll = j.get_int("str_min_roll", str_min); str_max_roll = j.get_int("str_min_roll", str_max); explosive = j.get_int("explosive", -1); sound_vol = j.get_int("sound_vol", -1); sound_fail_vol = j.get_int("sound_fail_vol", -1); collapse_radius = j.get_int( "collapse_radius", 1 ); destroy_only = j.get_bool("destroy_only", false); bash_below = j.get_bool("bash_below", false); sound = j.get_string("sound", _("smash!")); sound_fail = j.get_string("sound_fail", _("thump!")); if( isfurniture ) { furn_set = j.get_string("furn_set", "f_null"); } else { ter_set = j.get_string( "ter_set" ); } if( j.has_member( "items" ) ) { JsonIn& stream = *j.get_raw( "items" ); drop_group = item_group::load_item_group( stream, "collection" ); } else { drop_group = "EMPTY_GROUP"; } if( j.has_array("tent_centers") ) { load_map_bash_tent_centers( j.get_array("tent_centers"), tent_centers ); } return true; }
void auto_pickup::deserialize(JsonIn &jsin) { vRules[(bChar) ? CHARACTER : GLOBAL].clear(); jsin.start_array(); while (!jsin.end_array()) { JsonObject jo = jsin.get_object(); const std::string sRule = jo.get_string("rule"); const bool bActive = jo.get_bool("active"); const bool bExclude = jo.get_bool("exclude"); vRules[(bChar) ? CHARACTER : GLOBAL].push_back(cRules(sRule, bActive, bExclude)); } }
void trap::load( JsonObject &jo ) { std::unique_ptr<trap> trap_ptr( new trap() ); trap &t = *trap_ptr; if( jo.has_member( "drops" ) ) { JsonArray drops_list = jo.get_array( "drops" ); while( drops_list.has_more() ) { t.components.push_back( drops_list.next_string() ); } } t.name = jo.get_string( "name" ); if( !t.name.empty() ) { t.name = _( t.name.c_str() ); } t.id = trap_str_id( jo.get_string( "id" ) ); t.loadid = trap_id( traplist.size() ); t.color = color_from_string( jo.get_string( "color" ) ); t.sym = jo.get_string( "symbol" ).at( 0 ); t.visibility = jo.get_int( "visibility" ); t.avoidance = jo.get_int( "avoidance" ); t.difficulty = jo.get_int( "difficulty" ); t.act = trap_function_from_string( jo.get_string( "action" ) ); t.benign = jo.get_bool( "benign", false ); t.funnel_radius_mm = jo.get_int( "funnel_radius", 0 ); t.trigger_weight = jo.get_int( "trigger_weight", -1 ); trapmap[t.id] = t.loadid; traplist.push_back( &t ); trap_ptr.release(); if( t.is_funnel() ) { funnel_traps.push_back( &t ); } }
void game::load_trap(JsonObject &jo) { std::vector<std::string> drops; if(jo.has_member("drops")) { JsonArray drops_list = jo.get_array("drops"); while(drops_list.has_more()) { drops.push_back(drops_list.next_string()); } } trap *new_trap = new trap( jo.get_string("id"), // "tr_beartrap" g->traps.size(), // tr_beartrap jo.get_string("name"), // "bear trap" color_from_string(jo.get_string("color")), jo.get_string("symbol").at(0), jo.get_int("visibility"), jo.get_int("avoidance"), jo.get_int("difficulty"), trap_function_from_string(jo.get_string("player_action")), trap_function_mon_from_string(jo.get_string("monster_action")), drops ); new_trap->benign = jo.get_bool("benign", false); new_trap->funnel_radius_mm = jo.get_int("funnel_radius", 0); trapmap[new_trap->id] = new_trap->loadid; traps.push_back(new_trap); }
void it_artifact_armor::deserialize(JsonObject &jo) { id = jo.get_string("id"); name = jo.get_string("name"); description = jo.get_string("description"); sym = jo.get_int("sym"); color = int_to_color(jo.get_int("color")); price = jo.get_int("price"); m1 = jo.get_string("m1"); m2 = jo.get_string("m2"); volume = jo.get_int("volume"); weight = jo.get_int("weight"); melee_dam = jo.get_int("melee_dam"); melee_cut = jo.get_int("melee_cut"); m_to_hit = jo.get_int("m_to_hit"); item_tags = jo.get_tags("item_flags"); covers = jo.get_int("covers"); encumber = jo.get_int("encumber"); coverage = jo.get_int("coverage"); thickness = jo.get_int("material_thickness"); env_resist = jo.get_int("env_resist"); warmth = jo.get_int("warmth"); storage = jo.get_int("storage"); power_armor = jo.get_bool("power_armor"); JsonArray ja = jo.get_array("effects_worn"); while (ja.has_more()) { effects_worn.push_back((art_effect_passive)ja.next_int()); } }
void load_trap(JsonObject &jo) { std::vector<std::string> drops; if(jo.has_member("drops")) { JsonArray drops_list = jo.get_array("drops"); while(drops_list.has_more()) { drops.push_back(drops_list.next_string()); } } std::string name = jo.get_string("name"); if (!name.empty()) { name = _(name.c_str()); } trap *new_trap = new trap( jo.get_string("id"), // "tr_beartrap" traplist.size(), // tr_beartrap name, // "bear trap" color_from_string(jo.get_string("color")), jo.get_string("symbol").at(0), jo.get_int("visibility"), jo.get_int("avoidance"), jo.get_int("difficulty"), trap_function_from_string(jo.get_string("action")), drops ); new_trap->benign = jo.get_bool("benign", false); new_trap->funnel_radius_mm = jo.get_int("funnel_radius", 0); new_trap->trigger_weight = jo.get_int("trigger_weight", -1); trapmap[new_trap->id] = new_trap->loadid; traplist.push_back(new_trap); }
// Load an item group from JSON void Item_factory::load_item_group(JsonObject &jsobj) { Item_tag group_id = jsobj.get_string("id"); Item_group *current_group; if (m_template_groups.count(group_id) > 0) { current_group = m_template_groups[group_id]; } else { current_group = new Item_group(group_id); m_template_groups[group_id] = current_group; } current_group->m_guns_have_ammo = jsobj.get_bool("guns_have_ammo", current_group->m_guns_have_ammo); JsonArray items = jsobj.get_array("items"); while (items.has_more()) { JsonArray pair = items.next_array(); current_group->add_entry(pair.get_string(0), pair.get_int(1)); } JsonArray groups = jsobj.get_array("groups"); while (groups.has_more()) { JsonArray pair = groups.next_array(); std::string name = pair.get_string(0); int frequency = pair.get_int(1); if (m_template_groups.count(name) == 0) { m_template_groups[name] = new Item_group(name); } current_group->add_group(m_template_groups[name], frequency); } }
bool map_bash_info::load(JsonObject &jsobj, std::string member, bool isfurniture) { if( jsobj.has_object(member) ) { JsonObject j = jsobj.get_object(member); str_min = j.get_int("str_min", 0); str_max = j.get_int("str_max", 0); str_min_blocked = j.get_int("str_min_blocked", -1); str_max_blocked = j.get_int("str_max_blocked", -1); str_min_roll = j.get_int("str_min_roll", str_min); str_max_roll = j.get_int("str_min_roll", str_max); explosive = j.get_int("explosive", -1); destroy_only = j.get_bool("destroy_only", false); sound = j.get_string("sound", _("smash!")); sound_fail = j.get_string("sound_fail", _("thump!")); if (isfurniture) { furn_set = j.get_string("furn_set", "f_null"); } else { ter_set = j.get_string("ter_set"); } if ( j.has_array("items") ) { load_map_bash_item_drop_list(j.get_array("items"), items); } return true; } else { return false; } }
void gun_actor::load( JsonObject &obj ) { // Mandatory gun_type = obj.get_string( "gun_type" ); ammo_type = obj.get_string( "ammo_type" ); JsonArray jarr = obj.get_array( "fake_skills" ); while( jarr.has_more() ) { JsonArray cur = jarr.next_array(); fake_skills[skill_id( cur.get_string( 0 ) )] = cur.get_int( 1 ); } range = obj.get_float( "range" ); description = obj.get_string( "description" ); move_cost = obj.get_int( "move_cost" ); targeting_cost = obj.get_int( "targeting_cost" ); // Optional: max_ammo = obj.get_int( "max_ammo", INT_MAX ); fake_str = obj.get_int( "fake_str", 8 ); fake_dex = obj.get_int( "fake_dex", 8 ); fake_int = obj.get_int( "fake_int", 8 ); fake_per = obj.get_int( "fake_per", 8 ); require_targeting_player = obj.get_bool( "require_targeting_player", true ); require_targeting_npc = obj.get_bool( "require_targeting_npc", false ); require_targeting_monster = obj.get_bool( "require_targeting_monster", false ); targeting_timeout = obj.get_int( "targeting_timeout", 8 ); targeting_timeout_extend = obj.get_int( "targeting_timeout_extend", 3 ); burst_limit = obj.get_int( "burst_limit", INT_MAX ); laser_lock = obj.get_bool( "laser_lock", false ); range_no_burst = obj.get_float( "range_no_burst", range + 1 ); if( obj.has_member( "targeting_sound" ) || obj.has_member( "targeting_volume" ) ) { // Both or neither, but not just one targeting_sound = obj.get_string( "targeting_sound" ); targeting_volume = obj.get_int( "targeting_volume" ); } // Sound of no ammo no_ammo_sound = obj.get_string( "no_ammo_sound", "" ); }
void mutation_category_trait::load( JsonObject &jsobj ) { mutation_category_trait new_category; new_category.id = jsobj.get_string( "id" ); new_category.raw_name = jsobj.get_string( "name" ); new_category.threshold_mut = trait_id( jsobj.get_string( "threshold_mut" ) ); new_category.raw_mutagen_message = jsobj.get_string( "mutagen_message" ); new_category.mutagen_hunger = jsobj.get_int( "mutagen_hunger", 10 ); new_category.mutagen_thirst = jsobj.get_int( "mutagen_thirst", 10 ); new_category.mutagen_pain = jsobj.get_int( "mutagen_pain", 2 ); new_category.mutagen_fatigue = jsobj.get_int( "mutagen_fatigue", 5 ); new_category.mutagen_morale = jsobj.get_int( "mutagen_morale", 0 ); new_category.raw_iv_message = jsobj.get_string( "iv_message" ); new_category.iv_min_mutations = jsobj.get_int( "iv_min_mutations", 1 ); new_category.iv_additional_mutations = jsobj.get_int( "iv_additional_mutations", 2 ); new_category.iv_additional_mutations_chance = jsobj.get_int( "iv_additional_mutations_chance", 3 ); new_category.iv_hunger = jsobj.get_int( "iv_hunger", 10 ); new_category.iv_thirst = jsobj.get_int( "iv_thirst", 10 ); new_category.iv_pain = jsobj.get_int( "iv_pain", 2 ); new_category.iv_fatigue = jsobj.get_int( "iv_fatigue", 5 ); new_category.iv_morale = jsobj.get_int( "iv_morale", 0 ); new_category.iv_morale_max = jsobj.get_int( "iv_morale_max", 0 ); new_category.iv_sound = jsobj.get_bool( "iv_sound", false ); new_category.raw_iv_sound_message = jsobj.get_string( "iv_sound_message", translate_marker( "You inject yoursel-arRGH!" ) ); new_category.raw_iv_sound_id = jsobj.get_string( "iv_sound_id", "shout" ); new_category.raw_iv_sound_variant = jsobj.get_string( "iv_sound_variant", "default" ); new_category.iv_noise = jsobj.get_int( "iv_noise", 0 ); new_category.iv_sleep = jsobj.get_bool( "iv_sleep", false ); new_category.raw_iv_sleep_message = jsobj.get_string( "iv_sleep_message", translate_marker( "You fall asleep." ) ); new_category.iv_sleep_dur = jsobj.get_int( "iv_sleep_dur", 0 ); static_cast<void>( translate_marker_context( "memorial_male", "Crossed a threshold" ) ); static_cast<void>( translate_marker_context( "memorial_female", "Crossed a threshold" ) ); new_category.raw_memorial_message = jsobj.get_string( "memorial_message", "Crossed a threshold" ); new_category.raw_junkie_message = jsobj.get_string( "junkie_message", translate_marker( "Oh, yeah! That's the stuff!" ) ); mutation_category_traits[new_category.id] = new_category; }
void safemode::deserialize( JsonIn &jsin ) { auto &temp_rules = ( is_character ) ? character_rules : global_rules; temp_rules.clear(); jsin.start_array(); while( !jsin.end_array() ) { JsonObject jo = jsin.get_object(); const std::string rule = jo.get_string( "rule" ); const bool active = jo.get_bool( "active" ); const bool whitelist = jo.get_bool( "whitelist" ); const Creature::Attitude attitude = ( Creature::Attitude ) jo.get_int( "attitude" ); const int proximity = jo.get_int( "proximity" ); temp_rules.push_back( rules_class( rule, active, whitelist, attitude, proximity ) ); } }
void leap_actor::load( JsonObject &obj ) { // Mandatory: max_range = obj.get_float( "max_range" ); // Optional: min_range = obj.get_float( "min_range", 1.0f ); allow_no_target = obj.get_bool( "allow_no_target", true ); move_cost = obj.get_int( "move_cost", 150 ); min_consider_range = obj.get_float( "min_consider_range", 0.0f ); max_consider_range = obj.get_float( "max_consider_range", 200.0f ); }
void it_artifact_armor::deserialize(JsonObject &jo) { id = jo.get_string("id"); name = jo.get_string("name"); description = jo.get_string("description"); sym = jo.get_int("sym"); color = int_to_color(jo.get_int("color")); price = jo.get_int("price"); // LEGACY: Since it seems artifacts get serialized out to disk, and they're // dynamic, we need to allow for them to be read from disk for, oh, I guess // quite some time. Loading and saving once will write things out as a JSON // array. if (jo.has_string("m1")) { materials.push_back(jo.get_string("m1")); } if (jo.has_string("m2")) { materials.push_back(jo.get_string("m2")); } // Assumption, perhaps dangerous, that we won't wind up with m1 and m2 and // a materials array in our serialized objects at the same time. if (jo.has_array("materials")) { JsonArray jarr = jo.get_array("materials"); for (int i = 0; i < jarr.size(); ++i) { materials.push_back(jarr.get_string(i)); } } if (materials.size() == 0) { // I don't think we need this, but a lot of code seems to want at least // one material and I'm not sure I found every single corner case. materials.push_back("null"); } volume = jo.get_int("volume"); weight = jo.get_int("weight"); melee_dam = jo.get_int("melee_dam"); melee_cut = jo.get_int("melee_cut"); m_to_hit = jo.get_int("m_to_hit"); item_tags = jo.get_tags("item_flags"); jo.read( "covers", covers); encumber = jo.get_int("encumber"); coverage = jo.get_int("coverage"); thickness = jo.get_int("material_thickness"); env_resist = jo.get_int("env_resist"); warmth = jo.get_int("warmth"); storage = jo.get_int("storage"); power_armor = jo.get_bool("power_armor"); JsonArray ja = jo.get_array("effects_worn"); while (ja.has_more()) { effects_worn.push_back((art_effect_passive)ja.next_int()); } }
void load_bionic(JsonObject &jsobj) { std::string id = jsobj.get_string("id"); std::string name = _(jsobj.get_string("name").c_str()); std::string description = _(jsobj.get_string("description").c_str()); int cost = jsobj.get_int("cost", 0); int time = jsobj.get_int("time", 0); bool faulty = jsobj.get_bool("faulty", false); bool power_source = jsobj.get_bool("power_source", false); bool active = jsobj.get_bool("active", false); if (faulty) { faulty_bionics.push_back(id); } if (power_source) { power_source_bionics.push_back(id); } if (!active) { unpowered_bionics.push_back(id); } bionics[id] = new bionic_data(name, power_source, active, cost, time, description, faulty); }
void MonsterGroupManager::LoadMonsterGroup(JsonObject &jo) { MonsterGroup g; g.name = jo.get_string("name"); g.defaultMonster = jo.get_string("default"); if (jo.has_array("monsters")) { JsonArray monarr = jo.get_array("monsters"); while (monarr.has_more()) { JsonObject mon = monarr.next_object(); std::string name = mon.get_string("monster"); int freq = mon.get_int("freq"); int cost = mon.get_int("cost_multiplier"); int pack_min = 1; int pack_max = 1; if(mon.has_member("pack_size")) { JsonArray packarr = mon.get_array("pack_size"); pack_min = packarr.next_int(); pack_max = packarr.next_int(); } int starts = 0; int ends = 0; if(mon.has_member("starts")) { starts = mon.get_int("starts") * ACTIVE_WORLD_OPTIONS["MONSTER_GROUP_DIFFICULTY"]; } if(mon.has_member("ends")) { ends = mon.get_int("ends") * ACTIVE_WORLD_OPTIONS["MONSTER_GROUP_DIFFICULTY"]; } MonsterGroupEntry new_mon_group = MonsterGroupEntry(name, freq, cost, pack_min, pack_max, starts, ends); if(mon.has_member("conditions")) { JsonArray conditions_arr = mon.get_array("conditions"); while(conditions_arr.has_more()) { new_mon_group.conditions.push_back(conditions_arr.next_string()); } } g.monsters.push_back(new_mon_group); } } g.replace_monster_group = jo.get_bool("replace_monster_group", false); g.new_monster_group = jo.get_string("new_monster_group_id", "NULL"); g.monster_group_time = jo.get_int("replacement_time", 0); monsterGroupMap[g.name] = g; }
void Item_factory::load_armor(JsonObject& jo) { it_armor* armor_template = new it_armor(); armor_template->encumber = jo.get_int("encumbrance"); armor_template->coverage = jo.get_int("coverage"); armor_template->thickness = jo.get_int("material_thickness"); armor_template->env_resist = jo.get_int("enviromental_protection"); armor_template->warmth = jo.get_int("warmth"); armor_template->storage = jo.get_int("storage"); armor_template->power_armor = jo.get_bool("power_armor", false); armor_template->covers = jo.has_member("covers") ? flags_from_json(jo, "covers", "bodyparts") : 0; itype *new_item_template = armor_template; load_basic_info(jo, new_item_template); }
void faction::load_faction(JsonObject &jsobj) { faction fac; fac.id = jsobj.get_string("id"); fac.name = jsobj.get_string("name"); fac.likes_u = jsobj.get_int("likes_u"); fac.respects_u = jsobj.get_int("respects_u"); fac.known_by_u = jsobj.get_bool("known_by_u"); fac.size = jsobj.get_int("size"); fac.power = jsobj.get_int("power"); fac.good = jsobj.get_int("good"); fac.strength = jsobj.get_int("strength"); fac.sneak = jsobj.get_int("sneak"); fac.crime = jsobj.get_int("crime"); fac.cult = jsobj.get_int("cult"); fac.desc = jsobj.get_string("description"); _all_faction[jsobj.get_string("id")] = fac; }
faction_template::faction_template( JsonObject &jsobj ) : name( jsobj.get_string( "name" ) ) , likes_u( jsobj.get_int( "likes_u" ) ) , respects_u( jsobj.get_int( "respects_u" ) ) , known_by_u( jsobj.get_bool( "known_by_u" ) ) , id( faction_id( jsobj.get_string( "id" ) ) ) , desc( jsobj.get_string( "description" ) ) , strength( jsobj.get_int( "strength" ) ) , sneak( jsobj.get_int( "sneak" ) ) , crime( jsobj.get_int( "crime" ) ) , cult( jsobj.get_int( "cult" ) ) , good( jsobj.get_int( "good" ) ) , size( jsobj.get_int( "size" ) ) , power( jsobj.get_int( "power" ) ) , combat_ability( jsobj.get_int( "combat_ability" ) ) , food_supply( jsobj.get_int( "food_supply" ) ) , wealth( jsobj.get_int( "wealth" ) ) { }
void sfx::load_playlist( JsonObject &jsobj ) { if( !sound_init_success ) { return; } JsonArray jarr = jsobj.get_array( "playlists" ); while( jarr.has_more() ) { JsonObject playlist = jarr.next_object(); const std::string playlist_id = playlist.get_string( "id" ); music_playlist playlist_to_load; playlist_to_load.shuffle = playlist.get_bool( "shuffle", false ); JsonArray files = playlist.get_array( "files" ); while( files.has_more() ) { JsonObject entry = files.next_object(); const music_playlist::entry e{ entry.get_string( "file" ), entry.get_int( "volume" ) }; playlist_to_load.entries.push_back( e ); } playlists[playlist_id] = std::move( playlist_to_load ); } }
void MonsterGroupManager::LoadMonsterGroup( JsonObject &jo ) { float mon_upgrade_factor = get_option<float>( "MONSTER_UPGRADE_FACTOR" ); MonsterGroup g; g.name = mongroup_id( jo.get_string( "name" ) ); bool extending = false; //If already a group with that name, add to it instead of overwriting it if( monsterGroupMap.count( g.name ) != 0 && !jo.get_bool( "override", false ) ) { g = monsterGroupMap[g.name]; extending = true; } if( !extending || jo.has_string( "default" ) ) { //Not mandatory to specify default if extending existing group g.defaultMonster = mtype_id( jo.get_string( "default" ) ); } g.is_animal = jo.get_bool( "is_animal", false ); if( jo.has_array( "monsters" ) ) { JsonArray monarr = jo.get_array( "monsters" ); while( monarr.has_more() ) { JsonObject mon = monarr.next_object(); const mtype_id name = mtype_id( mon.get_string( "monster" ) ); int freq = mon.get_int( "freq" ); int cost = mon.get_int( "cost_multiplier" ); int pack_min = 1; int pack_max = 1; if( mon.has_member( "pack_size" ) ) { JsonArray packarr = mon.get_array( "pack_size" ); pack_min = packarr.next_int(); pack_max = packarr.next_int(); } static const time_duration tdfactor = 1_hours; time_duration starts = 0_turns; time_duration ends = 0_turns; if( mon.has_member( "starts" ) ) { starts = tdfactor * mon.get_int( "starts" ) * ( mon_upgrade_factor > 0 ? mon_upgrade_factor : 1 ); } if( mon.has_member( "ends" ) ) { ends = tdfactor * mon.get_int( "ends" ) * ( mon_upgrade_factor > 0 ? mon_upgrade_factor : 1 ); } MonsterGroupEntry new_mon_group = MonsterGroupEntry( name, freq, cost, pack_min, pack_max, starts, ends ); if( mon.has_member( "conditions" ) ) { JsonArray conditions_arr = mon.get_array( "conditions" ); while( conditions_arr.has_more() ) { new_mon_group.conditions.push_back( conditions_arr.next_string() ); } } g.monsters.push_back( new_mon_group ); } } g.replace_monster_group = jo.get_bool( "replace_monster_group", false ); g.new_monster_group = mongroup_id( jo.get_string( "new_monster_group_id", mongroup_id::NULL_ID().str() ) ); assign( jo, "replacement_time", g.monster_group_time, false, 1_days ); g.is_safe = jo.get_bool( "is_safe", false ); g.freq_total = jo.get_int( "freq_total", ( extending ? g.freq_total : 1000 ) ); if( jo.get_bool( "auto_total", false ) ) { //Fit the max size to the sum of all freqs int total = 0; for( MonsterGroupEntry &mon : g.monsters ) { total += mon.frequency; } g.freq_total = total; } monsterGroupMap[g.name] = g; }
ma_buff load_buff(JsonObject &jo) { ma_buff buff; buff.id = jo.get_string("id"); buff.name = _(jo.get_string("name").c_str()); buff.description = _(jo.get_string("description").c_str()); buff.buff_duration = jo.get_int("buff_duration", 2); buff.max_stacks = jo.get_int("max_stacks", 1); buff.reqs.unarmed_allowed = jo.get_bool("unarmed_allowed", false); buff.reqs.melee_allowed = jo.get_bool("melee_allowed", false); buff.reqs.min_melee = jo.get_int("min_melee", 0); buff.reqs.min_unarmed = jo.get_int("min_unarmed", 0); buff.dodges_bonus = jo.get_int("bonus_dodges", 0); buff.blocks_bonus = jo.get_int("bonus_blocks", 0); buff.hit = jo.get_int("hit", 0); buff.bash = jo.get_int("bash", 0); buff.cut = jo.get_int("cut", 0); buff.dodge = jo.get_int("dodge", 0); buff.speed = jo.get_int("speed", 0); buff.block = jo.get_int("block", 0); buff.arm_bash = jo.get_int("arm_bash", 0); buff.arm_cut = jo.get_int("arm_cut", 0); buff.bash_stat_mult = jo.get_float("bash_mult", 1.0); buff.cut_stat_mult = jo.get_float("cut_mult", 1.0); buff.hit_str = jo.get_float("hit_str", 0.0); buff.hit_dex = jo.get_float("hit_dex", 0.0); buff.hit_int = jo.get_float("hit_int", 0.0); buff.hit_per = jo.get_float("hit_per", 0.0); buff.bash_str = jo.get_float("bash_str", 0.0); buff.bash_dex = jo.get_float("bash_dex", 0.0); buff.bash_int = jo.get_float("bash_int", 0.0); buff.bash_per = jo.get_float("bash_per", 0.0); buff.cut_str = jo.get_float("cut_str", 0.0); buff.cut_dex = jo.get_float("cut_dex", 0.0); buff.cut_int = jo.get_float("cut_int", 0.0); buff.cut_per = jo.get_float("cut_per", 0.0); buff.dodge_str = jo.get_float("dodge_str", 0.0); buff.dodge_dex = jo.get_float("dodge_dex", 0.0); buff.dodge_int = jo.get_float("dodge_int", 0.0); buff.dodge_per = jo.get_float("dodge_per", 0.0); buff.block_str = jo.get_float("block_str", 0.0); buff.block_dex = jo.get_float("block_dex", 0.0); buff.block_int = jo.get_float("block_int", 0.0); buff.block_per = jo.get_float("block_per", 0.0); buff.quiet = jo.get_bool("quiet", false); buff.throw_immune = jo.get_bool("throw_immune", false); buff.reqs.req_buffs = jo.get_tags("req_buffs"); ma_buffs[buff.id] = buff; return buff; }
void load_martial_art(JsonObject &jo) { martialart ma; JsonArray jsarr; ma.id = jo.get_string("id"); ma.name = _(jo.get_string("name").c_str()); ma.description = _(jo.get_string("description").c_str()); jsarr = jo.get_array("static_buffs"); while (jsarr.has_more()) { JsonObject jsobj = jsarr.next_object(); ma.static_buffs.push_back(load_buff(jsobj)); } jsarr = jo.get_array("onmove_buffs"); while (jsarr.has_more()) { JsonObject jsobj = jsarr.next_object(); ma.onmove_buffs.push_back(load_buff(jsobj)); } jsarr = jo.get_array("onhit_buffs"); while (jsarr.has_more()) { JsonObject jsobj = jsarr.next_object(); ma.onhit_buffs.push_back(load_buff(jsobj)); } jsarr = jo.get_array("onattack_buffs"); while (jsarr.has_more()) { JsonObject jsobj = jsarr.next_object(); ma.onattack_buffs.push_back(load_buff(jsobj)); } jsarr = jo.get_array("ondodge_buffs"); while (jsarr.has_more()) { JsonObject jsobj = jsarr.next_object(); ma.ondodge_buffs.push_back(load_buff(jsobj)); } jsarr = jo.get_array("onblock_buffs"); while (jsarr.has_more()) { JsonObject jsobj = jsarr.next_object(); ma.onblock_buffs.push_back(load_buff(jsobj)); } jsarr = jo.get_array("ongethit_buffs"); while (jsarr.has_more()) { JsonObject jsobj = jsarr.next_object(); ma.onblock_buffs.push_back(load_buff(jsobj)); } ma.techniques = jo.get_tags("techniques"); ma.weapons = jo.get_tags("weapons"); ma.leg_block = jo.get_int("leg_block", -1); ma.arm_block = jo.get_int("arm_block", -1); ma.arm_block_with_bio_armor_arms = jo.get_bool("arm_block_with_bio_armor_arms", false); ma.leg_block_with_bio_armor_legs = jo.get_bool("leg_block_with_bio_armor_legs", false); martialarts[ma.id] = ma; }
void input_manager::load(const std::string &file_name, bool is_user_preferences) { std::ifstream data_file(file_name.c_str(), std::ifstream::in | std::ifstream::binary); if(!data_file.good()) { // Only throw if this is the first file to load, that file _must_ exist, // otherwise the keybindings can not be read at all. if (action_contexts.empty()) { throw "Could not read " + file_name; } return; } JsonIn jsin(data_file); //Crawl through once and create an entry for every definition jsin.start_array(); while (!jsin.end_array()) { // JSON object representing the action JsonObject action = jsin.get_object(); const std::string action_id = action.get_string("id"); const std::string context = action.get_string("category", default_context_id); t_actions &actions = action_contexts[context]; if (!is_user_preferences && action.has_member("name")) { // Action names are not user preferences. Some experimental builds // post-0.A had written action names into the user preferences // config file. Any names that exist in user preferences will be // ignored. actions[action_id].name = action.get_string("name"); } // Iterate over the bindings JSON array JsonArray bindings = action.get_array("bindings"); t_input_event_list events; while (bindings.has_more()) { JsonObject keybinding = bindings.next_object(); std::string input_method = keybinding.get_string("input_method"); input_event new_event; if(input_method == "keyboard") { new_event.type = CATA_INPUT_KEYBOARD; } else if(input_method == "gamepad") { new_event.type = CATA_INPUT_GAMEPAD; } else if(input_method == "mouse") { new_event.type = CATA_INPUT_MOUSE; } if (keybinding.has_array("key")) { JsonArray keys = keybinding.get_array("key"); while (keys.has_more()) { new_event.sequence.push_back( get_keycode(keys.next_string()) ); } } else { // assume string if not array, and throw if not string new_event.sequence.push_back( get_keycode(keybinding.get_string("key")) ); } events.push_back(new_event); } // An invariant of this class is that user-created, local keybindings // with an empty set of input_events do not exist in the // action_contexts map. In prior versions of this class, this was not // true, so users of experimental builds post-0.A will have empty // local keybindings saved in their keybindings.json config. // // To be backwards compatible with keybindings.json from prior // experimental builds, we will detect user-created, local keybindings // with empty input_events and disregard them. When keybindings are // later saved, these remnants won't be saved. if (!is_user_preferences || !events.empty() || context == default_context_id || actions.count(action_id) > 0) { // In case this is the second file containing user preferences, // this replaces the default bindings with the user's preferences. action_attributes &attributes = actions[action_id]; attributes.input_events = events; if (action.has_member("is_user_created")) { attributes.is_user_created = action.get_bool("is_user_created"); } } } }
void MonsterGenerator::load_monster(JsonObject &jo) { // id std::string mid; if (jo.has_member("id")) { mid = jo.get_string("id"); if (mon_templates.count(mid) > 0) { delete mon_templates[mid]; } mtype *newmon = new mtype; newmon->id = mid; newmon->name = jo.get_string("name").c_str(); if(jo.has_member("name_plural")) { newmon->name_plural = jo.get_string("name_plural"); } else { // default behaviour: Assume the regular plural form (appending an “s”) newmon->name_plural = newmon->name + "s"; } newmon->description = _(jo.get_string("description").c_str()); newmon->mat = jo.get_string("material"); newmon->species = jo.get_tags("species"); newmon->categories = jo.get_tags("categories"); newmon->sym = jo.get_string("symbol"); if( utf8_wrapper( newmon->sym ).display_width() != 1 ) { jo.throw_error( "monster symbol should be exactly one console cell width", "symbol" ); } newmon->color = color_from_string(jo.get_string("color")); newmon->size = get_from_string(jo.get_string("size", "MEDIUM"), size_map, MS_MEDIUM); newmon->phase = get_from_string(jo.get_string("phase", "SOLID"), phase_map, SOLID); newmon->difficulty = jo.get_int("diff", 0); newmon->agro = jo.get_int("aggression", 0); newmon->morale = jo.get_int("morale", 0); newmon->speed = jo.get_int("speed", 0); newmon->melee_skill = jo.get_int("melee_skill", 0); newmon->melee_dice = jo.get_int("melee_dice", 0); newmon->melee_sides = jo.get_int("melee_dice_sides", 0); newmon->melee_cut = jo.get_int("melee_cut", 0); newmon->sk_dodge = jo.get_int("dodge", 0); newmon->armor_bash = jo.get_int("armor_bash", 0); newmon->armor_cut = jo.get_int("armor_cut", 0); newmon->hp = jo.get_int("hp", 0); jo.read("starting_ammo", newmon->starting_ammo); newmon->luminance = jo.get_float("luminance", 0); newmon->revert_to_itype = jo.get_string( "revert_to_itype", "" ); if (jo.has_array("attack_effs")) { JsonArray jsarr = jo.get_array("attack_effs"); while (jsarr.has_more()) { JsonObject e = jsarr.next_object(); mon_effect_data new_eff(e.get_string("id", "null"), e.get_int("duration", 0), body_parts[e.get_string("bp", "NUM_BP")], e.get_bool("permanent", false), e.get_int("chance", 100)); newmon->atk_effs.push_back(new_eff); } } if (jo.has_string("death_drops")) { newmon->death_drops = jo.get_string("death_drops"); } else if (jo.has_object("death_drops")) { JsonObject death_frop_json = jo.get_object("death_drops"); // Make up a group name, should be unique (include the monster id), newmon->death_drops = newmon->id + "_death_drops_auto"; const std::string subtype = death_frop_json.get_string("subtype", "distribution"); // and load the entry as a standard item group using the made up name. item_group::load_item_group(death_frop_json, newmon->death_drops, subtype); } else if (jo.has_member("death_drops")) { jo.throw_error("invalid type, must be string or object", "death_drops"); } newmon->dies = get_death_functions(jo, "death_function"); load_special_defense(newmon, jo, "special_when_hit"); load_special_attacks(newmon, jo, "special_attacks"); std::set<std::string> flags, anger_trig, placate_trig, fear_trig; flags = jo.get_tags("flags"); anger_trig = jo.get_tags("anger_triggers"); placate_trig = jo.get_tags("placate_triggers"); fear_trig = jo.get_tags("fear_triggers"); newmon->flags = get_set_from_tags(flags, flag_map, MF_NULL); newmon->anger = get_set_from_tags(anger_trig, trigger_map, MTRIG_NULL); newmon->fear = get_set_from_tags(fear_trig, trigger_map, MTRIG_NULL); newmon->placate = get_set_from_tags(placate_trig, trigger_map, MTRIG_NULL); mon_templates[mid] = newmon; } }
void mtype::load( JsonObject &jo ) { MonsterGenerator &gen = MonsterGenerator::generator(); // Name and name plural are not translated here, but when needed in // combination with the actual count in `mtype::nname`. mandatory( jo, was_loaded, "name", name ); // default behaviour: Assume the regular plural form (appending an “s”) optional( jo, was_loaded, "name_plural", name_plural, name + "s" ); mandatory( jo, was_loaded, "description", description, translated_string_reader ); // Have to overwrite the default { "hflesh" } here if( !was_loaded || jo.has_member( "material" ) ) { mat = { jo.get_string( "material" ) }; } optional( jo, was_loaded, "species", species, auto_flags_reader<species_id> {} ); optional( jo, was_loaded, "categories", categories, auto_flags_reader<> {} ); // See monfaction.cpp if( !was_loaded || jo.has_member( "default_faction" ) ) { const auto faction = mfaction_str_id( jo.get_string( "default_faction" ) ); default_faction = monfactions::get_or_add_faction( faction ); } if( !was_loaded || jo.has_member( "symbol" ) ) { sym = jo.get_string( "symbol" ); if( utf8_wrapper( sym ).display_width() != 1 ) { jo.throw_error( "monster symbol should be exactly one console cell width", "symbol" ); } } mandatory( jo, was_loaded, "color", color, color_reader{} ); const typed_flag_reader<decltype( Creature::size_map )> size_reader{ Creature::size_map, "invalid creature size" }; optional( jo, was_loaded, "size", size, size_reader, MS_MEDIUM ); const typed_flag_reader<decltype( gen.phase_map )> phase_reader{ gen.phase_map, "invalid phase id" }; optional( jo, was_loaded, "phase", phase, phase_reader, SOLID ); optional( jo, was_loaded, "diff", difficulty, 0 ); optional( jo, was_loaded, "aggression", agro, 0 ); optional( jo, was_loaded, "morale", morale, 0 ); optional( jo, was_loaded, "speed", speed, 0 ); optional( jo, was_loaded, "attack_cost", attack_cost, 100 ); optional( jo, was_loaded, "melee_skill", melee_skill, 0 ); optional( jo, was_loaded, "melee_dice", melee_dice, 0 ); optional( jo, was_loaded, "melee_dice_sides", melee_sides, 0 ); optional( jo, was_loaded, "melee_cut", melee_cut, 0 ); optional( jo, was_loaded, "dodge", sk_dodge, 0 ); optional( jo, was_loaded, "armor_bash", armor_bash, 0 ); optional( jo, was_loaded, "armor_cut", armor_cut, 0 ); optional( jo, was_loaded, "armor_acid", armor_acid, armor_cut / 2 ); optional( jo, was_loaded, "armor_fire", armor_fire, 0 ); optional( jo, was_loaded, "hp", hp, 0 ); optional( jo, was_loaded, "starting_ammo", starting_ammo ); optional( jo, was_loaded, "luminance", luminance, 0 ); optional( jo, was_loaded, "revert_to_itype", revert_to_itype, "" ); optional( jo, was_loaded, "vision_day", vision_day, 40 ); optional( jo, was_loaded, "vision_night", vision_night, 1 ); optional( jo, was_loaded, "armor_stab", armor_stab, 0.8f * armor_cut ); // TODO: allow adding/removing specific entries if `was_loaded` is true if( jo.has_array( "attack_effs" ) ) { JsonArray jsarr = jo.get_array( "attack_effs" ); while( jsarr.has_more() ) { JsonObject e = jsarr.next_object(); mon_effect_data new_eff( efftype_id( e.get_string( "id" ) ), e.get_int( "duration", 0 ), get_body_part_token( e.get_string( "bp", "NUM_BP" ) ), e.get_bool( "permanent", false ), e.get_int( "chance", 100 ) ); atk_effs.push_back( new_eff ); } } if( jo.has_member( "death_drops" ) ) { JsonIn &stream = *jo.get_raw( "death_drops" ); death_drops = item_group::load_item_group( stream, "distribution" ); } const typed_flag_reader<decltype( gen.death_map )> death_reader{ gen.death_map, "invalid monster death function" }; optional( jo, was_loaded, "death_function", dies, death_reader ); if( dies.empty() ) { // TODO: really needed? Is an empty `dies` container not allowed? dies.push_back( mdeath::normal ); } // TODO: allow overriding/adding/removing those if `was_loaded` is true gen.load_special_defense( this, jo, "special_when_hit" ); gen.load_special_attacks( this, jo, "special_attacks" ); // Disable upgrading when JSON contains `"upgrades": false`, but fallback to the // normal behavior (including error checking) if "upgrades" is not boolean or not `false`. if( jo.has_bool( "upgrades" ) && !jo.get_bool( "upgrades" ) ) { upgrade_group = mongroup_id::NULL_ID; upgrade_into = mtype_id::NULL_ID; upgrades = false; } else if( jo.has_member( "upgrades" ) ) { JsonObject up = jo.get_object( "upgrades" ); optional( up, was_loaded, "half_life", half_life, -1 ); optional( up, was_loaded, "into_group", upgrade_group, auto_flags_reader<mongroup_id> {}, mongroup_id::NULL_ID ); optional( up, was_loaded, "into", upgrade_into, auto_flags_reader<mtype_id> {}, mtype_id::NULL_ID ); upgrades = true; } const typed_flag_reader<decltype( gen.flag_map )> flag_reader{ gen.flag_map, "invalid monster flag" }; optional( jo, was_loaded, "flags", flags, flag_reader ); const typed_flag_reader<decltype( gen.trigger_map )> trigger_reader{ gen.trigger_map, "invalid monster trigger" }; optional( jo, was_loaded, "anger_triggers", anger, trigger_reader ); optional( jo, was_loaded, "placate_triggers", placate, trigger_reader ); optional( jo, was_loaded, "fear_triggers", fear, trigger_reader ); }