Created
November 10, 2016 21:51
-
-
Save sigsegv-mvm/ee7ed6c6deaec50c5de59cd03fe6c4b2 to your computer and use it in GitHub Desktop.
How TF2 health regen works, in detail
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Health regen stuff | |
// Based on server_srv.so version 20151007a | |
// Reverse engineering by sigsegv | |
/* this Think function is called once per second */ | |
void CTFPlayer::RegenThink() | |
{ | |
if (!this->IsAlive()) | |
{ | |
// The member variable m_flRegenAmount is stored between calls | |
// This means that fractional health regen amounts will build up over time | |
// (e.g. 0.2 health regen will result in +1 hp every 5 seconds or so) | |
if (this->IsPlayerClass(TF_CLASS_MEDIC)) | |
{ | |
float flTimeSinceDamage = this->GetLastDamageTime() - gpGlobals->curtime; | |
// Set the innate medic health regen based on time-since-last-damage: | |
// < 5 seconds: +3.0 | |
// 5-10 seconds: smoothly scales between +3.0 and +6.0 | |
// > 10 seconds: +6.0 | |
float flMedicRegen = RemapValClamped(flTimeSinceDamage, 5.0f, 10.0f, 3.0f, 6.0f); | |
// Handling for the Healing Mastery upgrade | |
if (TFGameRules()->GameModeUsesUpgrades()) | |
{ | |
int iAttr_HealingMastery = 0; | |
CALL_ATTRIB_HOOK_INT(iAttr_HealingMastery, healing_mastery); | |
if (iAttr_HealingMastery != 0) | |
{ | |
// The attribute value range (0 to 4) is mapped to a scale factor range (1.00x to 2.00x) | |
// [ 0: 1.00x 1: 1.25x 2: 1.50x 3: 1.75x 4: 2.00x ] | |
float flScaleFactor = RemapValClamped((float)iAttr_HealingMastery, 0.0f, 4.0f, 1.00f, 2.00f); | |
flMedicRegen *= flScaleFactor; | |
} | |
} | |
this->m_flRegenAmount += flMedicRegen; | |
} | |
// Add/subtract the health regen attribute(s) active on the player | |
float flAttr_HealthRegen = 0.0f; | |
CALL_ATTRIB_HOOK_FLOAT(flAttr_HealthRegen, add_health_regen); | |
this->m_flRegenAmount += flAttr_HealthRegen; | |
// SKIPPED: Mannpower rune stuff | |
int iRegenAmount = 0; | |
// If we are regenning by at least 1 positive health point, then heal | |
if (this->m_flRegenAmount >= 1.0f) | |
{ | |
// Get just the integer part of the regen amount | |
iRegenAmount = (int)floor(this->m_flRegenAmount); | |
// Don't bother healing if already at full health | |
// This is completely redundant because CBaseEntity::TakeHealth does the exact same check | |
if (this->GetHealth() < this->GetMaxHealth()) | |
{ | |
// Heal the player by iRegenAmount health points (will not exceed max health) | |
this->TakeHealth((float)iRegenAmount, DMG_GENERIC); | |
} | |
} | |
// If we are regenning by at least 1 negative health point, then hurt | |
// BUG: if m_flRegenAmount is exactly -1.0f, no hurt occurs (should be: <= -1.0f) | |
if (this->m_flRegenAmount < -1.0f) | |
{ | |
// Get just the integer part of the regen amount | |
iRegenAmount = (int)ceil(this->m_flRegenAmount); | |
// Hurt the player by -iRegenAmount health points | |
// [ Attacker: self Inflictor: self Weapon: none Force: none Location: middle of player ] | |
this->TakeDamage(CTakeDamageInfo(this, this, nullptr, vec3_origin, this->WorldSpaceCenter(), (float)(-iRegenAmount), DMG_GENERIC)); | |
} | |
// SKIPPED: irrelevant stuff | |
// If we did heal or hurt ourselves, then remove the integer amount we | |
// healed/hurt from the future regen amount (but leave any fractional part) | |
this->m_flRegenAmount -= (float)iRegenAmount; | |
// SKIPPED: irrelevant stuff | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment