⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 soccerobjects.cpp

📁 Blood 2全套源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	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 + -