Skip to content

Commit

Permalink
Transforming a mutation into another on activation (#39523)
Browse files Browse the repository at this point in the history
  • Loading branch information
Fris0uman authored Apr 17, 2020
1 parent 06de14f commit af60511
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 32 deletions.
28 changes: 24 additions & 4 deletions data/json/mutations/mutations.json
Original file line number Diff line number Diff line change
Expand Up @@ -2263,6 +2263,7 @@
"points": 2,
"visibility": 8,
"ugliness": 4,
"pierce_dmg_bonus": 2,
"description": "Your skin is covered in small, woody thorns. Whenever an unarmed opponent strikes a part of your body that is not covered by clothing, they will receive minor damage. Your punches may also deal extra damage.",
"prereqs": [ "BARK" ],
"category": [ "PLANT" ]
Expand Down Expand Up @@ -2450,6 +2451,7 @@
"name": { "str": "Long Fingernails" },
"points": 1,
"visibility": 1,
"pierce_dmg_bonus": 0.5,
"description": "Your fingernails are long and sharp. If you aren't wearing gloves, your unarmed attacks deal a minor amount of cutting damage.",
"types": [ "CLAWS" ],
"changes_to": [ "CLAWS", "TALONS" ],
Expand All @@ -2464,6 +2466,8 @@
"visibility": 3,
"ugliness": 2,
"cut_dmg_bonus": 3,
"pierce_dmg_bonus": 3,
"butchering_quality": 4,
"description": "You have claws on the ends of your fingers. If you aren't wearing gloves, your unarmed attacks deal a minor amount of cutting damage.",
"types": [ "CLAWS" ],
"prereqs": [ "NAILS" ],
Expand All @@ -2479,6 +2483,7 @@
"visibility": 3,
"ugliness": 4,
"cut_dmg_bonus": 1,
"butchering_quality": 4,
"flags": [ "UNARMED_BONUS" ],
"description": "Your claws have grown tougher and slightly gnarled.",
"types": [ "CLAWS" ],
Expand All @@ -2497,6 +2502,8 @@
"valid": false,
"purifiable": false,
"cut_dmg_bonus": 1,
"pierce_dmg_bonus": 3,
"butchering_quality": 8,
"flags": [ "UNARMED_BONUS" ],
"description": "Your paws are bone, muscle, and claw with a thin layer of skin and fur. They might as well be made of stainless steel.",
"types": [ "CLAWS" ],
Expand All @@ -2511,15 +2518,26 @@
"id": "CLAWS_RETRACT",
"name": { "str": "Retractable Claws" },
"points": 2,
"ugliness": 1,
"cut_dmg_bonus": 3,
"flags": [ "NEED_ACTIVE_TO_MELEE" ],
"description": "You have claws on the ends of your fingers, and can extend or retract them as desired. Gloves will still get in the way, though.",
"types": [ "CLAWS" ],
"prereqs": [ "CLAWS" ],
"cancels": [ "ARM_TENTACLES", "ARM_TENTACLES_4", "ARM_TENTACLES_8" ],
"category": [ "FELINE" ],
"active": true,
"transform": { "target": "CLAWS_RETRACT_active", "msg_transform": "You extend your claws.", "active": false, "moves": 10 },
"cost": 0
},
{
"type": "mutation",
"id": "CLAWS_RETRACT_active",
"name": { "str": "Extended Claws" },
"copy-from": "CLAWS_RETRACT",
"valid": false,
"ugliness": 1,
"cut_dmg_bonus": 3,
"pierce_dmg_bonus": 3,
"butchering_quality": 4,
"description": "Sharp claws are exten from the end of your fingers.",
"transform": { "target": "CLAWS_RETRACT", "msg_transform": "You retract your claws.", "active": false, "moves": 10 },
"cost": 0
},
{
Expand Down Expand Up @@ -2555,6 +2573,7 @@
"visibility": 4,
"ugliness": 3,
"cut_dmg_bonus": 3,
"butchering_quality": 4,
"flags": [ "UNARMED_BONUS" ],
"mixed_effect": true,
"restricts_gear": [ "HAND_L", "HAND_R" ],
Expand Down Expand Up @@ -3633,6 +3652,7 @@
"points": 1,
"visibility": 8,
"ugliness": 6,
"butchering_quality": 4,
"mixed_effect": true,
"description": "A set of insect-like mandibles have grown around your mouth. They allow you to eat faster and provide a slicing unarmed attack, but prevent wearing mouthwear. Slightly reduces wet effects.",
"types": [ "TEETH", "MUZZLE" ],
Expand Down
1 change: 0 additions & 1 deletion doc/JSON_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,6 @@ Also see `monster_attacks.json` for more special attacks, for example, impale an
#### Flags
- ```UNARMED_BONUS``` You get a bonus to unarmed bash and cut damage equal to unarmed_skill/2 up to 4.
- ```NEED_ACTIVE_TO_MELEE``` This mutation gives bonus to unarmed melee only if it's active.
- ```NO_DISEASE``` This mutation grants immunity to diseases.
- ```NO_THIRST``` Your thirst is not modified by food or drinks.
- ```NO_RADIATION``` This mutation grants immunity to radiations.
Expand Down
7 changes: 7 additions & 0 deletions doc/JSON_INFO.md
Original file line number Diff line number Diff line change
Expand Up @@ -1239,7 +1239,9 @@ an `event_statistic`. For example:
"visibility": 0, // Visibility of the trait for purposes of NPC interaction (default: 0)
"ugliness": 0, // Ugliness of the trait for purposes of NPC interaction (default: 0)
"cut_dmg_bonus": 3, // Bonus to unarmed cut damage (default: 0)
"pierce_dmg_bonus": 3, // Bonus to unarmed pierce damage (default: 0.0)
"bash_dmg_bonus": 3, // Bonus to unarmed bash damage (default: 0)
"butchering_quality": 4, // Butchering quality of this mutations (default: 0)
"rand_cut_bonus": { "min": 2, "max": 3 }, // Random bonus to unarmed cut damage between min and max.
"rand_bash_bonus": { "min": 2, "max": 3 }, // Random bonus to unarmed bash damage between min and max.
"bodytemp_modifiers" : [100, 150], // Range of additional bodytemp units (these units are described in 'weather.h'. First value is used if the person is already overheated, second one if it's not.
Expand Down Expand Up @@ -1320,6 +1322,11 @@ an `event_statistic`. For example:
"healing_awake": 1.0, // Healing rate per turn while awake.
"healing_resting": 0.5, // Healing rate per turn while resting.
"mending_modifier": 1.2 // Multiplier on how fast your limbs mend - This value would make your limbs mend 20% faster
"transform": { "target": "BIOLUM1", // Trait_id of the mutation this one will transfomr into
"msg_transform": "You turn your photophore OFF.", // message displayed upon transformation
"active": false , // Will the target mutation start powered ( turn ON ).
"moves": 100 // how many moves this costs. (default: 0)
}
```

### Vehicle Groups
Expand Down
2 changes: 2 additions & 0 deletions src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,8 @@ class Character : public Creature, public visitable<Character>
/** Add or removes a mutation on the player, but does not trigger mutation loss/gain effects. */
void set_mutation( const trait_id & );
void unset_mutation( const trait_id & );
/**Unset switched mutation and set target mutation instead*/
void switch_mutations( const trait_id &switched, const trait_id &target, bool start_powered );

// Trigger and disable mutations that can be so toggled.
void activate_mutation( const trait_id &mutation );
Expand Down
24 changes: 7 additions & 17 deletions src/melee.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ static const efftype_id effect_narcosis( "narcosis" );
static const efftype_id effect_poison( "poison" );
static const efftype_id effect_stunned( "stunned" );

static const trait_id trait_CLAWS( "CLAWS" );
static const trait_id trait_CLAWS_RETRACT( "CLAWS_RETRACT" );
static const trait_id trait_CLAWS_ST( "CLAWS_ST" );
static const trait_id trait_CLAWS_TENTACLE( "CLAWS_TENTACLE" );
static const trait_id trait_CLUMSY( "CLUMSY" );
static const trait_id trait_DEBUG_NIGHTVISION( "DEBUG_NIGHTVISION" );
Expand Down Expand Up @@ -947,6 +944,7 @@ void Character::roll_cut_damage( bool crit, damage_instance &di, bool average,
if( has_bionic( bionic_id( "bio_razors" ) ) ) {
per_hand += 2;
}

for( const trait_id &mut : get_mutations() ) {
if( mut->flags.count( "NEED_ACTIVE_TO_MELEE" ) > 0 && !has_active_mutation( mut ) ) {
continue;
Expand Down Expand Up @@ -1014,27 +1012,19 @@ void Character::roll_stab_damage( bool crit, damage_instance &di, bool /*average
weap.is_null();
if( left_empty || right_empty ) {
float per_hand = 0.0f;
if( has_trait( trait_CLAWS ) || has_active_mutation( trait_CLAWS_RETRACT ) ) {
per_hand += 3;
}

if( has_trait( trait_NAILS ) ) {
per_hand += .5;
}
for( const trait_id &mut : get_mutations() ) {
per_hand += mut->pierce_dmg_bonus;

if( has_bionic( bionic_id( "bio_razors" ) ) ) {
per_hand += 2;
if( mut->flags.count( "UNARMED_BONUS" ) > 0 && cut_bonus > 0 ) {
per_hand += std::min( unarmed_skill / 2, 4 );
}
}

if( has_trait( trait_THORNS ) ) {
if( has_bionic( bionic_id( "bio_razors" ) ) ) {
per_hand += 2;
}

if( has_trait( trait_CLAWS_ST ) ) {
/** @EFFECT_UNARMED increases stabbing damage with CLAWS_ST */
per_hand += 3 + unarmed_skill / 2.0;
}

cut_dam += per_hand; // First hand
if( left_empty && right_empty ) {
// Second hand
Expand Down
24 changes: 24 additions & 0 deletions src/mutation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,17 @@ void Character::unset_mutation( const trait_id &trait_ )
reset_encumbrance();
}

void Character::switch_mutations( const trait_id &switched, const trait_id &target,
bool start_powered )
{
unset_mutation( switched );
mutation_loss_effect( switched );

set_mutation( target );
my_mutations[target].powered = start_powered;
mutation_effect( target );
}

int Character::get_mod( const trait_id &mut, const std::string &arg ) const
{
auto &mod_data = mut->mods;
Expand Down Expand Up @@ -494,6 +505,13 @@ void Character::activate_mutation( const trait_id &mut )
recalc_sight_limits();
}

if( mdata.transform ) {
const cata::value_ptr<mut_transform> trans = mdata.transform;
mod_moves( - trans->moves );
switch_mutations( mut, trans->target, trans->active );
return;
}

if( mut == trait_WEB_WEAVER ) {
g->m.add_field( pos(), fd_web, 1 );
add_msg_if_player( _( "You start spinning web with your spinnerets!" ) );
Expand Down Expand Up @@ -619,6 +637,12 @@ void Character::deactivate_mutation( const trait_id &mut )
// Handle stat changes from deactivation
apply_mods( mut, false );
recalc_sight_limits();
const mutation_branch &mdata = mut.obj();
if( mdata.transform ) {
const cata::value_ptr<mut_transform> trans = mdata.transform;
mod_moves( -trans->moves );
switch_mutations( mut, trans->target, trans->active );
}
}

trait_id Character::trait_by_invlet( const int ch ) const
Expand Down
19 changes: 19 additions & 0 deletions src/mutation.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ struct mut_attack {
bool hardcoded_effect = false;
};

struct mut_transform {

trait_id target;

/** displayed if player sees transformation with %s replaced by item name */
translation msg_transform;
/** used to set the active property of the transformed @ref target */
bool active = false;
/** subtracted from @ref Creature::moves when transformation is successful */
int moves = 0;
mut_transform();
bool load( const JsonObject &jsobj, const std::string &member );
};

struct mutation_branch {
trait_id id;
bool was_loaded = false;
Expand Down Expand Up @@ -131,6 +145,7 @@ struct mutation_branch {
float str_modifier = 0.0f;
//melee bonuses
int cut_dmg_bonus = 0;
float pierce_dmg_bonus = 0.0;
std::pair<int, int> rand_cut_bonus;
int bash_dmg_bonus = 0;
std::pair<int, int> rand_bash_bonus;
Expand All @@ -151,6 +166,10 @@ struct mutation_branch {
cata::optional<int> scent_mask;
int bleed_resist = 0;

int butchering_quality = 0;

cata::value_ptr<mut_transform> transform;

/**Map of crafting skills modifiers, can be negative*/
std::map<skill_id, int> craft_skill_bonus;

Expand Down
27 changes: 27 additions & 0 deletions src/mutation_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,20 @@ void mutation_branch::load_trait( const JsonObject &jo, const std::string &src )
trait_factory.load( jo, src );
}

mut_transform::mut_transform() : active( false ), moves( 0 ) {}

bool mut_transform::load( const JsonObject &jsobj, const std::string &member )
{
JsonObject j = jsobj.get_object( member );

assign( j, "target", target );
assign( j, "msg_transform", msg_transform );
assign( j, "active", active );
assign( j, "moves", moves );

return true;
}

void mutation_branch::load( const JsonObject &jo, const std::string & )
{
mandatory( jo, was_loaded, "id", id );
Expand Down Expand Up @@ -293,6 +307,10 @@ void mutation_branch::load( const JsonObject &jo, const std::string & )
optional( si, was_loaded, "type", ranged_mutation );
optional( si, was_loaded, "message", raw_ranged_mutation_message );
}
if( jo.has_object( "transform" ) ) {
transform = cata::make_value<mut_transform>();
transform->load( jo, "transform" );
}
optional( jo, was_loaded, "initial_ma_styles", initial_ma_styles );

if( jo.has_array( "bodytemp_modifiers" ) ) {
Expand Down Expand Up @@ -331,6 +349,7 @@ void mutation_branch::load( const JsonObject &jo, const std::string & )
optional( jo, was_loaded, "stealth_modifier", stealth_modifier, 0.0f );
optional( jo, was_loaded, "str_modifier", str_modifier, 0.0f );
optional( jo, was_loaded, "cut_dmg_bonus", cut_dmg_bonus, 0 );
optional( jo, was_loaded, "pierce_dmg_bonus", pierce_dmg_bonus, 0.0f );
optional( jo, was_loaded, "bash_dmg_bonus", bash_dmg_bonus, 0 );
optional( jo, was_loaded, "dodge_modifier", dodge_modifier, 0.0f );
optional( jo, was_loaded, "speed_modifier", speed_modifier, 1.0f );
Expand Down Expand Up @@ -367,6 +386,8 @@ void mutation_branch::load( const JsonObject &jo, const std::string & )
optional( jo, was_loaded, "can_only_heal_with", can_only_heal_with );
optional( jo, was_loaded, "can_heal_with", can_heal_with );

optional( jo, was_loaded, "butchering_quality", butchering_quality, 0 );

optional( jo, was_loaded, "allowed_category", allowed_category );

optional( jo, was_loaded, "mana_modifier", mana_modifier, 0 );
Expand Down Expand Up @@ -535,6 +556,12 @@ void mutation_branch::check_consistency()
debugmsg( "mutation %s refers to undefined mutation type %s", mid.c_str(), type );
}
}
if( mid->transform ) {
const trait_id tid = mid->transform->target;
if( !tid.is_valid() ) {
debugmsg( "mutation %s transform uses undefined target %s", mid.c_str(), tid.c_str() );
}
}
for( const std::pair<species_id, int> elem : an_id ) {
if( !elem.first.is_valid() ) {
debugmsg( "mutation %s refers to undefined species id %s", mid.c_str(), elem.first.c_str() );
Expand Down
18 changes: 14 additions & 4 deletions src/mutation_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ void player::power_mutations()
std::vector<trait_id> passive;
std::vector<trait_id> active;
for( std::pair<const trait_id, trait_data> &mut : my_mutations ) {
if( !mut.first->activated ) {
if( !mut.first->activated && ! mut.first->transform ) {
passive.push_back( mut.first );
} else {
active.push_back( mut.first );
Expand Down Expand Up @@ -290,10 +290,15 @@ void player::power_mutations()
break;
}
const auto &mut_data = mut_id.obj();
const cata::value_ptr<mut_transform> &trans = mut_data.transform;
if( menu_mode == "activating" ) {
if( mut_data.activated ) {
if( mut_data.activated || trans ) {
if( my_mutations[mut_id].powered ) {
add_msg_if_player( m_neutral, _( "You stop using your %s." ), mut_data.name() );
if( trans && !trans->msg_transform.empty() ) {
add_msg_if_player( m_neutral, trans->msg_transform );
} else {
add_msg_if_player( m_neutral, _( "You stop using your %s." ), mut_data.name() );
}

deactivate_mutation( mut_id );
// Action done, leave screen
Expand All @@ -303,7 +308,12 @@ void player::power_mutations()
( !mut_data.fatigue || get_fatigue() <= 400 ) ) {

g->draw();
add_msg_if_player( m_neutral, _( "You activate your %s." ), mut_data.name() );
if( trans && !trans->msg_transform.empty() ) {
add_msg_if_player( m_neutral, trans->msg_transform );
} else {
add_msg_if_player( m_neutral, _( "You activate your %s." ), mut_data.name() );
}

activate_mutation( mut_id );
// Action done, leave screen
break;
Expand Down
9 changes: 3 additions & 6 deletions src/visitable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "active_item_cache.h"
#include "bionics.h"
#include "mutation.h"
#include "character.h"
#include "colony.h"
#include "debug.h"
Expand Down Expand Up @@ -278,12 +279,8 @@ int visitable<Character>::max_quality( const quality_id &qual ) const
}

if( qual == qual_BUTCHER ) {
if( self->has_trait( trait_CLAWS_ST ) ) {
res = std::max( res, 8 );
} else if( self->has_trait( trait_TALONS ) || self->has_trait( trait_MANDIBLES ) ||
self->has_trait( trait_CLAWS ) || self->has_trait( trait_CLAWS_RETRACT ) ||
self->has_trait( trait_CLAWS_RAT ) ) {
res = std::max( res, 4 );
for( const trait_id &mut : self->get_mutations() ) {
res = std::max( res, mut->butchering_quality );
}
}

Expand Down

0 comments on commit af60511

Please sign in to comment.