本文整理汇总了C++中JsonObject::has_bool方法的典型用法代码示例。如果您正苦于以下问题:C++ JsonObject::has_bool方法的具体用法?C++ JsonObject::has_bool怎么用?C++ JsonObject::has_bool使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类JsonObject
的用法示例。
在下文中一共展示了JsonObject::has_bool方法的6个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: load
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();
//.........这里部分代码省略.........
示例2: load
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();
//.........这里部分代码省略.........
示例3: load
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;
}
//.........这里部分代码省略.........
示例4: load
//.........这里部分代码省略.........
assign( jo, "emit_fields", emit_fields );
if( jo.has_member( "special_when_hit" ) ) {
JsonArray jsarr = jo.get_array( "special_when_hit" );
const auto iter = gen.defense_map.find( jsarr.get_string( 0 ) );
if( iter == gen.defense_map.end() ) {
jsarr.throw_error( "Invalid monster defense function" );
}
sp_defense = iter->second;
def_chance = jsarr.get_int( 1 );
} else if( !was_loaded ) {
sp_defense = &mdefense::none;
def_chance = 0;
}
if( !was_loaded || jo.has_member( "special_attacks" ) ) {
special_attacks.clear();
special_attacks_names.clear();
add_special_attacks( jo, "special_attacks", src );
} else {
// Note: special_attacks left as is, new attacks are added to it!
// Note: member name prefixes are compatible with those used by generic_typed_reader
if( jo.has_object( "extend" ) ) {
auto tmp = jo.get_object( "extend" );
add_special_attacks( tmp, "special_attacks", src );
}
if( jo.has_object( "delete" ) ) {
auto tmp = jo.get_object( "delete" );
remove_special_attacks( tmp, "special_attacks", src );
}
}
// 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, "age_grow", age_grow, -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;
}
//Reproduction
if( jo.has_member( "reproduction" ) ) {
JsonObject repro = jo.get_object( "reproduction" );
optional( repro, was_loaded, "baby_count", baby_count, -1 );
optional( repro, was_loaded, "baby_timer", baby_timer, -1 );
optional( repro, was_loaded, "baby_monster", baby_monster, auto_flags_reader<mtype_id> {},
mtype_id::NULL_ID() );
optional( repro, was_loaded, "baby_egg", baby_egg, auto_flags_reader<itype_id> {},
"null" );
if( jo.has_member( "baby_flags" ) ) {
baby_flags.clear();
JsonArray baby_tags = jo.get_array( "baby_flags" );
while( baby_tags.has_more() ) {
baby_flags.push_back( baby_tags.next_string() );
}
}
reproduces = true;
}
if( jo.has_member( "biosignature" ) ) {
JsonObject biosig = jo.get_object( "biosignature" );
optional( biosig, was_loaded, "biosig_timer", biosig_timer, -1 );
optional( biosig, was_loaded, "biosig_item", biosig_item, auto_flags_reader<itype_id> {},
"null" );
biosignatures = true;
}
optional( jo, was_loaded, "burn_into", burn_into, auto_flags_reader<mtype_id> {},
mtype_id::NULL_ID() );
const typed_flag_reader<decltype( gen.flag_map )> flag_reader{ gen.flag_map, "invalid monster flag" };
optional( jo, was_loaded, "flags", flags, flag_reader );
// Can't calculate yet - we want all flags first
optional( jo, was_loaded, "bash_skill", bash_skill, -1 );
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 );
if( jo.has_member( "path_settings" ) ) {
auto jop = jo.get_object( "path_settings" );
// Here rather than in pathfinding.cpp because we want monster-specific defaults and was_loaded
optional( jop, was_loaded, "max_dist", path_settings.max_dist, 0 );
optional( jop, was_loaded, "max_length", path_settings.max_length, -1 );
optional( jop, was_loaded, "bash_strength", path_settings.bash_strength, -1 );
optional( jop, was_loaded, "allow_open_doors", path_settings.allow_open_doors, false );
optional( jop, was_loaded, "avoid_traps", path_settings.avoid_traps, false );
optional( jop, was_loaded, "allow_climb_stairs", path_settings.allow_climb_stairs, true );
}
}
示例5: load_modfile
void mod_manager::load_modfile(JsonObject &jo, const std::string &main_path)
{
if (!jo.has_string("type") || jo.get_string("type") != "MOD_INFO") {
// Ignore anything that is not a mod-info
return;
}
std::string m_ident = jo.get_string("ident");
if (has_mod(m_ident)) {
// TODO: change this to make unique ident for the mod
// (instead of discarding it?)
debugmsg("there is already a mod with ident %s", m_ident.c_str());
return;
}
if( jo.has_bool( "obsolete" ) ) {
// Marked obsolete, no need to try to load anything else.
MOD_INFORMATION *modfile = new MOD_INFORMATION;
modfile->ident = m_ident;
modfile->obsolete = true;
mod_map[modfile->ident] = modfile;
return;
}
std::string t_type = jo.get_string("mod-type", "SUPPLEMENTAL");
std::vector<std::string> m_authors;
if (jo.has_array("authors")) {
m_authors = jo.get_string_array("authors");
} else {
if(jo.has_string("author")) {
m_authors.push_back(jo.get_string("author"));
}
}
std::string m_name = jo.get_string("name", "");
if (m_name.empty()) {
// "No name" gets confusing if many mods have no name
//~ name of a mod that has no name entry, (%s is the mods identifier)
m_name = string_format(_("No name (%s)"), m_ident.c_str());
} else {
m_name = _(m_name.c_str());
}
std::string m_desc = jo.get_string("description", "");
if (m_desc.empty()) {
m_desc = _("No description");
} else {
m_desc = _(m_desc.c_str());
}
std::string m_path;
if (jo.has_string("path")) {
m_path = jo.get_string("path");
if (m_path.empty()) {
// If an empty path is given, use only the
// folder of the modinfo.json
m_path = main_path;
} else {
// prefix the folder of modinfo.json
m_path = main_path + "/" + m_path;
}
} else {
// Default if no path is given:
// "<folder-of-modinfo.json>/data"
m_path = main_path + "/data";
}
std::vector<std::string> m_dependencies;
if (jo.has_member("dependencies") && jo.has_array("dependencies")) {
JsonArray jarr = jo.get_array("dependencies");
while(jarr.has_more()) {
const std::string dep = jarr.next_string();
if (dep == m_ident) {
debugmsg("mod %s has itself as dependency", m_ident.c_str());
continue;
}
if (std::find(m_dependencies.begin(), m_dependencies.end(), dep) != m_dependencies.end()) {
// Some dependency listed twice, ignore it, what else can be done?
continue;
}
m_dependencies.push_back(dep);
}
}
mod_type m_type;
if (t_type == "CORE") {
m_type = MT_CORE;
} else if (t_type == "SUPPLEMENTAL") {
m_type = MT_SUPPLEMENTAL;
} else {
throw std::string("Invalid mod type: ") + t_type + " for mod " + m_ident;
}
MOD_INFORMATION *modfile = new MOD_INFORMATION;
modfile->ident = m_ident;
modfile->_type = m_type;
modfile->authors = m_authors;
modfile->name = m_name;
modfile->description = m_desc;
modfile->dependencies = m_dependencies;
modfile->path = m_path;
mod_map[modfile->ident] = modfile;
}
示例6: load
//.........这里部分代码省略.........
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, "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 );
optional( jo, was_loaded, "attack_effs", atk_effs, mon_attack_effect_reader{} );
// TODO: make this work with `was_loaded`
if( jo.has_array( "melee_damage" ) ) {
JsonArray arr = jo.get_array( "melee_damage" );
melee_damage = load_damage_instance( arr );
} else if( jo.has_object( "melee_damage" ) ) {
melee_damage = load_damage_instance( jo );
}
if( jo.has_int( "melee_cut" ) ) {
int bonus_cut = jo.get_int( "melee_cut" );
melee_damage.add_damage( DT_CUT, bonus_cut );
}
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 );
}
if( jo.has_member( "special_when_hit" ) ) {
JsonArray jsarr = jo.get_array( "special_when_hit" );
const auto iter = gen.defense_map.find( jsarr.get_string( 0 ) );
if( iter == gen.defense_map.end() ) {
jsarr.throw_error( "Invalid monster defense function" );
}
sp_defense = iter->second;
def_chance = jsarr.get_int( 1 );
} else if( !was_loaded ) {
sp_defense = &mdefense::none;
def_chance = 0;
}
if( !was_loaded || jo.has_member( "special_attacks" ) ) {
special_attacks.clear();
special_attacks_names.clear();
add_special_attacks( jo, "special_attacks" );
} else {
// Note: special_attacks left as is, new attacks are added to it!
// Note: member name prefixes are compatible with those used by generic_typed_reader
remove_special_attacks( jo, "remove:special_attacks" );
add_special_attacks( jo, "add: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;
}
optional( jo, was_loaded, "burn_into", burn_into, auto_flags_reader<mtype_id> {}, mtype_id::NULL_ID );
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 );
}