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.
|
|
|
|
*
|
|
|
|
****/
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// Houndeye - spooky sonic dog.
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#include "extdll.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "cbase.h"
|
|
|
|
#include "monsters.h"
|
|
|
|
#include "schedule.h"
|
|
|
|
#include "animation.h"
|
|
|
|
#include "nodes.h"
|
|
|
|
#include "squadmonster.h"
|
|
|
|
#include "soundent.h"
|
|
|
|
#include "game.h"
|
|
|
|
|
|
|
|
// houndeye does 20 points of damage spread over a sphere 384 units in diameter, and each additional
|
2013-08-30 13:34:05 -07:00
|
|
|
// squad member increases the BASE damage by 110%, per the spec.
|
2021-11-28 16:54:48 +01:00
|
|
|
#define HOUNDEYE_MAX_SQUAD_SIZE 4
|
|
|
|
#define HOUNDEYE_MAX_ATTACK_RADIUS 384
|
|
|
|
#define HOUNDEYE_SQUAD_BONUS (float)1.1
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2019-09-30 04:18:46 -05:00
|
|
|
// Marphy Fact Files Fix - Fix various instances of Houndeye not correctly blinking/closing eyes
|
|
|
|
#define HOUNDEYE_EYE_FRAMES 3 // how many different switchable maps for the eye
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define HOUNDEYE_SOUND_STARTLE_VOLUME 128 // how loud a sound has to be to badly scare a sleeping houndeye
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// monster-specific tasks
|
|
|
|
//=========================================================
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
TASK_HOUND_CLOSE_EYE = LAST_COMMON_TASK + 1,
|
|
|
|
TASK_HOUND_OPEN_EYE,
|
|
|
|
TASK_HOUND_THREAT_DISPLAY,
|
|
|
|
TASK_HOUND_FALL_ASLEEP,
|
|
|
|
TASK_HOUND_WAKE_UP,
|
|
|
|
TASK_HOUND_HOP_BACK
|
|
|
|
};
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// monster-specific schedule types
|
|
|
|
//=========================================================
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
SCHED_HOUND_AGITATED = LAST_COMMON_SCHEDULE + 1,
|
|
|
|
SCHED_HOUND_HOP_RETREAT,
|
|
|
|
SCHED_HOUND_FAIL,
|
|
|
|
};
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// Monster's Anim Events Go Here
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
#define HOUND_AE_WARN 1
|
|
|
|
#define HOUND_AE_STARTATTACK 2
|
|
|
|
#define HOUND_AE_THUMP 3
|
|
|
|
#define HOUND_AE_ANGERSOUND1 4
|
|
|
|
#define HOUND_AE_ANGERSOUND2 5
|
|
|
|
#define HOUND_AE_HOPBACK 6
|
|
|
|
#define HOUND_AE_CLOSE_EYE 7
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
class CHoundeye : public CSquadMonster
|
|
|
|
{
|
|
|
|
public:
|
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;
|
|
|
|
void HandleAnimEvent(MonsterEvent_t* pEvent) override;
|
|
|
|
void SetYawSpeed() override;
|
|
|
|
void WarmUpSound();
|
2021-03-05 23:07:22 +01:00
|
|
|
void AlertSound() override;
|
|
|
|
void DeathSound() override;
|
2021-03-05 20:54:33 +01:00
|
|
|
void WarnSound();
|
2021-03-05 23:07:22 +01:00
|
|
|
void PainSound() override;
|
|
|
|
void IdleSound() override;
|
2021-11-28 16:54:48 +01:00
|
|
|
void StartTask(Task_t* pTask) override;
|
|
|
|
void RunTask(Task_t* pTask) override;
|
2021-03-05 20:54:33 +01:00
|
|
|
void SonicAttack();
|
2021-03-05 23:07:22 +01:00
|
|
|
void PrescheduleThink() override;
|
2021-11-28 16:54:48 +01:00
|
|
|
void SetActivity(Activity NewActivity) override;
|
|
|
|
void WriteBeamColor();
|
|
|
|
bool CheckRangeAttack1(float flDot, float flDist) override;
|
|
|
|
bool FValidateHintType(short sHint) override;
|
|
|
|
bool FCanActiveIdle() override;
|
|
|
|
Schedule_t* GetScheduleOfType(int Type) override;
|
|
|
|
Schedule_t* GetSchedule() override;
|
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;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
CUSTOM_SCHEDULES;
|
|
|
|
static TYPEDESCRIPTION m_SaveData[];
|
|
|
|
|
|
|
|
int m_iSpriteTexture;
|
2021-11-28 16:54:48 +01:00
|
|
|
bool m_fAsleep; // some houndeyes sleep in idle mode if this is set, the houndeye is lying down
|
|
|
|
bool m_fDontBlink; // don't try to open/close eye if this bit is set!
|
|
|
|
Vector m_vecPackCenter; // the center of the pack. The leader maintains this by averaging the origins of all pack members.
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
2021-11-28 16:54:48 +01:00
|
|
|
LINK_ENTITY_TO_CLASS(monster_houndeye, CHoundeye);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
TYPEDESCRIPTION CHoundeye::m_SaveData[] =
|
|
|
|
{
|
|
|
|
DEFINE_FIELD(CHoundeye, m_iSpriteTexture, FIELD_INTEGER),
|
|
|
|
DEFINE_FIELD(CHoundeye, m_fAsleep, FIELD_BOOLEAN),
|
|
|
|
DEFINE_FIELD(CHoundeye, m_fDontBlink, FIELD_BOOLEAN),
|
|
|
|
DEFINE_FIELD(CHoundeye, m_vecPackCenter, FIELD_POSITION_VECTOR),
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
IMPLEMENT_SAVERESTORE(CHoundeye, CSquadMonster);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//=========================================================
|
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 CHoundeye::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
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// FValidateHintType
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
bool CHoundeye::FValidateHintType(short sHint)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
static short sHoundHints[] =
|
2021-11-28 16:54:48 +01:00
|
|
|
{
|
|
|
|
HINT_WORLD_MACHINERY,
|
|
|
|
HINT_WORLD_BLINKING_LIGHT,
|
|
|
|
HINT_WORLD_HUMAN_BLOOD,
|
|
|
|
HINT_WORLD_ALIEN_BLOOD,
|
|
|
|
};
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
for (i = 0; i < ARRAYSIZE(sHoundHints); i++)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (sHoundHints[i] == sHint)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
ALERT(at_aiconsole, "Couldn't validate hint type");
|
2021-11-19 13:43:33 +01:00
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// FCanActiveIdle
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
bool CHoundeye::FCanActiveIdle()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (InSquad())
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CSquadMonster* pSquadLeader = MySquadLeader();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
for (int i = 0; i < MAX_SQUAD_MEMBERS; i++)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CSquadMonster* pMember = pSquadLeader->MySquadMember(i);
|
|
|
|
|
|
|
|
if (pMember != NULL && pMember != this && pMember->m_iHintNode != NO_NODE)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// someone else in the group is active idling right now!
|
2021-11-19 13:43:33 +01:00
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-19 13:45:16 +01:00
|
|
|
return true;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// CheckRangeAttack1 - overridden for houndeyes so that they
|
|
|
|
// try to get within half of their max attack radius before
|
|
|
|
// attacking, so as to increase their chances of doing damage.
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
bool CHoundeye::CheckRangeAttack1(float flDot, float flDist)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (flDist <= (HOUNDEYE_MAX_ATTACK_RADIUS * 0.5) && flDot >= 0.3)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// SetYawSpeed - allows each sequence to have a different
|
|
|
|
// turn rate associated with it.
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::SetYawSpeed()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
int ys;
|
|
|
|
|
|
|
|
ys = 90;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (m_Activity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
case ACT_CROUCHIDLE: //sleeping!
|
2013-08-30 13:34:05 -07:00
|
|
|
ys = 0;
|
|
|
|
break;
|
2021-11-28 16:54:48 +01:00
|
|
|
case ACT_IDLE:
|
2013-08-30 13:34:05 -07:00
|
|
|
ys = 60;
|
|
|
|
break;
|
|
|
|
case ACT_WALK:
|
|
|
|
ys = 90;
|
|
|
|
break;
|
2021-11-28 16:54:48 +01:00
|
|
|
case ACT_RUN:
|
2013-08-30 13:34:05 -07:00
|
|
|
ys = 90;
|
|
|
|
break;
|
|
|
|
case ACT_TURN_LEFT:
|
|
|
|
case ACT_TURN_RIGHT:
|
|
|
|
ys = 90;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pev->yaw_speed = ys;
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// SetActivity
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::SetActivity(Activity NewActivity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
int iSequence;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (NewActivity == m_Activity)
|
2013-08-30 13:34:05 -07:00
|
|
|
return;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_MonsterState == MONSTERSTATE_COMBAT && NewActivity == ACT_IDLE && RANDOM_LONG(0, 1))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// play pissed idle.
|
2021-11-28 16:54:48 +01:00
|
|
|
iSequence = LookupSequence("madidle");
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
m_Activity = NewActivity; // Go ahead and set this so it doesn't keep trying when the anim is not present
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
// In case someone calls this with something other than the ideal activity
|
|
|
|
m_IdealActivity = m_Activity;
|
|
|
|
|
|
|
|
// Set to the desired anim, or default anim if the desired is not present
|
2021-11-28 16:54:48 +01:00
|
|
|
if (iSequence > ACTIVITY_NOT_AVAILABLE)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->sequence = iSequence; // Set to the reset anim (if it's there)
|
|
|
|
pev->frame = 0; // FIX: frame counter shouldn't be reset when its the same activity as before
|
2013-08-30 13:34:05 -07:00
|
|
|
ResetSequenceInfo();
|
|
|
|
SetYawSpeed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-29 20:31:17 +01:00
|
|
|
CSquadMonster::SetActivity(NewActivity);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// HandleAnimEvent - catches the monster-specific messages
|
|
|
|
// that occur when tagged animation frames are played.
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::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-28 16:54:48 +01:00
|
|
|
case HOUND_AE_WARN:
|
|
|
|
// do stuff for this event.
|
|
|
|
WarnSound();
|
|
|
|
break;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
case HOUND_AE_STARTATTACK:
|
|
|
|
WarmUpSound();
|
|
|
|
break;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-29 20:55:01 +01:00
|
|
|
case HOUND_AE_HOPBACK:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
float flGravity = g_psv_gravity->value;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->flags &= ~FL_ONGROUND;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->velocity = gpGlobals->v_forward * -200;
|
|
|
|
pev->velocity.z += (0.6 * flGravity) * 0.5;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
case HOUND_AE_THUMP:
|
|
|
|
// emit the shockwaves
|
|
|
|
SonicAttack();
|
|
|
|
break;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
case HOUND_AE_ANGERSOUND1:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM);
|
|
|
|
break;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
case HOUND_AE_ANGERSOUND2:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain1.wav", 1, ATTN_NORM);
|
|
|
|
break;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
case HOUND_AE_CLOSE_EYE:
|
|
|
|
if (!m_fDontBlink)
|
|
|
|
{
|
|
|
|
pev->skin = HOUNDEYE_EYE_FRAMES - 1;
|
|
|
|
}
|
|
|
|
break;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
default:
|
|
|
|
CSquadMonster::HandleAnimEvent(pEvent);
|
|
|
|
break;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// Spawn
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::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/houndeye.mdl");
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 36));
|
|
|
|
|
|
|
|
pev->solid = SOLID_SLIDEBOX;
|
|
|
|
pev->movetype = MOVETYPE_STEP;
|
|
|
|
m_bloodColor = BLOOD_COLOR_YELLOW;
|
|
|
|
pev->effects = 0;
|
|
|
|
pev->health = gSkillData.houndeyeHealth;
|
|
|
|
pev->yaw_speed = 5; //!!! should we put this in the monster's changeanim function since turn rates may vary with state/anim?
|
|
|
|
m_flFieldOfView = 0.5; // indicates the width of this monster's forward view cone ( as a dotproduct result )
|
|
|
|
m_MonsterState = MONSTERSTATE_NONE;
|
|
|
|
m_fAsleep = false; // everyone spawns awake
|
|
|
|
m_fDontBlink = false;
|
|
|
|
m_afCapability |= bits_CAP_SQUAD;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
MonsterInit();
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// Precache - precaches all resources this monster needs
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::Precache()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
PRECACHE_MODEL("models/houndeye.mdl");
|
|
|
|
|
|
|
|
PRECACHE_SOUND("houndeye/he_alert1.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_alert2.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_alert3.wav");
|
|
|
|
|
|
|
|
PRECACHE_SOUND("houndeye/he_die1.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_die2.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_die3.wav");
|
|
|
|
|
|
|
|
PRECACHE_SOUND("houndeye/he_idle1.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_idle2.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_idle3.wav");
|
|
|
|
|
|
|
|
PRECACHE_SOUND("houndeye/he_hunt1.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_hunt2.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_hunt3.wav");
|
|
|
|
|
|
|
|
PRECACHE_SOUND("houndeye/he_pain1.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_pain3.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_pain4.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_pain5.wav");
|
|
|
|
|
|
|
|
PRECACHE_SOUND("houndeye/he_attack1.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_attack3.wav");
|
|
|
|
|
|
|
|
PRECACHE_SOUND("houndeye/he_blast1.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_blast2.wav");
|
|
|
|
PRECACHE_SOUND("houndeye/he_blast3.wav");
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
m_iSpriteTexture = PRECACHE_MODEL("sprites/shockwave.spr");
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// IdleSound
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::IdleSound()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (RANDOM_LONG(0, 2))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
case 0:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_idle1.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_idle2.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_idle3.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// IdleSound
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::WarmUpSound()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (RANDOM_LONG(0, 1))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
case 0:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_attack1.wav", 0.7, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_attack3.wav", 0.7, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// WarnSound
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::WarnSound()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (RANDOM_LONG(0, 2))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
case 0:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_hunt1.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_hunt2.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_hunt3.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// AlertSound
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::AlertSound()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (InSquad() && !IsLeader())
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
return; // only leader makes ALERT sound.
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (RANDOM_LONG(0, 2))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
case 0:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_alert1.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
2021-11-28 16:54:48 +01:00
|
|
|
case 1:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_alert2.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
2021-11-28 16:54:48 +01:00
|
|
|
case 2:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_alert3.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// DeathSound
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::DeathSound()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (RANDOM_LONG(0, 2))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
case 0:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_die1.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
case 1:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_die2.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
case 2:
|
2021-11-28 16:54:48 +01:00
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_die3.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// PainSound
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::PainSound()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (RANDOM_LONG(0, 2))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
case 0:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain3.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
2021-11-28 16:54:48 +01:00
|
|
|
case 1:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain4.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
2021-11-28 16:54:48 +01:00
|
|
|
case 2:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_VOICE, "houndeye/he_pain5.wav", 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// WriteBeamColor - writes a color vector to the network
|
|
|
|
// based on the size of the group.
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::WriteBeamColor()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
byte bRed, bGreen, bBlue;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (InSquad())
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (SquadCount())
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
case 2:
|
|
|
|
// no case for 0 or 1, cause those are impossible for monsters in Squads.
|
2021-11-28 16:54:48 +01:00
|
|
|
bRed = 101;
|
|
|
|
bGreen = 133;
|
|
|
|
bBlue = 221;
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
case 3:
|
2021-11-28 16:54:48 +01:00
|
|
|
bRed = 67;
|
|
|
|
bGreen = 85;
|
|
|
|
bBlue = 255;
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
case 4:
|
2021-11-28 16:54:48 +01:00
|
|
|
bRed = 62;
|
|
|
|
bGreen = 33;
|
|
|
|
bBlue = 211;
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
default:
|
2021-11-28 16:54:48 +01:00
|
|
|
ALERT(at_aiconsole, "Unsupported Houndeye SquadSize!\n");
|
|
|
|
bRed = 188;
|
|
|
|
bGreen = 220;
|
|
|
|
bBlue = 255;
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// solo houndeye - weakest beam
|
2021-11-28 16:54:48 +01:00
|
|
|
bRed = 188;
|
|
|
|
bGreen = 220;
|
|
|
|
bBlue = 255;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
WRITE_BYTE(bRed);
|
|
|
|
WRITE_BYTE(bGreen);
|
|
|
|
WRITE_BYTE(bBlue);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// SonicAttack
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::SonicAttack()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
float flAdjustedDamage;
|
|
|
|
float flDist;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (RANDOM_LONG(0, 2))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
case 0:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast1.wav", 1, ATTN_NORM);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast2.wav", 1, ATTN_NORM);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
EMIT_SOUND(ENT(pev), CHAN_WEAPON, "houndeye/he_blast3.wav", 1, ATTN_NORM);
|
|
|
|
break;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// blast circles
|
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 + 16);
|
|
|
|
WRITE_COORD(pev->origin.x);
|
|
|
|
WRITE_COORD(pev->origin.y);
|
|
|
|
WRITE_COORD(pev->origin.z + 16 + HOUNDEYE_MAX_ATTACK_RADIUS / .2); // reach damage radius over .3 seconds
|
|
|
|
WRITE_SHORT(m_iSpriteTexture);
|
|
|
|
WRITE_BYTE(0); // startframe
|
|
|
|
WRITE_BYTE(0); // framerate
|
|
|
|
WRITE_BYTE(2); // life
|
|
|
|
WRITE_BYTE(16); // width
|
|
|
|
WRITE_BYTE(0); // noise
|
|
|
|
|
|
|
|
WriteBeamColor();
|
|
|
|
|
|
|
|
WRITE_BYTE(255); //brightness
|
|
|
|
WRITE_BYTE(0); // speed
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
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 + 16);
|
|
|
|
WRITE_COORD(pev->origin.x);
|
|
|
|
WRITE_COORD(pev->origin.y);
|
|
|
|
WRITE_COORD(pev->origin.z + 16 + (HOUNDEYE_MAX_ATTACK_RADIUS / 2) / .2); // reach damage radius over .3 seconds
|
|
|
|
WRITE_SHORT(m_iSpriteTexture);
|
|
|
|
WRITE_BYTE(0); // startframe
|
|
|
|
WRITE_BYTE(0); // framerate
|
|
|
|
WRITE_BYTE(2); // life
|
|
|
|
WRITE_BYTE(16); // width
|
|
|
|
WRITE_BYTE(0); // noise
|
|
|
|
|
|
|
|
WriteBeamColor();
|
|
|
|
|
|
|
|
WRITE_BYTE(255); //brightness
|
|
|
|
WRITE_BYTE(0); // speed
|
2013-08-30 13:34:05 -07:00
|
|
|
MESSAGE_END();
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseEntity* pEntity = NULL;
|
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, pev->origin, HOUNDEYE_MAX_ATTACK_RADIUS)) != 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
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!FClassnameIs(pEntity->pev, "monster_houndeye"))
|
|
|
|
{ // houndeyes don't hurt other houndeyes with their attack
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// houndeyes do FULL damage if the ent in question is visible. Half damage otherwise.
|
|
|
|
// This means that you must get out of the houndeye's attack range entirely to avoid damage.
|
|
|
|
// Calculate full damage first
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (SquadCount() > 1)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// squad gets attack bonus.
|
2021-11-28 16:54:48 +01:00
|
|
|
flAdjustedDamage = gSkillData.houndeyeDmgBlast + gSkillData.houndeyeDmgBlast * (HOUNDEYE_SQUAD_BONUS * (SquadCount() - 1));
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// solo
|
|
|
|
flAdjustedDamage = gSkillData.houndeyeDmgBlast;
|
|
|
|
}
|
|
|
|
|
|
|
|
flDist = (pEntity->Center() - pev->origin).Length();
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
flAdjustedDamage -= (flDist / HOUNDEYE_MAX_ATTACK_RADIUS) * flAdjustedDamage;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!FVisible(pEntity))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pEntity->IsPlayer())
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// if this entity is a client, and is not in full view, inflict half damage. We do this so that players still
|
2013-08-30 13:34:05 -07:00
|
|
|
// take the residual damage if they don't totally leave the houndeye's effective radius. We restrict it to clients
|
|
|
|
// so that monsters in other parts of the level don't take the damage and get pissed.
|
|
|
|
flAdjustedDamage *= 0.5;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
else if (!FClassnameIs(pEntity->pev, "func_breakable") && !FClassnameIs(pEntity->pev, "func_pushable"))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// do not hurt nonclients through walls, but allow damage to be done to breakables
|
|
|
|
flAdjustedDamage = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//ALERT ( at_aiconsole, "Damage: %f\n", flAdjustedDamage );
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (flAdjustedDamage > 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pEntity->TakeDamage(pev, pev, flAdjustedDamage, DMG_SONIC | DMG_ALWAYSGIB);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
|
|
|
// start task
|
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::StartTask(Task_t* pTask)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
m_iTaskStatus = TASKSTATUS_RUNNING;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (pTask->iTask)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_HOUND_FALL_ASLEEP:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_fAsleep = true; // signal that hound is lying down (must stand again before doing anything else!)
|
|
|
|
m_iTaskStatus = TASKSTATUS_COMPLETE;
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_HOUND_WAKE_UP:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_fAsleep = false; // signal that hound is standing again
|
|
|
|
m_iTaskStatus = TASKSTATUS_COMPLETE;
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_HOUND_OPEN_EYE:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_fDontBlink = false; // turn blinking back on and that code will automatically open the eye
|
|
|
|
m_iTaskStatus = TASKSTATUS_COMPLETE;
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_HOUND_CLOSE_EYE:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->skin = 0;
|
|
|
|
m_fDontBlink = true; // tell blink code to leave the eye alone.
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_HOUND_THREAT_DISPLAY:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_IdealActivity = ACT_IDLE_ANGRY;
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_HOUND_HOP_BACK:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_IdealActivity = ACT_LEAP;
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_RANGE_ATTACK1:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_IdealActivity = ACT_RANGE_ATTACK1;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
/*
|
2013-08-30 13:34:05 -07:00
|
|
|
if ( InSquad() )
|
|
|
|
{
|
|
|
|
// see if there is a battery to connect to.
|
|
|
|
CSquadMonster *pSquad = m_pSquadLeader;
|
|
|
|
|
|
|
|
while ( pSquad )
|
|
|
|
{
|
|
|
|
if ( pSquad->m_iMySlot == bits_SLOT_HOUND_BATTERY )
|
|
|
|
{
|
|
|
|
// draw a beam.
|
|
|
|
MESSAGE_BEGIN( MSG_BROADCAST, SVC_TEMPENTITY );
|
|
|
|
WRITE_BYTE( TE_BEAMENTS );
|
|
|
|
WRITE_SHORT( ENTINDEX( this->edict() ) );
|
|
|
|
WRITE_SHORT( ENTINDEX( pSquad->edict() ) );
|
|
|
|
WRITE_SHORT( m_iSpriteTexture );
|
|
|
|
WRITE_BYTE( 0 ); // framestart
|
|
|
|
WRITE_BYTE( 0 ); // framerate
|
|
|
|
WRITE_BYTE( 10 ); // life
|
|
|
|
WRITE_BYTE( 40 ); // width
|
|
|
|
WRITE_BYTE( 10 ); // noise
|
|
|
|
WRITE_BYTE( 0 ); // r, g, b
|
|
|
|
WRITE_BYTE( 50 ); // r, g, b
|
|
|
|
WRITE_BYTE( 250); // r, g, b
|
|
|
|
WRITE_BYTE( 255 ); // brightness
|
|
|
|
WRITE_BYTE( 30 ); // speed
|
|
|
|
MESSAGE_END();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pSquad = pSquad->m_pSquadNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_SPECIAL_ATTACK1:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_IdealActivity = ACT_SPECIAL_ATTACK1;
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_GUARD:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_IdealActivity = ACT_GUARD;
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
default:
|
|
|
|
{
|
2021-11-29 20:31:17 +01:00
|
|
|
CSquadMonster::StartTask(pTask);
|
2021-11-28 16:54:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// RunTask
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
void CHoundeye::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
|
|
|
{
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_HOUND_THREAT_DISPLAY:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
MakeIdealYaw(m_vecEnemyLKP);
|
|
|
|
ChangeYaw(pev->yaw_speed);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_fSequenceFinished)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
TaskComplete();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_HOUND_CLOSE_EYE:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->skin < HOUNDEYE_EYE_FRAMES - 1)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->skin++;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_HOUND_HOP_BACK:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_fSequenceFinished)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
TaskComplete();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case TASK_SPECIAL_ATTACK1:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
pev->skin = RANDOM_LONG(0, HOUNDEYE_EYE_FRAMES - 1);
|
|
|
|
|
|
|
|
MakeIdealYaw(m_vecEnemyLKP);
|
|
|
|
ChangeYaw(pev->yaw_speed);
|
|
|
|
|
|
|
|
float life;
|
|
|
|
life = ((255 - pev->frame) / (pev->framerate * m_flFrameRate));
|
|
|
|
if (life < 0.1)
|
|
|
|
life = 0.1;
|
|
|
|
|
|
|
|
MESSAGE_BEGIN(MSG_PAS, SVC_TEMPENTITY, pev->origin);
|
|
|
|
WRITE_BYTE(TE_IMPLOSION);
|
|
|
|
WRITE_COORD(pev->origin.x);
|
|
|
|
WRITE_COORD(pev->origin.y);
|
|
|
|
WRITE_COORD(pev->origin.z + 16);
|
|
|
|
WRITE_BYTE(50 * life + 100); // radius
|
|
|
|
WRITE_BYTE(pev->frame / 25.0); // count
|
|
|
|
WRITE_BYTE(life * 10); // life
|
|
|
|
MESSAGE_END();
|
|
|
|
|
|
|
|
if (m_fSequenceFinished)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
SonicAttack();
|
|
|
|
TaskComplete();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
default:
|
|
|
|
{
|
2021-11-29 20:31:17 +01:00
|
|
|
CSquadMonster::RunTask(pTask);
|
2021-11-28 16:54:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// PrescheduleThink
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
void CHoundeye::PrescheduleThink()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// if the hound is mad and is running, make hunt noises.
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_MonsterState == MONSTERSTATE_COMBAT && m_Activity == ACT_RUN && RANDOM_FLOAT(0, 1) < 0.2)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
WarnSound();
|
|
|
|
}
|
|
|
|
|
|
|
|
// at random, initiate a blink if not already blinking or sleeping
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!m_fDontBlink)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((pev->skin == 0) && RANDOM_LONG(0, 0x7F) == 0)
|
|
|
|
{ // start blinking!
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->skin = HOUNDEYE_EYE_FRAMES - 1;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
else if (pev->skin != 0)
|
|
|
|
{ // already blinking
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->skin--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if you are the leader, average the origins of each pack member to get an approximate center.
|
2021-11-28 16:54:48 +01:00
|
|
|
if (IsLeader())
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CSquadMonster* pSquadMember;
|
2013-08-30 13:34:05 -07:00
|
|
|
int iSquadCount = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_SQUAD_MEMBERS; i++)
|
|
|
|
{
|
|
|
|
pSquadMember = MySquadMember(i);
|
|
|
|
|
|
|
|
if (pSquadMember)
|
|
|
|
{
|
|
|
|
iSquadCount++;
|
|
|
|
m_vecPackCenter = m_vecPackCenter + pSquadMember->pev->origin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_vecPackCenter = m_vecPackCenter / iSquadCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
|
|
|
// AI Schedules Specific to this monster
|
|
|
|
//=========================================================
|
2019-09-30 04:02:48 -05:00
|
|
|
// Marphy Fact Files Fix - Fix freeze stutter after leaderlook sequence
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundGuardPack[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, (float)0},
|
2022-08-06 13:41:59 +02:00
|
|
|
{TASK_PLAY_SEQUENCE, (float)ACT_GUARD},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundGuardPack[] =
|
|
|
|
{
|
|
|
|
{tlHoundGuardPack,
|
|
|
|
ARRAYSIZE(tlHoundGuardPack),
|
|
|
|
bits_COND_SEE_HATE |
|
|
|
|
bits_COND_LIGHT_DAMAGE |
|
|
|
|
bits_COND_HEAVY_DAMAGE |
|
|
|
|
bits_COND_PROVOKED |
|
|
|
|
bits_COND_HEAR_SOUND,
|
|
|
|
|
|
|
|
bits_SOUND_COMBAT | // sound flags
|
|
|
|
bits_SOUND_WORLD |
|
|
|
|
bits_SOUND_MEAT |
|
|
|
|
bits_SOUND_PLAYER,
|
|
|
|
"GuardPack"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// primary range attack
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundYell1[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, (float)0},
|
|
|
|
{TASK_FACE_IDEAL, (float)0},
|
|
|
|
{TASK_RANGE_ATTACK1, (float)0},
|
|
|
|
{TASK_SET_SCHEDULE, (float)SCHED_HOUND_AGITATED},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundYell2[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, (float)0},
|
|
|
|
{TASK_FACE_IDEAL, (float)0},
|
|
|
|
{TASK_RANGE_ATTACK1, (float)0},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundRangeAttack[] =
|
|
|
|
{
|
|
|
|
{tlHoundYell1,
|
|
|
|
ARRAYSIZE(tlHoundYell1),
|
|
|
|
bits_COND_LIGHT_DAMAGE |
|
|
|
|
bits_COND_HEAVY_DAMAGE,
|
|
|
|
0,
|
|
|
|
"HoundRangeAttack1"},
|
|
|
|
{tlHoundYell2,
|
|
|
|
ARRAYSIZE(tlHoundYell2),
|
|
|
|
bits_COND_LIGHT_DAMAGE |
|
|
|
|
bits_COND_HEAVY_DAMAGE,
|
|
|
|
0,
|
|
|
|
"HoundRangeAttack2"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// lie down and fall asleep
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundSleep[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, (float)0},
|
|
|
|
{TASK_SET_ACTIVITY, (float)ACT_IDLE},
|
|
|
|
{TASK_WAIT_RANDOM, (float)5},
|
|
|
|
{TASK_PLAY_SEQUENCE, (float)ACT_CROUCH},
|
|
|
|
{TASK_SET_ACTIVITY, (float)ACT_CROUCHIDLE},
|
|
|
|
{TASK_HOUND_FALL_ASLEEP, (float)0},
|
|
|
|
{TASK_WAIT_RANDOM, (float)25},
|
|
|
|
{TASK_HOUND_CLOSE_EYE, (float)0},
|
|
|
|
//{ TASK_WAIT, (float)10 },
|
|
|
|
//{ TASK_WAIT_RANDOM, (float)10 },
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundSleep[] =
|
|
|
|
{
|
|
|
|
{tlHoundSleep,
|
|
|
|
ARRAYSIZE(tlHoundSleep),
|
|
|
|
bits_COND_HEAR_SOUND |
|
|
|
|
bits_COND_LIGHT_DAMAGE |
|
|
|
|
bits_COND_HEAVY_DAMAGE |
|
|
|
|
bits_COND_NEW_ENEMY,
|
|
|
|
|
|
|
|
bits_SOUND_COMBAT |
|
|
|
|
bits_SOUND_PLAYER |
|
|
|
|
bits_SOUND_WORLD,
|
|
|
|
"Hound Sleep"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// wake and stand up lazily
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundWakeLazy[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, (float)0},
|
|
|
|
{TASK_HOUND_OPEN_EYE, (float)0},
|
|
|
|
{TASK_WAIT_RANDOM, (float)2.5},
|
|
|
|
{TASK_PLAY_SEQUENCE, (float)ACT_STAND},
|
|
|
|
{TASK_HOUND_WAKE_UP, (float)0},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundWakeLazy[] =
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
{tlHoundWakeLazy,
|
|
|
|
ARRAYSIZE(tlHoundWakeLazy),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
"WakeLazy"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// wake and stand up with great urgency!
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundWakeUrgent[] =
|
|
|
|
{
|
|
|
|
{TASK_HOUND_OPEN_EYE, (float)0},
|
|
|
|
{TASK_PLAY_SEQUENCE, (float)ACT_HOP},
|
|
|
|
{TASK_FACE_IDEAL, (float)0},
|
|
|
|
{TASK_HOUND_WAKE_UP, (float)0},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundWakeUrgent[] =
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
{tlHoundWakeUrgent,
|
|
|
|
ARRAYSIZE(tlHoundWakeUrgent),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
"WakeUrgent"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundSpecialAttack1[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, 0},
|
|
|
|
{TASK_FACE_IDEAL, (float)0},
|
|
|
|
{TASK_SPECIAL_ATTACK1, (float)0},
|
|
|
|
{TASK_PLAY_SEQUENCE, (float)ACT_IDLE_ANGRY},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundSpecialAttack1[] =
|
|
|
|
{
|
|
|
|
{tlHoundSpecialAttack1,
|
|
|
|
ARRAYSIZE(tlHoundSpecialAttack1),
|
|
|
|
bits_COND_NEW_ENEMY |
|
|
|
|
bits_COND_LIGHT_DAMAGE |
|
|
|
|
bits_COND_HEAVY_DAMAGE |
|
|
|
|
bits_COND_ENEMY_OCCLUDED,
|
|
|
|
|
|
|
|
0,
|
|
|
|
"Hound Special Attack1"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundAgitated[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, 0},
|
|
|
|
{TASK_HOUND_THREAT_DISPLAY, 0},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundAgitated[] =
|
|
|
|
{
|
|
|
|
{tlHoundAgitated,
|
|
|
|
ARRAYSIZE(tlHoundAgitated),
|
|
|
|
bits_COND_NEW_ENEMY |
|
|
|
|
bits_COND_LIGHT_DAMAGE |
|
|
|
|
bits_COND_HEAVY_DAMAGE,
|
|
|
|
0,
|
|
|
|
"Hound Agitated"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundHopRetreat[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, 0},
|
|
|
|
{TASK_HOUND_HOP_BACK, 0},
|
|
|
|
{TASK_SET_SCHEDULE, (float)SCHED_TAKE_COVER_FROM_ENEMY},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundHopRetreat[] =
|
|
|
|
{
|
|
|
|
{tlHoundHopRetreat,
|
|
|
|
ARRAYSIZE(tlHoundHopRetreat),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
"Hound Hop Retreat"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// hound fails in combat with client in the PVS
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundCombatFailPVS[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, 0},
|
|
|
|
{TASK_HOUND_THREAT_DISPLAY, 0},
|
|
|
|
{TASK_WAIT_FACE_ENEMY, (float)1},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundCombatFailPVS[] =
|
|
|
|
{
|
|
|
|
{tlHoundCombatFailPVS,
|
|
|
|
ARRAYSIZE(tlHoundCombatFailPVS),
|
|
|
|
bits_COND_NEW_ENEMY |
|
|
|
|
bits_COND_LIGHT_DAMAGE |
|
|
|
|
bits_COND_HEAVY_DAMAGE,
|
|
|
|
0,
|
|
|
|
"HoundCombatFailPVS"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// hound fails in combat with no client in the PVS. Don't keep peeping!
|
2021-11-28 16:54:48 +01:00
|
|
|
Task_t tlHoundCombatFailNoPVS[] =
|
|
|
|
{
|
|
|
|
{TASK_STOP_MOVING, 0},
|
|
|
|
{TASK_HOUND_THREAT_DISPLAY, 0},
|
|
|
|
{TASK_WAIT_FACE_ENEMY, (float)2},
|
|
|
|
{TASK_SET_ACTIVITY, (float)ACT_IDLE},
|
|
|
|
{TASK_WAIT_PVS, 0},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Schedule_t slHoundCombatFailNoPVS[] =
|
|
|
|
{
|
|
|
|
{tlHoundCombatFailNoPVS,
|
|
|
|
ARRAYSIZE(tlHoundCombatFailNoPVS),
|
|
|
|
bits_COND_NEW_ENEMY |
|
|
|
|
bits_COND_LIGHT_DAMAGE |
|
|
|
|
bits_COND_HEAVY_DAMAGE,
|
|
|
|
0,
|
|
|
|
"HoundCombatFailNoPVS"},
|
2013-08-30 13:34:05 -07:00
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
DEFINE_CUSTOM_SCHEDULES(CHoundeye){
|
2013-08-30 13:34:05 -07:00
|
|
|
slHoundGuardPack,
|
|
|
|
slHoundRangeAttack,
|
2021-11-28 16:54:48 +01:00
|
|
|
&slHoundRangeAttack[1],
|
2013-08-30 13:34:05 -07:00
|
|
|
slHoundSleep,
|
|
|
|
slHoundWakeLazy,
|
|
|
|
slHoundWakeUrgent,
|
|
|
|
slHoundSpecialAttack1,
|
|
|
|
slHoundAgitated,
|
|
|
|
slHoundHopRetreat,
|
|
|
|
slHoundCombatFailPVS,
|
|
|
|
slHoundCombatFailNoPVS,
|
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
IMPLEMENT_CUSTOM_SCHEDULES(CHoundeye, CSquadMonster);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// GetScheduleOfType
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
Schedule_t* CHoundeye::GetScheduleOfType(int Type)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_fAsleep)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// if the hound is sleeping, must wake and stand!
|
2021-11-28 16:54:48 +01:00
|
|
|
if (HasConditions(bits_COND_HEAR_SOUND))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
CSound* pWakeSound;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
pWakeSound = PBestSound();
|
2021-11-28 16:54:48 +01:00
|
|
|
ASSERT(pWakeSound != NULL);
|
|
|
|
if (pWakeSound)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
MakeIdealYaw(pWakeSound->m_vecOrigin);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (FLSoundVolume(pWakeSound) >= HOUNDEYE_SOUND_STARTLE_VOLUME)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// awakened by a loud sound
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundWakeUrgent[0];
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// sound was not loud enough to scare the bejesus out of houndeye
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundWakeLazy[0];
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
else if (HasConditions(bits_COND_NEW_ENEMY))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// get up fast, to fight.
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundWakeUrgent[0];
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// hound is waking up on its own
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundWakeLazy[0];
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (Type)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-29 20:55:01 +01:00
|
|
|
case SCHED_IDLE_STAND:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// we may want to sleep instead of stand!
|
|
|
|
if (InSquad() && !IsLeader() && !m_fAsleep && RANDOM_LONG(0, 29) < 1)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundSleep[0];
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2022-08-06 13:41:59 +02:00
|
|
|
// Marphy Fact Files Fix - Restore squad leader leaderlook animation
|
|
|
|
if (InSquad() && IsLeader() && !m_fAsleep && RANDOM_LONG(0, 14) < 1)
|
|
|
|
{
|
|
|
|
return &slHoundGuardPack[0];
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
else
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-29 20:31:17 +01:00
|
|
|
return CSquadMonster::GetScheduleOfType(Type);
|
2021-11-28 16:54:48 +01:00
|
|
|
}
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case SCHED_RANGE_ATTACK1:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundRangeAttack[0];
|
|
|
|
/*
|
2013-08-30 13:34:05 -07:00
|
|
|
if ( InSquad() )
|
|
|
|
{
|
|
|
|
return &slHoundRangeAttack[ RANDOM_LONG( 0, 1 ) ];
|
|
|
|
}
|
|
|
|
|
|
|
|
return &slHoundRangeAttack[ 1 ];
|
|
|
|
*/
|
2021-11-28 16:54:48 +01:00
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case SCHED_SPECIAL_ATTACK1:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundSpecialAttack1[0];
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case SCHED_GUARD:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundGuardPack[0];
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case SCHED_HOUND_AGITATED:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundAgitated[0];
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case SCHED_HOUND_HOP_RETREAT:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return &slHoundHopRetreat[0];
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
case SCHED_FAIL:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_MonsterState == MONSTERSTATE_COMBAT)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!FNullEnt(FIND_CLIENT_IN_PVS(edict())))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// client in PVS
|
|
|
|
return &slHoundCombatFailPVS[0];
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// client has taken off!
|
|
|
|
return &slHoundCombatFailNoPVS[0];
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
else
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-29 20:31:17 +01:00
|
|
|
return CSquadMonster::GetScheduleOfType(Type);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
2021-11-29 20:55:01 +01:00
|
|
|
default:
|
|
|
|
{
|
2021-11-29 20:31:17 +01:00
|
|
|
return CSquadMonster::GetScheduleOfType(Type);
|
2021-11-28 16:54:48 +01:00
|
|
|
}
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//=========================================================
|
2021-11-28 16:54:48 +01:00
|
|
|
// GetSchedule
|
2013-08-30 13:34:05 -07:00
|
|
|
//=========================================================
|
2021-11-29 20:31:17 +01:00
|
|
|
Schedule_t* CHoundeye::GetSchedule()
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
switch (m_MonsterState)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-29 20:55:01 +01:00
|
|
|
case MONSTERSTATE_COMBAT:
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// dead enemy
|
|
|
|
if (HasConditions(bits_COND_ENEMY_DEAD))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
// call base class, all code to handle dead enemies is centralized there.
|
2021-11-29 20:31:17 +01:00
|
|
|
return CBaseMonster::GetSchedule();
|
2021-11-28 16:54:48 +01:00
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (HasConditions(bits_COND_LIGHT_DAMAGE | bits_COND_HEAVY_DAMAGE))
|
|
|
|
{
|
|
|
|
if (RANDOM_FLOAT(0, 1) <= 0.4)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
TraceResult tr;
|
|
|
|
UTIL_MakeVectors(pev->angles);
|
|
|
|
UTIL_TraceHull(pev->origin, pev->origin + gpGlobals->v_forward * -128, dont_ignore_monsters, head_hull, ENT(pev), &tr);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (tr.flFraction == 1.0)
|
|
|
|
{
|
|
|
|
// it's clear behind, so the hound will jump
|
|
|
|
return GetScheduleOfType(SCHED_HOUND_HOP_RETREAT);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
return GetScheduleOfType(SCHED_TAKE_COVER_FROM_ENEMY);
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (HasConditions(bits_COND_CAN_RANGE_ATTACK1))
|
|
|
|
{
|
|
|
|
if (OccupySlot(bits_SLOTS_HOUND_ATTACK))
|
|
|
|
{
|
|
|
|
return GetScheduleOfType(SCHED_RANGE_ATTACK1);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
|
|
|
|
return GetScheduleOfType(SCHED_HOUND_AGITATED);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
break;
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
return CSquadMonster::GetSchedule();
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|