Exemplo n.º 1
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());
    }
}
Exemplo n.º 2
0
bool jsonstring(JsonObject &jsobj, std::string key, std::string & var) {
    if ( jsobj.has_string(key) ) {
        var = jsobj.get_string(key);
        return true;
    }
    return false;
}
Exemplo n.º 3
0
void vpart_info::load_wheel( cata::optional<vpslot_wheel> &whptr, JsonObject &jo )
{
    vpslot_wheel wh_info;
    if( whptr ) {
        wh_info = *whptr;
    }
    assign( jo, "rolling_resistance", wh_info.rolling_resistance );
    assign( jo, "contact_area", wh_info.contact_area );
    wh_info.terrain_mod = standard_terrain_mod;
    wh_info.or_rating = 0.5f;
    if( jo.has_string( "wheel_type" ) ) {
        const std::string wheel_type = jo.get_string( "wheel_type" );
        if( wheel_type == "rigid" ) {
            wh_info.terrain_mod = rigid_terrain_mod;
            wh_info.or_rating = 0.1;
        } else if( wheel_type == "off-road" ) {
            wh_info.terrain_mod = off_road_terrain_mod;
            wh_info.or_rating = 0.7;
        } else if( wheel_type == "racing" ) {
            wh_info.terrain_mod = racing_terrain_mod;
            wh_info.or_rating = 0.3;
        } else if( wheel_type == "treads" ) {
            wh_info.terrain_mod = treads_terrain_mod;
            wh_info.or_rating = 0.9;
        }
    }

    whptr = wh_info;
    assert( whptr );
}
Exemplo n.º 4
0
void VehicleFactory::load_vehicle_spawn(JsonObject &jo)
{
    const std::string spawn_id = jo.get_string("id");
    VehicleSpawn spawn;

    JsonArray types = jo.get_array("spawn_types");

    while (types.has_more()) {
        JsonObject type = types.next_object();

        if(type.has_object("vehicle_json")) {
            JsonObject vjo = type.get_object("vehicle_json");
            spawn.add(type.get_float("weight"), std::make_shared<VehicleFunction_json>(vjo));
        }
        else if(type.has_string("vehicle_function")) {
            if(builtin_functions.count(type.get_string("vehicle_function")) == 0) {
                type.throw_error("load_vehicle_spawn: unable to find builtin function", "vehicle_function");
            }

            spawn.add(type.get_float("weight"), std::make_shared<VehicleFunction_builtin>(
                builtin_functions[type.get_string("vehicle_function")]));
        }
        else {
            type.throw_error("load_vehicle_spawn: missing required vehicle_json (object) or vehicle_function (string).");
        }
    }

    spawns[spawn_id] = spawn;
}
Exemplo n.º 5
0
void fault::load_fault( JsonObject &jo )
{
    fault f;

    f.id_ = fault_id( jo.get_string( "id" ) );
    f.name_ = _( jo.get_string( "name" ) );
    f.description_ = _( jo.get_string( "description" ) );

    f.time_ = jo.get_int( "time" );

    auto sk = jo.get_array( "skills" );
    while( sk.has_more() ) {
        auto cur = sk.next_array();
        f.skills_.emplace( skill_id( cur.get_string( 0 ) ), cur.size() >= 2 ? cur.get_int( 1 ) : 1 );
    }

    if( jo.has_string( "requirements" ) ) {
        f.requirements_ = requirement_id( jo.get_string( "requirements" ) );

    } else {
        auto req = jo.get_object( "requirements" );
        const requirement_id req_id( std::string( "inline_fault_" ) + f.id_.str() );
        requirement_data::load_requirement( req, req_id );
        f.requirements_ = req_id;
    }

    if( faults_all.find( f.id_ ) != faults_all.end() ) {
        jo.throw_error( "parsed fault overwrites existing definition", "id" );
    } else {
        faults_all[ f.id_ ] = f;
    }
}
Exemplo n.º 6
0
bool map_bash_info::load(JsonObject &jsobj, std::string member, bool isfurniture) {
    if( jsobj.has_object(member) ) {
        JsonObject j = jsobj.get_object(member);

        if ( jsonint(j, "num_tests", num_tests ) == false ) {
            if ( jsonint(j, "str_min", str_min ) && jsonint(j, "str_max", str_max ) ) {
                num_tests = 1;
            }
        } else if ( num_tests > 0 ) {
            str_min = j.get_int("str_min");
            str_max = j.get_int("str_max");
        }

        jsonint(j, "str_min_blocked", str_min_blocked );
        jsonint(j, "str_max_blocked", str_max_blocked );
        jsonint(j, "str_min_roll", str_min_roll );
        jsonint(j, "chance", chance );
        jsonstring(j, "sound", sound );
        jsonstring(j, "sound_fail", sound_fail );

        if ( jsonstring(j, "ter_set", ter_set ) == false && isfurniture == false ) {
            ter_set = "t_rubble";
            debugmsg("terrain[\"%s\"].bash.ter_set is not set!",jsobj.get_string("id").c_str() );
        }

        if ( j.has_array("items") ) {
            JsonArray ja = j.get_array("items");
            if (ja.size() > 0) {
                int c=0;
                while ( ja.has_more() ) {
                    if ( ja.has_object(c) ) {
                        JsonObject jio = ja.next_object();
                        if ( jio.has_string("item") && jio.has_int("amount") ) {
                            if ( jio.has_int("minamount") ) {
                                map_bash_item_drop drop( jio.get_string("item"), jio.get_int("amount"), jio.get_int("minamount") );
                                jsonint(jio, "chance", drop.chance);
                                items.push_back(drop);
                            } else {
                                map_bash_item_drop drop( jio.get_string("item"), jio.get_int("amount") );
                                jsonint(jio, "chance", drop.chance);
                                items.push_back(drop);
                            }
                        } else {
                            debugmsg("terrain[\"%s\"].bash.items[%d]: invalid entry",jsobj.get_string("id").c_str(),c);
                        }
                    } else {
                        debugmsg("terrain[\"%s\"].bash.items[%d]: invalid entry",jsobj.get_string("id").c_str(),c);
                    }
                    c++;
                }
            }
        }

//debugmsg("%d/%d %s %s/%s %d",str_min,str_max, ter_set.c_str(), sound.c_str(), sound_fail.c_str(), items.size() );
        return true;
    } else {
        return false;
    }
}
Exemplo n.º 7
0
void profession::load( JsonObject &jo, const std::string & )
{
    //If the "name" is an object then we have to deal with gender-specific titles,
    if( jo.has_object( "name" ) ) {
        JsonObject name_obj = jo.get_object( "name" );
        _name_male = pgettext( "profession_male", name_obj.get_string( "male" ).c_str() );
        _name_female = pgettext( "profession_female", name_obj.get_string( "female" ).c_str() );
    } else if( jo.has_string( "name" ) ) {
        // Same profession names for male and female in English.
        // Still need to different names in other languages.
        const std::string name = jo.get_string( "name" );
        _name_female = pgettext( "profession_female", name.c_str() );
        _name_male = pgettext( "profession_male", name.c_str() );
    } else if( !was_loaded ) {
        jo.throw_error( "missing mandatory member \"name\"" );
    }

    if( !was_loaded || jo.has_member( "description" ) ) {
        const std::string desc = jo.get_string( "description" );
        // These also may differ depending on the language settings!
        _description_male = pgettext( "prof_desc_male", desc.c_str() );
        _description_female = pgettext( "prof_desc_female", desc.c_str() );
    }

    mandatory( jo, was_loaded, "points", _point_cost );

    if( !was_loaded || jo.has_member( "items" ) ) {
        JsonObject items_obj = jo.get_object( "items" );

        if( items_obj.has_array( "both" ) ) {
            optional( items_obj, was_loaded, "both", legacy_starting_items, item_reader {} );
        }
        if( items_obj.has_object( "both" ) ) {
            _starting_items = item_group::load_item_group( *items_obj.get_raw( "both" ), "collection" );
        }
        if( items_obj.has_array( "male" ) ) {
            optional( items_obj, was_loaded, "male", legacy_starting_items_male, item_reader {} );
        }
        if( items_obj.has_object( "male" ) ) {
            _starting_items_male = item_group::load_item_group( *items_obj.get_raw( "male" ), "collection" );
        }
        if( items_obj.has_array( "female" ) ) {
            optional( items_obj, was_loaded, "female",  legacy_starting_items_female, item_reader {} );
        }
        if( items_obj.has_object( "female" ) ) {
            _starting_items_female = item_group::load_item_group( *items_obj.get_raw( "female" ),
                                     "collection" );
        }
    }
    optional( jo, was_loaded, "no_bonus", no_bonus );

    optional( jo, was_loaded, "skills", _starting_skills, skilllevel_reader {} );
    optional( jo, was_loaded, "addictions", _starting_addictions, addiction_reader {} );
    // TODO: use string_id<bionic_type> or so
    optional( jo, was_loaded, "CBMs", _starting_CBMs, auto_flags_reader<bionic_id> {} );
    // TODO: use string_id<mutation_branch> or so
    optional( jo, was_loaded, "traits", _starting_traits, auto_flags_reader<trait_id> {} );
    optional( jo, was_loaded, "flags", flags, auto_flags_reader<> {} );
}
Exemplo n.º 8
0
void MonsterGroupManager::LoadMonsterWhitelist( JsonObject &jo )
{
    if( jo.has_string( "mode" ) && jo.get_string( "mode" ) == "EXCLUSIVE" ) {
        monster_whitelist_is_exclusive = true;
    }
    add_to_set( monster_whitelist, jo, "monsters" );
    add_to_set( monster_categories_whitelist, jo, "categories" );
}
Exemplo n.º 9
0
// copypasta: init.cpp
void load_object(JsonObject &jo)
{
    std::string type = jo.get_string("type");
    if ( ! jo.has_string("type") )
    {
        jo.throw_error( "JSON object has no type" );
    }
}
Exemplo n.º 10
0
/**
 *Caches a vehicle definition from a JsonObject to be loaded after itypes is initialized.
 */
void vehicle_prototype::load(JsonObject &jo)
{
    vehicle_prototype &vproto = vtypes[ vproto_id( jo.get_string( "id" ) ) ];
    // If there are already parts defined, this vehicle prototype overrides an existing one.
    // If the json contains a name, it means a completely new prototype (replacing the
    // original one), therefor the old data has to be cleared.
    // If the json does not contain a name (the prototype would have no name), it means appending
    // to the existing prototype (the parts are not cleared).
    if( !vproto.parts.empty() && jo.has_string( "name" ) ) {
        vproto = std::move( vehicle_prototype() );
    }
    if( vproto.parts.empty() ) {
        vproto.name = jo.get_string( "name" );
    }

    vgroups[vgroup_id(jo.get_string("id"))].add_vehicle(vproto_id(jo.get_string("id")), 100);

    JsonArray parts = jo.get_array("parts");
    while (parts.has_more()) {
        JsonObject part = parts.next_object();
        const point pxy( part.get_int("x"), part.get_int("y") );
        const vpart_str_id pid( part.get_string( "part" ) );
        vproto.parts.emplace_back( pxy, pid );
    }

    JsonArray items = jo.get_array("items");
    while(items.has_more()) {
        JsonObject spawn_info = items.next_object();
        vehicle_item_spawn next_spawn;
        next_spawn.pos.x = spawn_info.get_int("x");
        next_spawn.pos.y = spawn_info.get_int("y");
        next_spawn.chance = spawn_info.get_int("chance");
        if(next_spawn.chance <= 0 || next_spawn.chance > 100) {
            debugmsg("Invalid spawn chance in %s (%d, %d): %d%%",
                     vproto.name.c_str(), next_spawn.pos.x, next_spawn.pos.y, next_spawn.chance);
        }
        if(spawn_info.has_array("items")) {
            //Array of items that all spawn together (ie jack+tire)
            JsonArray item_group = spawn_info.get_array("items");
            while(item_group.has_more()) {
                next_spawn.item_ids.push_back(item_group.next_string());
            }
        } else if(spawn_info.has_string("items")) {
            //Treat single item as array
            next_spawn.item_ids.push_back(spawn_info.get_string("items"));
        }
        if(spawn_info.has_array("item_groups")) {
            //Pick from a group of items, just like map::place_items
            JsonArray item_group_names = spawn_info.get_array("item_groups");
            while(item_group_names.has_more()) {
                next_spawn.item_groups.push_back(item_group_names.next_string());
            }
        } else if(spawn_info.has_string("item_groups")) {
            next_spawn.item_groups.push_back(spawn_info.get_string("item_groups"));
        }
        vproto.item_spawns.push_back( std::move( next_spawn ) );
    }
}
Exemplo n.º 11
0
void assign_function( JsonObject &jo, const std::string &id, Fun &target, const std::map<std::string, Fun> &cont )
{
    if( jo.has_string( id ) ) {
        const auto iter = cont.find( jo.get_string( id ) );
        if( iter != cont.end() ) {
            target = iter->second;
        } else {
            jo.throw_error( "Invalid mission function", id );
        }
    }
}
Exemplo n.º 12
0
// copypasta: init.cpp
void load_object(JsonObject &jo)
{
    std::string type = jo.get_string("type");
    if ( ! jo.has_string("type") )
    {
        std::stringstream err;
        err << jo.line_number() << ": ";
        err << "JSON object has no type";
        throw err.str();
    }
}
Exemplo n.º 13
0
void npc_favor::deserialize(JsonIn &jsin)
{
    JsonObject jo = jsin.get_object();
    type = npc_favor_type(jo.get_int("type"));
    jo.read("value", value);
    jo.read("itype_id", item_id);
    skill = NULL;
    if (jo.has_int("skill_id")) {
        skill = Skill::skill(jo.get_int("skill_id"));
    } else if (jo.has_string("skill_id")) {
        skill = Skill::skill(jo.get_string("skill_id"));
    }
}
Exemplo n.º 14
0
damage_instance load_damage_instance( JsonObject &jo )
{
    damage_instance di;
    if( jo.has_array( "values" ) ) {
        JsonArray jarr = jo.get_array( "values" );
        while( jarr.has_more() ) {
            JsonObject curr = jarr.next_object();
            di.damage_units.push_back( load_damage_unit( curr ) );
        }
    } else if( jo.has_string( "damage_type" ) ) {
        di.damage_units.push_back( load_damage_unit( jo ) );
    }

    return di;
}
Exemplo n.º 15
0
VehicleFunction_json::VehicleFunction_json(JsonObject &jo)
    : vehicle(jo.get_string("vehicle")),
    number(jo, "number"),
    fuel(jo.get_int("fuel")),
    status(jo.get_int("status"))
{
    if(jo.has_string("placement")) {
        placement = jo.get_string("placement");
    }
    else {
        //location = std::make_unique<Vehicle_Location>(jmapgen_int(jo, "x"), jmapgen_int(jo, "y"), facings);
        // that would be better, but it won't exist until c++14, so for now we do this:
        VehicleFacings facings(jo, "facing");
        location.reset(new VehicleLocation(jmapgen_int(jo, "x"), jmapgen_int(jo, "y"), facings));
    }
}
Exemplo n.º 16
0
static mut_attack load_mutation_attack( JsonObject &jo )
{
    mut_attack ret;
    jo.read( "attack_text_u", ret.attack_text_u );
    jo.read( "attack_text_npc", ret.attack_text_npc );
    jo.read( "required_mutations", ret.required_mutations );
    jo.read( "blocker_mutations", ret.blocker_mutations );
    jo.read( "hardcoded_effect", ret.hardcoded_effect );

    if( jo.has_string( "body_part" ) ) {
        ret.bp = get_body_part_token( jo.get_string( "body_part" ) );
    }

    jo.read( "chance", ret.chance );

    if( jo.has_array( "base_damage" ) ) {
        JsonArray jo_dam = jo.get_array( "base_damage" );
        ret.base_damage = load_damage_instance( jo_dam );
    } else if( jo.has_object( "base_damage" ) ) {
        JsonObject jo_dam = jo.get_object( "base_damage" );
        ret.base_damage = load_damage_instance( jo_dam );
    }

    if( jo.has_array( "strength_damage" ) ) {
        JsonArray jo_dam = jo.get_array( "strength_damage" );
        ret.strength_damage = load_damage_instance( jo_dam );
    } else if( jo.has_object( "strength_damage" ) ) {
        JsonObject jo_dam = jo.get_object( "strength_damage" );
        ret.strength_damage = load_damage_instance( jo_dam );
    }

    if( ret.attack_text_u.empty() || ret.attack_text_npc.empty() ) {
        jo.throw_error( "Attack message unset" );
    }

    if( !ret.hardcoded_effect && ret.base_damage.empty() && ret.strength_damage.empty() ) {
        jo.throw_error( "Damage unset" );
    } else if( ret.hardcoded_effect && ( !ret.base_damage.empty() || !ret.strength_damage.empty() ) ) {
        jo.throw_error( "Damage and hardcoded effect are both set (must be one, not both)" );
    }

    if( ret.chance <= 0 ) {
        jo.throw_error( "Chance of procing must be set and positive" );
    }

    return ret;
}
Exemplo n.º 17
0
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];
}
Exemplo n.º 18
0
unsigned Item_factory::flags_from_json(JsonObject& jo, std::string member, std::string flag_type)
{
    //If none is found, just use the standard none action
    unsigned flag = 0;
    //Otherwise, grab the right label to look for
    if ( jo.has_array(member) ) {
        JsonArray jarr = jo.get_array(member);
        while (jarr.has_more()){
            set_flag_by_string(flag, jarr.next_string(), flag_type);
        }
    } else if ( jo.has_string(member) ) {
        //we should have gotten a string, if not an array
        set_flag_by_string(flag, jo.get_string(member), flag_type);
    }

    return flag;
}
Exemplo n.º 19
0
void json_item_substitution::do_load( JsonObject &jo )
{
    const bool item_mode = jo.has_string( "item" );
    const std::string title = jo.get_string( item_mode ? "item" : "trait" );

    auto check_duplicate_item = [&]( const itype_id & it ) {
        return substitutions.find( it ) != substitutions.end() ||
               std::find_if( bonuses.begin(), bonuses.end(),
        [&it]( const std::pair<itype_id, trait_requirements> &p ) {
            return p.first == it;
        } ) != bonuses.end();
    };
    if( item_mode && check_duplicate_item( title ) ) {
        jo.throw_error( "Duplicate definition of item" );
    }

    if( jo.has_array( "bonus" ) ) {
        if( !item_mode ) {
            jo.throw_error( "Bonuses can only be used in item mode" );
        }
        JsonArray arr = jo.get_array( "bonus" );
        bonuses.emplace_back( title, trait_requirements::load( arr ) );
    } else if( !jo.has_array( "sub" ) ) {
        jo.throw_error( "Missing sub array" );
    }

    JsonArray sub = jo.get_array( "sub" );
    while( sub.has_more() ) {
        JsonArray line = sub.next_array();
        substitution s;
        const itype_id old_it = item_mode ? title : line.next_string();
        if( item_mode ) {
            s.trait_reqs = trait_requirements::load( line );
        } else {
            if( check_duplicate_item( old_it ) ) {
                line.throw_error( "Duplicate definition of item" );
            }
            s.trait_reqs.present.push_back( trait_id( title ) );
        }
        // Error if the array doesn't have at least one new_item
        do {
            s.infos.push_back( substitution::info::load( line ) );
        } while( line.has_more() );
        substitutions[old_it].push_back( s );
    }
}
Exemplo n.º 20
0
void translation::deserialize( JsonIn &jsin )
{
    if( jsin.test_string() ) {
        ctxt = cata::nullopt;
        raw = jsin.get_string();
        needs_translation = true;
    } else {
        JsonObject jsobj = jsin.get_object();
        if( jsobj.has_string( "ctxt" ) ) {
            ctxt = jsobj.get_string( "ctxt" );
        } else {
            ctxt = cata::nullopt;
        }
        raw = jsobj.get_string( "str" );
        needs_translation = true;
    }
}
void mattack_actor::load( JsonObject &jo, const std::string &src )
{
    bool strict = src == "dda";

    // Legacy support
    if( !jo.has_string( "id" ) ) {
        id = jo.get_string( "type" );
    } else {
        // Loading ids can't be strict at the moment, since it has to match the stored version
        assign( jo, "id", id, false );
    }

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

    load_internal( jo, src );
    // Set was_loaded manually because we don't have generic_factory to do it for us
    was_loaded = true;
}
Exemplo n.º 22
0
void requirement_data::load_requirement( JsonObject &jsobj, const std::string &id )
{
    requirement_data req;

    JsonArray jsarr;
    jsarr = jsobj.get_array( "components" );
    req.load_obj_list( jsarr, req.components );
    jsarr = jsobj.get_array( "qualities" );
    req.load_obj_list( jsarr, req.qualities );
    jsarr = jsobj.get_array( "tools" );
    req.load_obj_list( jsarr, req.tools );

    if( !id.empty() ) {
        req.id_ = requirement_id( id );
    } else if( jsobj.has_string( "id" ) ) {
        req.id_ = requirement_id( jsobj.get_string( "id" ) );
    } else {
        jsobj.throw_error( "id was not specified for requirement" );
    }

    save_requirement( req );
}
Exemplo n.º 23
0
void load_season_array( JsonObject &jo, const std::string &key, C &container, F load_func )
{
    if( jo.has_string( key ) ) {
        container.fill( load_func( jo.get_string( key ) ) );

    } else if( jo.has_array( key ) ) {
        auto arr = jo.get_array( key );
        if( arr.size() == 1 ) {
            container.fill( load_func( arr.get_string( 0 ) ) );

        } else if( arr.size() == container.size() ) {
            for( auto &e : container ) {
                e = load_func( arr.next_string() );
            }

        } else {
            jo.throw_error( "Incorrect number of entries", key );
        }

    } else {
        jo.throw_error( "Expected string or array", key );
    }
}
Exemplo n.º 24
0
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() );
        }
    }
}
Exemplo n.º 25
0
void mission_type::load( JsonObject &jo, const std::string &src )
{
    const bool strict = src == "dda";

    mandatory( jo, was_loaded, "name", name );

    mandatory( jo, was_loaded, "difficulty", difficulty );
    mandatory( jo, was_loaded, "value", value );

    if( jo.has_member( "origins" ) ) {
        origins.clear();
        for( auto &m : jo.get_tags( "origins" ) ) {
            origins.emplace_back( io::string_to_enum_look_up( io::origin_map, m ) );
        }
    }

    if( std::any_of( origins.begin(), origins.end(), []( mission_origin origin ) {
    return origin == ORIGIN_ANY_NPC || origin == ORIGIN_OPENER_NPC || origin == ORIGIN_SECONDARY;
} ) ) {
        auto djo = jo.get_object( "dialogue" );
        // TODO: There should be a cleaner way to do it
        mandatory( djo, was_loaded, "describe", dialogue[ "describe" ] );
        mandatory( djo, was_loaded, "offer", dialogue[ "offer" ] );
        mandatory( djo, was_loaded, "accepted", dialogue[ "accepted" ] );
        mandatory( djo, was_loaded, "rejected", dialogue[ "rejected" ] );
        mandatory( djo, was_loaded, "advice", dialogue[ "advice" ] );
        mandatory( djo, was_loaded, "inquire", dialogue[ "inquire" ] );
        mandatory( djo, was_loaded, "success", dialogue[ "success" ] );
        mandatory( djo, was_loaded, "success_lie", dialogue[ "success_lie" ] );
        mandatory( djo, was_loaded, "failure", dialogue[ "failure" ] );
    }

    optional( jo, was_loaded, "urgent", urgent );
    optional( jo, was_loaded, "item", item_id );
    optional( jo, was_loaded, "count", item_count, 1 );

    goal = jo.get_enum_value<decltype( goal )>( "goal" );

    assign_function( jo, "place", place, tripoint_function_map );
    if( jo.has_string( "start" ) ) {
        assign_function( jo, "start", start, mission_function_map );
    } else if( jo.has_member( "start" ) ) {
        JsonObject j_start = jo.get_object( "start" );
        parse_start( j_start );
    }
    assign_function( jo, "end", end, mission_function_map );
    assign_function( jo, "fail", fail, mission_function_map );

    assign( jo, "deadline_low", deadline_low, false, 1_days );
    assign( jo, "deadline_high", deadline_high, false, 1_days );

    if( jo.has_member( "followup" ) ) {
        follow_up = mission_type_id( jo.get_string( "followup" ) );
    }

    if( jo.has_member( "monster_species" ) ) {
        monster_species = species_id( jo.get_string( "monster_species" ) );
    }
    if( jo.has_member( "monster_type" ) ) {
        monster_type = mtype_id( jo.get_string( "monster_type" ) );
    }

    if( jo.has_member( "monster_kill_goal" ) ) {
        monster_kill_goal = jo.get_int( "monster_kill_goal" );
    }

    assign( jo, "destination", target_id, strict );
}
Exemplo n.º 26
0
void recipe::load( JsonObject &jo, const std::string &src )
{
    bool strict = src == "dda";

    abstract = jo.has_string( "abstract" );

    if( abstract ) {
        ident_ = recipe_id( jo.get_string( "abstract" ) );
    } else {
        result_ = jo.get_string( "result" );
        ident_ = recipe_id( result_ );
    }

    assign( jo, "time", time, strict, 0 );
    assign( jo, "difficulty", difficulty, strict, 0, MAX_SKILL );
    assign( jo, "flags", flags );

    // automatically set contained if we specify as container
    assign( jo, "contained", contained, strict );
    contained |= assign( jo, "container", container, strict );

    if( jo.has_array( "batch_time_factors" ) ) {
        auto batch = jo.get_array( "batch_time_factors" );
        batch_rscale = batch.get_int( 0 ) / 100.0;
        batch_rsize  = batch.get_int( 1 );
    }

    assign( jo, "charges", charges );
    assign( jo, "result_mult", result_mult );

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

    if( jo.has_member( "skills_required" ) ) {
        auto sk = jo.get_array( "skills_required" );
        required_skills.clear();

        if( sk.empty() ) {
            // clear all requirements

        } else if( sk.has_array( 0 ) ) {
            // multiple requirements
            while( sk.has_more() ) {
                auto arr = sk.next_array();
                required_skills[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 );
            }

        } else {
            // single requirement
            required_skills[skill_id( sk.get_string( 0 ) )] = sk.get_int( 1 );
        }
    }

    // simplified autolearn sets requirements equal to required skills at finalization
    if( jo.has_bool( "autolearn" ) ) {
        assign( jo, "autolearn", autolearn );

    } else if( jo.has_array( "autolearn" ) ) {
        autolearn = true;
        auto sk = jo.get_array( "autolearn" );
        while( sk.has_more() ) {
            auto arr = sk.next_array();
            autolearn_requirements[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 );
        }
    }

    if( jo.has_member( "decomp_learn" ) ) {
        learn_by_disassembly.clear();

        if( jo.has_int( "decomp_learn" ) ) {
            if( !skill_used ) {
                jo.throw_error( "decomp_learn specified with no skill_used" );
            }
            assign( jo, "decomp_learn", learn_by_disassembly[skill_used] );

        } else if( jo.has_array( "decomp_learn" ) ) {
            auto sk = jo.get_array( "decomp_learn" );
            while( sk.has_more() ) {
                auto arr = sk.next_array();
                learn_by_disassembly[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 );
            }
        }
    }

    if( jo.has_member( "book_learn" ) ) {
        auto bk = jo.get_array( "book_learn" );
        booksets.clear();

        while( bk.has_more() ) {
            auto arr = bk.next_array();
            booksets.emplace( arr.get_string( 0 ), arr.size() > 1 ? arr.get_int( 1 ) : -1 );
        }
    }

    // recipes not specifying any external requirements inherit from their parent recipe (if any)
    if( jo.has_string( "using" ) ) {
        reqs_external = { { requirement_id( jo.get_string( "using" ) ), 1 } };

    } else if( jo.has_array( "using" ) ) {
        auto arr = jo.get_array( "using" );
        reqs_external.clear();

        while( arr.has_more() ) {
            auto cur = arr.next_array();
            reqs_external.emplace_back( requirement_id( cur.get_string( 0 ) ), cur.get_int( 1 ) );
        }
    }

    const std::string type = jo.get_string( "type" );

    if( type == "recipe" ) {
        if( jo.has_string( "id_suffix" ) ) {
            if( abstract ) {
                jo.throw_error( "abstract recipe cannot specify id_suffix", "id_suffix" );
            }
            ident_ = recipe_id( ident_.str() + "_" + jo.get_string( "id_suffix" ) );
        }

        assign( jo, "category", category, strict );
        assign( jo, "subcategory", subcategory, strict );
        assign( jo, "reversible", reversible, strict );

        if( jo.has_member( "byproducts" ) ) {
            auto bp = jo.get_array( "byproducts" );
            byproducts.clear();
            while( bp.has_more() ) {
                auto arr = bp.next_array();
                byproducts[ arr.get_string( 0 ) ] += arr.size() == 2 ? arr.get_int( 1 ) : 1;
            }
        }
    } else if( type == "uncraft" ) {
        reversible = true;
    } else {
        jo.throw_error( "unknown recipe type", "type" );
    }

    // inline requirements are always replaced (cannot be inherited)
    const auto req_id = string_format( "inline_%s_%s", type.c_str(), ident_.c_str() );
    requirement_data::load_requirement( jo, req_id );
    reqs_internal = { { requirement_id( req_id ), 1 } };
}
Exemplo n.º 27
0
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;
}
Exemplo n.º 28
0
void recipe_dictionary::load( JsonObject &jo, const std::string &src, bool uncraft )
{
    bool strict = src == "core";

    recipe r;

    // defer entries dependent upon as-yet unparsed definitions
    if( jo.has_string( "copy-from" ) ) {
        auto base = jo.get_string( "copy-from" );
        if( uncraft ) {
            if( !recipe_dict.uncraft.count( base ) ) {
                deferred.emplace_back( jo.str(), src );
                return;
            }
            r = recipe_dict.uncraft[ base ];
        } else {
            if( !recipe_dict.recipes.count( base ) ) {
                deferred.emplace_back( jo.str(), src );
                return;
            }
            r = recipe_dict.recipes[ base ];
        }
    }

    if( jo.has_string( "abstract" ) ) {
        r.ident_ = jo.get_string( "abstract" );
        r.abstract = true;
    } else {
        r.ident_ = r.result = jo.get_string( "result" );
        r.abstract = false;
    }

    if( !uncraft ) {
        if( jo.has_string( "id_suffix" ) ) {
            if( r.abstract ) {
                jo.throw_error( "abstract recipe cannot specify id_suffix", "id_suffix" );
            }
            r.ident_ += "_" + jo.get_string( "id_suffix" );
        }
        assign( jo, "category", r.category, strict );
        assign( jo, "subcategory", r.subcategory, strict );
        assign( jo, "reversible", r.reversible, strict );
    } else {
        r.reversible = true;
    }

    assign( jo, "time", r.time, strict, 0 );
    assign( jo, "difficulty", r.difficulty, strict, 0, MAX_SKILL );
    assign( jo, "flags", r.flags );

    // automatically set contained if we specify as container
    assign( jo, "contained", r.contained, strict );
    r.contained |= assign( jo, "container", r.container, strict );

    if( jo.has_array( "batch_time_factors" ) ) {
        auto batch = jo.get_array( "batch_time_factors" );
        r.batch_rscale = batch.get_int( 0 ) / 100.0;
        r.batch_rsize  = batch.get_int( 1 );
    }

    assign( jo, "charges", r.charges );
    assign( jo, "result_mult", r.result_mult );

    assign( jo, "skill_used", r.skill_used, strict );

    if( jo.has_member( "skills_required" ) ) {
        auto sk = jo.get_array( "skills_required" );
        r.required_skills.clear();

        if( sk.empty() ) {
            // clear all requirements

        } else if( sk.has_array( 0 ) ) {
            // multiple requirements
            while( sk.has_more() ) {
                auto arr = sk.next_array();
                r.required_skills[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 );
            }

        } else {
            // single requirement
            r.required_skills[skill_id( sk.get_string( 0 ) )] = sk.get_int( 1 );
        }
    }

    // simplified autolearn sets requirements equal to required skills at finalization
    if( jo.has_bool( "autolearn" ) ) {
        assign( jo, "autolearn", r.autolearn );

    } else if( jo.has_array( "autolearn" ) ) {
        r.autolearn = true;
        auto sk = jo.get_array( "autolearn" );
        while( sk.has_more() ) {
            auto arr = sk.next_array();
            r.autolearn_requirements[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 );
        }
    }

    if( jo.has_member( "decomp_learn" ) ) {
        r.learn_by_disassembly.clear();

        if( jo.has_int( "decomp_learn" ) ) {
            if( !r.skill_used ) {
                jo.throw_error( "decomp_learn specified with no skill_used" );
            }
            assign( jo, "decomp_learn", r.learn_by_disassembly[r.skill_used] );

        } else if( jo.has_array( "decomp_learn" ) ) {
            auto sk = jo.get_array( "decomp_learn" );
            while( sk.has_more() ) {
                auto arr = sk.next_array();
                r.learn_by_disassembly[skill_id( arr.get_string( 0 ) )] = arr.get_int( 1 );
            }
        }
    }

    if( !uncraft && jo.has_member( "byproducts" ) ) {
        auto bp = jo.get_array( "byproducts" );
        r.byproducts.clear();
        while( bp.has_more() ) {
            auto arr = bp.next_array();
            r.byproducts[ arr.get_string( 0 ) ] += arr.size() == 2 ? arr.get_int( 1 ) : 1;
        }
    }

    if( jo.has_member( "book_learn" ) ) {
        auto bk = jo.get_array( "book_learn" );
        r.booksets.clear();

        while( bk.has_more() ) {
            auto arr = bk.next_array();
            r.booksets.emplace( arr.get_string( 0 ), arr.get_int( 1 ) );
        }
    }

    // recipes not specifying any external requirements inherit from their parent recipe (if any)
    if( jo.has_string( "using" ) ) {
        r.reqs_external = { { requirement_id( jo.get_string( "using" ) ), 1 } };

    } else if( jo.has_array( "using" ) ) {
        auto arr = jo.get_array( "using" );
        r.reqs_external.clear();

        while( arr.has_more() ) {
            auto cur = arr.next_array();
            r.reqs_external.emplace_back( requirement_id( cur.get_string( 0 ) ), cur.get_int( 1 ) );
        }
    }

    // inline requirements are always replaced (cannot be inherited)
    auto req_id = string_format( "inline_%s_%s", uncraft ? "uncraft" : "recipe", r.ident_.c_str() );
    requirement_data::load_requirement( jo, req_id );
    r.reqs_internal = { { requirement_id( req_id ), 1 } };

    if( uncraft ) {
        recipe_dict.uncraft[ r.ident_ ] = r;
    } else {
        recipe_dict.recipes[ r.ident_ ] = r;
    }
}
Exemplo n.º 29
0
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;
    }
}
Exemplo n.º 30
0
/**
 * Reads in a vehicle part from a JsonObject.
 */
void vpart_info::load( JsonObject &jo, const std::string &src )
{
    vpart_info def;

    if( jo.has_string( "copy-from" ) ) {
        auto const base = vpart_info_all.find( vpart_id( jo.get_string( "copy-from" ) ) );
        auto const ab = abstract_parts.find( vpart_id( jo.get_string( "copy-from" ) ) );
        if( base != vpart_info_all.end() ) {
            def = base->second;
        } else if( ab != abstract_parts.end() ) {
            def = ab->second;
        } else {
            deferred.emplace_back( jo.str(), src );
            return;
        }
    }

    if( jo.has_string( "abstract" ) ) {
        def.id = vpart_id( jo.get_string( "abstract" ) );
    } else {
        def.id = vpart_id( jo.get_string( "id" ) );
    }

    assign( jo, "name", def.name_ );
    assign( jo, "item", def.item );
    assign( jo, "location", def.location );
    assign( jo, "durability", def.durability );
    assign( jo, "damage_modifier", def.dmg_mod );
    assign( jo, "power", def.power );
    assign( jo, "epower", def.epower );
    assign( jo, "fuel_type", def.fuel_type );
    assign( jo, "default_ammo", def.default_ammo );
    assign( jo, "folded_volume", def.folded_volume );
    assign( jo, "size", def.size );
    assign( jo, "difficulty", def.difficulty );
    assign( jo, "bonus", def.bonus );
    assign( jo, "flags", def.flags );

    if( jo.has_member( "requirements" ) ) {
        auto reqs = jo.get_object( "requirements" );

        parse_vp_reqs( reqs, def.id.str(), "install", def.install_reqs, def.install_skills, def.install_moves );
        parse_vp_reqs( reqs, def.id.str(), "removal", def.removal_reqs, def.removal_skills, def.removal_moves );
        parse_vp_reqs( reqs, def.id.str(), "repair",  def.repair_reqs,  def.repair_skills,  def.repair_moves  );

        def.legacy = false;
    }

    if( jo.has_member( "symbol" ) ) {
        def.sym = jo.get_string( "symbol" )[ 0 ];
    }
    if( jo.has_member( "broken_symbol" ) ) {
        def.sym_broken = jo.get_string( "broken_symbol" )[ 0 ];
    }

    if( jo.has_member( "color" ) ) {
        def.color = color_from_string( jo.get_string( "color" ) );
    }
    if( jo.has_member( "broken_color" ) ) {
        def.color_broken = color_from_string( jo.get_string( "broken_color" ) );
    }

    if( jo.has_member( "breaks_into" ) ) {
        JsonIn& stream = *jo.get_raw( "breaks_into" );
        def.breaks_into_group = item_group::load_item_group( stream, "collection" );
    }

    auto qual = jo.get_array( "qualities" );
    if( !qual.empty() ) {
        def.qualities.clear();
        while( qual.has_more() ) {
            auto pair = qual.next_array();
            def.qualities[ quality_id( pair.get_string( 0 ) ) ] = pair.get_int( 1 );
        }
    }

    if( jo.has_member( "damage_reduction" ) ) {
        JsonObject dred = jo.get_object( "damage_reduction" );
        def.damage_reduction = load_damage_array( dred );
    } else {
        def.damage_reduction.fill( 0.0f );
    }

    if( jo.has_string( "abstract" ) ) {
        abstract_parts[def.id] = def;
    } else {
        vpart_info_all[def.id] = def;
    }
}