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

📄 soccerobjects.cpp

📁 Blood 2全套源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
;
;	 MODULE:		SOCCEROBJECTS (.CPP)
;
;	PURPOSE:		Soccer objects for zombie-head soccer
;
;	HISTORY:		1/26/99 [bp] This file was created
;
;	COMMENT:		Copyright (c) 1999, Monolith Productions Inc.
;
****************************************************************************/

#include "SoccerObjects.h"
#include "ObjectUtilities.h"
#include <mbstring.h>
#include "SoundTypes.h"
#include "ObjectUtilities.h"
#include "LMessage.h"
#include "ClientGibFx.h"
#include "ClientServerShared.h"
#include "Trigger.h"
#include "BloodServerShell.h"
#include "NetDefs.h"

#define TIMEBETWEENBOUNCESOUNDS		0.1f
#define MAXBOUNCEFACTOR				0.5f
#define MINBOUNCEFACTOR				0.2f
#define MAXBALLVEL					1000.0f
#define MINBALLVEL					20.0f
#define BALLDRAG					0.8f
#define MINFORCESOUND				100.0f
#define BALLRESPAWNTIME				60.0f

//////////////////// SOCCER GOAL ///////////////////////////

DList SoccerGoal::m_GoalList =
{
	0, 
	{ DNULL, DNULL, DNULL }
};

BEGIN_CLASS(SoccerGoal)
	ADD_LONGINTPROP( TeamID, 1 )
	ADD_BOOLPROP( Directional, DFALSE )
	ADD_ROTATIONPROP( GoalDirection )
	ADD_BOOLPROP( BoxPhysics, DTRUE )
	ADD_STRINGPROP( ScoreSound, "" )
	ADD_REALPROP( ScoreSoundRadius, 1000.0f )
	ADD_STRINGPROP( ScoreTarget, "" )
	ADD_STRINGPROP( ScoreMsg, "" )
END_CLASS_DEFAULT_FLAGS(SoccerGoal, B2BaseClass, NULL, NULL, CF_ALWAYSLOAD)


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::SoccerGoal
//
//	PURPOSE:	Constructor
//
// ----------------------------------------------------------------------- //

SoccerGoal::SoccerGoal() : B2BaseClass( OT_WORLDMODEL )
{
	m_nTeamID = TEAM_1;
	m_bDirectional = DFALSE;
	VEC_SET( m_vGoalDirection, 0.0f, 0.0f, 1.0f );
	m_hstrScoreSound = DNULL;
	m_fRadius = 1000.0f;
	m_hstrScoreTarget = DNULL;
	m_hstrScoreMsg = DNULL;
	m_bBoxPhysics = DTRUE;
	m_hSoccerBall = DNULL;
	m_nNumBallsToMake = 0;
	m_bWaitOneFrame = DFALSE;

	if( m_GoalList.m_nElements == 0 )
		dl_InitList( &m_GoalList );

	dl_AddTail( &m_GoalList, &m_Link, this );
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::~SoccerGoal
//
//	PURPOSE:	Destructor
//
// ----------------------------------------------------------------------- //

SoccerGoal::~SoccerGoal()
{
	dl_RemoveAt( &m_GoalList, &m_Link );

	if( m_hstrScoreSound )
		g_pServerDE->FreeString( m_hstrScoreSound );

	if( m_hstrScoreTarget )
		g_pServerDE->FreeString( m_hstrScoreTarget );

	if( m_hstrScoreMsg )
		g_pServerDE->FreeString( m_hstrScoreMsg );
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::EngineMessageFn
//
//	PURPOSE:	Handler for engine messages
//
// ----------------------------------------------------------------------- //

DDWORD SoccerGoal::EngineMessageFn( DDWORD messageID, void *pData, DFLOAT fData )
{
	DDWORD dwRet;

	// Handle the engine messages we're interested in...
	switch( messageID )
	{
		case MID_PRECREATE:
		{
			dwRet = B2BaseClass::EngineMessageFn( messageID, pData, fData );

			if (fData == PRECREATE_WORLDFILE || fData == PRECREATE_STRINGPROP)
			{
				ReadProp((ObjectCreateStruct*)pData);
			}

			PostPropRead((ObjectCreateStruct*)pData);

			return dwRet;
			break;
		}

		case MID_INITIALUPDATE:
		{
			OnInitialUpdate(pData, fData);
			break;
		}

		case MID_UPDATE:
		{
			Update( );
			break;
		}

		case MID_TOUCHNOTIFY:
		{
			OnTouchNotify((HOBJECT)pData);
			break;
		}
	}

	return B2BaseClass::EngineMessageFn(messageID, pData, fData);
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::ReadProp
//
//	PURPOSE:	Reads SoccerGoal properties
//
// ----------------------------------------------------------------------- //

void SoccerGoal::ReadProp(ObjectCreateStruct *pStruct)
{
	GenericProp genProp;
	DVector vUp, vRight;

	if( g_pServerDE->GetPropGeneric( "TeamID", &genProp ) == DE_OK )
	{
		m_nTeamID = ( int )genProp.m_Long;
	}

	if( g_pServerDE->GetPropGeneric( "Directional", &genProp ) == DE_OK )
	{
		m_bDirectional = genProp.m_Bool;
	}

	if( g_pServerDE->GetPropGeneric( "GoalDirection", &genProp ) == DE_OK )
	{
		g_pServerDE->GetRotationVectors( &genProp.m_Rotation, &vUp, &vRight, &m_vGoalDirection );
	}
	
	if( g_pServerDE->GetPropGeneric( "BoxPhysics", &genProp ) == DE_OK )
	{
		m_bBoxPhysics = genProp.m_Bool;
	}

	if( m_hstrScoreSound )
	{
		g_pServerDE->FreeString( m_hstrScoreSound );
		m_hstrScoreSound = DNULL;
	}
	if( g_pServerDE->GetPropGeneric( "ScoreSound", &genProp ) == DE_OK )
	{
		if( genProp.m_String[0] )
			m_hstrScoreSound = g_pServerDE->CreateString( genProp.m_String );
	}

	if( g_pServerDE->GetPropGeneric( "ScoreSoundRadius", &genProp ) == DE_OK )
	{
		m_fRadius = genProp.m_Float;
	}

	if( m_hstrScoreTarget )
	{
		g_pServerDE->FreeString( m_hstrScoreTarget );
		m_hstrScoreTarget = DNULL;
	}
	if( g_pServerDE->GetPropGeneric( "ScoreTarget", &genProp ) == DE_OK && genProp.m_String[0] )
	{
		if( genProp.m_String[0] )
			m_hstrScoreTarget = g_pServerDE->CreateString( genProp.m_String );
	}

	if( m_hstrScoreMsg )
	{
		g_pServerDE->FreeString( m_hstrScoreMsg );
		m_hstrScoreMsg = DNULL;
	}
	if( g_pServerDE->GetPropGeneric( "ScoreMsg", &genProp ) == DE_OK )
	{
		m_hstrScoreMsg = g_pServerDE->CreateString( genProp.m_String );
	}
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::PostPropRead()
//
//	PURPOSE:	Updates the properties now that they have been read
//
// ----------------------------------------------------------------------- //

void SoccerGoal::PostPropRead(ObjectCreateStruct* pStruct)
{
	// Sanity checks...
	if( !pStruct )
		return;

	_mbscpy(( unsigned char * )pStruct->m_Filename, ( const unsigned char * )pStruct->m_Name );

	// Set the flags we want...
	pStruct->m_Flags = FLAG_TOUCH_NOTIFY;
	if( m_bBoxPhysics )
		pStruct->m_Flags |= FLAG_BOXPHYSICS;
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::OnInitialUpdate()
//
//	PURPOSE:	Handles the MID_INITIALUPDATE engine message
//
// ----------------------------------------------------------------------- //

void SoccerGoal::OnInitialUpdate(void* pData, DFLOAT fData)
{
	m_hSoccerBall = g_pServerDE->GetClass( "SoccerBall" );

	g_pServerDE->SetNextUpdate( m_hObject, 0.0f );
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::ObjectMessageFn
//
//	PURPOSE:	Handle messages from objects
//
// ----------------------------------------------------------------------- //
/*
DDWORD SoccerGoal::ObjectMessageFn(HOBJECT hSender, DDWORD messageID, HMESSAGEREAD hRead)
{
	switch (messageID)
	{
		default: break;
	}

	return B2BaseClass::ObjectMessageFn(hSender, messageID, hRead);
}
*/

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::OnTouchNotify()
//
//	PURPOSE:	Handles the MID_TOUCHNOTIFY engine messsage
//
// ----------------------------------------------------------------------- //

void SoccerGoal::OnTouchNotify( HOBJECT hObj )
{
	CollisionInfo colInfo;
	DVector vBallVel;
	DBOOL bGoal;
	SoccerBall *pSoccerBall;
	DVector vPos, vDir, vDims;
	HOBJECT hPlayer;
	LMessage *pMsg;
	
	if( g_pServerDE->IsKindOf( g_pServerDE->GetObjectClass(hObj), m_hSoccerBall ))
	{
		pSoccerBall = ( SoccerBall * )g_pServerDE->HandleToObject( hObj );
		if( !pSoccerBall )
			return;

		// Already recorded this goal.  Ball should delete itself soon.
		if( pSoccerBall->IsMadeGoal( ))
			return;

		// Ball has to enter from correct side for directional goals
		if( m_bDirectional )
		{
			// Assume no goal
			bGoal = DFALSE;

			g_pServerDE->GetVelocity( hObj, &vBallVel );

			// Check if going in the right direction
			if( VEC_DOT( vBallVel, m_vGoalDirection ) > 0.0f )
			{
				bGoal = DTRUE;
			}
		}
		else
			bGoal = DTRUE;

		if( bGoal )
		{
			if(( hPlayer = pSoccerBall->GetLastPlayerTouched( )) == DNULL )
				return;
			// Send message to player and ball
			if( g_pServerDE->Common( )->CreateMessage( pMsg ) != LT_OK )
				return;
			pMsg->WriteByte( m_nTeamID );
			g_pServerDE->SendToObject( *pMsg, MID_GOAL, m_hObject, hPlayer, 0 );
			g_pServerDE->SendToObject( *pMsg, MID_GOAL, m_hObject, hObj, 0 );

			pMsg->Release();

			// Create special effects
			g_pServerDE->GetObjectPos( hObj, &vPos );
			g_pServerDE->GetVelocity( hObj, &vDir );
			VEC_MULSCALAR( vDir, vDir, -1.0f );
			VEC_SET( vDims, 25.0f, 25.0f, 25.0f );
			SetupClientGibFX( &vPos, &vDir, &vDims, ( SURFTYPE_FLESH/10 ) | SIZE_SMALL | TRAIL_BLOOD, 1.0f, 5 );

			// Play the sound
			if( m_hstrScoreSound )
			{
				g_pServerDE->GetObjectPos( m_hObject, &vPos );
				PlaySoundFromPos( &vPos, g_pServerDE->GetStringData( m_hstrScoreSound ), m_fRadius, SOUNDPRIORITY_MISC_MEDIUM );
			}

			SendTrigger( );
		}
	}
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::Update()
//
//	PURPOSE:	Updates the goal
//
// ----------------------------------------------------------------------- //

void SoccerGoal::Update( )
{
	DLink *pCur;
	int nGoalIndex;
	SoccerGoal *pGoal;

	// This is needed just in case the world is shutting down.  If it is
	// then we don't want to make a new ball.  If we wait one frame,
	// then the world will have completely gone away, and we won't make
	// a new ball.
	if( m_bWaitOneFrame )
	{
		m_bWaitOneFrame = DFALSE;
		g_pServerDE->SetNextUpdate( m_hObject, 0.001f );
		return;
	}

	while( m_nNumBallsToMake )
	{
		// Choose a random goal to send trigger
		if( !m_GoalList.m_nElements )
			return;
		nGoalIndex = ( int )( g_pServerDE->IntRandom( 0, m_GoalList.m_nElements - 1 ));
		pCur = m_GoalList.m_Head.m_pNext;
		while( pCur != &m_GoalList.m_Head && nGoalIndex > 0 )
		{
			pCur = pCur->m_pNext;
			nGoalIndex--;
		}
		pGoal = ( SoccerGoal * )pCur->m_pData;
		if( pGoal )
			pGoal->SendTrigger( );

		m_nNumBallsToMake--;
	}

	g_pServerDE->SetNextUpdate( m_hObject, 0.0f );
}


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::SendTrigger()
//
//	PURPOSE:	Sends trigger message
//
// ----------------------------------------------------------------------- //

void SoccerGoal::SendTrigger( )
{
	// Send the message
	if( m_hstrScoreTarget && m_hstrScoreMsg )
	{
		SendTriggerMsgToObjects( this, m_hstrScoreTarget, m_hstrScoreMsg );
	}
}

// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerGoal::SpawnBall()
//
//	PURPOSE:	Goal must spawn a new ball, cuz something bad happened
//				to the other ball
//
// ----------------------------------------------------------------------- //

void SoccerGoal::SpawnBall( )
{
	m_nNumBallsToMake++;
	g_pServerDE->SetNextUpdate( m_hObject, 0.001f );
	m_bWaitOneFrame = DTRUE;
}


//////////////////// SOCCER BALL ///////////////////////////

BEGIN_CLASS( SoccerBall )
END_CLASS_DEFAULT( SoccerBall, B2BaseClass, NULL, NULL )


// ----------------------------------------------------------------------- //
//
//	ROUTINE:	SoccerBall::SoccerBall
//
//	PURPOSE:	Constructor
//
// ----------------------------------------------------------------------- //

SoccerBall::SoccerBall() : B2BaseClass( OT_MODEL )
{
	m_bOnGround = DFALSE;
	m_fLastTimeOnGround = 0.0f;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -