2016-06-04 15:24:23 +02:00
|
|
|
/***
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
****/
|
2016-06-25 18:33:39 +02:00
|
|
|
|
2016-06-04 15:24:23 +02:00
|
|
|
#include "extdll.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "cbase.h"
|
2024-09-18 22:18:58 +02:00
|
|
|
#include "game.h"
|
2016-06-04 15:24:23 +02:00
|
|
|
#include "monsters.h"
|
|
|
|
#include "schedule.h"
|
|
|
|
#include "flyingmonster.h"
|
|
|
|
|
|
|
|
#define FLYING_AE_FLAP (8)
|
|
|
|
#define FLYING_AE_FLAPSOUND (9)
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
extern DLL_GLOBAL edict_t *g_pBodyQueueHead;
|
2016-06-04 15:24:23 +02:00
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
int CFlyingMonster::CheckLocalMove( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
// UNDONE: need to check more than the endpoint
|
2016-07-31 15:48:50 +02:00
|
|
|
if( FBitSet( pev->flags, FL_SWIM ) && ( UTIL_PointContents( vecEnd ) != CONTENTS_WATER ) )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2016-07-31 15:48:50 +02:00
|
|
|
// ALERT( at_aiconsole, "can't swim out of water\n" );
|
2016-06-04 15:24:23 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
TraceResult tr;
|
|
|
|
|
2019-10-13 13:49:25 +02:00
|
|
|
UTIL_TraceHull( vecStart + Vector( 0.0f, 0.0f, 32.0f ), vecEnd + Vector( 0.0f, 0.0f, 32.0f ), dont_ignore_monsters, large_hull, edict(), &tr );
|
2016-06-04 15:24:23 +02: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 );
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
if( pflDist )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2019-10-13 13:49:25 +02:00
|
|
|
*pflDist = ( ( tr.vecEndPos - Vector( 0.0f, 0.0f, 32.0f ) ) - vecStart ).Length();// get the distance.
|
2016-06-04 15:24:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ALERT( at_console, "check %d %d %f\n", tr.fStartSolid, tr.fAllSolid, tr.flFraction );
|
2019-10-13 13:49:25 +02:00
|
|
|
if( tr.fStartSolid || tr.flFraction < 1.0f )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2016-07-31 15:48:50 +02:00
|
|
|
if( pTarget && pTarget->edict() == gpGlobals->trace_ent )
|
2016-06-04 15:24:23 +02:00
|
|
|
return LOCALMOVE_VALID;
|
|
|
|
return LOCALMOVE_INVALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
return LOCALMOVE_VALID;
|
|
|
|
}
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
BOOL CFlyingMonster::FTriangulate( const Vector &vecStart, const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
return CBaseMonster::FTriangulate( vecStart, vecEnd, flDist, pTargetEnt, pApex );
|
|
|
|
}
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
Activity CFlyingMonster::GetStoppedActivity( void )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2016-07-31 15:48:50 +02:00
|
|
|
if( pev->movetype != MOVETYPE_FLY ) // UNDONE: Ground idle here, IDLE may be something else
|
2016-06-04 15:24:23 +02:00
|
|
|
return ACT_IDLE;
|
|
|
|
|
|
|
|
return ACT_HOVER;
|
|
|
|
}
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
void CFlyingMonster::Stop( void )
|
|
|
|
{
|
2016-06-04 15:24:23 +02:00
|
|
|
Activity stopped = GetStoppedActivity();
|
2016-07-31 15:48:50 +02:00
|
|
|
if( m_IdealActivity != stopped )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
m_flightSpeed = 0;
|
|
|
|
m_IdealActivity = stopped;
|
|
|
|
}
|
2019-10-13 13:49:25 +02:00
|
|
|
pev->angles.z = 0.0f;
|
|
|
|
pev->angles.x = 0.0f;
|
2016-06-04 15:24:23 +02:00
|
|
|
m_vecTravel = g_vecZero;
|
|
|
|
}
|
|
|
|
|
2024-09-18 22:18:58 +02:00
|
|
|
float CFlyingMonster::ChangeYaw( int yawSpeed )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2016-07-31 15:48:50 +02:00
|
|
|
if( pev->movetype == MOVETYPE_FLY )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
float diff = FlYawDiff();
|
2019-10-13 13:49:25 +02:00
|
|
|
float target = 0.0f;
|
2016-06-04 15:24:23 +02:00
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
if( m_IdealActivity != GetStoppedActivity() )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2019-10-13 13:49:25 +02:00
|
|
|
if( diff < -20.0f )
|
|
|
|
target = 90.0f;
|
|
|
|
else if( diff > 20.0f )
|
|
|
|
target = -90.0f;
|
2016-06-04 15:24:23 +02:00
|
|
|
}
|
2024-09-18 22:18:58 +02:00
|
|
|
|
|
|
|
float speed = 220.f;
|
|
|
|
|
|
|
|
if( monsteryawspeedfix.value )
|
|
|
|
{
|
|
|
|
if( m_flLastZYawTime == 0.f )
|
|
|
|
m_flLastZYawTime = gpGlobals->time - gpGlobals->frametime;
|
|
|
|
|
|
|
|
float delta = Q_min( gpGlobals->time - m_flLastZYawTime, 0.25f );
|
|
|
|
m_flLastZYawTime = gpGlobals->time;
|
|
|
|
|
|
|
|
speed *= delta;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
speed *= gpGlobals->frametime;
|
|
|
|
|
|
|
|
pev->angles.z = UTIL_Approach( target, pev->angles.z, speed );
|
2016-06-04 15:24:23 +02:00
|
|
|
}
|
2024-09-18 22:18:58 +02:00
|
|
|
return CBaseMonster::ChangeYaw( yawSpeed );
|
2016-06-04 15:24:23 +02:00
|
|
|
}
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
void CFlyingMonster::Killed( entvars_t *pevAttacker, int iGib )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
pev->movetype = MOVETYPE_STEP;
|
|
|
|
ClearBits( pev->flags, FL_ONGROUND );
|
|
|
|
pev->angles.z = 0;
|
|
|
|
pev->angles.x = 0;
|
|
|
|
CBaseMonster::Killed( pevAttacker, iGib );
|
|
|
|
}
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
void CFlyingMonster::HandleAnimEvent( MonsterEvent_t *pEvent )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
switch( pEvent->event )
|
|
|
|
{
|
|
|
|
case FLYING_AE_FLAP:
|
|
|
|
m_flightSpeed = 400;
|
|
|
|
break;
|
|
|
|
case FLYING_AE_FLAPSOUND:
|
2016-07-31 15:48:50 +02:00
|
|
|
if( m_pFlapSound )
|
2016-06-04 15:24:23 +02:00
|
|
|
EMIT_SOUND( edict(), CHAN_BODY, m_pFlapSound, 1, ATTN_NORM );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CBaseMonster::HandleAnimEvent( pEvent );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
void CFlyingMonster::Move( float flInterval )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2016-07-31 15:48:50 +02:00
|
|
|
if( pev->movetype == MOVETYPE_FLY )
|
2016-06-04 15:24:23 +02:00
|
|
|
m_flGroundSpeed = m_flightSpeed;
|
|
|
|
CBaseMonster::Move( flInterval );
|
|
|
|
}
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
BOOL CFlyingMonster::ShouldAdvanceRoute( float flWaypointDist )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
// Get true 3D distance to the goal so we actually reach the correct height
|
2016-07-31 15:48:50 +02:00
|
|
|
if( m_Route[m_iRouteIndex].iType & bits_MF_IS_GOAL )
|
|
|
|
flWaypointDist = ( m_Route[m_iRouteIndex].vecLocation - pev->origin ).Length();
|
2016-06-04 15:24:23 +02:00
|
|
|
|
2019-10-13 13:49:25 +02:00
|
|
|
if( flWaypointDist <= 64.0f + ( m_flGroundSpeed * gpGlobals->frametime ) )
|
2016-06-04 15:24:23 +02:00
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CFlyingMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval )
|
|
|
|
{
|
2016-07-31 15:48:50 +02:00
|
|
|
if( pev->movetype == MOVETYPE_FLY )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2019-10-13 13:49:25 +02:00
|
|
|
if( gpGlobals->time - m_stopTime > 1.0f )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2016-07-31 15:48:50 +02:00
|
|
|
if( m_IdealActivity != m_movementActivity )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
m_IdealActivity = m_movementActivity;
|
|
|
|
m_flGroundSpeed = m_flightSpeed = 200;
|
|
|
|
}
|
|
|
|
}
|
2016-07-31 15:48:50 +02:00
|
|
|
Vector vecMove = pev->origin + ( ( vecDir + ( m_vecTravel * m_momentum ) ).Normalize() * (m_flGroundSpeed * flInterval ) );
|
2016-06-04 15:24:23 +02:00
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
if( m_IdealActivity != m_movementActivity )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2019-10-13 13:49:25 +02:00
|
|
|
m_flightSpeed = UTIL_Approach( 100, m_flightSpeed, 75.0f * gpGlobals->frametime );
|
2016-07-31 15:48:50 +02:00
|
|
|
if( m_flightSpeed < 100 )
|
2016-06-04 15:24:23 +02:00
|
|
|
m_stopTime = gpGlobals->time;
|
|
|
|
}
|
|
|
|
else
|
2019-10-13 13:49:25 +02:00
|
|
|
m_flightSpeed = UTIL_Approach( 20, m_flightSpeed, 300.0f * gpGlobals->frametime );
|
2016-06-25 18:33:39 +02:00
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
if( CheckLocalMove( pev->origin, vecMove, pTargetEnt, NULL ) )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2016-07-31 15:48:50 +02:00
|
|
|
m_vecTravel = vecMove - pev->origin;
|
2016-06-04 15:24:23 +02:00
|
|
|
m_vecTravel = m_vecTravel.Normalize();
|
2016-07-31 15:48:50 +02:00
|
|
|
UTIL_MoveToOrigin( ENT( pev ), vecMove, ( m_flGroundSpeed * flInterval ), MOVE_STRAFE );
|
2016-06-04 15:24:23 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_IdealActivity = GetStoppedActivity();
|
|
|
|
m_stopTime = gpGlobals->time;
|
|
|
|
m_vecTravel = g_vecZero;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
CBaseMonster::MoveExecute( pTargetEnt, vecDir, flInterval );
|
|
|
|
}
|
|
|
|
|
|
|
|
float CFlyingMonster::CeilingZ( const Vector &position )
|
|
|
|
{
|
|
|
|
TraceResult tr;
|
|
|
|
|
|
|
|
Vector minUp = position;
|
|
|
|
Vector maxUp = position;
|
2019-10-13 13:49:25 +02:00
|
|
|
maxUp.z += 4096.0f;
|
2016-06-04 15:24:23 +02:00
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
UTIL_TraceLine( position, maxUp, ignore_monsters, NULL, &tr );
|
2019-10-13 13:49:25 +02:00
|
|
|
if( tr.flFraction != 1.0f )
|
2016-06-04 15:24:23 +02:00
|
|
|
maxUp.z = tr.vecEndPos.z;
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
if( ( pev->flags ) & FL_SWIM )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
return UTIL_WaterLevel( position, minUp.z, maxUp.z );
|
|
|
|
}
|
|
|
|
return maxUp.z;
|
|
|
|
}
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
BOOL CFlyingMonster::ProbeZ( const Vector &position, const Vector &probe, float *pFraction )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2016-07-31 15:48:50 +02:00
|
|
|
int conPosition = UTIL_PointContents( position );
|
|
|
|
if( ( ( ( pev->flags ) & FL_SWIM ) == FL_SWIM ) ^ ( conPosition == CONTENTS_WATER ) )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
// SWIMING & !WATER
|
|
|
|
// or FLYING & WATER
|
|
|
|
//
|
2019-10-13 13:49:25 +02:00
|
|
|
*pFraction = 0.0f;
|
2016-06-04 15:24:23 +02:00
|
|
|
return TRUE; // We hit a water boundary because we are where we don't belong.
|
|
|
|
}
|
2016-07-31 15:48:50 +02:00
|
|
|
int conProbe = UTIL_PointContents( probe );
|
|
|
|
if( conProbe == conPosition )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
// The probe is either entirely inside the water (for fish) or entirely
|
|
|
|
// outside the water (for birds).
|
|
|
|
//
|
2019-10-13 13:49:25 +02:00
|
|
|
*pFraction = 1.0f;
|
2016-06-04 15:24:23 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-07-31 15:48:50 +02:00
|
|
|
Vector ProbeUnit = ( probe - position ).Normalize();
|
|
|
|
float ProbeLength = ( probe - position ).Length();
|
2016-06-04 15:24:23 +02:00
|
|
|
float maxProbeLength = ProbeLength;
|
|
|
|
float minProbeLength = 0;
|
|
|
|
|
|
|
|
float diff = maxProbeLength - minProbeLength;
|
2019-10-13 13:49:25 +02:00
|
|
|
while( diff > 1.0f )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
2019-10-13 13:49:25 +02:00
|
|
|
float midProbeLength = minProbeLength + diff / 2.0f;
|
2016-06-04 15:24:23 +02:00
|
|
|
Vector midProbeVec = midProbeLength * ProbeUnit;
|
2016-07-31 15:48:50 +02:00
|
|
|
if( UTIL_PointContents( position + midProbeVec ) == conPosition )
|
2016-06-04 15:24:23 +02:00
|
|
|
{
|
|
|
|
minProbeLength = midProbeLength;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
maxProbeLength = midProbeLength;
|
|
|
|
}
|
|
|
|
diff = maxProbeLength - minProbeLength;
|
|
|
|
}
|
|
|
|
*pFraction = minProbeLength/ProbeLength;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
float CFlyingMonster::FloorZ( const Vector &position )
|
|
|
|
{
|
|
|
|
TraceResult tr;
|
|
|
|
|
|
|
|
Vector down = position;
|
2019-10-13 13:49:25 +02:00
|
|
|
down.z -= 2048.0f;
|
2016-06-04 15:24:23 +02:00
|
|
|
|
|
|
|
UTIL_TraceLine( position, down, ignore_monsters, NULL, &tr );
|
|
|
|
|
2019-10-13 13:49:25 +02:00
|
|
|
if( tr.flFraction != 1.0f )
|
2016-06-04 15:24:23 +02:00
|
|
|
return tr.vecEndPos.z;
|
|
|
|
|
|
|
|
return down.z;
|
|
|
|
}
|