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.
|
|
|
|
*
|
|
|
|
****/
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// Gargantua
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
#include "extdll.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "cbase.h"
|
|
|
|
#include "monsters.h"
|
|
|
|
#include "schedule.h"
|
|
|
|
#include "customentity.h"
|
|
|
|
#include "weapons.h"
|
|
|
|
#include "effects.h"
|
|
|
|
#include "soundent.h"
|
|
|
|
#include "decals.h"
|
|
|
|
#include "explode.h"
|
|
|
|
#include "func_break.h"
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// Gargantua Monster
|
|
|
|
//=========================================================
|
|
|
|
const float GARG_ATTACKDIST = 80.0;
|
|
|
|
|
|
|
|
// Garg animation events
|
2021-11-28 16:54:48 +01:00
|
|
|
#define GARG_AE_SLASH_LEFT 1
|
2013-08-30 13:34:05 -07:00
|
|
|
//#define GARG_AE_BEAM_ATTACK_RIGHT 2 // No longer used
|
2021-11-28 16:54:48 +01:00
|
|
|
#define GARG_AE_LEFT_FOOT 3
|
|
|
|
#define GARG_AE_RIGHT_FOOT 4
|
|
|
|
#define GARG_AE_STOMP 5
|
|
|
|
#define GARG_AE_BREATHE 6
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
|
|
|
// Gargantua is immune to any damage but this
|
2021-11-28 16:54:48 +01:00
|
|
|
#define GARG_DAMAGE (DMG_ENERGYBEAM | DMG_CRUSH | DMG_MORTAR | DMG_BLAST)
|
|
|
|
#define GARG_EYE_SPRITE_NAME "sprites/gargeye1.spr"
|
|
|
|
#define GARG_BEAM_SPRITE_NAME "sprites/xbeam3.spr"
|
|
|
|
#define GARG_BEAM_SPRITE2 "sprites/xbeam3.spr"
|
|
|
|
#define GARG_STOMP_SPRITE_NAME "sprites/gargeye1.spr"
|
|
|
|
#define GARG_STOMP_BUZZ_SOUND "weapons/mine_charge.wav"
|
|
|
|
#define GARG_FLAME_LENGTH 330
|
|
|
|
#define GARG_GIB_MODEL "models/metalplategibs.mdl"
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define ATTN_GARG (ATTN_NORM)
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define STOMP_SPRITE_COUNT 10
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
int gStompSprite = 0, gGargGibModel = 0;
|
2021-11-28 16:54:48 +01:00
|
|
|
void SpawnExplosion(Vector center, float randomRange, float time, int magnitude);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
class CSmoker;
|
|
|
|
|
|
|
|
// Spiral Effect
|
|
|
|
class CSpiral : public CBaseEntity
|
|
|
|
{
|
|
|
|
public:
|
2021-03-05 23:07:22 +01:00
|
|
|
void Spawn() override;
|
|
|
|
void Think() override;
|
|
|
|
int ObjectCaps() override { return FCAP_DONT_SAVE; }
|
2021-11-28 16:54:48 +01:00
|
|
|
static CSpiral* Create(const Vector& origin, float height, float radius, float duration);
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
2021-11-28 16:54:48 +01:00
|
|
|
LINK_ENTITY_TO_CLASS(streak_spiral, CSpiral);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
|
|
|
class CStomp : public CBaseEntity
|
|
|
|
{
|
|
|
|
public:
|
2021-03-05 23:07:22 +01:00
|
|
|
void Spawn() override;
|
|
|
|
void Think() override;
|
2021-11-28 16:54:48 +01:00
|
|
|
static CStomp* StompCreate(const Vector& origin, const Vector& end, float speed);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
bool Save(CSave& save) override;
|
|
|
|
bool Restore(CRestore& restore) override;
|
|
|
|
static TYPEDESCRIPTION m_SaveData[];
|
2021-03-11 14:38:20 +01:00
|
|
|
|
|
|
|
float m_flLastThinkTime;
|
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
private:
|
2021-11-28 16:54:48 +01:00
|
|
|
// UNDONE: re-use this sprite list instead of creating new ones all the time
|
|
|
|
// CSprite *m_pSprites[ STOMP_SPRITE_COUNT ];
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
LINK_ENTITY_TO_CLASS(garg_stomp, CStomp);
|
2021-03-11 14:38:20 +01:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
TYPEDESCRIPTION CStomp::m_SaveData[] =
|
|
|
|
{
|
|
|
|
DEFINE_FIELD(CStomp, m_flLastThinkTime, FIELD_TIME),
|
2021-03-11 14:38:20 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
IMPLEMENT_SAVERESTORE(CStomp, CBaseEntity);
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CStomp* CStomp::StompCreate(const Vector& origin, const Vector& end, float speed)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CStomp* pStomp = GetClassPtr((CStomp*)NULL);
|
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
pStomp->pev->origin = origin;
|
|
|
|
Vector dir = (end - origin);
|
|
|
|
pStomp->pev->scale = dir.Length();
|
|
|
|
pStomp->pev->movedir = dir.Normalize();
|
|
|
|
pStomp->pev->speed = speed;
|
|
|
|
pStomp->Spawn();
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
return pStomp;
|
|
|
|
}
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CStomp::Spawn()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->nextthink = gpGlobals->time;
|
|
|
|
pev->classname = MAKE_STRING("garg_stomp");
|
|
|
|
pev->dmgtime = gpGlobals->time;
|
|
|
|
|
|
|
|
pev->framerate = 30;
|
|
|
|
pev->model = MAKE_STRING(GARG_STOMP_SPRITE_NAME);
|
|
|
|
pev->rendermode = kRenderTransTexture;
|
|
|
|
pev->renderamt = 0;
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND_DYN(edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND, 1, ATTN_NORM, 0, PITCH_NORM * 0.55);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define STOMP_INTERVAL 0.025
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CStomp::Think()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-03-11 14:38:20 +01:00
|
|
|
if (m_flLastThinkTime == 0)
|
|
|
|
{
|
|
|
|
m_flLastThinkTime = gpGlobals->time - gpGlobals->frametime;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Use 1/4th the delta time to match the original behavior more closely
|
|
|
|
const float deltaTime = (gpGlobals->time - m_flLastThinkTime) / 4;
|
|
|
|
|
|
|
|
m_flLastThinkTime = gpGlobals->time;
|
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
TraceResult tr;
|
|
|
|
|
|
|
|
pev->nextthink = gpGlobals->time + 0.1;
|
|
|
|
|
|
|
|
// Do damage for this frame
|
|
|
|
Vector vecStart = pev->origin;
|
|
|
|
vecStart.z += 30;
|
2021-03-11 14:38:20 +01:00
|
|
|
Vector vecEnd = vecStart + (pev->movedir * pev->speed * deltaTime);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceHull(vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr);
|
|
|
|
|
|
|
|
if (tr.pHit && tr.pHit != pev->owner)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = CBaseEntity::Instance(tr.pHit);
|
|
|
|
entvars_t* pevOwner = pev;
|
|
|
|
if (pev->owner)
|
2013-08-30 13:34:05 -07:00
|
|
|
pevOwner = VARS(pev->owner);
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pEntity)
|
|
|
|
pEntity->TakeDamage(pev, pevOwner, gSkillData.gargantuaDmgStomp, DMG_SONIC);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
// Accelerate the effect
|
2021-03-11 14:38:20 +01:00
|
|
|
pev->speed = pev->speed + deltaTime * pev->framerate;
|
|
|
|
pev->framerate = pev->framerate + deltaTime * 1500;
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
// Move and spawn trails
|
2021-11-28 16:54:48 +01:00
|
|
|
while (gpGlobals->time - pev->dmgtime > STOMP_INTERVAL)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->origin = pev->origin + pev->movedir * pev->speed * STOMP_INTERVAL;
|
2021-11-28 16:54:48 +01:00
|
|
|
for (int i = 0; i < 2; i++)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CSprite* pSprite = CSprite::SpriteCreate(GARG_STOMP_SPRITE_NAME, pev->origin, true);
|
|
|
|
if (pSprite)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceLine(pev->origin, pev->origin - Vector(0, 0, 500), ignore_monsters, edict(), &tr);
|
2013-08-30 13:34:05 -07:00
|
|
|
pSprite->pev->origin = tr.vecEndPos;
|
2021-11-28 16:54:48 +01:00
|
|
|
pSprite->pev->velocity = Vector(RANDOM_FLOAT(-200, 200), RANDOM_FLOAT(-200, 200), 175);
|
2013-08-30 13:34:05 -07:00
|
|
|
// pSprite->AnimateAndDie( RANDOM_FLOAT( 8.0, 12.0 ) );
|
|
|
|
pSprite->pev->nextthink = gpGlobals->time + 0.3;
|
2021-11-28 16:54:48 +01:00
|
|
|
pSprite->SetThink(&CSprite::SUB_Remove);
|
|
|
|
pSprite->SetTransparency(kRenderTransAdd, 255, 255, 255, 255, kRenderFxFadeFast);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pev->dmgtime += STOMP_INTERVAL;
|
|
|
|
// Scale has the "life" of this effect
|
|
|
|
pev->scale -= STOMP_INTERVAL * pev->speed;
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->scale <= 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// Life has run out
|
|
|
|
UTIL_Remove(this);
|
2021-11-28 16:54:48 +01:00
|
|
|
STOP_SOUND(edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void StreakSplash(const Vector& origin, const Vector& direction, int color, int count, int speed, int velocityRange)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, origin);
|
|
|
|
WRITE_BYTE(TE_STREAK_SPLASH);
|
|
|
|
WRITE_COORD(origin.x); // origin
|
|
|
|
WRITE_COORD(origin.y);
|
|
|
|
WRITE_COORD(origin.z);
|
|
|
|
WRITE_COORD(direction.x); // direction
|
|
|
|
WRITE_COORD(direction.y);
|
|
|
|
WRITE_COORD(direction.z);
|
|
|
|
WRITE_BYTE(color); // Streak color 6
|
|
|
|
WRITE_SHORT(count); // count
|
|
|
|
WRITE_SHORT(speed);
|
|
|
|
WRITE_SHORT(velocityRange); // Random velocity modifier
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class CGargantua : public CBaseMonster
|
|
|
|
{
|
|
|
|
public:
|
2021-03-05 23:07:22 +01:00
|
|
|
void Spawn() override;
|
|
|
|
void Precache() override;
|
|
|
|
void SetYawSpeed() override;
|
2021-11-28 16:54:48 +01:00
|
|
|
int Classify() override;
|
|
|
|
bool TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType) override;
|
|
|
|
void TraceAttack(entvars_t* pevAttacker, float flDamage, Vector vecDir, TraceResult* ptr, int bitsDamageType) override;
|
|
|
|
void HandleAnimEvent(MonsterEvent_t* pEvent) override;
|
|
|
|
|
|
|
|
bool CheckMeleeAttack1(float flDot, float flDist) override; // Swipe
|
|
|
|
bool CheckMeleeAttack2(float flDot, float flDist) override; // Flames
|
|
|
|
bool CheckRangeAttack1(float flDot, float flDist) override; // Stomp attack
|
2021-03-05 23:07:22 +01:00
|
|
|
void SetObjectCollisionBox() override
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->absmin = pev->origin + Vector(-80, -80, 0);
|
|
|
|
pev->absmax = pev->origin + Vector(80, 80, 214);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t* GetScheduleOfType(int Type) override;
|
|
|
|
void StartTask(Task_t* pTask) override;
|
|
|
|
void RunTask(Task_t* pTask) override;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-03-05 23:07:22 +01:00
|
|
|
void PrescheduleThink() override;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void Killed(entvars_t* pevAttacker, int iGib) override;
|
2021-03-05 20:54:33 +01:00
|
|
|
void DeathEffect();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void EyeOff();
|
2021-11-28 16:54:48 +01:00
|
|
|
void EyeOn(int level);
|
2021-03-05 20:54:33 +01:00
|
|
|
void EyeUpdate();
|
|
|
|
void Leap();
|
|
|
|
void StompAttack();
|
|
|
|
void FlameCreate();
|
|
|
|
void FlameUpdate();
|
2021-11-28 16:54:48 +01:00
|
|
|
void FlameControls(float angleX, float angleY);
|
2021-03-05 20:54:33 +01:00
|
|
|
void FlameDestroy();
|
2021-11-19 14:31:11 +01:00
|
|
|
inline bool FlameIsOn() { return m_pFlame[0] != NULL; }
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void FlameDamage(Vector vecStart, Vector vecEnd, entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
bool Save(CSave& save) override;
|
|
|
|
bool Restore(CRestore& restore) override;
|
|
|
|
static TYPEDESCRIPTION m_SaveData[];
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
CUSTOM_SCHEDULES;
|
|
|
|
|
|
|
|
private:
|
2021-11-28 16:54:48 +01:00
|
|
|
static const char* pAttackHitSounds[];
|
|
|
|
static const char* pBeamAttackSounds[];
|
|
|
|
static const char* pAttackMissSounds[];
|
|
|
|
static const char* pRicSounds[];
|
|
|
|
static const char* pFootSounds[];
|
|
|
|
static const char* pIdleSounds[];
|
|
|
|
static const char* pAlertSounds[];
|
|
|
|
static const char* pPainSounds[];
|
|
|
|
static const char* pAttackSounds[];
|
|
|
|
static const char* pStompSounds[];
|
|
|
|
static const char* pBreatheSounds[];
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
CBaseEntity* GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType);
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CSprite* m_pEyeGlow; // Glow around the eyes
|
|
|
|
CBeam* m_pFlame[4]; // Flame beams
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
int m_eyeBrightness; // Brightness target
|
|
|
|
float m_seeTime; // Time to attack (when I see the enemy, I set this)
|
|
|
|
float m_flameTime; // Time of next flame attack
|
|
|
|
float m_painSoundTime; // Time of next pain sound
|
|
|
|
float m_streakTime; // streak timer (don't send too many)
|
|
|
|
float m_flameX; // Flame thrower aim
|
|
|
|
float m_flameY;
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
LINK_ENTITY_TO_CLASS(monster_gargantua, CGargantua);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
TYPEDESCRIPTION CGargantua::m_SaveData[] =
|
|
|
|
{
|
|
|
|
DEFINE_FIELD(CGargantua, m_pEyeGlow, FIELD_CLASSPTR),
|
|
|
|
DEFINE_FIELD(CGargantua, m_eyeBrightness, FIELD_INTEGER),
|
|
|
|
DEFINE_FIELD(CGargantua, m_seeTime, FIELD_TIME),
|
|
|
|
DEFINE_FIELD(CGargantua, m_flameTime, FIELD_TIME),
|
|
|
|
DEFINE_FIELD(CGargantua, m_streakTime, FIELD_TIME),
|
|
|
|
DEFINE_FIELD(CGargantua, m_painSoundTime, FIELD_TIME),
|
|
|
|
DEFINE_ARRAY(CGargantua, m_pFlame, FIELD_CLASSPTR, 4),
|
|
|
|
DEFINE_FIELD(CGargantua, m_flameX, FIELD_FLOAT),
|
|
|
|
DEFINE_FIELD(CGargantua, m_flameY, FIELD_FLOAT),
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
IMPLEMENT_SAVERESTORE(CGargantua, CBaseMonster);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pAttackHitSounds[] =
|
|
|
|
{
|
|
|
|
"zombie/claw_strike1.wav",
|
|
|
|
"zombie/claw_strike2.wav",
|
|
|
|
"zombie/claw_strike3.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pBeamAttackSounds[] =
|
|
|
|
{
|
|
|
|
"garg/gar_flameoff1.wav",
|
|
|
|
"garg/gar_flameon1.wav",
|
|
|
|
"garg/gar_flamerun1.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pAttackMissSounds[] =
|
|
|
|
{
|
|
|
|
"zombie/claw_miss1.wav",
|
|
|
|
"zombie/claw_miss2.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pRicSounds[] =
|
|
|
|
{
|
2013-08-30 13:34:05 -07:00
|
|
|
#if 0
|
|
|
|
"weapons/ric1.wav",
|
|
|
|
"weapons/ric2.wav",
|
|
|
|
"weapons/ric3.wav",
|
|
|
|
"weapons/ric4.wav",
|
|
|
|
"weapons/ric5.wav",
|
|
|
|
#else
|
2021-11-28 16:54:48 +01:00
|
|
|
"debris/metal4.wav",
|
|
|
|
"debris/metal6.wav",
|
|
|
|
"weapons/ric4.wav",
|
|
|
|
"weapons/ric5.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pFootSounds[] =
|
|
|
|
{
|
|
|
|
"garg/gar_step1.wav",
|
|
|
|
"garg/gar_step2.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pIdleSounds[] =
|
|
|
|
{
|
|
|
|
"garg/gar_idle1.wav",
|
|
|
|
"garg/gar_idle2.wav",
|
|
|
|
"garg/gar_idle3.wav",
|
|
|
|
"garg/gar_idle4.wav",
|
|
|
|
"garg/gar_idle5.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pAttackSounds[] =
|
|
|
|
{
|
|
|
|
"garg/gar_attack1.wav",
|
|
|
|
"garg/gar_attack2.wav",
|
|
|
|
"garg/gar_attack3.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pAlertSounds[] =
|
|
|
|
{
|
|
|
|
"garg/gar_alert1.wav",
|
|
|
|
"garg/gar_alert2.wav",
|
|
|
|
"garg/gar_alert3.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pPainSounds[] =
|
|
|
|
{
|
|
|
|
"garg/gar_pain1.wav",
|
|
|
|
"garg/gar_pain2.wav",
|
|
|
|
"garg/gar_pain3.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pStompSounds[] =
|
|
|
|
{
|
|
|
|
"garg/gar_stomp1.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
const char* CGargantua::pBreatheSounds[] =
|
|
|
|
{
|
|
|
|
"garg/gar_breathe1.wav",
|
|
|
|
"garg/gar_breathe2.wav",
|
|
|
|
"garg/gar_breathe3.wav",
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
//=========================================================
|
|
|
|
// AI Schedules Specific to this monster
|
|
|
|
//=========================================================
|
|
|
|
#if 0
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
SCHED_ = LAST_COMMON_SCHEDULE + 1,
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
TASK_SOUND_ATTACK = LAST_COMMON_TASK + 1,
|
|
|
|
TASK_FLAME_SWEEP,
|
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlGargFlame[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, (float)0},
|
|
|
|
{TASK_FACE_ENEMY, (float)0},
|
|
|
|
{TASK_SOUND_ATTACK, (float)0},
|
|
|
|
// { TASK_PLAY_SEQUENCE, (float)ACT_SIGNAL1 },
|
|
|
|
{TASK_SET_ACTIVITY, (float)ACT_MELEE_ATTACK2},
|
|
|
|
{TASK_FLAME_SWEEP, (float)4.5},
|
|
|
|
{TASK_SET_ACTIVITY, (float)ACT_IDLE},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slGargFlame[] =
|
|
|
|
{
|
|
|
|
{tlGargFlame,
|
|
|
|
ARRAYSIZE(tlGargFlame),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
"GargFlame"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// primary melee attack
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlGargSwipe[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, 0},
|
|
|
|
{TASK_FACE_ENEMY, (float)0},
|
|
|
|
{TASK_MELEE_ATTACK1, (float)0},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slGargSwipe[] =
|
|
|
|
{
|
|
|
|
{tlGargSwipe,
|
|
|
|
ARRAYSIZE(tlGargSwipe),
|
|
|
|
bits_COND_CAN_MELEE_ATTACK2,
|
|
|
|
0,
|
|
|
|
"GargSwipe"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
DEFINE_CUSTOM_SCHEDULES(CGargantua){
|
2013-08-30 13:34:05 -07:00
|
|
|
slGargFlame,
|
|
|
|
slGargSwipe,
|
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
IMPLEMENT_CUSTOM_SCHEDULES(CGargantua, CBaseMonster);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void CGargantua::EyeOn(int level)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_eyeBrightness = level;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CGargantua::EyeOff()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
m_eyeBrightness = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CGargantua::EyeUpdate()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_pEyeGlow)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_pEyeGlow->pev->renderamt = UTIL_Approach(m_eyeBrightness, m_pEyeGlow->pev->renderamt, 26);
|
|
|
|
if (m_pEyeGlow->pev->renderamt == 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
m_pEyeGlow->pev->effects |= EF_NODRAW;
|
|
|
|
else
|
|
|
|
m_pEyeGlow->pev->effects &= ~EF_NODRAW;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetOrigin(m_pEyeGlow->pev, pev->origin);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CGargantua::StompAttack()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
TraceResult trace;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeVectors(pev->angles);
|
|
|
|
Vector vecStart = pev->origin + Vector(0, 0, 60) + 35 * gpGlobals->v_forward;
|
|
|
|
Vector vecAim = ShootAtEnemy(vecStart);
|
2013-08-30 13:34:05 -07:00
|
|
|
Vector vecEnd = (vecAim * 1024) + vecStart;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceLine(vecStart, vecEnd, ignore_monsters, edict(), &trace);
|
|
|
|
CStomp::StompCreate(vecStart, trace.vecEndPos, 0);
|
|
|
|
UTIL_ScreenShake(pev->origin, 12.0, 100.0, 2.0, 1000);
|
2021-12-02 17:53:57 -05:00
|
|
|
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pStompSounds), 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10, 10));
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceLine(pev->origin, pev->origin - Vector(0, 0, 20), ignore_monsters, edict(), &trace);
|
|
|
|
if (trace.flFraction < 1.0)
|
|
|
|
UTIL_DecalTrace(&trace, DECAL_GARGSTOMP1);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CGargantua::FlameCreate()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
int i;
|
|
|
|
Vector posGun, angleGun;
|
2013-08-30 13:34:05 -07:00
|
|
|
TraceResult trace;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeVectors(pev->angles);
|
|
|
|
|
|
|
|
for (i = 0; i < 4; i++)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (i < 2)
|
|
|
|
m_pFlame[i] = CBeam::BeamCreate(GARG_BEAM_SPRITE_NAME, 240);
|
2013-08-30 13:34:05 -07:00
|
|
|
else
|
2021-11-28 16:54:48 +01:00
|
|
|
m_pFlame[i] = CBeam::BeamCreate(GARG_BEAM_SPRITE2, 140);
|
|
|
|
if (m_pFlame[i])
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
int attach = i % 2;
|
2013-08-30 13:34:05 -07:00
|
|
|
// attachment is 0 based in GetAttachment
|
2021-11-28 16:54:48 +01:00
|
|
|
GetAttachment(attach + 1, posGun, angleGun);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
Vector vecEnd = (gpGlobals->v_forward * GARG_FLAME_LENGTH) + posGun;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceLine(posGun, vecEnd, dont_ignore_monsters, edict(), &trace);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
m_pFlame[i]->PointEntInit(trace.vecEndPos, entindex());
|
|
|
|
if (i < 2)
|
|
|
|
m_pFlame[i]->SetColor(255, 130, 90);
|
2013-08-30 13:34:05 -07:00
|
|
|
else
|
2021-11-28 16:54:48 +01:00
|
|
|
m_pFlame[i]->SetColor(0, 120, 255);
|
|
|
|
m_pFlame[i]->SetBrightness(190);
|
|
|
|
m_pFlame[i]->SetFlags(BEAM_FSHADEIN);
|
|
|
|
m_pFlame[i]->SetScrollRate(20);
|
2013-08-30 13:34:05 -07:00
|
|
|
// attachment is 1 based in SetEndAttachment
|
2021-11-28 16:54:48 +01:00
|
|
|
m_pFlame[i]->SetEndAttachment(attach + 2);
|
|
|
|
CSoundEnt::InsertSound(bits_SOUND_COMBAT, posGun, 384, 0.3);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND_DYN(edict(), CHAN_BODY, pBeamAttackSounds[1], 1.0, ATTN_NORM, 0, PITCH_NORM);
|
|
|
|
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, pBeamAttackSounds[2], 1.0, ATTN_NORM, 0, PITCH_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CGargantua::FlameControls(float angleX, float angleY)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (angleY < -180)
|
2013-08-30 13:34:05 -07:00
|
|
|
angleY += 360;
|
2021-11-28 16:54:48 +01:00
|
|
|
else if (angleY > 180)
|
2013-08-30 13:34:05 -07:00
|
|
|
angleY -= 360;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (angleY < -45)
|
2013-08-30 13:34:05 -07:00
|
|
|
angleY = -45;
|
2021-11-28 16:54:48 +01:00
|
|
|
else if (angleY > 45)
|
2013-08-30 13:34:05 -07:00
|
|
|
angleY = 45;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
m_flameX = UTIL_ApproachAngle(angleX, m_flameX, 4);
|
|
|
|
m_flameY = UTIL_ApproachAngle(angleY, m_flameY, 8);
|
|
|
|
SetBoneController(0, m_flameY);
|
|
|
|
SetBoneController(1, m_flameX);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CGargantua::FlameUpdate()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
int i;
|
|
|
|
static float offset[2] = {60, -60};
|
|
|
|
TraceResult trace;
|
|
|
|
Vector vecStart, angleGun;
|
|
|
|
bool streaks = false;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
for (i = 0; i < 2; i++)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_pFlame[i])
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
Vector vecAim = pev->angles;
|
|
|
|
vecAim.x += m_flameX;
|
|
|
|
vecAim.y += m_flameY;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeVectors(vecAim);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
GetAttachment(i + 1, vecStart, angleGun);
|
2013-08-30 13:34:05 -07:00
|
|
|
Vector vecEnd = vecStart + (gpGlobals->v_forward * GARG_FLAME_LENGTH); // - offset[i] * gpGlobals->v_right;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceLine(vecStart, vecEnd, dont_ignore_monsters, edict(), &trace);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
m_pFlame[i]->SetStartPos(trace.vecEndPos);
|
|
|
|
m_pFlame[i + 2]->SetStartPos((vecStart * 0.6) + (trace.vecEndPos * 0.4));
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (trace.flFraction != 1.0 && gpGlobals->time > m_streakTime)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
StreakSplash(trace.vecEndPos, trace.vecPlaneNormal, 6, 20, 50, 400);
|
2021-11-19 13:45:16 +01:00
|
|
|
streaks = true;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_DecalTrace(&trace, DECAL_SMALLSCORCH1 + RANDOM_LONG(0, 2));
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
// RadiusDamage( trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN );
|
2021-11-28 16:54:48 +01:00
|
|
|
FlameDamage(vecStart, trace.vecEndPos, pev, pev, gSkillData.gargantuaDmgFire, CLASS_ALIEN_MONSTER, DMG_BURN);
|
|
|
|
|
|
|
|
MESSAGE_BEGIN(MSG_BROADCAST, SVC_TEMPENTITY);
|
|
|
|
WRITE_BYTE(TE_ELIGHT);
|
|
|
|
WRITE_SHORT(entindex() + 0x1000 * (i + 2)); // entity, attachment
|
|
|
|
WRITE_COORD(vecStart.x); // origin
|
|
|
|
WRITE_COORD(vecStart.y);
|
|
|
|
WRITE_COORD(vecStart.z);
|
|
|
|
WRITE_COORD(RANDOM_FLOAT(32, 48)); // radius
|
|
|
|
WRITE_BYTE(255); // R
|
|
|
|
WRITE_BYTE(255); // G
|
|
|
|
WRITE_BYTE(255); // B
|
|
|
|
WRITE_BYTE(2); // life * 10
|
|
|
|
WRITE_COORD(0); // decay
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
}
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
if (streaks)
|
2013-08-30 13:34:05 -07:00
|
|
|
m_streakTime = gpGlobals->time;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CGargantua::FlameDamage(Vector vecStart, Vector vecEnd, entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = NULL;
|
|
|
|
TraceResult tr;
|
|
|
|
float flAdjustedDamage;
|
|
|
|
Vector vecSpot;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
Vector vecMid = (vecStart + vecEnd) * 0.5;
|
|
|
|
|
|
|
|
float searchRadius = (vecStart - vecMid).Length();
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Vector vecAim = (vecEnd - vecStart).Normalize();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// iterate on all entities in the vicinity.
|
2021-11-28 16:54:48 +01:00
|
|
|
while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecMid, searchRadius)) != NULL)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pEntity->pev->takedamage != DAMAGE_NO)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// UNDONE: this should check a damage mask, not an ignore
|
2021-11-28 16:54:48 +01:00
|
|
|
if (iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore)
|
|
|
|
{ // houndeyes don't hurt other houndeyes with their attack
|
2013-08-30 13:34:05 -07:00
|
|
|
continue;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
vecSpot = pEntity->BodyTarget(vecMid);
|
|
|
|
|
|
|
|
float dist = DotProduct(vecAim, vecSpot - vecMid);
|
2013-08-30 13:34:05 -07:00
|
|
|
if (dist > searchRadius)
|
|
|
|
dist = searchRadius;
|
|
|
|
else if (dist < -searchRadius)
|
|
|
|
dist = searchRadius;
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
Vector vecSrc = vecMid + dist * vecAim;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceLine(vecSrc, vecSpot, dont_ignore_monsters, ENT(pev), &tr);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (tr.flFraction == 1.0 || tr.pHit == pEntity->edict())
|
|
|
|
{ // the explosion can 'see' this entity, so hurt them!
|
2013-08-30 13:34:05 -07:00
|
|
|
// decrease damage for an ent that's farther from the flame.
|
2021-11-28 16:54:48 +01:00
|
|
|
dist = (vecSrc - tr.vecEndPos).Length();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
if (dist > 64)
|
|
|
|
{
|
|
|
|
flAdjustedDamage = flDamage - (dist - 64) * 0.4;
|
|
|
|
if (flAdjustedDamage <= 0)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
flAdjustedDamage = flDamage;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ALERT( at_console, "hit %s\n", STRING( pEntity->pev->classname ) );
|
|
|
|
if (tr.flFraction != 1.0)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
ClearMultiDamage();
|
|
|
|
pEntity->TraceAttack(pevInflictor, flAdjustedDamage, (tr.vecEndPos - vecSrc).Normalize(), &tr, bitsDamageType);
|
|
|
|
ApplyMultiDamage(pevInflictor, pevAttacker);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity->TakeDamage(pevInflictor, pevAttacker, flAdjustedDamage, bitsDamageType);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CGargantua::FlameDestroy()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, pBeamAttackSounds[0], 1.0, ATTN_NORM, 0, PITCH_NORM);
|
|
|
|
for (i = 0; i < 4; i++)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_pFlame[i])
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_Remove(m_pFlame[i]);
|
2013-08-30 13:34:05 -07:00
|
|
|
m_pFlame[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CGargantua::PrescheduleThink()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!HasConditions(bits_COND_SEE_ENEMY))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
m_seeTime = gpGlobals->time + 5;
|
|
|
|
EyeOff();
|
|
|
|
}
|
|
|
|
else
|
2021-11-28 16:54:48 +01:00
|
|
|
EyeOn(200);
|
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
EyeUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// Classify - indicates this monster's place in the
|
2013-08-30 13:34:05 -07:00
|
|
|
// relationship table.
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
int CGargantua::Classify()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return CLASS_ALIEN_MONSTER;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// SetYawSpeed - allows each sequence to have a different
|
|
|
|
// turn rate associated with it.
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CGargantua::SetYawSpeed()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
int ys;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (m_Activity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
case ACT_IDLE:
|
|
|
|
ys = 60;
|
|
|
|
break;
|
|
|
|
case ACT_TURN_LEFT:
|
|
|
|
case ACT_TURN_RIGHT:
|
|
|
|
ys = 180;
|
|
|
|
break;
|
|
|
|
case ACT_WALK:
|
|
|
|
case ACT_RUN:
|
|
|
|
ys = 60;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ys = 60;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pev->yaw_speed = ys;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// Spawn
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CGargantua::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
|
|
|
|
|
|
|
SET_MODEL(ENT(pev), "models/garg.mdl");
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetSize(pev, Vector(-32, -32, 0), Vector(32, 32, 64));
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->solid = SOLID_SLIDEBOX;
|
|
|
|
pev->movetype = MOVETYPE_STEP;
|
|
|
|
m_bloodColor = BLOOD_COLOR_GREEN;
|
|
|
|
pev->health = gSkillData.gargantuaHealth;
|
2013-08-30 13:34:05 -07:00
|
|
|
//pev->view_ofs = Vector ( 0, 0, 96 );// taken from mdl file
|
2021-11-28 16:54:48 +01:00
|
|
|
m_flFieldOfView = -0.2; // width of forward view cone ( as a dotproduct result )
|
|
|
|
m_MonsterState = MONSTERSTATE_NONE;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
MonsterInit();
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
m_pEyeGlow = CSprite::SpriteCreate(GARG_EYE_SPRITE_NAME, pev->origin, false);
|
|
|
|
m_pEyeGlow->SetTransparency(kRenderGlow, 255, 255, 255, 0, kRenderFxNoDissipation);
|
|
|
|
m_pEyeGlow->SetAttachment(edict(), 1);
|
2013-08-30 13:34:05 -07:00
|
|
|
EyeOff();
|
|
|
|
m_seeTime = gpGlobals->time + 5;
|
|
|
|
m_flameTime = gpGlobals->time + 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// Precache - precaches all resources this monster needs
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CGargantua::Precache()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
PRECACHE_MODEL("models/garg.mdl");
|
2021-11-28 16:54:48 +01:00
|
|
|
PRECACHE_MODEL(GARG_EYE_SPRITE_NAME);
|
|
|
|
PRECACHE_MODEL(GARG_BEAM_SPRITE_NAME);
|
|
|
|
PRECACHE_MODEL(GARG_BEAM_SPRITE2);
|
|
|
|
gStompSprite = PRECACHE_MODEL(GARG_STOMP_SPRITE_NAME);
|
|
|
|
gGargGibModel = PRECACHE_MODEL(GARG_GIB_MODEL);
|
|
|
|
PRECACHE_SOUND(GARG_STOMP_BUZZ_SOUND);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-12-02 17:53:57 -05:00
|
|
|
PRECACHE_SOUND_ARRAY(pAttackHitSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pBeamAttackSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pAttackMissSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pRicSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pFootSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pIdleSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pAlertSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pPainSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pAttackSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pStompSounds);
|
|
|
|
PRECACHE_SOUND_ARRAY(pBreatheSounds);
|
2021-11-28 16:54:48 +01:00
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void CGargantua::TraceAttack(entvars_t* pevAttacker, float flDamage, Vector vecDir, TraceResult* ptr, int bitsDamageType)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
ALERT(at_aiconsole, "CGargantua::TraceAttack\n");
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!IsAlive())
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseMonster::TraceAttack(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
|
2013-08-30 13:34:05 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// UNDONE: Hit group specific damage?
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((bitsDamageType & (GARG_DAMAGE | DMG_BLAST)) != 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_painSoundTime < gpGlobals->time)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-12-02 17:53:57 -05:00
|
|
|
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pPainSounds), 1.0, ATTN_GARG, 0, PITCH_NORM);
|
2021-11-28 16:54:48 +01:00
|
|
|
m_painSoundTime = gpGlobals->time + RANDOM_FLOAT(2.5, 4);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bitsDamageType &= GARG_DAMAGE;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (bitsDamageType == 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->dmgtime != gpGlobals->time || (RANDOM_LONG(0, 100) < 20))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_Ricochet(ptr->vecEndPos, RANDOM_FLOAT(0.5, 1.5));
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->dmgtime = gpGlobals->time;
|
2021-11-28 16:54:48 +01:00
|
|
|
// if ( RANDOM_LONG(0,100) < 25 )
|
|
|
|
// EMIT_SOUND_DYN( ENT(pev), CHAN_BODY, pRicSounds[ RANDOM_LONG(0,ARRAYSIZE(pRicSounds)-1) ], 1.0, ATTN_NORM, 0, PITCH_NORM );
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
flDamage = 0;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseMonster::TraceAttack(pevAttacker, flDamage, vecDir, ptr, bitsDamageType);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
bool CGargantua::TakeDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
ALERT(at_aiconsole, "CGargantua::TakeDamage\n");
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (IsAlive())
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((bitsDamageType & GARG_DAMAGE) == 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
flDamage *= 0.01;
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((bitsDamageType & DMG_BLAST) != 0)
|
|
|
|
SetConditions(bits_COND_LIGHT_DAMAGE);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
return CBaseMonster::TakeDamage(pevInflictor, pevAttacker, flDamage, bitsDamageType);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CGargantua::DeathEffect()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
UTIL_MakeVectors(pev->angles);
|
|
|
|
Vector deathPos = pev->origin + gpGlobals->v_forward * 100;
|
|
|
|
|
|
|
|
// Create a spiral of streaks
|
2021-11-28 16:54:48 +01:00
|
|
|
CSpiral::Create(deathPos, (pev->absmax.z - pev->absmin.z) * 0.6, 125, 1.5);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
Vector position = pev->origin;
|
|
|
|
position.z += 32;
|
2021-11-28 16:54:48 +01:00
|
|
|
for (i = 0; i < 7; i += 2)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
SpawnExplosion(position, 70, (i * 0.3), 60 + (i * 20));
|
2013-08-30 13:34:05 -07:00
|
|
|
position.z += 15;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pSmoker = CBaseEntity::Create("env_smoker", pev->origin, g_vecZero, NULL);
|
|
|
|
pSmoker->pev->health = 1; // 1 smoke balls
|
|
|
|
pSmoker->pev->scale = 46; // 4.6X normal size
|
|
|
|
pSmoker->pev->dmg = 0; // 0 radial distribution
|
|
|
|
pSmoker->pev->nextthink = gpGlobals->time + 2.5; // Start in 2.5 seconds
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void CGargantua::Killed(entvars_t* pevAttacker, int iGib)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
EyeOff();
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_Remove(m_pEyeGlow);
|
2013-08-30 13:34:05 -07:00
|
|
|
m_pEyeGlow = NULL;
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseMonster::Killed(pevAttacker, GIB_NEVER);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// CheckMeleeAttack1
|
|
|
|
// Garg swipe attack
|
2021-11-28 16:54:48 +01:00
|
|
|
//
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
bool CGargantua::CheckMeleeAttack1(float flDot, float flDist)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
if (flDot >= 0.7)
|
|
|
|
{
|
|
|
|
if (flDist <= GARG_ATTACKDIST)
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Flame thrower madness!
|
2021-11-28 16:54:48 +01:00
|
|
|
bool CGargantua::CheckMeleeAttack2(float flDot, float flDist)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// ALERT(at_aiconsole, "CheckMelee(%f, %f)\n", flDot, flDist);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (gpGlobals->time > m_flameTime)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
if (flDot >= 0.8 && flDist > GARG_ATTACKDIST)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (flDist <= GARG_FLAME_LENGTH)
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// CheckRangeAttack1
|
|
|
|
// flDot is the cos of the angle of the cone within which
|
|
|
|
// the attack can occur.
|
|
|
|
//=========================================================
|
|
|
|
//
|
|
|
|
// Stomp attack
|
|
|
|
//
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
bool CGargantua::CheckRangeAttack1(float flDot, float flDist)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (gpGlobals->time > m_seeTime)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
if (flDot >= 0.7 && flDist > GARG_ATTACKDIST)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return true;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// HandleAnimEvent - catches the monster-specific messages
|
|
|
|
// that occur when tagged animation frames are played.
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
void CGargantua::HandleAnimEvent(MonsterEvent_t* pEvent)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (pEvent->event)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-29 20:55:01 +01:00
|
|
|
case GARG_AE_SLASH_LEFT:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// HACKHACK!!!
|
|
|
|
CBaseEntity* pHurt = GargantuaCheckTraceHullAttack(GARG_ATTACKDIST + 10.0, gSkillData.gargantuaDmgSlash, DMG_SLASH);
|
|
|
|
if (pHurt)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((pHurt->pev->flags & (FL_MONSTER | FL_CLIENT)) != 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pHurt->pev->punchangle.x = -30; // pitch
|
|
|
|
pHurt->pev->punchangle.y = -30; // yaw
|
|
|
|
pHurt->pev->punchangle.z = 30; // roll
|
|
|
|
//UTIL_MakeVectors(pev->angles); // called by CheckTraceHullAttack
|
|
|
|
pHurt->pev->velocity = pHurt->pev->velocity - gpGlobals->v_right * 100;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-12-02 17:53:57 -05:00
|
|
|
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0, 15));
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
else // Play a random attack miss sound
|
2021-12-02 17:53:57 -05:00
|
|
|
EMIT_SOUND_DYN(edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackMissSounds), 1.0, ATTN_NORM, 0, 50 + RANDOM_LONG(0, 15));
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
Vector forward;
|
|
|
|
UTIL_MakeVectorsPrivate(pev->angles, forward, NULL, NULL);
|
|
|
|
}
|
|
|
|
break;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
case GARG_AE_RIGHT_FOOT:
|
|
|
|
case GARG_AE_LEFT_FOOT:
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_ScreenShake(pev->origin, 4.0, 3.0, 1.0, 750);
|
2021-12-02 17:53:57 -05:00
|
|
|
EMIT_SOUND_DYN(edict(), CHAN_BODY, RANDOM_SOUND_ARRAY(pFootSounds), 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10, 10));
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GARG_AE_STOMP:
|
|
|
|
StompAttack();
|
|
|
|
m_seeTime = gpGlobals->time + 12;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GARG_AE_BREATHE:
|
2021-12-02 17:53:57 -05:00
|
|
|
EMIT_SOUND_DYN(edict(), CHAN_VOICE, RANDOM_SOUND_ARRAY(pBreatheSounds), 1.0, ATTN_GARG, 0, PITCH_NORM + RANDOM_LONG(-10, 10));
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
CBaseMonster::HandleAnimEvent(pEvent);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// CheckTraceHullAttack - expects a length to trace, amount
|
2013-08-30 13:34:05 -07:00
|
|
|
// of damage to do, and damage type. Returns a pointer to
|
|
|
|
// the damaged entity in case the monster wishes to do
|
|
|
|
// other stuff to the victim (punchangle, etc)
|
|
|
|
// Used for many contact-range melee attacks. Bites, claws, etc.
|
|
|
|
|
|
|
|
// Overridden for Gargantua because his swing starts lower as
|
|
|
|
// a percentage of his height (otherwise he swings over the
|
|
|
|
// players head)
|
|
|
|
//=========================================================
|
|
|
|
CBaseEntity* CGargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType)
|
|
|
|
{
|
|
|
|
TraceResult tr;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeVectors(pev->angles);
|
2013-08-30 13:34:05 -07:00
|
|
|
Vector vecStart = pev->origin;
|
|
|
|
vecStart.z += 64;
|
|
|
|
Vector vecEnd = vecStart + (gpGlobals->v_forward * flDist) - (gpGlobals->v_up * flDist * 0.3);
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceHull(vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr);
|
|
|
|
|
|
|
|
if (tr.pHit)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = CBaseEntity::Instance(tr.pHit);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (iDamage > 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity->TakeDamage(pev, pev, iDamage, iDmgType);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return pEntity;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t* CGargantua::GetScheduleOfType(int Type)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// HACKHACK - turn off the flames if they are on and garg goes scripted / dead
|
2021-11-28 16:54:48 +01:00
|
|
|
if (FlameIsOn())
|
2013-08-30 13:34:05 -07:00
|
|
|
FlameDestroy();
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (Type)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
case SCHED_MELEE_ATTACK2:
|
|
|
|
return slGargFlame;
|
|
|
|
case SCHED_MELEE_ATTACK1:
|
|
|
|
return slGargSwipe;
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
return CBaseMonster::GetScheduleOfType(Type);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void CGargantua::StartTask(Task_t* pTask)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (pTask->iTask)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
case TASK_FLAME_SWEEP:
|
|
|
|
FlameCreate();
|
|
|
|
m_flWaitFinished = gpGlobals->time + pTask->flData;
|
|
|
|
m_flameTime = gpGlobals->time + 6;
|
|
|
|
m_flameX = 0;
|
|
|
|
m_flameY = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TASK_SOUND_ATTACK:
|
2021-11-28 16:54:48 +01:00
|
|
|
if (RANDOM_LONG(0, 100) < 30)
|
2021-12-02 17:53:57 -05:00
|
|
|
EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, RANDOM_SOUND_ARRAY(pAttackSounds), 1.0, ATTN_GARG, 0, PITCH_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
TaskComplete();
|
|
|
|
break;
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
case TASK_DIE:
|
|
|
|
m_flWaitFinished = gpGlobals->time + 1.6;
|
|
|
|
DeathEffect();
|
2021-11-28 22:10:47 +01:00
|
|
|
[[fallthrough]];
|
2021-11-28 16:54:48 +01:00
|
|
|
default:
|
|
|
|
CBaseMonster::StartTask(pTask);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// RunTask
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
void CGargantua::RunTask(Task_t* pTask)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (pTask->iTask)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
case TASK_DIE:
|
2021-11-28 16:54:48 +01:00
|
|
|
if (gpGlobals->time > m_flWaitFinished)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->renderfx = kRenderFxExplode;
|
|
|
|
pev->rendercolor.x = 255;
|
|
|
|
pev->rendercolor.y = 0;
|
|
|
|
pev->rendercolor.z = 0;
|
|
|
|
StopAnimation();
|
|
|
|
pev->nextthink = gpGlobals->time + 0.15;
|
2021-11-28 16:54:48 +01:00
|
|
|
SetThink(&CGargantua::SUB_Remove);
|
2013-08-30 13:34:05 -07:00
|
|
|
int i;
|
2021-11-28 16:54:48 +01:00
|
|
|
int parts = MODEL_FRAMES(gGargGibModel);
|
|
|
|
for (i = 0; i < 10; i++)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CGib* pGib = GetClassPtr((CGib*)NULL);
|
|
|
|
|
|
|
|
pGib->Spawn(GARG_GIB_MODEL);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
int bodyPart = 0;
|
2021-11-28 16:54:48 +01:00
|
|
|
if (parts > 1)
|
|
|
|
bodyPart = RANDOM_LONG(0, pev->body - 1);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
pGib->pev->body = bodyPart;
|
|
|
|
pGib->m_bloodColor = BLOOD_COLOR_YELLOW;
|
|
|
|
pGib->m_material = matNone;
|
|
|
|
pGib->pev->origin = pev->origin;
|
2021-11-28 16:54:48 +01:00
|
|
|
pGib->pev->velocity = UTIL_RandomBloodVector() * RANDOM_FLOAT(300, 500);
|
2013-08-30 13:34:05 -07:00
|
|
|
pGib->pev->nextthink = gpGlobals->time + 1.25;
|
2021-11-28 16:54:48 +01:00
|
|
|
pGib->SetThink(&CGib::SUB_FadeOut);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin);
|
|
|
|
WRITE_BYTE(TE_BREAKMODEL);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// position
|
|
|
|
WRITE_COORD(pev->origin.x);
|
|
|
|
WRITE_COORD(pev->origin.y);
|
|
|
|
WRITE_COORD(pev->origin.z);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// size
|
|
|
|
WRITE_COORD(200);
|
|
|
|
WRITE_COORD(200);
|
|
|
|
WRITE_COORD(128);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// velocity
|
|
|
|
WRITE_COORD(0);
|
|
|
|
WRITE_COORD(0);
|
|
|
|
WRITE_COORD(0);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// randomization
|
|
|
|
WRITE_BYTE(200);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// Model
|
|
|
|
WRITE_SHORT(gGargGibModel); //model id#
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// # of shards
|
|
|
|
WRITE_BYTE(50);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// duration
|
|
|
|
WRITE_BYTE(20); // 3.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_FLESH);
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
CBaseMonster::RunTask(pTask);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TASK_FLAME_SWEEP:
|
2021-11-28 16:54:48 +01:00
|
|
|
if (gpGlobals->time > m_flWaitFinished)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
FlameDestroy();
|
|
|
|
TaskComplete();
|
2021-11-28 16:54:48 +01:00
|
|
|
FlameControls(0, 0);
|
|
|
|
SetBoneController(0, 0);
|
|
|
|
SetBoneController(1, 0);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-19 14:40:35 +01:00
|
|
|
bool cancel = false;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
Vector angles = g_vecZero;
|
|
|
|
|
|
|
|
FlameUpdate();
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEnemy = m_hEnemy;
|
|
|
|
if (pEnemy)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
Vector org = pev->origin;
|
|
|
|
org.z += 64;
|
|
|
|
Vector dir = pEnemy->BodyTarget(org) - org;
|
2021-11-28 16:54:48 +01:00
|
|
|
angles = UTIL_VecToAngles(dir);
|
2013-08-30 13:34:05 -07:00
|
|
|
angles.x = -angles.x;
|
|
|
|
angles.y -= pev->angles.y;
|
2021-11-28 16:54:48 +01:00
|
|
|
if (dir.Length() > 400)
|
2021-11-19 13:45:16 +01:00
|
|
|
cancel = true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
if (fabs(angles.y) > 60)
|
2021-11-19 13:45:16 +01:00
|
|
|
cancel = true;
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
if (cancel)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
m_flWaitFinished -= 0.5;
|
|
|
|
m_flameTime -= 0.5;
|
|
|
|
}
|
|
|
|
// FlameControls( angles.x + 2 * sin(gpGlobals->time*8), angles.y + 28 * sin(gpGlobals->time*8.5) );
|
2021-11-28 16:54:48 +01:00
|
|
|
FlameControls(angles.x, angles.y);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseMonster::RunTask(pTask);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class CSmoker : public CBaseEntity
|
|
|
|
{
|
|
|
|
public:
|
2021-03-05 23:07:22 +01:00
|
|
|
void Spawn() override;
|
|
|
|
void Think() override;
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
LINK_ENTITY_TO_CLASS(env_smoker, CSmoker);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CSmoker::Spawn()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->movetype = MOVETYPE_NONE;
|
|
|
|
pev->nextthink = gpGlobals->time;
|
|
|
|
pev->solid = SOLID_NOT;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetSize(pev, g_vecZero, g_vecZero);
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->effects |= EF_NODRAW;
|
|
|
|
pev->angles = g_vecZero;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CSmoker::Think()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// lots of smoke
|
2021-11-28 16:54:48 +01:00
|
|
|
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, pev->origin);
|
|
|
|
WRITE_BYTE(TE_SMOKE);
|
|
|
|
WRITE_COORD(pev->origin.x + RANDOM_FLOAT(-pev->dmg, pev->dmg));
|
|
|
|
WRITE_COORD(pev->origin.y + RANDOM_FLOAT(-pev->dmg, pev->dmg));
|
|
|
|
WRITE_COORD(pev->origin.z);
|
|
|
|
WRITE_SHORT(g_sModelIndexSmoke);
|
|
|
|
WRITE_BYTE(RANDOM_LONG(pev->scale, pev->scale * 1.1));
|
|
|
|
WRITE_BYTE(RANDOM_LONG(8, 14)); // framerate
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
|
|
|
pev->health--;
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->health > 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2);
|
|
|
|
else
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_Remove(this);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CSpiral::Spawn()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->movetype = MOVETYPE_NONE;
|
|
|
|
pev->nextthink = gpGlobals->time;
|
|
|
|
pev->solid = SOLID_NOT;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetSize(pev, g_vecZero, g_vecZero);
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->effects |= EF_NODRAW;
|
|
|
|
pev->angles = g_vecZero;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CSpiral* CSpiral::Create(const Vector& origin, float height, float radius, float duration)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (duration <= 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
return NULL;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CSpiral* pSpiral = GetClassPtr((CSpiral*)NULL);
|
2013-08-30 13:34:05 -07:00
|
|
|
pSpiral->Spawn();
|
|
|
|
pSpiral->pev->dmgtime = pSpiral->pev->nextthink;
|
|
|
|
pSpiral->pev->origin = origin;
|
|
|
|
pSpiral->pev->scale = radius;
|
|
|
|
pSpiral->pev->dmg = height;
|
|
|
|
pSpiral->pev->speed = duration;
|
|
|
|
pSpiral->pev->health = 0;
|
|
|
|
pSpiral->pev->angles = g_vecZero;
|
|
|
|
|
|
|
|
return pSpiral;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SPIRAL_INTERVAL 0.1 //025
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
void CSpiral::Think()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
float time = gpGlobals->time - pev->dmgtime;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
while (time > SPIRAL_INTERVAL)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
Vector position = pev->origin;
|
2021-11-28 16:54:48 +01:00
|
|
|
Vector direction = Vector(0, 0, 1);
|
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
float fraction = 1.0 / pev->speed;
|
|
|
|
|
|
|
|
float radius = (pev->scale * pev->health) * fraction;
|
|
|
|
|
|
|
|
position.z += (pev->health * pev->dmg) * fraction;
|
|
|
|
pev->angles.y = (pev->health * 360 * 8) * fraction;
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_MakeVectors(pev->angles);
|
2013-08-30 13:34:05 -07:00
|
|
|
position = position + gpGlobals->v_forward * radius;
|
|
|
|
direction = (direction + gpGlobals->v_forward).Normalize();
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
StreakSplash(position, Vector(0, 0, 1), RANDOM_LONG(8, 11), 20, RANDOM_LONG(50, 150), 400);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Jeez, how many counters should this take ? :)
|
|
|
|
pev->dmgtime += SPIRAL_INTERVAL;
|
|
|
|
pev->health += SPIRAL_INTERVAL;
|
|
|
|
time -= SPIRAL_INTERVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pev->nextthink = gpGlobals->time;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->health >= pev->speed)
|
|
|
|
UTIL_Remove(this);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// HACKHACK Cut and pasted from explode.cpp
|
2021-11-28 16:54:48 +01:00
|
|
|
void SpawnExplosion(Vector center, float randomRange, float time, int magnitude)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
KeyValueData kvd;
|
|
|
|
char buf[128];
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
center.x += RANDOM_FLOAT(-randomRange, randomRange);
|
|
|
|
center.y += RANDOM_FLOAT(-randomRange, randomRange);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pExplosion = CBaseEntity::Create("env_explosion", center, g_vecZero, NULL);
|
|
|
|
sprintf(buf, "%3d", magnitude);
|
2013-08-30 13:34:05 -07:00
|
|
|
kvd.szKeyName = "iMagnitude";
|
|
|
|
kvd.szValue = buf;
|
2021-11-28 16:54:48 +01:00
|
|
|
pExplosion->KeyValue(&kvd);
|
2013-08-30 13:34:05 -07:00
|
|
|
pExplosion->pev->spawnflags |= SF_ENVEXPLOSION_NODAMAGE;
|
|
|
|
|
|
|
|
pExplosion->Spawn();
|
2021-11-28 16:54:48 +01:00
|
|
|
pExplosion->SetThink(&CBaseEntity::SUB_CallUseToggle);
|
2013-08-30 13:34:05 -07:00
|
|
|
pExplosion->pev->nextthink = gpGlobals->time + time;
|
|
|
|
}
|