quake4-sdk/source/game/Healing_Station.cpp

210 lines
5.4 KiB
C++

#include "../idlib/precompiled.h"
#pragma hdrstop
#include "Game_local.h"
#include "Healing_Station.h"
CLASS_DECLARATION( idAnimatedEntity, rvHealingStation )
END_CLASS
/*
================
rvHealingStation::Think
================
*/
void rvHealingStation::Think ( void ) {
// TODO: I'm guessing this is bad, but I wanted to get this in so that people could start
// placing it. The entity decided to stop thinking and I didn't have time to debug it.
BecomeActive( TH_ALL );
stateThread.Execute();
UpdateAnimation();
if ( thinkFlags & TH_UPDATEVISUALS ) {
if ( healthDispensed > 0 ) {
CreateFrame( float( healthDispensed ) / maxHealth );
}
Present();
}
}
/*
================
rvHealingStation::Spawn
================
*/
void rvHealingStation::Spawn ( void ) {
entityToHeal = 0;
nextHealTime = 0;
healFrequency = spawnArgs.GetInt( "heal_frequency", "24" );
healAmount = spawnArgs.GetInt( "heal_amount", "1" );
healthDispensed = 0;
soundStartTime = 0;
soundLength = 0;
maxHealth = spawnArgs.GetInt( "max_health", "100" );
dispenseAnim = GetAnimator()->GetAnim( spawnArgs.GetString( "dispense_anim", "dispense" ) );
CreateFrame( 0 );
stateThread.SetOwner( this );
stateThread.SetName( GetName() );
GetAnimator()->CycleAnim( ANIMCHANNEL_ALL, GetAnimator()->GetAnim( spawnArgs.GetString( "anim", "idle" ) ), gameLocal.time, 4 );
}
/*
================
rvHealingStation::Save
================
*/
void rvHealingStation::Save ( idSaveGame *savefile ) const {
stateThread.Save( savefile );
entityToHeal.Save ( savefile );
savefile->WriteInt( nextHealTime );
savefile->WriteInt( healFrequency );
savefile->WriteInt( healAmount );
savefile->WriteInt( healthDispensed );
savefile->WriteInt( maxHealth );
savefile->WriteInt( dispenseAnim );
savefile->WriteInt( soundStartTime );
savefile->WriteInt( soundLength );
}
/*
================
rvHealingStation::Restore
================
*/
void rvHealingStation::Restore ( idRestoreGame *savefile ) {
stateThread.Restore( savefile, this );
entityToHeal.Restore ( savefile );
savefile->ReadInt( nextHealTime );
savefile->ReadInt( healFrequency );
savefile->ReadInt( healAmount );
savefile->ReadInt( healthDispensed );
savefile->ReadInt( maxHealth );
savefile->ReadInt( dispenseAnim );
savefile->ReadInt( soundStartTime );
savefile->ReadInt( soundLength );
}
/*
================
rvHealingStation::BeginHealing
================
*/
void rvHealingStation::BeginHealing ( idEntity *toHeal ) {
entityToHeal = toHeal;
stateThread.SetState( "Healing" );
}
/*
================
rvHealingStation::EndHealing
================
*/
void rvHealingStation::EndHealing ( void ) {
entityToHeal = NULL;
}
/*
================
rvHealingStation::CreateFrame
================
*/
void rvHealingStation::CreateFrame ( float station_health ) {
// Update the GUI
if ( renderEntity.gui[ 0 ] ) {
renderEntity.gui[ 0 ]->SetStateFloat( "station_health", 1.0f - station_health );
renderEntity.gui[ 0 ]->StateChanged( gameLocal.time, true );
}
// Update the Animation
int numFrames = GetAnimator()->GetAnim( dispenseAnim )->NumFrames();
float lerp = numFrames * station_health;
int frame = lerp;
lerp = lerp - frame;
frameBlend_t frameBlend = { 0, frame, frame + 1, 1.0f - lerp, lerp };
GetAnimator()->SetFrame( ANIMCHANNEL_ALL, dispenseAnim, frameBlend );
}
/*
================
rvHealingStation::IsPlaying
================
*/
bool rvHealingStation::IsPlaying ( void ) {
idSoundEmitter* emitter = soundSystem->EmitterForIndex ( SOUNDWORLD_GAME, GetSoundEmitter ( ) );
if( emitter ) {
return ( emitter->CurrentlyPlaying ( ) );
}
return false;
}
/*
===============================================================================
States
===============================================================================
*/
CLASS_STATES_DECLARATION ( rvHealingStation )
STATE ( "Healing", rvHealingStation::State_Healing )
END_CLASS_STATES
/*
================
rvHealingStation::State_Healing
================
*/
stateResult_t rvHealingStation::State_Healing ( const stateParms_t& parms ) {
enum {
STAGE_INIT,
STAGE_WAIT,
STAGE_DISPENSE,
};
if ( entityToHeal.IsValid() ) {
idPlayer* player = static_cast<idPlayer*>( entityToHeal.GetEntity( ) );
const int entityMaxHealth = player->inventory.maxHealth;
if ( healthDispensed < maxHealth && // and we have health to dispense...
entityToHeal->health < entityMaxHealth && // and the entity needs health.
entityToHeal->health > 0 ) // and he's still alive.
{
switch ( parms.stage ) {
case STAGE_INIT:
soundStartTime = gameLocal.time;
StartSound( "snd_start", SND_CHANNEL_ANY, 0, false, &soundLength );
return SRESULT_STAGE ( STAGE_WAIT );
case STAGE_WAIT:
if ( gameLocal.time > soundStartTime + soundLength ) {
soundStartTime = 0;
soundLength = 0;
return SRESULT_STAGE ( STAGE_DISPENSE );
}
return SRESULT_WAIT;
case STAGE_DISPENSE:
if ( gameLocal.time > nextHealTime ) { // If it's time to heal...
int healthGiven = Min( maxHealth - healthDispensed, Min( healAmount, entityMaxHealth - entityToHeal->health ) );
entityToHeal->health += healthGiven;
healthDispensed += healthGiven;
nextHealTime = gameLocal.time + healFrequency;
}
if ( !IsPlaying ( ) ) {
StartSound( "snd_loop", SND_CHANNEL_ANY, 0, false, NULL );
}
return SRESULT_WAIT;
}
}
}
StopSound ( SND_CHANNEL_ANY, 0 );
StartSound ( "snd_stop", SND_CHANNEL_ANY, 0, false, NULL );
return SRESULT_DONE;
}