cs16-client-legacy/dlls/hostage.cpp
2015-12-27 14:32:17 +03:00

1029 lines
23 KiB
C++

/***
*
* Copyright (c) 1996-2002, 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.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
#include "stdafx.h"
#include "cbase.h"
#include "monsters.h"
#include "weapons.h"
#include "player.h"
#include "hostage.h"
#include "gamerules.h"
#include "training_gamerules.h"
#include "hltv.h"
#include "game.h"
#include "trains.h"
#include "vehicle.h"
extern int gmsgHostagePos;
extern int gmsgHostageK;
int g_iHostageNumber;
LINK_ENTITY_TO_CLASS(monster_scientist, CHostage);
LINK_ENTITY_TO_CLASS(hostage_entity, CHostage);
void CHostage::Spawn(void)
{
Precache();
if (pev->classname)
RemoveEntityHashValue(pev, STRING(pev->classname), CLASSNAME);
pev->classname = MAKE_STRING("hostage_entity");
AddEntityHashValue(pev, STRING(pev->classname), CLASSNAME);
pev->movetype = MOVETYPE_STEP;
pev->solid = SOLID_SLIDEBOX;
pev->takedamage = DAMAGE_YES;
pev->flags |= FL_MONSTER;
pev->deadflag = DEAD_NO;
pev->max_health = 100;
pev->health = pev->max_health;
pev->gravity = 1;
pev->view_ofs = VEC_HOSTAGE_VIEW;
pev->velocity = Vector(0, 0, 0);
if (pev->spawnflags & SF_MONSTER_HITMONSTERCLIP)
pev->flags |= FL_MONSTERCLIP;
if (pev->skin < 0)
pev->skin = 0;
SET_MODEL(ENT(pev), STRING(pev->model));
SetActivity(ACT_IDLE);
m_flNextChange = 0;
m_State = STAND;
m_hTargetEnt = NULL;
m_hStoppedTargetEnt = NULL;
m_vPathToFollow[0] = Vector(0, 0, 0);
m_flFlinchTime = 0;
m_bRescueMe = 0;
UTIL_SetSize(pev, VEC_HOSTAGE_HULL_MIN, VEC_HOSTAGE_HULL_MAX);
UTIL_MakeVectors(pev->v_angle);
SetBoneController(0, UTIL_VecToYaw(gpGlobals->v_forward));
SetBoneController(1, 0);
SetBoneController(2, 0);
SetBoneController(3, 0);
SetBoneController(4, 0);
DROP_TO_FLOOR(ENT(pev));
SetThink(&CHostage::IdleThink);
pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2);
m_flNextFullThink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2);
m_vStart = pev->origin;
m_vStartAngles = pev->angles;
m_vOldPos = Vector(9999, 9999, 9999);
m_iHostageIndex = ++g_iHostageNumber;
nTargetNode = -1;
m_fHasPath = FALSE;
m_flLastPathCheck = -1;
m_flPathAcquired = -1;
m_flPathCheckInterval = 0.1;
m_flNextRadarTime = gpGlobals->time + RANDOM_FLOAT(0, 1);
m_LocalNav = new CLocalNav(this);
m_bStuck = FALSE;
m_flStuckTime = 0;
m_improv = NULL;
}
void CHostage::Precache(void)
{
m_whichModel = 0;
if (FStringNull(pev->model))
pev->model = MAKE_STRING("models/scientist.mdl");
PRECACHE_MODEL((char *)STRING(pev->model));
PRECACHE_SOUND("hostage/hos1.wav");
PRECACHE_SOUND("hostage/hos2.wav");
PRECACHE_SOUND("hostage/hos3.wav");
PRECACHE_SOUND("hostage/hos4.wav");
PRECACHE_SOUND("hostage/hos5.wav");
PRECACHE_MODEL("sprites/smoke.spr");
}
void CHostage::SetActivity(Activity activity)
{
if (m_Activity != activity)
{
int animDesired = LookupActivity(activity);
if (animDesired != -1)
{
if (pev->sequence != animDesired)
{
if ((m_Activity != ACT_WALK && m_Activity != ACT_RUN) || (activity != ACT_WALK && activity != ACT_RUN))
pev->frame = 0;
pev->sequence = animDesired;
}
m_Activity = activity;
ResetSequenceInfo();
}
}
}
void CHostage::SetFlinchActivity(void)
{
switch (m_LastHitGroup)
{
case HITGROUP_GENERIC:
case HITGROUP_HEAD:
case HITGROUP_CHEST:
case HITGROUP_STOMACH: SetActivity(ACT_SMALL_FLINCH); break;
case HITGROUP_LEFTARM: SetActivity(ACT_FLINCH_LEFTARM); break;
case HITGROUP_RIGHTARM: SetActivity(ACT_FLINCH_RIGHTARM); break;
case HITGROUP_LEFTLEG: SetActivity(ACT_FLINCH_LEFTLEG); break;
case HITGROUP_RIGHTLEG: SetActivity(ACT_FLINCH_RIGHTLEG); break;
}
}
void CHostage::SetDeathActivity(void)
{
if (m_improv)
return;
switch (m_LastHitGroup)
{
case HITGROUP_GENERIC:
case HITGROUP_HEAD: SetActivity(ACT_DIE_HEADSHOT); break;
case HITGROUP_CHEST: SetActivity(ACT_DIESIMPLE); break;
case HITGROUP_STOMACH: SetActivity(ACT_DIEFORWARD); break;
case HITGROUP_LEFTARM: SetActivity(ACT_DIEBACKWARD); break;
case HITGROUP_RIGHTARM: SetActivity(ACT_DIESIMPLE); break;
case HITGROUP_LEFTLEG: SetActivity(ACT_DIEBACKWARD); break;
case HITGROUP_RIGHTLEG: SetActivity(ACT_DIEFORWARD); break;
}
}
float CHostage::GetModifiedDamage(float flDamage)
{
switch (m_LastHitGroup)
{
case HITGROUP_GENERIC: flDamage *= 1.75; break;
case HITGROUP_HEAD: flDamage *= 2.5; break;
case HITGROUP_CHEST: flDamage *= 1.5; break;
case HITGROUP_STOMACH: flDamage *= 1.75; break;
case HITGROUP_LEFTARM:
case HITGROUP_RIGHTARM: flDamage *= 0.75; break;
case HITGROUP_LEFTLEG:
case HITGROUP_RIGHTLEG: flDamage *= 0.6; break;
}
return flDamage;
}
void CHostage::PlayPainSound(void)
{
if (m_LastHitGroup == HITGROUP_HEAD)
{
int rand = RANDOM_FLOAT(0, 1);
switch (rand)
{
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/headshot1.wav", VOL_NORM, ATTN_NORM); break;
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/headshot2.wav", VOL_NORM, ATTN_NORM); break;
}
}
}
void CHostage::IdleThink(void)
{
pev->nextthink = gpGlobals->time + (1.0 / 30);
DispatchAnimEvents(StudioFrameAdvance());
if (gpGlobals->time >= m_flNextFullThink)
{
m_flNextFullThink = gpGlobals->time + 0.1;
if (pev->deadflag == DEAD_DEAD)
{
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0));
return;
}
if (m_hTargetEnt != NULL)
{
if ((m_bStuck != FALSE && gpGlobals->time - m_flStuckTime > 5) || m_hTargetEnt->pev->deadflag != DEAD_NO)
{
m_State = STAND;
m_hTargetEnt = NULL;
m_bStuck = FALSE;
}
}
if (m_hTargetEnt != 0 || m_improv)
{
CBasePlayer *pPlayer;
if (m_improv)
{
}
else
pPlayer = GetClassPtr((CBasePlayer *)m_hTargetEnt->pev);
if (!pPlayer || pPlayer->m_iTeam == TEAM_CT)
{
if (!g_pGameRules->m_bMapHasRescueZone)
{
BOOL hasRescueZone = FALSE;
if (UTIL_FindEntityByClassname(NULL, "info_hostage_rescue"))
hasRescueZone = TRUE;
CBaseEntity *pEntity = NULL;
while ((pEntity = UTIL_FindEntityByClassname(pEntity, "info_hostage_rescue")) != NULL)
{
if ((pEntity->pev->origin - pev->origin).Length() < 256)
{
m_bRescueMe = TRUE;
break;
}
}
if (!hasRescueZone)
{
pEntity = NULL;
while ((pEntity = UTIL_FindEntityByClassname(pEntity, "info_player_start")) != NULL)
{
if ((pEntity->pev->origin - pev->origin).Length() < 256)
{
m_bRescueMe = TRUE;
break;
}
}
}
}
if (m_bRescueMe)
{
if (g_pGameRules->IsCareer() && pPlayer && !pPlayer->IsBot())
{
}
if (pPlayer)
{
pev->deadflag = DEAD_RESPAWNABLE;
pPlayer->AddAccount(1000);
UTIL_LogPrintf("\"%s<%i><%s><CT>\" triggered \"Rescued_A_Hostage\"\n", STRING(pPlayer->pev->netname), GETPLAYERUSERID(pPlayer->edict()), GETPLAYERAUTHID(pPlayer->edict()));
}
SendHostageEventMsg();
MESSAGE_BEGIN(MSG_SPEC, SVC_DIRECTOR);
WRITE_BYTE(9);
WRITE_BYTE(DRC_CMD_EVENT);
WRITE_SHORT(pPlayer ? ENTINDEX(pPlayer->edict()) : 0);
WRITE_SHORT(ENTINDEX(edict()));
WRITE_LONG(15);
MESSAGE_END();
pev->effects |= EF_NODRAW;
Remove();
g_pGameRules->m_iHostagesRescued++;
g_pGameRules->CheckWinConditions();
if (pPlayer)
Broadcast("rescued");
else
Broadcast("escaped");
}
}
}
DoFollow();
if (pev->deadflag != DEAD_DEAD && !(pev->effects & EF_NODRAW))
{
if (m_flNextRadarTime <= gpGlobals->time)
{
if ((m_vOldPos - pev->origin).Length() > 1)
{
m_vOldPos = pev->origin;
if (!g_pGameRules->m_fTeamCount)
SendHostagePositionMsg();
}
m_flNextRadarTime = gpGlobals->time + 1;
}
}
if (m_flFlinchTime <= gpGlobals->time)
{
if (pev->velocity.Length() > 160)
SetActivity(ACT_RUN);
else if (pev->velocity.Length() > 15)
SetActivity(ACT_WALK);
else
SetActivity(ACT_IDLE);
}
}
}
void CHostage::Remove(void)
{
pev->movetype = MOVETYPE_NONE;
pev->solid = SOLID_NOT;
pev->takedamage = DAMAGE_NO;
UTIL_SetSize(pev, Vector(0, 0, 0), Vector(0, 0, 0));
pev->nextthink = -1;
m_flNextFullThink = -1;
}
void CHostage::RePosition(void)
{
pev->health = pev->max_health;
pev->movetype = MOVETYPE_STEP;
pev->solid = SOLID_SLIDEBOX;
pev->takedamage = DAMAGE_YES;
pev->deadflag = DEAD_NO;
pev->velocity = Vector(0, 0, 0);
pev->angles = m_vStartAngles;
pev->effects &= ~EF_NODRAW;
m_hTargetEnt = NULL;
m_hStoppedTargetEnt = NULL;
m_bTouched = FALSE;
m_bRescueMe = FALSE;
m_vOldPos = Vector(9999, 9999, 9999);
m_flNextRadarTime = 0;
UTIL_SetOrigin(pev, m_vStart);
UTIL_SetSize(pev, VEC_HOSTAGE_HULL_MIN, VEC_HOSTAGE_HULL_MAX);
DROP_TO_FLOOR(ENT(pev));
SetActivity(ACT_IDLE);
SetThink(&CHostage::IdleThink);
pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2);
m_fHasPath = FALSE;
nTargetNode = -1;
m_flLastPathCheck = -1;
m_flPathAcquired = -1;
m_flPathCheckInterval = 0.1;
m_flNextFullThink = gpGlobals->time + RANDOM_FLOAT(0.1, 0.2);
}
int CHostage::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType)
{
CBasePlayer *pAttacker = NULL;
flDamage = GetModifiedDamage(flDamage);
if (flDamage > pev->health)
flDamage = pev->health;
pev->health -= flDamage;
if (m_improv)
{
}
PlayPainSound();
if (pevAttacker)
{
CBaseEntity *pEntity = GetClassPtr((CBaseEntity *)pevAttacker);
if (pEntity->Classify() == CLASS_VEHICLE)
{
CBaseEntity *pDriver = ((CFuncVehicle *)pEntity)->m_pDriver;
if (pDriver)
pevAttacker = pDriver->pev;
}
if (pEntity->IsPlayer())
pAttacker = GetClassPtr((CBasePlayer *)pevAttacker);
}
if (pev->health <= 0)
{
pev->health = 0;
pev->movetype = MOVETYPE_TOSS;
ClearBits(pev->flags, FL_ONGROUND);
SetDeathActivity();
if (pAttacker)
{
pAttacker->AddAccount((-25 - flDamage) * 20);
AnnounceDeath(pAttacker);
ApplyHostagePenalty(pAttacker);
}
pev->takedamage = DAMAGE_NO;
pev->deadflag = DEAD_DEAD;
pev->solid = SOLID_NOT;
if (m_improv)
{
}
g_pGameRules->CheckWinConditions();
if (!g_pGameRules->m_fTeamCount)
SendHostageEventMsg();
pev->nextthink = gpGlobals->time + 3;
SetThink(&CHostage::Remove);
return 0;
}
m_flFlinchTime = gpGlobals->time + 0.75;
if (m_improv)
{
}
else
{
SetFlinchActivity();
if (pAttacker)
{
pAttacker->AddAccount((int)flDamage * -20);
ClientPrint(pAttacker->pev, HUD_PRINTCENTER, "#Injured_Hostage");
if (!(pAttacker->m_flDisplayHistory & DHF_HOSTAGE_INJURED))
{
pAttacker->HintMessage("#Hint_careful_around_hostages");
pAttacker->m_flDisplayHistory |= DHF_HOSTAGE_INJURED;
}
return 1;
}
}
return 0;
}
void CHostage::AnnounceDeath(CBasePlayer *pAttacker)
{
ClientPrint(pAttacker->pev, HUD_PRINTCENTER, "#Killed_Hostage");
if (!(pAttacker->m_flDisplayHistory & DHF_HOSTAGE_KILLED))
{
pAttacker->HintMessage("#Hint_lost_money");
pAttacker->m_flDisplayHistory |= DHF_HOSTAGE_KILLED;
}
if (!g_pGameRules->IsMultiplayer())
CHalfLifeTraining::HostageDied();
UTIL_LogPrintf("\"%s<%i><%s><%s>\" triggered \"Killed_A_Hostage\"\n", STRING(pAttacker->pev->netname), GETPLAYERUSERID(pAttacker->edict()), GETPLAYERAUTHID(pAttacker->edict()), GetTeam(pAttacker->m_iTeam));
MESSAGE_BEGIN(MSG_SPEC, SVC_DIRECTOR);
WRITE_BYTE(9);
WRITE_BYTE(DRC_CMD_EVENT);
WRITE_SHORT(ENTINDEX(pAttacker->edict()));
WRITE_SHORT(ENTINDEX(edict()));
WRITE_LONG(15);
MESSAGE_END();
}
void CHostage::ApplyHostagePenalty(CBasePlayer *pAttacker)
{
if (pAttacker->m_iTeam == TEAM_TERRORIST)
{
int iHostagePenalty = (int)CVAR_GET_FLOAT("mp_hostagepenalty");
if (iHostagePenalty)
{
if (pAttacker->m_iHostagesKilled++ == iHostagePenalty)
pAttacker->HintMessage("#Hint_removed_for_next_hostage_killed", TRUE);
else if (pAttacker->m_iHostagesKilled >= iHostagePenalty)
CLIENT_COMMAND(pAttacker->edict(), "disconnect\n");
}
}
}
void CHostage::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
if (!pActivator->IsPlayer())
return;
if (pev->takedamage == DAMAGE_NO)
return;
CBasePlayer *pPlayer = (CBasePlayer *)pActivator;
if (pPlayer->m_iTeam != TEAM_CT)
{
if (!(pPlayer->m_flDisplayHistory & DHF_HOSTAGE_CTMOVE))
{
pPlayer->m_flDisplayHistory |= DHF_HOSTAGE_CTMOVE;
pPlayer->HintMessage("#Only_CT_Can_Move_Hostages", FALSE, TRUE);
}
return;
}
if (gpGlobals->time >= m_flNextChange)
{
m_flNextChange = gpGlobals->time + 1;
if (m_improv)
{
}
else
{
m_flPathAcquired = gpGlobals->time;
if (pPlayer != m_hTargetEnt)
{
m_State = FOLLOW;
m_hTargetEnt = pPlayer;
m_hStoppedTargetEnt = NULL;
}
else if (m_State == FOLLOW)
{
m_State = STAND;
m_hTargetEnt = NULL;
m_hStoppedTargetEnt = pPlayer;
}
else
m_State = FOLLOW;
if (m_State == FOLLOW)
PlayFollowRescueSound();
}
GiveCTTouchBonus(pPlayer);
pPlayer->HostageUsed();
}
}
void CHostage::GiveCTTouchBonus(CBasePlayer *pPlayer)
{
if (m_bTouched == FALSE)
{
m_bTouched = TRUE;
g_pGameRules->m_iAccountCT += 100;
pPlayer->AddAccount(150);
UTIL_LogPrintf("\"%s<%i><%s><CT>\" triggered \"Touched_A_Hostage\"\n", STRING(pPlayer->pev->netname), GETPLAYERUSERID(pPlayer->edict()), GETPLAYERAUTHID(pPlayer->edict()));
}
}
void CHostage::PlayFollowRescueSound(void)
{
switch (RANDOM_LONG(0, 4))
{
case 0: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hostage/hos1.wav", VOL_NORM, ATTN_NORM); break;
case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hostage/hos2.wav", VOL_NORM, ATTN_NORM); break;
case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hostage/hos3.wav", VOL_NORM, ATTN_NORM); break;
case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hostage/hos4.wav", VOL_NORM, ATTN_NORM); break;
case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "hostage/hos5.wav", VOL_NORM, ATTN_NORM); break;
}
}
int CHostage::ObjectCaps(void)
{
return CBaseMonster::ObjectCaps() | FCAP_MUST_SPAWN | FCAP_ONOFF_USE;
}
void UTIL_DrawBeamPoints(Vector vecSrc, Vector vecDest, int iLifetime, byte bRed, byte bGreen, byte bBlue);
void CHostage::Touch(CBaseEntity *pOther)
{
if (m_improv)
return;
if (pOther->IsPlayer() !=FALSE)
{
if (((CBasePlayer *)pOther)->m_iTeam != TEAM_CT)
return;
}
else
{
if (!FClassnameIs(pOther->pev, "hostage_entity"))
return;
}
Vector vecSrc, vecDest;
vecDest = (pev->origin - pOther->pev->origin);
ALERT(at_logged, "Check this! %s %s %i\n", __FILE__, __FUNCTION__, __LINE__);
//vecDest.z = pev->origin.z - pev->origin.z;
vecDest = vecDest.Normalize() * 50;
pev->velocity = pev->velocity + vecDest;
vecSrc = pev->origin;
vecDest = vecSrc + (pev->velocity.Normalize() * 500);
UTIL_DrawBeamPoints(vecSrc, vecDest, 10, 0, 255, 0);
}
void CHostage::PointAt(Vector &origin)
{
pev->angles.x = 0;
pev->angles.y = UTIL_VecToAngles(origin - pev->origin).y;
pev->angles.z = 0;
}
void CHostage::DoFollow(void)
{
if (m_hTargetEnt == NULL)
return;
CBaseEntity *pFollowing;
Vector vecDest;
float flRadius;
int nindexPath;
pFollowing = GetClassPtr((CBaseEntity *)m_hTargetEnt->pev);
m_LocalNav->SetTargetEnt(pFollowing);
vecDest = pFollowing->pev->origin;
vecDest.z += pFollowing->pev->mins.z;
flRadius = (vecDest - pev->origin).Length();
if (flRadius < 80)
{
if (m_fHasPath)
return;
if (m_LocalNav->PathTraversable(pev->origin, vecDest, TRUE) != TRAVERSABLE_NO)
return;
}
if (FBitSet(pev->flags, FL_ONGROUND))
{
if (gpGlobals->time > m_flLastPathCheck + m_flPathCheckInterval)
{
if (!m_fHasPath || pFollowing->pev->velocity.Length2D() > 1)
{
m_flLastPathCheck = gpGlobals->time;
m_LocalNav->RequestNav(this);
}
}
}
if (m_fHasPath)
{
nTargetNode = nindexPath = m_LocalNav->GetFurthestTraversableNode(pev->origin, vecNodes, m_nPathNodes, TRUE);
if (!nindexPath)
{
if ((vecNodes[nTargetNode] - pev->origin).Length2D() < HOSTAGE_STEPSIZE)
nTargetNode = -1;
}
if (nTargetNode == -1)
{
m_fHasPath = FALSE;
m_flPathCheckInterval = 0.1;
}
}
if (gpGlobals->time < m_flFlinchTime)
return;
if (nTargetNode != -1)
{
if (FBitSet(pev->flags, FL_ONGROUND))
PointAt(vecNodes[nTargetNode]);
if (IsOnLadder())
pev->v_angle.x = -60;
MoveToward(vecNodes[nTargetNode]);
m_bStuck = FALSE;
}
if (pev->takedamage == DAMAGE_YES)
{
if (m_improv)
{
}
if (m_hTargetEnt != NULL && m_State == FOLLOW)
{
if (!m_bStuck)
{
if (flRadius > 200)
{
m_bStuck = TRUE;
m_flStuckTime = gpGlobals->time;
}
}
}
}
if (FBitSet(pev->flags, FL_ONGROUND))
{
if (m_flPathAcquired != -1 && m_flPathAcquired + 2 > gpGlobals->time)
{
if (pev->velocity.Length2D() < 1 || nTargetNode == -1)
Wiggle();
}
}
}
void CHostage::MoveToward(Vector &vecLoc)
{
int nFwdMove;
Vector vecFwd;
Vector vecbigDest;
Vector vecMove;
CBaseEntity *pFollowing;
Vector vecAng;
float flDist;
pFollowing = GetClassPtr((CBaseEntity *)m_hTargetEnt->pev);
vecMove = vecLoc - pev->origin;
vecAng = UTIL_VecToAngles(vecMove);
vecAng = Vector(0, vecAng.y, 0);
UTIL_MakeVectorsPrivate(vecAng, vecFwd, NULL, NULL);
if ((vecFwd * m_LocalNav->s_flStepSize).Length2D() <= (vecLoc - pev->origin).Length2D())
flDist = (vecFwd * m_LocalNav->s_flStepSize).Length2D();
else
flDist = (vecLoc - pev->origin).Length2D();
vecbigDest = pev->origin + (vecFwd * flDist);
nFwdMove = m_LocalNav->PathTraversable(pev->origin, vecbigDest, FALSE);
if (nFwdMove != TRAVERSABLE_NO)
{
vecbigDest = pFollowing->pev->origin;
vecbigDest.z += pFollowing->pev->mins.z;
if (FBitSet(pev->flags, FL_ONGROUND))
{
flDist = (vecbigDest - pev->origin).Length();
if (flDist >= 110)
{
if (flDist >= 250)
flDist = 400;
else
flDist = 300;
}
}
else
flDist = 250;
pev->velocity.x = vecFwd.x * flDist;
pev->velocity.y = vecFwd.y * flDist;
UTIL_DrawBeamPoints(pev->origin, pev->origin + (pev->velocity.Normalize() * 500), 10, 255, 0, 0);
if (nFwdMove == TRAVERSABLE_STEPJUMPABLE)
{
if (FBitSet(pev->flags, FL_ONGROUND))
pev->velocity.z = 270;
}
}
}
void CHostage::NavReady(void)
{
CBaseEntity *pFollowing;
Vector vecSrc;
Vector vecDest;
TraceResult tr;
int nindexPath;
if (m_hTargetEnt == NULL)
return;
pFollowing = GetClassPtr((CBaseEntity *)m_hTargetEnt->pev);
vecSrc = pFollowing->pev->origin;
vecDest = pFollowing->pev->origin;
if (!FBitSet(pFollowing->pev->flags, FL_ONGROUND))
{
UTIL_TraceHull(vecSrc, vecDest - Vector(0, 0, 300), ignore_monsters, human_hull, pFollowing->edict(), &tr);
if (tr.fStartSolid || tr.flFraction == 1)
return;
vecDest = tr.vecEndPos;
}
vecDest.z += pFollowing->pev->mins.z;
m_LocalNav->SetTargetEnt(pFollowing);
nindexPath = m_LocalNav->FindPath(pev->origin, vecDest, 40, TRUE);
if (nindexPath != -1)
{
m_fHasPath = TRUE;
nTargetNode = -1;
m_flPathAcquired = gpGlobals->time;
m_flPathCheckInterval = 0.5;
m_nPathNodes = m_LocalNav->SetupPathNodes(nindexPath, vecNodes, TRUE);
}
else if (!m_fHasPath)
{
m_flPathCheckInterval += 0.1;
if (m_flPathCheckInterval >= 0.5)
m_flPathCheckInterval = 0.5;
}
}
void CHostage::SendHostagePositionMsg(void)
{
CBaseEntity *pEntity = NULL;
while ((pEntity = UTIL_FindEntityByClassname(pEntity, "player")) != NULL)
{
if (FNullEnt(pEntity->edict()))
break;
if (!pEntity->IsPlayer())
continue;
if (pEntity->pev->flags == FL_DORMANT)
continue;
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
if (pPlayer->pev->deadflag == DEAD_NO && pPlayer->m_iTeam == TEAM_CT)
{
MESSAGE_BEGIN(MSG_ONE, gmsgHostagePos, NULL, pPlayer->pev);
WRITE_BYTE(0);
WRITE_BYTE(m_iHostageIndex);
WRITE_COORD(pev->origin.x);
WRITE_COORD(pev->origin.y);
WRITE_COORD(pev->origin.z);
MESSAGE_END();
}
}
}
void CHostage::SendHostageEventMsg(void)
{
CBaseEntity *pEntity = NULL;
while ((pEntity = UTIL_FindEntityByClassname(pEntity, "player")) != NULL)
{
if (FNullEnt(pEntity->edict()))
break;
if (!pEntity->IsPlayer())
continue;
if (pEntity->pev->flags == FL_DORMANT)
continue;
CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev);
if (pPlayer->pev->deadflag == DEAD_NO && pPlayer->m_iTeam == TEAM_CT)
{
MESSAGE_BEGIN(MSG_ONE, gmsgHostageK, NULL, pPlayer->pev);
WRITE_BYTE(m_iHostageIndex);
MESSAGE_END();
}
if (pPlayer->pev->deadflag == DEAD_NO)
pPlayer->SendHostageIcons();
}
}
void CHostage::Wiggle(void)
{
TraceResult tr;
Vector vec = Vector(0, 0, 0);
Vector wiggle_directions[8] =
{
Vector(50, 0, 0),
Vector(-50, 0, 0),
Vector(0, 50, 0),
Vector(0, -50, 0),
Vector(50, 50, 0),
Vector(50, -50, 0),
Vector(-50, 50, 0),
Vector(-50, -50, 0)
};
for (int i = 0; i < 8; i++)
{
vec=pev->origin + wiggle_directions[i];
if (m_LocalNav->PathTraversable(pev->origin, vec, TRUE) == TRAVERSABLE_NO)
vec = vec - wiggle_directions[i];
}
Vector vecSrc, vecDest;
vec = vec + Vector(RANDOM_FLOAT(-3, 3), RANDOM_FLOAT(-3, 3), 0);
pev->velocity = pev->velocity + (vec.Normalize() * 100);
vecSrc = pev->origin;
vecDest = vecSrc + (pev->velocity.Normalize() * 500);
UTIL_DrawBeamPoints(vecSrc, vecDest, 10, 0, 0, 255);
}
void CHostage::PreThink(void)
{
Vector vecSrc;
Vector vecDest;
TraceResult tr;
float flOrigDist;
float flRaisedDist;
if (m_improv)
return;
if (!FBitSet(pev->flags, FL_ONGROUND))
return;
if (pev->velocity.Length2D() < 1)
return;
vecSrc = pev->origin;
vecDest = vecSrc + pev->velocity * gpGlobals->frametime;
vecDest.z = vecSrc.z;
TRACE_MONSTER_HULL(edict(), vecSrc, vecDest, dont_ignore_monsters, edict(), &tr);
if (tr.fStartSolid)
return;
if (tr.flFraction == 1)
return;
if (tr.vecPlaneNormal.z > 0.7)
return;
flOrigDist = (tr.vecEndPos - pev->origin).Length2D();
vecSrc.z += m_LocalNav->s_flStepSize;
vecDest = vecSrc + (pev->velocity.Normalize() * 0.1);
vecDest.z = vecSrc.z;
TRACE_MONSTER_HULL(edict(), vecSrc, vecDest, dont_ignore_monsters, edict(), &tr);
if (tr.fStartSolid)
return;
vecSrc = tr.vecEndPos;
vecDest = tr.vecEndPos;
vecDest.z -= m_LocalNav->s_flStepSize;
TRACE_MONSTER_HULL(edict(), vecSrc, vecDest, dont_ignore_monsters, edict(), &tr);
if (tr.vecPlaneNormal.z < 0.7)
return;
flRaisedDist = (tr.vecEndPos - pev->origin).Length2D();
if (flRaisedDist > flOrigDist)
{
Vector vecOrigin = pev->origin;
vecOrigin.z = tr.vecEndPos.z;
UTIL_SetOrigin(pev, vecOrigin);
pev->velocity.z += pev->gravity * g_psv_gravity->value * gpGlobals->frametime;
}
}
int CHostage::BloodColor(void)
{
return DONT_BLEED;
}
void UTIL_DrawBeamPoints(Vector vecSrc, Vector vecDest, int iLifetime, byte bRed, byte bGreen, byte bBlue)
{
#ifdef _DEBUG
static int s_iBeamSprite = 0;
if (!s_iBeamSprite)
s_iBeamSprite = PRECACHE_MODEL("sprites/smoke.spr");
MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSrc);
WRITE_BYTE(TE_BEAMPOINTS);
WRITE_COORD(vecSrc.x);
WRITE_COORD(vecSrc.y);
WRITE_COORD(vecSrc.z);
WRITE_COORD(vecDest.x);
WRITE_COORD(vecDest.y);
WRITE_COORD(vecDest.z);
WRITE_SHORT(s_iBeamSprite);
WRITE_BYTE(0);
WRITE_BYTE(0);
WRITE_BYTE(iLifetime);
WRITE_BYTE(10);
WRITE_BYTE(0);
WRITE_BYTE(bRed);
WRITE_BYTE(bGreen);
WRITE_BYTE(bBlue);
WRITE_BYTE(255);
WRITE_BYTE(0);
MESSAGE_END();
#endif
}