2022-12-17 13:32:43 +01:00
|
|
|
/***
|
2013-08-30 13:34:05 -07:00
|
|
|
*
|
|
|
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
|
|
|
*
|
|
|
|
* This product contains software technology licensed from Id
|
|
|
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* This source code contains proprietary and confidential information of
|
|
|
|
* Valve LLC and its suppliers. Access to this code is restricted to
|
|
|
|
* persons who have executed a written SDK license with Valve. Any access,
|
|
|
|
* use or distribution of this code by or to any unlicensed person is illegal.
|
|
|
|
*
|
|
|
|
****/
|
|
|
|
#include "extdll.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "cbase.h"
|
|
|
|
#include "monsters.h"
|
|
|
|
#include "weapons.h"
|
|
|
|
#include "soundent.h"
|
|
|
|
#include "effects.h"
|
|
|
|
#include "customentity.h"
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
typedef struct
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
int isValid;
|
|
|
|
EHANDLE hGrunt;
|
2021-11-28 16:54:48 +01:00
|
|
|
Vector vecOrigin;
|
|
|
|
Vector vecAngles;
|
2013-08-30 13:34:05 -07:00
|
|
|
} t_ospreygrunt;
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SF_WAITFORTRIGGER 0x40
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define MAX_CARRY 24
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
class COsprey : public CBaseMonster
|
|
|
|
{
|
|
|
|
public:
|
2021-11-28 16:54:48 +01:00
|
|
|
bool Save(CSave& save) override;
|
|
|
|
bool Restore(CRestore& restore) override;
|
|
|
|
static TYPEDESCRIPTION m_SaveData[];
|
2021-11-29 20:31:17 +01:00
|
|
|
int ObjectCaps() override { return CBaseMonster::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2021-03-05 23:07:22 +01:00
|
|
|
void Spawn() override;
|
|
|
|
void Precache() override;
|
2021-11-28 16:54:48 +01:00
|
|
|
int Classify() override { return CLASS_MACHINE; }
|
|
|
|
int BloodColor() override { return DONT_BLEED; }
|
|
|
|
void Killed(entvars_t* pevAttacker, int iGib) override;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void UpdateGoal();
|
2021-11-19 14:31:11 +01:00
|
|
|
bool HasDead();
|
2021-03-05 20:54:33 +01:00
|
|
|
void EXPORT FlyThink();
|
|
|
|
void EXPORT DeployThink();
|
|
|
|
void Flight();
|
2021-11-28 16:54:48 +01:00
|
|
|
void EXPORT HitTouch(CBaseEntity* pOther);
|
2021-03-05 20:54:33 +01:00
|
|
|
void EXPORT FindAllThink();
|
|
|
|
void EXPORT HoverThink();
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseMonster* MakeGrunt(Vector vecSrc);
|
|
|
|
void EXPORT CrashTouch(CBaseEntity* pOther);
|
2021-03-05 20:54:33 +01:00
|
|
|
void EXPORT DyingThink();
|
2021-11-28 16:54:48 +01:00
|
|
|
void EXPORT CommandUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2022-08-04 12:30:11 +02:00
|
|
|
bool TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) override;
|
2021-11-28 16:54:48 +01:00
|
|
|
void TraceAttack(entvars_t* pevAttacker, float flDamage, Vector vecDir, TraceResult* ptr, int bitsDamageType) override;
|
2021-03-05 20:54:33 +01:00
|
|
|
void ShowDamage();
|
2022-03-15 12:33:12 +01:00
|
|
|
void Update();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* m_pGoalEnt;
|
2013-08-30 13:34:05 -07:00
|
|
|
Vector m_vel1;
|
|
|
|
Vector m_vel2;
|
|
|
|
Vector m_pos1;
|
|
|
|
Vector m_pos2;
|
|
|
|
Vector m_ang1;
|
|
|
|
Vector m_ang2;
|
|
|
|
float m_startTime;
|
|
|
|
float m_dTime;
|
|
|
|
|
|
|
|
Vector m_velocity;
|
|
|
|
|
|
|
|
float m_flIdealtilt;
|
|
|
|
float m_flRotortilt;
|
|
|
|
|
|
|
|
float m_flRightHealth;
|
|
|
|
float m_flLeftHealth;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
int m_iUnits;
|
2013-08-30 13:34:05 -07:00
|
|
|
EHANDLE m_hGrunt[MAX_CARRY];
|
|
|
|
Vector m_vecOrigin[MAX_CARRY];
|
|
|
|
EHANDLE m_hRepel[4];
|
|
|
|
|
|
|
|
int m_iSoundState;
|
|
|
|
int m_iSpriteTexture;
|
|
|
|
|
|
|
|
int m_iPitch;
|
|
|
|
|
|
|
|
int m_iExplode;
|
2021-11-28 16:54:48 +01:00
|
|
|
int m_iTailGibs;
|
|
|
|
int m_iBodyGibs;
|
|
|
|
int m_iEngineGibs;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
int m_iDoLeftSmokePuff;
|
|
|
|
int m_iDoRightSmokePuff;
|
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
LINK_ENTITY_TO_CLASS(monster_osprey, COsprey);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
TYPEDESCRIPTION COsprey::m_SaveData[] =
|
|
|
|
{
|
|
|
|
DEFINE_FIELD(COsprey, m_pGoalEnt, FIELD_CLASSPTR),
|
|
|
|
DEFINE_FIELD(COsprey, m_vel1, FIELD_VECTOR),
|
|
|
|
DEFINE_FIELD(COsprey, m_vel2, FIELD_VECTOR),
|
|
|
|
DEFINE_FIELD(COsprey, m_pos1, FIELD_POSITION_VECTOR),
|
|
|
|
DEFINE_FIELD(COsprey, m_pos2, FIELD_POSITION_VECTOR),
|
|
|
|
DEFINE_FIELD(COsprey, m_ang1, FIELD_VECTOR),
|
|
|
|
DEFINE_FIELD(COsprey, m_ang2, FIELD_VECTOR),
|
|
|
|
|
|
|
|
DEFINE_FIELD(COsprey, m_startTime, FIELD_TIME),
|
|
|
|
DEFINE_FIELD(COsprey, m_dTime, FIELD_FLOAT),
|
|
|
|
DEFINE_FIELD(COsprey, m_velocity, FIELD_VECTOR),
|
|
|
|
|
|
|
|
DEFINE_FIELD(COsprey, m_flIdealtilt, FIELD_FLOAT),
|
|
|
|
DEFINE_FIELD(COsprey, m_flRotortilt, FIELD_FLOAT),
|
|
|
|
|
|
|
|
DEFINE_FIELD(COsprey, m_flRightHealth, FIELD_FLOAT),
|
|
|
|
DEFINE_FIELD(COsprey, m_flLeftHealth, FIELD_FLOAT),
|
|
|
|
|
|
|
|
DEFINE_FIELD(COsprey, m_iUnits, FIELD_INTEGER),
|
|
|
|
DEFINE_ARRAY(COsprey, m_hGrunt, FIELD_EHANDLE, MAX_CARRY),
|
|
|
|
DEFINE_ARRAY(COsprey, m_vecOrigin, FIELD_POSITION_VECTOR, MAX_CARRY),
|
|
|
|
DEFINE_ARRAY(COsprey, m_hRepel, FIELD_EHANDLE, 4),
|
|
|
|
|
|
|
|
// DEFINE_FIELD( COsprey, m_iSoundState, FIELD_INTEGER ),
|
|
|
|
// DEFINE_FIELD( COsprey, m_iSpriteTexture, FIELD_INTEGER ),
|
|
|
|
// DEFINE_FIELD( COsprey, m_iPitch, FIELD_INTEGER ),
|
|
|
|
|
|
|
|
DEFINE_FIELD(COsprey, m_iDoLeftSmokePuff, FIELD_INTEGER),
|
|
|
|
DEFINE_FIELD(COsprey, m_iDoRightSmokePuff, FIELD_INTEGER),
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
2021-11-28 16:54:48 +01:00
|
|
|
IMPLEMENT_SAVERESTORE(COsprey, CBaseMonster);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void COsprey::Spawn()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
Precache();
|
2013-08-30 13:34:05 -07:00
|
|
|
// motor
|
|
|
|
pev->movetype = MOVETYPE_FLY;
|
|
|
|
pev->solid = SOLID_BBOX;
|
|
|
|
|
|
|
|
SET_MODEL(ENT(pev), "models/osprey.mdl");
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetSize(pev, Vector(-400, -400, -100), Vector(400, 400, 32));
|
|
|
|
UTIL_SetOrigin(pev, pev->origin);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2022-03-14 14:57:18 +01:00
|
|
|
//Set FL_FLY so the Osprey model is interpolated.
|
|
|
|
pev->flags |= FL_MONSTER | FL_FLY;
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->takedamage = DAMAGE_YES;
|
|
|
|
m_flRightHealth = 200;
|
|
|
|
m_flLeftHealth = 200;
|
|
|
|
pev->health = 400;
|
2022-03-15 12:33:12 +01:00
|
|
|
pev->max_health = pev->health;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
m_flFieldOfView = 0; // 180 degrees
|
|
|
|
|
|
|
|
pev->sequence = 0;
|
2021-11-28 16:54:48 +01:00
|
|
|
ResetSequenceInfo();
|
|
|
|
pev->frame = RANDOM_LONG(0, 0xFF);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
InitBoneControllers();
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
SetThink(&COsprey::FindAllThink);
|
|
|
|
SetUse(&COsprey::CommandUse);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 15:32:26 +01:00
|
|
|
if ((pev->spawnflags & SF_WAITFORTRIGGER) == 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->nextthink = gpGlobals->time + 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_pos2 = pev->origin;
|
|
|
|
m_ang2 = pev->angles;
|
|
|
|
m_vel2 = pev->velocity;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void COsprey::Precache()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_PrecacheOther("monster_human_grunt");
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
PRECACHE_MODEL("models/osprey.mdl");
|
|
|
|
PRECACHE_MODEL("models/HVR.mdl");
|
|
|
|
|
|
|
|
PRECACHE_SOUND("apache/ap_rotor4.wav");
|
|
|
|
PRECACHE_SOUND("weapons/mortarhit.wav");
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
m_iSpriteTexture = PRECACHE_MODEL("sprites/rope.spr");
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
m_iExplode = PRECACHE_MODEL("sprites/fexplo.spr");
|
|
|
|
m_iTailGibs = PRECACHE_MODEL("models/osprey_tailgibs.mdl");
|
|
|
|
m_iBodyGibs = PRECACHE_MODEL("models/osprey_bodygibs.mdl");
|
|
|
|
m_iEngineGibs = PRECACHE_MODEL("models/osprey_enginegibs.mdl");
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void COsprey::CommandUse(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->nextthink = gpGlobals->time + 0.1;
|
|
|
|
}
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void COsprey::FindAllThink()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = NULL;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
m_iUnits = 0;
|
2021-11-28 16:54:48 +01:00
|
|
|
while (m_iUnits < MAX_CARRY && (pEntity = UTIL_FindEntityByClassname(pEntity, "monster_human_grunt")) != NULL)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
if (pEntity->IsAlive())
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_hGrunt[m_iUnits] = pEntity;
|
|
|
|
m_vecOrigin[m_iUnits] = pEntity->pev->origin;
|
2013-08-30 13:34:05 -07:00
|
|
|
m_iUnits++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_iUnits == 0)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
ALERT(at_console, "osprey error: no grunts to resupply\n");
|
|
|
|
UTIL_Remove(this);
|
2013-08-30 13:34:05 -07:00
|
|
|
return;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
SetThink(&COsprey::FlyThink);
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->nextthink = gpGlobals->time + 0.1;
|
|
|
|
m_startTime = gpGlobals->time;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void COsprey::DeployThink()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeAimVectors(pev->angles);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
Vector vecForward = gpGlobals->v_forward;
|
|
|
|
Vector vecRight = gpGlobals->v_right;
|
|
|
|
Vector vecUp = gpGlobals->v_up;
|
|
|
|
|
|
|
|
Vector vecSrc;
|
|
|
|
|
|
|
|
TraceResult tr;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceLine(pev->origin, pev->origin + Vector(0, 0, -4096.0), ignore_monsters, ENT(pev), &tr);
|
|
|
|
CSoundEnt::InsertSound(bits_SOUND_DANGER, tr.vecEndPos, 400, 0.3);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
vecSrc = pev->origin + vecForward * 32 + vecRight * 100 + vecUp * -96;
|
|
|
|
m_hRepel[0] = MakeGrunt(vecSrc);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
vecSrc = pev->origin + vecForward * -64 + vecRight * 100 + vecUp * -96;
|
|
|
|
m_hRepel[1] = MakeGrunt(vecSrc);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
vecSrc = pev->origin + vecForward * 32 + vecRight * -100 + vecUp * -96;
|
|
|
|
m_hRepel[2] = MakeGrunt(vecSrc);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
vecSrc = pev->origin + vecForward * -64 + vecRight * -100 + vecUp * -96;
|
2021-11-28 16:54:48 +01:00
|
|
|
m_hRepel[3] = MakeGrunt(vecSrc);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
SetThink(&COsprey::HoverThink);
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->nextthink = gpGlobals->time + 0.1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
bool COsprey::HasDead()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
for (int i = 0; i < m_iUnits; i++)
|
|
|
|
{
|
|
|
|
if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive())
|
|
|
|
{
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_vecOrigin[i] = m_hGrunt[i]->pev->origin; // send them to where they died
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
2021-11-19 13:43:33 +01:00
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
CBaseMonster* COsprey::MakeGrunt(Vector vecSrc)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity;
|
|
|
|
CBaseMonster* pGrunt;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
TraceResult tr;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceLine(vecSrc, vecSrc + Vector(0, 0, -4096.0), dont_ignore_monsters, ENT(pev), &tr);
|
|
|
|
if (tr.pHit && Instance(tr.pHit)->pev->solid != SOLID_BSP)
|
2013-08-30 13:34:05 -07:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (int i = 0; i < m_iUnits; i++)
|
|
|
|
{
|
|
|
|
if (m_hGrunt[i] == NULL || !m_hGrunt[i]->IsAlive())
|
|
|
|
{
|
|
|
|
if (m_hGrunt[i] != NULL && m_hGrunt[i]->pev->rendermode == kRenderNormal)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_hGrunt[i]->SUB_StartFadeOut();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity = Create("monster_human_grunt", vecSrc, pev->angles);
|
|
|
|
pGrunt = pEntity->MyMonsterPointer();
|
2013-08-30 13:34:05 -07:00
|
|
|
pGrunt->pev->movetype = MOVETYPE_FLY;
|
2021-11-28 16:54:48 +01:00
|
|
|
pGrunt->pev->velocity = Vector(0, 0, RANDOM_FLOAT(-196, -128));
|
|
|
|
pGrunt->SetActivity(ACT_GLIDE);
|
|
|
|
|
|
|
|
CBeam* pBeam = CBeam::BeamCreate("sprites/rope.spr", 10);
|
|
|
|
pBeam->PointEntInit(vecSrc + Vector(0, 0, 112), pGrunt->entindex());
|
|
|
|
pBeam->SetFlags(BEAM_FSOLID);
|
|
|
|
pBeam->SetColor(255, 255, 255);
|
|
|
|
pBeam->SetThink(&CBeam::SUB_Remove);
|
2013-08-30 13:34:05 -07:00
|
|
|
pBeam->pev->nextthink = gpGlobals->time + -4096.0 * tr.flFraction / pGrunt->pev->velocity.z + 0.5;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// ALERT( at_console, "%d at %.0f %.0f %.0f\n", i, m_vecOrigin[i].x, m_vecOrigin[i].y, m_vecOrigin[i].z );
|
2013-08-30 13:34:05 -07:00
|
|
|
pGrunt->m_vecLastPosition = m_vecOrigin[i];
|
|
|
|
m_hGrunt[i] = pGrunt;
|
|
|
|
return pGrunt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ALERT( at_console, "none dead\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void COsprey::HoverThink()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
{
|
2021-11-28 15:32:26 +01:00
|
|
|
if (m_hRepel[i] != NULL && m_hRepel[i]->pev->health > 0 && (m_hRepel[i]->pev->flags & FL_ONGROUND) == 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == 4)
|
|
|
|
{
|
|
|
|
m_startTime = gpGlobals->time;
|
2021-11-28 16:54:48 +01:00
|
|
|
SetThink(&COsprey::FlyThink);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pev->nextthink = gpGlobals->time + 0.1;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeAimVectors(pev->angles);
|
2022-03-15 12:33:12 +01:00
|
|
|
Update();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void COsprey::UpdateGoal()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
if (m_pGoalEnt)
|
|
|
|
{
|
|
|
|
m_pos1 = m_pos2;
|
|
|
|
m_ang1 = m_ang2;
|
|
|
|
m_vel1 = m_vel2;
|
|
|
|
m_pos2 = m_pGoalEnt->pev->origin;
|
|
|
|
m_ang2 = m_pGoalEnt->pev->angles;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeAimVectors(Vector(0, m_ang2.y, 0));
|
2013-08-30 13:34:05 -07:00
|
|
|
m_vel2 = gpGlobals->v_forward * m_pGoalEnt->pev->speed;
|
|
|
|
|
|
|
|
m_startTime = m_startTime + m_dTime;
|
|
|
|
m_dTime = 2.0 * (m_pos1 - m_pos2).Length() / (m_vel1.Length() + m_pGoalEnt->pev->speed);
|
|
|
|
|
|
|
|
if (m_ang1.y - m_ang2.y < -180)
|
|
|
|
{
|
|
|
|
m_ang1.y += 360;
|
|
|
|
}
|
|
|
|
else if (m_ang1.y - m_ang2.y > 180)
|
|
|
|
{
|
|
|
|
m_ang1.y -= 360;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_pGoalEnt->pev->speed < 400)
|
|
|
|
m_flIdealtilt = 0;
|
|
|
|
else
|
|
|
|
m_flIdealtilt = -90;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
ALERT(at_console, "osprey missing target");
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void COsprey::FlyThink()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
StudioFrameAdvance();
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->nextthink = gpGlobals->time + 0.1;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_pGoalEnt == NULL && !FStringNull(pev->target)) // this monster has a target
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_pGoalEnt = CBaseEntity::Instance(FIND_ENTITY_BY_TARGETNAME(NULL, STRING(pev->target)));
|
|
|
|
UpdateGoal();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (gpGlobals->time > m_startTime + m_dTime)
|
2022-03-14 19:25:27 +01:00
|
|
|
{
|
|
|
|
if (m_pGoalEnt != nullptr)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2022-03-14 19:26:28 +01:00
|
|
|
if (m_pGoalEnt->pev->speed == 0)
|
|
|
|
{
|
|
|
|
SetThink(&COsprey::DeployThink);
|
|
|
|
}
|
|
|
|
do
|
|
|
|
{
|
|
|
|
m_pGoalEnt = CBaseEntity::Instance(FIND_ENTITY_BY_TARGETNAME(NULL, STRING(m_pGoalEnt->pev->target)));
|
|
|
|
} while (m_pGoalEnt->pev->speed < 400 && !HasDead());
|
|
|
|
UpdateGoal();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2022-03-14 19:25:27 +01:00
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Flight();
|
2022-03-15 12:33:12 +01:00
|
|
|
Update();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void COsprey::Flight()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
float t = (gpGlobals->time - m_startTime);
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2022-03-14 19:26:28 +01:00
|
|
|
//Only update if delta time is non-zero. It's zero if we're not moving at all (usually because we have no target).
|
|
|
|
if (m_dTime != 0)
|
|
|
|
{
|
|
|
|
float scale = 1.0 / m_dTime;
|
|
|
|
|
|
|
|
float f = UTIL_SplineFraction(t * scale, 1.0);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2022-03-14 19:26:28 +01:00
|
|
|
Vector pos = (m_pos1 + m_vel1 * t) * (1.0 - f) + (m_pos2 - m_vel2 * (m_dTime - t)) * f;
|
|
|
|
Vector ang = (m_ang1) * (1.0 - f) + (m_ang2)*f;
|
|
|
|
m_velocity = m_vel1 * (1.0 - f) + m_vel2 * f;
|
|
|
|
|
|
|
|
UTIL_SetOrigin(pev, pos);
|
|
|
|
pev->angles = ang;
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeAimVectors(pev->angles);
|
|
|
|
float flSpeed = DotProduct(gpGlobals->v_forward, m_velocity);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// float flSpeed = DotProduct( gpGlobals->v_forward, pev->velocity );
|
|
|
|
|
|
|
|
float m_flIdealtilt = (160 - flSpeed) / 10.0;
|
|
|
|
|
|
|
|
// ALERT( at_console, "%f %f\n", flSpeed, flIdealtilt );
|
|
|
|
if (m_flRotortilt < m_flIdealtilt)
|
|
|
|
{
|
|
|
|
m_flRotortilt += 0.5;
|
|
|
|
if (m_flRotortilt > 0)
|
|
|
|
m_flRotortilt = 0;
|
|
|
|
}
|
|
|
|
if (m_flRotortilt > m_flIdealtilt)
|
|
|
|
{
|
|
|
|
m_flRotortilt -= 0.5;
|
|
|
|
if (m_flRotortilt < -90)
|
|
|
|
m_flRotortilt = -90;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
SetBoneController(0, m_flRotortilt);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
|
|
|
if (m_iSoundState == 0)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, 0, 110);
|
2013-08-30 13:34:05 -07:00
|
|
|
// EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", 0.5, 0.2, 0, 110 );
|
|
|
|
|
|
|
|
m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pPlayer = NULL;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
pPlayer = UTIL_FindEntityByClassname(NULL, "player");
|
|
|
|
// UNDONE: this needs to send different sounds to every player for multiplayer.
|
2013-08-30 13:34:05 -07:00
|
|
|
if (pPlayer)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
float pitch = DotProduct(m_velocity - pPlayer->pev->velocity, (pPlayer->pev->origin - pev->origin).Normalize());
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
pitch = (int)(100 + pitch / 75.0);
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pitch > 250)
|
2013-08-30 13:34:05 -07:00
|
|
|
pitch = 250;
|
|
|
|
if (pitch < 50)
|
|
|
|
pitch = 50;
|
|
|
|
|
|
|
|
if (pitch == 100)
|
|
|
|
pitch = 101;
|
|
|
|
|
|
|
|
if (pitch != m_iPitch)
|
|
|
|
{
|
|
|
|
m_iPitch = pitch;
|
|
|
|
EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav", 1.0, 0.15, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch);
|
|
|
|
// ALERT( at_console, "%.0f\n", pitch );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// EMIT_SOUND_DYN(ENT(pev), CHAN_STATIC, "apache/ap_whine1.wav", flVol, 0.2, SND_CHANGE_PITCH | SND_CHANGE_VOL, pitch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void COsprey::HitTouch(CBaseEntity* pOther)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->nextthink = gpGlobals->time + 2.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
int COsprey::TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType )
|
|
|
|
{
|
|
|
|
if (m_flRotortilt <= -90)
|
|
|
|
{
|
|
|
|
m_flRotortilt = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_flRotortilt -= 45;
|
|
|
|
}
|
|
|
|
SetBoneController( 0, m_flRotortilt );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void COsprey::Killed(entvars_t* pevAttacker, int iGib)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->movetype = MOVETYPE_TOSS;
|
|
|
|
pev->gravity = 0.3;
|
|
|
|
pev->velocity = m_velocity;
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->avelocity = Vector(RANDOM_FLOAT(-20, 20), 0, RANDOM_FLOAT(-50, 50));
|
|
|
|
STOP_SOUND(ENT(pev), CHAN_STATIC, "apache/ap_rotor4.wav");
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetSize(pev, Vector(-32, -32, -64), Vector(32, 32, 0));
|
|
|
|
SetThink(&COsprey::DyingThink);
|
|
|
|
SetTouch(&COsprey::CrashTouch);
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->nextthink = gpGlobals->time + 0.1;
|
|
|
|
pev->health = 0;
|
|
|
|
pev->takedamage = DAMAGE_NO;
|
2022-03-15 12:33:12 +01:00
|
|
|
pev->deadflag = DEAD_DYING;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
m_startTime = gpGlobals->time + 4.0;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void COsprey::CrashTouch(CBaseEntity* pOther)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// only crash if we hit something solid
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pOther->pev->solid == SOLID_BSP)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
SetTouch(NULL);
|
2013-08-30 13:34:05 -07:00
|
|
|
m_startTime = gpGlobals->time;
|
|
|
|
pev->nextthink = gpGlobals->time;
|
|
|
|
m_velocity = pev->velocity;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void COsprey::DyingThink()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
StudioFrameAdvance();
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->nextthink = gpGlobals->time + 0.1;
|
|
|
|
|
|
|
|
pev->avelocity = pev->avelocity * 1.02;
|
|
|
|
|
|
|
|
// still falling?
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_startTime > gpGlobals->time)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeAimVectors(pev->angles);
|
2022-03-15 12:33:12 +01:00
|
|
|
Update();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
Vector vecSpot = pev->origin + pev->velocity * 0.2;
|
|
|
|
|
|
|
|
// random explosions
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSpot);
|
|
|
|
WRITE_BYTE(TE_EXPLOSION); // This just makes a dynamic light now
|
|
|
|
WRITE_COORD(vecSpot.x + RANDOM_FLOAT(-150, 150));
|
|
|
|
WRITE_COORD(vecSpot.y + RANDOM_FLOAT(-150, 150));
|
|
|
|
WRITE_COORD(vecSpot.z + RANDOM_FLOAT(-150, -50));
|
|
|
|
WRITE_SHORT(g_sModelIndexFireball);
|
|
|
|
WRITE_BYTE(RANDOM_LONG(0, 29) + 30); // scale * 10
|
|
|
|
WRITE_BYTE(12); // framerate
|
|
|
|
WRITE_BYTE(TE_EXPLFLAG_NONE);
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
|
|
|
// lots of smoke
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSpot);
|
|
|
|
WRITE_BYTE(TE_SMOKE);
|
|
|
|
WRITE_COORD(vecSpot.x + RANDOM_FLOAT(-150, 150));
|
|
|
|
WRITE_COORD(vecSpot.y + RANDOM_FLOAT(-150, 150));
|
|
|
|
WRITE_COORD(vecSpot.z + RANDOM_FLOAT(-150, -50));
|
|
|
|
WRITE_SHORT(g_sModelIndexSmoke);
|
|
|
|
WRITE_BYTE(100); // scale * 10
|
|
|
|
WRITE_BYTE(10); // framerate
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
|
|
|
|
|
|
|
vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5;
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSpot);
|
|
|
|
WRITE_BYTE(TE_BREAKMODEL);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// position
|
|
|
|
WRITE_COORD(vecSpot.x);
|
|
|
|
WRITE_COORD(vecSpot.y);
|
|
|
|
WRITE_COORD(vecSpot.z);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// size
|
|
|
|
WRITE_COORD(800);
|
|
|
|
WRITE_COORD(800);
|
|
|
|
WRITE_COORD(132);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// velocity
|
|
|
|
WRITE_COORD(pev->velocity.x);
|
|
|
|
WRITE_COORD(pev->velocity.y);
|
|
|
|
WRITE_COORD(pev->velocity.z);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// randomization
|
|
|
|
WRITE_BYTE(50);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// Model
|
|
|
|
WRITE_SHORT(m_iTailGibs); //model id#
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// # of shards
|
|
|
|
WRITE_BYTE(8); // let client decide
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// duration
|
|
|
|
WRITE_BYTE(200); // 10.0 seconds
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// flags
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
WRITE_BYTE(BREAK_METAL);
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// don't stop it we touch a entity
|
|
|
|
pev->flags &= ~FL_ONGROUND;
|
|
|
|
pev->nextthink = gpGlobals->time + 0.2;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Vector vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5;
|
|
|
|
|
|
|
|
/*
|
|
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
|
|
WRITE_BYTE( TE_EXPLOSION); // This just makes a dynamic light now
|
|
|
|
WRITE_COORD( vecSpot.x );
|
|
|
|
WRITE_COORD( vecSpot.y );
|
|
|
|
WRITE_COORD( vecSpot.z + 512 );
|
|
|
|
WRITE_SHORT( m_iExplode );
|
|
|
|
WRITE_BYTE( 250 ); // scale * 10
|
|
|
|
WRITE_BYTE( 10 ); // framerate
|
|
|
|
MESSAGE_END();
|
|
|
|
*/
|
|
|
|
|
|
|
|
// gibs
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSpot);
|
|
|
|
WRITE_BYTE(TE_SPRITE);
|
|
|
|
WRITE_COORD(vecSpot.x);
|
|
|
|
WRITE_COORD(vecSpot.y);
|
|
|
|
WRITE_COORD(vecSpot.z + 512);
|
|
|
|
WRITE_SHORT(m_iExplode);
|
|
|
|
WRITE_BYTE(250); // scale * 10
|
|
|
|
WRITE_BYTE(255); // brightness
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
|
|
|
/*
|
|
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
|
|
WRITE_BYTE( TE_SMOKE );
|
|
|
|
WRITE_COORD( vecSpot.x );
|
|
|
|
WRITE_COORD( vecSpot.y );
|
|
|
|
WRITE_COORD( vecSpot.z + 300 );
|
|
|
|
WRITE_SHORT( g_sModelIndexSmoke );
|
|
|
|
WRITE_BYTE( 250 ); // scale * 10
|
|
|
|
WRITE_BYTE( 6 ); // framerate
|
|
|
|
MESSAGE_END();
|
|
|
|
*/
|
|
|
|
|
|
|
|
// blast circle
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PAS, SVC_TEMPENTITY, pev->origin);
|
|
|
|
WRITE_BYTE(TE_BEAMCYLINDER);
|
|
|
|
WRITE_COORD(pev->origin.x);
|
|
|
|
WRITE_COORD(pev->origin.y);
|
|
|
|
WRITE_COORD(pev->origin.z);
|
|
|
|
WRITE_COORD(pev->origin.x);
|
|
|
|
WRITE_COORD(pev->origin.y);
|
|
|
|
WRITE_COORD(pev->origin.z + 2000); // reach damage radius over .2 seconds
|
|
|
|
WRITE_SHORT(m_iSpriteTexture);
|
|
|
|
WRITE_BYTE(0); // startframe
|
|
|
|
WRITE_BYTE(0); // framerate
|
|
|
|
WRITE_BYTE(4); // life
|
|
|
|
WRITE_BYTE(32); // width
|
|
|
|
WRITE_BYTE(0); // noise
|
|
|
|
WRITE_BYTE(255); // r, g, b
|
|
|
|
WRITE_BYTE(255); // r, g, b
|
|
|
|
WRITE_BYTE(192); // r, g, b
|
|
|
|
WRITE_BYTE(128); // brightness
|
|
|
|
WRITE_BYTE(0); // speed
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_STATIC, "weapons/mortarhit.wav", 1.0, 0.3);
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
RadiusDamage(pev->origin, pev, pev, 300, CLASS_NONE, DMG_BLAST);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// gibs
|
|
|
|
vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5;
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PAS, SVC_TEMPENTITY, vecSpot);
|
|
|
|
WRITE_BYTE(TE_BREAKMODEL);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// position
|
|
|
|
WRITE_COORD(vecSpot.x);
|
|
|
|
WRITE_COORD(vecSpot.y);
|
|
|
|
WRITE_COORD(vecSpot.z + 64);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// size
|
|
|
|
WRITE_COORD(800);
|
|
|
|
WRITE_COORD(800);
|
|
|
|
WRITE_COORD(128);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// velocity
|
|
|
|
WRITE_COORD(m_velocity.x);
|
|
|
|
WRITE_COORD(m_velocity.y);
|
|
|
|
WRITE_COORD(fabs(m_velocity.z) * 0.25);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// randomization
|
|
|
|
WRITE_BYTE(40);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// Model
|
|
|
|
WRITE_SHORT(m_iBodyGibs); //model id#
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// # of shards
|
|
|
|
WRITE_BYTE(128);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// duration
|
|
|
|
WRITE_BYTE(200); // 10.0 seconds
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// flags
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
WRITE_BYTE(BREAK_METAL);
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_Remove(this);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void COsprey::ShowDamage()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_iDoLeftSmokePuff > 0 || RANDOM_LONG(0, 99) > m_flLeftHealth)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
Vector vecSrc = pev->origin + gpGlobals->v_right * -340;
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSrc);
|
|
|
|
WRITE_BYTE(TE_SMOKE);
|
|
|
|
WRITE_COORD(vecSrc.x);
|
|
|
|
WRITE_COORD(vecSrc.y);
|
|
|
|
WRITE_COORD(vecSrc.z);
|
|
|
|
WRITE_SHORT(g_sModelIndexSmoke);
|
|
|
|
WRITE_BYTE(RANDOM_LONG(0, 9) + 20); // scale * 10
|
|
|
|
WRITE_BYTE(12); // framerate
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
if (m_iDoLeftSmokePuff > 0)
|
|
|
|
m_iDoLeftSmokePuff--;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_iDoRightSmokePuff > 0 || RANDOM_LONG(0, 99) > m_flRightHealth)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
Vector vecSrc = pev->origin + gpGlobals->v_right * 340;
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSrc);
|
|
|
|
WRITE_BYTE(TE_SMOKE);
|
|
|
|
WRITE_COORD(vecSrc.x);
|
|
|
|
WRITE_COORD(vecSrc.y);
|
|
|
|
WRITE_COORD(vecSrc.z);
|
|
|
|
WRITE_SHORT(g_sModelIndexSmoke);
|
|
|
|
WRITE_BYTE(RANDOM_LONG(0, 9) + 20); // scale * 10
|
|
|
|
WRITE_BYTE(12); // framerate
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
if (m_iDoRightSmokePuff > 0)
|
|
|
|
m_iDoRightSmokePuff--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-15 12:33:12 +01:00
|
|
|
void COsprey::Update()
|
|
|
|
{
|
|
|
|
//Look around so AI triggers work.
|
|
|
|
Look(4092);
|
|
|
|
|
|
|
|
//Listen for sounds so AI triggers work.
|
|
|
|
Listen();
|
|
|
|
|
|
|
|
ShowDamage();
|
|
|
|
FCheckAITrigger();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool COsprey::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
|
|
|
|
{
|
|
|
|
//Set enemy to last attacker.
|
|
|
|
//Ospreys are not capable of fighting so they'll get angry at whatever shoots at them, not whatever looks like an enemy.
|
|
|
|
m_hEnemy = Instance(pevAttacker);
|
|
|
|
|
|
|
|
//It's on now!
|
|
|
|
m_MonsterState = MONSTERSTATE_COMBAT;
|
|
|
|
|
|
|
|
return CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void COsprey::TraceAttack(entvars_t* pevAttacker, float flDamage, Vector vecDir, TraceResult* ptr, int bitsDamageType)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// ALERT( at_console, "%d %.0f\n", ptr->iHitgroup, flDamage );
|
|
|
|
|
|
|
|
// only so much per engine
|
|
|
|
if (ptr->iHitgroup == 3)
|
|
|
|
{
|
|
|
|
if (m_flRightHealth < 0)
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
m_flRightHealth -= flDamage;
|
2022-03-15 17:15:51 +01:00
|
|
|
m_iDoRightSmokePuff = 3 + (flDamage / 5.0);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr->iHitgroup == 2)
|
|
|
|
{
|
|
|
|
if (m_flLeftHealth < 0)
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
m_flLeftHealth -= flDamage;
|
2022-03-15 17:15:51 +01:00
|
|
|
m_iDoLeftSmokePuff = 3 + (flDamage / 5.0);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// hit hard, hits cockpit, hits engines
|
|
|
|
if (flDamage > 50 || ptr->iHitgroup == 1 || ptr->iHitgroup == 2 || ptr->iHitgroup == 3)
|
|
|
|
{
|
|
|
|
// ALERT( at_console, "%.0f\n", flDamage );
|
2021-11-28 16:54:48 +01:00
|
|
|
AddMultiDamage(pevAttacker, this, flDamage, bitsDamageType);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_Sparks(ptr->vecEndPos);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|