Files
2026-05-05 15:01:01 -07:00

301 lines
8.7 KiB
C++

//**************************************************************************
//**
//** GAME_CILIA.CPP
//**
//** Specific type of SpherePart. When shot, they retract for a while,
//** and trigger nearby cilia to retract as well.
//**************************************************************************
// HEADER FILES ------------------------------------------------------------
#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
// CLASS DECLARATIONS ------------------------------------------------------
const idEventDef EV_StickOut( "stickout", NULL );
const idEventDef EV_TriggerNearby( "triggernearby", NULL );
const idEventDef EV_Idle( "idle", NULL );
CLASS_DECLARATION( hhSpherePart, hhSphereCilia )
EVENT( EV_Activate, hhSphereCilia::Event_Trigger )
EVENT( EV_TriggerNearby, hhSphereCilia::Event_TriggerNearby )
EVENT( EV_StickOut, hhSphereCilia::Event_StickOut )
EVENT( EV_Idle, hhSphereCilia::Event_Idle ) // JRM
EVENT( EV_Touch, hhSphereCilia::Event_Touch )
END_CLASS
// STATE DECLARATIONS -------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
// PRIVATE DATA DEFINITIONS ------------------------------------------------
// CODE --------------------------------------------------------------------
//==========================================================================
//
// hhSphereCilia::Spawn
//
//==========================================================================
void hhSphereCilia::Spawn(void) {
fl.takedamage = true; // Allow the spherepart to be damaged
fl.allowSpiritWalkTouch = true;
bRetracted = false; // Start sticking out
bAlreadyActivated = false; // Hasn't been touched yet
//HUMANHEAD jsh PCF 4/26/06 allow creatures to trigger cilia
GetPhysics()->SetContents( CONTENTS_TRIGGER | CONTENTS_RENDERMODEL );
idleAnim = GetAnimator()->GetAnim("idle");
pullInAnim = GetAnimator()->GetAnim("pullin");
stickOutAnim = GetAnimator()->GetAnim("stickout");
spawnArgs.GetFloat( "nearbySize", "128", nearbySize );
spawnArgs.GetFloat( "idleDelay", "-1", idleDelay );
if( idleDelay < 0 ) { // negative number denotes a random start delay
idleDelay = gameLocal.random.RandomFloat();
}
GetAnimator()->ClearAllAnims( gameLocal.time, 0 );
GetAnimator()->CycleAnim(ANIMCHANNEL_ALL, idleAnim, gameLocal.time + idleDelay * 1000, 100 );
}
void hhSphereCilia::Save(idSaveGame *savefile) const {
savefile->WriteInt( pullInAnim );
savefile->WriteInt( stickOutAnim );
savefile->WriteFloat( nearbySize );
savefile->WriteFloat( idleDelay );
savefile->WriteBool( bRetracted );
savefile->WriteBool( bAlreadyActivated );
}
void hhSphereCilia::Restore( idRestoreGame *savefile ) {
savefile->ReadInt( pullInAnim );
savefile->ReadInt( stickOutAnim );
savefile->ReadFloat( nearbySize );
savefile->ReadFloat( idleDelay );
savefile->ReadBool( bRetracted );
savefile->ReadBool( bAlreadyActivated );
}
//==========================================================================
//
// hhSphereCilia::Damage
//
// Currently similar to
//==========================================================================
void hhSphereCilia::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir,
const char *damageDefName, const float damageScale, const int location ) {
hhFxInfo fxInfo;
if( bRetracted ) { // Don't trigger if already retracted
return;
}
bRetracted = true;
// Remove collision on the model
GetPhysics()->SetContents(0);
// Switch to the broken model
SetModel( spawnArgs.GetString( "model_broken", "" ) );
// Play an explode sound
StartSound( "snd_explode", SND_CHANNEL_ANY, 0, true, NULL );
fl.takedamage = false;
fl.applyDamageEffects = false; // Cilia don't accept damage wounds, since they swap out models
PostEventSec( &EV_TriggerNearby, 0.2f + gameLocal.random.RandomFloat() * 0.1 );
ApplyEffect();
}
//==========================================================================
//
// hhSphereCilia::Event_Touch
//
//==========================================================================
void hhSphereCilia::Event_Touch( idEntity *other, trace_t *trace ) {
Trigger( other );
}
//==========================================================================
//
// hhSphereCilia::Trigger
//
//==========================================================================
void hhSphereCilia::Trigger( idEntity *activator ) {
if( bRetracted || !activator ) { // Don't trigger if already retracted
return;
}
bRetracted = true;
// Remove collision on the model
GetPhysics()->SetContents(0);
GetAnimator()->ClearAllAnims( gameLocal.time, 0 );
GetAnimator()->PlayAnim( ANIMCHANNEL_ALL, pullInAnim, gameLocal.time, 100);
StartSound( "snd_in", SND_CHANNEL_ANY, 0, true, NULL );
PostEventSec( &EV_TriggerNearby, 0.2f + gameLocal.random.RandomFloat() * 0.1 );
PostEventSec( &EV_StickOut, 5.0f + idleDelay );
// Trigger this cilia's targets the first time it is touched
if ( !bAlreadyActivated ) {
ActivateTargets( activator );
bAlreadyActivated = true;
}
ApplyEffect();
}
//==========================================================================
//
// hhSphereCilia::Event_Trigger
//
//==========================================================================
void hhSphereCilia::Event_Trigger( idEntity *activator ) {
Trigger( activator );
}
//==========================================================================
//
// hhSphereCilia::Event_TriggerNearby
//
// Trigger nearby cilia (to create a cascading retract effect)
//==========================================================================
void hhSphereCilia::Event_TriggerNearby( void ) {
int i;
int e;
hhSphereCilia *ent;
idEntity *entityList[ MAX_GENTITIES ];
int numListedEntities;
idBounds bounds;
idVec3 org;
org = GetPhysics()->GetOrigin();
for ( i = 0 ; i < 3 ; i++ ) {
bounds[0][i] = org[i] - nearbySize;
bounds[1][i] = org[i] + nearbySize;
}
// Find the first closest neighbor cilia to trigger
numListedEntities = gameLocal.clip.EntitiesTouchingBounds( bounds, -1, entityList, MAX_GENTITIES );
for ( e = 0 ; e < numListedEntities ; e++ ) {
if( !entityList[e]->IsType( hhSphereCilia::Type ) ) {
continue;
}
ent = static_cast< hhSphereCilia * >( entityList[e] );
if( ent->bRetracted ) {
continue;
}
ent->Trigger( this );
}
}
//==========================================================================
//
// hhSphereCilia::Event_StickOut
//
// Return the cilia to its original state
//==========================================================================
#define MAX_NEARBY_CILIA 8
void hhSphereCilia::Event_StickOut( void ) {
int i;
int num;
idEntity *touch[MAX_NEARBY_CILIA];
idEntity *hit;
bool canFit;
// Check if the cilia can fit when sticking out
num = gameLocal.clip.EntitiesTouchingBounds( GetPhysics()->GetAbsBounds(), -1, touch, MAX_NEARBY_CILIA );
canFit = true;
for( i = 0; i < num; i++ ) {
hit = touch[ i ];
assert( hit );
if(( hit == this )) {
continue;
}
// Hit an entity, so reset the cilia to attempt to emerge in a bit
PostEventSec( &EV_StickOut, 5.0f );
return;
}
//HUMANHEAD jsh PCF 4/26/06 allow creatures to trigger cilia
// Restore the proper collision
GetPhysics()->SetContents( CONTENTS_TRIGGER | CONTENTS_RENDERMODEL );
// Play the stick out anims and blend the idle back in
GetAnimator()->PlayAnim( ANIMCHANNEL_ALL, stickOutAnim, gameLocal.time, 100);
PostEventMS(&EV_Idle, 100); // JRM
StartSound( "snd_out", SND_CHANNEL_ANY, 0, true, NULL);
bRetracted = false;
}
//
// Event_Idle
//
// JRM
void hhSphereCilia::Event_Idle(void) {
assert(idleAnim);
GetAnimator()->CycleAnim(ANIMCHANNEL_ALL, idleAnim, gameLocal.time, 200);
};
void hhSphereCilia::ApplyEffect( void ) {
hhFxInfo fxInfo;
fxInfo.SetNormal( GetAxis()[0] );
fxInfo.RemoveWhenDone( true );
BroadcastFxInfoPrefixed( "fx_explode", GetOrigin() + (GetAxis()[0] * 16.0f), GetAxis(), &fxInfo );
int num;
int i;
idEntity* ents[MAX_GENTITIES];
num = gameLocal.clip.EntitiesTouchingBounds( GetPhysics()->GetAbsBounds(), MASK_SHOT_BOUNDINGBOX|CONTENTS_RENDERMODEL, ents, MAX_GENTITIES );
const char *damageType = spawnArgs.GetString("damageType", "damage_cilia");
for( i = 0; i < num; i++ ) {
if( ents[ i ] != this && !ents[ i ]->IsType(hhSphereCilia::Type) && !ents[ i ]->IsType(idAFAttachment::Type) ) {
ents[ i ]->Damage( this, this, vec3_origin, damageType, 1.0f, INVALID_JOINT );
}
}
}