mirror of
https://github.com/blendogames/quadrilateralcowboy.git
synced 2024-11-24 04:51:31 +00:00
562 lines
No EOL
14 KiB
C++
562 lines
No EOL
14 KiB
C++
|
|
#include "../idlib/precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "Game_local.h"
|
|
|
|
#define TURN_TIME 300
|
|
#define SHOT_DELAY 350
|
|
|
|
const idEventDef EV_sentry_activate( "sentryactivate", "d" );
|
|
const idEventDef EV_sentry_issentryactive( "issentryactive", NULL, 'd' );
|
|
const idEventDef EV_sentry_turn( "sentryturn", "f" );
|
|
const idEventDef EV_sentry_pitch( "sentrypitch", "f" );
|
|
const idEventDef EV_sentry_face( "sentryface", "fff" );
|
|
const idEventDef EV_sentry_stand( "sentrystand" );
|
|
const idEventDef EV_sentry_fire( "sentryfire" );
|
|
const idEventDef EV_sentry_getlaser( "sentrygetlaser", NULL, 'v' );
|
|
const idEventDef EV_sentry_sentrykill( "sentrykill" );
|
|
|
|
CLASS_DECLARATION( idMoveableItem, idSentry )
|
|
|
|
EVENT( EV_sentry_activate, idSentry::Event_activate)
|
|
EVENT( EV_sentry_issentryactive, idSentry::Event_issentryactive)
|
|
EVENT( EV_sentry_turn, idSentry::Event_sentryturn)
|
|
EVENT( EV_sentry_pitch, idSentry::Event_sentrypitch)
|
|
EVENT( EV_sentry_face, idSentry::Event_sentryface)
|
|
EVENT( EV_sentry_fire, idSentry::Event_sentryfire)
|
|
EVENT( EV_sentry_stand, idSentry::Event_sentrystand)
|
|
EVENT( EV_sentry_getlaser, idSentry::Event_sentrygetlaser)
|
|
EVENT( EV_sentry_sentrykill, idSentry::Event_sentrykill)
|
|
|
|
END_CLASS
|
|
|
|
|
|
void idSentry::Spawn( void )
|
|
{
|
|
idDict args;
|
|
jointHandle_t muzzleJoint;
|
|
idVec3 muzzlePos;
|
|
idMat3 muzzleAxis;
|
|
idVec3 forward, right, up;
|
|
|
|
pitch = 0;
|
|
yaw = 0;
|
|
state = OFF;
|
|
|
|
BecomeActive( TH_THINK );
|
|
|
|
args.Clear();
|
|
args.SetVector( "origin", this->GetPhysics()->GetOrigin() );
|
|
args.Set( "model", "env_sentry" );
|
|
|
|
model = ( idAnimatedEntity * )gameLocal.SpawnEntityType( idAnimatedEntity::Type, &args );
|
|
model->Bind(this, true);
|
|
|
|
model->Event_PlayAnim( "closed", 4 );
|
|
|
|
|
|
//spawn beam end.
|
|
args.SetVector( "origin", vec3_origin );
|
|
beamEnd = ( idBeam * )gameLocal.SpawnEntityType( idBeam::Type, &args );
|
|
|
|
muzzleJoint = model->GetAnimator()->GetJointHandle( "muzzle" );
|
|
model->GetAnimator()->GetJointTransform( muzzleJoint, gameLocal.time, muzzlePos, muzzleAxis );
|
|
|
|
//spawn beam start.
|
|
args.Clear();
|
|
args.Set( "target", beamEnd->name.c_str() );
|
|
args.SetVector( "origin", muzzlePos + this->GetPhysics()->GetOrigin() );
|
|
args.SetBool( "start_off", true );
|
|
args.Set( "skin", spawnArgs.GetString("beamskin", "skins/beam_turret") );
|
|
args.SetInt( "width", spawnArgs.GetInt("beamwidth", "3") );
|
|
|
|
beamStart = ( idBeam * )gameLocal.SpawnEntityType( idBeam::Type, &args );
|
|
beamStart->BindToJoint( model, muzzleJoint, false );
|
|
beamStart->BecomeActive(TH_PHYSICS);
|
|
beamStart->GetRenderEntity()->shaderParms[ SHADERPARM_RED ] = 0;
|
|
beamStart->GetRenderEntity()->shaderParms[ SHADERPARM_GREEN ] = 1;
|
|
beamStart->GetRenderEntity()->shaderParms[ SHADERPARM_BLUE ] = 0;
|
|
|
|
//laser sight dot.
|
|
args.Clear();
|
|
args.SetVector( "origin", vec3_origin );
|
|
args.Set( "model", spawnArgs.GetString("lasermodel", "models/lasersight/tris.ase") );
|
|
args.SetInt( "solid", 0 );
|
|
laserdot = gameLocal.SpawnEntityType( idStaticEntity::Type, &args );
|
|
laserdot->GetRenderEntity()->shaderParms[ SHADERPARM_RED ] = 0;
|
|
laserdot->GetRenderEntity()->shaderParms[ SHADERPARM_GREEN ] = 1;
|
|
laserdot->GetRenderEntity()->shaderParms[ SHADERPARM_BLUE ] = 0;
|
|
|
|
laserdot->Hide();
|
|
|
|
|
|
|
|
|
|
yawActive = false;
|
|
yawTimeEnd = 0;
|
|
yawTimeStart = 0;
|
|
yawStart = 0;
|
|
yawEnd = 0;
|
|
|
|
pitchActive = false;
|
|
pitchTimeEnd = 0;
|
|
pitchTimeStart = 0;
|
|
pitchStart = 0;
|
|
pitchEnd = 0;
|
|
|
|
|
|
|
|
//nose camera.
|
|
this->GetPhysics()->GetAxis().ToAngles().ToVectors(&forward, &right, &up);
|
|
|
|
args.Clear();
|
|
args.SetVector( "origin", muzzlePos + this->GetPhysics()->GetOrigin() + (up * 2.6f) );
|
|
args.Set( "classname", "func_cameraview" );
|
|
gameLocal.SpawnEntityDef( args, &nosecam );
|
|
nosecam->BindToJoint( model, muzzleJoint, true );
|
|
nosecam->BecomeActive(TH_PHYSICS);
|
|
this->spawnArgs.Set("nosecamera_name", nosecam->GetName());
|
|
|
|
nextShotTime = 0;
|
|
queuedShots = 0;
|
|
}
|
|
|
|
|
|
void idSentry::Save( idSaveGame *savefile ) const {
|
|
savefile->WriteInt(state);
|
|
savefile->WriteFloat(yaw);
|
|
savefile->WriteFloat(pitch);
|
|
|
|
savefile->WriteObject(beamStart);
|
|
savefile->WriteObject(beamEnd);
|
|
savefile->WriteObject(model);
|
|
savefile->WriteObject(laserdot);
|
|
savefile->WriteObject(nosecam);
|
|
|
|
savefile->WriteInt(laserActivateTime);
|
|
|
|
savefile->WriteFloat(yawStart);
|
|
savefile->WriteFloat(yawEnd);
|
|
savefile->WriteInt(yawTimeStart);
|
|
savefile->WriteInt(yawTimeEnd);
|
|
savefile->WriteBool(yawActive);
|
|
|
|
savefile->WriteFloat(pitchStart);
|
|
savefile->WriteFloat(pitchEnd);
|
|
savefile->WriteInt(pitchTimeStart);
|
|
savefile->WriteInt(pitchTimeEnd);
|
|
savefile->WriteBool(pitchActive);
|
|
|
|
savefile->WriteInt(queuedShots);
|
|
savefile->WriteInt(nextShotTime);
|
|
|
|
}
|
|
|
|
void idSentry::Restore( idRestoreGame *savefile ) {
|
|
savefile->ReadInt(state);
|
|
savefile->ReadFloat(yaw);
|
|
savefile->ReadFloat(pitch);
|
|
|
|
savefile->ReadObject(reinterpret_cast<idClass *&>(beamStart));
|
|
savefile->ReadObject(reinterpret_cast<idClass *&>(beamEnd));
|
|
savefile->ReadObject(reinterpret_cast<idClass *&>(model));
|
|
savefile->ReadObject(reinterpret_cast<idClass *&>(laserdot));
|
|
savefile->ReadObject(reinterpret_cast<idClass *&>(nosecam));
|
|
|
|
|
|
savefile->ReadInt(laserActivateTime);
|
|
|
|
savefile->ReadFloat(yawStart);
|
|
savefile->ReadFloat(yawEnd);
|
|
savefile->ReadInt(yawTimeStart);
|
|
savefile->ReadInt(yawTimeEnd);
|
|
savefile->ReadBool(yawActive);
|
|
|
|
savefile->ReadFloat(pitchStart);
|
|
savefile->ReadFloat(pitchEnd);
|
|
savefile->ReadInt(pitchTimeStart);
|
|
savefile->ReadInt(pitchTimeEnd);
|
|
savefile->ReadBool(pitchActive);
|
|
|
|
savefile->ReadInt(queuedShots);
|
|
savefile->ReadInt(nextShotTime);
|
|
}
|
|
|
|
void idSentry::Event_sentrygetlaser()
|
|
{
|
|
idThread::ReturnVector(this->beamEnd->GetPhysics()->GetOrigin());
|
|
}
|
|
|
|
void idSentry::Event_sentrystand()
|
|
{
|
|
idAngles ang = this->GetPhysics()->GetAxis().ToAngles();
|
|
ang.pitch = 0;
|
|
ang.roll = 0;
|
|
this->GetPhysics()->SetAxis( ang.ToMat3() );
|
|
this->SetOrigin(this->GetPhysics()->GetOrigin() + idVec3(0,0,0.1f));
|
|
}
|
|
|
|
void idSentry::Event_sentryfire()
|
|
{
|
|
if (gameLocal.time > nextShotTime)
|
|
{
|
|
fireShot();
|
|
nextShotTime = gameLocal.time + SHOT_DELAY;
|
|
}
|
|
else
|
|
{
|
|
queuedShots++;
|
|
}
|
|
}
|
|
|
|
void idSentry::fireShot()
|
|
{
|
|
jointHandle_t muzzleJoint, muzzleBackJoint;
|
|
idVec3 offset1, offset2;
|
|
idMat3 axis;
|
|
|
|
muzzleJoint = model->GetAnimator()->GetJointHandle( "muzzle" );
|
|
muzzleBackJoint = model->GetAnimator()->GetJointHandle( "muzzle_back" );
|
|
|
|
if ( model->GetJointWorldTransform( muzzleJoint, gameLocal.time, offset1, axis )
|
|
&& model->GetJointWorldTransform( muzzleBackJoint, gameLocal.time, offset2, axis ))
|
|
{
|
|
//trace_t tr;
|
|
const idDict * projectileDef;
|
|
idEntity * ent;
|
|
idVec3 forward;
|
|
idDict args;
|
|
idEntity * particles;
|
|
idAngles particlesAngles;
|
|
idVec3 bulletspeed;
|
|
|
|
StartSound( "snd_fire", SND_CHANNEL_ANY, 0, false, NULL );
|
|
|
|
|
|
forward = offset1 - offset2;
|
|
forward.Normalize();
|
|
|
|
|
|
//fire the projectile.
|
|
|
|
//FIRE.
|
|
|
|
idProjectile *bullet;
|
|
projectileDef = gameLocal.FindEntityDefDict( spawnArgs.GetString("projectile", "projectile_sentrybullet"), false );
|
|
bulletspeed = projectileDef->GetVector("velocity", "256 0 0");
|
|
gameLocal.SpawnEntityDef( *projectileDef, &ent, false );
|
|
bullet = ( idProjectile * )ent;
|
|
bullet->Create( this, offset1, forward );
|
|
bullet->Launch( offset1, forward, forward * bulletspeed.x );
|
|
|
|
|
|
args.Clear();
|
|
args.SetVector( "origin", offset1);
|
|
args.Set( "model", spawnArgs.GetString("smoke_fire", "gunsmoke.prt") );
|
|
args.SetBool( "start_off", false );
|
|
particles = gameLocal.SpawnEntityType( idExplodable::Type, &args );
|
|
particlesAngles = forward.ToAngles();
|
|
particlesAngles.pitch += 90;
|
|
particles->SetAngles(particlesAngles);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//BC shell casing.
|
|
idVec3 gunPos;
|
|
jointHandle_t gunJoint;
|
|
idMat3 gunAxis;
|
|
gunJoint = model->GetAnimator()->GetJointHandle( "pivot" );
|
|
model->GetAnimator()->GetJointTransform( gunJoint, gameLocal.time, gunPos, gunAxis);
|
|
gunPos = this->GetPhysics()->GetOrigin() + gunPos * this->GetPhysics()->GetAxis();
|
|
|
|
idEntity *shellEnt;
|
|
const idDict * shellDef = gameLocal.FindEntityDefDict( spawnArgs.GetString( "shell", "moveable_shell"), false );
|
|
gameLocal.SpawnEntityDef( *shellDef, &shellEnt, false );
|
|
shellEnt->GetPhysics()->SetOrigin(gunPos);
|
|
shellEnt->GetPhysics()->SetAxis(this->GetPhysics()->GetAxis());
|
|
|
|
idVec3 right;
|
|
forward.ToAngles().ToVectors( NULL, &right, NULL);
|
|
idVec3 shellVelocity = (right * (16 + gameLocal.random.CRandomFloat() * 8) ) + idVec3(0,0,80+gameLocal.random.CRandomFloat() * 12) + (forward * (gameLocal.random.CRandomFloat() * 8) );
|
|
shellEnt->GetPhysics()->SetLinearVelocity(shellVelocity);
|
|
}
|
|
}
|
|
|
|
void idSentry::Event_sentryface( float x, float y, float z )
|
|
{
|
|
idVec3 dirToTarget;
|
|
jointHandle_t pivotJoint;
|
|
idVec3 offset;
|
|
idMat3 axis;
|
|
|
|
pivotJoint = model->GetAnimator()->GetJointHandle( "pivot" );
|
|
model->GetJointWorldTransform(pivotJoint, gameLocal.time, offset, axis);
|
|
|
|
|
|
|
|
dirToTarget = idVec3(x,y,z) - offset;
|
|
|
|
idAngles ang1 = dirToTarget.ToAngles();
|
|
ang1.yaw -= this->GetPhysics()->GetAxis().ToAngles().yaw;
|
|
ang1.pitch -= this->GetPhysics()->GetAxis().ToAngles().pitch;
|
|
|
|
|
|
dirToTarget = ang1.ToForward();
|
|
dirToTarget.Normalize();
|
|
|
|
model->GetAnimator()->SetJointAxis(pivotJoint, JOINTMOD_WORLD, dirToTarget.ToMat3());
|
|
}
|
|
|
|
void idSentry::Event_sentryturn( float yawValue )
|
|
{
|
|
yawTimeStart = gameLocal.time;
|
|
yawTimeEnd = gameLocal.time + TURN_TIME;
|
|
|
|
yawStart = yaw;
|
|
yawEnd = yaw - yawValue;
|
|
|
|
yawActive = true;
|
|
}
|
|
|
|
void idSentry::Event_sentrypitch( float pitchValue )
|
|
{
|
|
pitchTimeStart = gameLocal.time;
|
|
pitchTimeEnd = gameLocal.time + TURN_TIME;
|
|
|
|
pitchStart = pitch;
|
|
pitchEnd = pitch - pitchValue;
|
|
|
|
pitchActive = true;
|
|
|
|
/*
|
|
jointHandle_t gunJoint;
|
|
this->pitch -= pitchValue;
|
|
|
|
idAngles ang(pitch, yaw,0);
|
|
gunJoint = model->GetAnimator()->GetJointHandle( "pivot" );
|
|
model->GetAnimator()->SetJointAxis(gunJoint, JOINTMOD_WORLD, ang.ToMat3());*/
|
|
}
|
|
|
|
void idSentry::Event_activate( int value )
|
|
{
|
|
if (value >= 1)
|
|
{
|
|
//turn on. Deploy.
|
|
model->Event_PlayAnim( "deploy", 4 );
|
|
state = DEPLOYING;
|
|
|
|
|
|
laserActivateTime = gameLocal.time + 1300;
|
|
|
|
}
|
|
else
|
|
{
|
|
//turn off. Pack up.
|
|
model->Event_PlayAnim( "close", 4 );
|
|
state = CLOSING;
|
|
|
|
|
|
|
|
pitchTimeStart = gameLocal.time;
|
|
pitchTimeEnd = gameLocal.time + 400;
|
|
pitchStart = pitch;
|
|
pitchEnd = 0;
|
|
pitchActive = true;
|
|
|
|
yawTimeStart = gameLocal.time;
|
|
yawTimeEnd = gameLocal.time + 400;
|
|
yawStart = yaw;
|
|
yawEnd = 0;
|
|
yawActive = true;
|
|
|
|
|
|
|
|
|
|
laserdot->Hide();
|
|
beamStart->Hide();
|
|
|
|
queuedShots = 0;
|
|
}
|
|
}
|
|
|
|
void idSentry::Event_issentryactive()
|
|
{
|
|
if (state == ON || state == DEPLOYING)
|
|
{
|
|
idThread::ReturnInt( 1 );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
idThread::ReturnInt( 0 );
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void idSentry::Think( void )
|
|
{
|
|
trace_t tr;
|
|
idVec3 offset1, offset2;
|
|
idMat3 axis;
|
|
jointHandle_t muzzleJoint, muzzleBackJoint;
|
|
|
|
|
|
//RunPhysics();
|
|
|
|
muzzleJoint = model->GetAnimator()->GetJointHandle( "muzzle" );
|
|
muzzleBackJoint = model->GetAnimator()->GetJointHandle( "muzzle_back" );
|
|
|
|
if ( model->GetJointWorldTransform( muzzleJoint, gameLocal.time, offset1, axis )
|
|
&& model->GetJointWorldTransform( muzzleBackJoint, gameLocal.time, offset2, axis ))
|
|
{
|
|
trace_t tr;
|
|
idVec3 forward;
|
|
|
|
forward = offset1 - offset2;
|
|
forward.Normalize();
|
|
|
|
//beam end goes through glass.
|
|
|
|
int i;
|
|
int maxGlassPanes = 32;
|
|
idVec3 beamTempStartPos = offset1;
|
|
|
|
for (i = 0; i < maxGlassPanes; i++)
|
|
{
|
|
trace_t beamTr;
|
|
gameLocal.clip.TracePoint( beamTr, beamTempStartPos, beamTempStartPos + (forward * 4096), MASK_SOLID | MASK_SHOT_RENDERMODEL, this );
|
|
|
|
if (!gameLocal.entities[ beamTr.c.entityNum ])
|
|
continue;
|
|
|
|
if (gameLocal.entities[ beamTr.c.entityNum ]->IsType( idBrittleFracture::Type ) || gameLocal.entities[ beamTr.c.entityNum ]->IsType( idQGlass::Type ))
|
|
{
|
|
//glass. continue the beam.
|
|
|
|
//gameRenderWorld->DebugLine(idVec4(1,1,0,1), beamTempStartPos, beamTr.endpos, 1, false);
|
|
|
|
beamTempStartPos = beamTr.endpos + (forward * 0.1f);
|
|
continue;
|
|
}
|
|
|
|
beamEnd->SetOrigin( beamTr.endpos );
|
|
break;
|
|
}
|
|
|
|
//gameLocal.clip.TracePoint( tr, offset1, offset1 + (forward * 4096), MASK_OPAQUE, this );
|
|
//beamEnd->SetOrigin( tr.endpos );
|
|
|
|
|
|
|
|
//beam dot stops at any solid surface.
|
|
gameLocal.clip.TracePoint( tr, offset1, offset1 + (forward * 4096), MASK_SOLID | MASK_SHOT_RENDERMODEL, this );
|
|
laserdot->SetOrigin( tr.endpos);
|
|
}
|
|
|
|
|
|
//yaw think.
|
|
if (yawActive)
|
|
{
|
|
jointHandle_t gunJoint;
|
|
|
|
float lerp;
|
|
float currentTime = gameLocal.time;
|
|
float lookTimeMax = yawTimeEnd - yawTimeStart;
|
|
float lookTimeMin = yawTimeStart;
|
|
currentTime -= yawTimeStart;
|
|
lerp = currentTime / lookTimeMax;
|
|
|
|
if (lerp > 1)
|
|
lerp = 1;
|
|
|
|
yaw = idMath::Lerp(yawStart, yawEnd, lerp);
|
|
idAngles ang(pitch, yaw,0);
|
|
gunJoint = model->GetAnimator()->GetJointHandle( "pivot" );
|
|
model->GetAnimator()->SetJointAxis(gunJoint, JOINTMOD_WORLD, ang.ToMat3());
|
|
|
|
if (lerp >= 1)
|
|
{
|
|
yawActive = false;
|
|
}
|
|
}
|
|
|
|
|
|
//yaw think.
|
|
if (pitchActive)
|
|
{
|
|
jointHandle_t gunJoint;
|
|
|
|
float lerp;
|
|
float currentTime = gameLocal.time;
|
|
float lookTimeMax = pitchTimeEnd - pitchTimeStart;
|
|
float lookTimeMin = pitchTimeStart;
|
|
currentTime -= pitchTimeStart;
|
|
lerp = currentTime / lookTimeMax;
|
|
|
|
if (lerp > 1)
|
|
lerp = 1;
|
|
|
|
pitch = idMath::Lerp(pitchStart, pitchEnd, lerp);
|
|
idAngles ang(pitch, yaw,0);
|
|
gunJoint = model->GetAnimator()->GetJointHandle( "pivot" );
|
|
model->GetAnimator()->SetJointAxis(gunJoint, JOINTMOD_WORLD, ang.ToMat3());
|
|
|
|
if (lerp >= 1)
|
|
{
|
|
pitchActive = false;
|
|
}
|
|
}
|
|
|
|
|
|
if (gameLocal.time > laserActivateTime && (laserdot->IsHidden() || beamStart->IsHidden())
|
|
&& (state == DEPLOYING || state == ON) )
|
|
{
|
|
laserdot->Show();
|
|
beamStart->Show();
|
|
}
|
|
|
|
//BC 10-2-2015 so that the camera can see the laserline. ugh! hack.
|
|
if (!beamStart->IsHidden())
|
|
gameRenderWorld->DebugLine(idVec4(0,1,0,1), beamStart->GetPhysics()->GetOrigin(), beamEnd->GetPhysics()->GetOrigin(),1, true);
|
|
|
|
|
|
if (gameLocal.time > nextShotTime && queuedShots > 0 && state != OFF)
|
|
{
|
|
fireShot();
|
|
nextShotTime = gameLocal.time + SHOT_DELAY;
|
|
queuedShots--;
|
|
}
|
|
|
|
|
|
//Present();
|
|
idMoveableItem::Think();
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void idSentry::OnGet( void )
|
|
{
|
|
//BC 6-28-2016 crash fix
|
|
gameLocal.KillCCTVs();
|
|
|
|
gameLocal.GetLocalPlayer()->StartSound( "snd_get", SND_CHANNEL_ANY, 0, false, NULL );
|
|
this->PostEventMS( &EV_Remove, 0 );
|
|
gameLocal.GetLocalPlayer()->GiveInventoryItem("weapon_sentry");
|
|
}
|
|
|
|
void idSentry::Event_sentrykill( void )
|
|
{
|
|
gameLocal.KillCCTVs();
|
|
laserdot->PostEventMS( &EV_Remove, 0 );
|
|
beamStart->PostEventMS( &EV_Remove, 0 );
|
|
beamEnd->PostEventMS( &EV_Remove, 0 );
|
|
} |