// 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);
    }
}
void Item_factory::load_gun(JsonObject& jo)
{
    it_gun* gun_template = new it_gun();
    gun_template->ammo = jo.get_string("ammo");
    gun_template->skill_used = Skill::skill(jo.get_string("skill"));
    gun_template->dmg_bonus = jo.get_int("ranged_damage");
    gun_template->range = jo.get_int("range");
    gun_template->dispersion = jo.get_int("dispersion");
    gun_template->recoil = jo.get_int("recoil");
    gun_template->durability = jo.get_int("durability");
    gun_template->burst = jo.get_int("burst");
    gun_template->clip = jo.get_int("clip_size");
    gun_template->reload_time = jo.get_int("reload");
    gun_template->pierce = jo.get_int("pierce", 0);
    gun_template->ammo_effects = jo.get_tags("ammo_effects");

    if ( jo.has_array("valid_mod_locations") ) {
        JsonArray jarr = jo.get_array("valid_mod_locations");
        while (jarr.has_more()){
            JsonArray curr = jarr.next_array();
            gun_template->valid_mod_locations.insert(std::pair<std::string, int>(curr.get_string(0), curr.get_int(1)));
            gun_template->occupied_mod_locations.insert(std::pair<std::string, int>(curr.get_string(0), 0));
        }
    }

    itype *new_item_template = gun_template;
    load_basic_info(jo, new_item_template);
}
Beispiel #3
0
void mutation_branch::load_trait_group( JsonObject &jsobj, const trait_group::Trait_group_tag &gid,
                                        const std::string &subtype )
{
    if( subtype != "distribution" && subtype != "collection" && subtype != "old" ) {
        jsobj.throw_error( "unknown trait group type", "subtype" );
    }

    Trait_group &tg = make_group_or_throw( gid, ( subtype == "collection" || subtype == "old" ) );

    // TODO: (sm) Looks like this makes the new code backwards-compatible with the old format. Great if so!
    if( subtype == "old" ) {
        JsonArray traits = jsobj.get_array( "traits" );
        while( traits.has_more() ) {
            JsonArray pair = traits.next_array();
            tg.add_trait_entry( trait_id( pair.get_string( 0 ) ), pair.get_int( 1 ) );
        }
        return;
    }

    // TODO: (sm) Taken from item_factory.cpp almost verbatim. Ensure that these work!
    if( jsobj.has_member( "entries" ) ) {
        JsonArray traits = jsobj.get_array( "entries" );
        while( traits.has_more() ) {
            JsonObject subobj = traits.next_object();
            add_entry( tg, subobj );
        }
    }
    if( jsobj.has_member( "traits" ) ) {
        JsonArray traits = jsobj.get_array( "traits" );
        while( traits.has_more() ) {
            if( traits.test_string() ) {
                tg.add_trait_entry( trait_id( traits.next_string() ), 100 );
            } else if( traits.test_array() ) {
                JsonArray subtrait = traits.next_array();
                tg.add_trait_entry( trait_id( subtrait.get_string( 0 ) ), subtrait.get_int( 1 ) );
            } else {
                JsonObject subobj = traits.next_object();
                add_entry( tg, subobj );
            }
        }
    }
    if( jsobj.has_member( "groups" ) ) {
        JsonArray traits = jsobj.get_array( "groups" );
        while( traits.has_more() ) {
            if( traits.test_string() ) {
                tg.add_group_entry( trait_group::Trait_group_tag( traits.next_string() ), 100 );
            } else if( traits.test_array() ) {
                JsonArray subtrait = traits.next_array();
                tg.add_group_entry( trait_group::Trait_group_tag( traits.get_string( 0 ) ), subtrait.get_int( 1 ) );
            } else {
                JsonObject subobj = traits.next_object();
                add_entry( tg, subobj );
            }
        }
    }
}
 profession::itypedec get_next( JsonIn &jin ) const {
     // either a plain item type id string, or an array with item type id
     // and as second entry the item description.
     if( jin.test_string() ) {
         return profession::itypedec( jin.get_string(), "" );
     }
     JsonArray jarr = jin.get_array();
     const auto id = jarr.get_string( 0 );
     const auto s = jarr.get_string( 1 );
     const auto snippet = _( s.c_str() );
     return profession::itypedec( id, snippet );
 }
void item_comp::load( JsonArray &ja )
{
    JsonArray comp = ja.next_array();
    type = comp.get_string( 0 );
    count = comp.get_int( 1 );
    // Recoverable is true by default.
    if( comp.size() > 2 ) {
        recoverable = comp.get_string( 2 ) == "NO_RECOVER" ? false : true;
    }
    if( count <= 0 ) {
        ja.throw_error( "item count must be a positive number" );
    }
}
void MonsterGenerator::load_special_defense(mtype *m, JsonObject &jo, std::string member) {
    if (jo.has_array(member)) {
        JsonArray jsarr = jo.get_array(member);
        if ( defense_map.find(jsarr.get_string(0)) != defense_map.end() ) {
            m->sp_defense = defense_map[jsarr.get_string(0)];
            m->def_chance = jsarr.get_int(1);
        } else {
            jsarr.throw_error("Invalid special_when_hit");
        }
    }

    if (m->sp_defense == NULL) {
        m->sp_defense = defense_map["NONE"];
    }
}
void mtype::add_special_attack( JsonArray inner, const std::string & )
{
    MonsterGenerator &gen = MonsterGenerator::generator();
    const std::string name = inner.get_string( 0 );
    const auto iter = gen.attack_map.find( name );
    if( iter == gen.attack_map.end() ) {
        inner.throw_error( "Invalid special_attacks" );
    }

    if( special_attacks.count( name ) > 0 ) {
        special_attacks.erase( name );
        const auto iter = std::find( special_attacks_names.begin(), special_attacks_names.end(), name );
        if( iter != special_attacks_names.end() ) {
            special_attacks_names.erase( iter );
        }
        if( test_mode ) {
            debugmsg( "%s specifies more than one attack of (sub)type %s, ignoring all but the last",
                      id.c_str(), name.c_str() );
        }
    }
    auto new_attack = mtype_special_attack( iter->second );
    new_attack.actor->cooldown = inner.get_int( 1 );
    special_attacks.emplace( name, new_attack );
    special_attacks_names.push_back( name );
}
void MonsterGenerator::load_special_attacks(mtype *m, JsonObject &jo, std::string member) {
    m->special_attacks.clear(); // make sure we're running with everything cleared

    if( !jo.has_array( member ) ) {
        return;
    }

    JsonArray outer = jo.get_array(member);
    while( outer.has_more() ) {
        if( outer.test_array() ) {
            JsonArray inner = outer.next_array();
            const auto &aname = inner.get_string(0);
            if ( attack_map.find(aname) != attack_map.end() ) {
                auto new_entry = mtype_special_attack(
                    attack_map[aname], inner.get_int(1) );
                m->special_attacks[aname] = new_entry;

                m->special_attacks_names.push_back(aname);
            } else {
                inner.throw_error("Invalid special_attacks");
            }
        } else if( outer.test_object() ) {
            set_attack_from_object(
                outer.next_object(), m->special_attacks, m->special_attacks_names );
        } else {
            outer.throw_error( "array element is neither array nor object." );
        }
    }
}
void tool_comp::load( JsonArray &ja )
{
    if( ja.test_string() ) {
        // constructions uses this format: [ "tool", ... ]
        type = ja.next_string();
        count = -1;
    } else {
        JsonArray comp = ja.next_array();
        type = comp.get_string( 0 );
        count = comp.get_int( 1 );
        requirement = comp.size() > 2 && comp.get_string( 2 ) == "LIST";
    }
    if( count == 0 ) {
        ja.throw_error( "tool count must not be 0" );
    }
    // Note: negative count means charges (of the tool) should be consumed
}
void item_comp::load( JsonArray &ja )
{
    JsonArray comp = ja.next_array();
    type = comp.get_string( 0 );
    count = comp.get_int( 1 );
    size_t handled = 2;
    while( comp.size() > handled ) {
        const std::string &flag = comp.get_string( handled++ );
        if( flag == "NO_RECOVER" ) {
            recoverable = false;
        } else if( flag == "LIST" ) {
            requirement = true;
        }
    }
    if( count <= 0 ) {
        ja.throw_error( "item count must be a positive number" );
    }
}
Beispiel #11
0
void VehicleGroup::load(JsonObject &jo)
{
    VehicleGroup &group = vgroups[vgroup_id(jo.get_string("id"))];

    JsonArray vehicles = jo.get_array("vehicles");
    while (vehicles.has_more()) {
        JsonArray pair = vehicles.next_array();
        group.add_vehicle(vproto_id(pair.get_string(0)), pair.get_int(1));
    }
}
Beispiel #12
0
void VehicleFactory::load_vehicle_group(JsonObject &jo)
{
    const Vehicle_tag group_id = jo.get_string("id");
    JsonArray vehicles = jo.get_array("vehicles");

    while (vehicles.has_more()) {
        JsonArray pair = vehicles.next_array();
        groups[group_id].add_vehicle(pair.get_string(0), pair.get_int(1));
    }
}
void mtype::add_special_attack( JsonArray inner )
{
    MonsterGenerator &gen = MonsterGenerator::generator();
    const std::string name = inner.get_string( 0 );
    const auto iter = gen.attack_map.find( name );
    if( iter == gen.attack_map.end() ) {
        inner.throw_error( "Invalid special_attacks" );
    }
    special_attacks[name] = mtype_special_attack( iter->second, inner.get_int( 1 ) );
    special_attacks_names.push_back( name );
}
void MonsterGenerator::load_special_defense(mtype *m, JsonObject &jo, std::string member) {
    if (jo.has_array(member)) {
        JsonArray jsarr = jo.get_array(member);
        m->sp_defense = defense_map[jsarr.get_string(0)];
        m->def_chance = jsarr.get_int(1);
    }

    if (m->sp_defense == NULL) {
        m->sp_defense = defense_map["NONE"];
    }
}
Beispiel #15
0
void tool_comp::load( JsonArray &ja )
{
    if( ja.test_string() ) {
        // constructions uses this format: [ "tool", ... ]
        type = ja.next_string();
        count = -1;
    } else {
        JsonArray comp = ja.next_array();
        type = comp.get_string( 0 );
        count = comp.get_int( 1 );
    }
}
Beispiel #16
0
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());
    }
}
Beispiel #17
0
void ma_technique::load( JsonObject &jo, const std::string &src )
{
    optional( jo, was_loaded, "name", name, translated_string_reader );
    optional( jo, was_loaded, "description", description, translated_string_reader );

    if( jo.has_member( "messages" ) ) {
        JsonArray jsarr = jo.get_array("messages");
        player_message = jsarr.get_string( 0 );
        if( !player_message.empty() ) {
            player_message = _(player_message.c_str());
        }
        npc_message = jsarr.get_string( 1 );
        if( !npc_message.empty() ) {
            npc_message = _(npc_message.c_str());
        }
    }

    optional( jo, was_loaded, "crit_tec", crit_tec, false );
    optional( jo, was_loaded, "defensive", defensive, false );
    optional( jo, was_loaded, "disarms", disarms, false );
    optional( jo, was_loaded, "dummy", dummy, false );
    optional( jo, was_loaded, "dodge_counter", dodge_counter, false );
    optional( jo, was_loaded, "block_counter", block_counter, false );
    optional( jo, was_loaded, "miss_recovery", miss_recovery, false );
    optional( jo, was_loaded, "grab_break", grab_break, false );

    optional( jo, was_loaded, "weighting", weighting, 1 );

    optional( jo, was_loaded, "down_dur", down_dur, 0 );
    optional( jo, was_loaded, "stun_dur", stun_dur, 0 );
    optional( jo, was_loaded, "knockback_dist", knockback_dist, 0 );
    optional( jo, was_loaded, "knockback_spread", knockback_spread, 0 );

    optional( jo, was_loaded, "aoe", aoe, "" );
    optional( jo, was_loaded, "flags", flags, auto_flags_reader<>{} );

    reqs.load( jo, src );
    bonuses.load( jo );
}
void Item_factory::set_qualities_from_json(JsonObject& jo, std::string member, itype* new_item_template)
{

    if ( jo.has_array(member) ) {
        JsonArray jarr = jo.get_array(member);
        while (jarr.has_more()){
            JsonArray curr = jarr.next_array();
            new_item_template->qualities.insert(std::pair<std::string, int>(curr.get_string(0), curr.get_int(1)));
        }
    } else {
        debugmsg("Qualities list for item %s not an array", new_item_template->id.c_str());
    }
}
void MonsterGenerator::load_special_attacks(mtype *m, JsonObject &jo, std::string member) {
    m->sp_attack.clear(); // make sure we're running with
    m->sp_freq.clear();   // everything cleared

    if (jo.has_array(member)) {
        JsonArray outer = jo.get_array(member);
        while (outer.has_more()) {
            JsonArray inner = outer.next_array();
            if ( attack_map.find(inner.get_string(0)) != attack_map.end() ) {
                m->sp_attack.push_back(attack_map[inner.get_string(0)]);
                m->sp_freq.push_back(inner.get_int(1));
            } else {
                inner.throw_error("Invalid special_attacks");
            }
        }
    }

    if (m->sp_attack.empty()) {
        m->sp_attack.push_back(attack_map["NONE"]);
        m->sp_freq.push_back(0);
    }
}
// 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 = new Item_group(group_id);
    m_template_groups[group_id] = current_group;

    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);
        // we had better have loaded it already!
        if (m_template_groups.find(name) == m_template_groups.end()) {
            throw jsobj.line_number() + ": unrecognized group name: " + name;
        }
        current_group->add_group(m_template_groups[name], frequency);
    }
}
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 Item_factory::set_material_from_json(JsonObject& jo, std::string member, itype* new_item_template)
{
    //If the value isn't found, just return a group of null materials
    std::string material_list[2] = {"null", "null"};
    if( jo.has_array(member) ) {
        JsonArray jarr = jo.get_array(member);
        if (jarr.size() > 2) {
            debugmsg("Too many materials provided for item %s", new_item_template->id.c_str());
        }
        material_list[0] = jarr.get_string(0);
        material_list[1] = jarr.get_string(1);
    } else if ( jo.has_string(member) ) {
        material_list[0] = jo.get_string(member);
    }
    new_item_template->m1 = material_list[0];
    new_item_template->m2 = material_list[1];
}
Beispiel #23
0
void melee_actor::load_internal( JsonObject &obj, const std::string & )
{
    // Optional:
    if( obj.has_array( "damage_max_instance" ) ) {
        JsonArray arr = obj.get_array( "damage_max_instance" );
        damage_max_instance = load_damage_instance( arr );
    } else if( obj.has_object( "damage_max_instance" ) ) {
        damage_max_instance = load_damage_instance( obj );
    }

    min_mul = obj.get_float( "min_mul", 0.0f );
    max_mul = obj.get_float( "max_mul", 1.0f );
    move_cost = obj.get_int( "move_cost", 100 );
    accuracy = obj.get_int( "accuracy", INT_MIN );

    optional( obj, was_loaded, "miss_msg_u", miss_msg_u, translated_string_reader,
              _( "The %s lunges at you, but you dodge!" ) );
    optional( obj, was_loaded, "no_dmg_msg_u", no_dmg_msg_u, translated_string_reader,
              _( "The %1$s bites your %2$s, but fails to penetrate armor!" ) );
    optional( obj, was_loaded, "hit_dmg_u", hit_dmg_u, translated_string_reader,
              _( "The %1$s bites your %2$s!" ) );
    optional( obj, was_loaded, "miss_msg_npc", miss_msg_npc, translated_string_reader,
              _( "The %s lunges at <npcname>, but they dodge!" ) );
    optional( obj, was_loaded, "no_dmg_msg_npc", no_dmg_msg_npc, translated_string_reader,
              _( "The %1$s bites <npcname>'s %2$s, but fails to penetrate armor!" ) );
    optional( obj, was_loaded, "hit_dmg_npc", hit_dmg_npc, translated_string_reader,
              _( "The %1$s bites <npcname>'s %2$s!" ) );

    if( obj.has_array( "body_parts" ) ) {
        JsonArray jarr = obj.get_array( "body_parts" );
        while( jarr.has_more() ) {
            JsonArray sub = jarr.next_array();
            const body_part bp = get_body_part_token( sub.get_string( 0 ) );
            const float prob = sub.get_float( 1 );
            body_parts.add_or_replace( bp, prob );
        }
    }

    if( obj.has_array( "effects" ) ) {
        JsonArray jarr = obj.get_array( "effects" );
        while( jarr.has_more() ) {
            JsonObject eff = jarr.next_object();
            effects.push_back( load_mon_effect_data( eff ) );
        }
    }
}
Beispiel #24
0
void mutation_branch::load_trait_group( JsonArray &entries, const trait_group::Trait_group_tag &gid,
                                        const bool is_collection )
{
    Trait_group &tg = make_group_or_throw( gid, is_collection );

    while( entries.has_more() ) {
        // Backwards-compatibility with old format ["TRAIT", 100]
        if( entries.test_array() ) {
            JsonArray subarr = entries.next_array();

            trait_id id( subarr.get_string( 0 ) );
            std::unique_ptr<Trait_creation_data> ptr(
                new Single_trait_creator( id, subarr.get_int( 1 ) ) );
            tg.add_entry( ptr );
            // Otherwise load new format {"trait": ... } or {"group": ...}
        } else {
            JsonObject subobj = entries.next_object();
            add_entry( tg, subobj );
        }
    }
}
void game::load_monitem(JsonObject &jo) {
    std::vector<std::string> tmp_keys;
    std::vector<items_location_and_chance> tmp_items;
    std::string mkey="";

    if ( jo.has_string("id") ) {
        tmp_keys.push_back( jo.get_string("id") );
    } else if ( jo.has_array("id") ) {
        jo.read("id", tmp_keys);
    } else {
        jo.throw_error("monitems: requires \"id\": \"monster_id\" or \"id\": [ \"multiple\", \"monster_ids\" ]");
    }

    if ( ! jo.has_array("item_groups") ) {
        jo.throw_error("monitems: requires \"item_groups\": [ [ \"group_one\", (chance) ], ... ]");
    }

    JsonArray ja = jo.get_array("item_groups");
    JsonArray ga;
    while ( ja.has_more() ) {
        ga = ja.next_array();
        if ( ! ga.has_string(0) || ! ga.has_number(1) ) {
             jo.throw_error("monitems: item_groups must contain arrays of [ \"string\", number ]");
        }
        tmp_items.push_back( items_location_and_chance( ga.get_string(0), ga.get_int(1) ) );
    }

    for( size_t i = 0; i < tmp_keys.size(); ++i ) {
        std::map<std::string, std::vector <items_location_and_chance> >::iterator it = monitems.find( tmp_keys[i] );
        if ( it == monitems.end() ) {
            monitems[ tmp_keys[i] ] = tmp_items;
        } else {
            it->second.insert( it->second.end(), tmp_items.begin(), tmp_items.end() );
        }
    }
}
Beispiel #26
0
void load_construction(JsonObject &jo)
{
    construction *con = new construction;
    JsonArray temp;

    con->description = _(jo.get_string("description").c_str());
    con->difficulty = jo.get_int("difficulty");
    con->time = jo.get_int("time");

    temp = jo.get_array("tools");
    while (temp.has_more()) {
        std::vector<component> tool_choices;
        JsonArray ja = temp.next_array();
        while (ja.has_more()) {
            std::string name = ja.next_string();
            tool_choices.push_back(component(name, 1));
        }
        con->tools.push_back(tool_choices);
    }

    temp = jo.get_array("components");
    while (temp.has_more()) {
        std::vector<component> comp_choices;
        JsonArray ja = temp.next_array();
        while (ja.has_more()) {
            JsonArray comp = ja.next_array();
            std::string name = comp.get_string(0);
            int quant = comp.get_int(1);
            comp_choices.push_back(component(name, quant));
        }
        con->components.push_back(comp_choices);
    }

    con->pre_terrain = jo.get_string("pre_terrain", "");
    if (con->pre_terrain.size() > 1
            && con->pre_terrain[0] == 'f'
            && con->pre_terrain[1] == '_') {
        con->pre_is_furniture = true;
    } else {
        con->pre_is_furniture = false;
    }

    con->post_terrain = jo.get_string("post_terrain", "");
    if (con->post_terrain.size() > 1
            && con->post_terrain[0] == 'f'
            && con->post_terrain[1] == '_') {
        con->post_is_furniture = true;
    } else {
        con->post_is_furniture = false;
    }

    con->pre_flags = jo.get_tags("pre_flags");

    std::string prefunc = jo.get_string("pre_special", "");
    if (prefunc == "check_empty") {
        con->pre_special = &construct::check_empty;
    } else if (prefunc == "check_support") {
        con->pre_special = &construct::check_support;
    } else {
        // should probably print warning if not ""
        con->pre_special = &construct::check_nothing;
    }

    std::string postfunc = jo.get_string("post_special", "");
    if (postfunc == "done_tree") {
        con->post_special = &construct::done_tree;
    } else if (postfunc == "done_trunk_log") {
        con->post_special = &construct::done_trunk_log;
    } else if (postfunc == "done_trunk_plank") {
        con->post_special = &construct::done_trunk_plank;
    } else if (postfunc == "done_vehicle") {
        con->post_special = &construct::done_vehicle;
    } else if (postfunc == "done_deconstruct") {
        con->post_special = &construct::done_deconstruct;
    } else {
        // ditto, should probably warn here
        con->post_special = &construct::done_nothing;
    }

    con->id = constructions.size();
    constructions.push_back(con);
    constructions_by_desc[con->description].push_back(con);
}
Beispiel #27
0
void item_comp::load( JsonArray &ja )
{
    JsonArray comp = ja.next_array();
    type = comp.get_string( 0 );
    count = comp.get_int( 1 );
}
Beispiel #28
0
void gun_actor::load_internal( JsonObject &obj, const std::string & )
{
    gun_type = obj.get_string( "gun_type" );

    obj.read( "ammo_type", ammo_type );

    if( obj.has_array( "fake_skills" ) ) {
        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 );
        }
    }

    obj.read( "fake_str", fake_str );
    obj.read( "fake_dex", fake_dex );
    obj.read( "fake_int", fake_int );
    obj.read( "fake_per", fake_per );

    auto arr = obj.get_array( "ranges" );
    while( arr.has_more() ) {
        auto mode = arr.next_array();
        if( mode.size() < 2 || mode.get_int( 0 ) > mode.get_int( 1 ) ) {
            obj.throw_error( "incomplete or invalid range specified", "ranges" );
        }
        ranges.emplace( std::make_pair<int, int>( mode.get_int( 0 ), mode.get_int( 1 ) ),
                        gun_mode_id( mode.size() > 2 ? mode.get_string( 2 ) : "" ) );
    }

    obj.read( "max_ammo", max_ammo );

    obj.read( "move_cost", move_cost );

    if( obj.read( "description", description ) ) {
        description = _( description );
    }
    if( obj.read( "failure_msg", failure_msg ) ) {
        failure_msg = _( failure_msg );
    }
    if( obj.read( "no_ammo_sound", no_ammo_sound ) ) {
        no_ammo_sound = _( no_ammo_sound );
    } else {
        no_ammo_sound = _( "Click." );
    }

    obj.read( "targeting_cost", targeting_cost );

    obj.read( "require_targeting_player", require_targeting_player );
    obj.read( "require_targeting_npc", require_targeting_npc );
    obj.read( "require_targeting_monster", require_targeting_monster );

    obj.read( "targeting_timeout", targeting_timeout );
    obj.read( "targeting_timeout_extend", targeting_timeout_extend );

    if( obj.read( "targeting_sound", targeting_sound ) ) {
        targeting_sound = _( targeting_sound );
    } else {
        targeting_sound = _( "Beep." );
    }

    obj.read( "targeting_volume", targeting_volume );

    obj.get_bool( "laser_lock", laser_lock );

    obj.read( "require_sunlight", require_sunlight );
}
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 );
    optional( jo, was_loaded, "attack_effs", atk_effs, mon_attack_effect_reader{} );

    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;
    }

    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 );
}
void mtype::load( JsonObject &jo, const std::string &src )
{
    bool strict = src == "dda";

    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 behavior: Assume the regular plural form (appending an “s”)
    optional( jo, was_loaded, "name_plural", name_plural, name + "s" );
    optional( jo, was_loaded, "description", description );

    optional( jo, was_loaded, "material", mat, auto_flags_reader<material_id> {} );
    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" );
        }
    }
    if( was_loaded && jo.has_member( "copy-from" ) && looks_like.empty() ) {
        looks_like = jo.get_string( "copy-from" );
    }
    if( jo.has_member( "looks_like" ) ) {
        looks_like = jo.get_string( "looks_like" );
    }

    assign( jo, "color", color );
    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 );

    assign( jo, "diff", difficulty, strict, 0 );
    assign( jo, "hp", hp, strict, 1 );
    assign( jo, "speed", speed, strict, 0 );
    assign( jo, "aggression", agro, strict, -100, 100 );
    assign( jo, "morale", morale, strict );

    assign( jo, "attack_cost", attack_cost, strict, 0 );
    assign( jo, "melee_skill", melee_skill, strict, 0 );
    assign( jo, "melee_dice", melee_dice, strict, 0 );
    assign( jo, "melee_dice_sides", melee_sides, strict, 0 );

    assign( jo, "dodge", sk_dodge, strict, 0 );
    assign( jo, "armor_bash", armor_bash, strict, 0 );
    assign( jo, "armor_cut", armor_cut, strict, 0 );
    assign( jo, "armor_stab", armor_stab, strict, 0 );
    assign( jo, "armor_acid", armor_acid, strict, 0 );
    assign( jo, "armor_fire", armor_fire, strict, 0 );

    assign( jo, "vision_day", vision_day, strict, 0 );
    assign( jo, "vision_night", vision_night, strict, 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, "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" );
    }

    assign( jo, "harvest", harvest, strict );

    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 );
    }

    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 );
    }
}