📄 soccerobjects.cpp
字号:
m_fLastBounceTime = 0.0f;
m_bBounced = DFALSE;
VEC_INIT( m_vLastPos );
VEC_SET( m_vLastNormal, 0.0f, 1.0f, 0.0f );
m_hLastPlayer = DNULL;
// m_hLight = DNULL;
// m_hLightAttachment = DNULL;
m_bMadeGoal = DFALSE;
m_fRespawnTime = g_pServerDE->GetTime( ) + BALLRESPAWNTIME;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: SoccerBall::~SoccerBall
//
// PURPOSE: Destructor
//
// ----------------------------------------------------------------------- //
SoccerBall::~SoccerBall()
{
SoccerGoal *pGoal;
DList *pList;
DLink *pCur;
// The ball is being removed normally
if( m_bMadeGoal )
return;
// If the ball isn't being removed because of a goal, then something
// has happened and we need to spawn a new ball. Tell the first
// goal to do this.
pList = SoccerGoal::GetGoalList( );
if( !pList || pList->m_nElements == 0 )
return;
pCur = pList->m_Head.m_pNext;
pGoal = ( SoccerGoal * )pCur->m_pData;
if( pGoal )
pGoal->SpawnBall( );
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: SoccerBall::EngineMessageFn
//
// PURPOSE: Handler for engine messages
//
// ----------------------------------------------------------------------- //
DDWORD SoccerBall::EngineMessageFn( DDWORD messageID, void *pData, DFLOAT fData )
{
// Handle the engine messages we're interested in...
switch( messageID )
{
case MID_PRECREATE:
{
if (fData == PRECREATE_WORLDFILE || fData == PRECREATE_STRINGPROP)
{
ReadProp((ObjectCreateStruct*)pData);
}
PostPropRead((ObjectCreateStruct*)pData);
break;
}
case MID_INITIALUPDATE:
{
OnInitialUpdate(pData, fData);
break;
}
case MID_TOUCHNOTIFY:
{
OnTouchNotify(( HOBJECT )pData, fData );
break;
}
case MID_UPDATE:
{
Update( );
break;
}
case MID_LINKBROKEN:
{
if( m_hLastPlayer == ( HOBJECT )pData )
{
m_hLastPlayer = DNULL;
}
/* else if( m_hLight == ( HOBJECT )pData )
{
g_pServerDE->RemoveAttachment( m_hLightAttachment );
m_hLightAttachment = DNULL;
m_hLight = DNULL;
}
*/
break;
}
}
return B2BaseClass::EngineMessageFn(messageID, pData, fData);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: SoccerBall::ReadProp
//
// PURPOSE: Reads SoccerBall properties
//
// ----------------------------------------------------------------------- //
void SoccerBall::ReadProp(ObjectCreateStruct *pStruct)
{
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: FlagStand::PostPropRead()
//
// PURPOSE: Updates the properties now that they have been read
//
// ----------------------------------------------------------------------- //
void SoccerBall::PostPropRead(ObjectCreateStruct* pStruct)
{
const NetGame *pNetGame;
// Sanity checks...
if( !pStruct )
return;
pNetGame = g_pBloodServerShell->GetNetGameInfo();
if( !pNetGame || pNetGame->m_nSocBallSkin == SOCBALL_SKIN_ZOMBIE )
{
SAFE_STRCPY( pStruct->m_Filename, "models_ao\\worldobjects_ao\\headball.abc" );
SAFE_STRCPY( pStruct->m_SkinName, "skins_ao\\worldobjects_ao\\headball.dtx" );
}
else
{
SAFE_STRCPY( pStruct->m_Filename, "models_ao\\worldobjects_ao\\soccerball.abc" );
SAFE_STRCPY( pStruct->m_SkinName, "skins_ao\\worldobjects_ao\\soccerball.dtx" );
}
// Set the flags we want...
pStruct->m_Flags = FLAG_TOUCH_NOTIFY | FLAG_GRAVITY | FLAG_SOLID | FLAG_VISIBLE | FLAG_REMOVEIFOUTSIDE;
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: SoccerBall::OnInitialUpdate()
//
// PURPOSE: Handles the MID_INITIALUPDATE engine message
//
// ----------------------------------------------------------------------- //
void SoccerBall::OnInitialUpdate(void* pData, DFLOAT fData)
{
DVector vDims;
DDWORD dwFlags;
g_pServerDE->SetForceIgnoreLimit( m_hObject, 0.0f );
// g_pServerDE->SetFrictionCoefficient( m_hObject, 10.0f );
g_pServerDE->GetModelAnimUserDims( m_hObject, &vDims, 0 );
if( VEC_MAGSQR( vDims ) < 1.0f )
VEC_SET( vDims, 1.0f, 1.0f, 1.0f );
g_pServerDE->SetObjectDims( m_hObject, &vDims );
m_fRadius = ( vDims.x + vDims.y + vDims.z ) / 3.0f;
g_pServerDE->SetNextUpdate( m_hObject, 0.001f );
// CreateLight( );
// Mark this object as savable
dwFlags = g_pServerDE->GetObjectUserFlags( m_hObject );
dwFlags |= USERFLG_NIGHTGOGGLESGLOW;
g_pServerDE->SetObjectUserFlags( m_hObject, dwFlags );
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: SoccerBall::ObjectMessageFn
//
// PURPOSE: Handle messages from objects
//
// ----------------------------------------------------------------------- //
DDWORD SoccerBall::ObjectMessageFn(HOBJECT hSender, DDWORD messageID, HMESSAGEREAD hRead)
{
switch (messageID)
{
case MID_GOAL:
{
m_bMadeGoal = DTRUE;
g_pServerDE->RemoveObject( m_hObject );
}
break;
default: break;
}
return B2BaseClass::ObjectMessageFn(hSender, messageID, hRead);
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: SoccerBall::Update()
//
// PURPOSE: Updates the ball
//
// ----------------------------------------------------------------------- //
void SoccerBall::Update( )
{
DVector vVel, vAccel, vAccelAdd, vPos, vForward, vCross, vTemp, vTemp2;
CollisionInfo collInfo;
float fVelMag, fDistTraveled, fTime, fRotAmount, fExp;
DRotation rRot;
g_pServerDE->GetObjectPos( m_hObject, &vPos );
g_pServerDE->GetVelocity( m_hObject, &vVel );
fVelMag = VEC_MAG( vVel );
fTime = g_pServerDE->GetTime( );
// Remove the ball if it's been sitting around for a while.
if( fTime > m_fRespawnTime )
{
g_pServerDE->RemoveObject( m_hObject );
return;
}
// Update the on ground info
g_pServerDE->GetStandingOn( m_hObject, &collInfo );
m_bOnGround = ( collInfo.m_hObject ) ? DTRUE : DFALSE;
if( m_bOnGround )
{
m_fLastTimeOnGround = fTime;
}
// Get how far we've traveled.
VEC_SUB( vForward, vPos, m_vLastPos );
fDistTraveled = VEC_MAG( vForward );
VEC_COPY( m_vLastPos, vPos );
// Rotate the ball
if( fDistTraveled > 0.0f )
{
VEC_MULSCALAR( vForward, vForward, 1.0f / fDistTraveled );
if( m_bOnGround )
{
VEC_COPY( m_vLastNormal, collInfo.m_Plane.m_Normal );
VEC_CROSS( vCross, vForward, m_vLastNormal );
fRotAmount = VEC_MAG( vCross ) * fDistTraveled / m_fRadius;
}
else
{
VEC_CROSS( vCross, vForward, m_vLastNormal );
fRotAmount = VEC_MAG( vCross ) * fDistTraveled / m_fRadius;
}
if( fRotAmount > 0.0f )
{
VEC_NORM( vCross );
g_pServerDE->GetObjectRotation( m_hObject, &rRot );
g_pServerDE->RotateAroundAxis( &rRot, &vCross, fRotAmount );
g_pServerDE->SetObjectRotation( m_hObject, &rRot );
}
}
// Adjust the velocity and accel
if( fVelMag < MINBALLVEL )
{
VEC_INIT( vVel );
g_pServerDE->SetVelocity( m_hObject, &vVel );
}
else if( fVelMag > MAXBALLVEL )
{
VEC_MULSCALAR( vVel, vVel, MAXBALLVEL / fVelMag );
g_pServerDE->SetVelocity( m_hObject, &vVel );
}
else
{
// new velocity is given by: v = ( a / k ) + ( v_0 - a / k ) * exp( -k * t )
g_pServerDE->GetAcceleration( m_hObject, &vAccel );
fExp = ( float )exp( -BALLDRAG * g_pServerDE->GetFrameTime( ));
VEC_DIVSCALAR( vTemp, vAccel, BALLDRAG );
VEC_SUB( vTemp2, vVel, vTemp );
VEC_MULSCALAR( vTemp2, vTemp2, fExp );
VEC_ADD( vVel, vTemp2, vTemp );
g_pServerDE->SetVelocity( m_hObject, &vVel );
}
// Make sure we're rolling if we're on a slope. This counteracts the way the
// engine stops objects on slopes.
if( m_bOnGround )
{
if( collInfo.m_Plane.m_Normal.y < 0.9f && fabs( vVel.y ) < 50.0f )
{
g_pServerDE->GetGlobalForce( &vAccelAdd );
vAccel.y += vAccelAdd.y * 0.5f;
g_pServerDE->SetAcceleration( m_hObject, &vAccel );
}
}
// Play a bounce sound if enough time has elapsed
if( m_bBounced )
{
if( fTime > m_fLastBounceTime + TIMEBETWEENBOUNCESOUNDS )
{
// Play a bounce sound...
PlaySoundFromPos( &vPos, "Sounds_ao\\events\\soccerball.wav", 750, SOUNDPRIORITY_MISC_MEDIUM );
}
m_bBounced = DFALSE;
}
g_pServerDE->SetNextUpdate( m_hObject, 0.001f );
}
// ----------------------------------------------------------------------- //
//
// ROUTINE: SoccerBall::OnTouchNotify()
//
// PURPOSE: Handles the MID_TOUCHNOTIFY engine messsage
//
// ----------------------------------------------------------------------- //
void SoccerBall::OnTouchNotify( HOBJECT hObj, float fForce )
{
CollisionInfo colInfo;
DVector vVel, vOtherVel, vEffectiveVel, vPos, vNewVel;
DVector vNormal;
float fEffectiveVelMag, fMultiplier, fVelMag;
DRotation rRot;
DVector vUp, vRight;
DBOOL bIsPlayer;
g_pServerDE->GetVelocity( m_hObject, &vVel );
g_pServerDE->GetVelocity( hObj, &vOtherVel );
g_pServerDE->GetObjectPos( m_hObject, &vPos );
if( hObj == g_pServerDE->GetWorldObject( ))
{
VEC_SUB( vEffectiveVel, vOtherVel, vVel );
fEffectiveVelMag = VEC_MAG( vEffectiveVel );
g_pServerDE->GetLastCollision( &colInfo );
// Compute new velocity reflected off of the surface.
if( VEC_MAGSQR( colInfo.m_Plane.m_Normal ) > 0.0f )
{
VEC_COPY( vNormal, colInfo.m_Plane.m_Normal );
if( fEffectiveVelMag > MAXBALLVEL )
fMultiplier = MAXBOUNCEFACTOR;
else
fMultiplier = MINBOUNCEFACTOR + ( MAXBOUNCEFACTOR - MINBOUNCEFACTOR ) * fEffectiveVelMag / MAXBALLVEL;
VEC_MULSCALAR( vNormal, vNormal, fEffectiveVelMag * fMultiplier );
VEC_ADD( vNewVel, vVel, vNormal );
if( fabs( vNewVel.y + vVel.y ) < 100.0f )
vNewVel.y = vVel.y;
g_pServerDE->SetVelocity( m_hObject, &vNewVel );
}
if( fabs( fForce ) > MINFORCESOUND )
m_bBounced = DTRUE;
}
else
{
// Ignore non-solid objects
if( !( g_pServerDE->GetObjectFlags( hObj ) & FLAG_SOLID ))
return;
bIsPlayer = IsPlayer( hObj );
if( bIsPlayer )
{
if( m_hLastPlayer && hObj != m_hLastPlayer )
{
g_pServerDE->BreakInterObjectLink( m_hObject, m_hLastPlayer );
}
m_hLastPlayer = hObj;
g_pServerDE->CreateInterObjectLink( m_hObject, m_hLastPlayer );
m_fRespawnTime = g_pServerDE->GetTime( ) + BALLRESPAWNTIME;
}
VEC_ADD( vVel, vVel, vOtherVel );
if( m_bOnGround && vVel.y < 0.0f )
vVel.y = 0.0f;
if( bIsPlayer )
vVel.y += g_pServerDE->Random( 150.0f, 300.0f );
fVelMag = VEC_MAG( vVel );
g_pServerDE->AlignRotation( &rRot, &vVel, DNULL );
g_pServerDE->EulerRotateX( &rRot, g_pServerDE->Random( -0.1f, 0.1f ));
g_pServerDE->EulerRotateY( &rRot, g_pServerDE->Random( -0.1f, 0.1f ));
g_pServerDE->EulerRotateZ( &rRot, g_pServerDE->Random( -0.1f, 0.1f ));
g_pServerDE->GetRotationVectors( &rRot, &vUp, &vRight, &vVel );
VEC_MULSCALAR( vVel, vVel, fVelMag );
g_pServerDE->SetVelocity( m_hObject, &vVel );
if( fabs( fForce ) > MINFORCESOUND || bIsPlayer )
m_bBounced = DTRUE;
}
}
/*
// ----------------------------------------------------------------------- //
//
// ROUTINE: SoccerBall::CreateLight()
//
// PURPOSE: Put a light on the soccer ball to make it more visible
//
// ----------------------------------------------------------------------- //
void SoccerBall::CreateLight( )
{
DVector vOffset;
DRotation rRot;
ObjectCreateStruct ocStruct;
INIT_OBJECTCREATESTRUCT(ocStruct);
if( m_hLightAttachment )
{
g_pServerDE->RemoveAttachment( m_hLightAttachment );
m_hLightAttachment = DNULL;
}
if( m_hLight )
{
g_pServerDE->RemoveObject( m_hLight );
m_hLight = DNULL;
}
ocStruct.m_Flags = FLAG_VISIBLE;
ocStruct.m_ObjectType = OT_LIGHT;
HCLASS hClass = g_pServerDE->GetClass("BaseClass");
if (!hClass) return;
LPBASECLASS pLight = g_pServerDE->CreateObject(hClass, &ocStruct);
if (!pLight) return;
m_hLight = pLight->m_hObject;
g_pServerDE->SetLightRadius( m_hLight, BALLLIGHTRADIUS );
g_pServerDE->SetLightColor( m_hLight, 0.25f, 1.0f, 0.25f );
VEC_INIT( vOffset );
ROT_INIT( rRot );
g_pServerDE->CreateAttachment( m_hObject, m_hLight, DNULL, &vOffset, &rRot, &m_hLightAttachment );
g_pServerDE->CreateInterObjectLink( m_hObject, m_hLight );
}
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -