Skip to content

Commit

Permalink
refactor(port): Make mutation_category ids be string_ids (#3810)
Browse files Browse the repository at this point in the history
* Make mutation_category ids be string_ids

The mutation_category_trait objects have ids, but they were just
std::strings.  Make them be a string_id<mutation_category_trait>
instead.

This is a general move towards type safety, although the specific goal I
wanted to achieve was better validity checking of cata_variants.

* Removed mutation_category_id exclusion from mapgen type check

---------

Co-authored-by: John Bytheway <[email protected]>
  • Loading branch information
Vollch and jbytheway authored Dec 2, 2023
1 parent 58294c5 commit ea4db65
Show file tree
Hide file tree
Showing 23 changed files with 117 additions and 102 deletions.
3 changes: 2 additions & 1 deletion src/cata_variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ template<>
struct convert<cata_variant_type::mutagen_technique> : convert_enum<mutagen_technique> {};

template<>
struct convert<cata_variant_type::mutation_category_id> : convert_string<std::string> {};
struct convert<cata_variant_type::mutation_category_id> :
convert_string_id<mutation_category_id> {};

template<>
struct convert<cata_variant_type::npc_template_id> : convert_string_id<npc_template_id> {};
Expand Down
10 changes: 5 additions & 5 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8300,7 +8300,7 @@ void Character::set_highest_cat_level()
for( const std::pair<const trait_id, int> &i : dependency_map ) {
const mutation_branch &mdata = i.first.obj();
if( !mdata.flags.count( flag_NON_THRESH ) ) {
for( const std::string &cat : mdata.category ) {
for( const mutation_category_id &cat : mdata.category ) {
// Decay category strength based on how far it is from the current mutation
mutation_category_level[cat] += 8 / static_cast<int>( std::pow( 2, i.second ) );
}
Expand Down Expand Up @@ -8333,17 +8333,17 @@ void Character::drench_mut_calc()
}

/// Returns the mutation category with the highest strength
std::string Character::get_highest_category() const
mutation_category_id Character::get_highest_category() const
{
int iLevel = 0;
std::string sMaxCat;
mutation_category_id sMaxCat;

for( const std::pair<const std::string, int> &elem : mutation_category_level ) {
for( const std::pair<const mutation_category_id, int> &elem : mutation_category_level ) {
if( elem.second > iLevel ) {
sMaxCat = elem.first;
iLevel = elem.second;
} else if( elem.second == iLevel ) {
sMaxCat.clear(); // no category on ties
sMaxCat = mutation_category_id(); // no category on ties
}
}
return sMaxCat;
Expand Down
10 changes: 5 additions & 5 deletions src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,7 @@ class Character : public Creature, public location_visitable<Character>
/** Returns true if the player doesn't have the mutation or a conflicting one and it complies with the force typing */
bool mutation_ok( const trait_id &mutation, bool force_good, bool force_bad ) const;
/** Picks a random valid mutation in a category and mutate_towards() it */
void mutate_category( const std::string &mut_cat );
void mutate_category( const mutation_category_id &mut_cat );
/** Mutates toward one of the given mutations, upgrading or removing conflicts if necessary */
bool mutate_towards( std::vector<trait_id> muts, int num_tries = INT_MAX );
/** Mutates toward the entered mutation, upgrading or removing conflicts if necessary */
Expand All @@ -939,7 +939,7 @@ class Character : public Creature, public location_visitable<Character>
/** Recalculates mutation_category_level[] values for the player */
void set_highest_cat_level();
/** Returns the highest mutation category */
std::string get_highest_category() const;
mutation_category_id get_highest_category() const;
/** Recalculates mutation drench protection for all bodyparts (ignored/good/neutral stats) */
void drench_mut_calc();
/** Recursively traverses the mutation's prerequisites and replacements, building up a map */
Expand All @@ -949,8 +949,8 @@ class Character : public Creature, public location_visitable<Character>
/**
* Returns true if this category of mutation is allowed.
*/
bool is_category_allowed( const std::vector<std::string> &category ) const;
bool is_category_allowed( const std::string &category ) const;
bool is_category_allowed( const std::vector<mutation_category_id> &category ) const;
bool is_category_allowed( const mutation_category_id &category ) const;

bool is_weak_to_water() const;

Expand Down Expand Up @@ -1847,7 +1847,7 @@ class Character : public Creature, public location_visitable<Character>
// the amount healed per bodypart per day
std::array<int, num_hp_parts> healed_total;

std::map<std::string, int> mutation_category_level;
std::map<mutation_category_id, int> mutation_category_level;

int adjust_for_focus( int amount ) const;
void update_type_of_scent( bool init = false );
Expand Down
8 changes: 5 additions & 3 deletions src/consumption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ static const efftype_id effect_visuals( "visuals" );

static const itype_id itype_syringe( "syringe" );

static const mutation_category_id mutation_category_URSINE( "URSINE" );

static const trait_id trait_ACIDBLOOD( "ACIDBLOOD" );
static const trait_id trait_AMORPHOUS( "AMORPHOUS" );
static const trait_id trait_ANTIFRUIT( "ANTIFRUIT" );
Expand Down Expand Up @@ -1151,11 +1153,11 @@ void Character::modify_morale( item &food, int nutr )
}
if( food.has_flag( flag_URSINE_HONEY ) && ( !crossed_threshold() ||
has_trait( trait_THRESH_URSINE ) ) &&
mutation_category_level["URSINE"] > 40 ) {
mutation_category_level[mutation_category_URSINE] > 40 ) {
// Need at least 5 bear mutations for effect to show, to filter out mutations in common with other categories
int honey_fun = has_trait( trait_THRESH_URSINE ) ?
std::min( mutation_category_level["URSINE"] / 8, 20 ) :
mutation_category_level["URSINE"] / 12;
std::min( mutation_category_level[mutation_category_URSINE] / 8, 20 ) :
mutation_category_level[mutation_category_URSINE] / 12;
if( honey_fun < 10 ) {
add_msg_if_player( m_good, _( "You find the sweet taste of honey surprisingly palatable." ) );
} else {
Expand Down
9 changes: 5 additions & 4 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1505,7 +1505,7 @@ int iuse::mycus( player *p, item *it, bool t, const tripoint &pos )
} else if( p->has_trait( trait_THRESH_MYCUS ) &&
!p->has_trait( trait_M_DEPENDENT ) ) { // OK, now set the hook.
if( !one_in( 3 ) ) {
p->mutate_category( "MYCUS" );
p->mutate_category( mutation_category_id( "MYCUS" ) );
p->mod_stored_nutr( 10 );
p->mod_thirst( 10 );
p->mod_fatigue( 5 );
Expand Down Expand Up @@ -6000,10 +6000,11 @@ int iuse::bell( player *p, item *it, bool, const tripoint & )
sounds::sound( p->pos(), 12, sounds::sound_t::music, _( "Clank! Clank!" ), true, "misc",
"cow_bell" );
if( !p->is_deaf() ) {
const int cow_factor = 1 + ( p->mutation_category_level.find( "CATTLE" ) ==
p->mutation_category_level.end() ?
auto cattle_level =
p->mutation_category_level.find( mutation_category_id( "CATTLE" ) );
const int cow_factor = 1 + ( cattle_level == p->mutation_category_level.end() ?
0 :
( p->mutation_category_level.find( "CATTLE" )->second ) / 8
( cattle_level->second ) / 8
);
if( x_in_y( cow_factor, 1 + cow_factor ) ) {
p->add_morale( MORALE_MUSIC, 1, 15 * ( cow_factor > 10 ? 10 : cow_factor ) );
Expand Down
10 changes: 5 additions & 5 deletions src/iuse_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4448,7 +4448,7 @@ std::unique_ptr<iuse_actor> mutagen_actor::clone() const

void mutagen_actor::load( const JsonObject &obj )
{
mutation_category = obj.get_string( "mutation_category", "ANY" );
mutation_category = mutation_category_id( obj.get_string( "mutation_category", "ANY" ) );
is_weak = obj.get_bool( "is_weak", false );
is_strong = obj.get_bool( "is_strong", false );
}
Expand All @@ -4462,7 +4462,7 @@ int mutagen_actor::use( player &p, item &it, bool, const tripoint & ) const
return checks.charges_used;
}

bool no_category = mutation_category == "ANY";
bool no_category = mutation_category == mutation_category_id( "ANY" );
bool balanced = get_option<bool>( "BALANCED_MUTATIONS" );
int accumulated_mutagen = p.get_effect_int( effect_accumulated_mutagen );
if( balanced && !is_strong && is_weak && accumulated_mutagen < 2 && no_category && !p.query_yn(
Expand Down Expand Up @@ -4518,7 +4518,7 @@ std::unique_ptr<iuse_actor> mutagen_iv_actor::clone() const

void mutagen_iv_actor::load( const JsonObject &obj )
{
mutation_category = obj.get_string( "mutation_category", "ANY" );
mutation_category = mutation_category_id( obj.get_string( "mutation_category", "ANY" ) );
}

int mutagen_iv_actor::use( player &p, item &it, bool, const tripoint & ) const
Expand Down Expand Up @@ -4566,9 +4566,9 @@ int mutagen_iv_actor::use( player &p, item &it, bool, const tripoint & ) const
p.mod_thirst( m_category.iv_thirst * mut_count );
p.mod_fatigue( m_category.iv_fatigue * mut_count );

if( m_category.id == "CHIMERA" ) {
if( m_category.id == mutation_category_id( "CHIMERA" ) ) {
p.add_morale( MORALE_MUTAGEN_CHIMERA, m_category.iv_morale, m_category.iv_morale_max );
} else if( m_category.id == "ELFA" ) {
} else if( m_category.id == mutation_category_id( "ELFA" ) ) {
p.add_morale( MORALE_MUTAGEN_ELF, m_category.iv_morale, m_category.iv_morale_max );
} else if( m_category.iv_morale > 0 ) {
p.add_morale( MORALE_MUTAGEN_MUTATION, m_category.iv_morale, m_category.iv_morale_max );
Expand Down
4 changes: 2 additions & 2 deletions src/iuse_actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1162,7 +1162,7 @@ class detach_gunmods_actor : public iuse_actor
class mutagen_actor : public iuse_actor
{
public:
std::string mutation_category;
mutation_category_id mutation_category;
bool is_weak = false;
bool is_strong = false;

Expand All @@ -1177,7 +1177,7 @@ class mutagen_actor : public iuse_actor
class mutagen_iv_actor : public iuse_actor
{
public:
std::string mutation_category;
mutation_category_id mutation_category;

mutagen_iv_actor() : iuse_actor( "mutagen_iv" ) {}

Expand Down
2 changes: 1 addition & 1 deletion src/magic_spell_effect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1069,7 +1069,7 @@ void spell_effect::mutate( const spell &sp, Creature &caster, const tripoint &ta
if( sp.has_flag( spell_flag::MUTATE_TRAIT ) ) {
guy->mutate_towards( trait_id( sp.effect_data() ) );
} else {
guy->mutate_category( sp.effect_data() );
guy->mutate_category( mutation_category_id( sp.effect_data() ) );
}
}
sp.make_sound( potential_target );
Expand Down
5 changes: 3 additions & 2 deletions src/map_field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1541,8 +1541,9 @@ void map::player_in_field( player &u )
const int intensity = cur.get_field_intensity();
bool inhaled = u.add_env_effect( effect_poison, bp_mouth, 5, intensity * 1_minutes );
if( u.has_trait( trait_THRESH_MYCUS ) || u.has_trait( trait_THRESH_MARLOSS ) ||
( ft == fd_insecticidal_gas && ( u.get_highest_category() == "INSECT" ||
u.get_highest_category() == "SPIDER" ) ) ) {
( ft == fd_insecticidal_gas &&
( u.get_highest_category() == mutation_category_id( "INSECT" ) ||
u.get_highest_category() == mutation_category_id( "SPIDER" ) ) ) ) {
inhaled |= u.add_env_effect( effect_badpoison, bp_mouth, 5, intensity * 1_minutes );
u.hurtall( rng( intensity, intensity * 2 ), nullptr );
u.add_msg_if_player( m_bad, _( "The %s burns your skin." ), cur.name() );
Expand Down
5 changes: 1 addition & 4 deletions src/mapgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1083,10 +1083,7 @@ class mapgen_value
const mapgen_parameter &param = param_it->second;
constexpr cata_variant_type req_type = cata_variant_type_for<StringId>();
cata_variant_type param_type = param.type();
// TODO: mutation_category_id also uses std::string as underlaying type,
// migrate to type safe string_id to get rid of this hack
if( param_type != req_type && req_type != cata_variant_type::string
&& req_type != cata_variant_type::mutation_category_id ) {
if( param_type != req_type && req_type != cata_variant_type::string ) {
debugmsg( "mapgen '%s' uses parameter '%s' of type '%s' in a context "
"expecting type '%s'", context, param_name,
io::enum_to_string( param_type ),
Expand Down
2 changes: 1 addition & 1 deletion src/memorial_logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ void memorial_logger::notify( const cata::event &e )
case event_type::crosses_mutation_threshold: {
character_id ch = e.get<character_id>( "character" );
if( ch == g->u.getID() ) {
std::string category_id =
mutation_category_id category_id =
e.get<cata_variant_type::mutation_category_id>( "category" );
const mutation_category_trait &category =
mutation_category_trait::get_category( category_id );
Expand Down
Loading

0 comments on commit ea4db65

Please sign in to comment.