NS/main/source/mod/AvHAlienTurret.cpp
2014-12-16 14:36:27 +01:00

411 lines
10 KiB
C++

//======== (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;
}