Source SDK

Source SDK

Not enough ratings
Motor Source 2013 - Salud regenerativa
By Oitnemood
En este artículo, recorreremos los pasos para añadir un sistema de regeneración de salud al estilo de Halo/Portal para un jugador, y con una pequeña modificación también para el multijugador. El código utilizado fue descubierto en el SDK de Alien Swarm.
   
Award
Favorite
Favorited
Unfavorite
Resumen
Así es como funcionará la lógica:

Comprueba si la salud del jugador está por debajo de la cantidad máxima
Comprueba el temporizador de regeneración y la última vez que el jugador fue herido
Añade la cantidad de regeneración a un flotador basado en el tiempo de fotogramas
Comprueba si el flotador es mayor que uno, y si lo es, lo añade a la salud del jugador
Añadir los ConVars
Para este tutorial, modificaremos la clase base del jugador. Abre server/player.cpp y añade los siguientes ConVars:

ConVar sv_regeneration ("sv_regeneration", "1", FCVAR_REPLICATED ); ConVar sv_regeneration_wait_time ("sv_regeneration_wait_time", "1.0", FCVAR_REPLICATED ); ConVar sv_regeneration_rate ("sv_regeneration_rate", "0.5", FCVAR_REPLICATED );
Esto nos permitirá equilibrar la tasa de regeneración durante el juego. Sin embargo, también necesitaremos un valor para mantener la cantidad de regeneración actual. Lugar:
float m_fRegenRemander;
en
int gEvilImpulse101;
Para conseguir que el constructor funcione ve a este código en player.cpp: CBasePlayer::CBasePlayer( ) debajo de m_iHealth = 0; alrededor de la línea 552 añade esto:
m_fRegenRemander = 0;
Consiguiendo el último tiempo de daño
Nota: Si se utiliza la base de código de HL2-Singleplayer, simplemente utilice m_flLastDamageTime en lugar de añadir m_fTimeLastHurt.

Ahora necesitamos averiguar el tiempo transcurrido desde que el jugador fue herido por última vez. Necesitamos esto porque queremos retrasar el tiempo antes de que comience la regeneración para que el jugador no comience a regenerarse cuando está recibiendo daño.
float m_fTimeLastHurt;
De vuelta en el lugar de player.cpp:
DEFINE_FIELD( m_fTimeLastHurt, FIELD_TIME ),
en
DEFINE_FIELD( m_tbdPrev, FIELD_TIME ),
en la línea 306 aproximadamente.

Ahora que tenemos un número para llevar la cuenta de cuándo el jugador fue herido por última vez, necesitaremos mantener ese valor actualizado. Para hacer esto agregue:
if ( GetHealth() < 100 ) //un valor como 20 si quieres que sera como gta v { m_fTimeLastHurt = gpGlobals->curtime; }
al final del método CBasePlayer::OnTakeDamage.
Regenerando
Ahora que todo está en su lugar, es el momento de añadir la lógica de regeneración. Al final de CBasePlayer::PostThink añade lo siguiente:

// Regeneración de los páramos if ( IsAlive() && GetHealth() < GetMaxHealth() && (sv_regeneration.GetInt() == 1) ) { // Color para superponer en la pantalla mientras el jugador recibe daño color32 hurtScreenOverlay = {80,0,0,64}; if ( gpGlobals->curtime > m_fTimeLastHurt + sv_regeneration_wait_time.GetFloat() ) { //Regenerar en base a la tasa, y escalarla por el frametime m_fRegenRemander += sv_regeneration_rate.GetFloat() * gpGlobals->frametime; if(m_fRegenRemander >= 1) { TakeHealth( m_fRegenRemander, DMG_GENERIC ); m_fRegenRemander = 0; } } else { UTIL_ScreenFade( this, hurtScreenOverlay, 1.0f, 0.1f, FFADE_IN|FFADE_PURGE ); } }

Y eso es todo.
Regeneración avanzada
Si quieres que sólo se regenere una parte de tu salud, hay dos maneras de hacerlo:

Restringir la regeneración para que sólo se produzca hasta un determinado valor de salud (por ejemplo, 50)
Restringir la regeneración para que sólo se produzca hasta un determinado intervalo de valores de salud (es decir, 20, 40, 60, 80 y 100 o etc.)
Para ello, necesitamos más ConVars.
ConVar sv_regen_interval("sv_regen_interval", "20", FCVAR_REPLICATED, "Set what interval of health to regen to.\n i.e. if this is set to the default value (20), if you are damaged to 75 health, you'll regenerate to 80 health.\n Set this to 0 to disable this mechanic."); ConVar sv_regen_limit("sv_regen_limit", "0", FCVAR_REPLICATED, "Set the limit as to how much health you can regen to.\n i.e. if this is set at 50, you can only regen to 50 health. If you are hurt and you are above 50 health, you will not regen.\n Set this to 0 to disable this mechanic.");
Ahora, necesitamos implementar esto en nuestro código de regeneración. ¿Recuerdas esto?
if(m_fRegenRemander >= 1) { TakeHealth( m_fRegenRemander, DMG_GENERIC ); m_fRegenRemander = 0; }
Es hora de complicar las cosas.
if(m_fRegenRemander >= 1) { //Si el intervalo de regeneración está establecido, y la salud es divisible uniformemente por ese intervalo, no regenera. if (sv_regen_interval.GetFloat() > 0 && floor(m_iHealth / sv_regen_interval.GetFloat()) == m_iHealth / sv_regen_interval.GetFloat()){ m_fRegenRemander = 0; } //Si el límite de regeneración está establecido, y la salud es igual o superior al límite, no regenera. else if (sv_regen_limit.GetFloat() > 0 && m_iHealth >= sv_regen_limit.GetFloat()){ m_fRegenRemander = 0; } else { TakeHealth(m_fRegenRemander, DMG_GENERIC); m_fRegenRemander = 0; } }
La edición de este código significa que cuando se hace una llamada para regenerar la salud, primero se comprueba si la salud actual cumple con una restricción que hemos establecido, y si lo hace, entonces no añade ninguna salud.

Revisemos este código un poco más despacio:
if (sv_regen_interval.GetFloat() > 0 && floor(m_iHealth / sv_regen_interval.GetFloat()) == m_iHealth / sv_regen_interval.GetFloat()){ m_fRegenRemander = 0; }
Esto, como se explica en el comentario, comprueba si sv_regen_interval se establece en algo mayor que 0, entonces comprueba si la salud actual dividida por el valor del intervalo da un número entero o un número entero. Si ambos son verdaderos, la salud no se añade.
else if (sv_regen_limit.GetFloat() > 0 && m_iHealth >= sv_regen_limit.GetFloat()){ m_fRegenRemander = 0; }

Esto, como también se explica en el comentario, comprueba si sv_regen_limit está establecido en algo mayor que 0, y luego comprueba si la salud actual cumple o supera ese límite. Si ambos son verdaderos, la salud no se añade.