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

Increase granularity of activity tracking to per turn. #45316

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
157 changes: 157 additions & 0 deletions src/activity_tracker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#include "activity_tracker.h"

#include "game_constants.h"
#include "options.h"
#include "string_formatter.h"

#include <limits>

int activity_tracker::weariness() const
{
if( intake > tracker ) {
return tracker * 0.5;
}
return tracker - intake * 0.5;
}

// Called every 5 minutes, when activity level is logged
void activity_tracker::try_reduce_weariness( int bmr, bool sleeping )
{
tick_counter++;
if( average_activity() - NO_EXERCISE <= std::numeric_limits<float>::epsilon() ) {
low_activity_ticks++;
// Recover twice as fast at rest
if( sleeping ) {
low_activity_ticks++;
}
}

const float recovery_mult = get_option<float>( "WEARY_RECOVERY_MULT" );

if( low_activity_ticks >= 6 ) {
int reduction = tracker;
// 1/20 of whichever's bigger
if( bmr > reduction ) {
reduction = bmr * recovery_mult;
} else {
reduction *= recovery_mult;
}
low_activity_ticks -= 6;

tracker -= reduction;
}

if( tick_counter >= 12 ) {
intake *= 1 - recovery_mult;
tick_counter -= 12;
}

// Normalize values, make sure we stay above 0
intake = std::max( intake, 0 );
tracker = std::max( tracker, 0 );
tick_counter = std::max( tick_counter, 0 );
low_activity_ticks = std::max( low_activity_ticks, 0 );
}

void activity_tracker::weary_clear()
{
tracker = 0;
intake = 0;
low_activity_ticks = 0;
tick_counter = 0;
}

std::string activity_tracker::debug_weary_info() const
{
return string_format( "Intake: %d Tracker: %d", intake, tracker );
}

void activity_tracker::calorie_adjust( int nkcal )
{
if( nkcal > 0 ) {
intake += nkcal;
} else {
// nkcal is negative, we need positive
tracker -= nkcal;
}
}

float activity_tracker::activity() const
{
if( current_turn == calendar::turn ) {
return current_activity;
}
return 1.0f;
}

float activity_tracker::average_activity() const
{
if( activity_reset && current_turn != calendar::turn ) {
return previous_activity / num_events;
}
return ( accumulated_activity + current_activity ) / num_events;
}

float activity_tracker::instantaneous_activity_level() const
{
if( current_turn == calendar::turn ) {
return current_activity;
}
return previous_turn_activity;
}

// The idea here is the character is going about their business logging activities,
// and log_activity() handles sorting them out, it records the largest magnitude for a given turn,
// and then rolls the previous turn's value into the accumulator once a new activity is logged.
// After a reset, we have to pretend the previous values weren't logged.
void activity_tracker::log_activity( float new_level )
{
current_activity = std::max( current_activity, new_level );
current_turn = calendar::turn;
}

void activity_tracker::new_turn()
{
if( activity_reset ) {
activity_reset = false;
previous_turn_activity = current_activity;
current_activity = NO_EXERCISE;
accumulated_activity = 0.0f;
num_events = 1;
} else {
// This is for the last turn that had activity logged.
accumulated_activity += current_activity;
// Then handle the interventing turns that had no activity logged.
int num_turns = to_turns<int>( calendar::turn - current_turn );
if( num_turns > 1 ) {
accumulated_activity += ( num_turns - 1 ) * NO_EXERCISE;
num_events += num_turns - 1;
}
previous_turn_activity = current_activity;
current_activity = NO_EXERCISE;
num_events++;
}
}

void activity_tracker::reset_activity_level()
{
previous_activity = accumulated_activity;
activity_reset = true;
}

std::string activity_tracker::activity_level_str() const
{
if( current_activity <= NO_EXERCISE ) {
return _( "NO_EXERCISE" );
} else if( current_activity <= LIGHT_EXERCISE ) {
return _( "LIGHT_EXERCISE" );
} else if( current_activity <= MODERATE_EXERCISE ) {
return _( "MODERATE_EXERCISE" );
} else if( current_activity <= BRISK_EXERCISE ) {
return _( "BRISK_EXERCISE" );
} else if( current_activity <= ACTIVE_EXERCISE ) {
return _( "ACTIVE_EXERCISE" );
} else {
return _( "EXTRA_EXERCISE" );
}
}
54 changes: 54 additions & 0 deletions src/activity_tracker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once
#ifndef CATA_SRC_ACTIVITY_TRACKER_H
#define CATA_SRC_ACTIVITY_TRACKER_H

#include "calendar.h"
kevingranade marked this conversation as resolved.
Show resolved Hide resolved

class JsonIn;
class JsonOut;

class activity_tracker
{
private:
float current_activity = 0.0;
float accumulated_activity = 0.0;
float previous_activity = 0.0;
float previous_turn_activity = 0.0;
time_point current_turn = calendar::turn_zero;
bool activity_reset = true;
int num_events = 1;

// Weariness metadata.
int tracker = 0;
int intake = 0;
// Semi-consecutive 5 minute ticks of low activity (or 2.5 if we're sleeping)
ZhilkinSerg marked this conversation as resolved.
Show resolved Hide resolved
int low_activity_ticks = 0;
// How many ticks since we've decreased intake
ZhilkinSerg marked this conversation as resolved.
Show resolved Hide resolved
int tick_counter = 0;
public:
// Logs activity level. If called multiple times in one turn, will preserve the highest.
void log_activity( float new_level );
// Informs the tracker that a new turn has started.
void new_turn();
// Resets accumulated activity level.
void reset_activity_level();
// outputs player activity level to a printable string
ZhilkinSerg marked this conversation as resolved.
Show resolved Hide resolved
std::string activity_level_str() const;
// Returns activity level recorded for the current turn.
float activity() const;
// Returns average of activity level for the current period.
float average_activity() const;
// Returns the previous turn's activity level until an action is tanken on the current turn.
ZhilkinSerg marked this conversation as resolved.
Show resolved Hide resolved
float instantaneous_activity_level() const;

int weariness() const;
void try_reduce_weariness( int bmr, bool sleeping );
void calorie_adjust( int nkcal );
void weary_clear();
std::string debug_weary_info() const;

void serialize( JsonOut &json ) const;
void deserialize( JsonIn &jsin );
};

#endif // CATA_SRC_ACTIVITY_TRACKER_H
2 changes: 1 addition & 1 deletion src/avatar_action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ bool avatar_action::move( avatar &you, map &m, const tripoint &d )

// by this point we're either walking, running, crouching, or attacking, so update the activity level to match
if( !is_riding ) {
you.increase_activity_level( you.current_movement_mode()->exertion_level() );
you.set_activity_level( you.current_movement_mode()->exertion_level() );
}

// If the player is *attempting to* move on the X axis, update facing direction of their sprite to match.
Expand Down
Loading