📄 hl1_npc_osprey.cpp
字号:
}
Vector vecImpulse( 0, 0, 0 );
// add gravity
vecImpulse.z -= 38.4; // 32ft/sec
ApplyAbsVelocityImpulse( vecImpulse );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
BEGIN_DATADESC( CBaseHelicopter )
DEFINE_THINKFUNC( CBaseHelicopter, HelicopterThink ),
DEFINE_THINKFUNC( CBaseHelicopter, CallDyingThink ),
DEFINE_ENTITYFUNC( CBaseHelicopter, CrashTouch ),
DEFINE_ENTITYFUNC( CBaseHelicopter, FlyTouch ),
DEFINE_FIELD( CBaseHelicopter, m_flForce, FIELD_FLOAT ),
DEFINE_FIELD( CBaseHelicopter, m_fHelicopterFlags, FIELD_INTEGER),
DEFINE_FIELD( CBaseHelicopter, m_vecDesiredFaceDir, FIELD_VECTOR ),
DEFINE_FIELD( CBaseHelicopter, m_vecDesiredPosition,FIELD_POSITION_VECTOR ),
DEFINE_FIELD( CBaseHelicopter, m_vecGoalOrientation,FIELD_VECTOR ),
DEFINE_FIELD( CBaseHelicopter, m_flLastSeen, FIELD_TIME ),
DEFINE_FIELD( CBaseHelicopter, m_flPrevSeen, FIELD_TIME ),
// DEFINE_FIELD( CBaseHelicopter, m_iSoundState, FIELD_INTEGER ), // Don't save, precached
DEFINE_FIELD( CBaseHelicopter, m_vecTarget, FIELD_VECTOR ),
DEFINE_FIELD( CBaseHelicopter, m_vecTargetPosition, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( CBaseHelicopter, m_flMaxSpeed, FIELD_FLOAT ),
DEFINE_FIELD( CBaseHelicopter, m_flMaxSpeedFiring, FIELD_FLOAT ),
DEFINE_FIELD( CBaseHelicopter, m_flGoalSpeed, FIELD_FLOAT ),
DEFINE_KEYFIELD( CBaseHelicopter, m_flInitialSpeed, FIELD_FLOAT, "InitialSpeed" ),
// Inputs
DEFINE_INPUTFUNC( CBaseHelicopter, FIELD_STRING, "ChangePathCorner", InputChangePathCorner),
DEFINE_INPUTFUNC( CBaseHelicopter, FIELD_VOID, "Activate", InputActivate),
// Outputs
DEFINE_OUTPUT(CBaseHelicopter, m_AtTarget, "AtPathCorner" ),
DEFINE_OUTPUT(CBaseHelicopter, m_LeaveTarget, "LeavePathCorner" ),//<<TEMP>> Undone
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CBaseHelicopter, DT_BaseHelicopter )
END_SEND_TABLE()
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
// Notes : Have your derived Helicopter's Spawn() function call this one FIRST
//------------------------------------------------------------------------------
void CBaseHelicopter::Precache( void )
{
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
// Notes : Have your derived Helicopter's Spawn() function call this one FIRST
//------------------------------------------------------------------------------
void CBaseHelicopter::Spawn( void )
{
Precache( );
SetSolid( SOLID_BBOX );
SetMoveType( MOVETYPE_STEP );
AddFlag( FL_FLY );
m_lifeState = LIFE_ALIVE;
// This base class assumes the helicopter has no guns or missiles.
// Set the appropriate flags in your derived class' Spawn() function.
m_fHelicopterFlags &= ~BITS_HELICOPTER_MISSILE_ON;
m_fHelicopterFlags &= ~BITS_HELICOPTER_GUN_ON;
m_pRotorSound = NULL;
m_flCycle = 0;
ResetSequenceInfo();
AddFlag( FL_NPC );
m_flMaxSpeed = BASECHOPPER_MAX_SPEED;
m_flMaxSpeedFiring = BASECHOPPER_MAX_FIRING_SPEED;
m_takedamage = DAMAGE_AIM;
// Don't start up if the level designer has asked the
// helicopter to start disabled.
if ( !(m_spawnflags & SF_AWAITINPUT) )
{
Startup();
SetNextThink( gpGlobals->curtime + 1.0f );
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
bool CBaseHelicopter::FireGun( void )
{
return true;
}
//------------------------------------------------------------------------------
// Purpose : The main think function for the helicopters
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseHelicopter::HelicopterThink( void )
{
SetNextThink( gpGlobals->curtime + HELICOPTER_THINK_INTERVAL );
// Don't keep this around for more than one frame.
ClearCondition( COND_ENEMY_DEAD );
// Animate and dispatch animation events.
DispatchAnimEvents( this );
PrescheduleThink();
ShowDamage( );
// -----------------------------------------------
// If AI is disabled, kill any motion and return
// -----------------------------------------------
if (CAI_BaseNPC::m_nDebugBits & bits_debugDisableAI)
{
SetAbsVelocity( vec3_origin );
SetLocalAngularVelocity( vec3_angle );
SetNextThink( gpGlobals->curtime + HELICOPTER_THINK_INTERVAL );
return;
}
Hunt();
HelicopterPostThink();
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseHelicopter::Hunt( void )
{
FlyPathCorners( );
if( HasCondition( COND_ENEMY_DEAD ) )
{
SetEnemy( NULL );
}
// Look for my best enemy. If I change enemies,
// be sure and change my prevseen/lastseen timers.
if( m_lifeState == LIFE_ALIVE )
{
GetSenses()->Look( 4092 );
ChooseEnemy();
if( HasEnemy() )
{
CheckEnemy( GetEnemy() );
if (FVisible( GetEnemy() ))
{
if (m_flLastSeen < gpGlobals->curtime - 2)
{
m_flPrevSeen = gpGlobals->curtime;
}
m_flLastSeen = gpGlobals->curtime;
m_vecTargetPosition = GetEnemy()->WorldSpaceCenter();
}
}
else
{
// look at where we're going instead
m_vecTargetPosition = m_vecDesiredPosition;
}
}
else
{
// If we're dead or dying, forget our enemy and don't look for new ones(sjb)
SetEnemy( NULL );
}
if ( 1 )
{
Vector targetDir = m_vecTargetPosition - GetAbsOrigin();
Vector desiredDir = m_vecDesiredPosition - GetAbsOrigin();
VectorNormalize( targetDir );
VectorNormalize( desiredDir );
if ( !IsCrashing() && m_flLastSeen + 5 > gpGlobals->curtime ) //&& DotProduct( targetDir, desiredDir) > 0.25)
{
// If we've seen the target recently, face the target.
//Msg( "Facing Target \n" );
m_vecDesiredFaceDir = targetDir;
}
else
{
// Face our desired position.
// Msg( "Facing Position\n" );
m_vecDesiredFaceDir = desiredDir;
}
}
else
{
// Face the way the path corner tells us to.
//Msg( "Facing my path corner\n" );
m_vecDesiredFaceDir = m_vecGoalOrientation;
}
Flight();
UpdatePlayerDopplerShift( );
// ALERT( at_console, "%.0f %.0f %.0f\n", gpGlobals->curtime, m_flLastSeen, m_flPrevSeen );
if (m_fHelicopterFlags & BITS_HELICOPTER_GUN_ON)
{
//if ( (m_flLastSeen + 1 > gpGlobals->curtime) && (m_flPrevSeen + 2 < gpGlobals->curtime) )
{
if (FireGun( ))
{
// slow down if we're firing
if (m_flGoalSpeed > m_flMaxSpeedFiring )
{
m_flGoalSpeed = m_flMaxSpeedFiring;
}
}
}
}
if (m_fHelicopterFlags & BITS_HELICOPTER_MISSILE_ON)
{
AimRocketGun();
}
// Finally, forget dead enemies.
if( GetEnemy() != NULL && !GetEnemy()->IsAlive() )
{
SetEnemy( NULL );
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseHelicopter::FlyPathCorners( void )
{
if ( m_pGoalEnt == NULL && m_target != NULL_STRING )// this monster has a target
{
m_pGoalEnt = gEntList.FindEntityByName( NULL, m_target, NULL );
if (m_pGoalEnt)
{
m_vecDesiredPosition = m_pGoalEnt->GetLocalOrigin();
// FIXME: orienation removed from path_corners!
AngleVectors( m_pGoalEnt->GetLocalAngles(), &m_vecGoalOrientation );
}
}
// walk route
if (m_pGoalEnt)
{
// ALERT( at_console, "%.0f\n", flLength );
if ( HasReachedTarget( ) )
{
// If we get this close to the desired position, it's assumed that we've reached
// the desired position, so move on.
// Fire target that I've reached my goal
m_AtTarget.FireOutput( m_pGoalEnt, this );
OnReachedTarget( m_pGoalEnt );
m_pGoalEnt = gEntList.FindEntityByName( NULL, m_pGoalEnt->m_target, NULL );
if (m_pGoalEnt)
{
m_vecDesiredPosition = m_pGoalEnt->GetAbsOrigin();
// FIXME: orienation removed from path_corners!
AngleVectors( m_pGoalEnt->GetLocalAngles(), &m_vecGoalOrientation );
// NDebugOverlay::Box( m_vecDesiredPosition, Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 0,255,0, false, 30.0);
}
}
}
else
{
// If we can't find a new target, just stay where we are.
m_vecDesiredPosition = GetAbsOrigin();
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseHelicopter::UpdatePlayerDopplerShift( )
{
// -----------------------------
// make rotor, engine sounds
// -----------------------------
if (m_iSoundState == 0)
{
// Sound startup.
InitializeRotorSound();
}
else
{
CBaseEntity *pPlayer = NULL;
// UNDONE: this needs to send different sounds to every player for multiplayer.
// FIXME: this isn't the correct way to find a player!!!
pPlayer = gEntList.FindEntityByName( NULL, "!player", this );
if (pPlayer)
{
Vector dir = pPlayer->GetLocalOrigin() - GetLocalOrigin();
VectorNormalize(dir);
float velReceiver = -DotProduct( pPlayer->GetAbsVelocity(), dir );
float velTransmitter = -DotProduct( GetAbsVelocity(), dir );
// speed of sound == 13049in/s
int iPitch = 100 * ((1 - velReceiver / 13049) / (1 + velTransmitter / 13049));
// clamp pitch shifts
if (iPitch > 250)
iPitch = 250;
if (iPitch < 50)
iPitch = 50;
// Msg( "Pitch:%d\n", iPitch );
UpdateRotorSoundPitch( iPitch );
//Msg( "%.0f\n", pitch );
//Msg( "%.0f\n", flVol );
}
else
{
Msg( "Chopper didn't find a player!\n" );
}
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void CBaseHelicopter::Flight( void )
{
if( GetFlags() & FL_ONGROUND )
{
//This would be really bad.
RemoveFlag( FL_ONGROUND );
}
// Generic speed up
if (m_flGoalSpeed < m_flMaxSpeed)
{
m_flGoalSpeed += GetAcceleration();
}
// NDebugOverlay::Line(GetAbsOrigin(), m_vecDesiredPosition, 0,0,255, true, 0.1);
// estimate where I'll be facing in one seconds
Vector forward, right, up;
AngleVectors( GetLocalAngles() + GetLocalAngularVelocity() * 2, &forward, &right, &up );
QAngle angVel = GetLocalAngularVelocity();
float flSide = DotProduct( m_vecDesiredFaceDir, right );
if (flSide < 0)
{
if ( angVel.y < 8 )
{
angVel.y += 2;
}
else if (angVel.y < 60)
{
angVel.y += 8;
}
}
else
{
if ( angVel.y > -8 )
{
angVel.y -= 2;
}
else if (angVel.y > -60)
{
angVel.y -= 8;
}
}
angVel.y *= ( 0.98 ); // why?! (sjb)
// estimate where I'll be in two seconds
AngleVectors( GetLocalAngles() + angVel, NULL, NULL, &up );
Vector vecEst = GetAbsOrigin() + GetAbsVelocity() * 2.0 + up * m_flForce * 20 - Vector( 0, 0, 384 * 2 );
// add immediate force
AngleVectors( GetLocalAngles(), &forward, &right, &up );
Vector vecImpulse( 0, 0, 0 );
vecImpulse.x += up.x * m_flForce;
vecImpulse.y += up.y * m_flForce;
vecImpulse.z += up.z * m_flForce;
// add gravity
vecImpulse.z -= 38.4; // 32ft/sec
ApplyAbsVelocityImpulse( vecImpulse );
float flSpeed = GetAbsVelocity().Length();
float flDir = DotProduct( Vector( forward.x, forward.y, 0 ), Vector( GetAbsVelocity().x, GetAbsVelocity().y, 0 ) );
if (flDir < 0)
{
flSpeed = -flSpeed;
}
float flDist = DotProduct( m_vecDesiredPosition - vecEst, forward );
// float flDist = (m_vecDesiredPosition - vecEst).Length();
// float flSlip = DotProduct( GetAbsVelocity(), right );
float flSlip = -DotProduct( m_vecDesiredPosition - vecEst, right );
// fly sideways
if (flSlip > 0)
{
if (GetLocalAngles().z > -30 && angVel.z > -15)
angVel.z -= 4;
else
angVel.z += 2;
}
else
{
if (GetLocalAngles().z < 30 && angVel.z < 15)
angVel.z += 4;
else
angVel.z -= 2;
}
// These functions contain code Ken wrote that used to be right here as part of the flight model,
// but we want different helicopter vehicles to have different drag characteristics, so I made
// them virtual functions (sjb)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -