mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-18 03:35:07 +02:00
Initial Prey Game integration support.
This commit is contained in:
@@ -0,0 +1,974 @@
|
||||
//*****************************************************************************
|
||||
//**
|
||||
//** GAME_WRAITH.CPP
|
||||
//**
|
||||
//** Game code for the Wraith creature
|
||||
//**
|
||||
//*****************************************************************************
|
||||
|
||||
// HEADER FILES ---------------------------------------------------------------
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "prey_local.h"
|
||||
|
||||
// MACROS ---------------------------------------------------------------------
|
||||
|
||||
#define TWEEN_BANK 1000
|
||||
|
||||
// TYPES ----------------------------------------------------------------------
|
||||
|
||||
// CLASS DECLARATIONS ---------------------------------------------------------
|
||||
|
||||
const idEventDef EV_Flee( "<flee>", NULL );
|
||||
const idEventDef EV_PlayAnimMoveEnd( "<playanimmoveend>", NULL );
|
||||
extern const idEventDef EV_SpawnDeathWraith;
|
||||
extern const idEventDef AI_FindEnemy;
|
||||
|
||||
CLASS_DECLARATION( hhMonsterAI, hhWraith )
|
||||
EVENT( EV_Flee, hhWraith::Event_Flee )
|
||||
EVENT( EV_PlayAnimMoveEnd, hhWraith::Event_PlayAnimMoveEnd )
|
||||
EVENT( AI_FindEnemy, hhWraith::Event_FindEnemy )
|
||||
EVENT( EV_Activate, hhWraith::Event_Activate )
|
||||
END_CLASS
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::Spawn
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::Spawn(void) {
|
||||
// List animations
|
||||
flyAnim = GetAnimator()->GetAnim( "fly" );
|
||||
possessAnim = GetAnimator()->GetAnim( "alert" );
|
||||
leftAnim = GetAnimator()->GetAnim( "bankLeft" );
|
||||
rightAnim = GetAnimator()->GetAnim( "bankRight" );
|
||||
fleeAnim = GetAnimator()->GetAnim( "flee" );
|
||||
fleeInAnim = GetAnimator()->GetAnim( "fleeIn" );
|
||||
|
||||
lastAnim = NULL;
|
||||
|
||||
canPossess = spawnArgs.GetBool( "possess", "1" );
|
||||
|
||||
// Physics and collision information
|
||||
fl.takedamage = true;
|
||||
|
||||
minDamageDist = spawnArgs.GetFloat( "minDamageDist", "50" );
|
||||
|
||||
// Initialize flight logic
|
||||
straightTicks = 0;
|
||||
damageTicks = 0;
|
||||
turnTicks = 0;
|
||||
|
||||
isScaling = false;
|
||||
|
||||
// Initially launch the wraith forward
|
||||
velocity = GetPhysics()->GetAxis()[0] * 100;
|
||||
|
||||
GetAnimator()->ClearAllAnims( gameLocal.time, 0 );
|
||||
GetAnimator()->CycleAnim( ANIMCHANNEL_ALL, flyAnim, gameLocal.time, 0 );
|
||||
|
||||
BecomeActive( TH_THINK );
|
||||
fl.neverDormant = true;
|
||||
|
||||
nextCheckTime = gameLocal.time + spawnArgs.GetInt("trace_check_time", "200");
|
||||
lastCheckOrigin = GetPhysics()->GetOrigin();
|
||||
lastDamageTime = spawnArgs.GetFloat( "damageDelay", "0.5" );
|
||||
|
||||
if ( spawnArgs.GetBool( "spawnFlyUp", "0" ) ) {
|
||||
state = WS_SPAWN;
|
||||
|
||||
// Orient the wraith pointing upwards
|
||||
desiredAxis[0] = idVec3( 0, 0, 1 );
|
||||
desiredAxis[1] = idVec3( 1, 0, 0 );
|
||||
desiredAxis[2] = idVec3( 0, -1, 0 );
|
||||
|
||||
// Set the speed of this movement
|
||||
desiredVelocity = spawnArgs.GetFloat( "initialVelocity", "10" ); // TODO: Make this random
|
||||
|
||||
// Calculate how far the wraith should fly and how long that should take
|
||||
// NOTE: If we make the velocity a random range, then we can make this spawn time constant
|
||||
countDownTimer = spawnArgs.GetFloat( "spawnTime", "0.5" ) * 60; // Half a second to raise up
|
||||
} else {
|
||||
state = WS_FLY;
|
||||
}
|
||||
|
||||
// Initialize .def values
|
||||
velocity_xy = spawnArgs.GetFloat( "velocity_xy", "7" ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
||||
velocity_z = spawnArgs.GetFloat( "velocity_z", "1" ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
||||
velocity_z_fast = spawnArgs.GetFloat( "velocity_z_fast", "5" ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
||||
dist_z_close = spawnArgs.GetFloat( "dist_z_close", "5" );
|
||||
dist_z_far = spawnArgs.GetFloat( "dist_z_far", "100" );
|
||||
|
||||
turn_threshold = DEG2RAD( spawnArgs.GetFloat( "turn_threshold", "5" ) ); // CJR PCF 5/17/06: Removed unnecessary 30Hz compensation
|
||||
turn_radius_max = DEG2RAD( spawnArgs.GetFloat( "turn_radius_max", "130" ) ); // CJR PCF 5/17/06: Remove unnecessary 30Hz compensation
|
||||
|
||||
straight_ticks = spawnArgs.GetInt( "straight_ticks", "30" ) * (USERCMD_HZ / 60.0f);
|
||||
damage_ticks = spawnArgs.GetFloat( "damage_ticks", "8" ) * (USERCMD_HZ / 60.0f);
|
||||
turn_ticks = spawnArgs.GetFloat( "turn_ticks", "200" ) * (USERCMD_HZ / 60.0f);
|
||||
|
||||
flee_speed_z = spawnArgs.GetFloat( "flee_speed_z", "10" ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
||||
|
||||
target_z_threshold = spawnArgs.GetFloat( "target_z_threshold", "20" );
|
||||
|
||||
// JRM: are we waiting for a trigger? Then no sound.
|
||||
if(!spawnArgs.GetBool("trigger","0")) {
|
||||
StartSound( "snd_flyloop", SND_CHANNEL_BODY );
|
||||
StartSound( "snd_sight", SND_CHANNEL_VOICE );
|
||||
|
||||
// If this wraith should flee when spawned, then kill it immediately and get it fleeing
|
||||
// This is used by the possessed kids to spawn a wraith that flees immediately
|
||||
if ( spawnArgs.GetBool("flee_at_spawn", "0" ) ) {
|
||||
// Fleeing
|
||||
Killed( this, this, 0, vec3_origin, 0 );
|
||||
|
||||
isScaling = true;
|
||||
scaleStart = spawnArgs.GetFloat( "scaleStart", "1" );
|
||||
scaleEnd = spawnArgs.GetFloat( "scaleEnd", "1" );
|
||||
scaleTime = spawnArgs.GetFloat( "scaleTime", "1" );
|
||||
|
||||
// Set data for dynamically scaling the wraith
|
||||
SetShaderParm( SHADERPARM_ANY_DEFORM, DEFORMTYPE_SCALE ); // Scale deform
|
||||
SetShaderParm( SHADERPARM_ANY_DEFORM_PARM1, scaleStart ); // Scale deform
|
||||
lastScaleTime = MS2SEC( gameLocal.time ) + scaleTime;
|
||||
}
|
||||
}
|
||||
|
||||
Event_SetMoveType(MOVETYPE_FLY); // JRM to get the wraiths to move again
|
||||
|
||||
GetPhysics()->SetContents( CONTENTS_SHOOTABLE|CONTENTS_SHOOTABLEBYARROW );
|
||||
GetPhysics()->SetClipMask( 0 );
|
||||
|
||||
bFaceEnemy = false;
|
||||
nextDrop = 0;
|
||||
nextChatter = 0;
|
||||
nextPossessTime = 0;
|
||||
|
||||
minChatter = SEC2MS(spawnArgs.GetFloat( "min_chatter_time", "3" ));
|
||||
maxChatter = SEC2MS(spawnArgs.GetFloat( "max_chatter_time", "6" ));
|
||||
|
||||
if ( !IsHidden() ) {
|
||||
Hide();
|
||||
PostEventMS( &EV_Activate, 0, this );
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::~hhWraith
|
||||
//
|
||||
//=============================================================================
|
||||
hhWraith::~hhWraith() {
|
||||
StopSound( SND_CHANNEL_BODY );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::Save
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::Save( idSaveGame *savefile ) const {
|
||||
savefile->WriteInt( lastAnim );
|
||||
savefile->WriteBool( canPossess );
|
||||
savefile->WriteVec3( velocity );
|
||||
savefile->WriteInt( damageTicks );
|
||||
savefile->WriteInt( straightTicks );
|
||||
savefile->WriteInt( turnTicks );
|
||||
savefile->WriteVec3( lastCheckOrigin );
|
||||
savefile->WriteFloat( lastDamageTime );
|
||||
savefile->WriteInt( state );
|
||||
savefile->WriteFloat( velocity_xy );
|
||||
savefile->WriteFloat( velocity_z );
|
||||
savefile->WriteFloat( velocity_z_fast );
|
||||
savefile->WriteFloat( dist_z_close );
|
||||
savefile->WriteFloat( dist_z_far );
|
||||
savefile->WriteFloat( turn_threshold );
|
||||
savefile->WriteFloat( turn_radius_max );
|
||||
savefile->WriteInt( straight_ticks );
|
||||
savefile->WriteInt( damage_ticks );
|
||||
savefile->WriteInt( turn_ticks );
|
||||
savefile->WriteFloat( flee_speed_z );
|
||||
savefile->WriteFloat( target_z_threshold );
|
||||
savefile->WriteFloat( minDamageDist );
|
||||
savefile->WriteBool( isScaling );
|
||||
savefile->WriteFloat( scaleStart );
|
||||
savefile->WriteFloat( scaleEnd );
|
||||
savefile->WriteFloat( lastScaleTime );
|
||||
savefile->WriteInt( countDownTimer );
|
||||
savefile->WriteMat3( desiredAxis );
|
||||
savefile->WriteFloat( desiredVelocity );
|
||||
savefile->WriteBool( bFaceEnemy );
|
||||
fxFly.Save( savefile );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::Restore
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::Restore( idRestoreGame *savefile ) {
|
||||
savefile->ReadInt( lastAnim );
|
||||
savefile->ReadBool( canPossess );
|
||||
savefile->ReadVec3( velocity );
|
||||
savefile->ReadInt( damageTicks );
|
||||
savefile->ReadInt( straightTicks );
|
||||
savefile->ReadInt( turnTicks );
|
||||
savefile->ReadVec3( lastCheckOrigin );
|
||||
savefile->ReadFloat( lastDamageTime );
|
||||
savefile->ReadInt( (int &)state );
|
||||
savefile->ReadFloat( velocity_xy );
|
||||
savefile->ReadFloat( velocity_z );
|
||||
savefile->ReadFloat( velocity_z_fast );
|
||||
savefile->ReadFloat( dist_z_close );
|
||||
savefile->ReadFloat( dist_z_far );
|
||||
savefile->ReadFloat( turn_threshold );
|
||||
savefile->ReadFloat( turn_radius_max );
|
||||
savefile->ReadInt( straight_ticks );
|
||||
savefile->ReadInt( damage_ticks );
|
||||
savefile->ReadInt( turn_ticks );
|
||||
savefile->ReadFloat( flee_speed_z );
|
||||
savefile->ReadFloat( target_z_threshold );
|
||||
savefile->ReadFloat( minDamageDist );
|
||||
savefile->ReadBool( isScaling );
|
||||
savefile->ReadFloat( scaleStart );
|
||||
savefile->ReadFloat( scaleEnd );
|
||||
savefile->ReadFloat( lastScaleTime );
|
||||
savefile->ReadInt( countDownTimer );
|
||||
savefile->ReadMat3( desiredAxis );
|
||||
savefile->ReadFloat( desiredVelocity );
|
||||
savefile->ReadBool( bFaceEnemy );
|
||||
|
||||
// List animations
|
||||
flyAnim = GetAnimator()->GetAnim( "fly" );
|
||||
possessAnim = GetAnimator()->GetAnim( "alert" );
|
||||
leftAnim = GetAnimator()->GetAnim( "bankLeft" );
|
||||
rightAnim = GetAnimator()->GetAnim( "bankRight" );
|
||||
fleeAnim = GetAnimator()->GetAnim( "flee" );
|
||||
fleeInAnim = GetAnimator()->GetAnim( "fleeIn" );
|
||||
|
||||
canPossess = spawnArgs.GetBool( "possess", "1" );
|
||||
|
||||
minDamageDist = spawnArgs.GetFloat( "minDamageDist", "50" );
|
||||
|
||||
// Initialize .def values
|
||||
velocity_xy = spawnArgs.GetFloat( "velocity_xy", "7" );
|
||||
velocity_z = spawnArgs.GetFloat( "velocity_z", "1" );
|
||||
velocity_z_fast = spawnArgs.GetFloat( "velocity_z_fast", "5" );
|
||||
dist_z_close = spawnArgs.GetFloat( "dist_z_close", "5" );
|
||||
dist_z_far = spawnArgs.GetFloat( "dist_z_far", "100" );
|
||||
|
||||
turn_threshold = DEG2RAD( spawnArgs.GetFloat( "turn_threshold", "5" ) );
|
||||
turn_radius_max = DEG2RAD( spawnArgs.GetFloat( "turn_radius_max", "130" ) );
|
||||
|
||||
straight_ticks = spawnArgs.GetInt( "straight_ticks", "30" ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
||||
damage_ticks = spawnArgs.GetFloat( "damage_ticks", "8" ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
||||
turn_ticks = spawnArgs.GetFloat( "turn_ticks", "200" ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
||||
|
||||
flee_speed_z = spawnArgs.GetFloat( "flee_speed_z", "10" );
|
||||
|
||||
target_z_threshold = spawnArgs.GetFloat( "target_z_threshold", "20" );
|
||||
|
||||
nextDrop = 0;
|
||||
nextChatter = 0;
|
||||
nextPossessTime = gameLocal.time + 500; // Don't possess for half a second after loading
|
||||
minChatter = SEC2MS(spawnArgs.GetFloat( "min_chatter_time", "3" ));
|
||||
maxChatter = SEC2MS(spawnArgs.GetFloat( "max_chatter_time", "6" ));
|
||||
|
||||
fxFly.Restore( savefile );
|
||||
|
||||
nextCheckTime = gameLocal.time + spawnArgs.GetInt("trace_check_time", "200");
|
||||
scaleTime = spawnArgs.GetFloat( "scaleTime", "1" );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::Think
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::Think(void) {
|
||||
if(!IsHidden()) { // JRM - NO TRACES WHEN HIDDEN!
|
||||
CheckCollisions();
|
||||
|
||||
if (gameLocal.time > nextDrop) {
|
||||
hhMonsterAI::Damage(this, this, vec3_origin, "damage_wraithminion", 0.05f, INVALID_JOINT);
|
||||
nextDrop = gameLocal.time + 1000;
|
||||
}
|
||||
|
||||
if (gameLocal.time > nextChatter) {
|
||||
StartSound( "snd_chatter", SND_CHANNEL_VOICE );
|
||||
nextChatter = gameLocal.time + (minChatter + gameLocal.random.RandomFloat() * (maxChatter - minChatter));
|
||||
}
|
||||
}
|
||||
|
||||
// Scale the wraith
|
||||
if ( isScaling ) {
|
||||
float delta = lastScaleTime - MS2SEC( gameLocal.time );
|
||||
if ( delta > 0 ) {
|
||||
SetShaderParm( SHADERPARM_ANY_DEFORM_PARM1, hhMath::Lerp( scaleEnd, scaleStart, delta / scaleTime ) );
|
||||
}
|
||||
}
|
||||
|
||||
hhMonsterAI::Think(); // JRM: Bypassing hhAI::Think()
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::Event_Activate
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::Event_Activate(idEntity *activator) {
|
||||
if ( IsHidden() ) {
|
||||
TeleportIn(activator);
|
||||
return;
|
||||
}
|
||||
if ( spawnArgs.GetBool("flee_at_spawn", "0" ) ) {
|
||||
// Fleeing
|
||||
Killed( this, this, 0, vec3_origin, 0 );
|
||||
|
||||
isScaling = true;
|
||||
scaleStart = spawnArgs.GetFloat( "scaleStart", "1" );
|
||||
scaleEnd = spawnArgs.GetFloat( "scaleEnd", "1" );
|
||||
scaleTime = spawnArgs.GetFloat( "scaleTime", "1" );
|
||||
|
||||
// Set data for dynamically scaling the wraith
|
||||
SetShaderParm( SHADERPARM_ANY_DEFORM, DEFORMTYPE_SCALE ); // Scale deform
|
||||
SetShaderParm( SHADERPARM_ANY_DEFORM_PARM1, scaleStart ); // Scale deform
|
||||
lastScaleTime = MS2SEC( gameLocal.time ) + scaleTime;
|
||||
}
|
||||
|
||||
hhMonsterAI::Event_Activate(activator);
|
||||
|
||||
// we've been waiting for a trigger
|
||||
if (spawnArgs.GetBool("trigger")) {
|
||||
StartSound( "snd_flyloop", SND_CHANNEL_BODY );
|
||||
StartSound( "snd_sight", SND_CHANNEL_VOICE );
|
||||
}
|
||||
|
||||
|
||||
const char *defName = spawnArgs.GetString("fx_fly");
|
||||
if (defName && defName[0]) {
|
||||
hhFxInfo fxInfo;
|
||||
|
||||
fxInfo.SetNormal( -GetAxis()[0] );
|
||||
fxInfo.SetEntity( this );
|
||||
fxInfo.RemoveWhenDone( false );
|
||||
fxFly = SpawnFxLocal( defName, GetOrigin(), GetAxis(), &fxInfo, gameLocal.isClient );
|
||||
if (fxFly.IsValid()) {
|
||||
fxFly->fl.neverDormant = true;
|
||||
|
||||
fxFly->fl.networkSync = false;
|
||||
fxFly->fl.clientEvents = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::FindEnemy
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::Event_FindEnemy( int useFOV ) {
|
||||
int i;
|
||||
idEntity *ent;
|
||||
idActor *closest;
|
||||
idActor *actor;
|
||||
float closestDist;
|
||||
float distSquared;
|
||||
|
||||
closest = NULL;
|
||||
closestDist = 99999999.0f;
|
||||
|
||||
if (team != 0) { // Search players
|
||||
for ( i = 0; i < gameLocal.numClients ; i++ ) {
|
||||
ent = gameLocal.entities[ i ];
|
||||
|
||||
if ( !ent || !ent->IsType( idActor::Type ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ent->IsType( hhPlayer::Type ) ) { // Check if the player is really dead or deathwalking
|
||||
hhPlayer *player = static_cast< hhPlayer * >( ent );
|
||||
if ( player->IsDead() || player->IsDeathWalking() ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Find the closest enemy
|
||||
distSquared = ( GetOrigin() - ent->GetOrigin() ).LengthSqr();
|
||||
if ( distSquared < closestDist ) {
|
||||
closestDist = distSquared;
|
||||
closest = static_cast<idActor *>( ent );
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // Search monsters
|
||||
int numMonsters = hhMonsterAI::allSimpleMonsters.Num();
|
||||
for ( i = 0; i < numMonsters ; i++ ) {
|
||||
actor = hhMonsterAI::allSimpleMonsters[ i ];
|
||||
|
||||
if ( !actor || actor==this ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore dormant entities!
|
||||
if (actor->IsHidden() || actor->fl.isDormant) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( (actor->health <= 0) || !(ReactionTo(actor) & ATTACK_ON_SIGHT) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
distSquared = (actor->GetOrigin() - GetOrigin()).LengthSqr();
|
||||
if ( distSquared < closestDist ) {
|
||||
closestDist = distSquared;
|
||||
closest = actor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (closest) {
|
||||
SetEnemy( closest );
|
||||
}
|
||||
else {
|
||||
// FIXME: No enemies found, should we just go away or circle for a while?
|
||||
Damage(this, this, vec3_origin, "damage_suicide", 1.0f, INVALID_JOINT);
|
||||
}
|
||||
|
||||
idThread::ReturnEntity( closest );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::UpdateEnemyPosition
|
||||
//
|
||||
// This is here to override the default UpdateEnemyPosition, which
|
||||
// runs code that is unnecessary for the wraiths
|
||||
//=============================================================================
|
||||
void hhWraith::UpdateEnemyPosition( void ) {
|
||||
// Do nothing. Wraith's don't need to check if the enemy is no longer visible, since they can go through walls
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::EnemyDead
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::EnemyDead() {
|
||||
if ( !enemy.IsValid() || !enemy->IsType( hhPlayer::Type ) ) { // Only consider the enemy dead if the enemy is not a player
|
||||
hhMonsterAI::EnemyDead();
|
||||
} else if ( enemy.IsValid() && enemy->IsType( hhPlayer::Type ) ) { // If the player is deathwalking, then the enemy is dead
|
||||
hhPlayer *player = static_cast< hhPlayer * >( enemy.GetEntity() );
|
||||
if ( player->IsDead() || player->IsDeathWalking() ) {
|
||||
hhMonsterAI::EnemyDead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::FlyMove
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::FlyMove( void ) {
|
||||
// The state of the creature determines how it will move
|
||||
switch ( state ) {
|
||||
case WS_SPAWN:
|
||||
FlyUp(); // Flying up right after spawn
|
||||
break;
|
||||
case WS_FLY:
|
||||
FlyToEnemy();
|
||||
break;
|
||||
case WS_FLEE: // Flying away
|
||||
FlyAway();
|
||||
break;
|
||||
// case WS_POSSESS_CHARGE:
|
||||
// WraithDamageEnemy();
|
||||
// break;
|
||||
case WS_STILL: // Wraith is not moving at all (playing a specific anim, etc)
|
||||
return;
|
||||
}
|
||||
|
||||
// run the physics for this frame
|
||||
physicsObj.UseFlyMove( true );
|
||||
physicsObj.UseVelocityMove( false );
|
||||
physicsObj.SetDelta( vec3_zero );
|
||||
physicsObj.ForceDeltaMove( disableGravity );
|
||||
RunPhysics();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::FlyToEnemy
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::FlyToEnemy( void ) {
|
||||
float delta = 0;
|
||||
bool dir = false;
|
||||
int anim;
|
||||
|
||||
if ( !enemy.IsValid() ) {
|
||||
PostEventMS( &AI_FindEnemy, 1, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if (canPossess) {
|
||||
// Determine which direction the wraith needs to turn to the enemy (if the wraith should turn)
|
||||
if ( --straightTicks <= 0 ) {
|
||||
dir = GetFacePosAngle( enemy->GetOrigin(), delta );
|
||||
|
||||
turnTicks++; // Add in the number of ticks that the wraith has been turning
|
||||
// If the wraith has been turning for a very long period of time (more than 4 seconds), then force the wraith to go straight
|
||||
|
||||
// Vary turn_ticks by +/- 25 depending on the DDA value
|
||||
if ( turnTicks > this->turn_ticks - (25 * ((gameLocal.GetDDAValue() - 0.5f) * 2))) {
|
||||
dir = 0;
|
||||
delta = 0;
|
||||
turnTicks = 0;
|
||||
deltaViewAngles.yaw = 0;
|
||||
}
|
||||
} else {
|
||||
dir = 0;
|
||||
delta = 0;
|
||||
deltaViewAngles.yaw = 0;
|
||||
turnTicks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Turn the wraith, and set the correct bank animation
|
||||
anim = flyAnim;
|
||||
if ( delta > this->turn_threshold ) { // Wraith should turn
|
||||
if ( dir ) { // Turn to the left
|
||||
deltaViewAngles.yaw = this->turn_radius_max;
|
||||
anim = leftAnim;
|
||||
} else {
|
||||
deltaViewAngles.yaw = -this->turn_radius_max;
|
||||
anim = rightAnim;
|
||||
}
|
||||
} else if ( straightTicks <= 0 ) { // Straight at the player
|
||||
deltaViewAngles.yaw = 0;
|
||||
// Vary straight_ticks by +/- 25 depending on the DDA value
|
||||
straightTicks = this->straight_ticks - (25 * ((gameLocal.GetDDAValue() - 0.5f) * 2)); // Stay on this path for a short period of time
|
||||
}
|
||||
|
||||
// Actually set the animation
|
||||
if ( anim != lastAnim ) {
|
||||
GetAnimator()->ClearAllAnims( gameLocal.time, TWEEN_BANK );
|
||||
GetAnimator()->CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, TWEEN_BANK );
|
||||
lastAnim = anim;
|
||||
}
|
||||
|
||||
velocity = viewAxis[0] * this->velocity_xy;
|
||||
if ( damageTicks > 0 ) { // Fly slower if damaged
|
||||
velocity *= 0.85f;
|
||||
velocity += 10 * idVec3( gameLocal.random.CRandomFloat(), gameLocal.random.CRandomFloat(), gameLocal.random.CRandomFloat() );
|
||||
|
||||
damageTicks--;
|
||||
}
|
||||
|
||||
// Equalize the z-height of the wraith relative to its target
|
||||
idVec3 enemyOrigin = enemy->GetEyePosition();
|
||||
idVec3 origin = GetPhysics()->GetOrigin();
|
||||
|
||||
// Factor in fly_offset
|
||||
enemyOrigin.z += fly_offset;
|
||||
|
||||
// Adjust z-velocity based upon the delta Z to target
|
||||
velocity.z = 0;
|
||||
if( ( origin.z > enemyOrigin.z + this->target_z_threshold ) || ( origin.z < enemyOrigin.z - this->target_z_threshold ) ) {
|
||||
float newZ = enemyOrigin.z + target_z_threshold * 0.5f;
|
||||
float deltaZ = newZ - origin.z;
|
||||
if ( abs( deltaZ ) > this->dist_z_far ) {
|
||||
velocity.z = this->velocity_z_fast * ( ( deltaZ > 0 ) ? 1 : -1 );
|
||||
} else if ( abs( deltaZ ) > this->dist_z_close ) {
|
||||
velocity.z = this->velocity_z * ( ( deltaZ > 0 ) ? 1 : -1 );
|
||||
}
|
||||
}
|
||||
|
||||
// 1.5x the velocity if DDA is 1.0, half it for DDA = 0.0, leave it the same for normal (DDA = 0.5)
|
||||
GetPhysics()->SetOrigin( GetPhysics()->GetOrigin() + (velocity * (gameLocal.GetDDAValue() + 0.5f)));
|
||||
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::FlyAway
|
||||
//
|
||||
// Wraiths will automatically fly away from their enemy and up
|
||||
// The Wraith will eventually be removed from the world in the CheckFleeRemove function
|
||||
//=============================================================================
|
||||
void hhWraith::FlyAway( void ) {
|
||||
|
||||
velocity.x = 0;
|
||||
velocity.y = 0;
|
||||
velocity.z = this->flee_speed_z;
|
||||
|
||||
GetPhysics()->SetOrigin( GetPhysics()->GetOrigin() + velocity );
|
||||
|
||||
UpdateVisuals();
|
||||
|
||||
// Check to see if the wraith has flown out of the world
|
||||
CheckFleeRemove();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::FlyUp
|
||||
//
|
||||
// mdl: Wraiths will automatically fly up after being spawned if spawnFlyUp is set to 1
|
||||
// NOT related to flying away during death, that's FlyAway()
|
||||
//=============================================================================
|
||||
void hhWraith::FlyUp( void ) {
|
||||
idVec3 velocity;
|
||||
|
||||
// Turn towards desired angle
|
||||
// TODO: Make this smooth
|
||||
SetAxis( desiredAxis );
|
||||
|
||||
// Apply velocity
|
||||
velocity = desiredAxis[0] * desiredVelocity;
|
||||
SetOrigin( GetOrigin() + velocity );
|
||||
|
||||
UpdateVisuals();
|
||||
|
||||
// If the wraith is near the end of the spawn, then smoothly rotate the wraith to the horizontal
|
||||
if ( --countDownTimer <= 0 ) {
|
||||
state = WS_FLY;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::TurnTowardEnemy
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::TurnTowardEnemy() {
|
||||
float delta;
|
||||
bool dir;
|
||||
|
||||
if ( !enemy.IsValid() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Face torward the enemy
|
||||
dir = GetFacePosAngle( enemy->GetOrigin(), delta );
|
||||
|
||||
if ( delta > turn_threshold ) {
|
||||
// Turn based upon delta angles
|
||||
if ( dir ) { // Turn to the right
|
||||
deltaViewAngles.yaw = turn_radius_max;
|
||||
} else {
|
||||
deltaViewAngles.yaw = -turn_radius_max;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::CheckFleeRemove
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::CheckFleeRemove( void ) {
|
||||
// Check if the Wraith has flown out of the world
|
||||
if( gameLocal.clip.Contents( GetPhysics()->GetOrigin() + idVec3(0, 0, 48), GetPhysics()->GetClipModel(), viewAxis, CONTENTS_SOLID, this ) ) {
|
||||
Hide();
|
||||
PostEventSec( &EV_Remove, 2.0f ); // Keep the wraith around for a few seconds so the sounds can finish
|
||||
state = WS_STILL; // No reason to keep moving the wraith
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::Damage
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
|
||||
hhMonsterAI::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
|
||||
damageTicks = this->damage_ticks;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::Killed
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
|
||||
hhFxInfo fx;
|
||||
//fx.SetEntity( this );
|
||||
fx.RemoveWhenDone( true );
|
||||
const char *deathFX;
|
||||
|
||||
// Stop flyloop and chatter sounds, if any
|
||||
StopSound( SND_CHANNEL_BODY );
|
||||
StopSound( SND_CHANNEL_VOICE );
|
||||
|
||||
if ( inflictor == this ) {
|
||||
// If we timed out, don't drop a soul
|
||||
spawnArgs.Delete( "def_dropSoul" );
|
||||
deathFX = spawnArgs.GetString( "fx_death" );
|
||||
} else {
|
||||
// Use alternate death fx if we were killed by the player
|
||||
deathFX = spawnArgs.GetString( "fx_death2" );
|
||||
}
|
||||
|
||||
SpawnFxLocal( deathFX, GetOrigin(), GetAxis(), &fx );
|
||||
|
||||
SAFE_REMOVE(fxFly);
|
||||
|
||||
hhMonsterAI::Killed( inflictor, attacker, damage, dir, location );
|
||||
|
||||
StartSound( "snd_death", SND_CHANNEL_VOICE );
|
||||
|
||||
Hide();
|
||||
|
||||
// activate targets
|
||||
//ActivateTargets( this );
|
||||
|
||||
PostEventSec( &EV_Remove, 4 );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::CheckCollisions
|
||||
//
|
||||
// Check if the wraith is entering or exiting the world
|
||||
//=============================================================================
|
||||
void hhWraith::CheckCollisions( void ) {
|
||||
|
||||
if (gameLocal.time < nextCheckTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
hhFxInfo fxInfo;
|
||||
trace_t tr1;
|
||||
trace_t tr2;
|
||||
idVec3 jointPos;
|
||||
idMat3 jointAxis;
|
||||
|
||||
if (!GetJointWorldTransform( spawnArgs.GetString("joint_collision"), jointPos, jointAxis )) {
|
||||
jointPos = GetOrigin();
|
||||
jointAxis = GetAxis();
|
||||
}
|
||||
|
||||
// Trace to determine if the wraith just flew through a wall, or just emerged from a wall
|
||||
// For speed, this only checks against the world
|
||||
idVec3 dir, point;
|
||||
gameLocal.clip.TracePoint( tr1, jointPos, lastCheckOrigin, MASK_SHOT_BOUNDINGBOX, this ); // Check if we entered something solid
|
||||
gameLocal.clip.TracePoint( tr2, lastCheckOrigin, jointPos, MASK_SHOT_BOUNDINGBOX, this ); // Check if we exited something solid
|
||||
|
||||
idVec3 playerOrigin = gameLocal.GetLocalPlayer()->GetOrigin();
|
||||
if ( tr1.fraction < 1.0f ) {
|
||||
point = tr1.c.point;
|
||||
dir = tr1.c.normal;
|
||||
}
|
||||
else if ( tr2.fraction < 1.0f) {
|
||||
point = tr2.c.point;
|
||||
dir = tr2.c.normal;
|
||||
}
|
||||
if ( tr1.fraction < 1.0f && tr2.fraction < 1.0f ) {
|
||||
if ( (tr1.c.point - playerOrigin).LengthSqr() <= (tr2.c.point - playerOrigin).LengthSqr() ) {
|
||||
point = tr1.c.point;
|
||||
dir = tr1.c.normal;
|
||||
}
|
||||
else {
|
||||
point = tr2.c.point;
|
||||
dir = tr2.c.normal;
|
||||
}
|
||||
}
|
||||
|
||||
if ( tr1.fraction < 1.0f || tr2.fraction < 1.0f ) {
|
||||
// Spawn an FX at wall collision
|
||||
//TODO: IMPORTANT: This currently spawns a system every check while passing through something. This creates enormous
|
||||
// amounts of particles. Fix so there is a single system spawned on the way in and a single system spawned on the way out.
|
||||
//TODO: This currently hits players so you get a big blob of particles right in your face and right behind you.
|
||||
const char *hitWallFxName = spawnArgs.GetString("fx_hitwall");
|
||||
if (hitWallFxName && *hitWallFxName) {
|
||||
fxInfo.RemoveWhenDone( true );
|
||||
BroadcastFxInfo(hitWallFxName, point, mat3_identity, &fxInfo);
|
||||
}
|
||||
|
||||
|
||||
// Project a spooge decal on the wall here
|
||||
const char *decalName = spawnArgs.GetString("mtr_decal", NULL);
|
||||
if (decalName && *decalName) {
|
||||
float depth = spawnArgs.GetFloat("decal_trace");
|
||||
float size = spawnArgs.GetFloat( "decal_size" );
|
||||
|
||||
// gameRenderWorld->DebugArrow(colorRed, point, point + dir*128, 5, 10000);
|
||||
|
||||
gameLocal.ProjectDecal(tr1.c.point, -tr1.c.normal, depth, true, size, decalName);
|
||||
gameLocal.ProjectDecal(tr2.c.point, -tr2.c.normal, depth, true, size, decalName);
|
||||
}
|
||||
}
|
||||
|
||||
// Possession check
|
||||
if ( canPossess && gameLocal.time > nextPossessTime ) {
|
||||
gameLocal.clip.TraceBounds( tr1, lastCheckOrigin, jointPos, GetPhysics()->GetBounds(), MASK_SHOT_BOUNDINGBOX, this );
|
||||
if ( gameLocal.entities[ tr1.c.entityNum ] && gameLocal.entities[ tr1.c.entityNum ]->IsType( idActor::Type ) ) {
|
||||
// If we hit a possessable actor, possess them
|
||||
idActor *actor = reinterpret_cast<idActor *> ( gameLocal.entities[ tr1.c.entityNum ] );
|
||||
if ( actor != lastActor.GetEntity() ) {
|
||||
// Play the attack sound
|
||||
StartSound( "snd_attack", SND_CHANNEL_VOICE );
|
||||
if ( actor->IsType( hhPlayer::Type ) ) {
|
||||
hhPlayer *player = reinterpret_cast<hhPlayer *> ( gameLocal.entities[ tr1.c.entityNum ] );
|
||||
int power = player->GetSpiritPower();
|
||||
power -= 25;
|
||||
|
||||
if ( power <= 0 ) { // Possess the player
|
||||
power = 0;
|
||||
// mdl: Wraiths no longer possess
|
||||
//if ( player->CanBePossessed() ) {
|
||||
// Possessable
|
||||
//WraithPossess( player );
|
||||
//} else
|
||||
if ( enemy.GetEntity() == player && player->IsSpiritWalking() && !player->IsPossessed() ) {
|
||||
// Send the player back to his body
|
||||
reinterpret_cast<hhPlayer *> (enemy.GetEntity())->DisableSpiritWalk(5);
|
||||
// Don't immediately possess if the players body happens to be right there.
|
||||
nextPossessTime = gameLocal.time + 1000;
|
||||
}
|
||||
} else { // Gain health from the player's spirit power
|
||||
health += 5;
|
||||
if ( health > spawnHealth ) {
|
||||
health = spawnHealth;
|
||||
}
|
||||
}
|
||||
player->SetSpiritPower( power );
|
||||
|
||||
}// else if ( actor->CanBePossessed() ) {
|
||||
// // Possess the actor
|
||||
// WraithPossess( actor );
|
||||
//}
|
||||
}
|
||||
lastActor = actor;
|
||||
} else {
|
||||
lastActor = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
nextCheckTime = gameLocal.time + spawnArgs.GetInt("trace_check_time", "200");
|
||||
lastCheckOrigin = jointPos;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::Event_Flee
|
||||
//
|
||||
// The wraith is about to flee and has already played the flee intro anim
|
||||
//=============================================================================
|
||||
void hhWraith::Event_Flee( ) {
|
||||
GetAnimator()->ClearAllAnims( gameLocal.time, 0 );
|
||||
GetAnimator()->CycleAnim( ANIMCHANNEL_ALL, fleeAnim, gameLocal.time, 0 );
|
||||
state = WS_FLEE;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::PlayAnimMove
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::PlayAnimMove( int anim, int blendTime ) {
|
||||
GetAnimator()->ClearAllAnims( gameLocal.time, blendTime );
|
||||
GetAnimator()->PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, blendTime );
|
||||
state = WS_STILL;
|
||||
PostEventMS( &EV_PlayAnimMoveEnd, GetAnimator()->GetAnim( possessAnim )->Length() - blendTime );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::PlayAnimMoveEnd
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::PlayAnimMoveEnd() {
|
||||
idVec3 boneOrigin;
|
||||
idMat3 boneAxis;
|
||||
GetJointWorldTransform( "Head", boneOrigin, boneAxis );
|
||||
|
||||
GetPhysics()->SetOrigin( boneOrigin ); // Move the wraith to the end of the animation
|
||||
|
||||
GetAnimator()->ClearAllAnims( gameLocal.time, 0 );
|
||||
GetAnimator()->CycleAnim( ANIMCHANNEL_ALL, flyAnim, gameLocal.time, 0 );
|
||||
state = WS_FLY;
|
||||
|
||||
damageTicks = 0;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::WraithPossess
|
||||
//
|
||||
// Actually possess an actor
|
||||
//=============================================================================
|
||||
void hhWraith::WraithPossess( idActor *actor ) {
|
||||
hhFxInfo fxInfo;
|
||||
|
||||
actor->Possess( this );
|
||||
|
||||
// Spawn in a flash
|
||||
fxInfo.RemoveWhenDone( true );
|
||||
BroadcastFxInfoPrefixed( "fx_possessionFlash", GetOrigin(), GetAxis(), &fxInfo );
|
||||
|
||||
// activate targets
|
||||
ActivateTargets( actor );
|
||||
|
||||
PostEventMS( &EV_Remove, 0 );
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// hhWraith::Event_PlayAnimMoveEnd
|
||||
//
|
||||
//=============================================================================
|
||||
void hhWraith::Event_PlayAnimMoveEnd( ) {
|
||||
PlayAnimMoveEnd();
|
||||
}
|
||||
|
||||
void hhWraith::Event_EnemyIsSpirit( hhPlayer *player, hhSpiritProxy *proxy ) {
|
||||
// Only switch to the proxy if the player has no spirit power
|
||||
//if ( player->GetSpiritPower() == 0 ) {
|
||||
// hhMonsterAI::Event_EnemyIsSpirit( player, proxy );
|
||||
//}
|
||||
}
|
||||
|
||||
void hhWraith::Event_EnemyIsPhysical( hhPlayer *player, hhSpiritProxy *proxy ) {
|
||||
// We don't care whether we can see the enemy or not
|
||||
enemy = player;
|
||||
}
|
||||
|
||||
void hhWraith::TeleportIn( idEntity *activator ) {
|
||||
if ( spawnArgs.GetBool( "quickSpawn" ) ) {
|
||||
PostEventMS( &EV_Show, 0 );
|
||||
PostEventMS( &EV_Activate, 50, activator );
|
||||
}
|
||||
else {
|
||||
hhFxInfo fx;
|
||||
fx.RemoveWhenDone( true );
|
||||
fx.SetEntity( this );
|
||||
SpawnFxLocal( spawnArgs.GetString( "fx_spawn" ), GetOrigin(), GetAxis(), &fx );
|
||||
PostEventMS( &EV_Show, 1000 );
|
||||
PostEventMS( &EV_Activate, 1050, activator );
|
||||
}
|
||||
}
|
||||
|
||||
void hhWraith::Portalled(idEntity *portal) {
|
||||
hhMonsterAI::Portalled( portal );
|
||||
if ( fxFly.IsValid() ) {
|
||||
hhFxInfo fxInfo;
|
||||
fxInfo.SetNormal( -GetAxis()[0] );
|
||||
fxInfo.SetEntity( this );
|
||||
fxInfo.RemoveWhenDone( false );
|
||||
|
||||
fxFly->SetFxInfo( fxInfo );
|
||||
|
||||
// Reset the fx system
|
||||
fxFly->Stop();
|
||||
fxFly->Start( gameLocal.time );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user