diff --git a/data/json/terrain.json b/data/json/terrain.json index 91faddee7c9d0..182512f6a5e57 100644 --- a/data/json/terrain.json +++ b/data/json/terrain.json @@ -958,6 +958,10 @@ },{ "type" : "terrain", "id" : "t_wall", + "aliases" : [ + "t_wall_h", + "t_wall_v" + ], "name": "wall", "symbol": "LINE_OXOX", "color": "ltgray", @@ -974,6 +978,10 @@ },{ "type" : "terrain", "id" : "t_concrete_wall", + "aliases" : [ + "t_concrete_h", + "t_concrete_v" + ], "name": "concrete wall", "symbol": "LINE_OXOX", "color": "dkgray", @@ -993,6 +1001,10 @@ },{ "type" : "terrain", "id" : "t_wall_metal", + "aliases" : [ + "t_wall_metal_h", + "t_wall_metal_v" + ], "name": "metal wall", "symbol": "LINE_OXOX", "color": "cyan", @@ -1013,6 +1025,10 @@ },{ "type" : "terrain", "id" : "t_wall_glass", + "aliases" : [ + "t_wall_glass_h", + "t_wall_glass_v" + ], "name": "glass wall", "symbol": "LINE_OXOX", "color": "ltcyan", @@ -1032,6 +1048,10 @@ },{ "type" : "terrain", "id" : "t_wall_glass_alarm", + "aliases" : [ + "t_wall_glass_h_alarm", + "t_wall_glass_v_alarm" + ], "name": "glass wall", "symbol": "LINE_OXOX", "color": "ltcyan", @@ -1052,6 +1072,10 @@ },{ "type" : "terrain", "id" : "t_reinforced_glass", + "aliases" : [ + "t_reinforced_glass_h", + "t_reinforced_glass_v" + ], "name": "reinforced glass", "symbol": "LINE_OXOX", "color": "ltcyan", @@ -3786,6 +3810,10 @@ },{ "type" : "terrain", "id" : "t_fungus_wall", + "aliases" : [ + "t_fungus_wall_h", + "t_fungus_wall_v" + ], "name": "fungal wall", "symbol": "O", "color": "dkgray", @@ -5137,6 +5165,10 @@ },{ "type" : "terrain", "id" : "t_wall_r", + "aliases" : [ + "t_wall_h_r", + "t_wall_v_r" + ], "name": "red wall", "symbol": "LINE_OXOX", "color": "red", @@ -5152,6 +5184,10 @@ },{ "type" : "terrain", "id" : "t_wall_w", + "aliases" : [ + "t_wall_h_w", + "t_wall_v_w" + ], "name": "white wall", "symbol": "LINE_OXOX", "color": "white", @@ -5167,6 +5203,10 @@ },{ "type" : "terrain", "id" : "t_wall_b", + "aliases" : [ + "t_wall_h_b", + "t_wall_v_b" + ], "name": "blue wall", "symbol": "LINE_OXOX", "color": "blue", @@ -5182,6 +5222,10 @@ },{ "type" : "terrain", "id" : "t_wall_g", + "aliases" : [ + "t_wall_h_g", + "t_wall_v_g" + ], "name": "green wall", "symbol": "LINE_OXOX", "color": "green", @@ -5197,6 +5241,10 @@ },{ "type" : "terrain", "id" : "t_wall_y", + "aliases" : [ + "t_wall_h_y", + "t_wall_v_y" + ], "name": "yellow wall", "symbol": "LINE_OXOX", "color": "yellow", @@ -5212,6 +5260,10 @@ },{ "type" : "terrain", "id" : "t_wall_p", + "aliases" : [ + "t_wall_h_p", + "t_wall_v_p" + ], "name": "purple wall", "symbol": "LINE_OXOX", "color": "magenta", diff --git a/data/mods/No_Fungi/terrain.json b/data/mods/No_Fungi/terrain.json index d0f27f3f86373..8d1dbc02364e9 100644 --- a/data/mods/No_Fungi/terrain.json +++ b/data/mods/No_Fungi/terrain.json @@ -2,6 +2,7 @@ { "type" : "terrain", "id" : "t_marloss", + "edit-mode" : "override", "name": "marloss bush", "symbol": "#", "color": "dkgray", @@ -16,6 +17,7 @@ },{ "type" : "terrain", "id" : "t_marloss_tree", + "edit-mode" : "override", "name": "marloss tree", "symbol": "7", "color": "dkgray", diff --git a/lua/class_definitions.lua b/lua/class_definitions.lua index ee8bc794402f9..706a97472075e 100644 --- a/lua/class_definitions.lua +++ b/lua/class_definitions.lua @@ -1425,7 +1425,7 @@ classes = { attributes = { close = { type = "ter_str_id", writable = true }, - harvest_season = { type = "int", writable = true }, + harvest_season = { type = "season_type", writable = true }, harvestable = { type = "string", writable = true }, name = { type = "string", writable = false }, open = { type = "ter_str_id", writable = true }, diff --git a/src/cata_tiles.cpp b/src/cata_tiles.cpp index 42af38a1c884f..acca8f41bf46e 100644 --- a/src/cata_tiles.cpp +++ b/src/cata_tiles.cpp @@ -2727,8 +2727,8 @@ void cata_tiles::do_tile_loading_report() { //TODO: exclude fake items from Item_factory::init_old() tile_loading_report(item_controller->get_all_itypes(), "Items", ""); auto mtypes = MonsterGenerator::generator().get_all_mtypes(); - lr_generic( mtypes.begin(), mtypes.end(), []( std::vector::iterator m ) { - return ( *m )->id.str(); + lr_generic( mtypes.begin(), mtypes.end(), []( const std::vector::iterator &m ) { + return ( *m ).id.str(); }, "Monsters", "" ); tile_loading_report(vpart_info::get_all().size(), "Vehicle Parts", "vp_"); tile_loading_report(trap::count(), "Traps", ""); diff --git a/src/catalua.cpp b/src/catalua.cpp index ab217b2a4bb01..6edd482557212 100644 --- a/src/catalua.cpp +++ b/src/catalua.cpp @@ -978,7 +978,7 @@ static int game_get_item_groups(lua_State *L) // monster_types = game.get_monster_types() static int game_get_monster_types(lua_State *L) { - std::vector mtypes = MonsterGenerator::generator().get_all_mtypes(); + const auto mtypes = MonsterGenerator::generator().get_all_mtypes(); lua_createtable(L, mtypes.size(), 0); // Preallocate enough space for all our monster types. @@ -992,7 +992,7 @@ static int game_get_monster_types(lua_State *L) // lua_rawset then does t[k] = v and pops v and k from the stack lua_pushnumber(L, i + 1); - LuaValue::push( L, mtypes[i]->id ); + LuaValue::push( L, mtypes[i].id ); lua_rawset(L, -3); } diff --git a/src/defense.cpp b/src/defense.cpp index 006343806274d..afd0846767142 100644 --- a/src/defense.cpp +++ b/src/defense.cpp @@ -179,7 +179,7 @@ void defense_game::game_over() void defense_game::init_mtypes() { for( auto &type : MonsterGenerator::generator().get_all_mtypes() ) { - mtype *const t = const_cast( type ); + mtype *const t = const_cast( &type ); t->difficulty *= 1.5; t->difficulty += int( t->difficulty / 5 ); t->flags.insert( MF_BASHES ); diff --git a/src/game.cpp b/src/game.cpp index 9b20582ec59d2..adc52e36ddaa2 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1111,8 +1111,8 @@ bool game::cleanup_at_end() int iTotalKills = 0; for( const auto &type : MonsterGenerator::generator().get_all_mtypes() ) { - if( kill_count( type->id ) > 0 ) { - iTotalKills += kill_count( type->id ); + if( kill_count( type.id ) > 0 ) { + iTotalKills += kill_count( type.id ); } } diff --git a/src/gates.cpp b/src/gates.cpp index 6c49b4120c3a7..def08b11c8a75 100644 --- a/src/gates.cpp +++ b/src/gates.cpp @@ -17,9 +17,9 @@ using gate_id = string_id; struct gate_data { gate_data() : - wall( NULL_ID ), - door( NULL_ID ), - floor( NULL_ID ), + wall(), + door(), + floor(), moves( 0 ), bash_dmg( 0 ), was_loaded( false ) {}; diff --git a/src/generic_factory.h b/src/generic_factory.h index ccb313a211aad..e7d16cabdbf7c 100644 --- a/src/generic_factory.h +++ b/src/generic_factory.h @@ -2,6 +2,7 @@ #define H_GENERIC_FACTORY #include "string_id.h" +#include "int_id.h" #include #include @@ -34,6 +35,9 @@ can be by it to implement its interface. - a `was_loaded` member of type `bool`, which must have the value `false` before the first call to `load`. + The type can also have: + - a 'check()' function (to run `generic_factory::check()` on all objects) + Those things must be visible from the factory, you may have to add this class as friend if necessary. @@ -103,25 +107,80 @@ const my_class &string_id::obj() const \endcode */ + +template +class string_id_reader; + template class generic_factory { protected: - std::unordered_map< string_id, T> data; + std::vector list; + std::unordered_map, int_id> map; std::string type_name; std::string id_member_name; + std::string alias_member_name; T &load_override( const string_id &id, JsonObject &jo ) { T obj; + obj.id = id; obj.load( jo ); obj.was_loaded = true; - T &result = data[id]; - result = std::move( obj ); - return result; + + T &inserted_obj = insert( obj ); + + if( !alias_member_name.empty() && jo.has_member( alias_member_name ) ) { + const int_id i_id = map[id]; + std::vector> aliases; + + mandatory( jo, obj.was_loaded, alias_member_name, aliases, string_id_reader {} ); + + for( const auto &alias : aliases ) { + if( map.count( alias ) > 0 ) { + jo.throw_error( "duplicate " + type_name + " alias \"" + alias.str() + "\" in \"" + id.str() + + "\"" ); + } + map[alias] = i_id; + } + } + + return inserted_obj; + } + + bool find_id( const string_id &id, int_id &result ) const { + result = id.get_cid(); + if( is_valid( result ) && list[result].id == id ) { + return true; + } + const auto iter = map.find( id ); + if( iter == map.end() ) { + return false; + } + result = iter->second; + id.set_cid( result ); + return true; } + void remove_aliases( const string_id &id ) { + int_id i_id; + if( !find_id( id, i_id ) ) { + return; + } + auto iter = map.begin(); + const auto end = map.end(); + for( ; iter != end; ) { + if( iter->second == i_id && iter->first != id ) { + map.erase( iter++ ); + } else { + ++iter; + } + } + } + + const T dummy_obj; + public: /** * @param type_name A string used in debug messages as the name of `T`, @@ -129,8 +188,11 @@ class generic_factory * @param id_member_name The name of the JSON member that contains the id of the * loaded object. */ - generic_factory( const std::string &type_name, const std::string &id_member_name = "id" ) - : type_name( type_name ), id_member_name( id_member_name ) { + generic_factory( const std::string &type_name, const std::string &id_member_name = "id", + const std::string &alias_member_name = "" ) + : type_name( type_name ), + id_member_name( id_member_name ), + alias_member_name( alias_member_name ) { } /** * Load an object of type T with the data from the given JSON object. @@ -144,13 +206,14 @@ class generic_factory */ T &load( JsonObject &jo ) { const string_id id( jo.get_string( id_member_name ) ); - const auto iter = data.find( id ); - const bool exists = iter != data.end(); + const auto iter = map.find( id ); + const bool exists = iter != map.end(); // "create" is the default, so the game catches accidental re-definitions of // existing objects. const std::string mode = jo.get_string( "edit-mode", "create" ); if( mode == "override" ) { + remove_aliases( id ); return load_override( id, jo ); } else if( mode == "modify" ) { @@ -158,9 +221,9 @@ class generic_factory jo.throw_error( "missing definition of " + type_name + " \"" + id.str() + "\" to be modified", id_member_name ); } - iter->second.load( jo ); - return iter->second; - + T &obj = list[iter->second]; + obj.load( jo ); + return obj; } else if( mode == "create" ) { if( exists ) { jo.throw_error( "duplicated definition of " + type_name + " \"" + id.str() + "\"", id_member_name ); @@ -175,51 +238,81 @@ class generic_factory /** * Add an object to the factory, without loading from JSON. * The new object replaces any existing object of the same id. + * The function returns the actual object reference. */ - void insert( const T &obj ) { - data[obj.id] = std::move( obj ); + T &insert( const T &obj ) { + const auto iter = map.find( obj.id ); + if( iter != map.end() ) { + T &result = list[iter->second]; + result = std::move( obj ); + result.id.set_cid( iter->second ); + return result; + } + + const int_id cid( list.size() ); + list.push_back( std::move( obj ) ); + + T &result = list.back(); + result.id.set_cid( cid ); + map[result.id] = cid; + return result; + } + /** + * Checks loaded/inserted objects for consistency + */ + void check() const { + for( const T &obj : list ) { + obj.check(); + } } /** * Returns the number of loaded objects. */ size_t size() const { - return data.size(); + return list.size(); + } + /** + * Returns whether factory is empty. + */ + bool empty() const { + return list.empty(); } /** * Removes all loaded objects. * Postcondition: `size() == 0` */ void reset() { - data.clear(); + list.clear(); + map.clear(); } /** * Returns all the loaded objects. It can be used to iterate over them. - * This returns a reference and is therefor quite fast, but you can also - * use @ref get_all, which returns a copy of this data with raw pointers. - * You should prefer `get_all` as it exposes a more stable interface. */ - const std::unordered_map, T> &all_ref() const { - return data; - } - std::vector get_all() const { - std::vector result; - result.reserve( data.size() ); - - using pair = typename std::unordered_map, T>::value_type; - std::transform( data.begin(), data.end(), back_inserter( result ), []( const pair & p ) { - return &p.second; - } ); - - return result; + const std::vector &get_all() const { + return list; } /** - * @name `string_id` interface functions + * @name `string_id/int_id` interface functions * * The functions here are supposed to be used by the id classes, they have the * same behavior as described in the id classes and can be used directly by * forwarding the parameters to them and returning their result. */ /**@{*/ + /** + * Returns the object with the given id. + * The input id should be valid, otherwise a debug message is issued. + * This function can be used to implement @ref int_id::obj(). + * Note: If the id was valid, the returned object can be modified (after + * casting the const away). + */ + const T &obj( const int_id &id ) const { + if( !is_valid( id ) ) { + debugmsg( "invalid %s id \"%d\"", type_name.c_str(), id ); + return dummy_obj; + } + return list[id]; + } /** * Returns the object with the given id. * The input id should be valid, otherwise a debug message is issued. @@ -227,21 +320,45 @@ class generic_factory * Note: If the id was valid, the returned object can be modified (after * casting the const away). */ - const T &obj( const string_id &sid ) const { - const auto iter = data.find( sid ); - if( iter == data.end() ) { - debugmsg( "invalid %s id \"%s\"", type_name.c_str(), sid.c_str() ); - static const T dummy{}; - return dummy; + const T &obj( const string_id &id ) const { + int_id i_id; + if( !find_id( id, i_id ) ) { + debugmsg( "invalid %s id \"%s\"", type_name.c_str(), id.c_str() ); + return dummy_obj; } - return iter->second; + return list[i_id]; + } + /** + * Checks whether the factory contains an object with the given id. + * This function can be used to implement @ref int_id::is_valid(). + */ + bool is_valid( const int_id &id ) const { + return static_cast( id ) < list.size(); } /** * Checks whether the factory contains an object with the given id. * This function can be used to implement @ref string_id::is_valid(). */ - bool is_valid( const string_id &sid ) const { - return data.count( sid ) > 0; + bool is_valid( const string_id &id ) const { + int_id dummy; + return find_id( id, dummy ); + } + /** + * Converts string_id to int_id. Returns null_id on failure. + */ + int_id convert( const string_id &id, const int_id &null_id ) const { + int_id result; + if( find_id( id, result ) ) { + return result; + } + debugmsg( "invalid %s id \"%s\"", type_name.c_str(), id.c_str() ); + return null_id; + } + /** + * Converts int_id to string_id. Returns null_id on failure. + */ + const string_id &convert( const int_id &id ) const { + return obj( id ).id; } /**@}*/ }; @@ -713,4 +830,16 @@ class enum_flags_reader : public generic_typed_reader> } }; +/** + * Loads string_id from JSON + */ +template +class string_id_reader : public generic_typed_reader> +{ + public: + string_id get_next( JsonIn &jin ) const { + return string_id( jin.get_string() ); + } +}; + #endif diff --git a/src/mapdata.cpp b/src/mapdata.cpp index d263bbb4af2c6..d217331ee11a0 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -2,12 +2,12 @@ #include "color.h" #include "init.h" #include "game_constants.h" +#include "generic_factory.h" #include "debug.h" #include "translations.h" #include "output.h" #include "item.h" #include "item_group.h" -#include "calendar.h" #include @@ -16,41 +16,13 @@ const std::set classic_extras = { "mx_helicopter", "mx_military", "mx_crater", "mx_collegekids" }; -const ter_str_id &convert_terrain_type( const ter_str_id & ); - -namespace // @todo This should belong to the generic_factory class -{ - -std::vector terlist; -std::map termap; - -const std::map::iterator find_ter_id( const ter_str_id &tid ) -{ - const auto &iter = termap.find( tid ); - if( iter != termap.end() ) { - return iter; - } - const auto &new_id = convert_terrain_type( tid ); - if( new_id == tid ) { - return iter; - } - const auto &conv_iter = termap.find( new_id ); - if( conv_iter != termap.end() ) { - termap[tid] = conv_iter->second; // So theres no need to convert anymore - } - return conv_iter; -} +template<> +const string_id string_id::NULL_ID( "t_null", 0 ); -void emplace_ter( const ter_t &ter ) +namespace { - // It's going to be generic_factory's responsibility, - // I leave it without additional checks for now - const ter_id cid = ter_id( terlist.size() ); - terlist.push_back( ter ); - termap[ter.id] = cid; - ter.id.set_cid( cid ); -} +generic_factory terrain_data( "terrain", "id", "aliases" ); } @@ -60,49 +32,25 @@ std::map furnmap; template<> inline bool int_id::is_valid() const { - return static_cast( _id ) < terlist.size(); + return terrain_data.is_valid( *this ); } template<> const ter_t &int_id::obj() const { - if( !is_valid() ) { - debugmsg( "invalid terrain id %d", _id ); - static const ter_t dummy{}; - return dummy; - } - return terlist[_id]; + return terrain_data.obj( *this ); } template<> const string_id &int_id::id() const { - return obj().id; + return terrain_data.convert( *this ); } -template<> -const string_id string_id::NULL_ID( "t_null", 0 ); - template<> int_id string_id::id() const { - const auto tid = get_cid(); - // Since we don't delete terrain objects, we don't - // particularly need the second condition, but - // generic case requires it. - // The idea: add a boolean flag 'deletion_occurred'. - // If it's false, we don't need to waste CPU time - // on string comparison, otherwise we make sure - if( tid.is_valid() && terlist[tid].id == *this ) { - return tid; - } - const auto &iter = find_ter_id( *this ); - if( iter != termap.end() ) { - set_cid( iter->second ); - return iter->second; - } - debugmsg( "can't find terrain %s", c_str() ); - return t_null; + return terrain_data.convert( *this, t_null ); } template<> @@ -113,23 +61,13 @@ int_id::int_id( const string_id &id ) : _id( id.id() ) template<> const ter_t &string_id::obj() const { - return id().obj(); + return terrain_data.obj( *this ); } template<> bool string_id::is_valid() const { - const auto tid = get_cid(); - - if( tid.is_valid() && terlist[tid].id == *this ) { - return true; - } - const auto &iter = find_ter_id( *this ); - if( iter != termap.end() ) { - set_cid( iter->second ); - return true; - } - return false; + return terrain_data.is_valid( *this ); } template<> @@ -411,120 +349,10 @@ void load_furniture(JsonObject &jsobj) void load_terrain(JsonObject &jsobj) { - if ( terlist.empty() ) { // todo@ This shouldn't live here - emplace_ter( null_terrain_t() ); - } - ter_t new_terrain; - - new_terrain.id = ter_str_id( jsobj.get_string("id") ); - if ( !new_terrain.id ) { - return; - } - new_terrain.name = _(jsobj.get_string("name").c_str()); - - new_terrain.load_symbol( jsobj ); - - new_terrain.movecost = jsobj.get_int("move_cost"); - - if(jsobj.has_member("trap")) { - // Store the string representation of the trap id. - // Overwrites the trap field in set_trap_ids() once ids are assigned.. - new_terrain.trap_id_str = jsobj.get_string("trap"); - } - new_terrain.trap = tr_null; - new_terrain.max_volume = jsobj.get_int("max_volume", MAX_VOLUME_IN_SQUARE); - - new_terrain.transparent = false; - new_terrain.connect_group = TERCONN_NONE; - - for( auto & flag : jsobj.get_string_array( "flags" ) ) { - new_terrain.set_flag( flag ); - } - - // connect_group is initialised to none, then terrain flags are set, then finally - // connections from JSON are set. This is so that wall flags can set wall connections - // but can be overridden by explicit connections in JSON. - if(jsobj.has_member("connects_to")) { - new_terrain.set_connects( jsobj.get_string("connects_to") ); - } - - if(jsobj.has_member("examine_action")) { - std::string function_name = jsobj.get_string("examine_action"); - new_terrain.examine = iexamine_function_from_string(function_name); - } else { - // if not specified, default to no action - new_terrain.examine = iexamine_function_from_string("none"); - } - - // if the terrain has something harvestable - if (jsobj.has_member("harvestable")) { - new_terrain.harvestable = jsobj.get_string("harvestable"); // get the harvestable - } - - if (jsobj.has_member("transforms_into")) { - new_terrain.transforms_into = ter_str_id( jsobj.get_string("transforms_into") ); // get the terrain to transform into later on - } - - if (jsobj.has_member("roof")) { - new_terrain.roof = ter_str_id( jsobj.get_string("roof") ); // Get the terrain to create above this one if there would be open air otherwise - } - - if (jsobj.has_member("harvest_season")) { - //get the harvest season - if (jsobj.get_string("harvest_season") == "SPRING") {new_terrain.harvest_season = 0;} // convert the season to int for calendar compare - else if (jsobj.get_string("harvest_season") == "SUMMER") {new_terrain.harvest_season = 1;} - else if (jsobj.get_string("harvest_season") == "AUTUMN") {new_terrain.harvest_season = 2;} - else {new_terrain.harvest_season = 3;} - } - - if ( jsobj.has_member("open") ) { - new_terrain.open = ter_str_id( jsobj.get_string("open") ); - } - if ( jsobj.has_member("close") ) { - new_terrain.close = ter_str_id( jsobj.get_string("close") ); - } - new_terrain.bash.load(jsobj, "bash", false); - new_terrain.deconstruct.load(jsobj, "deconstruct", false); - - emplace_ter( new_terrain ); -} - -const ter_str_id &convert_terrain_type( const ter_str_id &t ) -{ - static const std::unordered_map ter_type_conversion_map = { { - { ter_str_id( "t_wall_h" ), ter_str_id( "t_wall" ) }, - { ter_str_id( "t_wall_v" ), ter_str_id( "t_wall" ) }, - { ter_str_id( "t_concrete_h" ), ter_str_id( "t_concrete_wall" ) }, - { ter_str_id( "t_concrete_v" ), ter_str_id( "t_concrete_wall" ) }, - { ter_str_id( "t_wall_metal_h" ), ter_str_id( "t_wall_metal" ) }, - { ter_str_id( "t_wall_metal_v" ), ter_str_id( "t_wall_metal" ) }, - { ter_str_id( "t_wall_glass_h" ), ter_str_id( "t_wall_glass" ) }, - { ter_str_id( "t_wall_glass_v" ), ter_str_id( "t_wall_glass" ) }, - { ter_str_id( "t_wall_glass_h_alarm" ), ter_str_id( "t_wall_glass_alarm" ) }, - { ter_str_id( "t_wall_glass_v_alarm" ), ter_str_id( "t_wall_glass_alarm" ) }, - { ter_str_id( "t_reinforced_glass_h" ), ter_str_id( "t_reinforced_glass" ) }, - { ter_str_id( "t_reinforced_glass_v" ), ter_str_id( "t_reinforced_glass" ) }, - { ter_str_id( "t_fungus_wall_h" ), ter_str_id( "t_fungus_wall" ) }, - { ter_str_id( "t_fungus_wall_v" ), ter_str_id( "t_fungus_wall" ) }, - { ter_str_id( "t_wall_h_r" ), ter_str_id( "t_wall_r" ) }, - { ter_str_id( "t_wall_v_r" ), ter_str_id( "t_wall_r" ) }, - { ter_str_id( "t_wall_h_w" ), ter_str_id( "t_wall_w" ) }, - { ter_str_id( "t_wall_v_w" ), ter_str_id( "t_wall_w" ) }, - { ter_str_id( "t_wall_h_b" ), ter_str_id( "t_wall_b" ) }, - { ter_str_id( "t_wall_v_b" ), ter_str_id( "t_wall_b" ) }, - { ter_str_id( "t_wall_h_g" ), ter_str_id( "t_wall_g" ) }, - { ter_str_id( "t_wall_v_g" ), ter_str_id( "t_wall_g" ) }, - { ter_str_id( "t_wall_h_y" ), ter_str_id( "t_wall_y" ) }, - { ter_str_id( "t_wall_v_y" ), ter_str_id( "t_wall_y" ) }, - { ter_str_id( "t_wall_h_p" ), ter_str_id( "t_wall_p" ) }, - { ter_str_id( "t_wall_v_p" ), ter_str_id( "t_wall_p" ) }, - } }; - - const auto iter = ter_type_conversion_map.find( t ); - if( iter == ter_type_conversion_map.end() ) { - return t; + if( terrain_data.empty() ) { // todo@ This shouldn't live here + terrain_data.insert( null_terrain_t() ); } - return iter->second; + terrain_data.load( jsobj ); } void map_data_common_t::set_flag( const std::string &flag ) @@ -911,19 +739,20 @@ void set_ter_ids() { t_guardrail_bg_dp = ter_id( "t_guardrail_bg_dp" ); t_improvised_shelter = ter_id( "t_improvised_shelter" ); - for( auto &elem : terlist ) { - if( elem.trap_id_str.empty() ) { - elem.trap = tr_null; + for( auto &elem : terrain_data.get_all() ) { + ter_t &ter = const_cast( elem ); + if( ter.trap_id_str.empty() ) { + ter.trap = tr_null; } else { - elem.trap = trap_str_id( elem.trap_id_str ); + ter.trap = trap_str_id( ter.trap_id_str ); } } } void reset_furn_ter() { - termap.clear(); - terlist.clear(); + terrain_data.reset(); + furnmap.clear(); furnlist.clear(); } @@ -1066,7 +895,63 @@ void set_furn_ids() { size_t ter_t::count() { - return termap.size(); + return terrain_data.size(); +} + +void ter_t::load( JsonObject &jo ) +{ + mandatory( jo, was_loaded, "name", name ); + mandatory( jo, was_loaded, "move_cost", movecost ); + optional( jo, was_loaded, "max_volume", max_volume, MAX_VOLUME_IN_SQUARE ); + optional( jo, was_loaded, "trap", trap_id_str ); + + load_symbol( jo ); + + trap = tr_null; + transparent = false; + connect_group = TERCONN_NONE; + + for( auto &flag : jo.get_string_array( "flags" ) ) { + set_flag( flag ); + } + // connect_group is initialised to none, then terrain flags are set, then finally + // connections from JSON are set. This is so that wall flags can set wall connections + // but can be overridden by explicit connections in JSON. + if( jo.has_member( "connects_to" ) ) { + set_connects( jo.get_string( "connects_to" ) ); + } + + if( jo.has_member( "examine_action" ) ) { + examine = iexamine_function_from_string( jo.get_string( "examine_action" ) ); + } else { + examine = iexamine_function_from_string( "none" ); + } + + optional( jo, was_loaded, "harvestable", harvestable ); + optional( jo, was_loaded, "open", open, NULL_ID ); + optional( jo, was_loaded, "close", close, NULL_ID ); + optional( jo, was_loaded, "transforms_into", transforms_into, NULL_ID ); + optional( jo, was_loaded, "roof", roof, NULL_ID ); + + if( jo.has_member("harvest_season") ) { + const std::string season = jo.get_string( "harvest_season" ); + + if( season == "SPRING" ) { + harvest_season = season_type::SPRING; + } else if( season == "SUMMER" ) { + harvest_season = season_type::SUMMER; + } else if( season == "AUTUMN" ) { + harvest_season = season_type::AUTUMN; + } else if( season == "WINTER" ) { + harvest_season = season_type::WINTER; + } else { + harvest_season = season_type::AUTUMN; + debugmsg( "Invalid harvest season \"%s\" in \"%s\".", season.c_str(), id.c_str() ); + } + } + + bash.load( jo, "bash", false ); + deconstruct.load( jo, "deconstruct", false ); } void check_bash_items(const map_bash_info &mbi, const std::string &id, bool is_terrain) @@ -1106,6 +991,22 @@ void check_decon_items(const map_deconstruct_info &mbi, const std::string &id, b } } +void ter_t::check() const +{ + check_bash_items( bash, id.str(), true ); + check_decon_items( deconstruct, id.str(), true ); + + if( !transforms_into.is_valid() ) { + debugmsg( "invalid transforms_into %s for %s", transforms_into.c_str(), id.c_str() ); + } + if( !open.is_valid() ) { + debugmsg( "invalid terrain %s for opening %s", open.c_str(), id.c_str() ); + } + if( !close.is_valid() ) { + debugmsg( "invalid terrain %s for closing %s", close.c_str(), id.c_str() ); + } +} + void check_furniture_and_terrain() { for( const furn_t& f : furnlist ) { @@ -1118,17 +1019,5 @@ void check_furniture_and_terrain() debugmsg( "invalid furniture %s for closing %s", f.close.c_str(), f.id.c_str() ); } } - for( const ter_t& t : terlist ) { - check_bash_items(t.bash, t.id.str(), true); - check_decon_items(t.deconstruct, t.id.str(), true); - if( !t.transforms_into.is_valid() ) { - debugmsg( "invalid transforms_into %s for %s", t.transforms_into.c_str(), t.id.c_str() ); - } - if( !t.open.is_valid() ) { - debugmsg( "invalid terrain %s for opening %s", t.open.c_str(), t.id.c_str() ); - } - if( !t.close.is_valid() ) { - debugmsg( "invalid terrain %s for closing %s", t.close.c_str(), t.id.c_str() ); - } - } + terrain_data.check(); } diff --git a/src/mapdata.h b/src/mapdata.h index 27a9be7bf28cd..fb1b12821fb3c 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -2,7 +2,7 @@ #define MAPDATA_H #include "game_constants.h" -#include "color.h" +#include "calendar.h" #include "enums.h" #include "iexamine.h" #include "int_id.h" @@ -259,7 +259,7 @@ struct ter_t : map_data_common_t { trap_id trap; // The id of the trap located at this terrain. Limit one trap per tile currently. - int harvest_season; // When will this terrain get harvested? + season_type harvest_season; // When will this terrain get harvested? ter_t() : open( NULL_ID ), @@ -267,9 +267,14 @@ struct ter_t : map_data_common_t { transforms_into( NULL_ID ), roof( NULL_ID ), trap( tr_null ), - harvest_season( 0 ) {}; + harvest_season( season_type::AUTUMN ) {}; static size_t count(); + + bool was_loaded = false; + + void load( JsonObject &jo ); + void check() const; }; void set_ter_ids(); diff --git a/src/martialarts.cpp b/src/martialarts.cpp index a7e0bcc7d0426..790318083b7d1 100644 --- a/src/martialarts.cpp +++ b/src/martialarts.cpp @@ -208,8 +208,8 @@ bool string_id::is_valid() const std::vector all_martialart_types() { std::vector result; - for( auto & e : martialarts.all_ref() ) { - result.push_back( e.first ); + for( const auto &ma : martialarts.get_all() ) { + result.push_back( ma.id ); } return result; } @@ -225,28 +225,27 @@ void check( const ma_requirements & req, const std::string &display_text ) void check_martialarts() { - for( auto &e : martialarts.all_ref() ) { - const auto style = &e; - for( auto technique = style->second.techniques.cbegin(); - technique != style->second.techniques.cend(); ++technique ) { + for( const auto &ma : martialarts.get_all() ) { + for( auto technique = ma.techniques.cbegin(); + technique != ma.techniques.cend(); ++technique ) { if( !technique->is_valid() ) { debugmsg( "Technique with id %s in style %s doesn't exist.", - technique->c_str(), style->second.name.c_str() ); + technique->c_str(), ma.name.c_str() ); } } - for( auto weapon = style->second.weapons.cbegin(); - weapon != style->second.weapons.cend(); ++weapon ) { + for( auto weapon = ma.weapons.cbegin(); + weapon != ma.weapons.cend(); ++weapon ) { if( !item::type_is_defined( *weapon ) ) { debugmsg( "Weapon %s in style %s doesn't exist.", - weapon->c_str(), style->second.name.c_str() ); + weapon->c_str(), ma.name.c_str() ); } } } - for( auto & t : ma_techniques.all_ref() ) { - ::check( t.second.reqs, string_format( "technique %s", t.first.c_str() ) ); + for( const auto &t : ma_techniques.get_all() ) { + ::check( t.reqs, string_format( "technique %s", t.id.c_str() ) ); } - for( auto & b : ma_buffs.all_ref() ) { - ::check( b.second.reqs, string_format( "buff %s", b.first.c_str() ) ); + for( const auto &b : ma_buffs.get_all() ) { + ::check( b.reqs, string_format( "buff %s", b.id.c_str() ) ); } } @@ -301,8 +300,8 @@ void finialize_martial_arts() { // This adds an effect type for each ma_buff, so we can later refer to it and don't need a // redundant definition of those effects in json. - for( auto &buff : ma_buffs.all_ref() ) { - const ma_buff_effect_type new_eff( buff.second ); + for( const auto &buff : ma_buffs.get_all() ) { + const ma_buff_effect_type new_eff( buff ); // Note the slicing here: new_eff is converted to a plain effect_type, but this doesn't // bother us because ma_buff_effect_type does not have any members that can be sliced. effect_type::register_ma_buff_effect( new_eff ); diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index 0565fcc3d856c..c6bf5c022fe10 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -104,8 +104,8 @@ void MonsterGenerator::reset() void MonsterGenerator::finalize_mtypes() { - for( auto &elem : mon_templates->all_ref() ) { - mtype &mon = const_cast( elem.second ); + for( const auto &elem : mon_templates->get_all() ) { + mtype &mon = const_cast( elem ); apply_species_attributes( mon ); set_mtype_flags( mon ); set_species_ids( mon ); @@ -576,7 +576,7 @@ void species_type::load( JsonObject &jo ) optional( jo, was_loaded, "fear_triggers", fear_trig, trigger_reader ); } -std::vector MonsterGenerator::get_all_mtypes() const +const std::vector &MonsterGenerator::get_all_mtypes() const { return mon_templates->get_all(); } @@ -584,8 +584,7 @@ std::vector MonsterGenerator::get_all_mtypes() const mtype_id MonsterGenerator::get_valid_hallucination() const { std::vector potentials; - for( auto &elem : mon_templates->all_ref() ) { - const mtype &mon = elem.second; + for( const auto &mon : mon_templates->get_all() ) { if( mon.id != NULL_ID && mon.id != mon_generator ) { potentials.push_back( mon.id ); } @@ -669,53 +668,52 @@ void mtype::remove_special_attacks( JsonObject &jo, const std::string &member_na void MonsterGenerator::check_monster_definitions() const { - for( const auto &elem : mon_templates->all_ref() ) { - const mtype *mon = &elem.second; - for( auto &spec : mon->species ) { + for( const auto &mon : mon_templates->get_all() ) { + for( auto &spec : mon.species ) { if( !spec.is_valid() ) { - debugmsg("monster %s has invalid species %s", mon->id.c_str(), spec.c_str()); + debugmsg("monster %s has invalid species %s", mon.id.c_str(), spec.c_str()); } } - if (!mon->death_drops.empty() && !item_group::group_is_defined(mon->death_drops)) { - debugmsg("monster %s has unknown death drop item group: %s", mon->id.c_str(), - mon->death_drops.c_str()); + if (!mon.death_drops.empty() && !item_group::group_is_defined(mon.death_drops)) { + debugmsg("monster %s has unknown death drop item group: %s", mon.id.c_str(), + mon.death_drops.c_str()); } - for( auto &m : mon->mat ) { + for( auto &m : mon.mat ) { if( m.str() == "null" || !m.is_valid() ) { - debugmsg( "monster %s has unknown material: %s", mon->id.c_str(), m.c_str() ); + debugmsg( "monster %s has unknown material: %s", mon.id.c_str(), m.c_str() ); } } - if( !mon->revert_to_itype.empty() && !item::type_is_defined( mon->revert_to_itype ) ) { - debugmsg("monster %s has unknown revert_to_itype: %s", mon->id.c_str(), - mon->revert_to_itype.c_str()); + if( !mon.revert_to_itype.empty() && !item::type_is_defined( mon.revert_to_itype ) ) { + debugmsg("monster %s has unknown revert_to_itype: %s", mon.id.c_str(), + mon.revert_to_itype.c_str()); } - for( auto & s : mon->starting_ammo ) { + for( auto & s : mon.starting_ammo ) { if( !item::type_is_defined( s.first ) ) { - debugmsg( "starting ammo %s of monster %s is unknown", s.first.c_str(), mon->id.c_str() ); + debugmsg( "starting ammo %s of monster %s is unknown", s.first.c_str(), mon.id.c_str() ); } } - for( auto & e : mon->atk_effs ) { + for( auto & e : mon.atk_effs ) { if( !e.id.is_valid() ) { - debugmsg( "attack effect %s of monster %s is unknown", e.id.c_str(), mon->id.c_str() ); + debugmsg( "attack effect %s of monster %s is unknown", e.id.c_str(), mon.id.c_str() ); } } - if( mon->upgrades ) { - if( mon->half_life <= 0 ) { - debugmsg( "half_life %d (<= 0) of monster %s is invalid", mon->half_life, mon->id.c_str() ); + if( mon.upgrades ) { + if( mon.half_life <= 0 ) { + debugmsg( "half_life %d (<= 0) of monster %s is invalid", mon.half_life, mon.id.c_str() ); } - if( !mon->upgrade_into && !mon->upgrade_group ) { - debugmsg( "no into nor into_group defined for monster %s", mon->id.c_str() ); + if( !mon.upgrade_into && !mon.upgrade_group ) { + debugmsg( "no into nor into_group defined for monster %s", mon.id.c_str() ); } - if( mon->upgrade_into && mon->upgrade_group ) { - debugmsg( "both into and into_group defined for monster %s", mon->id.c_str() ); + if( mon.upgrade_into && mon.upgrade_group ) { + debugmsg( "both into and into_group defined for monster %s", mon.id.c_str() ); } - if( !mon->upgrade_into.is_valid() ) { + if( !mon.upgrade_into.is_valid() ) { debugmsg( "upgrade_into %s of monster %s is not a valid monster id", - mon->upgrade_into.c_str(), mon->id.c_str() ); + mon.upgrade_into.c_str(), mon.id.c_str() ); } - if( !mon->upgrade_group.is_valid() ) { + if( !mon.upgrade_group.is_valid() ) { debugmsg( "upgrade_group %s of monster %s is not a valid monster group id", - mon->upgrade_group.c_str(), mon->id.c_str() ); + mon.upgrade_group.c_str(), mon.id.c_str() ); } } } diff --git a/src/monstergenerator.h b/src/monstergenerator.h index eb56caddb790d..3c53c903182b9 100644 --- a/src/monstergenerator.h +++ b/src/monstergenerator.h @@ -62,7 +62,7 @@ class MonsterGenerator void check_monster_definitions() const; - std::vector get_all_mtypes() const; + const std::vector &get_all_mtypes() const; mtype_id get_valid_hallucination() const; friend struct mtype; friend struct species_type; diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index d242c3bc4c770..fd9f9eb4f326e 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -243,9 +243,9 @@ void player::randomize( const bool random_scenario, points_left &points ) } if( random_scenario ) { std::vector scenarios; - for( const scenario *const scenptr : scenario::get_all() ) { - if (!scenptr->has_flag("CHALLENGE")) { - scenarios.emplace_back( scenptr ); + for( const auto &scen : scenario::get_all() ) { + if (!scen.has_flag("CHALLENGE")) { + scenarios.emplace_back( &scen ); } } g->scen = random_entry( scenarios ); @@ -342,7 +342,7 @@ void player::randomize( const bool random_scenario, points_left &points ) case 2: case 3: case 4: - if( allow_traits ) { + if( allow_traits ) { rn = random_good_trait(); auto &mdata = mutation_branch::get( rn ); if( !has_trait(rn) && points.trait_points_left() >= mdata.points && @@ -1307,13 +1307,13 @@ tab_direction set_profession(WINDOW *w, player *u, points_left &points) do { if (recalc_profs) { sorted_profs.clear(); - for( const profession *const profptr : profession::get_all() ) { - if ((g->scen->profsize() == 0 && profptr->has_flag("SCEN_ONLY") == false) || - g->scen->profquery( profptr->ident() ) ) { - if (!lcmatch(profptr->gender_appropriate_name(u->male), filterstring)) { + for( const auto &prof : profession::get_all() ) { + if ((g->scen->profsize() == 0 && prof.has_flag("SCEN_ONLY") == false) || + g->scen->profquery( prof.ident() ) ) { + if (!lcmatch(prof.gender_appropriate_name(u->male), filterstring)) { continue; } - sorted_profs.push_back(profptr); + sorted_profs.push_back(&prof); } } profs_length = sorted_profs.size(); @@ -1595,8 +1595,8 @@ tab_direction set_skills(WINDOW *w, player *u, points_left &points) std::map prof_skills; const auto &pskills = u->prof->skills(); - - std::copy( pskills.begin(), pskills.end(), + + std::copy( pskills.begin(), pskills.end(), std::inserter( prof_skills, prof_skills.begin() ) ); do { @@ -1843,11 +1843,11 @@ tab_direction set_scenario(WINDOW *w, player *u, points_left &points) do { if (recalc_scens) { sorted_scens.clear(); - for( const scenario *const scenptr : scenario::get_all() ) { - if (!lcmatch(scenptr->gender_appropriate_name(u->male), filterstring)) { + for( const auto &scen : scenario::get_all() ) { + if (!lcmatch(scen.gender_appropriate_name(u->male), filterstring)) { continue; } - sorted_scens.push_back( scenptr ); + sorted_scens.push_back( &scen ); } scens_length = sorted_scens.size(); if (scens_length == 0) { @@ -2128,10 +2128,10 @@ tab_direction set_description(WINDOW *w, player *u, const bool allow_reroll, poi uimenu select_location; select_location.text = _("Select a starting location."); int offset = 0; - for( const start_location *const loc : start_location::get_all() ) { - if (g->scen->allowed_start(loc->ident()) || g->scen->has_flag("ALL_STARTS")) { - select_location.entries.push_back( uimenu_entry( loc->name() ) ); - if( loc->ident() == u->start_location ) { + for( const auto &loc : start_location::get_all() ) { + if (g->scen->allowed_start(loc.ident()) || g->scen->has_flag("ALL_STARTS")) { + select_location.entries.push_back( uimenu_entry( loc.name() ) ); + if( loc.ident() == u->start_location ) { select_location.selected = offset; } offset++; @@ -2344,9 +2344,9 @@ tab_direction set_description(WINDOW *w, player *u, const bool allow_reroll, poi } else if ( action == "CHOOSE_LOCATION" ) { select_location.redraw(); select_location.query(); - for( const start_location *const loc : start_location::get_all() ) { - if( loc->name() == select_location.entries[ select_location.selected ].txt ) { - u->start_location = loc->ident(); + for( const auto &loc : start_location::get_all() ) { + if( loc.name() == select_location.entries[ select_location.selected ].txt ) { + u->start_location = loc.ident(); } } werase(select_location.window); diff --git a/src/player.cpp b/src/player.cpp index 271ea1f3f4c73..7a5235bd04f1a 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -2041,12 +2041,12 @@ void player::memorial( std::ofstream &memorial_file, std::string epitaph ) // map to kill count for( const auto &type : MonsterGenerator::generator().get_all_mtypes() ) { - if( g->kill_count( type->id ) > 0 ) { + if( g->kill_count( type.id ) > 0 ) { kill_counts[std::tuple( - type->nname(), - type->sym - )] += g->kill_count( type->id ); - total_kills += g->kill_count( type->id ); + type.nname(), + type.sym + )] += g->kill_count( type.id ); + total_kills += g->kill_count( type.id ); } } @@ -9478,7 +9478,7 @@ bool player::can_wear( const item& it, bool alert ) const if( ( ( it.covers( bp_foot_l ) && is_wearing_shoes( "left" ) ) || ( it.covers( bp_foot_r ) && is_wearing_shoes( "right") ) ) && - ( !it.has_flag( "OVERSIZE" ) || !it.has_flag( "OUTER" ) ) && + ( !it.has_flag( "OVERSIZE" ) || !it.has_flag( "OUTER" ) ) && !it.has_flag( "SKINTIGHT" ) && !it.has_flag( "BELTED" ) ) { // Checks to see if the player is wearing shoes if( alert ) { diff --git a/src/profession.cpp b/src/profession.cpp index deaa18f93f9fb..f3e06ba23b752 100644 --- a/src/profession.cpp +++ b/src/profession.cpp @@ -158,11 +158,11 @@ const profession *profession::weighted_random() return generic(); } - const auto &map = all_profs.all_ref(); + const auto &list = all_profs.get_all(); while( true ) { - auto iter = map.begin(); - std::advance( iter, rng( 0, map.size() - 1 ) ); - const profession &prof = iter->second; + auto iter = list.begin(); + std::advance( iter, rng( 0, list.size() - 1 ) ); + const profession &prof = *iter; if( x_in_y( 2, abs( prof.point_cost() ) + 2 ) && !prof.has_flag( "SCEN_ONLY" ) ) { return &prof; @@ -171,7 +171,7 @@ const profession *profession::weighted_random() } } -std::vector profession::get_all() +const std::vector &profession::get_all() { return all_profs.get_all(); } @@ -183,8 +183,8 @@ void profession::reset() void profession::check_definitions() { - for( auto &pair : all_profs.all_ref() ) { - pair.second.check_definition(); + for( const auto &prof : all_profs.get_all() ) { + prof.check_definition(); } } diff --git a/src/profession.h b/src/profession.h index ce28db1423bdf..6e528d75cafeb 100644 --- a/src/profession.h +++ b/src/profession.h @@ -70,7 +70,7 @@ enum add_type : int; static const profession *generic(); // points to the generic, default profession // return a random profession, weighted for use w/ random character creation or npcs static const profession *weighted_random(); - static std::vector get_all(); + static const std::vector &get_all(); static bool has_initialized(); // clear profession map, every profession pointer becames invalid! diff --git a/src/scenario.cpp b/src/scenario.cpp index 212ff01e6fe10..5255c8e2fbd62 100644 --- a/src/scenario.cpp +++ b/src/scenario.cpp @@ -116,11 +116,11 @@ const scenario *scenario::weighted_random() return generic(); } - const auto &map = all_scenarios.all_ref(); + const auto &list = all_scenarios.get_all(); while( true ) { - auto iter = map.begin(); - std::advance( iter, rng( 0, map.size() - 1 ) ); - const scenario &scen = iter->second; + auto iter = list.begin(); + std::advance( iter, rng( 0, list.size() - 1 ) ); + const scenario &scen = *iter; if( x_in_y( 2, abs( scen.point_cost() ) + 2 ) ) { return &scen; @@ -129,7 +129,7 @@ const scenario *scenario::weighted_random() } } -std::vector scenario::get_all() +const std::vector &scenario::get_all() { return all_scenarios.get_all(); } @@ -141,8 +141,8 @@ void scenario::reset() void scenario::check_definitions() { - for( auto &pair : all_scenarios.all_ref() ) { - pair.second.check_definition(); + for( const auto &scen : all_scenarios.get_all() ) { + scen.check_definition(); } } diff --git a/src/scenario.h b/src/scenario.h index 2c4bb58028b83..ec64a2d5978ef 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -60,7 +60,7 @@ class scenario static const scenario* generic(); // points to the generic, default profession // return a random scenario, weighted for use w/ random character creation static const scenario* weighted_random(); - static std::vector get_all(); + static const std::vector &get_all(); // clear scenario map, every scenario pointer becames invalid! static void reset(); diff --git a/src/start_location.cpp b/src/start_location.cpp index c2ba63079af63..3a56a9cfe1135 100644 --- a/src/start_location.cpp +++ b/src/start_location.cpp @@ -56,7 +56,7 @@ std::string start_location::target() const return _target; } -std::vector start_location::get_all() +const std::vector &start_location::get_all() { return all_starting_locations.get_all(); } diff --git a/src/start_location.h b/src/start_location.h index 679db18f5bdf0..e3eb5080bd105 100644 --- a/src/start_location.h +++ b/src/start_location.h @@ -30,7 +30,7 @@ class start_location static void load_location( JsonObject &jsonobj ); static void reset(); - static std::vector get_all(); + static const std::vector &get_all(); /** * Find a suitable start location on the overmap. diff --git a/src/wish.cpp b/src/wish.cpp index e94ef2bfda858..32899744b2666 100644 --- a/src/wish.cpp +++ b/src/wish.cpp @@ -368,12 +368,12 @@ void game::wishmonster( const tripoint &p ) int i = 0; for( const auto &montype : MonsterGenerator::generator().get_all_mtypes() ) { - wmenu.addentry( i, true, 0, "%s", montype->nname().c_str() ); - wmenu.entries[i].extratxt.txt = montype->sym; - wmenu.entries[i].extratxt.color = montype->color; + wmenu.addentry( i, true, 0, "%s", montype.nname().c_str() ); + wmenu.entries[i].extratxt.txt = montype.sym; + wmenu.entries[i].extratxt.color = montype.color; wmenu.entries[i].extratxt.left = 1; ++i; - mtypes.push_back( montype ); + mtypes.push_back( &montype ); } do {