diff --git a/src/activity_handlers.cpp b/src/activity_handlers.cpp index 373a316ff6108..36cf58147f56e 100644 --- a/src/activity_handlers.cpp +++ b/src/activity_handlers.cpp @@ -1457,6 +1457,8 @@ void activity_handlers::forage_finish( player_activity *act, player *p ) loc = "forage_winter"; next_ter = ter_str_id( "t_underbrush_harvested_winter" ); break; + default: + debugmsg( "Invalid season" ); } g->m.ter_set( act->placement, next_ter ); diff --git a/src/artifact.cpp b/src/artifact.cpp index d5726fa786d33..9b871754f55ea 100644 --- a/src/artifact.cpp +++ b/src/artifact.cpp @@ -1427,129 +1427,144 @@ void it_artifact_armor::serialize( JsonOut &json ) const namespace io { -#define PAIR(x) { #x, x } -static const std::unordered_map art_effect_passive_values = { { - //PAIR( AEP_NULL ), // not really used - PAIR( AEP_STR_UP ), - PAIR( AEP_DEX_UP ), - PAIR( AEP_PER_UP ), - PAIR( AEP_INT_UP ), - PAIR( AEP_ALL_UP ), - PAIR( AEP_SPEED_UP ), - PAIR( AEP_PBLUE ), - PAIR( AEP_SNAKES ), - PAIR( AEP_INVISIBLE ), - PAIR( AEP_CLAIRVOYANCE ), - PAIR( AEP_CLAIRVOYANCE_PLUS ), - PAIR( AEP_SUPER_CLAIRVOYANCE ), - PAIR( AEP_STEALTH ), - PAIR( AEP_EXTINGUISH ), - PAIR( AEP_GLOW ), - PAIR( AEP_PSYSHIELD ), - PAIR( AEP_RESIST_ELECTRICITY ), - PAIR( AEP_CARRY_MORE ), - PAIR( AEP_SAP_LIFE ), - PAIR( AEP_FUN ), - //PAIR( AEP_SPLIT, // not really used - PAIR( AEP_HUNGER ), - PAIR( AEP_THIRST ), - PAIR( AEP_SMOKE ), - PAIR( AEP_EVIL ), - PAIR( AEP_SCHIZO ), - PAIR( AEP_RADIOACTIVE ), - PAIR( AEP_MUTAGENIC ), - PAIR( AEP_ATTENTION ), - PAIR( AEP_STR_DOWN ), - PAIR( AEP_DEX_DOWN ), - PAIR( AEP_PER_DOWN ), - PAIR( AEP_INT_DOWN ), - PAIR( AEP_ALL_DOWN ), - PAIR( AEP_SPEED_DOWN ), - PAIR( AEP_FORCE_TELEPORT ), - PAIR( AEP_MOVEMENT_NOISE ), - PAIR( AEP_BAD_WEATHER ), - PAIR( AEP_SICK ), - } -}; -static const std::unordered_map art_effect_active_values = { { - //PAIR( AEA_NULL ), // not really used - PAIR( AEA_STORM ), - PAIR( AEA_FIREBALL ), - PAIR( AEA_ADRENALINE ), - PAIR( AEA_MAP ), - PAIR( AEA_BLOOD ), - PAIR( AEA_FATIGUE ), - PAIR( AEA_ACIDBALL ), - PAIR( AEA_PULSE ), - PAIR( AEA_HEAL ), - PAIR( AEA_CONFUSED ), - PAIR( AEA_ENTRANCE ), - PAIR( AEA_BUGS ), - PAIR( AEA_TELEPORT ), - PAIR( AEA_LIGHT ), - PAIR( AEA_GROWTH ), - PAIR( AEA_HURTALL ), - PAIR( AEA_FUN ), - //PAIR( AEA_SPLIT ), // not really used - PAIR( AEA_RADIATION ), - PAIR( AEA_PAIN ), - PAIR( AEA_MUTATE ), - PAIR( AEA_PARALYZE ), - PAIR( AEA_FIRESTORM ), - PAIR( AEA_ATTENTION ), - PAIR( AEA_TELEGLOW ), - PAIR( AEA_NOISE ), - PAIR( AEA_SCREAM ), - PAIR( AEA_DIM ), - PAIR( AEA_FLASH ), - PAIR( AEA_VOMIT ), - PAIR( AEA_SHADOWS ), - PAIR( AEA_STAMINA_EMPTY ), - } -}; -static const std::unordered_map art_charge_values = { { - PAIR( ARTC_NULL ), - PAIR( ARTC_TIME ), - PAIR( ARTC_SOLAR ), - PAIR( ARTC_PAIN ), - PAIR( ARTC_HP ), - PAIR( ARTC_FATIGUE ), - PAIR( ARTC_PORTAL ), - } -}; -static const std::unordered_map art_charge_req_values = { { - PAIR( ACR_NULL ), - PAIR( ACR_EQUIP ), - PAIR( ACR_SKIN ), - PAIR( ACR_SLEEP ), - PAIR( ACR_RAD ), - PAIR( ACR_WET ), - PAIR( ACR_SKY ), - } -}; -#undef PAIR - +#define PAIR(x) case x: return #x; template<> -art_effect_passive string_to_enum( const std::string &data ) +std::string enum_to_string( art_effect_passive data ) { - return string_to_enum_look_up( art_effect_passive_values, data ); + switch( data ) { + // *INDENT-OFF* + PAIR( AEP_NULL ) + PAIR( AEP_STR_UP ) + PAIR( AEP_DEX_UP ) + PAIR( AEP_PER_UP ) + PAIR( AEP_INT_UP ) + PAIR( AEP_ALL_UP ) + PAIR( AEP_SPEED_UP ) + PAIR( AEP_PBLUE ) + PAIR( AEP_SNAKES ) + PAIR( AEP_INVISIBLE ) + PAIR( AEP_CLAIRVOYANCE ) + PAIR( AEP_CLAIRVOYANCE_PLUS ) + PAIR( AEP_SUPER_CLAIRVOYANCE ) + PAIR( AEP_STEALTH ) + PAIR( AEP_EXTINGUISH ) + PAIR( AEP_GLOW ) + PAIR( AEP_PSYSHIELD ) + PAIR( AEP_RESIST_ELECTRICITY ) + PAIR( AEP_CARRY_MORE ) + PAIR( AEP_SAP_LIFE ) + PAIR( AEP_FUN ) + PAIR( AEP_SPLIT ) + PAIR( AEP_HUNGER ) + PAIR( AEP_THIRST ) + PAIR( AEP_SMOKE ) + PAIR( AEP_EVIL ) + PAIR( AEP_SCHIZO ) + PAIR( AEP_RADIOACTIVE ) + PAIR( AEP_MUTAGENIC ) + PAIR( AEP_ATTENTION ) + PAIR( AEP_STR_DOWN ) + PAIR( AEP_DEX_DOWN ) + PAIR( AEP_PER_DOWN ) + PAIR( AEP_INT_DOWN ) + PAIR( AEP_ALL_DOWN ) + PAIR( AEP_SPEED_DOWN ) + PAIR( AEP_FORCE_TELEPORT ) + PAIR( AEP_MOVEMENT_NOISE ) + PAIR( AEP_BAD_WEATHER ) + PAIR( AEP_SICK ) + // *INDENT-ON* + case NUM_AEPS: + break; + } + debugmsg( "Invalid AEP" ); + abort(); } - template<> -art_effect_active string_to_enum( const std::string &data ) +std::string enum_to_string( art_effect_active data ) { - return string_to_enum_look_up( art_effect_active_values, data ); + switch( data ) { + // *INDENT-OFF* + PAIR( AEA_NULL ) + PAIR( AEA_STORM ) + PAIR( AEA_FIREBALL ) + PAIR( AEA_ADRENALINE ) + PAIR( AEA_MAP ) + PAIR( AEA_BLOOD ) + PAIR( AEA_FATIGUE ) + PAIR( AEA_ACIDBALL ) + PAIR( AEA_PULSE ) + PAIR( AEA_HEAL ) + PAIR( AEA_CONFUSED ) + PAIR( AEA_ENTRANCE ) + PAIR( AEA_BUGS ) + PAIR( AEA_TELEPORT ) + PAIR( AEA_LIGHT ) + PAIR( AEA_GROWTH ) + PAIR( AEA_HURTALL ) + PAIR( AEA_FUN ) + PAIR( AEA_SPLIT ) + PAIR( AEA_RADIATION ) + PAIR( AEA_PAIN ) + PAIR( AEA_MUTATE ) + PAIR( AEA_PARALYZE ) + PAIR( AEA_FIRESTORM ) + PAIR( AEA_ATTENTION ) + PAIR( AEA_TELEGLOW ) + PAIR( AEA_NOISE ) + PAIR( AEA_SCREAM ) + PAIR( AEA_DIM ) + PAIR( AEA_FLASH ) + PAIR( AEA_VOMIT ) + PAIR( AEA_SHADOWS ) + PAIR( AEA_STAMINA_EMPTY ) + // *INDENT-ON* + case NUM_AEAS: + break; + } + debugmsg( "Invalid AEA" ); + abort(); } template<> -art_charge string_to_enum( const std::string &data ) +std::string enum_to_string( art_charge data ) { - return string_to_enum_look_up( art_charge_values, data ); + switch( data ) { + // *INDENT-OFF* + PAIR( ARTC_NULL ) + PAIR( ARTC_TIME ) + PAIR( ARTC_SOLAR ) + PAIR( ARTC_PAIN ) + PAIR( ARTC_HP ) + PAIR( ARTC_FATIGUE ) + PAIR( ARTC_PORTAL ) + // *INDENT-ON* + case NUM_ARTCS: + break; + } + debugmsg( "Invalid ARTC" ); + abort(); } template<> -art_charge_req string_to_enum( const std::string &data ) +std::string enum_to_string( art_charge_req data ) { - return string_to_enum_look_up( art_charge_req_values, data ); + switch( data ) { + // *INDENT-OFF* + PAIR( ACR_NULL ) + PAIR( ACR_EQUIP ) + PAIR( ACR_SKIN ) + PAIR( ACR_SLEEP ) + PAIR( ACR_RAD ) + PAIR( ACR_WET ) + PAIR( ACR_SKY ) + // *INDENT-ON* + case NUM_ACRS: + break; + } + debugmsg( "Invalid ACR" ); + abort(); } +#undef PAIR + } // namespace io diff --git a/src/artifact.h b/src/artifact.h index f6093c339b6e1..3c6f409d87a33 100644 --- a/src/artifact.h +++ b/src/artifact.h @@ -10,6 +10,7 @@ class JsonObject; class JsonOut; class item; +template struct enum_traits; enum art_effect_active : int { AEA_NULL = 0, @@ -52,6 +53,11 @@ enum art_effect_active : int { NUM_AEAS }; +template<> +struct enum_traits { + static constexpr art_effect_active last = art_effect_active::NUM_AEAS; +}; + enum art_charge : int { ARTC_NULL, // Never recharges! ARTC_TIME, // Very slowly recharges with time @@ -63,6 +69,11 @@ enum art_charge : int { NUM_ARTCS }; +template<> +struct enum_traits { + static constexpr art_charge last = art_charge::NUM_ARTCS; +}; + enum art_charge_req : int { ACR_NULL = 0, //No extra requirement ACR_EQUIP, //Must be worn/wielded as appropriate @@ -74,6 +85,11 @@ enum art_charge_req : int { NUM_ACRS }; +template<> +struct enum_traits { + static constexpr art_charge_req last = art_charge_req::NUM_ACRS; +}; + /* CLASSES */ class it_artifact_tool : public itype diff --git a/src/bodypart.cpp b/src/bodypart.cpp index e0a30f19d2836..21d37963705ac 100644 --- a/src/bodypart.cpp +++ b/src/bodypart.cpp @@ -21,6 +21,9 @@ side opposite_side( side s ) return side::RIGHT; case side::RIGHT: return side::LEFT; + case side::num_sides: + debugmsg( "invalid side %d", static_cast( s ) ); + break; } return s; @@ -29,17 +32,20 @@ side opposite_side( side s ) namespace io { -static const std::map side_map = {{ - { "left", side::LEFT }, - { "right", side::RIGHT }, - { "both", side::BOTH } - } -}; - template<> -side string_to_enum( const std::string &data ) +std::string enum_to_string( side data ) { - return string_to_enum_look_up( side_map, data ); + switch( data ) { + // *INDENT-OFF* + case side::LEFT: return "left"; + case side::RIGHT: return "right"; + case side::BOTH: return "both"; + // *INDENT-ON* + case side::num_sides: + break; + } + debugmsg( "Invalid side" ); + abort(); } } // namespace io diff --git a/src/bodypart.h b/src/bodypart.h index a55585f320183..b7e2f414e6efb 100644 --- a/src/bodypart.h +++ b/src/bodypart.h @@ -39,7 +39,13 @@ struct enum_traits { enum class side : int { BOTH, LEFT, - RIGHT + RIGHT, + num_sides +}; + +template<> +struct enum_traits { + static constexpr auto last = side::num_sides; }; /** diff --git a/src/calendar.cpp b/src/calendar.cpp index b146de76b7ee9..cc70366e5746d 100644 --- a/src/calendar.cpp +++ b/src/calendar.cpp @@ -5,6 +5,7 @@ #include #include +#include "debug.h" #include "options.h" #include "rng.h" #include "string_formatter.h" @@ -154,6 +155,8 @@ double current_daylight_level( const time_point &p ) case WINTER: modifier = ( 1. - deviation ) + ( percent * deviation ); break; + default: + debugmsg( "Invalid season" ); } return modifier * default_daylight_level(); diff --git a/src/calendar.h b/src/calendar.h index 54f39bfe9cf26..a38bce3898ab4 100644 --- a/src/calendar.h +++ b/src/calendar.h @@ -11,13 +11,20 @@ class time_duration; class time_point; class JsonOut; class JsonIn; +template struct enum_traits; /** Real world seasons */ enum season_type { SPRING = 0, SUMMER = 1, AUTUMN = 2, - WINTER = 3 + WINTER = 3, + NUM_SEASONS +}; + +template<> +struct enum_traits { + static constexpr season_type last = season_type::NUM_SEASONS; }; /** Phases of the moon */ diff --git a/src/clothing_mod.cpp b/src/clothing_mod.cpp index 1d5001ecaf116..274e7a2cc1252 100644 --- a/src/clothing_mod.cpp +++ b/src/clothing_mod.cpp @@ -33,45 +33,25 @@ const clothing_mod &string_id::obj() const namespace io { -static const std::map clothing_mod_type_map = {{ - { "acid", clothing_mod_type_acid }, - { "fire", clothing_mod_type_fire }, - { "bash", clothing_mod_type_bash }, - { "cut", clothing_mod_type_cut }, - { "encumbrance", clothing_mod_type_encumbrance }, - { "warmth", clothing_mod_type_warmth }, - { "storage", clothing_mod_type_storage }, - { "invalid", clothing_mod_type_invalid } - } -}; - -template<> -clothing_mod_type string_to_enum( const std::string &data ) -{ - auto iter = clothing_mod_type_map.find( data ); - - if( iter == clothing_mod_type_map.end() ) { - debugmsg( "Invalid mod type '%s'.", data ); - return clothing_mod_type_invalid; - } - - return string_to_enum_look_up( clothing_mod_type_map, data ); -} - template<> std::string enum_to_string( clothing_mod_type data ) { - const auto iter = std::find_if( clothing_mod_type_map.begin(), clothing_mod_type_map.end(), - [data]( const std::pair &pr ) { - return pr.second == data; - } ); - - if( iter == clothing_mod_type_map.end() ) { - debugmsg( "Invalid mod type value '%d'.", data ); - return "invalid"; - } - - return iter->first; + switch( data ) { + // *INDENT-OFF* + case clothing_mod_type_acid: return "acid"; + case clothing_mod_type_fire: return "fire"; + case clothing_mod_type_bash: return "bash"; + case clothing_mod_type_cut: return "cut"; + case clothing_mod_type_encumbrance: return "encumbrance"; + case clothing_mod_type_warmth: return "warmth"; + case clothing_mod_type_storage: return "storage"; + case clothing_mod_type_invalid: return "invalid"; + // *INDENT-ON* + case num_clothing_mod_types: + break; + }; + debugmsg( "Invalid mod type value '%d'.", data ); + return "invalid"; } } // namespace io diff --git a/src/clothing_mod.h b/src/clothing_mod.h index 81dbde6964ad6..b53e121156f16 100644 --- a/src/clothing_mod.h +++ b/src/clothing_mod.h @@ -13,6 +13,8 @@ class JsonObject; class player; class item; +template struct enum_traits; + enum clothing_mod_type : int { clothing_mod_type_acid, clothing_mod_type_fire, @@ -21,7 +23,13 @@ enum clothing_mod_type : int { clothing_mod_type_encumbrance, clothing_mod_type_warmth, clothing_mod_type_storage, - clothing_mod_type_invalid + clothing_mod_type_invalid, + num_clothing_mod_types +}; + +template<> +struct enum_traits { + static constexpr clothing_mod_type last = clothing_mod_type::num_clothing_mod_types; }; struct mod_value { diff --git a/src/condition.cpp b/src/condition.cpp index 48a3522453045..9b173a3841100 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -524,11 +524,11 @@ void conditional_t::set_mission_goal( JsonObject &jo ) std::string mission_goal_str = jo.get_string( "mission_goal" ); condition = [mission_goal_str]( const T & d ) { mission *miss = d.beta->chatbin.mission_selected; - const auto mgoal = mission_goal_strs.find( mission_goal_str ); - if( !miss || mgoal == mission_goal_strs.end() ) { + if( !miss ) { return false; } - return miss->get_type().goal == mgoal->second; + const mission_goal mgoal = io::string_to_enum( mission_goal_str ); + return miss->get_type().goal == mgoal; }; } diff --git a/src/craft_command.cpp b/src/craft_command.cpp index fbc944dfa2273..66f7ab0e2b183 100644 --- a/src/craft_command.cpp +++ b/src/craft_command.cpp @@ -33,6 +33,7 @@ std::string comp_selection::nname() const case use_from_player: // Is the same as the default return; case use_from_none: case cancel: + case num_usages: break; } @@ -42,34 +43,22 @@ std::string comp_selection::nname() const namespace io { -static const std::map usage_map = {{ - { "map", usage::use_from_map }, - { "player", usage::use_from_player }, - { "both", usage::use_from_both }, - { "none", usage::use_from_none }, - { "cancel", usage::cancel } - } -}; - -template<> -usage string_to_enum( const std::string &data ) -{ - return string_to_enum_look_up( usage_map, data ); -} - template<> std::string enum_to_string( usage data ) { - const auto iter = std::find_if( usage_map.begin(), usage_map.end(), - [data]( const std::pair &kv ) { - return kv.second == data; - } ); - - if( iter == usage_map.end() ) { - throw InvalidEnumString{}; + switch( data ) { + // *INDENT-OFF* + case usage::use_from_map: return "map"; + case usage::use_from_player: return "player"; + case usage::use_from_both: return "both"; + case usage::use_from_none: return "none"; + case usage::cancel: return "cancel"; + // *INDENT-ON* + case usage::num_usages: + break; } - - return iter->first; + debugmsg( "Invalid usage" ); + abort(); } } // namespace io @@ -293,6 +282,7 @@ std::vector> craft_command::check_item_components_miss break; case use_from_none: case cancel: + case num_usages: break; } } else { @@ -316,6 +306,7 @@ std::vector> craft_command::check_item_components_miss break; case use_from_none: case cancel: + case num_usages: break; } } @@ -347,6 +338,7 @@ std::vector> craft_command::check_tool_components_miss case use_from_both: case use_from_none: case cancel: + case num_usages: break; } } else if( !crafter->has_amount( type, 1 ) && !map_inv.has_tools( type, 1 ) ) { diff --git a/src/craft_command.h b/src/craft_command.h index 0099a5f2e395b..f87cf8188d203 100644 --- a/src/craft_command.h +++ b/src/craft_command.h @@ -14,16 +14,23 @@ class player; class recipe; class JsonIn; class JsonOut; +template struct enum_traits; /** * enum used by comp_selection to indicate where a component should be consumed from. */ enum usage { + use_from_none = 0, use_from_map = 1, use_from_player = 2, use_from_both = 1 | 2, - use_from_none = 4, - cancel = 8 // FIXME: hacky. + cancel = 4, // FIXME: hacky. + num_usages +}; + +template<> +struct enum_traits { + static constexpr usage last = usage::num_usages; }; /** diff --git a/src/crafting.cpp b/src/crafting.cpp index 5822c4d549670..fb50239892a6c 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -1734,6 +1734,7 @@ bool player::craft_consume_tools( item &craft, int mulitplier, bool start_craft case use_from_both: case use_from_none: case cancel: + case num_usages: break; } } else if( !has_amount( type, 1 ) && !map_inv.has_tools( type, 1 ) ) { diff --git a/src/enum_bitset.h b/src/enum_bitset.h index f3175699c4485..31e48ec3ebab2 100644 --- a/src/enum_bitset.h +++ b/src/enum_bitset.h @@ -5,28 +5,13 @@ #include #include -template -struct enum_traits; - -namespace detail -{ - -template -using last_type = typename std::decay::last )>::type; - -template -struct has_proper_traits : std::false_type {}; - -template -struct has_proper_traits> : std::true_type {}; - -} // namespace detail +#include "enum_traits.h" template class enum_bitset { static_assert( std::is_enum::value, "the template argument is not an enum." ); - static_assert( detail::has_proper_traits::value, + static_assert( has_enum_traits::value, "a specialization of 'enum_traits' template containing 'last' element of the enum must be defined somewhere. " "The `last` constant must be of the same type as the enum iteslf." ); diff --git a/src/enum_conversions.h b/src/enum_conversions.h new file mode 100644 index 0000000000000..316f0a343309a --- /dev/null +++ b/src/enum_conversions.h @@ -0,0 +1,86 @@ +#pragma once +#ifndef CATA_ENUM_CONVERSIONS_H +#define CATA_ENUM_CONVERSIONS_H + +#include + +#include "debug.h" +#include "enum_traits.h" + +namespace io +{ +/** + * @name Enumeration (de)serialization to/from string. + * + * @ref enum_to_string converts an enumeration value to a string (which can be written to JSON). + * The result must be an non-empty string. + * + * This function must be implemented somewhere for each enumeration type for + * which conversion is required. + * + * Such enums must also specialize enum_traits to specify their 'last' member. + * + * @ref string_to_enum converts the string value back into an enumeration value. The input + * is expected to be one of the outputs of @ref enum_to_string. If the given string does + * not match an enumeration, an @ref InvalidEnumString is thrown. + * + * @code string_to_enum(enum_to_string(X)) == X @endcode must yield true for all values + * of the enumeration E. + */ +/*@{*/ +class InvalidEnumString : public std::runtime_error +{ + public: + InvalidEnumString() : std::runtime_error( "invalid enum string" ) { } + InvalidEnumString( const std::string &msg ) : std::runtime_error( msg ) { } +}; + +template +std::string enum_to_string( E data ); + +template +std::unordered_map build_enum_lookup_map() +{ + static_assert( std::is_enum::value, "E should be an enum type" ); + static_assert( has_enum_traits::value, "enum E needs a specialization of enum_traits" ); + std::unordered_map result; + + using Int = std::underlying_type_t; + constexpr Int max = static_cast( enum_traits::last ); + + for( Int i = 0; i < max; ++i ) { + E e = static_cast( i ); + auto inserted = result.emplace( enum_to_string( e ), e ); + if( !inserted.second ) { + debugmsg( "repeated enum string %s (%d and %d)", inserted.first->first, + static_cast( inserted.first->second ), i ); + abort(); + } + } + + return result; +} + +// Helper function to do the lookup in an associative container +template +inline E string_to_enum_look_up( const C &container, const std::string &data ) +{ + const auto iter = container.find( data ); + if( iter == container.end() ) { + throw InvalidEnumString{}; + } + return iter->second; +} + +template +E string_to_enum( const std::string &data ) +{ + static const std::unordered_map string_to_enum_map = + build_enum_lookup_map(); + return string_to_enum_look_up( string_to_enum_map, data ); +} + +/*@}*/ +} // namespace io + +#endif // CATA_ENUM_CONVERSIONS_H diff --git a/src/enum_traits.h b/src/enum_traits.h new file mode 100644 index 0000000000000..2cb3af1e20212 --- /dev/null +++ b/src/enum_traits.h @@ -0,0 +1,22 @@ +#pragma once +#ifndef CATA_ENUM_TRAITS_H +#define CATA_ENUM_TRAITS_H + +template +struct enum_traits; + +namespace enum_traits_detail +{ + +template +using last_type = typename std::decay::last )>::type; + +} // namespace enum_traits_detail + +template +struct has_enum_traits : std::false_type {}; + +template +struct has_enum_traits> : std::true_type {}; + +#endif // CATA_ENUM_TRAITS_H diff --git a/src/enums.h b/src/enums.h index 66417bc8d01fb..4440085106f38 100644 --- a/src/enums.h +++ b/src/enums.h @@ -2,6 +2,8 @@ #ifndef ENUMS_H #define ENUMS_H +template struct enum_traits; + template constexpr inline int sgn( const T x ) { @@ -50,6 +52,12 @@ enum ot_match_type { // occur at the beginning, end, or middle and does not have any rules about // underscore delimiting. contains, + num_ot_match_type +}; + +template<> +struct enum_traits { + static constexpr ot_match_type last = ot_match_type::num_ot_match_type; }; enum special_game_id : int { @@ -107,6 +115,11 @@ enum art_effect_passive : int { NUM_AEPS }; +template<> +struct enum_traits { + static constexpr art_effect_passive last = art_effect_passive::NUM_AEPS; +}; + enum artifact_natural_property { ARTPROP_NULL, ARTPROP_WRIGGLING, // @@ -130,7 +143,12 @@ enum artifact_natural_property { }; enum phase_id : int { - PNULL, SOLID, LIQUID, GAS, PLASMA + PNULL, SOLID, LIQUID, GAS, PLASMA, num_phases +}; + +template<> +struct enum_traits { + static constexpr phase_id last = phase_id::num_phases; }; // Return the class an in-world object uses to interact with the world. diff --git a/src/faction_camp.cpp b/src/faction_camp.cpp index a743ee394daee..f376311a7938e 100644 --- a/src/faction_camp.cpp +++ b/src/faction_camp.cpp @@ -2254,6 +2254,8 @@ bool basecamp::gathering_return( const std::string &task, time_duration min_time case WINTER: itemlist = "foraging_faction_camp_winter"; break; + default: + debugmsg( "Invalid season" ); } } if( task == "_faction_camp_trapping" || task == "_faction_camp_hunting" ) { diff --git a/src/item.cpp b/src/item.cpp index 6ea9866d238fe..8019f8f24cd39 100644 --- a/src/item.cpp +++ b/src/item.cpp @@ -583,6 +583,7 @@ body_part_set item::get_covered_body_parts( const side s ) const switch( s ) { case side::BOTH: + case side::num_sides: break; case side::LEFT: @@ -3503,6 +3504,7 @@ std::string item::display_name( unsigned int quantity ) const switch( get_side() ) { case side::BOTH: + case side::num_sides: break; case side::LEFT: sidetxt = string_format( " (%s)", _( "left" ) ); diff --git a/src/item_factory.cpp b/src/item_factory.cpp index 37b1fa03393e6..dddad4cbb95ca 100644 --- a/src/item_factory.cpp +++ b/src/item_factory.cpp @@ -2670,17 +2670,22 @@ use_function Item_factory::usage_from_string( const std::string &type ) const namespace io { -static const std::unordered_map phase_id_values = { { - { "liquid", LIQUID }, - { "solid", SOLID }, - { "gas", GAS }, - { "plasma", PLASMA }, - } -}; template<> -phase_id string_to_enum( const std::string &data ) -{ - return string_to_enum_look_up( phase_id_values, data ); +std::string enum_to_string( phase_id data ) +{ + switch( data ) { + // *INDENT-OFF* + case PNULL: return "null"; + case LIQUID: return "liquid"; + case SOLID: return "solid"; + case GAS: return "gas"; + case PLASMA: return "plasma"; + // *INDENT-ON* + case num_phases: + break; + } + debugmsg( "Invalid phase" ); + abort(); } } // namespace io diff --git a/src/json.h b/src/json.h index effca6a7c147e..f11391cebe1d4 100644 --- a/src/json.h +++ b/src/json.h @@ -14,6 +14,7 @@ #include #include "colony.h" +#include "enum_conversions.h" #include "optional.h" /* Cataclysm-DDA homegrown JSON tools @@ -44,48 +45,6 @@ class JsonError : public std::runtime_error } }; -namespace io -{ -/** - * @name Enumeration (de)serialization to/from string. - * - * @ref enum_to_string converts an enumeration value to a string (which can be written to JSON). - * The result must be an non-empty string. - * - * @ref string_to_enum converts the string value back into an enumeration value. The input - * is expected to be one of the outputs of @ref enum_to_string. If the given string does - * not match an enumeration, an @ref InvalidEnumString is to be thrown. - * - * @code string_to_enum(enum_to_string(X)) == X @endcode must yield true for all values - * of the enumeration E. - * - * The functions need to be implemented somewhere for each enumeration type they are used on. - */ -/*@{*/ -class InvalidEnumString : public std::runtime_error -{ - public: - InvalidEnumString() : std::runtime_error( "invalid enum string" ) { } - InvalidEnumString( const std::string &msg ) : std::runtime_error( msg ) { } -}; -template -E string_to_enum( const std::string &data ); -template -std::string enum_to_string( E data ); - -// Helper function to do the lookup in a container (map or unordered_map) -template -inline E string_to_enum_look_up( const C &container, const std::string &data ) -{ - const auto iter = container.find( data ); - if( iter == container.end() ) { - throw InvalidEnumString{}; - } - return iter->second; -} -/*@}*/ -} // namespace io - /* JsonIn * ====== * diff --git a/src/magic.cpp b/src/magic.cpp index 3fa1638f11bcd..96221dfef4fd0 100644 --- a/src/magic.cpp +++ b/src/magic.cpp @@ -39,64 +39,69 @@ #include "point.h" #include "string_formatter.h" -namespace -{ -const std::map target_map = { - { "ally", valid_target::target_ally }, - { "hostile", valid_target::target_hostile }, - { "self", valid_target::target_self }, - { "ground", valid_target::target_ground }, - { "none", valid_target::target_none }, - { "item", valid_target::target_item }, - { "fd_fire", valid_target::target_fd_fire }, - { "fd_blood", valid_target::target_fd_blood } -}; -const std::map bp_map = { - { "TORSO", body_part::bp_torso }, - { "HEAD", body_part::bp_head }, - { "EYES", body_part::bp_eyes }, - { "MOUTH", body_part::bp_mouth }, - { "ARM_L", body_part::bp_arm_l }, - { "ARM_R", body_part::bp_arm_r }, - { "HAND_L", body_part::bp_hand_l }, - { "HAND_R", body_part::bp_hand_r }, - { "LEG_L", body_part::bp_leg_l }, - { "LEG_R", body_part::bp_leg_r }, - { "FOOT_L", body_part::bp_foot_l }, - { "FOOT_R", body_part::bp_foot_r } -}; -const std::map flag_map = { - { "PERMANENT", spell_flag::PERMANENT }, - { "IGNORE_WALLS", spell_flag::IGNORE_WALLS }, - { "HOSTILE_SUMMON", spell_flag::HOSTILE_SUMMON }, - { "HOSTILE_50", spell_flag::HOSTILE_50 }, - { "SILENT", spell_flag::SILENT }, - { "LOUD", spell_flag::LOUD }, - { "VERBAL", spell_flag::VERBAL }, - { "SOMATIC", spell_flag::SOMATIC }, - { "NO_HANDS", spell_flag::NO_HANDS }, - { "NO_LEGS", spell_flag::NO_LEGS }, - { "CONCENTRATE", spell_flag::CONCENTRATE } -}; -} // namespace - namespace io { +// *INDENT-OFF* template<> -valid_target string_to_enum( const std::string &trigger ) -{ - return string_to_enum_look_up( target_map, trigger ); +std::string enum_to_string( valid_target data ) +{ + switch( data ) { + case valid_target::target_ally: return "ally"; + case valid_target::target_hostile: return "hostile"; + case valid_target::target_self: return "self"; + case valid_target::target_ground: return "ground"; + case valid_target::target_none: return "none"; + case valid_target::target_item: return "item"; + case valid_target::target_fd_fire: return "fd_fire"; + case valid_target::target_fd_blood: return "fd_blood"; + case valid_target::_LAST: break; + } + debugmsg( "Invalid valid_target" ); + abort(); } template<> -body_part string_to_enum( const std::string &trigger ) -{ - return string_to_enum_look_up( bp_map, trigger ); +std::string enum_to_string( body_part data ) +{ + switch( data ) { + case body_part::bp_torso: return "TORSO"; + case body_part::bp_head: return "HEAD"; + case body_part::bp_eyes: return "EYES"; + case body_part::bp_mouth: return "MOUTH"; + case body_part::bp_arm_l: return "ARM_L"; + case body_part::bp_arm_r: return "ARM_R"; + case body_part::bp_hand_l: return "HAND_L"; + case body_part::bp_hand_r: return "HAND_R"; + case body_part::bp_leg_l: return "LEG_L"; + case body_part::bp_leg_r: return "LEG_R"; + case body_part::bp_foot_l: return "FOOT_L"; + case body_part::bp_foot_r: return "FOOT_R"; + case body_part::num_bp: break; + } + debugmsg( "Invalid body_part" ); + abort(); } template<> -spell_flag string_to_enum( const std::string &trigger ) -{ - return string_to_enum_look_up( flag_map, trigger ); -} +std::string enum_to_string( spell_flag data ) +{ + switch( data ) { + case spell_flag::PERMANENT: return "PERMANENT"; + case spell_flag::IGNORE_WALLS: return "IGNORE_WALLS"; + case spell_flag::HOSTILE_SUMMON: return "HOSTILE_SUMMON"; + case spell_flag::HOSTILE_50: return "HOSTILE_50"; + case spell_flag::SILENT: return "SILENT"; + case spell_flag::LOUD: return "LOUD"; + case spell_flag::VERBAL: return "VERBAL"; + case spell_flag::SOMATIC: return "SOMATIC"; + case spell_flag::NO_HANDS: return "NO_HANDS"; + case spell_flag::NO_LEGS: return "NO_LEGS"; + case spell_flag::CONCENTRATE: return "CONCENTRATE"; + case spell_flag::LAST: break; + } + debugmsg( "Invalid spell_flag" ); + abort(); +} +// *INDENT-ON* + } // namespace io // LOADING @@ -900,9 +905,11 @@ int spell::casting_exp( const player &p ) const std::string spell::enumerate_targets() const { std::vector all_valid_targets; - for( const std::pair pair : target_map ) { - if( is_valid_target( pair.second ) && pair.second != target_none ) { - all_valid_targets.emplace_back( pair.first ); + int last_target = static_cast( valid_target::_LAST ); + for( int i = 0; i < last_target; ++i ) { + valid_target t = static_cast( i ); + if( is_valid_target( t ) && t != target_none ) { + all_valid_targets.emplace_back( io::enum_to_string( t ) ); } } if( all_valid_targets.size() == 1 ) { diff --git a/src/map_extras.cpp b/src/map_extras.cpp index 697452e67cab0..b1a24f80e2ca2 100644 --- a/src/map_extras.cpp +++ b/src/map_extras.cpp @@ -53,18 +53,20 @@ class npc_template; namespace io { -static const std::map map_extra_method_map = {{ - { "null", map_extra_method::null }, - { "map_extra_function", map_extra_method::map_extra_function }, - { "mapgen", map_extra_method::mapgen }, - { "update_mapgen", map_extra_method::update_mapgen }, - } -}; - template<> -map_extra_method string_to_enum( const std::string &data ) +std::string enum_to_string( map_extra_method data ) { - return string_to_enum_look_up( map_extra_method_map, data ); + switch( data ) { + // *INDENT-OFF* + case map_extra_method::null: return "null"; + case map_extra_method::map_extra_function: return "map_extra_function"; + case map_extra_method::mapgen: return "mapgen"; + case map_extra_method::update_mapgen: return "update_mapgen"; + case map_extra_method::num_map_extra_methods: break; + // *INDENT-ON* + } + debugmsg( "Invalid map_extra_method" ); + abort(); } } // namespace io diff --git a/src/map_extras.h b/src/map_extras.h index 9b5a89a026ca3..6d766fa923d10 100644 --- a/src/map_extras.h +++ b/src/map_extras.h @@ -13,12 +13,19 @@ class JsonObject; class map; struct tripoint; +template struct enum_traits; enum class map_extra_method : int { null = 0, map_extra_function, mapgen, update_mapgen, + num_map_extra_methods +}; + +template<> +struct enum_traits { + static constexpr map_extra_method last = map_extra_method::num_map_extra_methods; }; using map_extra_pointer = void( * )( map &, const tripoint & ); diff --git a/src/mapdata.cpp b/src/mapdata.cpp index dad1c37838a6d..ed5ce64a8901f 100644 --- a/src/mapdata.cpp +++ b/src/mapdata.cpp @@ -1075,17 +1075,21 @@ size_t ter_t::count() namespace io { -static const std::map season_map = {{ - { "spring", season_type::SPRING }, - { "summer", season_type::SUMMER }, - { "autumn", season_type::AUTUMN }, - { "winter", season_type::WINTER } - } -}; template<> -season_type string_to_enum( const std::string &data ) +std::string enum_to_string( season_type data ) { - return string_to_enum_look_up( season_map, data ); + switch( data ) { + // *INDENT-OFF* + case season_type::SPRING: return "spring"; + case season_type::SUMMER: return "summer"; + case season_type::AUTUMN: return "autumn"; + case season_type::WINTER: return "winter"; + // *INDENT-ON* + case season_type::NUM_SEASONS: + break; + } + debugmsg( "Invalid season_type" ); + abort(); } } // namespace io @@ -1104,10 +1108,7 @@ void map_data_common_t::load( JsonObject &jo, const std::string &src ) auto season_strings = harvest_jo.get_tags( "seasons" ); std::set seasons; std::transform( season_strings.begin(), season_strings.end(), std::inserter( seasons, - seasons.begin() ), - []( const std::string & data ) { - return io::string_to_enum( data ); - } ); + seasons.begin() ), io::string_to_enum ); harvest_id hl; if( harvest_jo.has_array( "entries" ) ) { diff --git a/src/mapdata.h b/src/mapdata.h index 70c4bec1cd7c0..cbad1bf2ee8e3 100644 --- a/src/mapdata.h +++ b/src/mapdata.h @@ -232,13 +232,13 @@ struct map_data_common_t { public: std::string name() const; - enum { SEASONS_PER_YEAR = 4 }; /* - * The symbol drawn on the screen for the terrain. Please note that there are extensive rules - * as to which possible object/field/entity in a single square gets drawn and that some symbols - * are "reserved" such as * and % to do programmatic behavior. + * The symbol drawn on the screen for the terrain. Please note that + * there are extensive rules as to which possible object/field/entity in + * a single square gets drawn and that some symbols are "reserved" such + * as * and % to do programmatic behavior. */ - std::array symbol_; + std::array symbol_; int light_emitted; int movecost; // The amount of movement points required to pass this terrain by default. @@ -247,7 +247,7 @@ struct map_data_common_t { translation description; - std::array color_; //The color the sym will draw in on the GUI. + std::array color_; //The color the sym will draw in on the GUI. void load_symbol( JsonObject &jo ); std::string looks_like; @@ -258,7 +258,7 @@ struct map_data_common_t { * When will this terrain/furniture get harvested and what will drop? * Note: This excludes items that take extra tools to harvest. */ - std::array harvest_by_season = {{ + std::array harvest_by_season = {{ harvest_id::NULL_ID(), harvest_id::NULL_ID(), harvest_id::NULL_ID(), harvest_id::NULL_ID() } }; diff --git a/src/mission.cpp b/src/mission.cpp index 9ff58f8755be1..4076fd1ae8865 100644 --- a/src/mission.cpp +++ b/src/mission.cpp @@ -704,33 +704,24 @@ mission_type::mission_type( mission_type_id ID, const std::string &NAME, mission namespace io { -static const std::map status_map = {{ - { "yet_to_start", mission::mission_status::yet_to_start }, - { "in_progress", mission::mission_status::in_progress }, - { "success", mission::mission_status::success }, - { "failure", mission::mission_status::failure } - } -}; -template<> -mission::mission_status string_to_enum( const std::string &data ) -{ - return string_to_enum_look_up( status_map, data ); -} - template<> std::string enum_to_string( mission::mission_status data ) { - const auto iter = std::find_if( status_map.begin(), status_map.end(), - [data]( const std::pair &pr ) { - return pr.second == data; - } ); + switch( data ) { + // *INDENT-OFF* + case mission::mission_status::yet_to_start: return "yet_to_start"; + case mission::mission_status::in_progress: return "in_progress"; + case mission::mission_status::success: return "success"; + case mission::mission_status::failure: return "failure"; + // *INDENT-ON* + case mission::mission_status::num_mission_status: + break; - if( iter == status_map.end() ) { - throw InvalidEnumString{}; } - - return iter->first; + debugmsg( "Invalid mission_status" ); + abort(); } + } // namespace io mission::mission_status mission::status_from_string( const std::string &s ) diff --git a/src/mission.h b/src/mission.h index 4a02ce68effeb..9640feb4866f3 100644 --- a/src/mission.h +++ b/src/mission.h @@ -33,6 +33,7 @@ class JsonOut; class overmapbuffer; class item; class npc; +template struct enum_traits; enum npc_mission : int; @@ -51,6 +52,11 @@ enum mission_origin { NUM_ORIGIN }; +template<> +struct enum_traits { + static constexpr mission_origin last = mission_origin::NUM_ORIGIN; +}; + enum mission_goal { MGOAL_NULL = 0, MGOAL_GO_TO, // Reach a certain overmap tile @@ -71,25 +77,10 @@ enum mission_goal { MGOAL_CONDITION, // Satisfy the dynamically created condition and talk to the mission giver NUM_MGOAL }; -const std::unordered_map mission_goal_strs = { { - { "MGOAL_NULL", MGOAL_NULL }, - { "MGOAL_GO_TO", MGOAL_GO_TO }, - { "MGOAL_GO_TO_TYPE", MGOAL_GO_TO_TYPE }, - { "MGOAL_FIND_ITEM", MGOAL_FIND_ITEM }, - { "MGOAL_FIND_ITEM_GROUP", MGOAL_FIND_ITEM_GROUP }, - { "MGOAL_FIND_ANY_ITEM", MGOAL_FIND_ANY_ITEM }, - { "MGOAL_FIND_MONSTER", MGOAL_FIND_MONSTER }, - { "MGOAL_FIND_NPC", MGOAL_FIND_NPC }, - { "MGOAL_ASSASSINATE", MGOAL_ASSASSINATE }, - { "MGOAL_KILL_MONSTER", MGOAL_KILL_MONSTER }, - { "MGOAL_KILL_MONSTER_TYPE", MGOAL_KILL_MONSTER_TYPE }, - { "MGOAL_RECRUIT_NPC", MGOAL_RECRUIT_NPC }, - { "MGOAL_RECRUIT_NPC_CLASS", MGOAL_RECRUIT_NPC_CLASS }, - { "MGOAL_COMPUTER_TOGGLE", MGOAL_COMPUTER_TOGGLE }, - { "MGOAL_KILL_MONSTER_SPEC", MGOAL_KILL_MONSTER_SPEC }, - { "MGOAL_TALK_TO_NPC", MGOAL_TALK_TO_NPC }, - { "MGOAL_CONDITION", MGOAL_CONDITION } - } + +template<> +struct enum_traits { + static constexpr mission_goal last = mission_goal::NUM_MGOAL; }; struct mission_place { @@ -300,7 +291,8 @@ class mission yet_to_start, in_progress, success, - failure + failure, + num_mission_status }; private: // So mission_type::create is simpler @@ -473,4 +465,9 @@ class mission }; +template<> +struct enum_traits { + static constexpr mission::mission_status last = mission::mission_status::num_mission_status; +}; + #endif diff --git a/src/mission_companion.cpp b/src/mission_companion.cpp index 27f568c1817e0..708e05a3fc9cd 100644 --- a/src/mission_companion.cpp +++ b/src/mission_companion.cpp @@ -1445,6 +1445,8 @@ bool talk_function::forage_return( npc &p ) case WINTER: itemlist = "forage_winter"; break; + default: + debugmsg( "Invalid season" ); } } auto result = item_group::item_from( itemlist ); diff --git a/src/missiondef.cpp b/src/missiondef.cpp index ebc9714fa2fea..533f02a44a337 100644 --- a/src/missiondef.cpp +++ b/src/missiondef.cpp @@ -139,45 +139,53 @@ static const std::map> trip namespace io { -static const std::map origin_map = {{ - { "ORIGIN_NULL", ORIGIN_NULL }, - { "ORIGIN_GAME_START", ORIGIN_GAME_START }, - { "ORIGIN_OPENER_NPC", ORIGIN_OPENER_NPC }, - { "ORIGIN_ANY_NPC", ORIGIN_ANY_NPC }, - { "ORIGIN_SECONDARY", ORIGIN_SECONDARY }, - { "ORIGIN_COMPUTER", ORIGIN_COMPUTER } - } -}; template<> -mission_origin string_to_enum( const std::string &data ) +std::string enum_to_string( mission_origin data ) { - return string_to_enum_look_up( origin_map, data ); + switch( data ) { + // *INDENT-OFF* + case ORIGIN_NULL: return "ORIGIN_NULL"; + case ORIGIN_GAME_START: return "ORIGIN_GAME_START"; + case ORIGIN_OPENER_NPC: return "ORIGIN_OPENER_NPC"; + case ORIGIN_ANY_NPC: return "ORIGIN_ANY_NPC"; + case ORIGIN_SECONDARY: return "ORIGIN_SECONDARY"; + case ORIGIN_COMPUTER: return "ORIGIN_COMPUTER"; + // *INDENT-ON* + case mission_origin::NUM_ORIGIN: + break; + } + debugmsg( "Invalid mission_origin" ); + abort(); } -static const std::map goal_map = {{ - { "MGOAL_NULL", MGOAL_NULL }, - { "MGOAL_GO_TO", MGOAL_GO_TO }, - { "MGOAL_GO_TO_TYPE", MGOAL_GO_TO_TYPE }, - { "MGOAL_FIND_ITEM", MGOAL_FIND_ITEM }, - { "MGOAL_FIND_ANY_ITEM", MGOAL_FIND_ANY_ITEM }, - { "MGOAL_FIND_ITEM_GROUP", MGOAL_FIND_ITEM_GROUP }, - { "MGOAL_FIND_MONSTER", MGOAL_FIND_MONSTER }, - { "MGOAL_FIND_NPC", MGOAL_FIND_NPC }, - { "MGOAL_ASSASSINATE", MGOAL_ASSASSINATE }, - { "MGOAL_KILL_MONSTER", MGOAL_KILL_MONSTER }, - { "MGOAL_KILL_MONSTER_TYPE", MGOAL_KILL_MONSTER_TYPE }, - { "MGOAL_KILL_MONSTER_SPEC", MGOAL_KILL_MONSTER_SPEC }, - { "MGOAL_RECRUIT_NPC", MGOAL_RECRUIT_NPC }, - { "MGOAL_RECRUIT_NPC_CLASS", MGOAL_RECRUIT_NPC_CLASS }, - { "MGOAL_COMPUTER_TOGGLE", MGOAL_COMPUTER_TOGGLE }, - { "MGOAL_TALK_TO_NPC", MGOAL_TALK_TO_NPC }, - { "MGOAL_CONDITION", MGOAL_CONDITION } - } -}; template<> -mission_goal string_to_enum( const std::string &data ) +std::string enum_to_string( mission_goal data ) { - return string_to_enum_look_up( goal_map, data ); + switch( data ) { + // *INDENT-OFF* + case MGOAL_NULL: return "MGOAL_NULL"; + case MGOAL_GO_TO: return "MGOAL_GO_TO"; + case MGOAL_GO_TO_TYPE: return "MGOAL_GO_TO_TYPE"; + case MGOAL_FIND_ITEM: return "MGOAL_FIND_ITEM"; + case MGOAL_FIND_ANY_ITEM: return "MGOAL_FIND_ANY_ITEM"; + case MGOAL_FIND_ITEM_GROUP: return "MGOAL_FIND_ITEM_GROUP"; + case MGOAL_FIND_MONSTER: return "MGOAL_FIND_MONSTER"; + case MGOAL_FIND_NPC: return "MGOAL_FIND_NPC"; + case MGOAL_ASSASSINATE: return "MGOAL_ASSASSINATE"; + case MGOAL_KILL_MONSTER: return "MGOAL_KILL_MONSTER"; + case MGOAL_KILL_MONSTER_TYPE: return "MGOAL_KILL_MONSTER_TYPE"; + case MGOAL_KILL_MONSTER_SPEC: return "MGOAL_KILL_MONSTER_SPEC"; + case MGOAL_RECRUIT_NPC: return "MGOAL_RECRUIT_NPC"; + case MGOAL_RECRUIT_NPC_CLASS: return "MGOAL_RECRUIT_NPC_CLASS"; + case MGOAL_COMPUTER_TOGGLE: return "MGOAL_COMPUTER_TOGGLE"; + case MGOAL_TALK_TO_NPC: return "MGOAL_TALK_TO_NPC"; + case MGOAL_CONDITION: return "MGOAL_CONDITION"; + // *INDENT-ON* + case mission_goal::NUM_MGOAL: + break; + } + debugmsg( "Invalid mission_goal" ); + abort(); } } // namespace io @@ -235,7 +243,7 @@ void mission_type::load( JsonObject &jo, const std::string &src ) 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 ) ); + origins.emplace_back( io::string_to_enum( m ) ); } } diff --git a/src/monstergenerator.cpp b/src/monstergenerator.cpp index dcc0b4f780782..f2d57a9775cee 100644 --- a/src/monstergenerator.cpp +++ b/src/monstergenerator.cpp @@ -27,152 +27,155 @@ #include "units.h" #include "translations.h" -namespace -{ - -const std::map trigger_map = { - { "STALK", mon_trigger::STALK }, - { "MEAT", mon_trigger::MEAT }, - { "PLAYER_WEAK", mon_trigger::HOSTILE_WEAK }, - { "PLAYER_CLOSE", mon_trigger::HOSTILE_CLOSE }, - { "HURT", mon_trigger::HURT }, - { "FIRE", mon_trigger::FIRE }, - { "FRIEND_DIED", mon_trigger::FRIEND_DIED }, - { "FRIEND_ATTACKED", mon_trigger::FRIEND_ATTACKED }, - { "SOUND", mon_trigger::SOUND }, - { "PLAYER_NEAR_BABY", mon_trigger::PLAYER_NEAR_BABY }, - { "MATING_SEASON", mon_trigger::MATING_SEASON } -}; - -const std::map flag_map = { - // see mtype.h for commentary - { "SEES", MF_SEES }, - { "HEARS", MF_HEARS }, - { "GOODHEARING", MF_GOODHEARING }, - { "SMELLS", MF_SMELLS }, - { "KEENNOSE", MF_KEENNOSE }, - { "STUMBLES", MF_STUMBLES }, - { "WARM", MF_WARM }, - { "NOHEAD", MF_NOHEAD }, - { "HARDTOSHOOT", MF_HARDTOSHOOT }, - { "GRABS", MF_GRABS }, - { "BASHES", MF_BASHES }, - { "GROUP_BASH", MF_GROUP_BASH }, - { "DESTROYS", MF_DESTROYS }, - { "BORES", MF_BORES }, - { "POISON", MF_POISON }, - { "VENOM", MF_VENOM }, - { "BADVENOM", MF_BADVENOM }, - { "PARALYZEVENOM", MF_PARALYZE }, - { "BLEED", MF_BLEED }, - { "WEBWALK", MF_WEBWALK }, - { "DIGS", MF_DIGS }, - { "CAN_DIG", MF_CAN_DIG }, - { "CAN_OPEN_DOORS", MF_CAN_OPEN_DOORS }, - { "FLIES", MF_FLIES }, - { "AQUATIC", MF_AQUATIC }, - { "SWIMS", MF_SWIMS }, - { "FISHABLE", MF_FISHABLE }, - { "ATTACKMON", MF_ATTACKMON }, - { "ANIMAL", MF_ANIMAL }, - { "PLASTIC", MF_PLASTIC }, - { "SUNDEATH", MF_SUNDEATH }, - { "ELECTRIC", MF_ELECTRIC }, - { "ACIDPROOF", MF_ACIDPROOF }, - { "ACIDTRAIL", MF_ACIDTRAIL }, - { "SHORTACIDTRAIL", MF_SHORTACIDTRAIL }, - { "FIREPROOF", MF_FIREPROOF }, - { "SLUDGEPROOF", MF_SLUDGEPROOF }, - { "SLUDGETRAIL", MF_SLUDGETRAIL }, - { "FIREY", MF_FIREY }, - { "QUEEN", MF_QUEEN }, - { "ELECTRONIC", MF_ELECTRONIC }, - { "FUR", MF_FUR }, - { "LEATHER", MF_LEATHER }, - { "WOOL", MF_WOOL }, - { "FEATHER", MF_FEATHER }, - { "CBM_CIV", MF_CBM_CIV }, - { "BONES", MF_BONES }, - { "FAT", MF_FAT }, - { "IMMOBILE", MF_IMMOBILE }, - { "RIDEABLE_MECH", MF_RIDEABLE_MECH }, - { "MILITARY_MECH", MF_MILITARY_MECH }, - { "MECH_RECON_VISION", MF_MECH_RECON_VISION }, - { "MECH_DEFENSIVE", MF_MECH_DEFENSIVE }, - { "HIT_AND_RUN", MF_HIT_AND_RUN }, - { "GUILT", MF_GUILT }, - { "HUMAN", MF_HUMAN }, - { "NO_BREATHE", MF_NO_BREATHE }, - { "REGENERATES_50", MF_REGENERATES_50 }, - { "REGENERATES_10", MF_REGENERATES_10 }, - { "REGENERATES_1", MF_REGENERATES_1 }, - { "REGENERATES_IN_DARK", MF_REGENERATES_IN_DARK }, - { "FLAMMABLE", MF_FLAMMABLE }, - { "REVIVES", MF_REVIVES }, - { "CHITIN", MF_CHITIN }, - { "VERMIN", MF_VERMIN }, - { "NOGIB", MF_NOGIB }, - { "ABSORBS", MF_ABSORBS }, - { "ABSORBS_SPLITS", MF_ABSORBS_SPLITS }, - { "LARVA", MF_LARVA }, - { "ARTHROPOD_BLOOD", MF_ARTHROPOD_BLOOD }, - { "ACID_BLOOD", MF_ACID_BLOOD }, - { "BILE_BLOOD", MF_BILE_BLOOD }, - { "REGEN_MORALE", MF_REGENMORALE }, - { "CBM_POWER", MF_CBM_POWER }, - { "CBM_SCI", MF_CBM_SCI }, - { "CBM_OP", MF_CBM_OP }, - { "CBM_TECH", MF_CBM_TECH }, - { "CBM_SUBS", MF_CBM_SUBS }, - { "FILTHY", MF_FILTHY }, - { "SWARMS", MF_SWARMS }, - { "CLIMBS", MF_CLIMBS }, - { "GROUP_MORALE", MF_GROUP_MORALE }, - { "INTERIOR_AMMO", MF_INTERIOR_AMMO }, - { "NIGHT_INVISIBILITY", MF_NIGHT_INVISIBILITY }, - { "REVIVES_HEALTHY", MF_REVIVES_HEALTHY }, - { "NO_NECRO", MF_NO_NECRO }, - { "PACIFIST", MF_PACIFIST }, - { "PUSH_MON", MF_PUSH_MON }, - { "PUSH_VEH", MF_PUSH_VEH }, - { "PATH_AVOID_DANGER_1", MF_AVOID_DANGER_1 }, - { "PATH_AVOID_DANGER_2", MF_AVOID_DANGER_2 }, - { "PATH_AVOID_FALL", MF_AVOID_FALL }, - { "PATH_AVOID_FIRE", MF_AVOID_FIRE }, - { "PRIORITIZE_TARGETS", MF_PRIORITIZE_TARGETS }, - { "NOT_HALLUCINATION", MF_NOT_HALLU }, - { "CATFOOD", MF_CATFOOD }, - { "CANPLAY", MF_CANPLAY }, - { "CATTLEFODDER", MF_CATTLEFODDER }, - { "BIRDFOOD", MF_BIRDFOOD }, - { "PET_MOUNTABLE", MF_PET_MOUNTABLE }, - { "DOGFOOD", MF_DOGFOOD }, - { "MILKABLE", MF_MILKABLE }, - { "NO_BREED", MF_NO_BREED }, - { "PET_WONT_FOLLOW", MF_PET_WONT_FOLLOW }, - { "DRIPS_NAPALM", MF_DRIPS_NAPALM }, - { "DRIPS_GASOLINE", MF_DRIPS_GASOLINE }, - { "ELECTRIC_FIELD", MF_ELECTRIC_FIELD }, - { "STUN_IMMUNE", MF_STUN_IMMUNE }, - { "LOUDMOVES", MF_LOUDMOVES }, - { "DROPS_AMMO", MF_DROPS_AMMO } -}; - -} // namespace - namespace io { template<> -mon_trigger string_to_enum( const std::string &trigger ) +std::string enum_to_string( mon_trigger data ) { - return string_to_enum_look_up( trigger_map, trigger ); + switch( data ) { + // *INDENT-OFF* + case mon_trigger::STALK: return "STALK"; + case mon_trigger::MEAT: return "MEAT"; + case mon_trigger::HOSTILE_WEAK: return "PLAYER_WEAK"; + case mon_trigger::HOSTILE_CLOSE: return "PLAYER_CLOSE"; + case mon_trigger::HURT: return "HURT"; + case mon_trigger::FIRE: return "FIRE"; + case mon_trigger::FRIEND_DIED: return "FRIEND_DIED"; + case mon_trigger::FRIEND_ATTACKED: return "FRIEND_ATTACKED"; + case mon_trigger::SOUND: return "SOUND"; + case mon_trigger::PLAYER_NEAR_BABY: return "PLAYER_NEAR_BABY"; + case mon_trigger::MATING_SEASON: return "MATING_SEASON"; + // *INDENT-ON* + case mon_trigger::_LAST: + break; + } + debugmsg( "Invalid mon_trigger" ); + abort(); } template<> -m_flag string_to_enum( const std::string &flag ) +std::string enum_to_string( m_flag data ) { - return string_to_enum_look_up( flag_map, flag ); + // see mtype.h for commentary + switch( data ) { + // *INDENT-OFF* + case MF_SEES: return "SEES"; + case MF_HEARS: return "HEARS"; + case MF_GOODHEARING: return "GOODHEARING"; + case MF_SMELLS: return "SMELLS"; + case MF_KEENNOSE: return "KEENNOSE"; + case MF_STUMBLES: return "STUMBLES"; + case MF_WARM: return "WARM"; + case MF_NOHEAD: return "NOHEAD"; + case MF_HARDTOSHOOT: return "HARDTOSHOOT"; + case MF_GRABS: return "GRABS"; + case MF_BASHES: return "BASHES"; + case MF_GROUP_BASH: return "GROUP_BASH"; + case MF_DESTROYS: return "DESTROYS"; + case MF_BORES: return "BORES"; + case MF_POISON: return "POISON"; + case MF_VENOM: return "VENOM"; + case MF_BADVENOM: return "BADVENOM"; + case MF_PARALYZE: return "PARALYZEVENOM"; + case MF_BLEED: return "BLEED"; + case MF_WEBWALK: return "WEBWALK"; + case MF_DIGS: return "DIGS"; + case MF_CAN_DIG: return "CAN_DIG"; + case MF_CAN_OPEN_DOORS: return "CAN_OPEN_DOORS"; + case MF_FLIES: return "FLIES"; + case MF_AQUATIC: return "AQUATIC"; + case MF_SWIMS: return "SWIMS"; + case MF_FISHABLE: return "FISHABLE"; + case MF_ATTACKMON: return "ATTACKMON"; + case MF_ANIMAL: return "ANIMAL"; + case MF_PLASTIC: return "PLASTIC"; + case MF_SUNDEATH: return "SUNDEATH"; + case MF_ELECTRIC: return "ELECTRIC"; + case MF_ACIDPROOF: return "ACIDPROOF"; + case MF_ACIDTRAIL: return "ACIDTRAIL"; + case MF_SHORTACIDTRAIL: return "SHORTACIDTRAIL"; + case MF_FIREPROOF: return "FIREPROOF"; + case MF_SLUDGEPROOF: return "SLUDGEPROOF"; + case MF_SLUDGETRAIL: return "SLUDGETRAIL"; + case MF_FIREY: return "FIREY"; + case MF_QUEEN: return "QUEEN"; + case MF_ELECTRONIC: return "ELECTRONIC"; + case MF_FUR: return "FUR"; + case MF_LEATHER: return "LEATHER"; + case MF_WOOL: return "WOOL"; + case MF_FEATHER: return "FEATHER"; + case MF_CBM_CIV: return "CBM_CIV"; + case MF_BONES: return "BONES"; + case MF_FAT: return "FAT"; + case MF_IMMOBILE: return "IMMOBILE"; + case MF_RIDEABLE_MECH: return "RIDEABLE_MECH"; + case MF_MILITARY_MECH: return "MILITARY_MECH"; + case MF_MECH_RECON_VISION: return "MECH_RECON_VISION"; + case MF_MECH_DEFENSIVE: return "MECH_DEFENSIVE"; + case MF_HIT_AND_RUN: return "HIT_AND_RUN"; + case MF_GUILT: return "GUILT"; + case MF_HUMAN: return "HUMAN"; + case MF_NO_BREATHE: return "NO_BREATHE"; + case MF_REGENERATES_50: return "REGENERATES_50"; + case MF_REGENERATES_10: return "REGENERATES_10"; + case MF_REGENERATES_1: return "REGENERATES_1"; + case MF_REGENERATES_IN_DARK: return "REGENERATES_IN_DARK"; + case MF_FLAMMABLE: return "FLAMMABLE"; + case MF_REVIVES: return "REVIVES"; + case MF_CHITIN: return "CHITIN"; + case MF_VERMIN: return "VERMIN"; + case MF_NOGIB: return "NOGIB"; + case MF_ABSORBS: return "ABSORBS"; + case MF_ABSORBS_SPLITS: return "ABSORBS_SPLITS"; + case MF_LARVA: return "LARVA"; + case MF_ARTHROPOD_BLOOD: return "ARTHROPOD_BLOOD"; + case MF_ACID_BLOOD: return "ACID_BLOOD"; + case MF_BILE_BLOOD: return "BILE_BLOOD"; + case MF_REGENMORALE: return "REGEN_MORALE"; + case MF_CBM_POWER: return "CBM_POWER"; + case MF_CBM_SCI: return "CBM_SCI"; + case MF_CBM_OP: return "CBM_OP"; + case MF_CBM_TECH: return "CBM_TECH"; + case MF_CBM_SUBS: return "CBM_SUBS"; + case MF_FILTHY: return "FILTHY"; + case MF_SWARMS: return "SWARMS"; + case MF_CLIMBS: return "CLIMBS"; + case MF_GROUP_MORALE: return "GROUP_MORALE"; + case MF_INTERIOR_AMMO: return "INTERIOR_AMMO"; + case MF_NIGHT_INVISIBILITY: return "NIGHT_INVISIBILITY"; + case MF_REVIVES_HEALTHY: return "REVIVES_HEALTHY"; + case MF_NO_NECRO: return "NO_NECRO"; + case MF_PACIFIST: return "PACIFIST"; + case MF_PUSH_MON: return "PUSH_MON"; + case MF_PUSH_VEH: return "PUSH_VEH"; + case MF_AVOID_DANGER_1: return "PATH_AVOID_DANGER_1"; + case MF_AVOID_DANGER_2: return "PATH_AVOID_DANGER_2"; + case MF_AVOID_FALL: return "PATH_AVOID_FALL"; + case MF_AVOID_FIRE: return "PATH_AVOID_FIRE"; + case MF_PRIORITIZE_TARGETS: return "PRIORITIZE_TARGETS"; + case MF_NOT_HALLU: return "NOT_HALLUCINATION"; + case MF_CATFOOD: return "CATFOOD"; + case MF_CANPLAY: return "CANPLAY"; + case MF_CATTLEFODDER: return "CATTLEFODDER"; + case MF_BIRDFOOD: return "BIRDFOOD"; + case MF_PET_MOUNTABLE: return "PET_MOUNTABLE"; + case MF_DOGFOOD: return "DOGFOOD"; + case MF_MILKABLE: return "MILKABLE"; + case MF_NO_BREED: return "NO_BREED"; + case MF_PET_WONT_FOLLOW: return "PET_WONT_FOLLOW"; + case MF_DRIPS_NAPALM: return "DRIPS_NAPALM"; + case MF_DRIPS_GASOLINE: return "DRIPS_GASOLINE"; + case MF_ELECTRIC_FIELD: return "ELECTRIC_FIELD"; + case MF_STUN_IMMUNE: return "STUN_IMMUNE"; + case MF_LOUDMOVES: return "LOUDMOVES"; + case MF_DROPS_AMMO: return "DROPS_AMMO"; + // *INDENT-ON* + case m_flag::MF_MAX: + break; + } + debugmsg( "Invalid m_flag" ); + abort(); } } // namespace io diff --git a/src/overmap.cpp b/src/overmap.cpp index 2c129f020bb25..6fdf1bc8888d5 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -4378,17 +4378,21 @@ overmap_special_id overmap_specials::create_building_from( const string_id ot_match_type_map = { { - { "EXACT", exact }, - { "TYPE", type }, - { "PREFIX", prefix }, - { "CONTAINS", contains }, - } -}; template<> -ot_match_type string_to_enum( const std::string &data ) -{ - return string_to_enum_look_up( ot_match_type_map, data ); +std::string enum_to_string( ot_match_type data ) +{ + switch( data ) { + // *INDENT-OFF* + case exact: return "EXACT"; + case type: return "TYPE"; + case prefix: return "PREFIX"; + case contains: return "CONTAINS"; + // *INDENT-ON* + case num_ot_match_type: + break; + } + debugmsg( "Invalid ot_match_type" ); + abort(); } } // namespace io