Adding Portal-style regenerating health: Difference between revisions
SirYodaJedi (talk | contribs) No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
This is a copy and paste tutorial to add '''Call of Duty's Low Health Regeneration''' for single-player. | This is a copy and paste tutorial to add '''Call of Duty's Low Health Regeneration''' for single-player. | ||
[[File:Codstyle.gif|Demonstration]] | [[File:Codstyle.gif|Demonstration]] | ||
This feature is inspired by [[ | This feature is inspired by [[Regenerating Health]]. | ||
With this feature, Medkits and Health Chargers are kinda pointless. | With this feature, Medkits and Health Chargers are kinda pointless. | ||
== How does this feature work? == | == How does this feature work? == | ||
* Check if the health is below the max health (100 HP) or below 25 HP (critical health state) | |||
* Check if the health is below the max health (100 | * Start the last damage timer for 5 seconds. It will reset each time the player takes damage, so hide in a safe place is required. | ||
* Start the last damage timer for 5 seconds. It will reset each time player | |||
* While in critical health state, the player will experience breathing like someone in pain sound. | * While in critical health state, the player will experience breathing like someone in pain sound. | ||
* After the last damage timer ends, the regeneration function will start and the health will be boosted to 100 again. | * After the last damage timer ends, the regeneration function will start and the health will be boosted to 100 again. | ||
Line 17: | Line 15: | ||
== Implement == | == Implement == | ||
First, open up '''player.h''' and search for this function: | |||
First, open up '''player.h''' and search this function | |||
<source lang=cpp> | <source lang=cpp> | ||
Line 43: | Line 40: | ||
</source> | </source> | ||
Under that function, add | Under that function, add these lines of code: | ||
<source lang=cpp> | <source lang=cpp> | ||
Line 59: | Line 56: | ||
== player.cpp == | == player.cpp == | ||
Then, we open up the '''player.cpp''': | |||
Then, we open up the '''player.cpp''' | |||
<source lang=cpp> | <source lang=cpp> | ||
Line 66: | Line 62: | ||
</source> | </source> | ||
Below that code, we add this | Below that code, we add this: | ||
<source lang=cpp> | <source lang=cpp> | ||
Line 75: | Line 71: | ||
== CBasePlayer::CBasePlayer() == | == CBasePlayer::CBasePlayer() == | ||
{{Note| I forgot to add this!}} | {{Note| I forgot to add this!}} | ||
On <code> CBasePlayer::CBasePlayer()</code> under <code> m_iReplayEntity = 0; </code> | On <code>CBasePlayer::CBasePlayer()</code> under <code> m_iReplayEntity = 0;</code> | ||
we add this: | |||
<source lang=cpp> | <source lang=cpp> | ||
m_flNextLowHealthSoundTime = 0.0f; | m_flNextLowHealthSoundTime = 0.0f; | ||
Line 83: | Line 79: | ||
== OnTakeDamage() == | == OnTakeDamage() == | ||
Look up | Look up the '''OnTakeDamage''' function and find this code: | ||
<source lang=cpp> | <source lang=cpp> | ||
Line 92: | Line 88: | ||
</source> | </source> | ||
Then | Then after that, add the following: | ||
<source lang=cpp> | <source lang=cpp> | ||
Line 156: | Line 152: | ||
== HandleFastRegen() == | == HandleFastRegen() == | ||
Below the '''OnTakeDamage()''' function, we create another function called HandleFastRegen(): | |||
Below the '''OnTakeDamage()''' function, we create another function called HandleFastRegen() | |||
<source lang=cpp> | <source lang=cpp> | ||
void CBasePlayer::HandleFastRegen() | void CBasePlayer::HandleFastRegen() | ||
Line 197: | Line 192: | ||
== PostThink() == | == PostThink() == | ||
Then, we go to the '''PostThink''' function and find this code: | |||
Then, we go to the '''PostThink''' function and find this code | |||
<source lang=cpp> | <source lang=cpp> | ||
#if !defined( NO_ENTITY_PREDICTION ) | #if !defined( NO_ENTITY_PREDICTION ) | ||
Line 205: | Line 199: | ||
#endif | #endif | ||
</source> | </source> | ||
Below, we add | Below, we add the following: | ||
<source lang=cpp> | <source lang=cpp> | ||
Line 238: | Line 232: | ||
</source> | </source> | ||
Lastly, we must precache the sound, you may want to precache the sound either in '''player.cpp''' or '''hl2_player.cpp''' | Lastly, we must precache the sound, you may want to precache the sound either in '''player.cpp''' or '''hl2_player.cpp'''! | ||
<source lang=cpp> | <source lang=cpp> | ||
Line 247: | Line 241: | ||
== Optional == | == Optional == | ||
Oh, you can customize the sound to your liking. [[:User:Hugancrit|I]] personally [https://github.com/Huga22118/source-sdk-2013/tree/master/sp/game/hugamod/sound/player/h1_misc use] this for my custom mod. Don't forget to precache the sound with the sound you want to change! | |||
; <code>Here are my sound scripts:</code> | |||
; <code>my sound scripts</code> | |||
<pre> | <pre> | ||
Line 259: | Line 252: | ||
"soundlevel" "SNDLVL_GUNFIRE" | "soundlevel" "SNDLVL_GUNFIRE" | ||
"pitch" "PITCH_NORM" | "pitch" "PITCH_NORM" | ||
"rndwave" | "rndwave" | ||
{ | { | ||
Line 270: | Line 262: | ||
"wave" "player/h1_misc/player_breathhurt7.wav" | "wave" "player/h1_misc/player_breathhurt7.wav" | ||
} | } | ||
} | } | ||
Line 280: | Line 270: | ||
"soundlevel" "SNDLVL_GUNFIRE" | "soundlevel" "SNDLVL_GUNFIRE" | ||
"pitch" "PITCH_NORM" | "pitch" "PITCH_NORM" | ||
"rndwave" | "rndwave" | ||
{ | { | ||
Line 288: | Line 275: | ||
"wave" "player/h1_misc/player_breathbetter2.wav" | "wave" "player/h1_misc/player_breathbetter2.wav" | ||
"wave" "player/h1_misc/player_breathbetter3.wav" | "wave" "player/h1_misc/player_breathbetter3.wav" | ||
} | |||
} | } | ||
<pre> | <pre> |
Revision as of 13:42, 7 May 2025
This is a copy and paste tutorial to add Call of Duty's Low Health Regeneration for single-player.
This feature is inspired by Regenerating Health.
With this feature, Medkits and Health Chargers are kinda pointless.
How does this feature work?
- Check if the health is below the max health (100 HP) or below 25 HP (critical health state)
- Start the last damage timer for 5 seconds. It will reset each time the player takes damage, so hide in a safe place is required.
- While in critical health state, the player will experience breathing like someone in pain sound.
- After the last damage timer ends, the regeneration function will start and the health will be boosted to 100 again.
- Repeat cycle :>
Implement
First, open up player.h and search for this function:
float ConsumeMovementTimeForUserCmdProcessing( float flTimeNeeded )
{
if ( m_flMovementTimeForUserCmdProcessingRemaining <= 0.0f )
{
return 0.0f;
}
else if ( flTimeNeeded > m_flMovementTimeForUserCmdProcessingRemaining + FLT_EPSILON )
{
float flResult = m_flMovementTimeForUserCmdProcessingRemaining;
m_flMovementTimeForUserCmdProcessingRemaining = 0.0f;
return flResult;
}
else
{
m_flMovementTimeForUserCmdProcessingRemaining -= flTimeNeeded;
if ( m_flMovementTimeForUserCmdProcessingRemaining < 0.0f )
m_flMovementTimeForUserCmdProcessingRemaining = 0.0f;
return flTimeNeeded;
}
}
Under that function, add these lines of code:
void HandleFastRegen();
float m_flLastDamageTime;
bool m_bFastRegenActive;
float m_flFastRegenStartTime;
float m_flNextFastRegenTime;
bool m_isPlayerNearDying = false;
bool m_bBuzzingSoundActive = false;
float m_flBuzzingSoundEndTime;
float m_flNextLowHealthSoundTime;
float m_flStartReliefSoundTime;
player.cpp
Then, we open up the player.cpp:
DEFINE_FIELD( m_tbdPrev, FIELD_TIME ),
Below that code, we add this:
DEFINE_FIELD(m_flLastDamageTime, FIELD_TIME),
DEFINE_FIELD(m_isPlayerNearDying, FIELD_BOOLEAN),
CBasePlayer::CBasePlayer()

On CBasePlayer::CBasePlayer()
under m_iReplayEntity = 0;
we add this:
m_flNextLowHealthSoundTime = 0.0f;
m_flStartReliefSoundTime = 0.0f;
OnTakeDamage()
Look up the OnTakeDamage function and find this code:
if ( bitsDamage & DMG_BLAST )
{
OnDamagedByExplosion( info );
}
Then after that, add the following:
if (GetHealth() < 100) {
m_flLastDamageTime = gpGlobals->curtime;
}
if (IsAlive() && GetHealth() < 100 /* && !m_bFastRegenActive*/) {
m_bFastRegenActive = true;
// HUGAMOD: Start regeneration after 5 seconds
// but it will reset each time you take damage
m_flFastRegenStartTime = gpGlobals->curtime + 5.0f;
m_flNextFastRegenTime = m_flFastRegenStartTime;
}
float flDamage = info.GetDamage();
if (GetHealth() < 25) {
color32 red = { 128, 0, 0, 128 };
UTIL_ScreenFade(this, red, 2.15f, 5.0f, FFADE_IN);
// HUGAMOD: Commented out ugly PunchAngle
//ViewPunch(QAngle(random->RandomInt(-2, 2), random->RandomInt(-2, 2), random->RandomInt(-2, 2)));
if (!m_isPlayerNearDying)
{
// HUGAMOD: Checks if the player is in a vehicle so that
// the player won't get punchangle, it will bug the view
// if you remove this check (i already bug-tested it :>)
if (!this->IsInAVehicle()) {
// HUGAMOD: Ported CSS Headshot PunchAngle
flDamage *= 4;
QAngle punchAngle = GetPunchAngle();
punchAngle.x = flDamage * -0.5;
if (punchAngle.x < -12)
punchAngle.x = -12;
punchAngle.z = flDamage * random->RandomFloat(-1, 1);
if (punchAngle.z < -9)
punchAngle.z = -9;
else if (punchAngle.z > 9)
punchAngle.z = 9;
SetPunchAngle(punchAngle);
}
EmitSound("Flesh.Headshot");
m_isPlayerNearDying = true;
}
if (!m_bBuzzingSoundActive)
{
int effect = random->RandomInt(32, 34);
CSingleUserRecipientFilter user(this);
enginesound->SetPlayerDSP(user, effect, false);
m_flBuzzingSoundEndTime = gpGlobals->curtime + 5.0f;
m_bBuzzingSoundActive = true;
}
}
HandleFastRegen()
Below the OnTakeDamage() function, we create another function called HandleFastRegen():
void CBasePlayer::HandleFastRegen()
{
if (gpGlobals->curtime - m_flLastDamageTime < 5.0f)
{
// Not enough time has passed, do not start regeneration
return;
}
if (m_bFastRegenActive && gpGlobals->curtime >= m_flFastRegenStartTime)
{
if (gpGlobals->curtime >= m_flNextFastRegenTime)
{
// Add 5 health each time
TakeHealth(5, DMG_GENERIC);
// Set the next regeneration time for 0.1 seconds
m_flNextFastRegenTime = gpGlobals->curtime + 0.1f;
m_isPlayerNearDying = false;
// Stop the regeneration if the health reaches 100
if (GetHealth() >= 100)
{
m_bFastRegenActive = false;
}
if (m_bBuzzingSoundActive && gpGlobals->curtime >= m_flBuzzingSoundEndTime)
{
// HUGAMOD: Delays the relief breathing sound
// for 0.45 - 0.5 seconds because it will collide with
// the hurt breathing sound
m_flStartReliefSoundTime = gpGlobals->curtime + RandomFloat(0.45, 0.5);
m_bBuzzingSoundActive = false;
}
}
}
}
PostThink()
Then, we go to the PostThink function and find this code:
#if !defined( NO_ENTITY_PREDICTION )
// Even if dead simulate entities
SimulatePlayerSimulatedEntities();
#endif
Below, we add the following:
// HUGAMOD: Dead player will ignore this
if (IsAlive()) {
if (GetHealth() < 25)
{
if (gpGlobals->curtime >= m_flNextLowHealthSoundTime)
{
// Play hurt breath sound
EmitSound("Player.Breathhurt");
// Set the next hurt breath sound time
m_flNextLowHealthSoundTime = gpGlobals->curtime + 1.0f; // Interval 1 detik
}
}
else
{
if (m_flStartReliefSoundTime > 0.0f && gpGlobals->curtime >= m_flStartReliefSoundTime)
{
EmitSound("Player.Breathbetter");
// Reset relief breath time to prevent looping
m_flStartReliefSoundTime = 0.0f;
}
StopSound("Player.Breathhurt"); // Stop breath hurt sound
// Reset breath hurt time to prevent looping
m_flNextLowHealthSoundTime = 0.0f;
}
}
HandleFastRegen();
Lastly, we must precache the sound, you may want to precache the sound either in player.cpp or hl2_player.cpp!
PrecacheScriptSound("Player.Breathhurt");
PrecacheScriptSound("Player.Breathbetter");
PrecacheScriptSound("Flesh.Headshot");
Optional
Oh, you can customize the sound to your liking. I personally use this for my custom mod. Don't forget to precache the sound with the sound you want to change!
Here are my sound scripts:
"Player.Breathhurt" { "channel" "CHAN_STATIC" "volume" "1.0" "soundlevel" "SNDLVL_GUNFIRE" "pitch" "PITCH_NORM" "rndwave" { "wave" "player/h1_misc/player_breathhurt1.wav" "wave" "player/h1_misc/player_breathhurt2.wav" "wave" "player/h1_misc/player_breathhurt3.wav" "wave" "player/h1_misc/player_breathhurt4.wav" "wave" "player/h1_misc/player_breathhurt5.wav" "wave" "player/h1_misc/player_breathhurt6.wav" "wave" "player/h1_misc/player_breathhurt7.wav" } } "Player.Breathbetter" { "channel" "CHAN_STATIC" "volume" "1.0" "soundlevel" "SNDLVL_GUNFIRE" "pitch" "PITCH_NORM" "rndwave" { "wave" "player/h1_misc/player_breathbetter1.wav" "wave" "player/h1_misc/player_breathbetter2.wav" "wave" "player/h1_misc/player_breathbetter3.wav" } }