Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fitness band and heartrate function for character #36233

Merged
merged 49 commits into from
Apr 12, 2020
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
1ee3c53
[WIP] Add heartrate function for character
CountAlex Dec 18, 2019
53e0fa0
Fixing lints
CountAlex Dec 18, 2019
9f77673
[WIP] Add fitness band to evaluate heart beat and exercise amount
CountAlex Dec 18, 2019
2af6920
Post-cherrypick changes.
CountAlex Dec 19, 2019
89f8ea5
item_actions.json lint fix
CountAlex Dec 19, 2019
e3cccf9
Grammar fix.
CountAlex Dec 19, 2019
18529d3
Traits, mutations and nicotine effect; isue declaration fix.
CountAlex Dec 19, 2019
ca398dd
Traits declaration.
CountAlex Dec 19, 2019
025deb2
Declaration fix and relocating a line of effect.
CountAlex Dec 19, 2019
2c367e3
Type cast fix.
CountAlex Dec 19, 2019
f3c9a90
Template function call fix.
CountAlex Dec 19, 2019
1a1e7cf
Style changes.
CountAlex Dec 19, 2019
c39d8b8
Displaying exercise level on fitband.
CountAlex Dec 19, 2019
5dba896
Whitespace fixes.
CountAlex Dec 19, 2019
13a0743
Grammar fix and plural naming removal.
CountAlex Dec 20, 2019
981f3c7
Lint fix.
CountAlex Dec 20, 2019
6292293
Style tweaks and meeting max line length with splitting strings.
CountAlex Dec 20, 2019
ce316c9
Astyle update
CountAlex Dec 20, 2019
d421ddd
Dead state check and moving omnicell check ahead to avoid redundant c…
CountAlex Dec 20, 2019
750386c
Fix to return value properly for simple cases.
CountAlex Dec 21, 2019
e079e0c
Uniting conditional statements.
CountAlex Dec 21, 2019
000c4a3
Add COLDBLOODs effects.
CountAlex Dec 22, 2019
b88ce6c
Fix trait calls.
CountAlex Dec 22, 2019
27425d1
Add morale and pain effects.
CountAlex Dec 22, 2019
5ac4d83
Fix for COLDBLOOD modifier.
CountAlex Dec 22, 2019
dfb7296
Fix ti numbers and limiting to max.
CountAlex Dec 22, 2019
d27c8d9
Review fixes.
CountAlex Dec 22, 2019
1f73f2c
Review changes.
CountAlex Dec 24, 2019
cfa150b
Add fitness band to itemgroups.
CountAlex Dec 24, 2019
c2ff511
Merge branch 'master' into heartrate
CountAlex Dec 31, 2019
6169c51
Division fix for tests.
CountAlex Jan 2, 2020
1bd1229
Type tweak.
CountAlex Jan 2, 2020
0e3a5ca
Merge branch 'master' into heartrate
CountAlex Jan 14, 2020
ce633d1
Post-conflict itemgroup tweak.
CountAlex Jan 14, 2020
834e6dd
Lint fix for locations.json
CountAlex Jan 14, 2020
cfa513d
Merge branch 'master' into heartrate
CountAlex Jan 23, 2020
d799d5b
Moving traits declaration to src/cata_string_consts.h
CountAlex Jan 23, 2020
6c6f186
Change calculation method for more relaxed increase based on average …
CountAlex Jan 23, 2020
6a2562d
Merge branch 'master' into heartrate
CountAlex Jan 26, 2020
f64fc16
Remove trait redeclaration
CountAlex Jan 26, 2020
be5cfdf
Merge branch 'master' into heartrate
CountAlex Jan 27, 2020
36415d5
Moving item to relocated item groups.
CountAlex Jan 27, 2020
4e47d13
Merge branch 'master' into heartrate
CountAlex Mar 2, 2020
4db6800
Merge branch 'master' into heartrate
CountAlex Mar 24, 2020
212ce78
Return proper string declaration for strings and effects
CountAlex Mar 24, 2020
bfef410
Automatic astyle fix
CountAlex Mar 24, 2020
717619d
Merge branch 'master' into heartrate
CountAlex Mar 27, 2020
a1c70d2
Merge branch 'master' into heartrate
CountAlex Mar 29, 2020
7ffa2a7
Remove cata_string_consts.h
CountAlex Apr 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions data/json/item_actions.json
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,11 @@
"id": "PORTABLE_GAME",
"name": { "ctxt": "PORTABLE_GAME", "str": "Play" }
},
{
"type": "item_action",
"id": "FITNESS_CHECK",
"name": "Check health metrics"
},
{
"type": "item_action",
"id": "deploy_tent",
Expand Down
18 changes: 18 additions & 0 deletions data/json/items/tool_armor.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,24 @@
"use_action": "PORTABLE_GAME",
"magazines": [ [ "battery", [ "light_minus_battery_cell", "light_minus_atomic_battery_cell", "light_minus_disposable_cell" ] ] ]
},
{
"type": "TOOL_ARMOR",
"id": "fitness_band",
"name": "fitness band",
"category": "clothing",
"volume": "100 ml",
"description": "A fitness band that can track your heartbeat, exercise level and also has a clock. Activate to see your metrics.",
"weight": "30 g",
"to_hit": -1,
"color": "light_gray",
"covers": [ "HAND_EITHER" ],
"price": 5000,
"material": [ "plastic" ],
"flags": [ "WATCH", "WATER_FRIENDLY", "BELTED", "FRAGILE", "ALLOWS_NATURAL_ATTACKS", "OVERSIZE" ],
"coverage": 15,
"symbol": "[",
"use_action": "FITNESS_CHECK"
},
{
"id": "holo_cloak",
"type": "TOOL_ARMOR",
Expand Down
88 changes: 88 additions & 0 deletions src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ static const efftype_id effect_bleed( "bleed" );
static const efftype_id effect_blind( "blind" );
static const efftype_id effect_blisters( "blisters" );
static const efftype_id effect_boomered( "boomered" );
static const efftype_id effect_cig( "cig" );
static const efftype_id effect_cold( "cold" );
static const efftype_id effect_common_cold( "common_cold" );
static const efftype_id effect_contacts( "contacts" );
Expand Down Expand Up @@ -150,9 +151,11 @@ static const trait_id trait_ACIDPROOF( "ACIDPROOF" );
static const trait_id trait_ADRENALINE( "ADRENALINE" );
static const trait_id trait_BADBACK( "BADBACK" );
static const trait_id trait_BARK( "BARK" );
static const trait_id trait_BADTEMPER( "BADTEMPER" );
static const trait_id trait_BIRD_EYE( "BIRD_EYE" );
static const trait_id trait_CEPH_EYES( "CEPH_EYES" );
static const trait_id trait_CEPH_VISION( "CEPH_VISION" );
static const trait_id trait_CHEMIMBALANCE( "CHEMIMBALANCE" );
static const trait_id trait_DEAF( "DEAF" );
static const trait_id trait_DEBUG_CLOAK( "DEBUG_CLOAK" );
static const trait_id trait_DEBUG_NIGHTVISION( "DEBUG_NIGHTVISION" );
Expand Down Expand Up @@ -186,6 +189,7 @@ static const trait_id trait_PACKMULE( "PACKMULE" );
static const trait_id trait_PER_SLIME_OK( "PER_SLIME_OK" );
static const trait_id trait_PER_SLIME( "PER_SLIME" );
static const trait_id trait_PYROMANIA( "PYROMANIA" );
static const trait_id trait_QUICK( "QUICK" );
static const trait_id trait_ROOTS2( "ROOTS2" );
static const trait_id trait_ROOTS3( "ROOTS3" );
static const trait_id trait_SEESLEEP( "SEESLEEP" );
Expand All @@ -194,6 +198,7 @@ static const trait_id trait_SHELL2( "SHELL2" );
static const trait_id trait_SHELL( "SHELL" );
static const trait_id trait_SHOUT2( "SHOUT2" );
static const trait_id trait_SHOUT3( "SHOUT3" );
static const trait_id trait_SLIMESPAWNER( "SLIMESPAWNER" );
static const trait_id trait_SLIMY( "SLIMY" );
static const trait_id trait_STRONGSTOMACH( "STRONGSTOMACH" );
static const trait_id trait_THRESH_CEPHALOPOD( "THRESH_CEPHALOPOD" );
Expand Down Expand Up @@ -7281,3 +7286,86 @@ void Character::use_fire( const int quantity )
return;
}
}

int Character::heartrate_bpm() const
{
//Dead have no heartbeat usually
if( is_dead_state() ) {
return 0;
}
//No heartbeat in omnicell
if( has_trait( trait_SLIMESPAWNER ) ) {
CountAlex marked this conversation as resolved.
Show resolved Hide resolved
return 0;
}
//This function returns heartrate in BPM basing of health, physical state, tiredness,
//moral effects, stimulators and anything that should fit here.
//Some values are picked to make sense from math point of view
//and seem correct but effects may vary in real life.
//This needs more attention from experienced contributors to work more smooth.
//Average healthy bpm is 60-80. That's a simple imitation of mormal distribution.
CountAlex marked this conversation as resolved.
Show resolved Hide resolved
//Must a better way to do that. Possibly this value should be generated with player creation.
int average_heartbeat = 70 + rng( -5, 5 ) + rng( -5, 5 );
CountAlex marked this conversation as resolved.
Show resolved Hide resolved
//Chemical imbalance makes this less predictable. It's possible this range needs tweaking
if( has_trait( trait_CHEMIMBALANCE ) ) {
average_heartbeat += rng( -15, 15 );
}
//Quick also raises basic BPM
if( has_trait( trait_QUICK ) ) {
average_heartbeat *= 1.1;
}
//Badtemper makes youк BPM raise from anger
if( has_trait( trait_BADTEMPER ) ) {
average_heartbeat *= 1.1;
}
const float stamina_level = float( get_stamina() ) / float( get_stamina_max() );
CountAlex marked this conversation as resolved.
Show resolved Hide resolved
float stamina_effect = 0;
if( stamina_level >= 0.9 ) {
stamina_effect = 0;
} else if( stamina_level >= 0.8 ) {
stamina_effect = 0.2;
} else if( stamina_level >= 0.6 ) {
stamina_effect = 0.5;
} else if( stamina_level >= 0.4 ) {
stamina_effect = 1;
} else if( stamina_level >= 0.2 ) {
stamina_effect = 1.5;
} else {
stamina_effect = 2;
}
//can triple heartrate
int heartbeat = average_heartbeat * ( 1 + stamina_effect );
const int stim_level = get_stim();
int stim_modifer = 0;
if( stim_level > 0 ) {
//that's asymptotical function that is equal to 1 at around 30 stim level
//and slows down all the time almost reaching 2.
//Tweaking x*x multiplier will accordingly change effect accumulation
stim_modifer = 2.1 - 2 / ( 1 + 0.001 * stim_level * stim_level );
}
heartbeat *= 1 + stim_modifer;
if( to_turns<int>( get_effect_dur( effect_cig ) ) > 0 ) {
CountAlex marked this conversation as resolved.
Show resolved Hide resolved
//Nicotine-induced tachycardia
if( get_effect_dur( effect_cig ) > 10_minutes * ( addiction_level( ADD_CIG ) + 1 ) ) {
heartbeat *= 1.4;
} else {
heartbeat *= 1.1;
}
}
//health effect that can make things better or worse is applied in the end.
//Based on get_max_healthy that already has bmi factored
const int healthy = get_max_healthy();
float healthy_modifier = 0;
//a bit arbitary formula that can use some love
healthy_modifier = -0.05 * round( healthy / 20 );
CountAlex marked this conversation as resolved.
Show resolved Hide resolved
heartbeat *= 1 + healthy_modifier;
//if BPM raised at least by 20% for a player with ADRENALINE, it adds 20% of avg to result
if( has_trait( trait_ADRENALINE ) && heartbeat > average_heartbeat * 1.2 ) {
heartbeat += average_heartbeat * 0.2;
}
//Add dependencies for COLDBLOOD?
//Add effects from addictions
//add morale effects, fear(?), medication effects
//A single clamp in the end should be enough
heartbeat = clamp( heartbeat, average_heartbeat, 250 );
return heartbeat;
}
1 change: 1 addition & 0 deletions src/character.h
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,7 @@ class Character : public Creature, public visitable<Character>
void drench( int saturation, const body_part_set &flags, bool ignore_waterproof );
/** Recalculates morale penalty/bonus from wetness based on mutations, equipment and temperature */
void apply_wetness_morale( int temperature );
int heartrate_bpm() const;

protected:
Character();
Expand Down
1 change: 1 addition & 0 deletions src/item_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ void Item_factory::init()
add_iuse( "PLANTBLECH", &iuse::plantblech );
add_iuse( "POISON", &iuse::poison );
add_iuse( "PORTABLE_GAME", &iuse::portable_game );
add_iuse( "FITNESS_CHECK", &iuse::fitness_check );
add_iuse( "PORTAL", &iuse::portal );
add_iuse( "PROZAC", &iuse::prozac );
add_iuse( "PURIFIER", &iuse::purifier );
Expand Down
38 changes: 38 additions & 0 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4410,6 +4410,44 @@ int iuse::portable_game( player *p, item *it, bool, const tripoint & )
return it->type->charges_to_use();
}

int iuse::fitness_check( player *p, item *it, bool, const tripoint & )
{
if( p->has_trait( trait_ILLITERATE ) ) {
p->add_msg_if_player( m_info, _( "You don't know what you're looking at." ) );
return 0;
} else {
//What else should block using f-band?
const int bpm = p->heartrate_bpm();
p->add_msg_if_player( _( "You check your health metrics on your %s." ), it->tname() );
//Maybe should pick better words
p->add_msg_if_player( _( "Your %s displays your heart's BPM: %i." ), it->tname(), bpm );
CountAlex marked this conversation as resolved.
Show resolved Hide resolved
if( bpm > 179 ) {
p->add_msg_if_player( _( "Your %s shows warning: 'Slow down! "
"Your pulse is getting too high, champion!'" ), it->tname() );
}
const std::string exercise = p->activity_level_str();
if( exercise == "NO_EXERCISE" ) {
p->add_msg_if_player( _( "Your %s shows your overall activity: "
"'You are not really active today. Try going for a walk!'." ), it->tname() );
} else if( exercise == "LIGHT_EXERCISE" ) {
p->add_msg_if_player( _( "Your %s shows your overall activity: "
"'Good start! Keep it up and move more.'" ), it->tname() );
} else if( exercise == "MODERATE_EXERCISE" ) {
p->add_msg_if_player( _( "Your %s shows your overall activity: "
"'Doing good! Don't stop, push the limit!'" ), it->tname() );
} else if( exercise == "ACTIVE_EXERCISE" ) {
//Ad will most likely need to go
p->add_msg_if_player( _( "Your %s shows your overall activity: 'Great job! "
"Take a break from workout and refresh with a bottle of sport drink!'" ), it->tname() );
} else {
p->add_msg_if_player( _( "Your %s shows your overall activity: "
"'You are too active! Avoid overexertion for your safety and health.'" ), it->tname() );
}
//TODO add whatever else makes sense (sleep quality, health level approximation?)
}
return it->type->charges_to_use();
}

int iuse::hand_crank( player *p, item *it, bool, const tripoint & )
{
if( p->is_npc() ) {
Expand Down
1 change: 1 addition & 0 deletions src/iuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ class iuse
int dive_tank( player *, item *, bool, const tripoint & );
int gasmask( player *, item *, bool, const tripoint & );
int portable_game( player *, item *, bool, const tripoint & );
int fitness_check( player *p, item *it, bool, const tripoint & );
int vibe( player *, item *, bool, const tripoint & );
int hand_crank( player *, item *, bool, const tripoint & );
int vortex( player *, item *, bool, const tripoint & );
Expand Down