Files
DoomRTX/neo/prey/Prey/prey_weaponsoulstripper.cpp
T
2026-05-05 15:01:01 -07:00

1427 lines
45 KiB
C++

#include "precompiled.h"
#pragma hdrstop
#include "prey_local.h"
const idEventDef EV_KillBeam( "killBeam", NULL, NULL );
CLASS_DECLARATION( hhWeaponFireController, hhSoulStripperAltFireController )
END_CLASS
/***********************************************************************
hhSoulStripperAltFireController::LaunchProjectiles
***********************************************************************/
void hhSoulStripperAltFireController::LaunchProjectiles( const idVec3& launchOrigin, const idMat3& aimAxis, const idVec3& pushVelocity, idEntity* projOwner ) {
// Spawn minion
idDict args;
idVec3 minionOffset = dict->GetVector( "minionOffset" );
args.SetVector( "origin", launchOrigin + aimAxis * minionOffset );
args.SetMatrix( "rotation", aimAxis );
const char *minionDef = dict->GetString( "def_minion" );
gameLocal.SpawnObject( minionDef, &args );
// Spawn blast effect
hhFxInfo fxInfo;
fxInfo.SetNormal( aimAxis[0] );
fxInfo.RemoveWhenDone( true );
self->BroadcastFxInfo( dict->GetString( "fx_blastflash" ), launchOrigin, aimAxis, &fxInfo );
}
CLASS_DECLARATION( hhWeaponFireController, hhBeamBasedFireController )
END_CLASS
/***********************************************************************
hhBeamBasedFireController::LaunchProjectiles
***********************************************************************/
void hhBeamBasedFireController::LaunchProjectiles( const idVec3& launchOrigin, const idMat3& aimAxis, const idVec3& pushVelocity, idEntity* projOwner ) {
idVec3 start, end;
trace_t results;
float traceLength;
idVec3 boneOrigin;
idMat3 boneAxis;
if ( projTime < gameLocal.time ) {
hhFireController::LaunchProjectiles(launchOrigin, aimAxis, pushVelocity, projOwner);
projTime = gameLocal.time + dict->GetInt("projRate", "100");
}
start = launchOrigin;
traceLength = dict->GetFloat("traceLength","100");
end = start + traceLength * aimAxis[0];
// Check to see if the beam should attempt to hit something
if (owner.IsValid()) {
//rww - can hit owners due to different angles in mp (although not the local client since the trace is done on the client every frame)
gameLocal.clip.TracePoint( results, start, end, MASK_SHOT_RENDERMODEL | CONTENTS_GAME_PORTAL, owner.GetEntity() );
}
else {
gameLocal.clip.TracePoint( results, start, end, MASK_SHOT_RENDERMODEL | CONTENTS_GAME_PORTAL, NULL );
}
if ( !shotbeam.IsValid() ) {
shotbeam = hhBeamSystem::SpawnBeam( launchOrigin, dict->GetString( "beam" ), aimAxis, true );
if( !shotbeam.IsValid() )
return;
if (self->GetOwner()) {
shotbeam->snapshotOwner = self->GetOwner(); //rww - this beam is client-local, but will remove itself when the gun is not actively in the snapshot (meaning, it's not actively updated)
}
}
shotbeam->Activate( true );
hhFxInfo fxInfo;
fxInfo.SetNormal( results.c.normal );
fxInfo.RemoveWhenDone( true );
if( !impactFx.IsValid() ) {
const char* str=dict->GetString("fx_impact");
if ( str && str[0] )
impactFx=self.GetEntity()->SpawnFxLocal( str, results.endpos, results.c.normal.ToMat3(), &fxInfo, true );
}
if( impactFx.IsValid() ) {
if (self.IsValid() && self->GetOwner()) {
impactFx->snapshotOwner = self->GetOwner(); //rww
}
static_cast<hhEntityFx*>( impactFx.GetEntity() )->SetFxInfo(fxInfo);
impactFx->Nozzle(true);
impactFx->SetOrigin(results.endpos-aimAxis[0]*20);
}
idVec3 beamOrigin;
idMat3 beamAxis;
CalculateMuzzlePosition( beamOrigin, beamAxis ); // Must use this instead of launchOrigin, since launch origin is forced into the player's bbox
if (gameLocal.isMultiplayer) { //rww - the visual origin of the beam needs to be from the player's world weapon joint to avoid the optic blast
idVec3 tpOrigin;
idMat3 tpAxis;
if (CheckThirdPersonMuzzle(tpOrigin, tpAxis)) {
beamOrigin = tpOrigin;
//just keep the existing axis
}
}
shotbeam->SetOrigin( beamOrigin );
shotbeam->SetAxis( aimAxis );
shotbeam->SetTargetLocation( results.endpos-aimAxis[0]*40 );
float length = (results.endpos - start).Length();
shotbeam->SetBeamOffsetScale( length/150.0f );
GetSelf()->CancelEvents( &EV_KillBeam );
GetSelf()->PostEventSec( &EV_KillBeam, dict->GetFloat( "beamTime", "0.1" ) );
}
void hhBeamBasedFireController::KillBeam()
{
if( impactFx.IsValid() ) {
impactFx->Nozzle(false);
if (gameLocal.isClient) {
impactFx->snapshotOwner = NULL; //rww - prevent it from being unhidden between now and the removal frame on the client
}
}
if( shotbeam.IsValid() )
shotbeam->Activate( false );
}
void hhBeamBasedFireController::Think()
{
if( shotbeam.IsValid() ) {
idVec3 beamOrigin;
idMat3 beamAxis;
CalculateMuzzlePosition( beamOrigin, beamAxis ); // Must use this instead of launchOrigin, since launch origin is forced into the player's bbox
idVec3 adjustedOrigin = AssureInsideCollisionBBox( beamOrigin, GetSelf()->GetAxis(), GetCollisionBBox(), projectileMaxHalfDimension );
idMat3 aimAxis = DetermineAimAxis( adjustedOrigin, GetSelf()->GetAxis() );
if (gameLocal.isMultiplayer) { //rww - the visual origin of the beam needs to be from the player's world weapon joint to avoid the optic blast
idVec3 tpOrigin;
idMat3 tpAxis;
if (CheckThirdPersonMuzzle(tpOrigin, tpAxis)) {
beamOrigin = tpOrigin;
//just keep the existing axis
}
}
shotbeam->SetOrigin( beamOrigin );
shotbeam->SetAxis( aimAxis );
}
}
/***********************************************************************
hhBeamBasedFireController::Init
***********************************************************************/
void hhBeamBasedFireController::Init( const idDict* viewDict, hhWeapon* self, hhPlayer* owner )
{
hhWeaponFireController::Init( viewDict, self, owner );
shotbeam = NULL;
projTime = 0;
}
/***********************************************************************
hhBeamBasedFireController::~hhBeamBasedFireController
***********************************************************************/
hhBeamBasedFireController::~hhBeamBasedFireController()
{
KillBeam();
if( impactFx.IsValid() )
SAFE_REMOVE(impactFx);
if( shotbeam.IsValid() )
SAFE_REMOVE(shotbeam);
}
void hhBeamBasedFireController::Save( idSaveGame *savefile ) const {
shotbeam.Save( savefile );
savefile->WriteInt( projTime );
impactFx.Save( savefile );
}
void hhBeamBasedFireController::Restore( idRestoreGame *savefile ) {
shotbeam.Restore( savefile );
savefile->ReadInt( projTime );
impactFx.Restore( savefile );
}
CLASS_DECLARATION( hhBeamBasedFireController, hhSunbeamFireController )
END_CLASS
void hhSunbeamFireController::LaunchProjectiles( const idVec3& launchOrigin, const idMat3& aimAxis, const idVec3& pushVelocity, idEntity* projOwner ) {
hhBeamBasedFireController::LaunchProjectiles(launchOrigin, aimAxis, pushVelocity, projOwner);
//HUMANHEAD PCF rww 05/18/06 - since values are assuming 60hz, make them relative
float backpush = dict->GetFloat("backpush","0.0")*(60.0f/(float)USERCMD_HZ);
float slowwalk = dict->GetFloat("slowwalk","0.0")*(60.0f/(float)USERCMD_HZ);
int knockback = dict->GetInt("knockback","0")*(60/USERCMD_HZ);
//HUMANHEAD END
hhPhysics_Player* pp = static_cast<hhPhysics_Player*>(owner->GetPlayerPhysics());
idVec3 v = pp->GetLinearVelocity()+owner->GetAxis()[0]*backpush;
float f = pp->GetLinearVelocity()*owner->GetAxis()[0];
v += owner->GetAxis()[0] * ( (f>0) ? slowwalk*f : 0 );
pp->SetLinearVelocity(v);
pp->SetKnockBack(knockback);
}
void hhSunbeamFireController::Think()
{
idVec3 start, end;
if( shotbeam.IsValid() ) {
start = shotbeam->GetOrigin();
end = shotbeam->GetTargetLocation();
float length = (end - start).Length();
idVec3 beamOrigin;
idMat3 beamAxis;
CalculateMuzzlePosition( beamOrigin, beamAxis ); // Must use this instead of launchOrigin, since launch origin is forced into the player's bbox
idVec3 adjustedOrigin = AssureInsideCollisionBBox( beamOrigin, GetSelf()->GetAxis(), GetCollisionBBox(), projectileMaxHalfDimension );
idMat3 aimAxis = DetermineAimAxis( adjustedOrigin, GetSelf()->GetAxis() );
end = beamOrigin + length * aimAxis[0];
if (gameLocal.isMultiplayer) { //rww - the visual origin of the beam needs to be from the player's world weapon joint to avoid the optic blast
idVec3 tpOrigin;
idMat3 tpAxis;
if (CheckThirdPersonMuzzle(tpOrigin, tpAxis)) {
beamOrigin = tpOrigin;
//just keep the existing axis
}
}
shotbeam->SetOrigin( beamOrigin );
shotbeam->SetAxis( aimAxis );
shotbeam->SetTargetLocation( end );
if( impactFx.IsValid() )
impactFx->SetOrigin( end );
}
}
CLASS_DECLARATION( hhWeaponFireController, hhPlasmaFireController )
END_CLASS
//=============================================================================
//
// hhPlasmaFireController::LaunchProjectiles
//
//=============================================================================
bool hhPlasmaFireController::LaunchProjectiles( const idVec3& pushVelocity ) {
char* projStr = "projectile_plasma";
fireDelay = dict->GetFloat( "fireRate" );
spread = DEG2RAD( dict->GetFloat("spread") );
yawSpread = dict->GetFloat("yawSpread");
usercmd_t cmd;
idAngles temp;
owner->GetPilotInput(cmd,temp);
idVec3 dir(cmd.forwardmove, -cmd.rightmove, cmd.upmove);
if( dir.x > 0 ) {
projStr = "projectile_plasmaf";
fireDelay = 0.1f;
}
if( dir.x < 0 ) {
spread = DEG2RAD(10);
fireDelay = 0.08f;
projStr = "projectile_plasmab";
}
if( dir.y != 0 ) {
spread *= 0.4f;
yawSpread +=8;
}
if( dir.z < 0 ) { //crouch
spread = DEG2RAD(0);
fireDelay = 1.0f;
projStr = "projectile_plasmac";
}
if( !owner->AI_ONGROUND ) { //jump
fireDelay = 0.06f;
projStr = "projectile_plasmaj";
}
projectile = gameLocal.FindEntityDefDict( projStr, false );
return hhWeaponFireController::LaunchProjectiles( pushVelocity );
}
/***********************************************************************
hhWeaponSoulStripper
***********************************************************************/
//const idEventDef EV_DamageBeamTarget( "<damageBeamTarget>", NULL );
const idEventDef EV_GetAnimPostFix( "getAnimPostfix", "", 's' );
const idEventDef EV_Leech( "leech", NULL, 'd' );
const idEventDef EV_EndLeech( "endLeech", NULL, 'f' );
const idEventDef EV_LightFadeIn( "<lightFadeIn>", "f" );
const idEventDef EV_LightFadeOut( "<lightFadeOut>", "f" );
const idEventDef EV_LightFade( "lightFade", "fff" );
const idEventDef EV_GetFireFunction( "getFireFunction", NULL, 's' );
CLASS_DECLARATION( hhWeapon, hhWeaponSoulStripper )
EVENT( EV_PostSpawn, hhWeaponSoulStripper::Event_PostSpawn )
EVENT( EV_GetAnimPostFix, hhWeaponSoulStripper::Event_GetAnimPostFix )
EVENT( EV_Leech, hhWeaponSoulStripper::Event_Leech )
EVENT( EV_EndLeech, hhWeaponSoulStripper::Event_EndLeech )
EVENT( AI_PlayAnim, hhWeaponSoulStripper::Event_PlayAnim )
EVENT( AI_PlayCycle, hhWeaponSoulStripper::Event_PlayCycle )
EVENT( EV_LightFadeIn, hhWeaponSoulStripper::Event_LightFadeIn )
EVENT( EV_LightFadeOut, hhWeaponSoulStripper::Event_LightFadeOut )
EVENT( EV_LightFade, hhWeaponSoulStripper::Event_LightFade )
EVENT( EV_GetFireFunction, hhWeaponSoulStripper::Event_GetFireFunction )
EVENT( EV_KillBeam, hhWeaponSoulStripper::Event_KillBeam )
END_CLASS
//=============================================================================
//
// hhWeaponSoulStripper::hhWeaponSoulStripper
//
//=============================================================================
hhWeaponSoulStripper::hhWeaponSoulStripper() {
// Initialize SFX on the weapon
beam = NULL; // Beam is properly spawned in PostSpawn
beamCanA1 = NULL; // Beam is properly spawned in PostSpawn
beamCanB1 = NULL; // Beam is properly spawned in PostSpawn
beamCanC1 = NULL; // Beam is properly spawned in PostSpawn
beamCanA2 = NULL; // Beam is properly spawned in PostSpawn
beamCanB2 = NULL; // Beam is properly spawned in PostSpawn
beamCanC2 = NULL; // Beam is properly spawned in PostSpawn
beamCanA3 = NULL; // Beam is properly spawned in PostSpawn
beamCanB3 = NULL; // Beam is properly spawned in PostSpawn
beamCanC3 = NULL; // Beam is properly spawned in PostSpawn
cansValid = false;
fxCanA = NULL;
fxCanB = NULL;
fxCanC = NULL;
targetTime = 0;
fcDeclNum = 0;
netInitialized = false;
//HUMANHEAD PCF mdl 05/04/06 - Initialize beamLightHandle here
beamLightHandle = -1;
}
//=============================================================================
//
// hhWeaponSoulStripper::Spawn
//
//=============================================================================
void hhWeaponSoulStripper::Spawn() {
BecomeActive( TH_TICKER );
fl.clientEvents = true; //rww
}
//=============================================================================
//
// hhWeaponSoulStripper::ParseDef
//
//=============================================================================
void hhWeaponSoulStripper::ParseDef( const char *objectname ) {
hhWeapon::ParseDef( objectname );
maxBeamLength = dict->GetFloat( "maxBeamLength", "1024" );
// Initialize weapon logic
targetNode = NULL;
beamLength = 0.0f;
if (gameLocal.isMultiplayer)
{ //rww - then do postspawn now.
Event_PostSpawn();
}
else
{ // Spawn the beams and SFX
PostEventMS( &EV_PostSpawn, 0 );
}
}
//=============================================================================
//
// hhWeaponSoulStripper::Event_PostSpawn
//
//=============================================================================
void hhWeaponSoulStripper::Event_PostSpawn() { //rww - note that this function can get called more than once in a leechgun's life time in mp on the client.
idVec3 boneOrigin;
idMat3 boneAxis;
GetJointWorldTransform( dict->GetString("attach_beam"), boneOrigin, boneAxis);
if (!beam.IsValid()) {
beam = hhBeamSystem::SpawnBeam( boneOrigin, dict->GetString( "beam_stripper" ), boneAxis, true );
if ( beam.IsValid() ) {
beam->Activate( false );
}
}
DestroyCans();
SpawnCans();
// Spawn beam light
memset( &beamLight, 0, sizeof( beamLight ) );
beamLight.lightId = LIGHTID_VIEW_MUZZLE_FLASH + owner->entityNumber;
beamLight.origin = GetOrigin();
beamLight.axis = GetAxis();
beamLight.pointLight = true;
beamLight.shader = declManager->FindMaterial( dict->GetString( "mtr_light" ) );
beamLight.shaderParms[ SHADERPARM_RED ] = 1.0f;
beamLight.shaderParms[ SHADERPARM_GREEN ] = 1.0f;
beamLight.shaderParms[ SHADERPARM_BLUE ] = 1.0f;
beamLight.shaderParms[ SHADERPARM_TIMESCALE ] = 1.0f;
beamLight.lightRadius[0] = 115;
beamLight.lightRadius[1] = 115;
beamLight.lightRadius[2] = 1;
//HUMANHEAD PCF mdl 05/04/06 - Moved this to the constructor
//beamLightHandle = -1;
const idDict *energyDef;
const char* str = owner->inventory.energyType;
if ( !str || !str[0] )
return;
energyDef = gameLocal.FindEntityDefDict( str );
if ( !energyDef )
return;
if (gameLocal.isClient) { //rww - do the minimal fireController update for the client here.
const idDeclEntityDef *fcDecl = gameLocal.FindEntityDef( energyDef->GetString("def_fireInfo"), false );
if (fcDecl) {
const char *fcSpawnClass = fcDecl->dict.GetString("spawnclass", NULL);
if (!fcSpawnClass || !fcSpawnClass[0]) {
fcSpawnClass = "hhWeaponFireController"; //default to regular fire controller
}
idTypeInfo *cls = idClass::GetClass(fcSpawnClass);
if (cls) {
ClientUpdateFC(cls->typeNum, fcDecl->Index());
}
}
}
else {
GiveEnergy( energyDef->GetString("def_fireInfo"), false );
}
}
void hhWeaponSoulStripper::CheckCans(void) {
bool wantCans = true;
if (owner.IsValid() && owner->entityNumber != gameLocal.localClientNum) { //rww - we don't need cannister fx unless we are the client that owns this weapon. (or spectating him)
if ( gameLocal.localClientNum >= 0 && gameLocal.entities[ gameLocal.localClientNum ] && gameLocal.entities[ gameLocal.localClientNum ]->IsType( idPlayer::Type ) ) {
idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ gameLocal.localClientNum ] );
if ( !p->spectating || p->spectator != owner->entityNumber ) {
wantCans = false;
}
} else {
wantCans = false;
}
}
if (wantCans != cansValid) {
DestroyCans();
if (wantCans) {
SpawnCans();
}
}
}
void hhWeaponSoulStripper::SpawnCans() {
if (owner.IsValid() && owner->entityNumber != gameLocal.localClientNum) { //rww - we don't need cannister fx unless we are the client that owns this weapon. (or spectating him)
if ( gameLocal.localClientNum >= 0 && gameLocal.entities[ gameLocal.localClientNum ] && gameLocal.entities[ gameLocal.localClientNum ]->IsType( idPlayer::Type ) ) {
idPlayer *p = static_cast< idPlayer * >( gameLocal.entities[ gameLocal.localClientNum ] );
if ( !p->spectating || p->spectator != owner->entityNumber ) {
return;
}
} else {
return;
}
}
// Spawn individual canister beams (top to center)
beamCanA1 = SpawnCanisterBeam( "attach_topA", "attach_soulA", beam_canTop );
beamCanB1 = SpawnCanisterBeam( "attach_topB", "attach_soulB", beam_canTop );
beamCanC1 = SpawnCanisterBeam( "attach_topC", "attach_soulC", beam_canTop );
// Spawn individual canister beams (bottom to center)
beamCanA2 = SpawnCanisterBeam( "attach_bottomA", "attach_soulA", beam_canBot );
beamCanB2 = SpawnCanisterBeam( "attach_bottomB", "attach_soulB", beam_canBot );
beamCanC2 = SpawnCanisterBeam( "attach_bottomC", "attach_soulC", beam_canBot );
// Spawn individual canister beams (faint bottom to top glow)
beamCanA3 = SpawnCanisterBeam( "attach_bottomA", "attach_topA", beam_canGlow );
beamCanB3 = SpawnCanisterBeam( "attach_bottomB", "attach_topB", beam_canGlow );
beamCanC3 = SpawnCanisterBeam( "attach_bottomC", "attach_topC", beam_canGlow );
fxCanA = SpawnCanisterFx( "attach_bottomA", fx_can );
fxCanB = SpawnCanisterFx( "attach_bottomB", fx_can );
fxCanC = SpawnCanisterFx( "attach_bottomC", fx_can );
cansValid = true;
}
void hhWeaponSoulStripper::DestroyCans() {
SAFE_REMOVE( beamCanA1 );
SAFE_REMOVE( beamCanB1 );
SAFE_REMOVE( beamCanC1 );
SAFE_REMOVE( beamCanA2 );
SAFE_REMOVE( beamCanB2 );
SAFE_REMOVE( beamCanC2 );
SAFE_REMOVE( beamCanA3 );
SAFE_REMOVE( beamCanB3 );
SAFE_REMOVE( beamCanC3 );
SAFE_REMOVE( fxCanA );
SAFE_REMOVE( fxCanB );
SAFE_REMOVE( fxCanC );
cansValid = false;
}
//=============================================================================
//
// hhWeaponSoulStripper::SpawnCanisterBeam
//
//=============================================================================
hhBeamSystem *hhWeaponSoulStripper::SpawnCanisterBeam( const char *bottom, const char *top, const idStr &beamName ) {
hhBeamSystem *system = NULL;
idVec3 boneOrigin;
idMat3 boneAxis;
if( beamName.IsEmpty() )
return NULL;
GetJointWorldTransform( dict->GetString(bottom), boneOrigin, boneAxis);
system = hhBeamSystem::SpawnBeam( boneOrigin, beamName, boneAxis, true );
if ( !system ) {
return NULL;
}
if (owner.IsValid()) {
system->snapshotOwner = owner.GetEntity(); //rww
}
GetJointWorldTransform( dict->GetString(top), boneOrigin, boneAxis);
system->SetTargetLocation( boneOrigin );
system->GetRenderEntity()->weaponDepthHack = true;
system->GetRenderEntity()->allowSurfaceInViewID = owner->entityNumber+1;
system->fl.neverDormant = true;
return system;
}
//=============================================================================
//
// hhWeaponSoulStripper::SpawnCanisterSprite
//
//=============================================================================
idEntity *hhWeaponSoulStripper::SpawnCanisterSprite( const char *attach, const char *spriteName ) {
idEntity *ent;
const char *jointName;
assert(gameLocal.isMultiplayer); //rww - i don't see this being used in mp, but if it is, it needs to be reworked.
jointName = dict->GetString( attach );
ent = gameLocal.SpawnObject( dict->GetString( spriteName ) );
if ( ent ) {
ent->MoveToJoint( this, jointName );
ent->BindToJoint( this, jointName, false );
ent->GetRenderEntity()->weaponDepthHack = true;
}
return ent;
}
hhEntityFx* hhWeaponSoulStripper::SpawnCanisterFx( const char *attach, const idStr &name ) {
const char *jointName;
idVec3 boneOrigin;
idMat3 boneAxis;
hhEntityFx* fx;
if( name.IsEmpty() )
return NULL;
jointName = dict->GetString( attach );
GetJointWorldTransform( dict->GetString(attach), boneOrigin, boneAxis);
hhFxInfo fxInfo;
fxInfo.SetEntity( this );
fxInfo.SetBindBone( jointName );
fx = SpawnFxLocal( name, boneOrigin, boneAxis, &fxInfo, true );
fx->GetRenderEntity()->weaponDepthHack = true;
fx->GetRenderEntity()->allowSurfaceInViewID = owner->entityNumber+1;
//don't attach canister fx to snapshotOwner, since they are local and temporary
/*
if (owner.IsValid()) {
fx->snapshotOwner = owner.GetEntity(); //rww
}
*/
return fx;
}
//=============================================================================
//
// hhWeaponSoulStripper::CreateAltFireController
//
//=============================================================================
hhWeaponFireController* hhWeaponSoulStripper::CreateAltFireController() {
return hhWeapon::CreateAltFireController();
//return new hhSoulStripperAltFireController;
}
//=============================================================================
//
// hhWeaponSoulStripper::~hhWeaponSoulStripper
//
//=============================================================================
hhWeaponSoulStripper::~hhWeaponSoulStripper() {
SAFE_REMOVE( beam );
DestroyCans();
// Remove the beam light
if ( beamLightHandle != -1 ) {
gameRenderWorld->FreeLightDef( beamLightHandle );
beamLightHandle = -1;
}
StopSound( SND_CHANNEL_WEAPON, false ); //rww - don't broadcast this. you're removing the entity on the client too, so not only would it get
//called there too, but once you receive the event the entity will be gone and it will be tossed.
}
//=============================================================================
//
// hhWeaponSoulStripper::UpdateGUI
//
//=============================================================================
void hhWeaponSoulStripper::UpdateGUI() {
if ( renderEntity.gui[0] ) {
renderEntity.gui[0]->SetStateInt( "souls", (GetAnimPostfix()>0) ? GetAnimPostfix()-'A'+1 : 0 );
float p = 3.0f * owner->inventory.AmmoPercentage(owner.GetEntity(), GetAmmoType());
renderEntity.gui[0]->SetStateFloat( "soulpercentageA", idMath::ClampFloat(0.0f, 1.0f, p - 0.0f) );
renderEntity.gui[0]->SetStateFloat( "soulpercentageB", idMath::ClampFloat(0.0f, 1.0f, p - 1.0f) );
renderEntity.gui[0]->SetStateFloat( "soulpercentageC", idMath::ClampFloat(0.0f, 1.0f, p - 2.0f) );
renderEntity.gui[0]->SetStateBool( "leeching", (targetNode) ? true : false);
const char* str;
if( targetNode ) {
const idDict *energyDef;
str = targetNode->spawnArgs.GetString( "def_energy" );
if ( str && str[0] ) {
energyDef = gameLocal.FindEntityDefDict( str );
if ( energyDef ) {
renderEntity.gui[0]->SetStateFloat( "meter", (gameLocal.time - targetTime)/energyDef->GetFloat( "leech_time", "500" ) );
renderEntity.gui[0]->SetStateInt( "leechtype", energyDef->GetInt("beamType")+1 );
}
}
}
if( fireController ) {
str = fireController->GetString("intgui");
if( str && str[0] )
renderEntity.gui[0]->SetStateInt( "type", str[0]-'1'+1 );
}
else {
renderEntity.gui[0]->SetStateInt( "type", 0 );
}
}
}
void hhWeaponSoulStripper::Event_Leech() {
idVec3 start, end;
trace_t results;
int captured = 0;
if ( !beam.IsValid() ) {
idThread::ReturnInt( 0 );
return;
}
start = GetOrigin();
// Currently latched onto a target, check to see if the target is within the valid cone and there is still a LOS to the target
if ( targetNode ) {
end = beam->GetTargetLocation();
// Verify that the target is within a cone in front of the weapon
idVec3 vecToTarget = end - start;
vecToTarget.Normalize();
float dpX = GetAxis()[0] * vecToTarget;
float dpY = GetAxis()[1] * vecToTarget;
// Target isn't in the cone, so reset the trace
if ( idMath::Fabs( dpY ) >= spawnArgs.GetFloat( "beamTargetAngle", "0.4" ) || !targetNode->CanLeech() ) {
//ReleaseEntity();
targetNode->LeechTrigger(GetOwner(),"leech_end");
targetNode = NULL;
end = start + maxBeamLength * GetAxis()[0];
}
}
else
end = start + maxBeamLength * GetAxis()[0];
// Check to see if the beam should attempt to hit something
if (owner.IsValid()) {
//rww - can hit owners due to different angles in mp (although not the local client since the trace is done on the client every frame)
gameLocal.clip.TracePoint( results, start, end, MASK_SHOT_RENDERMODEL | CONTENTS_GAME_PORTAL, owner.GetEntity() );
}
else {
gameLocal.clip.TracePoint( results, start, end, MASK_SHOT_RENDERMODEL | CONTENTS_GAME_PORTAL, this );
}
beamLength = (results.endpos - start).Length();
// Hit something
if ( results.fraction < 1.0f ) {
captured = CaptureEnergy( results );
// Update the main beam
UpdateBeam( start, true ); // struck an entity
}
//if( owner.IsValid() ) {
// owner->WeaponFireFeedback( dict );
//}
// Return true if the beam has struck an entity
idThread::ReturnFloat( (float)captured );
}
//=============================================================================
//
// hhWeaponSoulStripper::Event_RecoilBeam
//
//=============================================================================
void hhWeaponSoulStripper::Event_EndLeech() {
idVec3 start;
idMat3 axis;
if ( !beam.IsValid() ) {
return;
}
if ( targetNode )
targetNode->LeechTrigger(GetOwner(),"leech_end");
targetNode = NULL;
// Update the main beam
UpdateBeam( start, false );
if( owner.IsValid() ) {
owner->WeaponFireFeedback( dict );
}
idThread::ReturnFloat( 0 );
}
//=============================================================================
//
// hhWeaponSoulStripper::Ticker
//
// Controls the length of the beam and firing projectiles
//=============================================================================
void hhWeaponSoulStripper::Ticker() {
// Update canister beams
UpdateCanisterBeam( beamCanA1.GetEntity(), "attach_topA", "attach_soulA" );
UpdateCanisterBeam( beamCanB1.GetEntity(), "attach_topB", "attach_soulB" );
UpdateCanisterBeam( beamCanC1.GetEntity(), "attach_topC", "attach_soulC" );
UpdateCanisterBeam( beamCanA2.GetEntity(), "attach_bottomA", "attach_soulA" );
UpdateCanisterBeam( beamCanB2.GetEntity(), "attach_bottomB", "attach_soulB" );
UpdateCanisterBeam( beamCanC2.GetEntity(), "attach_bottomC", "attach_soulC" );
UpdateCanisterBeam( beamCanA3.GetEntity(), "attach_bottomA", "attach_topA" );
UpdateCanisterBeam( beamCanB3.GetEntity(), "attach_bottomB", "attach_topB" );
UpdateCanisterBeam( beamCanC3.GetEntity(), "attach_bottomC", "attach_topC" );
hhBeamBasedFireController *beamController;
hhSunbeamFireController *sun;
if ( fireController && fireController->IsType(hhBeamBasedFireController::Type) ) {
if ( fireController->IsType(hhSunbeamFireController::Type) ) {
sun = static_cast<hhSunbeamFireController *>(fireController);
sun->Think();
}
else {
beamController = static_cast<hhBeamBasedFireController *>(fireController);
beamController->Think();
}
}
// Update our current animation if cans changed
if ( GetAnimPostfix() != lastCanState ) {
if ( GetAnimator()->IsAnimating( gameLocal.time ) && lastAnim.Length() != 0 ) {
idStr animname = lastAnim;
animname.Append( GetAnimPostfix() );
int anim = GetAnimator()->GetAnim( animname );
if( anim )
GetAnimator()->CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS(4) );
}
lastCanState = GetAnimPostfix();
}
}
//=============================================================================
//
// hhWeaponSoulStripper::UpdateBeam
//
// Updates the beam system
// - beam length
// - scale issues (don't let the beam wiggle as wildly when it is pulled close)
// - beam light
//=============================================================================
void hhWeaponSoulStripper::UpdateBeam( idVec3 start, bool struckEntity ) {
float scale;
idVec3 boneOrigin;
idMat3 boneAxis;
if ( !beam.IsValid() ) {
return;
}
if ( targetNode ) {
beam->Activate( true );
GetJointWorldTransform( dict->GetString("attach_beam"), boneOrigin, boneAxis);
beam->SetOrigin( boneOrigin );
beam->SetArcVector( GetAxis()[0] );
scale = beamLength / 150.0f;
if( scale > 1 ) {
scale = 1;
}
if ( targetNode->entityNumber < ENTITYNUM_MAX_NORMAL ) {
beam->SetTargetLocation( targetNode->leechPoint );
}
int beamType=0;
const idDict *energyDef;
const char* str = targetNode->spawnArgs.GetString( "def_energy" );
if ( str && str[0] ) {
energyDef = gameLocal.FindEntityDefDict( str );
if ( energyDef )
beamType=energyDef->GetInt("beamType");
}
beam->SetShaderParm( SHADERPARM_MODE, beamType );
beamLight.shaderParms[ SHADERPARM_MODE ] = beamType;
beam->SetBeamOffsetScale( scale );
// Update the beam light
beamLight.axis[0] = GetAxis()[2];
beamLight.axis[1] = GetAxis()[1];
beamLight.axis[2] = GetAxis()[0]; // Re-align the light to point along the beam
beamLight.origin = (GetOrigin() + GetAxis()[0] * beamLength * 0.25f); // Set beam origin to the midpoint of the weapon origin and the target
beamLight.lightRadius[2] = 128.0f + beamLength * 0.5f; // Scale the light size based upon the beam (larger than half, so the beam extends beyond the extents slightly)
if ( beamLightHandle != -1 ) {
gameRenderWorld->UpdateLightDef( beamLightHandle, &beamLight );
} else {
beamLightHandle = gameRenderWorld->AddLightDef( &beamLight );
}
} else {
beam->Activate( false );
// Hide the beam light
if ( beamLightHandle != -1 ) {
gameRenderWorld->FreeLightDef( beamLightHandle );
beamLightHandle = -1;
}
}
}
//=============================================================================
//
// hhWeaponSoulStripper::UpdateCanisterBeam
//
//=============================================================================
void hhWeaponSoulStripper::UpdateCanisterBeam( hhBeamSystem *system, const char *top, const char *bottom ) {
idVec3 boneOrigin;
idMat3 boneAxis;
if ( !system ) {
return;
}
GetJointWorldTransform( dict->GetString( top ), boneOrigin, boneAxis);
system->SetTargetLocation( boneOrigin );
GetJointWorldTransform( dict->GetString( bottom ), boneOrigin, boneAxis);
system->SetOrigin( boneOrigin );
}
//=============================================================================
//
// hhWeaponSoulStripper::CaptureEnergy
//
//=============================================================================
int hhWeaponSoulStripper::CaptureEnergy( trace_t &results ) {
idEntity *hitEntity;
hhEnergyNode* hitNode;
hitEntity = gameLocal.GetTraceEntity(results);
if ( hitEntity && hitEntity->IsType( hhEnergyNode::Type ) ) {
hitNode = static_cast<hhEnergyNode*>(hitEntity);
if ( !hitNode->CanLeech() )
return 0;
}
else {
if ( targetNode )
targetNode->LeechTrigger(GetOwner(),"leech_end");
targetNode = NULL;
return 0;
}
if ( targetNode != hitNode ) {
if ( targetNode )
targetNode->LeechTrigger(GetOwner(),"leech_end");
targetTime = gameLocal.time;
targetNode = hitNode;
targetNode->LeechTrigger(GetOwner(),"leech_start");
}
const idDict *energyDef;
const char* str = targetNode->spawnArgs.GetString( "def_energy" );
if ( !str || !str[0] )
return 0; // blank node
energyDef = gameLocal.FindEntityDefDict( str );
if ( !energyDef )
return 0;
if ( gameLocal.time - targetTime < energyDef->GetInt( "leech_time", "500" ) )
return 1; //not enough time
targetNode->LeechTrigger(GetOwner(),"leech_success");
targetNode->Finish();
targetTime = gameLocal.time;
//create new firecontroller for new energy type
if( !GiveEnergy( energyDef->GetString("def_fireInfo"), true ) )
return 0;
StartSound( "snd_intake", SND_CHANNEL_ANY );
SpawnCanisterFx( "attach_sidevent", spawnArgs.GetString("fx_sidevent") );
SpawnCanisterFx( "attach_steam", spawnArgs.GetString("fx_steam") );
owner->inventory.energyType = str;
return 2;
}
bool hhWeaponSoulStripper::GiveEnergy( const char *energyType, bool fill ) {
if ( !energyType || !energyType[0] )
return false;
//create new firecontroller for new energy type
if (gameLocal.isClient) //rww - handle this properly through snapshots
return true;
SAFE_DELETE_PTR(fireController);
const idDeclEntityDef *fcDecl = gameLocal.FindEntityDef( energyType, false );
const idDict* infoDict = fcDecl ? &fcDecl->dict : NULL;
fcDeclNum = 0;
if( infoDict ) {
const char *spawn;
idTypeInfo *cls;
if( fill ) {
int num = owner->GetWeaponNum("weaponobj_soulstripper");
assert(num);
owner->weaponInfo[ num ].ammoMax = infoDict->GetInt("ammoAmount");
owner->spawnArgs.SetInt( "max_ammo_energy", infoDict->GetInt("ammoAmount") );
owner->inventory.ammo[owner->inventory.AmmoIndexForAmmoClass("ammo_energy")]=0;
owner->Give( "ammo_energy", infoDict->GetString("ammoAmount") );
}
beam_canTop = infoDict->GetString( "beam_canTop" );
beam_canBot = infoDict->GetString( "beam_canBot" );
beam_canGlow = infoDict->GetString( "beam_canGlow" );
fx_can = infoDict->GetString( "fx_can" );
DestroyCans();
SpawnCans();
infoDict->GetString( "spawnclass", NULL, &spawn );
if ( !spawn || !spawn[0] ) { //rww - changed to be in line with client behavior
spawn = "hhWeaponFireController"; //default to regular fire controller
}
cls = idClass::GetClass( spawn );
if ( !cls || !cls->IsType( hhWeaponFireController::Type ) ) {
common->Warning( "Could not spawn. Class '%s' not found.", spawn );
return false;
}
fireController = static_cast<hhWeaponFireController *>( cls->CreateInstance() );
if ( !fireController ) {
common->Warning( "Could not spawn '%s'. Instance could not be created.", spawn );
return false;
}
fcDeclNum = fcDecl->Index();
/*
else {
fireController = CreateFireController();
}
*/
fireController->Init( infoDict, this, owner.GetEntity() );
}
//if it failed, use generic empty controller
if ( !fireController ) {
const idDict* infoDict = gameLocal.FindEntityDefDict( spawnArgs.GetString("def_fireInfo"), false );
if( infoDict ) {
fireController = CreateFireController();
fireController->Init( infoDict, this, owner.GetEntity() );
}
}
return true;
}
//=============================================================================
//
// hhWeaponSoulStripper::GetAnimPostfix
//
// Appends to the passed in postfix.
//=============================================================================
char hhWeaponSoulStripper::GetAnimPostfix() {
// Choose the anim postfix based upon ammo
float p=owner->inventory.AmmoPercentage(owner.GetEntity(), GetAmmoType());
if(p > 0)
return (int)(2.9f*p) + 'A';
else
return 0;
}
//=============================================================================
//
// hhWeaponSoulStripper::Event_GetAnimPostFix
//
//=============================================================================
void hhWeaponSoulStripper::Event_GetAnimPostFix() {
idStr postfix( GetAnimPostfix() );
idThread::ReturnString( postfix.c_str() );
}
//=============================================================================
//
// hhWeaponSoulStripper::Event_PlayAnim
//
//=============================================================================
void hhWeaponSoulStripper::Event_PlayAnim( int channel, const char *animname ) {
lastAnim = "";
idStr anim = animname;
anim.Append( GetAnimPostfix() );
hhWeapon::Event_PlayAnim( channel, anim.c_str() );
}
//=============================================================================
//
// hhWeaponSoulStripper::Event_PlayCycle
//
//=============================================================================
void hhWeaponSoulStripper::Event_PlayCycle( int channel, const char *animname ) {
lastAnim = animname;
idStr anim = animname;
anim.Append( GetAnimPostfix() );
hhWeapon::Event_PlayCycle( channel, anim.c_str() );
}
//=============================================================================
//
// hhWeaponSoulStripper::PresentWeapon
//
//=============================================================================
void hhWeaponSoulStripper::PresentWeapon( bool showViewModel ) {
if ( IsHidden() || !owner->CanShowWeaponViewmodel() || pm_thirdPerson.GetBool() ) {
if ( beamCanA1.IsValid() ) beamCanA1->Activate( false );
if ( beamCanB1.IsValid() ) beamCanB1->Activate( false );
if ( beamCanC1.IsValid() ) beamCanC1->Activate( false );
if ( beamCanA2.IsValid() ) beamCanA2->Activate( false );
if ( beamCanB2.IsValid() ) beamCanB2->Activate( false );
if ( beamCanC2.IsValid() ) beamCanC2->Activate( false );
if ( beamCanA3.IsValid() ) beamCanA3->Activate( false );
if ( beamCanB3.IsValid() ) beamCanB3->Activate( false );
if ( beamCanC3.IsValid() ) beamCanC3->Activate( false );
if ( fxCanA.IsValid() ) fxCanA->Hide();
if ( fxCanB.IsValid() ) fxCanB->Hide();
if ( fxCanC.IsValid() ) fxCanC->Hide();
} else {
if ( beamCanA1.IsValid() ) beamCanA1->Activate( true );
if ( beamCanB1.IsValid() ) beamCanB1->Activate( true );
if ( beamCanC1.IsValid() ) beamCanC1->Activate( true );
if ( beamCanA2.IsValid() ) beamCanA2->Activate( true );
if ( beamCanB2.IsValid() ) beamCanB2->Activate( true );
if ( beamCanC2.IsValid() ) beamCanC2->Activate( true );
if ( beamCanA3.IsValid() ) beamCanA3->Activate( true );
if ( beamCanB3.IsValid() ) beamCanB3->Activate( true );
if ( beamCanC3.IsValid() ) beamCanC3->Activate( true );
if ( fxCanA.IsValid() ) fxCanA->Show();
if ( fxCanB.IsValid() ) fxCanB->Show();
if ( fxCanC.IsValid() ) fxCanC->Show();
}
hhWeapon::PresentWeapon( showViewModel );
}
//=============================================================================
//
// hhWeaponSoulStripper::Show
//
//=============================================================================
void hhWeaponSoulStripper::Show() {
if ( beamCanA1.IsValid() ) beamCanA1->Show();
if ( beamCanB1.IsValid() ) beamCanB1->Show();
if ( beamCanC1.IsValid() ) beamCanC1->Show();
if ( beamCanA2.IsValid() ) beamCanA2->Show();
if ( beamCanB2.IsValid() ) beamCanB2->Show();
if ( beamCanC2.IsValid() ) beamCanC2->Show();
if ( beamCanA3.IsValid() ) beamCanA3->Show();
if ( beamCanB3.IsValid() ) beamCanB3->Show();
if ( beamCanC3.IsValid() ) beamCanC3->Show();
if ( fxCanA.IsValid() ) fxCanA->Show();
if ( fxCanB.IsValid() ) fxCanB->Show();
if ( fxCanC.IsValid() ) fxCanC->Show();
hhWeapon::Show();
}
//=============================================================================
//
// hhWeaponSoulStripper::Hide
//
//=============================================================================
void hhWeaponSoulStripper::Hide() {
if ( beamCanA1.IsValid() ) beamCanA1->Hide();
if ( beamCanB1.IsValid() ) beamCanB1->Hide();
if ( beamCanC1.IsValid() ) beamCanC1->Hide();
if ( beamCanA2.IsValid() ) beamCanA2->Hide();
if ( beamCanB2.IsValid() ) beamCanB2->Hide();
if ( beamCanC2.IsValid() ) beamCanC2->Hide();
if ( beamCanA3.IsValid() ) beamCanA3->Hide();
if ( beamCanB3.IsValid() ) beamCanB3->Hide();
if ( beamCanC3.IsValid() ) beamCanC3->Hide();
if ( fxCanA.IsValid() ) fxCanA->Hide();
if ( fxCanB.IsValid() ) fxCanB->Hide();
if ( fxCanC.IsValid() ) fxCanC->Hide();
hhWeapon::Hide();
}
/*
================
hhWeaponSoulStripper::Save
================
*/
void hhWeaponSoulStripper::Save( idSaveGame *savefile ) const {
savefile->WriteRenderLight( beamLight );
//HUMANHEAD PCF mdl 05/04/06 - Don't save light handles
//savefile->WriteInt( beamLightHandle );
beam.Save( savefile );
beamCanA1.Save( savefile );
beamCanB1.Save( savefile );
beamCanC1.Save( savefile );
beamCanA2.Save( savefile );
beamCanB2.Save( savefile );
beamCanC2.Save( savefile );
beamCanA3.Save( savefile );
beamCanB3.Save( savefile );
beamCanC3.Save( savefile );
fxCanA.Save( savefile );
fxCanB.Save( savefile );
fxCanC.Save( savefile );
savefile->WriteBool(cansValid);
savefile->WriteFloat( beamLength );
savefile->WriteFloat( maxBeamLength );
savefile->WriteObject( targetNode );
savefile->WriteVec3( targetOffset );
savefile->WriteString( lastAnim );
// savefile->WriteInt( lastAltAmmo );
}
/*
================
hhWeaponSoulStripper::Restore
================
*/
void hhWeaponSoulStripper::Restore( idRestoreGame *savefile ) {
savefile->ReadRenderLight( beamLight );
//HUMANHEAD PCF mdl 05/04/06 - Don't save light handles
//savefile->ReadInt( beamLightHandle );
beam.Restore( savefile );
beamCanA1.Restore( savefile );
beamCanB1.Restore( savefile );
beamCanC1.Restore( savefile );
beamCanA2.Restore( savefile );
beamCanB2.Restore( savefile );
beamCanC2.Restore( savefile );
beamCanA3.Restore( savefile );
beamCanB3.Restore( savefile );
beamCanC3.Restore( savefile );
fxCanA.Restore( savefile );
fxCanB.Restore( savefile );
fxCanC.Restore( savefile );
savefile->ReadBool(cansValid);
savefile->ReadFloat( beamLength );
savefile->ReadFloat( maxBeamLength );
savefile->ReadObject( reinterpret_cast<idClass *&> ( targetNode ) );
savefile->ReadVec3( targetOffset );
savefile->ReadString( lastAnim );;
}
/*
=================
hhWeaponSoulStripper::ReadFromSnapshot
rww - update the fire controller on the client
=================
*/
void hhWeaponSoulStripper::ClientUpdateFC(int fcType, int fcDefNumber) {
SAFE_DELETE_PTR(fireController);
idTypeInfo *typeInfo = idClass::GetType(fcType);
const idDeclEntityDef *fcDecl = static_cast<const idDeclEntityDef *>(declManager->DeclByIndex(DECL_ENTITYDEF, fcDefNumber, false));
if (typeInfo && fcDecl) {
int num = owner->GetWeaponNum("weaponobj_soulstripper");
assert(num);
owner->weaponInfo[ num ].ammoMax = fcDecl->dict.GetInt("ammoAmount");
owner->spawnArgs.SetInt( "max_ammo_energy", fcDecl->dict.GetInt("ammoAmount") );
beam_canTop = fcDecl->dict.GetString( "beam_canTop" );
beam_canBot = fcDecl->dict.GetString( "beam_canBot" );
beam_canGlow = fcDecl->dict.GetString( "beam_canGlow" );
fx_can = fcDecl->dict.GetString( "fx_can" );
DestroyCans();
SpawnCans();
fireController = static_cast<hhWeaponFireController *>(typeInfo->CreateInstance());
if (fireController) {
fireController->Init(&fcDecl->dict, this, owner.GetEntity());
}
}
}
/*
=================
hhWeaponSoulStripper::WriteToSnapshot
rww - write applicable weapon values to snapshot
=================
*/
void hhWeaponSoulStripper::WriteToSnapshot( idBitMsgDelta &msg ) const {
//target entity
if (targetNode) {
msg.WriteBits(1, 1);
msg.WriteBits(targetNode->entityNumber, GENTITYNUM_BITS);
}
else {
msg.WriteBits(0, 1);
}
//write the fire controller type
if (fireController) {
msg.WriteBits(fireController->GetType()->typeNum, idClass::GetTypeNumBits());
msg.WriteBits(gameLocal.ServerRemapDecl(-1, DECL_ENTITYDEF, fcDeclNum ), gameLocal.entityDefBits);
}
else {
msg.WriteBits(0, idClass::GetTypeNumBits());
msg.WriteBits(0, gameLocal.entityDefBits);
}
hhWeapon::WriteToSnapshot(msg);
}
/*
=================
hhWeaponSoulStripper::ReadFromSnapshot
rww - read applicable weapon values from snapshot
=================
*/
void hhWeaponSoulStripper::ReadFromSnapshot( const idBitMsgDelta &msg ) {
//target entity
bool hasEnt = !!msg.ReadBits(1);
if (hasEnt) {
int entNum = msg.ReadBits(GENTITYNUM_BITS);
targetNode = static_cast<hhEnergyNode*>(gameLocal.entities[entNum]);
}
else {
targetNode = NULL;
}
int fcType = msg.ReadBits(idClass::GetTypeNumBits());
int fcDefNumber = gameLocal.ClientRemapDecl(DECL_ENTITYDEF, msg.ReadBits(gameLocal.entityDefBits));
//standard weapon stuff (primarily done before switch logic to get owner)
hhWeapon::ReadFromSnapshot(msg);
if (owner.IsValid() && fcType && (!fireController || fcType != fireController->GetType()->typeNum || !netInitialized)) {
//if there is no fire controller on the client or the fire controller does not much the type given by the server, switch
ClientUpdateFC(fcType, fcDefNumber);
netInitialized = true;
}
}
/*
================
hhWeaponSoulStripper::GetClipBits
================
*/
int hhWeaponSoulStripper::GetClipBits(void) const {
return 12; //0-4096
}
void hhWeaponSoulStripper::Event_LightFadeIn( float fadetime ) {
if (gameLocal.isMultiplayer) { //rww - none of this in mp
return;
}
idEntity *ent;
idEntity *next;
idLight *light;
idVec3 color;
for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = next ) {
next = ent->spawnNode.Next();
if( !gameLocal.InPlayerPVS(ent) )
continue;
if ( !ent->IsType( idLight::Type ) )
continue;
light = static_cast<idLight*>( ent );
if ( light->GetMaterial()->IsFogLight() )
continue;
light->GetColor( color );
if ( color == idVec3(0.001f,0.f,0.f) )
light->FadeIn( fadetime );
}
}
void hhWeaponSoulStripper::Event_LightFadeOut( float fadetime ) {
if (gameLocal.isMultiplayer) { //rww - none of this in mp
return;
}
idEntity *ent;
idEntity *next;
idLight *light;
idVec3 color;
for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = next ) {
next = ent->spawnNode.Next();
if( !gameLocal.InPlayerPVS(ent) )
continue;
if ( !ent->IsType( idLight::Type ) )
continue;
light = static_cast<idLight*>( ent );
if ( light->GetMaterial()->IsFogLight() )
continue;
light->GetColor( color );
if( light->spawnArgs.GetVector("_color", "1 1 1") == color && light->GetCurrentLevel()==1 )
light->Fade(idVec4(0.001f,0.f,0.f,0.f), fadetime );
}
}
void hhWeaponSoulStripper::Event_LightFade( float fadeOut, float pause, float fadeIn ) {
PostEventSec( &EV_LightFadeOut, 0, fadeOut );
PostEventSec( &EV_LightFadeIn, pause, fadeIn );
}
void hhWeaponSoulStripper::Event_GetFireFunction() {
if ( fireController ) {
idThread::ReturnString( fireController->GetScriptFunction() );
}
}
void hhWeaponSoulStripper::Event_KillBeam() {
if ( fireController && fireController->IsType(hhBeamBasedFireController::Type) ) {
hhBeamBasedFireController *beamController = static_cast<hhBeamBasedFireController *>(fireController);
beamController->KillBeam();
}
}
/*void hhWeaponSoulStripper::Event_GetFireSound() {
if ( fireController ) {
idThread::ReturnString( fireController->GetScriptFunction() );
}
}*/