mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
1669 lines
60 KiB
C++
1669 lines
60 KiB
C++
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "prey_local.h"
|
|
|
|
const idEventDef CX_LaserOn("sunBeamOn", NULL, 'd');
|
|
const idEventDef CX_LaserOff("sunBeamOff");
|
|
const idEventDef MA_UpdateLasers("<updateLasers>");
|
|
const idEventDef MA_AssignLeftMuzzleFx( "<assignLeftMuzzleFx>", "e" );
|
|
const idEventDef MA_AssignRightMuzzleFx( "<assignRightMuzzleFx>", "e" );
|
|
const idEventDef MA_AssignLeftImpactFx( "<assignLeftImpactFx>", "e" );
|
|
const idEventDef MA_AssignRightImpactFx( "<assignRightImpactFx>", "e" );
|
|
const idEventDef MA_AssignLeftRechargeFx( "<assignLeftRechargeFx>", "e" );
|
|
const idEventDef MA_AssignRightRechargeFx( "<assignRightRechargeFx>", "e" );
|
|
const idEventDef MA_SetGunOffset( "setGunOffset", "v" );
|
|
const idEventDef MA_EndLeftBeams( "<endLeftBeams>" );
|
|
const idEventDef MA_EndRightBeams( "<endRightBeams>" );
|
|
const idEventDef MA_HudEvent( "hudEvent", "s" );
|
|
const idEventDef MA_GunRecharge( "gunRecharge", "d" );
|
|
const idEventDef MA_EndRecharge( "endRecharge" );
|
|
const idEventDef MA_ResetRechargeBeam( "<resetRechargeBeam>" );
|
|
const idEventDef MA_SparkLeft( "<sparkLeft>" );
|
|
const idEventDef MA_SparkRight( "<sparkRight>" );
|
|
const idEventDef MA_LeftGunDeath( "<leftGunDeath>" );
|
|
const idEventDef MA_RightGunDeath( "<rightGunDeath>" );
|
|
const idEventDef MA_StartRechargeBeams( "<startRechargeBeams>" );
|
|
|
|
CLASS_DECLARATION(hhMonsterAI, hhCreatureX)
|
|
EVENT(CX_LaserOn, hhCreatureX::Event_LaserOn )
|
|
EVENT(CX_LaserOff, hhCreatureX::Event_LaserOff )
|
|
EVENT(MA_UpdateLasers, hhCreatureX::Event_UpdateLasers )
|
|
EVENT(MA_AssignRightMuzzleFx, hhCreatureX::Event_AssignRightMuzzleFx )
|
|
EVENT(MA_AssignLeftMuzzleFx, hhCreatureX::Event_AssignLeftMuzzleFx )
|
|
EVENT(MA_AssignRightImpactFx, hhCreatureX::Event_AssignRightImpactFx )
|
|
EVENT(MA_AssignLeftImpactFx, hhCreatureX::Event_AssignLeftImpactFx )
|
|
EVENT(MA_SetGunOffset, hhCreatureX::Event_SetGunOffset )
|
|
EVENT(MA_EndLeftBeams, hhCreatureX::Event_EndLeftBeams )
|
|
EVENT(MA_EndRightBeams, hhCreatureX::Event_EndRightBeams )
|
|
EVENT(MA_HudEvent, hhCreatureX::Event_HudEvent )
|
|
EVENT(MA_GunRecharge, hhCreatureX::Event_GunRecharge )
|
|
EVENT(MA_EndRecharge, hhCreatureX::Event_EndRecharge )
|
|
EVENT(MA_ResetRechargeBeam, hhCreatureX::Event_ResetRechargeBeam )
|
|
EVENT(MA_SparkLeft, hhCreatureX::Event_SparkLeft )
|
|
EVENT(MA_SparkRight, hhCreatureX::Event_SparkRight )
|
|
EVENT(MA_LeftGunDeath, hhCreatureX::Event_LeftGunDeath )
|
|
EVENT(MA_RightGunDeath, hhCreatureX::Event_RightGunDeath )
|
|
EVENT(MA_StartRechargeBeams, hhCreatureX::Event_StartRechargeBeams )
|
|
END_CLASS
|
|
|
|
#ifndef ID_DEMO_BUILD //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
|
|
void hhCreatureX::Spawn() {
|
|
idVec3 boneOrigin;
|
|
idMat3 boneAxis;
|
|
targetStart_L = vec3_zero;
|
|
targetStart_R = vec3_zero;
|
|
targetEnd_L = vec3_zero;
|
|
targetEnd_R = vec3_zero;
|
|
targetCurrent_L = vec3_zero;
|
|
targetCurrent_R = vec3_zero;
|
|
bLaserLeftActive = false;
|
|
bLaserRightActive = false;
|
|
nextBeamTime = 0;
|
|
nextLeftZapTime = 0;
|
|
nextRightZapTime = 0;
|
|
nextLaserLeft = 0;
|
|
nextLaserRight = 0;
|
|
nextHealthTick = 0;
|
|
rightGunLives = spawnArgs.GetInt( "gun_lives", "3" );
|
|
leftGunLives = spawnArgs.GetInt( "gun_lives", "3" );
|
|
rightGunHealth = spawnArgs.GetInt( "gun_health", "20" );
|
|
leftGunHealth = spawnArgs.GetInt( "gun_health", "20" );
|
|
bScripted = spawnArgs.GetBool( "scripted", "0" );
|
|
numBurstBeams = 0;
|
|
|
|
if ( bScripted ) {
|
|
//don't spawn any combat related entities if scripted
|
|
return;
|
|
}
|
|
|
|
laserRight = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamLaser" ) );
|
|
if( laserRight.IsValid() ) {
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_right"), boneOrigin, boneAxis );
|
|
|
|
idVec3 junkOrigin = boneOrigin + viewAxis[0] * 60; //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.x)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.y)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.z)); //Test for bad origin
|
|
|
|
laserRight->SetOrigin( boneOrigin + viewAxis[0] * 60 );
|
|
laserRight->Activate( false );
|
|
}
|
|
laserLeft = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamLaser" ) );
|
|
if( laserLeft.IsValid() ) {
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_left"), boneOrigin, boneAxis );
|
|
|
|
idVec3 junkOrigin = boneOrigin + viewAxis[0] * 60; //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.x)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.y)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.z)); //Test for bad origin
|
|
|
|
laserLeft->SetOrigin( boneOrigin + viewAxis[0] * 60 );
|
|
laserLeft->Activate( false );
|
|
}
|
|
preLaserRight = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamLaser" ) );
|
|
if( preLaserRight.IsValid() ) {
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_right"), boneOrigin, boneAxis );
|
|
|
|
idVec3 junkOrigin = boneOrigin; //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.x)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.y)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.z)); //Test for bad origin
|
|
|
|
preLaserRight->SetOrigin( boneOrigin );
|
|
preLaserRight->BindToJoint( this, spawnArgs.GetString("laser_bone_right"), false );
|
|
preLaserRight->Activate( false );
|
|
}
|
|
preLaserLeft = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamLaser" ) );
|
|
if( preLaserLeft.IsValid() ) {
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_left"), boneOrigin, boneAxis );
|
|
|
|
idVec3 junkOrigin = boneOrigin; //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.x)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.y)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(junkOrigin.z)); //Test for bad origin
|
|
|
|
preLaserLeft->SetOrigin( boneOrigin );
|
|
preLaserLeft->BindToJoint( this, spawnArgs.GetString("laser_bone_left"), false );
|
|
preLaserLeft->Activate( false );
|
|
}
|
|
PostEventSec( &MA_UpdateLasers, spawnArgs.GetFloat( "laser_freq", "0.1" ) );
|
|
|
|
leftBeamList.Clear();
|
|
rightBeamList.Clear();
|
|
leftRechargeBeam.Clear();
|
|
rightRechargeBeam.Clear();
|
|
leftRecharger.Clear();
|
|
rightRecharger.Clear();
|
|
if ( spawnArgs.GetBool( "use_recharge" ) ) {
|
|
numBurstBeams = spawnArgs.GetInt( "num_burst_beams", "4" );
|
|
for ( int i = 0; i < numBurstBeams; i ++ ) {
|
|
leftBeamList.Append( hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamBurst" ) ) );
|
|
if( leftBeamList[i].IsValid() ) {
|
|
leftBeamList[i]->Activate( false );
|
|
GetJointWorldTransform( spawnArgs.GetString("damage_bone_left"), boneOrigin, boneAxis );
|
|
leftBeamList[i]->SetOrigin( boneOrigin );
|
|
leftBeamList[i]->BindToJoint( this, spawnArgs.GetString("damage_bone_left"), false );
|
|
}
|
|
rightBeamList.Append( hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamBurst" ) ) );
|
|
if( rightBeamList[i].IsValid() ) {
|
|
rightBeamList[i]->Activate( false );
|
|
GetJointWorldTransform( spawnArgs.GetString("damage_bone_right"), boneOrigin, boneAxis );
|
|
rightBeamList[i]->SetOrigin( boneOrigin );
|
|
rightBeamList[i]->BindToJoint( this, spawnArgs.GetString("damage_bone_right"), false );
|
|
}
|
|
}
|
|
|
|
leftRechargeBeam = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamRecharge" ) );
|
|
if( leftRechargeBeam.IsValid() ) {
|
|
leftRechargeBeam->Activate( false );
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_left"), boneOrigin, boneAxis );
|
|
leftRechargeBeam->SetOrigin( boneOrigin );
|
|
leftRechargeBeam->BindToJoint( this, spawnArgs.GetString("laser_bone_left"), false );
|
|
leftRechargeBeam->Hide();
|
|
}
|
|
rightRechargeBeam = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamRecharge" ) );
|
|
if( rightRechargeBeam.IsValid() ) {
|
|
rightRechargeBeam->Activate( false );
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_right"), boneOrigin, boneAxis );
|
|
rightRechargeBeam->SetOrigin( boneOrigin );
|
|
rightRechargeBeam->BindToJoint( this, spawnArgs.GetString("laser_bone_right"), false );
|
|
rightRechargeBeam->Hide();
|
|
}
|
|
leftDamageBeam = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamDamage" ) );
|
|
if( leftDamageBeam.IsValid() ) {
|
|
leftDamageBeam->Activate( false );
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_left"), boneOrigin, boneAxis );
|
|
leftDamageBeam->SetOrigin( boneOrigin );
|
|
leftDamageBeam->BindToJoint( this, spawnArgs.GetString("laser_bone_left"), false );
|
|
leftDamageBeam->Hide();
|
|
}
|
|
rightDamageBeam = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamDamage" ) );
|
|
if( rightDamageBeam.IsValid() ) {
|
|
rightDamageBeam->Activate( false );
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_right"), boneOrigin, boneAxis );
|
|
rightDamageBeam->SetOrigin( boneOrigin );
|
|
rightDamageBeam->BindToJoint( this, spawnArgs.GetString("laser_bone_right"), false );
|
|
rightDamageBeam->Hide();
|
|
}
|
|
leftRetractBeam = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamRetract" ) );
|
|
if( leftRetractBeam.IsValid() ) {
|
|
leftRetractBeam->Activate( false );
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_left"), boneOrigin, boneAxis );
|
|
leftRetractBeam->SetOrigin( boneOrigin );
|
|
leftRetractBeam->BindToJoint( this, spawnArgs.GetString("laser_bone_left"), false );
|
|
leftRetractBeam->Hide();
|
|
}
|
|
rightRetractBeam = hhBeamSystem::SpawnBeam( vec3_origin, spawnArgs.GetString( "def_beamRetract" ) );
|
|
if( rightRetractBeam.IsValid() ) {
|
|
rightRetractBeam->Activate( false );
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_right"), boneOrigin, boneAxis );
|
|
rightRetractBeam->SetOrigin( boneOrigin );
|
|
rightRetractBeam->BindToJoint( this, spawnArgs.GetString("laser_bone_right"), false );
|
|
rightRetractBeam->Hide();
|
|
}
|
|
|
|
idEntity *ent;
|
|
idDict dict;
|
|
const idDict *rechargeDict = gameLocal.FindEntityDefDict(spawnArgs.GetString("def_recharger"));
|
|
if ( !rechargeDict ) {
|
|
gameLocal.Error( "Unknown def_recharger: %s\n", spawnArgs.GetString("def_recharger") );
|
|
}
|
|
dict.Copy(*rechargeDict);
|
|
gameLocal.SpawnEntityDef( dict, &ent );
|
|
if ( ent ) {
|
|
leftRecharger.Assign( ent );
|
|
leftRecharger->GetPhysics()->DisableClip();
|
|
leftRecharger->GetPhysics()->SetClipMask( 0 );
|
|
leftRecharger->HideNoDormant();
|
|
leftRecharger->SetOrigin( GetOrigin() );
|
|
leftRecharger->SetEnemy( this );
|
|
leftRecharger->spawnArgs.Set( "left_recharger", "1" ); //set key for left or right
|
|
}
|
|
ent = NULL;
|
|
gameLocal.SpawnEntityDef( dict, &ent );
|
|
if ( ent ) {
|
|
rightRecharger.Assign( ent );
|
|
rightRecharger->GetPhysics()->DisableClip();
|
|
rightRecharger->GetPhysics()->SetClipMask( 0 );
|
|
rightRecharger->HideNoDormant();
|
|
rightRecharger->SetOrigin( GetOrigin() );
|
|
rightRecharger->SetEnemy( this );
|
|
rightRecharger->spawnArgs.Set( "right_recharger", "1" ); //set key for left or right
|
|
}
|
|
}
|
|
}
|
|
|
|
hhCreatureX::~hhCreatureX() {
|
|
MuzzleLeftOff();
|
|
MuzzleRightOff();
|
|
|
|
SAFE_REMOVE( laserRight );
|
|
SAFE_REMOVE( laserLeft );
|
|
SAFE_REMOVE( preLaserLeft );
|
|
SAFE_REMOVE( preLaserRight );
|
|
}
|
|
|
|
void hhCreatureX::Event_LaserOn() {
|
|
if ( !enemy.IsValid() ) {
|
|
idThread::ReturnInt( false );
|
|
return;
|
|
}
|
|
if ( !AI_RIGHT_DAMAGED ) {
|
|
bLaserRightActive = true;
|
|
}
|
|
if ( !AI_LEFT_DAMAGED ) {
|
|
bLaserLeftActive = true;
|
|
}
|
|
idVec3 toEnemy = GetEnemy()->GetOrigin() - GetOrigin();
|
|
targetStart_L = GetOrigin() + spawnArgs.GetFloat( "test_1", "0.5" ) * toEnemy;
|
|
targetStart_L.z = GetOrigin().z;
|
|
float distToStart = (targetStart_L - GetOrigin()).LengthFast();
|
|
if ( distToStart < 200 ) {
|
|
targetStart_L = GetOrigin() + toEnemy;
|
|
targetStart_L.z = GetOrigin().z;
|
|
}
|
|
targetStart_R = GetOrigin() + spawnArgs.GetFloat( "test_1", "0.5" ) * toEnemy;
|
|
targetStart_R.z = GetOrigin().z;
|
|
distToStart = (targetStart_R - GetOrigin()).LengthFast();
|
|
if ( distToStart < 200 ) {
|
|
targetStart_R = GetOrigin() + toEnemy;
|
|
targetStart_R.z = GetOrigin().z;
|
|
}
|
|
targetEnd_L = GetOrigin() + spawnArgs.GetFloat( "test_2", "1.4" ) * toEnemy;
|
|
targetEnd_L.z = GetOrigin().z + spawnArgs.GetFloat( "test_4", "50" );
|
|
targetEnd_R = GetOrigin() + spawnArgs.GetFloat( "test_2", "1.4" ) * toEnemy;
|
|
targetEnd_R.z = GetOrigin().z + spawnArgs.GetFloat( "test_4", "50" );
|
|
if ( ai_debugBrain.GetBool() ) {
|
|
gameRenderWorld->DebugArrow( colorRed, targetStart_L, targetEnd_L, 10, 10000 );
|
|
}
|
|
targetAlpha_L = 0.0f;
|
|
targetAlpha_R = 0.0f;
|
|
if ( !bLaserLeftActive && !bLaserRightActive ) {
|
|
idThread::ReturnInt( false );
|
|
}
|
|
idThread::ReturnInt( true );
|
|
}
|
|
|
|
void hhCreatureX::Event_LaserOff() {
|
|
bLaserLeftActive = false;
|
|
bLaserRightActive = false;
|
|
targetStart_L = vec3_zero;
|
|
targetStart_R = vec3_zero;
|
|
targetEnd_L = vec3_zero;
|
|
targetEnd_R = vec3_zero;
|
|
MuzzleLeftOff();
|
|
MuzzleRightOff();
|
|
}
|
|
|
|
void hhCreatureX::Event_UpdateLasers() {
|
|
if ( !enemy.IsValid() ) {
|
|
PostEventSec( &MA_UpdateLasers, spawnArgs.GetFloat( "laser_freq", "0.1" ) );
|
|
return;
|
|
}
|
|
trace_t trace;
|
|
float dist = 0;
|
|
idVec3 boneOrigin, traceEnd;
|
|
idMat3 boneAxis;
|
|
idEntity *hitEntity = NULL;
|
|
int hitCount = 0;
|
|
if ( laserRight.IsValid() && bLaserRightActive ) {
|
|
MuzzleRightOn();
|
|
traceEnd = targetCurrent_R + 2000 * (targetCurrent_R - laserRight->GetOrigin()).ToNormal();
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_right"), boneOrigin, boneAxis );
|
|
gameLocal.clip.TracePoint( trace, laserRight->GetOrigin(), traceEnd, MASK_SHOT_RENDERMODEL, this );
|
|
if ( ai_debugBrain.GetBool() ) {
|
|
gameRenderWorld->DebugArrow( colorRed, laserRight->GetOrigin(), traceEnd, 10, 200 );
|
|
}
|
|
if ( trace.fraction < 1.0f ) {
|
|
dist = (trace.endpos - laserRight->GetOrigin()).Length();
|
|
hitEntity = gameLocal.GetTraceEntity( trace );
|
|
if ( hitEntity ) {
|
|
hitEntity->Damage( this, this, hitEntity->GetOrigin() - GetOrigin().ToNormal(), spawnArgs.GetString( "def_laserDamage" ), 1.0, 0 );
|
|
}
|
|
}
|
|
} else {
|
|
MuzzleRightOff();
|
|
}
|
|
if ( laserLeft.IsValid() && bLaserLeftActive ) {
|
|
MuzzleLeftOn();
|
|
traceEnd = targetCurrent_L + 2000 * (targetCurrent_L - laserLeft->GetOrigin()).ToNormal();
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_left"), boneOrigin, boneAxis );
|
|
gameLocal.clip.TracePoint( trace, laserLeft->GetOrigin(), traceEnd, MASK_SHOT_RENDERMODEL, this );
|
|
if ( ai_debugBrain.GetBool() ) {
|
|
gameRenderWorld->DebugArrow( colorRed, laserLeft->GetOrigin(), traceEnd, 10, 200 );
|
|
}
|
|
if ( trace.fraction < 1.0f ) {
|
|
dist = (trace.endpos - laserLeft->GetOrigin()).Length();
|
|
hitEntity = gameLocal.GetTraceEntity( trace );
|
|
if ( hitEntity ) {
|
|
hitEntity->Damage( this, this, hitEntity->GetOrigin() - GetOrigin().ToNormal(), spawnArgs.GetString( "def_laserDamage" ), 1.0, 0 );
|
|
}
|
|
}
|
|
} else {
|
|
MuzzleLeftOff();
|
|
}
|
|
PostEventSec( &MA_UpdateLasers, spawnArgs.GetFloat( "laser_freq", "0.1" ) );
|
|
}
|
|
|
|
void hhCreatureX::Event_ResetRechargeBeam() {
|
|
if ( !AI_RECHARGING ) {
|
|
return;
|
|
}
|
|
if ( leftRecharger.IsValid() ) {
|
|
leftRecharger->SetShaderParm( 6, 0.0f );
|
|
}
|
|
if ( rightRecharger.IsValid() ) {
|
|
rightRecharger->SetShaderParm( 6, 0.0f );
|
|
}
|
|
if ( rechargeLeftFx.IsValid() ) {
|
|
rechargeLeftFx->SetParticleShaderParm( 6, 0.0f );
|
|
}
|
|
if ( rechargeRightFx.IsValid() ) {
|
|
rechargeRightFx->SetParticleShaderParm( 6, 0.0f );
|
|
}
|
|
if ( leftRechargeBeam.IsValid() ) {
|
|
leftRechargeBeam->Activate( true );
|
|
leftRechargeBeam->Show();
|
|
}
|
|
if ( rightRechargeBeam.IsValid() ) {
|
|
rightRechargeBeam->Activate( true );
|
|
rightRechargeBeam->Show();
|
|
}
|
|
if ( leftDamageBeam.IsValid() ) {
|
|
leftDamageBeam->Activate( false );
|
|
}
|
|
if ( rightDamageBeam.IsValid() ) {
|
|
rightDamageBeam->Activate( false );
|
|
}
|
|
if ( leftRetractBeam.IsValid() ) {
|
|
leftRetractBeam->Activate( false );
|
|
}
|
|
if ( rightRetractBeam.IsValid() ) {
|
|
rightRetractBeam->Activate( false );
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::Think() {
|
|
PROFILE_SCOPE("AI", PROFMASK_NORMAL|PROFMASK_AI);
|
|
if (ai_skipThink.GetBool()) {
|
|
return;
|
|
}
|
|
|
|
idVec3 pastEnemy;
|
|
hhMonsterAI::Think();
|
|
if ( AI_RECHARGING ) {
|
|
bool damaged = false;
|
|
if ( leftRecharger.IsValid() ) {
|
|
//recharger damage. switch out beams
|
|
if ( leftRechargeBeam.IsValid() && leftRecharger->GetHealth() < leftRechargerHealth ) {
|
|
if ( leftRechargerHealth > 0 && !leftRecharger->IsDead() ) {
|
|
damaged = true;
|
|
}
|
|
leftRechargeBeam->Activate( false );
|
|
leftDamageBeam->Show();
|
|
leftDamageBeam->Activate( true );
|
|
leftRecharger->SetShaderParm( 6, 1.0f );
|
|
if ( rechargeLeftFx.IsValid() ) {
|
|
rechargeLeftFx->SetParticleShaderParm( 6, 1.0f );
|
|
}
|
|
}
|
|
leftRechargerHealth = leftRecharger->GetHealth();
|
|
}
|
|
if ( rightRecharger.IsValid() ) {
|
|
//recharger damage. switch out beams
|
|
if ( rightRechargeBeam.IsValid() && rightRecharger->GetHealth() < rightRechargerHealth ) {
|
|
if ( rightRechargerHealth > 0 && !rightRecharger->IsDead() ) {
|
|
damaged = true;
|
|
}
|
|
rightRechargeBeam->Activate( false );
|
|
rightDamageBeam->Show();
|
|
rightDamageBeam->Activate( true );
|
|
rightRecharger->SetShaderParm( 6, 1.0f );
|
|
if ( rechargeRightFx.IsValid() ) {
|
|
rechargeRightFx->SetParticleShaderParm( 6, 1.0f );
|
|
}
|
|
}
|
|
rightRechargerHealth = rightRecharger->GetHealth();
|
|
}
|
|
if ( damaged ) {
|
|
PostEventSec( &MA_ResetRechargeBeam, spawnArgs.GetFloat( "damage_beam_duration", "0.8" ) );
|
|
}
|
|
if ( !AI_LEFT_DAMAGED && leftRecharger.IsValid() && leftRecharger->GetHealth() <= 0 ) {
|
|
//recharger has died so start retracting the beams and schedule the gun's death
|
|
StartSound( "snd_gun_predeath", SND_CHANNEL_ANY );
|
|
SAFE_REMOVE( leftRechargeBeam );
|
|
PostEventSec( &MA_LeftGunDeath, spawnArgs.GetFloat("retract_delay", "0.9") );
|
|
const char *defName = spawnArgs.GetString( "fx_retract" );
|
|
if ( defName && defName[0] && leftDamageBeam.IsValid() ) {
|
|
hhFxInfo fxInfo;
|
|
fxInfo.RemoveWhenDone( true );
|
|
retractLeftFx = SpawnFxLocal( defName, leftDamageBeam->GetTargetLocation(), mat3_identity, &fxInfo, gameLocal.isClient );
|
|
}
|
|
if ( leftRetractBeam.IsValid() ) {
|
|
leftRetractBeam->Show();
|
|
leftRetractBeam->Activate( true );
|
|
}
|
|
if ( leftDamageBeam.IsValid() ) {
|
|
leftDamageBeam->Activate( false );
|
|
leftDamageBeam->Hide();
|
|
}
|
|
AI_LEFT_DAMAGED = true;
|
|
}
|
|
if ( !AI_RIGHT_DAMAGED && rightRecharger.IsValid() && rightRecharger->GetHealth() <= 0 ) {
|
|
//recharger has died so start retracting the beams and schedule the gun's death
|
|
StartSound( "snd_gun_predeath", SND_CHANNEL_ANY );
|
|
SAFE_REMOVE( rightRechargeBeam );
|
|
PostEventSec( &MA_RightGunDeath, spawnArgs.GetFloat("retract_delay", "1") );
|
|
const char *defName = spawnArgs.GetString( "fx_retract" );
|
|
if ( defName && defName[0] && leftDamageBeam.IsValid() ) {
|
|
hhFxInfo fxInfo;
|
|
fxInfo.RemoveWhenDone( true );
|
|
retractRightFx = SpawnFxLocal( defName, rightDamageBeam->GetTargetLocation(), mat3_identity, &fxInfo, gameLocal.isClient );
|
|
}
|
|
if ( rightRetractBeam.IsValid() ) {
|
|
rightRetractBeam->Show();
|
|
rightRetractBeam->Activate( true );
|
|
}
|
|
if ( rightDamageBeam.IsValid() ) {
|
|
rightDamageBeam->Activate( false );
|
|
rightDamageBeam->Hide();
|
|
}
|
|
AI_RIGHT_DAMAGED = true;
|
|
}
|
|
if ( AI_HEALTH_TICK && gameLocal.time >= nextHealthTick ) {
|
|
health += spawnArgs.GetInt( "recharge_delta", "1" );
|
|
nextHealthTick += spawnArgs.GetInt( "recharge_period" );
|
|
if ( health > spawnArgs.GetInt( "health" ) ) {
|
|
AI_HEALTH_TICK = false;
|
|
health = spawnArgs.GetInt( "health" );
|
|
}
|
|
}
|
|
} else {
|
|
if ( leftRechargeBeam.IsValid() ) {
|
|
leftRechargeBeam->Activate( false );
|
|
}
|
|
if ( rightRechargeBeam.IsValid() ) {
|
|
rightRechargeBeam->Activate( false );
|
|
}
|
|
}
|
|
|
|
if ( AI_LEFT_DAMAGED && gameLocal.time > nextLeftZapTime ) {
|
|
nextLeftZapTime = gameLocal.time + SEC2MS(spawnArgs.GetFloat( "zap_period", "0.3" ));
|
|
for ( int i = 0; i < numBurstBeams; i ++ ) {
|
|
if ( leftBeamList[i].IsValid() && !leftBeamList[i]->IsActivated() ) {
|
|
leftBeamList[i]->Activate( true );
|
|
leftBeamList[i]->SetTargetLocation( leftBeamList[i]->GetOrigin() + spawnArgs.GetFloat( "zap_length", "50" ) * hhUtils::RandomSpreadDir( hhUtils::RandomVector().ToMat3(), 16.0f ) );
|
|
PostEventSec(&MA_EndLeftBeams, spawnArgs.GetFloat( "beam_duration_1", "0.2" ) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ( AI_RIGHT_DAMAGED && gameLocal.time > nextRightZapTime ) {
|
|
nextRightZapTime = gameLocal.time + SEC2MS(spawnArgs.GetFloat( "zap_period", "0.3" ));
|
|
for ( int i = 0; i < numBurstBeams; i ++ ) {
|
|
if ( rightBeamList[i].IsValid() && !rightBeamList[i]->IsActivated() ) {
|
|
rightBeamList[i]->Activate( true );
|
|
rightBeamList[i]->SetTargetLocation( rightBeamList[i]->GetOrigin() + spawnArgs.GetFloat( "zap_length", "50" ) * hhUtils::RandomSpreadDir( hhUtils::RandomVector().ToMat3(), 16.0f ) );
|
|
PostEventSec(&MA_EndRightBeams, spawnArgs.GetFloat( "beam_duration_1", "0.2" ) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( enemy.IsValid() ) {
|
|
//left laser
|
|
//HUMANHEAD jsh PCF 5/12/06 30hz issue with beam movement
|
|
targetAlpha_L += spawnArgs.GetFloat( "laser_move_delta", "0.1" ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
|
if ( targetAlpha_L > 1.0f ) {
|
|
targetAlpha_L = 1.0f;
|
|
}
|
|
targetCurrent_L = targetStart_L + targetAlpha_L * ( targetEnd_L - targetStart_L );
|
|
pastEnemy = GetEnemy()->GetOrigin() + idVec3( 0,0,30 );
|
|
//HUMANHEAD jsh PCF 5/12/06 30hz issue with beam movement
|
|
targetEnd_L += spawnArgs.GetFloat( "laser_track_delta", "0.1" ) * ( pastEnemy - targetEnd_L ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
|
|
|
//right laser
|
|
//HUMANHEAD jsh PCF 5/12/06 30hz issue with beam movement
|
|
targetAlpha_R += spawnArgs.GetFloat( "laser_move_delta", "0.1" ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
|
if ( targetAlpha_R > 1.0f ) {
|
|
targetAlpha_R = 1.0f;
|
|
}
|
|
targetCurrent_R = targetStart_R + targetAlpha_R * ( targetEnd_R - targetStart_R );
|
|
pastEnemy = GetEnemy()->GetOrigin() + idVec3( 0,0,30 );
|
|
//HUMANHEAD jsh PCF 5/12/06 30hz issue with beam movement
|
|
targetEnd_R += spawnArgs.GetFloat( "laser_track_delta", "0.1" ) * ( pastEnemy - targetEnd_R ) * (60.0f * USERCMD_ONE_OVER_HZ);
|
|
}
|
|
|
|
if ( gameLocal.time > nextBeamTime ) {
|
|
nextBeamTime = gameLocal.time + SEC2MS(spawnArgs.GetFloat( "beam_period", "0.3" ));
|
|
for ( int i = 0; i < leftBeamList.Num(); i ++ ) {
|
|
if ( leftBeamList[i].IsValid() && leftBeamList[i]->IsActivated() ) {
|
|
leftBeamList[i]->SetTargetLocation( leftBeamList[i]->GetOrigin() + spawnArgs.GetFloat( "beam_length", "100" ) * hhUtils::RandomSpreadDir( hhUtils::RandomVector().ToMat3(), 16.0f ) );
|
|
}
|
|
}
|
|
for ( int i = 0; i < rightBeamList.Num(); i ++ ) {
|
|
if ( rightBeamList[i].IsValid() && rightBeamList[i]->IsActivated() ) {
|
|
rightBeamList[i]->SetTargetLocation( rightBeamList[i]->GetOrigin() + spawnArgs.GetFloat( "beam_length", "100" ) * hhUtils::RandomSpreadDir( hhUtils::RandomVector().ToMat3(), 16.0f ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
idVec3 boneOrigin, traceEnd;
|
|
idMat3 boneAxis;
|
|
trace_t trace;
|
|
memset(&trace, 0, sizeof(trace));
|
|
if ( !enemy.IsValid() ) {
|
|
return;
|
|
}
|
|
|
|
if ( laserRight.IsValid() && bLaserRightActive ) {
|
|
traceEnd = targetCurrent_R + 2000 * (targetCurrent_R - laserRight->GetOrigin()).ToNormal();
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_right"), boneOrigin, boneAxis );
|
|
gameLocal.clip.TracePoint( trace, laserRight->GetOrigin(), traceEnd, MASK_SHOT_RENDERMODEL, this );
|
|
if ( trace.fraction < 1.0f ) {
|
|
if ( preLaserRight.IsValid() ) {
|
|
if ( preLaserRight->IsHidden() ) {
|
|
preLaserRight->Show();
|
|
}
|
|
preLaserRight->Activate( true );
|
|
preLaserRight->SetTargetEntity( laserRight.GetEntity() );
|
|
}
|
|
if ( laserRight->IsHidden() ) {
|
|
laserRight->Show();
|
|
}
|
|
laserRight->SetOrigin( boneOrigin + viewAxis[0] * 60 );
|
|
laserRight->Activate( true );
|
|
laserRight->SetTargetLocation( trace.endpos - viewAxis[1] * 10 );
|
|
}
|
|
float dist = (laserRight->GetTargetLocation() - laserRight->GetOrigin()).Length();
|
|
if ( dist > 100.0f && impactRightFx.IsValid() ) {
|
|
impactRightFx->SetOrigin( laserRight->GetTargetLocation() );
|
|
}
|
|
laserEndRight = trace.endpos;
|
|
} else {
|
|
if ( preLaserRight.IsValid() ) {
|
|
preLaserRight->Activate( false );
|
|
}
|
|
if ( laserRight.IsValid() ) {
|
|
laserRight->Activate( false );
|
|
}
|
|
}
|
|
|
|
if ( laserLeft.IsValid() && bLaserLeftActive ) {
|
|
traceEnd = targetCurrent_L + 2000 * (targetCurrent_L - laserLeft->GetOrigin()).ToNormal();
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_left"), boneOrigin, boneAxis );
|
|
gameLocal.clip.TracePoint( trace, laserLeft->GetOrigin(), traceEnd, MASK_SHOT_RENDERMODEL, this );
|
|
if ( trace.fraction < 1.0f ) {
|
|
if ( preLaserLeft.IsValid() ) {
|
|
if ( preLaserLeft->IsHidden() ) {
|
|
preLaserLeft->Show();
|
|
}
|
|
preLaserLeft->Activate( true );
|
|
preLaserLeft->SetTargetEntity( laserLeft.GetEntity() );
|
|
}
|
|
if ( laserLeft->IsHidden() ) {
|
|
laserLeft->Show();
|
|
}
|
|
laserLeft->SetOrigin( boneOrigin + viewAxis[0] * 60 );
|
|
laserLeft->Activate( true );
|
|
laserLeft->SetTargetLocation( trace.endpos + viewAxis[1] * 10 );
|
|
}
|
|
float dist = (laserLeft->GetTargetLocation() - laserLeft->GetOrigin()).Length();
|
|
if ( dist > 100.0f && impactLeftFx.IsValid() ) {
|
|
impactLeftFx->SetOrigin( laserLeft->GetTargetLocation() );
|
|
}
|
|
laserEndLeft = trace.endpos;
|
|
} else {
|
|
if ( preLaserLeft.IsValid() ) {
|
|
preLaserLeft->Activate( false );
|
|
}
|
|
if ( laserLeft.IsValid() ) {
|
|
laserLeft->Activate( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
#define LinkScriptVariable( name ) name.LinkTo( scriptObject, #name )
|
|
void hhCreatureX::LinkScriptVariables() {
|
|
hhMonsterAI::LinkScriptVariables();
|
|
LinkScriptVariable( AI_GUN_TRACKING );
|
|
LinkScriptVariable( AI_RECHARGING );
|
|
LinkScriptVariable( AI_LEFT_FIRE );
|
|
LinkScriptVariable( AI_RIGHT_FIRE );
|
|
LinkScriptVariable( AI_LEFT_DAMAGED );
|
|
LinkScriptVariable( AI_RIGHT_DAMAGED );
|
|
LinkScriptVariable( AI_FIRING_LASER );
|
|
LinkScriptVariable( AI_HEALTH_TICK );
|
|
LinkScriptVariable( AI_GUN_EXPLODE );
|
|
}
|
|
|
|
void hhCreatureX::Event_RightGunDeath() {
|
|
bool explodeGun = false;
|
|
if ( rightRetractBeam.IsValid() ) {
|
|
rightRetractBeam->Show();
|
|
rightRetractBeam->Activate( true );
|
|
|
|
//retract the damage beam a little bit
|
|
idVec3 bonePos;
|
|
idMat3 boneAxis;
|
|
GetJointWorldTransform( spawnArgs.GetString( "gun_bone_right" ), bonePos, boneAxis );
|
|
idVec3 lastTargetLocation = rightRetractBeam->GetTargetLocation();
|
|
rightRetractBeam->SetTargetEntity( NULL );
|
|
if ( ai_debugBrain.GetBool() ) {
|
|
gameRenderWorld->DebugArrow( colorRed, lastTargetLocation, bonePos, 10, 1 );
|
|
}
|
|
rightRetractBeam->SetTargetLocation( lastTargetLocation + spawnArgs.GetFloat("retract_speed", "50") * (bonePos - lastTargetLocation).ToNormal() );
|
|
if ( retractRightFx.IsValid() ) {
|
|
retractRightFx->SetOrigin( rightRetractBeam->GetTargetLocation() );
|
|
}
|
|
if ( (lastTargetLocation - bonePos).LengthFast() < 30.0f ) {
|
|
explodeGun = true;
|
|
rightRetractBeam->Activate( false );
|
|
} else {
|
|
PostEventSec( &MA_RightGunDeath, 0.01f );
|
|
}
|
|
}
|
|
|
|
if ( explodeGun || !rightRetractBeam.IsValid() ) {
|
|
CancelEvents( &MA_ResetRechargeBeam );
|
|
SAFE_REMOVE( rightRechargeBeam );
|
|
SAFE_REMOVE( retractRightFx );
|
|
for ( int i=0;i<numBurstBeams;i++ ) {
|
|
if ( rightBeamList[i].IsValid() ) {
|
|
rightBeamList[i]->Activate( true );
|
|
rightBeamList[i]->SetTargetLocation( rightBeamList[i]->GetOrigin() + spawnArgs.GetFloat( "beam_length", "100" ) * hhUtils::RandomSpreadDir( GetEnemy()->GetOrigin().ToMat3(), 16.0f ) );
|
|
}
|
|
}
|
|
StartSound( "snd_jenny_scream", SND_CHANNEL_ANY );
|
|
PostEventSec(&MA_EndRightBeams, spawnArgs.GetFloat( "beam_duration_3", "1.0" ) );
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_smoke"), spawnArgs.GetString("damage_bone_right"), NULL );
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_gun_death"), spawnArgs.GetString("damage_bone_right"), NULL );
|
|
AI_RIGHT_DAMAGED = true;
|
|
PostEventSec(&MA_SparkLeft, spawnArgs.GetFloat( "spark_freq", "1" ) + gameLocal.random.RandomFloat() );
|
|
if ( AI_LEFT_DAMAGED ) {
|
|
SetSkinByName( spawnArgs.GetString( "skin_nogun_both" ) );
|
|
} else {
|
|
SetSkinByName( spawnArgs.GetString( "skin_nogun_right" ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::Event_LeftGunDeath() {
|
|
bool explodeGun = false;
|
|
if ( leftRetractBeam.IsValid() ) {
|
|
leftRetractBeam->Show();
|
|
leftRetractBeam->Activate( true );
|
|
|
|
//retract the damage beam a little bit
|
|
idVec3 bonePos;
|
|
idMat3 boneAxis;
|
|
GetJointWorldTransform( spawnArgs.GetString( "gun_bone_left" ), bonePos, boneAxis );
|
|
idVec3 lastTargetLocation = leftRetractBeam->GetTargetLocation();
|
|
leftRetractBeam->SetTargetEntity( NULL );
|
|
if ( ai_debugBrain.GetBool() ) {
|
|
gameRenderWorld->DebugArrow( colorRed, lastTargetLocation, bonePos, 10, 1 );
|
|
}
|
|
leftRetractBeam->SetTargetLocation( lastTargetLocation + spawnArgs.GetFloat("retract_speed", "50") * (bonePos - lastTargetLocation).ToNormal() );
|
|
if ( retractLeftFx.IsValid() ) {
|
|
retractLeftFx->SetOrigin( leftRetractBeam->GetTargetLocation() );
|
|
}
|
|
if ( (lastTargetLocation - bonePos).LengthFast() < 30.0f ) {
|
|
explodeGun = true;
|
|
leftRetractBeam->Activate( false );
|
|
} else {
|
|
PostEventSec( &MA_LeftGunDeath, 0.01f );
|
|
}
|
|
}
|
|
|
|
if ( explodeGun || !leftRetractBeam.IsValid() ) {
|
|
CancelEvents( &MA_ResetRechargeBeam );
|
|
SAFE_REMOVE( leftRechargeBeam );
|
|
SAFE_REMOVE( retractLeftFx );
|
|
for ( int i=0;i<numBurstBeams;i++ ) {
|
|
if ( leftBeamList[i].IsValid() ) {
|
|
leftBeamList[i]->Activate( true );
|
|
leftBeamList[i]->SetTargetLocation( leftBeamList[i]->GetOrigin() + spawnArgs.GetFloat( "beam_length", "100" ) * hhUtils::RandomSpreadDir( GetEnemy()->GetOrigin().ToMat3(), 16.0f ) );
|
|
}
|
|
}
|
|
StartSound( "snd_jenny_scream", SND_CHANNEL_ANY );
|
|
PostEventSec(&MA_EndLeftBeams, spawnArgs.GetFloat( "beam_duration_3", "1.0" ) );
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_smoke"), spawnArgs.GetString("damage_bone_left"), NULL );
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_gun_death"), spawnArgs.GetString("damage_bone_left"), NULL );
|
|
AI_LEFT_DAMAGED = true;
|
|
PostEventSec(&MA_SparkLeft, spawnArgs.GetFloat( "spark_freq", "1" ) + gameLocal.random.RandomFloat() );
|
|
if ( AI_RIGHT_DAMAGED ) {
|
|
SetSkinByName( spawnArgs.GetString( "skin_nogun_both" ) );
|
|
} else {
|
|
SetSkinByName( spawnArgs.GetString( "skin_nogun_left" ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool hhCreatureX::UpdateAnimationControllers( void ) {
|
|
idVec3 local;
|
|
idVec3 focusPos;
|
|
idVec3 left;
|
|
idVec3 dir;
|
|
idVec3 orientationJointPos;
|
|
idVec3 localDir;
|
|
idAngles newLookAng;
|
|
idAngles diff;
|
|
idMat3 mat;
|
|
idMat3 axis;
|
|
idMat3 orientationJointAxis;
|
|
idAFAttachment *headEnt = head.GetEntity();
|
|
idVec3 eyepos;
|
|
idVec3 pos;
|
|
int i;
|
|
idAngles jointAng;
|
|
float orientationJointYaw;
|
|
|
|
if ( AI_DEAD ) {
|
|
|
|
for (int i = 0; i < jawFlapList.Num(); i++) {
|
|
jawFlapInfo_t &flapInfo = jawFlapList[i];
|
|
animator.ClearJoint( flapInfo.bone );
|
|
}
|
|
animator.ClearJoint( leftEyeJoint );
|
|
animator.ClearJoint( rightEyeJoint );
|
|
|
|
return idActor::UpdateAnimationControllers();
|
|
}
|
|
|
|
if ( orientationJoint == INVALID_JOINT ) {
|
|
orientationJointAxis = viewAxis;
|
|
orientationJointPos = physicsObj.GetOrigin();
|
|
orientationJointYaw = current_yaw;
|
|
} else {
|
|
GetJointWorldTransform( orientationJoint, gameLocal.time, orientationJointPos, orientationJointAxis );
|
|
orientationJointYaw = orientationJointAxis[ 2 ].ToYaw();
|
|
orientationJointAxis = idAngles( 0.0f, orientationJointYaw, 0.0f ).ToMat3();
|
|
}
|
|
|
|
if ( ai_debugBrain.GetBool() ) {
|
|
gameRenderWorld->DebugArrow( colorCyan, orientationJointPos, orientationJointPos + orientationJointAxis[0] * 64.0, 10, 1 );
|
|
}
|
|
|
|
if ( focusJoint != INVALID_JOINT ) {
|
|
if ( headEnt ) {
|
|
headEnt->GetJointWorldTransform( focusJoint, gameLocal.time, eyepos, axis );
|
|
} else {
|
|
// JRMMERGE_GRAVAXIS - What about GetGravAxis() are we still using/needing that?
|
|
GetJointWorldTransform( focusJoint, gameLocal.time, eyepos, axis );
|
|
}
|
|
eyeOffset.z = eyepos.z - physicsObj.GetOrigin().z;
|
|
} else {
|
|
eyepos = GetEyePosition();
|
|
}
|
|
|
|
if ( headEnt ) {
|
|
CopyJointsFromBodyToHead();
|
|
}
|
|
|
|
// Update the IK after we've gotten all the joint positions we need, but before we set any joint positions.
|
|
// Getting the joint positions causes the joints to be updated. The IK gets joint positions itself (which
|
|
// are already up to date because of getting the joints in this function) and then sets their positions, which
|
|
// forces the heirarchy to be updated again next time we get a joint or present the model. If IK is enabled,
|
|
// or if we have a seperate head, we end up transforming the joints twice per frame. Characters with no
|
|
// head entity and no ik will only transform their joints once. Set g_debuganim to the current entity number
|
|
// in order to see how many times an entity transforms the joints per frame.
|
|
idActor::UpdateAnimationControllers();
|
|
|
|
idEntity *focusEnt = focusEntity.GetEntity();
|
|
//HUMANHEAD jsh allow eyefocus independent from allowJointMod
|
|
if ( ( !allowJointMod && !allowEyeFocus ) || ( gameLocal.time >= focusTime && focusTime != -1 ) || GetPhysics()->GetGravityNormal() != idVec3( 0,0,-1) ) {
|
|
focusPos = GetEyePosition() + orientationJointAxis[ 0 ] * 512.0f;
|
|
} else if ( focusEnt == NULL ) {
|
|
// keep looking at last position until focusTime is up
|
|
focusPos = currentFocusPos;
|
|
} else if ( focusEnt == enemy.GetEntity() ) {
|
|
focusPos = lastVisibleEnemyPos + lastVisibleEnemyEyeOffset - eyeVerticalOffset * enemy.GetEntity()->GetPhysics()->GetGravityNormal();
|
|
} else if ( focusEnt->IsType( idActor::Type ) ) {
|
|
focusPos = static_cast<idActor *>( focusEnt )->GetEyePosition() - eyeVerticalOffset * focusEnt->GetPhysics()->GetGravityNormal();
|
|
} else {
|
|
focusPos = focusEnt->GetPhysics()->GetOrigin();
|
|
}
|
|
|
|
currentFocusPos = currentFocusPos + ( focusPos - currentFocusPos ) * eyeFocusRate;
|
|
|
|
// determine yaw from origin instead of from focus joint since joint may be offset, which can cause us to bounce between two angles
|
|
dir = focusPos - orientationJointPos;
|
|
newLookAng.yaw = idMath::AngleNormalize180( dir.ToYaw() - orientationJointYaw );
|
|
newLookAng.roll = 0.0f;
|
|
newLookAng.pitch = 0.0f;
|
|
|
|
newLookAng += lookOffset;
|
|
|
|
#if 0
|
|
gameRenderWorld->DebugLine( colorRed, orientationJointPos, focusPos, gameLocal.msec );
|
|
gameRenderWorld->DebugLine( colorYellow, orientationJointPos, orientationJointPos + orientationJointAxis[ 0 ] * 32.0f, gameLocal.msec );
|
|
gameRenderWorld->DebugLine( colorGreen, orientationJointPos, orientationJointPos + newLookAng.ToForward() * 48.0f, gameLocal.msec );
|
|
#endif
|
|
|
|
//JRMMERGE_GRAVAXIS: This changed to much to merge, see if you can get your monsters on planets changes back in here. I'll leave both versions
|
|
#if OLD_CODE
|
|
GetGravViewAxis().ProjectVector( dir, localDir ); // HUMANHEAD JRM: VIEWAXIS_TO_GETGRAVVIEWAXIS
|
|
lookAng.yaw = idMath::AngleNormalize180( localDir.ToYaw() );
|
|
lookAng.pitch = -idMath::AngleNormalize180( localDir.ToPitch() );
|
|
lookAng.roll = 0.0f;
|
|
#else
|
|
// determine pitch from joint position
|
|
dir = focusPos - eyepos;
|
|
if ( ai_debugBrain.GetBool() ) {
|
|
gameRenderWorld->DebugArrow( colorYellow, eyepos, eyepos + dir, 10, 1 );
|
|
}
|
|
dir.NormalizeFast();
|
|
orientationJointAxis.ProjectVector( dir, localDir );
|
|
newLookAng.pitch = -idMath::AngleNormalize180( localDir.ToPitch() ) + lookOffset.pitch;
|
|
newLookAng.roll = 0.0f;
|
|
#endif
|
|
|
|
diff = newLookAng - lookAng;
|
|
|
|
if ( eyeAng != diff ) {
|
|
eyeAng = diff;
|
|
eyeAng.Clamp( eyeMin, eyeMax );
|
|
idAngles angDelta = diff - eyeAng;
|
|
if ( !angDelta.Compare( ang_zero, 0.1f ) ) {
|
|
alignHeadTime = gameLocal.time;
|
|
} else {
|
|
alignHeadTime = gameLocal.time + ( 0.5f + 0.5f * gameLocal.random.RandomFloat() ) * focusAlignTime;
|
|
}
|
|
}
|
|
|
|
if ( idMath::Fabs( newLookAng.yaw ) < 0.1f ) {
|
|
alignHeadTime = gameLocal.time;
|
|
}
|
|
|
|
if ( ( gameLocal.time >= alignHeadTime ) || ( gameLocal.time < forceAlignHeadTime ) ) {
|
|
alignHeadTime = gameLocal.time + ( 0.5f + 0.5f * gameLocal.random.RandomFloat() ) * focusAlignTime;
|
|
destLookAng = newLookAng;
|
|
destLookAng.Clamp( lookMin, lookMax );
|
|
}
|
|
|
|
diff = destLookAng - lookAng;
|
|
if ( ( lookMin.pitch == -180.0f ) && ( lookMax.pitch == 180.0f ) ) {
|
|
if ( ( diff.pitch > 180.0f ) || ( diff.pitch <= -180.0f ) ) {
|
|
diff.pitch = 360.0f - diff.pitch;
|
|
}
|
|
}
|
|
if ( ( lookMin.yaw == -180.0f ) && ( lookMax.yaw == 180.0f ) ) {
|
|
if ( diff.yaw > 180.0f ) {
|
|
diff.yaw -= 360.0f;
|
|
} else if ( diff.yaw <= -180.0f ) {
|
|
diff.yaw += 360.0f;
|
|
}
|
|
}
|
|
lookAng = lookAng + diff * headFocusRate;
|
|
lookAng.Normalize180();
|
|
|
|
jointAng.roll = 0.0f;
|
|
if ( allowJointMod ) {
|
|
for( i = 0; i < lookJoints.Num(); i++ ) {
|
|
jointAng.pitch = lookAng.pitch * lookJointAngles[ i ].pitch;
|
|
jointAng.yaw = lookAng.yaw * lookJointAngles[ i ].yaw;
|
|
animator.SetJointAxis( lookJoints[ i ], JOINTMOD_WORLD, jointAng.ToMat3() );
|
|
}
|
|
}
|
|
|
|
if ( move.moveType == MOVETYPE_FLY ) {
|
|
// lean into turns
|
|
AdjustFlyingAngles();
|
|
}
|
|
|
|
if ( headEnt ) {
|
|
idAnimator *headAnimator = headEnt->GetAnimator();
|
|
|
|
// HUMANHEAD pdm: Added support for look joints in head entities
|
|
if ( allowJointMod ) {
|
|
for( i = 0; i < headLookJoints.Num(); i++ ) {
|
|
jointAng.pitch = lookAng.pitch * headLookJointAngles[ i ].pitch;
|
|
jointAng.yaw = lookAng.yaw * headLookJointAngles[ i ].yaw;
|
|
headAnimator->SetJointAxis( headLookJoints[ i ], JOINTMOD_WORLD, jointAng.ToMat3() );
|
|
}
|
|
}
|
|
// HUMANHEAD END
|
|
|
|
if ( allowEyeFocus ) {
|
|
idMat3 eyeAxis = ( lookAng + eyeAng ).ToMat3(); idMat3 headTranspose = headEnt->GetPhysics()->GetAxis().Transpose();
|
|
axis = eyeAxis * orientationJointAxis;
|
|
left = axis[ 1 ] * eyeHorizontalOffset;
|
|
eyepos -= headEnt->GetPhysics()->GetOrigin();
|
|
headAnimator->SetJointPos( leftEyeJoint, JOINTMOD_WORLD_OVERRIDE, eyepos + ( axis[ 0 ] * 64.0f + left ) * headTranspose );
|
|
headAnimator->SetJointPos( rightEyeJoint, JOINTMOD_WORLD_OVERRIDE, eyepos + ( axis[ 0 ] * 64.0f - left ) * headTranspose );
|
|
|
|
//if ( ai_debugMove.GetBool() ) {
|
|
// gameRenderWorld->DebugLine( colorRed, orientationJointPos, eyepos + ( axis[ 0 ] * 64.0f + left ) * headTranspose, gameLocal.msec );
|
|
//}
|
|
} else {
|
|
headAnimator->ClearJoint( leftEyeJoint );
|
|
headAnimator->ClearJoint( rightEyeJoint );
|
|
}
|
|
} else {
|
|
if ( allowEyeFocus ) {
|
|
idMat3 eyeAxis = ( lookAng + eyeAng ).ToMat3();
|
|
axis = eyeAxis * orientationJointAxis;
|
|
left = axis[ 1 ] * eyeHorizontalOffset;
|
|
eyepos += axis[ 0 ] * 64.0f - physicsObj.GetOrigin();
|
|
animator.SetJointPos( leftEyeJoint, JOINTMOD_WORLD_OVERRIDE, eyepos + left );
|
|
animator.SetJointPos( rightEyeJoint, JOINTMOD_WORLD_OVERRIDE, eyepos - left );
|
|
} else {
|
|
animator.ClearJoint( leftEyeJoint );
|
|
animator.ClearJoint( rightEyeJoint );
|
|
}
|
|
}
|
|
|
|
//HUMANHEAD pdm jawflap
|
|
hhAnimator *theAnimator;
|
|
if (head.IsValid()) {
|
|
theAnimator = head->GetAnimator();
|
|
}
|
|
else {
|
|
theAnimator = GetAnimator();
|
|
}
|
|
JawFlap(theAnimator);
|
|
//END HUMANHEAD
|
|
|
|
//update guns
|
|
//HUMANHEAD jsh PCF 4/27/06 no gun tracking
|
|
//if ( enemy.IsValid() ) {
|
|
// if ( AI_GUN_TRACKING && !AI_DEAD && !AI_RECHARGING ) {
|
|
// idVec3 focusPos, bonePos;
|
|
// idMat3 boneAxis;
|
|
|
|
// idAngles ang = ang_zero;
|
|
// ang.pitch = (bonePos - enemy->GetOrigin()).ToPitch();
|
|
// ang.pitch += gunShake.pitch;
|
|
// ang.yaw = (targetCurrent_L-bonePos).ToYaw() - viewAxis.ToAngles().yaw;
|
|
// ang.yaw += gunShake.yaw;
|
|
// GetJointWorldTransform( spawnArgs.GetString( "gun_bone_left" ), bonePos, boneAxis );
|
|
// animator.SetJointAxis( animator.GetJointHandle( spawnArgs.GetString( "gun_bone_left" ) ), JOINTMOD_WORLD, idAngles( (bonePos - targetCurrent_L).ToPitch(), (targetCurrent_L-bonePos).ToYaw() - viewAxis.ToAngles().yaw, 0.0f ).ToMat3() );
|
|
|
|
// ang.yaw = (targetCurrent_R-bonePos).ToYaw() - viewAxis.ToAngles().yaw;
|
|
// ang.yaw += gunShake.yaw;
|
|
// GetJointWorldTransform( spawnArgs.GetString( "gun_bone_right" ), bonePos, boneAxis );
|
|
// animator.SetJointAxis( animator.GetJointHandle( spawnArgs.GetString( "gun_bone_right" ) ), JOINTMOD_WORLD, idAngles( (bonePos - targetCurrent_R).ToPitch(), (targetCurrent_R-bonePos).ToYaw() - viewAxis.ToAngles().yaw, 0.0f ).ToMat3() );
|
|
// } else {
|
|
// animator.SetJointAxis( animator.GetJointHandle( spawnArgs.GetString( "gun_bone_left" ) ), JOINTMOD_WORLD, mat3_identity );
|
|
// animator.SetJointAxis( animator.GetJointHandle( spawnArgs.GetString( "gun_bone_right" ) ), JOINTMOD_WORLD, mat3_identity );
|
|
// }
|
|
//}
|
|
|
|
return true;
|
|
}
|
|
|
|
void hhCreatureX::Killed(idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) {
|
|
HandleNoGore();
|
|
|
|
//stop sparking upon death
|
|
CancelEvents( &MA_SparkLeft );
|
|
CancelEvents( &MA_SparkRight );
|
|
SAFE_REMOVE( preLaserLeft );
|
|
SAFE_REMOVE( preLaserRight );
|
|
AI_LEFT_DAMAGED = false;
|
|
AI_RIGHT_DAMAGED = false;
|
|
|
|
if ( laserLeft.IsValid() ) {
|
|
laserLeft->Hide();
|
|
}
|
|
if ( laserRight.IsValid() ) {
|
|
laserRight->Hide();
|
|
}
|
|
|
|
if ( spawnArgs.GetBool( "use_death_point", "0" ) ) {
|
|
if ( !AI_DEAD ) {
|
|
fl.takedamage = false;
|
|
AI_DEAD = true;
|
|
state = GetScriptFunction( "state_Predeath" );
|
|
SetState( state );
|
|
SetWaitState( "" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( AI_DEAD ) {
|
|
AI_DAMAGE = true;
|
|
return;
|
|
}
|
|
|
|
fl.takedamage = false;
|
|
idAngles ang;
|
|
const char *modelDeath;
|
|
|
|
// make sure the monster is activated
|
|
EndAttack();
|
|
|
|
if ( g_debugDamage.GetBool() ) {
|
|
gameLocal.Printf( "Damage: joint: '%s', zone '%s'\n", animator.GetJointName( ( jointHandle_t )location ),
|
|
GetDamageGroup( location ) );
|
|
}
|
|
|
|
if ( inflictor ) {
|
|
AI_SPECIAL_DAMAGE = inflictor->spawnArgs.GetInt( "special_damage" );
|
|
} else {
|
|
AI_SPECIAL_DAMAGE = 0;
|
|
}
|
|
|
|
if ( AI_DEAD ) {
|
|
AI_PAIN = true;
|
|
AI_DAMAGE = true;
|
|
return;
|
|
}
|
|
|
|
// stop all voice sounds
|
|
StopSound( SND_CHANNEL_VOICE, false );
|
|
if ( head.GetEntity() ) {
|
|
head.GetEntity()->StopSound( SND_CHANNEL_VOICE, false );
|
|
head.GetEntity()->GetAnimator()->ClearAllAnims( gameLocal.time, 100 );
|
|
}
|
|
|
|
disableGravity = false;
|
|
move.moveType = MOVETYPE_DEAD;
|
|
af_push_moveables = false;
|
|
|
|
physicsObj.UseFlyMove( false );
|
|
physicsObj.ForceDeltaMove( false );
|
|
|
|
// end our looping ambient sound
|
|
StopSound( SND_CHANNEL_AMBIENT, false );
|
|
|
|
if ( attacker && attacker->IsType( idActor::Type ) ) {
|
|
gameLocal.AlertAI( ( idActor * )attacker );
|
|
}
|
|
|
|
// activate targets
|
|
ActivateTargets( attacker );
|
|
|
|
RemoveAttachments();
|
|
RemoveProjectile();
|
|
StopMove( MOVE_STATUS_DONE );
|
|
|
|
ClearEnemy();
|
|
AI_DEAD = true;
|
|
|
|
// HUMANHEAD jsh commented out for girlfriendx
|
|
// make monster nonsolid
|
|
if ( spawnArgs.GetBool( "boss" ) ) {
|
|
physicsObj.SetContents( 0 );
|
|
physicsObj.GetClipModel()->Unlink();
|
|
}
|
|
|
|
Unbind();
|
|
|
|
// spawn death clip model
|
|
if ( spawnArgs.GetBool( "boss" ) ) {
|
|
idDict dict;
|
|
const idDict *torsoDict = gameLocal.FindEntityDefDict(spawnArgs.GetString("def_deathclip"));
|
|
dict.Copy(*torsoDict);
|
|
dict.SetVector("origin", GetOrigin() + modelOffset * GetAxis() );
|
|
dict.SetMatrix("rotation", GetAxis());
|
|
idEntity *e;
|
|
gameLocal.SpawnEntityDef(dict, &e);
|
|
if ( e ) {
|
|
e->GetPhysics()->SetContents( CONTENTS_PLAYERCLIP );
|
|
}
|
|
}
|
|
|
|
if ( StartRagdoll() ) {
|
|
StartSound( "snd_death", SND_CHANNEL_VOICE, 0, false, NULL );
|
|
// HUMANHEAD JRM - some monsters are removed, but always need to play sound
|
|
} else if(spawnArgs.GetBool("death_sound_always","0")) {
|
|
StartSound( "snd_death", SND_CHANNEL_VOICE, 0, false, NULL );
|
|
}
|
|
// HUMANHEAD JRM - end
|
|
|
|
if ( spawnArgs.GetString( "model_death", "", &modelDeath ) ) {
|
|
// lost soul is only case that does not use a ragdoll and has a model_death so get the death sound in here
|
|
StartSound( "snd_death", SND_CHANNEL_VOICE, 0, false, NULL );
|
|
renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
|
|
SetModel( modelDeath );
|
|
physicsObj.SetLinearVelocity( vec3_zero );
|
|
physicsObj.PutToRest();
|
|
physicsObj.DisableImpact();
|
|
}
|
|
|
|
restartParticles = false;
|
|
|
|
state = GetScriptFunction( "state_Killed" );
|
|
SetState( state );
|
|
SetWaitState( "" );
|
|
|
|
if ( attacker && attacker->IsType( idPlayer::Type ) ) {
|
|
static_cast< idPlayer* >( attacker )->AddAIKill();
|
|
}
|
|
|
|
// General non-item dropping (for monsters, souls, etc.)
|
|
const idKeyValue *kv = NULL;
|
|
kv = spawnArgs.MatchPrefix( "def_drops", NULL );
|
|
while ( kv ) {
|
|
|
|
idStr drops = kv->GetValue();
|
|
idDict args;
|
|
|
|
idStr last5 = kv->GetKey().Right(5);
|
|
if ( drops.Length() && idStr::Icmp( last5, "Joint" ) != 0) {
|
|
args.Set( "classname", drops );
|
|
|
|
// HUMANHEAD pdm: specify monster so souls can call back to remove body when picked up
|
|
args.Set("monsterSpawnedBy", name.c_str());
|
|
|
|
idVec3 origin;
|
|
idMat3 axis;
|
|
idStr jointKey = kv->GetKey() + idStr("Joint");
|
|
idStr jointName = spawnArgs.GetString( jointKey );
|
|
idStr joint2JointKey = kv->GetKey() + idStr("Joint2Joint");
|
|
idStr j2jName = spawnArgs.GetString( joint2JointKey );
|
|
|
|
idEntity *newEnt = NULL;
|
|
gameLocal.SpawnEntityDef( args, &newEnt );
|
|
HH_ASSERT(newEnt != NULL);
|
|
|
|
if(jointName.Length()) {
|
|
jointHandle_t joint = GetAnimator()->GetJointHandle( jointName );
|
|
if (!GetAnimator()->GetJointTransform( joint, gameLocal.time, origin, axis ) ) {
|
|
gameLocal.Printf( "%s refers to invalid joint '%s' on entity '%s'\n", (const char*)jointKey.c_str(), (const char*)jointName, (const char*)name );
|
|
origin = renderEntity.origin;
|
|
axis = renderEntity.axis;
|
|
}
|
|
axis *= renderEntity.axis;
|
|
origin = renderEntity.origin + origin * renderEntity.axis;
|
|
newEnt->SetAxis(axis);
|
|
newEnt->SetOrigin(origin);
|
|
}
|
|
else {
|
|
|
|
newEnt->SetAxis(viewAxis);
|
|
newEnt->SetOrigin(GetOrigin());
|
|
}
|
|
|
|
}
|
|
|
|
kv = spawnArgs.MatchPrefix( "def_drops", kv );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
hhCreatureX::Save
|
|
=====================
|
|
*/
|
|
void hhCreatureX::Save( idSaveGame *savefile ) const {
|
|
laserRight.Save( savefile );
|
|
laserLeft.Save( savefile );
|
|
savefile->WriteBool( bLaserLeftActive );
|
|
savefile->WriteBool( bLaserRightActive );
|
|
|
|
int i, num = leftBeamList.Num();
|
|
savefile->WriteInt( num );
|
|
for ( i = 0; i < num; i++ ) {
|
|
leftBeamList[i].Save( savefile );
|
|
}
|
|
|
|
num = rightBeamList.Num();
|
|
savefile->WriteInt( num );
|
|
for ( i = 0; i < num; i++ ) {
|
|
rightBeamList[i].Save( savefile );
|
|
}
|
|
|
|
savefile->WriteInt( numBurstBeams );
|
|
savefile->WriteInt( leftGunHealth );
|
|
savefile->WriteInt( rightGunHealth );
|
|
savefile->WriteAngles( gunShake );
|
|
savefile->WriteInt( nextBeamTime );
|
|
savefile->WriteInt( nextLeftZapTime );
|
|
savefile->WriteInt( nextRightZapTime );
|
|
savefile->WriteInt( leftGunLives );
|
|
savefile->WriteInt( rightGunLives );
|
|
|
|
savefile->WriteVec3( targetStart_L );
|
|
savefile->WriteVec3( targetEnd_L );
|
|
savefile->WriteVec3( targetCurrent_L );
|
|
savefile->WriteVec3( targetStart_R );
|
|
savefile->WriteVec3( targetEnd_R );
|
|
savefile->WriteVec3( targetCurrent_R );
|
|
|
|
savefile->WriteFloat( targetAlpha_L );
|
|
savefile->WriteFloat( targetAlpha_R );
|
|
|
|
savefile->WriteVec3( laserEndLeft );
|
|
savefile->WriteVec3( laserEndRight );
|
|
|
|
savefile->WriteInt( nextLaserLeft );
|
|
savefile->WriteInt( nextLaserRight );
|
|
savefile->WriteInt( nextHealthTick );
|
|
|
|
leftRecharger.Save( savefile );
|
|
rightRecharger.Save( savefile );
|
|
|
|
leftRechargeBeam.Save( savefile );
|
|
rightRechargeBeam.Save( savefile );
|
|
|
|
leftDamageBeam.Save( savefile );
|
|
rightDamageBeam.Save( savefile );
|
|
|
|
leftRetractBeam.Save( savefile );
|
|
rightRetractBeam.Save( savefile );
|
|
|
|
preLaserLeft.Save( savefile );
|
|
preLaserRight.Save( savefile );
|
|
|
|
muzzleLeftFx.Save( savefile );
|
|
muzzleRightFx.Save( savefile );
|
|
impactLeftFx.Save( savefile );
|
|
impactRightFx.Save( savefile );
|
|
rechargeLeftFx.Save( savefile );
|
|
rechargeRightFx.Save( savefile );
|
|
retractLeftFx.Save( savefile );
|
|
retractRightFx.Save( savefile );
|
|
|
|
savefile->WriteInt( leftRechargerHealth );
|
|
savefile->WriteInt( rightRechargerHealth );
|
|
savefile->WriteBool( bScripted );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
hhCreatureX::Restore
|
|
=====================
|
|
*/
|
|
void hhCreatureX::Restore( idRestoreGame *savefile ) {
|
|
laserRight.Restore( savefile );
|
|
laserLeft.Restore( savefile );
|
|
savefile->ReadBool( bLaserLeftActive );
|
|
savefile->ReadBool( bLaserRightActive );
|
|
|
|
int i, num;
|
|
savefile->ReadInt( num );
|
|
leftBeamList.SetNum( num );
|
|
for ( i = 0; i < num; i++ ) {
|
|
leftBeamList[i].Restore( savefile );
|
|
}
|
|
|
|
savefile->ReadInt( num );
|
|
rightBeamList.SetNum( num );
|
|
for ( int i = 0; i < num; i++ ) {
|
|
rightBeamList[i].Restore( savefile );
|
|
}
|
|
|
|
savefile->ReadInt( numBurstBeams );
|
|
savefile->ReadInt( leftGunHealth );
|
|
savefile->ReadInt( rightGunHealth );
|
|
savefile->ReadAngles( gunShake );
|
|
savefile->ReadInt( nextBeamTime );
|
|
savefile->ReadInt( nextLeftZapTime );
|
|
savefile->ReadInt( nextRightZapTime );
|
|
savefile->ReadInt( leftGunLives );
|
|
savefile->ReadInt( rightGunLives );
|
|
|
|
savefile->ReadVec3( targetStart_L );
|
|
savefile->ReadVec3( targetEnd_L );
|
|
savefile->ReadVec3( targetCurrent_L );
|
|
savefile->ReadVec3( targetStart_R );
|
|
savefile->ReadVec3( targetEnd_R );
|
|
savefile->ReadVec3( targetCurrent_R );
|
|
|
|
savefile->ReadFloat( targetAlpha_L );
|
|
savefile->ReadFloat( targetAlpha_R );
|
|
|
|
savefile->ReadVec3( laserEndLeft );
|
|
savefile->ReadVec3( laserEndRight );
|
|
|
|
savefile->ReadInt( nextLaserLeft );
|
|
savefile->ReadInt( nextLaserRight );
|
|
savefile->ReadInt( nextHealthTick );
|
|
|
|
leftRecharger.Restore( savefile );
|
|
rightRecharger.Restore( savefile );
|
|
|
|
leftRechargeBeam.Restore( savefile );
|
|
rightRechargeBeam.Restore( savefile );
|
|
|
|
leftDamageBeam.Restore( savefile );
|
|
rightDamageBeam.Restore( savefile );
|
|
|
|
leftRetractBeam.Restore( savefile );
|
|
rightRetractBeam.Restore( savefile );
|
|
|
|
preLaserLeft.Restore( savefile );
|
|
preLaserRight.Restore( savefile );
|
|
|
|
muzzleLeftFx.Restore( savefile );
|
|
muzzleRightFx.Restore( savefile );
|
|
impactLeftFx.Restore( savefile );
|
|
impactRightFx.Restore( savefile );
|
|
rechargeLeftFx.Restore( savefile );
|
|
rechargeRightFx.Restore( savefile );
|
|
retractLeftFx.Restore( savefile );
|
|
retractRightFx.Restore( savefile );
|
|
|
|
savefile->ReadInt( leftRechargerHealth );
|
|
savefile->ReadInt( rightRechargerHealth );
|
|
savefile->ReadBool( bScripted );
|
|
}
|
|
|
|
|
|
void hhCreatureX::MuzzleLeftOn() {
|
|
if ( !muzzleLeftFx.IsValid() ) {
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_muzzle"), spawnArgs.GetString("muzzle_bone_left"), NULL, &MA_AssignLeftMuzzleFx, false );
|
|
}
|
|
if ( !impactLeftFx.IsValid() ) {
|
|
BroadcastFxInfo( spawnArgs.GetString("fx_impact"), GetOrigin(), GetAxis(), NULL, &MA_AssignLeftImpactFx, false );
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::MuzzleLeftOff() {
|
|
SAFE_REMOVE( muzzleLeftFx );
|
|
SAFE_REMOVE( impactLeftFx );
|
|
}
|
|
|
|
void hhCreatureX::Event_AssignLeftMuzzleFx( hhEntityFx* fx ) {
|
|
muzzleLeftFx = fx;
|
|
}
|
|
|
|
void hhCreatureX::Event_AssignRightMuzzleFx( hhEntityFx* fx ) {
|
|
muzzleRightFx = fx;
|
|
}
|
|
|
|
void hhCreatureX::Event_AssignRightImpactFx( hhEntityFx* fx ) {
|
|
impactRightFx = fx;
|
|
}
|
|
|
|
void hhCreatureX::Event_AssignLeftImpactFx( hhEntityFx* fx ) {
|
|
impactLeftFx = fx;
|
|
}
|
|
|
|
|
|
void hhCreatureX::Event_AssignLeftRechargeFx( hhEntityFx* fx ) {
|
|
rechargeLeftFx = fx;
|
|
}
|
|
|
|
void hhCreatureX::Event_AssignRightRechargeFx( hhEntityFx* fx ) {
|
|
rechargeRightFx= fx;
|
|
}
|
|
|
|
void hhCreatureX::MuzzleRightOn() {
|
|
if ( !muzzleRightFx.IsValid() ) {
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_muzzle"), spawnArgs.GetString("muzzle_bone_right"), NULL, &MA_AssignRightMuzzleFx, false );
|
|
}
|
|
if ( !impactRightFx.IsValid() ) {
|
|
BroadcastFxInfo( spawnArgs.GetString("fx_impact"), GetOrigin(), GetAxis(), NULL, &MA_AssignRightImpactFx, false );
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::MuzzleRightOff() {
|
|
SAFE_REMOVE( muzzleRightFx );
|
|
SAFE_REMOVE( impactRightFx );
|
|
}
|
|
|
|
void hhCreatureX::Event_SetGunOffset( const idAngles &ang ) {
|
|
gunShake = ang;
|
|
}
|
|
|
|
void hhCreatureX::Event_EndLeftBeams() {
|
|
for ( int i = 0; i < numBurstBeams; i ++ ) {
|
|
if( leftBeamList[i].IsValid() ) {
|
|
leftBeamList[i]->Activate( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::Event_EndRightBeams() {
|
|
for ( int i = 0; i < numBurstBeams; i ++ ) {
|
|
if( rightBeamList[i].IsValid() ) {
|
|
rightBeamList[i]->Activate( false );
|
|
}
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::Event_StartRechargeBeams() {
|
|
StartSound( "snd_recharge_beam_start", SND_CHANNEL_ANY );
|
|
if ( leftRecharger.IsValid() ) {
|
|
const char *defName = spawnArgs.GetString( "fx_recharge_beam_start" );
|
|
if (defName && defName[0]) {
|
|
hhFxInfo fxInfo;
|
|
fxInfo.RemoveWhenDone( true );
|
|
idEntityFx *rechargeFx = SpawnFxLocal( defName, leftRecharger->GetOrigin(), leftRecharger->GetAxis(), &fxInfo, gameLocal.isClient );
|
|
if ( rechargeFx ) {
|
|
rechargeFx->Bind( leftRecharger.GetEntity(), true );
|
|
}
|
|
}
|
|
if ( leftRechargeBeam.IsValid() ) {
|
|
leftRechargeBeam->Activate( true );
|
|
leftRechargeBeam->SetTargetEntity( leftRecharger.GetEntity(), 0, leftRecharger->spawnArgs.GetVector( "offsetModel" ) );
|
|
}
|
|
}
|
|
if ( rightRecharger.IsValid() ) {
|
|
const char *defName = spawnArgs.GetString( "fx_recharge_beam_start" );
|
|
if (defName && defName[0]) {
|
|
hhFxInfo fxInfo;
|
|
fxInfo.RemoveWhenDone( true );
|
|
idEntityFx *rechargeFx = SpawnFxLocal( defName, rightRecharger->GetOrigin(), rightRecharger->GetAxis(), &fxInfo, gameLocal.isClient );
|
|
if ( rechargeFx ) {
|
|
rechargeFx->Bind( rightRecharger.GetEntity(), true );
|
|
}
|
|
}
|
|
|
|
if ( rightRechargeBeam.IsValid() ) {
|
|
rightRechargeBeam->Activate( true );
|
|
rightRechargeBeam->SetTargetEntity( rightRecharger.GetEntity(), 0, rightRecharger->spawnArgs.GetVector( "offsetModel" ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::Event_GunRecharge( int onOff ) {
|
|
if ( onOff ) {
|
|
idVec3 boneOrigin;
|
|
idMat3 boneAxis;
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_right"), boneOrigin, boneAxis );
|
|
BroadcastFxInfo( spawnArgs.GetString("fx_recharger_enter"), boneOrigin, boneAxis, NULL, NULL, false );
|
|
|
|
GetJointWorldTransform( spawnArgs.GetString("laser_bone_left"), boneOrigin, boneAxis );
|
|
BroadcastFxInfo( spawnArgs.GetString("fx_recharger_enter"), boneOrigin, boneAxis, NULL, NULL, false );
|
|
|
|
PostEventSec( &MA_StartRechargeBeams, spawnArgs.GetFloat( "recharge_delay", "0.9" ) );
|
|
if ( leftRecharger.IsValid() ) {
|
|
if ( leftRetractBeam.IsValid() ) {
|
|
leftRetractBeam->SetTargetEntity( leftRecharger.GetEntity(), 0, leftRecharger->spawnArgs.GetVector( "offsetModel" ) );
|
|
}
|
|
leftRechargerHealth = leftRecharger->GetHealth();
|
|
if ( leftDamageBeam.IsValid() ) {
|
|
leftDamageBeam->SetTargetEntity( leftRecharger.GetEntity(), 0, leftRecharger->spawnArgs.GetVector( "offsetModel" ) );
|
|
}
|
|
leftRecharger->Show();
|
|
leftRecharger->SetOrigin( GetOrigin() );
|
|
idVec3 offset = spawnArgs.GetVector( "healer_offset", "0 80 60" );
|
|
leftRecharger->MoveToPosition( GetOrigin() + viewAxis * offset );
|
|
leftRecharger->SetState( leftRecharger->GetScriptFunction( "state_Healer" ) );
|
|
leftRecharger->SetWaitState( "" );
|
|
}
|
|
if ( rightRecharger.IsValid() ) {
|
|
if ( rightRetractBeam.IsValid() ) {
|
|
rightRetractBeam->SetTargetEntity( rightRecharger.GetEntity(), 0, rightRecharger->spawnArgs.GetVector( "offsetModel" ) );
|
|
}
|
|
rightRechargerHealth = rightRecharger->GetHealth();
|
|
if ( rightDamageBeam.IsValid() ) {
|
|
rightDamageBeam->SetTargetEntity( rightRecharger.GetEntity(), 0, rightRecharger->spawnArgs.GetVector( "offsetModel" ) );
|
|
}
|
|
rightRecharger->Show();
|
|
idVec3 offset = spawnArgs.GetVector( "healer_offset", "0 80 60" );
|
|
offset.y *= -1;
|
|
rightRecharger->SetOrigin( GetOrigin() );
|
|
rightRecharger->MoveToPosition( GetOrigin() + viewAxis * offset );
|
|
rightRecharger->SetState( rightRecharger->GetScriptFunction( "state_Healer" ) );
|
|
rightRecharger->SetWaitState( "" );
|
|
}
|
|
if ( !AI_LEFT_DAMAGED ) {
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_weakpoint"), spawnArgs.GetString("recharge_bone_left"), NULL, &MA_AssignLeftRechargeFx, false );
|
|
}
|
|
if ( !AI_RIGHT_DAMAGED ) {
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_weakpoint"), spawnArgs.GetString("recharge_bone_right"), NULL, &MA_AssignRightRechargeFx, false );
|
|
}
|
|
} else {
|
|
SAFE_REMOVE( rechargeLeftFx );
|
|
SAFE_REMOVE( rechargeRightFx );
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::Event_EndRecharge() {
|
|
if ( leftRechargeBeam.IsValid() ) {
|
|
leftRechargeBeam->Activate( false );
|
|
}
|
|
if ( leftRecharger.IsValid() ) {
|
|
leftRecharger->SetState( leftRecharger->GetScriptFunction( "state_Return" ) );
|
|
}
|
|
if ( rightRechargeBeam.IsValid() ) {
|
|
rightRechargeBeam->Activate( false );
|
|
}
|
|
if ( rightRecharger.IsValid() ) {
|
|
rightRecharger->SetState( rightRecharger->GetScriptFunction( "state_Return" ) );
|
|
}
|
|
if ( rightDamageBeam.IsValid() ) {
|
|
rightDamageBeam->Activate( false );
|
|
}
|
|
if ( leftDamageBeam.IsValid() ) {
|
|
leftDamageBeam->Activate( false );
|
|
}
|
|
CancelEvents( &MA_ResetRechargeBeam );
|
|
CancelEvents( &MA_StartRechargeBeams );
|
|
}
|
|
|
|
//HUMANHEAD jsh PCF 4/27/06 initialized proj and made sure ReturnEntity is called
|
|
void hhCreatureX::Event_AttackMissile( const char *jointname, const idDict *projDef, int boneDir ) {
|
|
idProjectile *proj = NULL;
|
|
|
|
// Bonedir launch?
|
|
if((BOOL)boneDir) {
|
|
proj = hhProjectile::SpawnProjectile(projDef);
|
|
if ( proj ) {
|
|
idMat3 axis;
|
|
idVec3 muzzle;
|
|
GetMuzzle( jointname, muzzle, axis );
|
|
proj->Create(this, muzzle, axis);
|
|
proj->Launch(muzzle, axis, vec3_zero);
|
|
}
|
|
}
|
|
else {
|
|
if ( shootTarget.IsValid() ) {
|
|
proj = LaunchProjectile( jointname, shootTarget.GetEntity(), false, projDef ); //HUMANHEAD mdc - pass projDef on for multiple proj support
|
|
} else {
|
|
proj = LaunchProjectile( jointname, enemy.GetEntity(), false, projDef ); //HUMANHEAD mdc - pass projDef on for multiple proj support
|
|
}
|
|
}
|
|
|
|
idThread::ReturnEntity( proj );
|
|
}
|
|
|
|
void hhCreatureX::Event_SparkLeft() {
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_spark"), spawnArgs.GetString("damage_bone_left"), NULL );
|
|
PostEventSec(&MA_SparkLeft, spawnArgs.GetFloat( "spark_freq", "1" ) + gameLocal.random.RandomFloat() );
|
|
}
|
|
|
|
void hhCreatureX::Event_SparkRight() {
|
|
BroadcastFxInfoAlongBone( spawnArgs.GetString("fx_spark"), spawnArgs.GetString("damage_bone_right"), NULL );
|
|
PostEventSec(&MA_SparkRight, spawnArgs.GetFloat( "spark_freq", "1" ) + gameLocal.random.RandomFloat() );
|
|
}
|
|
|
|
void hhCreatureX::Event_HudEvent( const char* eventName ) {
|
|
idPlayer* player = gameLocal.GetLocalPlayer();
|
|
if ( player && player->hud ) {
|
|
gameLocal.GetLocalPlayer()->hud->HandleNamedEvent( eventName );
|
|
gameLocal.GetLocalPlayer()->hud->StateChanged(gameLocal.time);
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::Activate( idEntity *activator ) {
|
|
if ( preLaserLeft.IsValid() ) {
|
|
HH_ASSERT(!FLOAT_IS_NAN(preLaserLeft->GetOrigin().x)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(preLaserLeft->GetOrigin().y)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(preLaserLeft->GetOrigin().z)); //Test for bad origin
|
|
}
|
|
if ( preLaserRight.IsValid() ) {
|
|
HH_ASSERT(!FLOAT_IS_NAN(preLaserRight->GetOrigin().x)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(preLaserRight->GetOrigin().y)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(preLaserRight->GetOrigin().z)); //Test for bad origin
|
|
}
|
|
if ( laserLeft.IsValid() ) {
|
|
HH_ASSERT(!FLOAT_IS_NAN(laserLeft->GetOrigin().x)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(laserLeft->GetOrigin().y)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(laserLeft->GetOrigin().z)); //Test for bad origin
|
|
}
|
|
if ( laserRight.IsValid() ) {
|
|
HH_ASSERT(!FLOAT_IS_NAN(laserRight->GetOrigin().x)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(laserRight->GetOrigin().y)); //Test for bad origin
|
|
HH_ASSERT(!FLOAT_IS_NAN(laserRight->GetOrigin().z)); //Test for bad origin
|
|
}
|
|
|
|
hhMonsterAI::Activate( activator );
|
|
}
|
|
|
|
void hhCreatureX::Show() {
|
|
hhMonsterAI::Show();
|
|
if ( preLaserLeft.IsValid() ) {
|
|
preLaserLeft->Hide();
|
|
preLaserLeft->Activate( false );
|
|
}
|
|
if ( preLaserRight.IsValid() ) {
|
|
preLaserRight->Hide();
|
|
preLaserRight->Activate( false );
|
|
}
|
|
if ( laserLeft.IsValid() ) {
|
|
laserLeft->Hide();
|
|
laserLeft->Activate( false );
|
|
}
|
|
if ( laserRight.IsValid() ) {
|
|
laserRight->Hide();
|
|
laserRight->Activate( false );
|
|
}
|
|
if ( leftRechargeBeam.IsValid() ) {
|
|
leftRechargeBeam->Hide();
|
|
leftRechargeBeam->Activate( false );
|
|
}
|
|
if ( rightRechargeBeam.IsValid() ) {
|
|
rightRechargeBeam->Hide();
|
|
rightRechargeBeam->Activate( false );
|
|
}
|
|
if ( leftDamageBeam.IsValid() ) {
|
|
leftDamageBeam->Hide();
|
|
leftDamageBeam->Activate( false );
|
|
}
|
|
if ( rightDamageBeam.IsValid() ) {
|
|
rightDamageBeam->Hide();
|
|
rightDamageBeam->Activate( false );
|
|
}
|
|
if ( leftRetractBeam.IsValid() ) {
|
|
leftRetractBeam->Hide();
|
|
leftRetractBeam->Activate( false );
|
|
}
|
|
if ( rightRetractBeam.IsValid() ) {
|
|
rightRetractBeam->Hide();
|
|
rightRetractBeam->Activate( false );
|
|
}
|
|
}
|
|
|
|
void hhCreatureX::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) {
|
|
if ( spawnArgs.GetBool( "boss" ) ) {
|
|
if ( attacker && attacker->IsType( idPlayer::Type ) && idStr::Icmp( damageDefName, spawnArgs.GetString( "def_damageTelefrag", "damage_telefrag" ) ) == 0 ) {
|
|
//telefragged so move somewhere nice
|
|
SetState( GetScriptFunction( "state_Telefragged" ) );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( !fl.takedamage ) {
|
|
return;
|
|
}
|
|
//check for splash damage or jenny-specific damage based on location
|
|
if ( AI_DEAD && spawnArgs.GetBool( "boss" ) ) {
|
|
const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
|
|
if ( ( damageDef && damageDef->GetFloat( "radius" ) > 0 ) ||
|
|
( location && strcmp( GetDamageGroup( location ), "jenny" ) == 0 ) ) {
|
|
SetState( GetScriptFunction( "state_RealDeath" ) );
|
|
fl.takedamage = false;
|
|
}
|
|
}
|
|
hhMonsterAI::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
|
|
}
|
|
#endif //HUMANHEAD jsh PCF 5/26/06: code removed for demo build
|