You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
311 lines
8.8 KiB
311 lines
8.8 KiB
/*** |
|
* |
|
* 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. |
|
* |
|
****/ |
|
/* |
|
|
|
===== monsters.cpp ======================================================== |
|
|
|
Monster-related utility code |
|
|
|
*/ |
|
|
|
#include "extdll.h" |
|
#include "util.h" |
|
#include "cbase.h" |
|
#include "animation.h" |
|
#include "saverestore.h" |
|
|
|
TYPEDESCRIPTION CBaseAnimating::m_SaveData[] = |
|
{ |
|
DEFINE_FIELD( CBaseAnimating, m_flFrameRate, FIELD_FLOAT ), |
|
DEFINE_FIELD( CBaseAnimating, m_flGroundSpeed, FIELD_FLOAT ), |
|
DEFINE_FIELD( CBaseAnimating, m_flLastEventCheck, FIELD_TIME ), |
|
DEFINE_FIELD( CBaseAnimating, m_fSequenceFinished, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( CBaseAnimating, m_fSequenceLoops, FIELD_BOOLEAN ), |
|
}; |
|
|
|
IMPLEMENT_SAVERESTORE( CBaseAnimating, CBaseDelay ) |
|
|
|
//========================================================= |
|
// StudioFrameAdvance - advance the animation frame up to the current time |
|
// if an flInterval is passed in, only advance animation that number of seconds |
|
//========================================================= |
|
float CBaseAnimating::StudioFrameAdvance( float flInterval ) |
|
{ |
|
if( flInterval == 0.0f ) |
|
{ |
|
flInterval = gpGlobals->time - pev->animtime; |
|
if( flInterval <= 0.001f ) |
|
{ |
|
pev->animtime = gpGlobals->time; |
|
return 0.0f; |
|
} |
|
} |
|
if( !pev->animtime ) |
|
flInterval = 0.0f; |
|
|
|
pev->frame += flInterval * m_flFrameRate * pev->framerate; |
|
pev->animtime = gpGlobals->time; |
|
|
|
if( pev->frame < 0.0f || pev->frame >= 256.0f ) |
|
{ |
|
if( m_fSequenceLoops ) |
|
pev->frame -= (int)( pev->frame / 256.0f ) * 256.0f; |
|
else |
|
pev->frame = ( pev->frame < 0.0f ) ? 0.0f : 255.0f; |
|
m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents |
|
} |
|
|
|
return flInterval; |
|
} |
|
|
|
//========================================================= |
|
// LookupActivity |
|
//========================================================= |
|
int CBaseAnimating::LookupActivity( int activity ) |
|
{ |
|
ASSERT( activity != 0 ); |
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
return ::LookupActivity( pmodel, pev, activity ); |
|
} |
|
|
|
//========================================================= |
|
// LookupActivityHeaviest |
|
// |
|
// Get activity with highest 'weight' |
|
// |
|
//========================================================= |
|
int CBaseAnimating::LookupActivityHeaviest( int activity ) |
|
{ |
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
return ::LookupActivityHeaviest( pmodel, pev, activity ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
int CBaseAnimating::LookupSequence( const char *label ) |
|
{ |
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
return ::LookupSequence( pmodel, label ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CBaseAnimating::ResetSequenceInfo() |
|
{ |
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
GetSequenceInfo( pmodel, pev, &m_flFrameRate, &m_flGroundSpeed ); |
|
m_fSequenceLoops = ( ( GetSequenceFlags() & STUDIO_LOOPING ) != 0 ); |
|
pev->animtime = gpGlobals->time; |
|
pev->framerate = 1.0; |
|
m_fSequenceFinished = FALSE; |
|
m_flLastEventCheck = gpGlobals->time; |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
BOOL CBaseAnimating::GetSequenceFlags() |
|
{ |
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
return ::GetSequenceFlags( pmodel, pev ); |
|
} |
|
|
|
//========================================================= |
|
// DispatchAnimEvents |
|
//========================================================= |
|
void CBaseAnimating::DispatchAnimEvents( float flInterval ) |
|
{ |
|
MonsterEvent_t event; |
|
|
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
if( !pmodel ) |
|
{ |
|
ALERT( at_aiconsole, "Gibbed monster is thinking!\n" ); |
|
return; |
|
} |
|
|
|
// FIXME: I have to do this or some events get missed, and this is probably causing the problem below |
|
flInterval = 0.1f; |
|
|
|
// FIX: this still sometimes hits events twice |
|
float flStart = pev->frame + ( m_flLastEventCheck - pev->animtime ) * m_flFrameRate * pev->framerate; |
|
float flEnd = pev->frame + flInterval * m_flFrameRate * pev->framerate; |
|
m_flLastEventCheck = pev->animtime + flInterval; |
|
|
|
m_fSequenceFinished = FALSE; |
|
if( flEnd >= 256.0f || flEnd <= 0.0f ) |
|
m_fSequenceFinished = TRUE; |
|
|
|
int index = 0; |
|
|
|
while( ( index = GetAnimationEvent( pmodel, pev, &event, flStart, flEnd, index ) ) != 0 ) |
|
{ |
|
HandleAnimEvent( &event ); |
|
} |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
float CBaseAnimating::SetBoneController( int iController, float flValue ) |
|
{ |
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
return SetController( pmodel, pev, iController, flValue ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CBaseAnimating::InitBoneControllers( void ) |
|
{ |
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
SetController( pmodel, pev, 0, 0.0 ); |
|
SetController( pmodel, pev, 1, 0.0 ); |
|
SetController( pmodel, pev, 2, 0.0 ); |
|
SetController( pmodel, pev, 3, 0.0 ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
float CBaseAnimating::SetBlending( int iBlender, float flValue ) |
|
{ |
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
return ::SetBlending( pmodel, pev, iBlender, flValue ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CBaseAnimating::GetBonePosition( int iBone, Vector &origin, Vector &angles ) |
|
{ |
|
GET_BONE_POSITION( ENT( pev ), iBone, origin, angles ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CBaseAnimating::GetAttachment( int iAttachment, Vector &origin, Vector &angles ) |
|
{ |
|
GET_ATTACHMENT( ENT( pev ), iAttachment, origin, angles ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
int CBaseAnimating::FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) |
|
{ |
|
void *pmodel = GET_MODEL_PTR( ENT( pev ) ); |
|
|
|
if( piDir == NULL ) |
|
{ |
|
int iDir; |
|
int sequence = ::FindTransition( pmodel, iEndingSequence, iGoalSequence, &iDir ); |
|
if( iDir != 1 ) |
|
return -1; |
|
else |
|
return sequence; |
|
} |
|
|
|
return ::FindTransition( pmodel, iEndingSequence, iGoalSequence, piDir ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
void CBaseAnimating::GetAutomovement( Vector &origin, Vector &angles, float flInterval ) |
|
{ |
|
|
|
} |
|
|
|
void CBaseAnimating::SetBodygroup( int iGroup, int iValue ) |
|
{ |
|
::SetBodygroup( GET_MODEL_PTR( ENT( pev ) ), pev, iGroup, iValue ); |
|
} |
|
|
|
int CBaseAnimating::GetBodygroup( int iGroup ) |
|
{ |
|
return ::GetBodygroup( GET_MODEL_PTR( ENT( pev ) ), pev, iGroup ); |
|
} |
|
|
|
int CBaseAnimating::ExtractBbox( int sequence, float *mins, float *maxs ) |
|
{ |
|
return ::ExtractBbox( GET_MODEL_PTR( ENT( pev ) ), sequence, mins, maxs ); |
|
} |
|
|
|
//========================================================= |
|
//========================================================= |
|
|
|
void CBaseAnimating::SetSequenceBox( void ) |
|
{ |
|
Vector mins, maxs; |
|
|
|
// Get sequence bbox |
|
if( ExtractBbox( pev->sequence, mins, maxs ) ) |
|
{ |
|
// expand box for rotation |
|
// find min / max for rotations |
|
float yaw = pev->angles.y * ( M_PI_F / 180.0f ); |
|
|
|
Vector xvector, yvector; |
|
xvector.x = cos( yaw ); |
|
xvector.y = sin( yaw ); |
|
yvector.x = -sin( yaw ); |
|
yvector.y = cos( yaw ); |
|
Vector bounds[2]; |
|
|
|
bounds[0] = mins; |
|
bounds[1] = maxs; |
|
|
|
Vector rmin( 9999.0f, 9999.0f, 9999.0f ); |
|
Vector rmax( -9999.0f, -9999.0f, -9999.0f ); |
|
Vector base, transformed; |
|
|
|
for( int i = 0; i <= 1; i++ ) |
|
{ |
|
base.x = bounds[i].x; |
|
for( int j = 0; j <= 1; j++ ) |
|
{ |
|
base.y = bounds[j].y; |
|
for( int k = 0; k <= 1; k++ ) |
|
{ |
|
base.z = bounds[k].z; |
|
|
|
// transform the point |
|
transformed.x = xvector.x * base.x + yvector.x * base.y; |
|
transformed.y = xvector.y * base.x + yvector.y * base.y; |
|
transformed.z = base.z; |
|
|
|
if( transformed.x < rmin.x ) |
|
rmin.x = transformed.x; |
|
if( transformed.x > rmax.x ) |
|
rmax.x = transformed.x; |
|
if( transformed.y < rmin.y ) |
|
rmin.y = transformed.y; |
|
if( transformed.y > rmax.y ) |
|
rmax.y = transformed.y; |
|
if( transformed.z < rmin.z ) |
|
rmin.z = transformed.z; |
|
if( transformed.z > rmax.z ) |
|
rmax.z = transformed.z; |
|
} |
|
} |
|
} |
|
rmin.z = 0.0f; |
|
rmax.z = rmin.z + 1.0f; |
|
UTIL_SetSize( pev, rmin, rmax ); |
|
} |
|
}
|
|
|