//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. =========
//
// The copyright to the contents herein is the property of Charles G. Cleveland.
// The contents may be used and/or copied only with the written permission of
// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose:
//
// $Workfile: AvHAlienTurret.cpp $
// $Date: 2002/11/22 21:28:15 $
//
//-------------------------------------------------------------------------------
// $Log: AvHAlienTurret.cpp,v $
// Revision 1.8 2002/11/22 21:28:15 Flayra
// - mp_consistency changes
//
// Revision 1.7 2002/10/24 21:20:49 Flayra
// - Alien turrets now credit their owner with kills
//
// Revision 1.6 2002/09/23 22:08:14 Flayra
// - Removed damage upgrades for alien turrets (used to be needed for offensive upgrades)
//
// Revision 1.5 2002/07/24 18:45:40 Flayra
// - Linux and scripting changes
//
// Revision 1.4 2002/07/23 16:57:05 Flayra
// - Alien turret refactoring and fixing (the view offset in spawn() was causing them to always miss crouched players)
//
// Revision 1.3 2002/07/01 21:14:21 Flayra
// - Added auto-building, added damage upgrade (from primal scream), added vertical FOV (doesn't work yet)
//
// Revision 1.2 2002/06/03 16:24:08 Flayra
// - Moved chamber firing into an event, added turret constants
//
// Revision 1.1 2002/05/28 17:12:17 Flayra
// - Offensive chamber that shoots spit
//
//===============================================================================
include "AvHAlienTurret.h"
include "AvHConstants.h"
include "AvHPlayerUpgrade.h"
include "AvHAlienEquipmentConstants.h"
include "AvHAlienWeaponConstants.h"
include "AvHAlienWeapons.h"
include "../common/hldm.h"
include "../common/event_api.h"
include "../common/event_args.h"
include "../common/vector_util.h"
include "AvHGamerules.h"
include "../util/MathUtil.h"
// Temporary
include "AvHMarineTurret.h"
include "AvHMarineEquipment.h"
include "AvHConstants.h"
include "AvHPlayerUpgrade.h"
LINK_ENTITY_TO_CLASS(kwOffenseChamber, AvHAlienTurret);
ifdef AVH_SERVER
LINK_ENTITY_TO_CLASS(kwSpikeProjectile, AvHSpike);
void AvHSpike::Precache(void)
{
CBaseEntity::Precache();
PRECACHE_UNMODIFIED_MODEL(kSpikeProjectileModel);
}
void AvHSpike::SetDamage(float inDamage)
{
this->mDamage = inDamage;
}
void AvHSpike::Spawn()
{
this->Precache();
CBaseEntity::Spawn();
this->pev->movetype = MOVETYPE_FLY; this->pev->classname = MAKE_STRING(kSpikeProjectileClassName); SET_MODEL(ENT(this->pev), kSpikeProjectileModel); this->pev->solid = SOLID_BBOX; this->mDamage = 0.0f; // Comment out effects line, uncomment next four, then comment out creation of temp entity in EV_SpikeGun to see server side Spike for testing if(!GetGameRules()->GetDrawInvisibleEntities()) { this->pev->effects = EF_NODRAW; } else { this->pev->frame = 0; this->pev->scale = 0.5; this->pev->rendermode = kRenderTransAlpha; this->pev->renderamt = 255; } //UTIL_SetSize(this->pev, Vector( 0, 0, 0), Vector(0, 0, 0));
// UTIL_SetSize(this->pev, Vector( -16, -16, -16), Vector(16, 16, 16));
//UTIL_SetSize(this->pev, Vector( -50, -50, -50), Vector(50, 50, 50));
SetTouch(&AvHSpike::SpikeTouch); // Enforce short range SetThink(&AvHSpike::SpikeDeath); this->pev->nextthink = gpGlobals->time + kSpikeLifetime;
}
void AvHSpike::SpikeDeath()
{
// Kill the Spike entity
UTIL_Remove(this);
// SetThink(SUB_Remove); // this->pev->nextthink = gpGlobals->time + 0.01f;
}
void AvHSpike::SpikeTouch(CBaseEntity* pOther)
{
CBaseEntity* theSpikeOwner = CBaseEntity::Instance(this->pev->owner);
if((pOther != theSpikeOwner) && (theSpikeOwner != NULL))
{
float theScalar = 1.0f;
if(GetGameRules()->CanEntityDoDamageTo(this, pOther, &theScalar))
{
float theDamage = this->mDamage*theScalar;
// Give credit to the spike owner's owner (spike's owner is OC, OC's owner is player) CBaseEntity* theSpikeOwnerOwner = NULL; entvars_t* theSpikeOwnerOwnerEntVars = NULL; if(theSpikeOwner) { AvHTurret* theTurret = dynamic_cast<AvHTurret*>(theSpikeOwner); if(theTurret) { theSpikeOwnerOwner = theTurret->GetAttacker(); } } if(!theSpikeOwnerOwner) { theSpikeOwnerOwner = theSpikeOwner; } if(theSpikeOwnerOwner) { theSpikeOwnerOwnerEntVars = theSpikeOwnerOwner->pev; } // Apply damage to receiver pOther->TakeDamage(theSpikeOwner->pev, theSpikeOwnerOwnerEntVars, theDamage, NS_DMG_LIGHT); } // Kill it off this->SpikeDeath(); }
}
endif
AvHAlienTurret::AvHAlienTurret() : AvHTurret(TECH_OFFENSE_CHAMBER, ALIEN_BUILD_OFFENSE_CHAMBER, kwsOffenseChamber, AVH_USER3_OFFENSE_CHAMBER)
{
}
AvHAlienTurret::AvHAlienTurret(AvHTechID inTechID, AvHMessageID inMessageID, char* inClassName, int inUser3) : AvHTurret(inTechID, inMessageID, inClassName, inUser3)
{
}
// Energy from movement chambers subtracts off the rate of fire
bool AvHAlienTurret::Energize(float inEnergyAmount)
{
bool theSuccess = false;
if(this->GetIsBuilt() && (this->mEnergy < 1.0f)) { if(this->m_hEnemy != NULL) { this->mEnergy = max(0.0f, min(1.0f, this->mEnergy + inEnergyAmount)); theSuccess = true; } } return theSuccess;
}
char* AvHAlienTurret::GetDeploySound() const
{
return kAlienTurretDeploy;
}
bool AvHAlienTurret::GetIsOrganic() const
{
return true;
}
int AvHAlienTurret::GetPointValue(void) const
{
return 2;
}
int AvHAlienTurret::GetXYRange() const
{
return 700;
}
void AvHAlienTurret::Precache()
{
PRECACHE_UNMODIFIED_MODEL(kOffenseChamberModel);
PRECACHE_UNMODIFIED_MODEL(kSpikeProjectileModel);
PRECACHE_UNMODIFIED_SOUND(kAlienTurretFire1);
PRECACHE_UNMODIFIED_SOUND(kAlienTurretDeploy);
PRECACHE_UNMODIFIED_MODEL(kAlienTurretSprite);
this->mEvent = PRECACHE_EVENT(1, kOffenseChamberEventName);
}
int AvHAlienTurret::GetVerticalFOV() const
{
return AvHTurret::GetVerticalFOV();
}
void AvHAlienTurret::PreBuiltThink()
{
if(!this->GetIsBuilt())
this->UpdateAutoBuild(kAlienBuildingThinkInterval*kAutoBuildScalar);
else
this->SetHasBeenBuilt();
this->pev->nextthink = gpGlobals->time + kAlienBuildingThinkInterval;
}
void AvHAlienTurret::Shoot(const Vector &inOrigin, const Vector &inToEnemy, const Vector& inVecEnemyVelocity)
{
// Spawn spike
AvHSpike* theSpike = GetClassPtr((AvHSpike*)NULL );
theSpike->Spawn();
// Make it invisible if(!GetGameRules()->GetDrawInvisibleEntities()) { theSpike->pev->effects = EF_NODRAW; } else { theSpike->pev->effects = 0; theSpike->pev->frame = 0; theSpike->pev->scale = 0.5; theSpike->pev->rendermode = kRenderTransAlpha; theSpike->pev->renderamt = 255; } // Predict where enemy will be when the spike hits and shoot that way float theTimeToReachEnemy = inToEnemy.Length()/(float)kOffenseChamberSpikeVelocity; Vector theEnemyPosition; VectorAdd(this->pev->origin, inToEnemy, theEnemyPosition); float theVelocityLength = inVecEnemyVelocity.Length(); Vector theEnemyNormVelocity = inVecEnemyVelocity.Normalize(); // Don't always hit very fast moving targets (jetpackers) const float kVelocityFactor = .7f; Vector thePredictedPosition; VectorMA(theEnemyPosition, theVelocityLength*kVelocityFactor*theTimeToReachEnemy, theEnemyNormVelocity, thePredictedPosition); Vector theOrigin = inOrigin; //Vector theDirToEnemy = inDirToEnemy.Normalize(); Vector theDirToPredictedEnemy; VectorSubtract(thePredictedPosition, this->pev->origin, theDirToPredictedEnemy); Vector theDirToEnemy = theDirToPredictedEnemy.Normalize(); //Vector theAttachOrigin, theAttachAngles; //GetAttachment(0, theAttachOrigin, theAttachAngles); //UTIL_SetOrigin(theSpike->pev, theStartPos); //VectorCopy(theStartPos, theSpike->pev->origin); VectorCopy(inOrigin, theSpike->pev->origin); // Pass this velocity to event int theVelocityScalar = kOffenseChamberSpikeVelocity; Vector theInitialVelocity; VectorScale(theDirToEnemy, theVelocityScalar, theInitialVelocity); // Set spike owner to OC so it doesn't collide with it theSpike->pev->owner = this->edict(); // Set Spike's team :) theSpike->pev->team = this->pev->team; VectorCopy(theInitialVelocity, theSpike->pev->velocity); // Set amount of damage it will do theSpike->SetDamage(BALANCE_VAR(kOffenseChamberDamage)); // Take into account network precision Vector theNetworkDirToEnemy; VectorScale(theDirToEnemy, 100.0f, theNetworkDirToEnemy); PLAYBACK_EVENT_FULL(0, 0, this->mEvent, 0, theOrigin, theNetworkDirToEnemy, 1.0f, 0.0, /*theWeaponIndex*/ this->entindex(), 0, 0, 0 ); // Play attack anim this->PlayAnimationAtIndex(6, true); this->Uncloak();
}
bool AvHAlienTurret::GetBaseClassAnimatesTurret() const
{
return false;
}
int AvHAlienTurret::MoveTurret(void)
{
// Set animation, without overriding
int theAnimation = this->GetIdle1Animation();
if(RANDOM_LONG(0, 1) == 0)
{
theAnimation = this->GetIdle2Animation();
}
this->PlayAnimationAtIndex(theAnimation, false);
return AvHTurret::MoveTurret();
}
int AvHAlienTurret::GetIdle1Animation() const
{
int theAnimation = -1;
if(this->GetIsBuilt()) { if(RANDOM_LONG(0, 5) == 0) { theAnimation = 4; } else { theAnimation = 2; } } return theAnimation;
}
int AvHAlienTurret::GetIdle2Animation() const
{
int theAnimation = -1;
if(this->GetIsBuilt()) { theAnimation = 3; } return theAnimation;
}
int AvHAlienTurret::GetTakeDamageAnimation() const
{
int theAnimation = -1;
if(this->GetIsBuilt()) { theAnimation = 7; } return theAnimation;
}
char* AvHAlienTurret::GetModelName() const
{
return kOffenseChamberModel;
}
float AvHAlienTurret::GetRateOfFire() const
{
return .5f + RANDOM_FLOAT(0.0f, (1.0f - this->mEnergy));
}
void AvHAlienTurret::ResetEntity()
{
AvHTurret::ResetEntity();
this->mEnergy = 0;
}
void AvHAlienTurret::Spawn()
{
this->mEnergy = 0.0f;
AvHTurret::Spawn(); SetThink(&AvHAlienTurret::PreBuiltThink); this->pev->nextthink = gpGlobals->time + kAlienBuildingThinkInterval;
}
void AvHAlienTurret::SetNextAttack()
{
AvHTurret::SetNextAttack();
this->mEnergy = 0.0f;
}