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
|
|
|
#include "extdll.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "cbase.h"
|
|
|
|
#include "monsters.h"
|
|
|
|
#include "schedule.h"
|
|
|
|
#include "flyingmonster.h"
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define FLYING_AE_FLAP (8)
|
|
|
|
#define FLYING_AE_FLAPSOUND (9)
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
int CFlyingMonster::CheckLocalMove(const Vector& vecStart, const Vector& vecEnd, CBaseEntity* pTarget, float* pflDist)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// UNDONE: need to check more than the endpoint
|
|
|
|
if (FBitSet(pev->flags, FL_SWIM) && (UTIL_PointContents(vecEnd) != CONTENTS_WATER))
|
|
|
|
{
|
|
|
|
// ALERT(at_aiconsole, "can't swim out of water\n");
|
2021-11-28 15:32:26 +01:00
|
|
|
return LOCALMOVE_INVALID;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
TraceResult tr;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceHull(vecStart + Vector(0, 0, 32), vecEnd + Vector(0, 0, 32), dont_ignore_monsters, large_hull, edict(), &tr);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// ALERT( at_console, "%.0f %.0f %.0f : ", vecStart.x, vecStart.y, vecStart.z );
|
|
|
|
// ALERT( at_console, "%.0f %.0f %.0f\n", vecEnd.x, vecEnd.y, vecEnd.z );
|
|
|
|
|
|
|
|
if (pflDist)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
*pflDist = ((tr.vecEndPos - Vector(0, 0, 32)) - vecStart).Length(); // get the distance.
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction );
|
2021-11-28 15:32:26 +01:00
|
|
|
if (0 != tr.fStartSolid || tr.flFraction < 1.0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pTarget && pTarget->edict() == gpGlobals->trace_ent)
|
2013-08-30 13:34:05 -07:00
|
|
|
return LOCALMOVE_VALID;
|
|
|
|
return LOCALMOVE_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
return LOCALMOVE_VALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
bool CFlyingMonster::FTriangulate(const Vector& vecStart, const Vector& vecEnd, float flDist, CBaseEntity* pTargetEnt, Vector* pApex)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return CBaseMonster::FTriangulate(vecStart, vecEnd, flDist, pTargetEnt, pApex);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
Activity CFlyingMonster::GetStoppedActivity()
|
2021-11-28 16:54:48 +01:00
|
|
|
{
|
|
|
|
if (pev->movetype != MOVETYPE_FLY) // UNDONE: Ground idle here, IDLE may be something else
|
2013-08-30 13:34:05 -07:00
|
|
|
return ACT_IDLE;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
return ACT_HOVER;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CFlyingMonster::Stop()
|
2021-11-28 16:54:48 +01:00
|
|
|
{
|
2013-08-30 13:34:05 -07:00
|
|
|
Activity stopped = GetStoppedActivity();
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_IdealActivity != stopped)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
m_flightSpeed = 0;
|
|
|
|
m_IdealActivity = stopped;
|
|
|
|
}
|
|
|
|
pev->angles.z = 0;
|
|
|
|
pev->angles.x = 0;
|
|
|
|
m_vecTravel = g_vecZero;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-08-28 16:36:24 +02:00
|
|
|
float CFlyingMonster::ChangeYaw(int yawSpeed)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->movetype == MOVETYPE_FLY)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
float diff = FlYawDiff();
|
|
|
|
float target = 0;
|
|
|
|
|
2024-08-28 16:36:24 +02:00
|
|
|
if (m_flLastZYawTime == 0.0f)
|
|
|
|
{
|
|
|
|
m_flLastZYawTime = gpGlobals->time - gpGlobals->frametime;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_IdealActivity != GetStoppedActivity())
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (diff < -20)
|
2013-08-30 13:34:05 -07:00
|
|
|
target = 90;
|
2021-11-28 16:54:48 +01:00
|
|
|
else if (diff > 20)
|
2013-08-30 13:34:05 -07:00
|
|
|
target = -90;
|
|
|
|
}
|
2021-01-13 22:52:16 +01:00
|
|
|
|
|
|
|
float delta = gpGlobals->time - m_flLastZYawTime;
|
|
|
|
m_flLastZYawTime = gpGlobals->time;
|
|
|
|
|
2024-08-28 16:36:24 +02:00
|
|
|
// Clamp delta like the engine does with frametime
|
|
|
|
if (delta > 0.25f)
|
|
|
|
delta = 0.25f;
|
2021-01-13 22:52:16 +01:00
|
|
|
|
2024-08-28 16:36:24 +02:00
|
|
|
float speed = 220.0f * delta;
|
|
|
|
pev->angles.z = UTIL_Approach(target, pev->angles.z, 220.0 * speed);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2024-08-28 16:36:24 +02:00
|
|
|
return CBaseMonster::ChangeYaw(yawSpeed);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CFlyingMonster::Killed(entvars_t* pevAttacker, int iGib)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
pev->movetype = MOVETYPE_STEP;
|
2021-11-28 16:54:48 +01:00
|
|
|
ClearBits(pev->flags, FL_ONGROUND);
|
2013-08-30 13:34:05 -07:00
|
|
|
pev->angles.z = 0;
|
|
|
|
pev->angles.x = 0;
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseMonster::Killed(pevAttacker, iGib);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CFlyingMonster::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
|
|
|
{
|
|
|
|
case FLYING_AE_FLAP:
|
|
|
|
m_flightSpeed = 400;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FLYING_AE_FLAPSOUND:
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_pFlapSound)
|
|
|
|
EMIT_SOUND(edict(), CHAN_BODY, m_pFlapSound, 1, ATTN_NORM);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseMonster::HandleAnimEvent(pEvent);
|
2013-08-30 13:34:05 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-29 20:31:17 +01:00
|
|
|
void CFlyingMonster::Move(float flInterval)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->movetype == MOVETYPE_FLY)
|
2013-08-30 13:34:05 -07:00
|
|
|
m_flGroundSpeed = m_flightSpeed;
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseMonster::Move(flInterval);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
bool CFlyingMonster::ShouldAdvanceRoute(float flWaypointDist)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// Get true 3D distance to the goal so we actually reach the correct height
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((m_Route[m_iRouteIndex].iType & bits_MF_IS_GOAL) != 0)
|
|
|
|
flWaypointDist = (m_Route[m_iRouteIndex].vecLocation - pev->origin).Length();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (flWaypointDist <= 64 + (m_flGroundSpeed * gpGlobals->frametime))
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void CFlyingMonster::MoveExecute(CBaseEntity* pTargetEnt, const Vector& vecDir, float flInterval)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (pev->movetype == MOVETYPE_FLY)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (gpGlobals->time - m_stopTime > 1.0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_IdealActivity != m_movementActivity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
m_IdealActivity = m_movementActivity;
|
|
|
|
m_flGroundSpeed = m_flightSpeed = 200;
|
|
|
|
}
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
Vector vecMove = pev->origin + ((vecDir + (m_vecTravel * m_momentum)).Normalize() * (m_flGroundSpeed * flInterval));
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (m_IdealActivity != m_movementActivity)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
m_flightSpeed = UTIL_Approach(100, m_flightSpeed, 75 * gpGlobals->frametime);
|
|
|
|
if (m_flightSpeed < 100)
|
2013-08-30 13:34:05 -07:00
|
|
|
m_stopTime = gpGlobals->time;
|
|
|
|
}
|
|
|
|
else
|
2021-11-28 16:54:48 +01:00
|
|
|
m_flightSpeed = UTIL_Approach(20, m_flightSpeed, 300 * gpGlobals->frametime);
|
|
|
|
|
|
|
|
if (LOCALMOVE_INVALID != CheckLocalMove(pev->origin, vecMove, pTargetEnt, NULL))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
m_vecTravel = (vecMove - pev->origin);
|
|
|
|
m_vecTravel = m_vecTravel.Normalize();
|
|
|
|
UTIL_MoveToOrigin(ENT(pev), vecMove, (m_flGroundSpeed * flInterval), MOVE_STRAFE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_IdealActivity = GetStoppedActivity();
|
|
|
|
m_stopTime = gpGlobals->time;
|
|
|
|
m_vecTravel = g_vecZero;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2021-11-28 16:54:48 +01:00
|
|
|
CBaseMonster::MoveExecute(pTargetEnt, vecDir, flInterval);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
float CFlyingMonster::CeilingZ(const Vector& position)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
TraceResult tr;
|
|
|
|
|
|
|
|
Vector minUp = position;
|
|
|
|
Vector maxUp = position;
|
|
|
|
maxUp.z += 4096.0;
|
|
|
|
|
|
|
|
UTIL_TraceLine(position, maxUp, ignore_monsters, NULL, &tr);
|
|
|
|
if (tr.flFraction != 1.0)
|
|
|
|
maxUp.z = tr.vecEndPos.z;
|
|
|
|
|
2021-11-28 15:32:26 +01:00
|
|
|
if ((pev->flags & FL_SWIM) != 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
return UTIL_WaterLevel(position, minUp.z, maxUp.z);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
return maxUp.z;
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
bool CFlyingMonster::ProbeZ(const Vector& position, const Vector& probe, float* pFraction)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
int conPosition = UTIL_PointContents(position);
|
2021-11-28 16:54:48 +01:00
|
|
|
if ((((pev->flags) & FL_SWIM) == FL_SWIM) ^ (conPosition == CONTENTS_WATER))
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
// SWIMING & !WATER
|
|
|
|
// or FLYING & WATER
|
|
|
|
//
|
|
|
|
*pFraction = 0.0;
|
2021-11-19 13:45:16 +01:00
|
|
|
return true; // We hit a water boundary because we are where we don't belong.
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
int conProbe = UTIL_PointContents(probe);
|
|
|
|
if (conProbe == conPosition)
|
|
|
|
{
|
|
|
|
// The probe is either entirely inside the water (for fish) or entirely
|
|
|
|
// outside the water (for birds).
|
|
|
|
//
|
|
|
|
*pFraction = 1.0;
|
2021-11-19 13:43:33 +01:00
|
|
|
return false;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
Vector ProbeUnit = (probe - position).Normalize();
|
|
|
|
float ProbeLength = (probe - position).Length();
|
2013-08-30 13:34:05 -07:00
|
|
|
float maxProbeLength = ProbeLength;
|
|
|
|
float minProbeLength = 0;
|
|
|
|
|
|
|
|
float diff = maxProbeLength - minProbeLength;
|
|
|
|
while (diff > 1.0)
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
float midProbeLength = minProbeLength + diff / 2.0;
|
2013-08-30 13:34:05 -07:00
|
|
|
Vector midProbeVec = midProbeLength * ProbeUnit;
|
2021-11-28 16:54:48 +01:00
|
|
|
if (UTIL_PointContents(position + midProbeVec) == conPosition)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
minProbeLength = midProbeLength;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
maxProbeLength = midProbeLength;
|
|
|
|
}
|
|
|
|
diff = maxProbeLength - minProbeLength;
|
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
*pFraction = minProbeLength / ProbeLength;
|
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
|
|
|
float CFlyingMonster::FloorZ(const Vector& position)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
TraceResult tr;
|
|
|
|
|
|
|
|
Vector down = position;
|
|
|
|
down.z -= 2048;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_TraceLine(position, down, ignore_monsters, NULL, &tr);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
if (tr.flFraction != 1.0)
|
2013-08-30 13:34:05 -07:00
|
|
|
return tr.vecEndPos.z;
|
|
|
|
|
|
|
|
return down.z;
|
|
|
|
}
|