thug/Code/Sk/Objects/TrickObject.cpp
2016-02-14 08:39:12 +11:00

1579 lines
49 KiB
C++

/*****************************************************************************
** **
** Neversoft Entertainment **
** **
** Copyright (C) 1999 - All Rights Reserved **
** **
******************************************************************************
** **
** Project: PS2 **
** **
** Module: TrickObject (OBJ) **
** **
** File name: TrickObject.cpp **
** **
** Created by: 03/05/01 - gj **
** **
** Description: trick object code **
** **
*****************************************************************************/
/*****************************************************************************
** Includes **
*****************************************************************************/
#include <sk/objects/trickobject.h>
#include <gel/net/server/netserv.h>
#include <gel/scripting/array.h>
#include <gel/scripting/checksum.h>
#include <gel/scripting/script.h>
#include <gel/scripting/symboltable.h>
#include <gel/scripting/utils.h>
#include <gfx/gfxutils.h>
#include <gfx/nx.h>
#include <gfx/nxsector.h>
#include <sk/gamenet/gamenet.h>
#include <sk/modules/skate/goalmanager.h>
#include <sk/modules/skate/skate.h>
#include <sk/objects/skater.h> // just needed in mygetassociatednetworkconnection
#include <sys/config/config.h>
#include <sk/components/RailEditorComponent.h>
#ifdef __NOPT_ASSERT__
//#include <sk/ParkEditor/ParkEd.h>
#endif
/*****************************************************************************
** Externals **
*****************************************************************************/
/*****************************************************************************
** Defines **
*****************************************************************************/
DefinePoolableClass(Lst::HashItem<Obj::CTrickCluster>);
enum
{
vMAX_TRICKS_TO_FREE = 128
};
/*****************************************************************************
** DBG Defines **
*****************************************************************************/
namespace Obj
{
/*****************************************************************************
** Private Types **
*****************************************************************************/
/*****************************************************************************
** Private Data **
*****************************************************************************/
/*****************************************************************************
** Public Data **
*****************************************************************************/
/*****************************************************************************
** Private Prototypes **
*****************************************************************************/
/*****************************************************************************
** Private Functions **
*****************************************************************************/
/*****************************************************************************
** Public Functions **
*****************************************************************************/
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickObject::CTrickObject( void ) : Lst::Node< CTrickObject >(this)
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickObject::CTrickObject( uint32 name_checksum ) : Lst::Node< CTrickObject >(this)
{
m_NameChecksum = name_checksum;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObject::InitializeTrickObjectColor( int seqIndex )
{
// Garrett: shouldn't need to do anything except clear color here
// checks for the wibbling data, and creates
// it if it doesn't already exist
// TODO: Should also screen out if it doesn't have any geometry
Nx::CSector *p_sector = Nx::CEngine::sGetSector(m_NameChecksum);
Dbg_MsgAssert(p_sector,("sGetSector(0x%x) returned NULL (%s)",m_NameChecksum,Script::FindChecksumName(m_NameChecksum)));
p_sector->ClearColor();
if (!Config::CD())
{
if ( Script::GetInt( "show_all_trick_objects", false ) )
{
// quick way to see all the trick objects in the scene
ModulateTrickObjectColor( 2 );
}
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObject::ModulateTrickObjectColor( int seqIndex )
{
Nx::CSector *p_sector = Nx::CEngine::sGetSector(m_NameChecksum);
Dbg_MsgAssert(p_sector,("sGetSector(0x%x) returned NULL (%s)",m_NameChecksum,Script::FindChecksumName(m_NameChecksum)));
Script::CArray* p_graffiti_col_tab = Script::GetArray( "graffitiColors" );
Dbg_MsgAssert( (uint) seqIndex < p_graffiti_col_tab->GetSize(), ( "graffitiColors array too small" ) );
Script::CArray *p_entry = p_graffiti_col_tab->GetArray(seqIndex);
#ifdef __NOPT_ASSERT__
int size = p_entry->GetSize();
Dbg_MsgAssert(size >= 3 && size <= 4, ("wrong size %d for color array", size));
#endif
Image::RGBA color;
color.r = p_entry->GetInteger( 0 );
color.g = p_entry->GetInteger( 1 );
color.b = p_entry->GetInteger( 2 );
color.a = 128;
p_sector->SetColor(color);
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObject::ClearTrickObjectColor( int seqIndex )
{
Nx::CSector *p_sector = Nx::CEngine::sGetSector(m_NameChecksum);
Dbg_MsgAssert(p_sector,("sGetSector(0x%x) returned NULL (%s)",m_NameChecksum,Script::FindChecksumName(m_NameChecksum)));
Script::CArray* p_graffiti_col_tab = Script::GetArray( "graffitiColors" );
Dbg_MsgAssert( (uint) seqIndex < p_graffiti_col_tab->GetSize(), ( "graffitiColors array too small" ) );
Script::CArray *p_entry = p_graffiti_col_tab->GetArray(seqIndex);
#ifdef __NOPT_ASSERT__
int size = p_entry->GetSize();
Dbg_MsgAssert(size >= 3 && size <= 4, ("wrong size %d for color array", size));
#endif
Image::RGBA color;
color.r = p_entry->GetInteger( 0 );
color.g = p_entry->GetInteger( 1 );
color.b = p_entry->GetInteger( 2 );
color.a = 128;
Image::RGBA orig_color = p_sector->GetColor();
if ((orig_color.r == color.r) &&
(orig_color.g == color.g) &&
(orig_color.b == color.b))
{
p_sector->ClearColor();
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickCluster::CTrickCluster( void ) : Lst::Node< CTrickCluster >(this)
{
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickCluster::CTrickCluster( uint32 name_checksum ) : Lst::Node< CTrickCluster >(this)
{
m_NameChecksum = name_checksum;
Reset();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickCluster::~CTrickCluster( void )
{
uint32 count = m_TrickObjectList.CountItems();
// first iterate through all the items,
// and destroy the associated objects
for ( uint32 i = 0; i < count; i++ )
{
Lst::Node< CTrickObject >* pNode = m_TrickObjectList.GetItem( 0 );
Dbg_Assert( pNode );
CTrickObject* pObject = pNode->GetData();
Dbg_Assert( pObject );
delete pObject;
}
// now remove all the nodes from the list
m_TrickObjectList.RemoveAllNodes();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CTrickCluster::GetScore( uint32 skater_id )
{
return ( m_IsOwned && (skater_id == m_OwnerId) );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickCluster::Reset( void )
{
m_Score = 0;
m_OwnerId = 0;
m_IsOwned = false; // no owner
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickCluster::ModulateTrickObjectColor( int seqIndex )
{
uint32 count = m_TrickObjectList.CountItems();
for ( uint32 i = 0; i < count; i++ )
{
Lst::Node< CTrickObject >* pNode = m_TrickObjectList.GetItem( i );
Dbg_Assert( pNode );
CTrickObject* pObject = pNode->GetData();
Dbg_Assert( pObject );
pObject->ModulateTrickObjectColor( seqIndex );
}
// If playing a created park, update any created rails for this cluster.
Mdl::Skate * p_skate_mod = Mdl::Skate::Instance();
if (p_skate_mod->m_cur_level == CRCD(0xb664035d,"load_sk5ed_gameplay"))
{
Obj::GetRailEditor()->ModulateRailColor(m_NameChecksum, seqIndex);
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickObject* CTrickCluster::find_trick_object( uint32 name_checksum )
{
uint32 count = m_TrickObjectList.CountItems();
// find the appropriate trick object
for ( uint32 i = 0; i < count; i++ )
{
Lst::Node< CTrickObject >* pNode = m_TrickObjectList.GetItem( i );
Dbg_Assert( pNode );
CTrickObject* pObject = pNode->GetData();
Dbg_Assert( pObject );
if ( pObject->m_NameChecksum == name_checksum )
{
return pObject;
}
}
return NULL;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickCluster::AddTrickObject( uint32 name_checksum )
{
Dbg_MsgAssert( !find_trick_object( name_checksum ),( "Trick object %s is already in list", Script::FindChecksumName(name_checksum) ));
CTrickObject* pObject = new CTrickObject( name_checksum );
if ( !pObject )
{
return false;
}
if ( pObject->InitializeTrickObjectColor( name_checksum ) )
{
// printf( "Adding %s to trick object list\n", Script::FindChecksumName( name_checksum ) );
m_TrickObjectList.AddToTail( pObject );
return true;
}
else
{
// if not valid
delete pObject;
return false;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickObjectManager::CTrickObjectManager( void ) : m_TrickClusterList(8), m_TrickAliasList(8)
{
// m_TrickAliasCount = 0;
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().ScriptHeap());
mp_ObserverState = new Script::CScriptStructure;
Mem::Manager::sHandle().PopContext();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickObjectManager::~CTrickObjectManager( void )
{
this->DeleteAllTrickObjects();
}
struct STrickObjectFreeInfo
{
uint32 skater_id; // which objects to free
uint32 num_tricks; // num tricks to free
uint32 trick_buffer[vMAX_TRICKS_TO_FREE];
};
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickCluster::FreeCluster( uint32 skater_id )
{
if ( this->m_IsOwned && ( this->m_OwnerId == skater_id ) )
{
this->m_IsOwned = false;
this->m_Score = 0;
return true;
}
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickCluster::ClearCluster( int seqIndex )
{
uint32 count = m_TrickObjectList.CountItems();
// find the appropriate trick object
for ( uint32 i = 0; i < count; i++ )
{
Lst::Node< CTrickObject >* pNode = m_TrickObjectList.GetItem( i );
Dbg_Assert( pNode );
CTrickObject* p_object = pNode->GetData();
Dbg_Assert( p_object );
if (!p_object->ClearTrickObjectColor(seqIndex))
{
return false;
}
}
// If playing a created park, clear any created rail colors for this cluster.
Mdl::Skate * p_skate_mod = Mdl::Skate::Instance();
if (p_skate_mod->m_cur_level == CRCD(0xb664035d,"load_sk5ed_gameplay"))
{
Obj::GetRailEditor()->ClearRailColor(m_NameChecksum);
}
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void free_trick_cluster(CTrickCluster* pCluster, void* pData)
{
Dbg_AssertPtr(pCluster);
Dbg_AssertPtr(pData);
STrickObjectFreeInfo* pFreeInfo = (STrickObjectFreeInfo*)pData;
if ( pCluster->FreeCluster( pFreeInfo->skater_id ) )
{
Dbg_MsgAssert( pFreeInfo->num_tricks < vMAX_TRICKS_TO_FREE, ( "Too many trick objects to free" ) );
pFreeInfo->trick_buffer[pFreeInfo->num_tricks] = pCluster->GetNameChecksum();
pFreeInfo->num_tricks++;
#ifdef __USER_GARY__
Dbg_Message( "Freeing up %s\n", Script::FindChecksumName(pCluster->GetNameChecksum()) );
#endif
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObjectManager::FreeTrickObjects( uint32 skater_id )
{
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
// clear the observer state when you exit the game
printf( "Clearing observer state\n" );
mp_ObserverState->Clear();
if( gamenet_man->OnServer())
{
STrickObjectFreeInfo theFreeInfo;
theFreeInfo.skater_id = skater_id;
theFreeInfo.num_tricks = 0;
m_TrickClusterList.HandleCallback(free_trick_cluster, (void*)&theFreeInfo);
if ( theFreeInfo.num_tricks <= 0 )
{
// no tricks to free
return false;
}
// send score updates, as something has changed
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
skate_mod->SendScoreUpdates( false );
}
clear_trick_clusters(skater_id + 1);
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 CTrickObjectManager::TrickObjectExists( uint32 name_checksum ){
// gets cluster checksum
CTrickCluster* pCluster = get_aliased_cluster( name_checksum );
if ( pCluster )
{
return pCluster->m_NameChecksum;
}
else
{
return 0;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 CTrickObjectManager::RequestLogTrick( uint32 num_pending_tricks, uint32* p_pending_tricks, char* p_inform_prev_owner, int skater_id, uint32 score )
{
printf("RequestLogTrick called\n");
// GJ: Note that this function only logs the trick; a message
// will be sent out to the clients to actually modify the color
uint32 i;
Dbg_Assert( p_pending_tricks );
Dbg_Assert( p_inform_prev_owner );
Dbg_Assert( num_pending_tricks < 128 );
static char s_change_mask[128];
for ( i = 0; i < num_pending_tricks; i++ )
{
s_change_mask[i] = 0;
}
for ( i = 0; i < num_pending_tricks; i++ )
{
CTrickCluster* pCluster = get_aliased_cluster( p_pending_tricks[i] );
// change only objects marked as trick objects
if ( !pCluster )
continue;
// tell the goal manager
Game::CGoalManager* pGoalManager = Game::GetGoalManager();
Dbg_Assert( pGoalManager );
pGoalManager->GotTrickObject( pCluster->GetNameChecksum(), score );
// if the score beats the score
if ( score > pCluster->m_Score )
{
bool owner_changed = ( pCluster->m_OwnerId != (uint32)skater_id );
if ( !pCluster->m_IsOwned || owner_changed )
{
// that the trick object has changed states
s_change_mask[i] = 1;
}
if ( pCluster->m_IsOwned && owner_changed )
{
// for tracking steal messages
Dbg_Assert( pCluster->m_OwnerId >= 0 && pCluster->m_OwnerId < GameNet::vMAX_PLAYERS );
p_inform_prev_owner[pCluster->m_OwnerId] = 1;
}
pCluster->m_OwnerId = skater_id;
pCluster->m_Score = score;
pCluster->m_IsOwned = true;
/* Game::CGoalManager* p_GoalManager = Game::GetGoalManager();
if ( p_GoalManager->IsInGraffitiGoal() )
{
p_GoalManager->GotGraffitiCluster( pCluster->GetNameChecksum() );
// printf("tricked in %s\n", Script::FindChecksumName( pCluster->GetNameChecksum() ) );
}
*/
}
}
uint32 num_changed = 0;
// shift them so that the changed ones are at the beginning
for ( i = 0; i < num_pending_tricks; i++ )
{
if ( s_change_mask[i] )
{
p_pending_tricks[num_changed] = p_pending_tricks[i];
num_changed++;
}
}
return num_changed;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickCluster* CTrickObjectManager::GetTrickCluster( uint32 name_checksum )
{
return find_trick_cluster( name_checksum );
}
struct SAutoTrick
{
uint32 pPendingTricks[32];
uint32 numPendingTricks;
};
Net::Conn* MyGetAssociatedNetworkConnection( uint32 skater_id )
{
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
Obj::CSkater* skater;
GameNet::PlayerInfo* player;
skater = skate_mod->GetSkaterById( skater_id );
if( skater )
{
player = gamenet_man->GetPlayerByObjectID( skater->GetID() );
if( player )
{
return player->m_Conn;
}
}
return NULL;
}
void MyLogTrickObject( int skater_id, int score, uint32 num_pending_tricks, uint32* p_pending_tricks, bool propagate )
{
Mdl::Skate * skate_mod = Mdl::Skate::Instance();
GameNet::Manager * gamenet_man = GameNet::Manager::Instance();
GameNet::MsgScoreLogTrickObject msg;
GameNet::MsgObsScoreLogTrickObject obs_msg;
Net::MsgDesc msg_desc;
Net::Server* server;
Net::Conn* conn;
GameNet::PlayerInfo* player;
Lst::Search< GameNet::PlayerInfo > sh;
if( propagate )
{
server = gamenet_man->GetServer();
Dbg_Assert( server );
conn = MyGetAssociatedNetworkConnection( skater_id );
// keep track of whom we need to send the steal message to
int i;
char previous_owner_flags[GameNet::vMAX_PLAYERS];
for ( i = 0; i < GameNet::vMAX_PLAYERS; i++ )
{
previous_owner_flags[i] = 0;
}
num_pending_tricks = skate_mod->GetTrickObjectManager()->RequestLogTrick( num_pending_tricks, p_pending_tricks, previous_owner_flags, skater_id, score );
if ( !num_pending_tricks )
{
return;
}
for ( i = 0; i < GameNet::vMAX_PLAYERS; i++ )
{
if ( previous_owner_flags[i] )
{
// GJ: This only sends the stolen message to the two parties involved
GameNet::PlayerInfo* pPlayerInfo;
GameNet::MsgStealMessage steal_msg;
Net::MsgDesc steal_msg_desc;
steal_msg.m_NewOwner = skater_id;
steal_msg.m_OldOwner = i;
steal_msg.m_GameId = gamenet_man->GetNetworkGameId();
pPlayerInfo = gamenet_man->GetPlayerByObjectID(skater_id);
Dbg_Assert( pPlayerInfo );
steal_msg_desc.m_Data = &steal_msg;
steal_msg_desc.m_Length = sizeof( GameNet::MsgStealMessage );
steal_msg_desc.m_Id = GameNet::MSG_ID_STEAL_MESSAGE;
server->EnqueueMessage( pPlayerInfo->GetConnHandle(), &steal_msg_desc );
steal_msg.m_NewOwner = skater_id;
steal_msg.m_OldOwner = i;
steal_msg.m_GameId = gamenet_man->GetNetworkGameId();
pPlayerInfo = gamenet_man->GetPlayerByObjectID(i);
//Dbg_Assert( pPlayerInfo );
// For now, don't assert if the player doesn't exist anymore. Just don't do anything.
// Eventually, Gary will fix this so that pieces of exiting players are reset
if( pPlayerInfo )
{
server->EnqueueMessage( pPlayerInfo->GetConnHandle(), &msg_desc );
}
}
}
#ifdef __USER_GARY__
printf( "Broadcasting %d tricks\n", num_pending_tricks );
#endif
msg.m_SubMsgId = GameNet::SCORE_MSG_ID_LOG_TRICK_OBJECT;
msg.m_OwnerId = skater_id;
msg.m_Score = score;
msg.m_NumPendingTricks = num_pending_tricks;
msg.m_GameId = gamenet_man->GetNetworkGameId();
uint32 max_pending_trick_buffer_size = GameNet::MsgScoreLogTrickObject::vMAX_PENDING_TRICKS * sizeof(uint32);
uint32 actual_pending_trick_buffer_size = msg.m_NumPendingTricks * sizeof(uint32);
memcpy( msg.m_PendingTrickBuffer, p_pending_tricks, actual_pending_trick_buffer_size );
msg_desc.m_Data = &msg;
msg_desc.m_Length = sizeof( GameNet::MsgScoreLogTrickObject ) - max_pending_trick_buffer_size + actual_pending_trick_buffer_size;
msg_desc.m_Id = GameNet::MSG_ID_SCORE;
msg_desc.m_Queue = Net::QUEUE_SEQUENCED;
msg_desc.m_GroupId = GameNet::vSEQ_GROUP_PLAYER_MSGS;
// tell players to change their colors
for( player = gamenet_man->FirstPlayerInfo( sh ); player;
player = gamenet_man->NextPlayerInfo( sh ))
{
//server->EnqueueMessage( player->GetConnHandle(), &msg_desc );
server->StreamMessage( player->GetConnHandle(), msg_desc.m_Id, msg_desc.m_Length,
msg_desc.m_Data, "TrickObj Buffer", GameNet::vSEQ_GROUP_PLAYER_MSGS );
}
obs_msg.m_OwnerId = skater_id;
obs_msg.m_NumPendingTricks = num_pending_tricks;
obs_msg.m_GameId = gamenet_man->GetNetworkGameId();
max_pending_trick_buffer_size = GameNet::MsgScoreLogTrickObject::vMAX_PENDING_TRICKS * sizeof(uint32);
actual_pending_trick_buffer_size = obs_msg.m_NumPendingTricks * sizeof(uint32);
memcpy( obs_msg.m_PendingTrickBuffer, p_pending_tricks, actual_pending_trick_buffer_size );
msg_desc.m_Data = &obs_msg;
msg_desc.m_Length = sizeof( GameNet::MsgObsScoreLogTrickObject ) - max_pending_trick_buffer_size + actual_pending_trick_buffer_size;
msg_desc.m_Id = GameNet::MSG_ID_OBSERVER_LOG_TRICK_OBJ;
// tell observers to change their colors
for( player = gamenet_man->FirstPlayerInfo( sh, true ); player;
player = gamenet_man->NextPlayerInfo( sh, true ))
{
if( player->IsObserving())
{
//server->EnqueueMessage( player->GetConnHandle(), &msg_desc );
server->StreamMessage( player->GetConnHandle(), msg_desc.m_Id, msg_desc.m_Length,
msg_desc.m_Data, "TrickObj Buffer", GameNet::vSEQ_GROUP_PLAYER_MSGS );
}
}
// send score updates, as something has changed
skate_mod->SendScoreUpdates( false );
// Let the server's client do the rest of the work
if( conn->IsLocal())
{
return;
}
}
#ifdef __USER_GARY__
printf( "Client is receiving %d tricks\n", num_pending_tricks );
#endif
// modulate the color here
for ( uint32 i = 0; i < num_pending_tricks; i++ )
{
skate_mod->GetTrickObjectManager()->ModulateTrickObjectColor( p_pending_tricks[i], skater_id );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void trick_off_object(CTrickCluster* pCluster, void* pData)
{
Dbg_AssertPtr(pCluster);
SAutoTrick* pAutoTrick = (SAutoTrick*)pData;
if ( pAutoTrick->numPendingTricks >= 32 )
{
return;
}
if ( !pCluster->m_IsOwned )
{
pAutoTrick->pPendingTricks[pAutoTrick->numPendingTricks] = pCluster->GetNameChecksum();
pAutoTrick->numPendingTricks++;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CTrickObjectManager::TrickOffAllObjects( uint32 skater_id )
{
SAutoTrick theAutoTrick;
theAutoTrick.numPendingTricks = 0;
m_TrickClusterList.HandleCallback(trick_off_object, &theAutoTrick);
if ( theAutoTrick.numPendingTricks > 0 )
{
MyLogTrickObject( skater_id, 1000, theAutoTrick.numPendingTricks, theAutoTrick.pPendingTricks, true );
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObjectManager::ModulateTrickObjectColor( uint32 name_checksum, int skater_id )
{
CTrickCluster* pCluster = get_aliased_cluster( name_checksum );
// change only objects marked as trick objects
if ( !pCluster )
{
// not a trick object
return false;
}
// convert skater_id ->seqIndex, as it's 1-based,
// or -1 to reset
int seqIndex = -1;
if ( skater_id != -1 )
{
seqIndex = skater_id + 1;
}
Dbg_MsgAssert( seqIndex == -1 || ( seqIndex >= 1 && seqIndex <= 8 ) ,( "Out of range seq index %d", seqIndex ));
pCluster->ModulateTrickObjectColor( seqIndex );
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickCluster* CTrickObjectManager::get_aliased_cluster( uint32 alias_checksum )
{
#if 0
for ( uint32 i = 0; i < m_TrickAliasCount; i++ )
{
if ( m_TrickAliasList[i].m_AliasChecksum == alias_checksum )
{
return m_TrickAliasList[i].mp_TrickCluster;
}
}
return NULL;
#endif
return m_TrickAliasList.GetItem(alias_checksum, false);
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CTrickCluster* CTrickObjectManager::find_trick_cluster( uint32 cluster_checksum )
{
#if 0
uint32 count = m_TrickClusterList.CountItems();
// find the appropriate trick object
for ( uint32 i = 0; i < count; i++ )
{
Lst::Node< CTrickCluster >* pNode = m_TrickClusterList.GetItem( i );
Dbg_Assert( pNode );
CTrickCluster* pCluster = pNode->GetData();
Dbg_Assert( pCluster );
if ( pCluster->m_NameChecksum == cluster_checksum )
{
return pCluster;
}
}
return NULL;
#endif
return m_TrickClusterList.GetItem( cluster_checksum, false );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObjectManager::clear_trick_clusters( int seqIndex )
{
m_TrickClusterList.IterateStart();
CTrickCluster *p_cluster;
while ((p_cluster = m_TrickClusterList.IterateNext()))
{
if (!p_cluster->ClearCluster(seqIndex))
{
return false;
}
}
return true;
}
// this is useful if you want to examine the functionality
// of a single trick object without sorting through hundreds of
// other trick objects... it represents one single piece in
// the foundry
//#define __TESTSINGLETRICKOBJECT__
#ifdef __TESTSINGLETRICKOBJECT__
const char* p_single_cluster_name = "ParkingLotBulldozer";
const char* p_single_object_name = "Parking_Lot_Bulldozer0";
#endif
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObjectManager::AddTrickCluster( uint32 name_checksum )
{
#ifdef __TESTSINGLETRICKOBJECT__
if ( name_checksum != Script::GenerateCRC(p_single_cluster_name) )
return false;
#endif
#ifdef __USER_GARY__
// printf( "+++ Adding trick object %s (%x)\n", Script::FindChecksumName(name_checksum), name_checksum );
#endif
if ( find_trick_cluster( name_checksum ) )
{
return false;
}
// If playing a created park, clear any created rail colors for this cluster.
Mdl::Skate * p_skate_mod = Mdl::Skate::Instance();
if (p_skate_mod->m_cur_level == CRCD(0xb664035d,"load_sk5ed_gameplay"))
{
Obj::GetRailEditor()->ClearRailColor(name_checksum);
}
// add the cluster since it doesn't already exist
CTrickCluster* pCluster = new CTrickCluster( name_checksum );
Dbg_Assert( pCluster );
// m_TrickClusterList.AddToTail( pCluster );
m_TrickClusterList.PutItem( name_checksum, pCluster );
m_NumTrickClusters++;
#if 0
Ed::ParkEditor* park_ed_mod = Ed::ParkEditor::Instance();
if (!park_ed_mod->IsInitialized())
{
Dbg_Assert( m_NumTrickClusters <= 256 );
}
#endif
// alias the cluster to itself
AddTrickAlias( name_checksum, name_checksum );
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObjectManager::AddTrickObjectToCluster( uint32 name_checksum, uint32 cluster_checksum )
{
#ifdef __TESTSINGLETRICKOBJECT__
if ( name_checksum != Script::GenerateCRC(p_single_object_name) )
return false;
#endif
CTrickCluster* pCluster = find_trick_cluster( cluster_checksum );
Dbg_MsgAssert( pCluster,( "cluster %s not found", Script::FindChecksumName( cluster_checksum ) ));
bool success = pCluster->AddTrickObject( name_checksum );
// only if not clustering to self
if ( success && ( name_checksum != cluster_checksum ) )
{
// bind the environment object to the cluster
AddTrickAlias( name_checksum, cluster_checksum );
}
return success;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObjectManager::AddTrickAlias( uint32 alias_checksum, uint32 cluster_checksum )
{
#ifdef __TESTSINGLETRICKOBJECT__
if ( cluster_checksum != Script::GenerateCRC(p_single_cluster_name) )
return false;
#endif
CTrickCluster* pCluster = get_aliased_cluster( alias_checksum );
if( pCluster )
{
Dbg_MsgAssert( 0,( "%s has already been aliased to %s cluster", Script::FindChecksumName(alias_checksum), Script::FindChecksumName(pCluster->m_NameChecksum) ));
}
pCluster = find_trick_cluster( cluster_checksum );
if( pCluster == NULL )
{
Dbg_MsgAssert( 0,( "cluster %s not found", Script::FindChecksumName(cluster_checksum) ));
}
m_TrickAliasList.PutItem(alias_checksum, pCluster);
#if 0
Dbg_MsgAssert( m_TrickAliasCount < vMAX_ALIASES,( "Too many aliases. Couldn't alias %s to cluster %s", Script::FindChecksumName(alias_checksum), Script::FindChecksumName(cluster_checksum) ));
m_TrickAliasList[m_TrickAliasCount].m_AliasChecksum = alias_checksum;
pCluster = find_trick_cluster( cluster_checksum );
m_TrickAliasList[m_TrickAliasCount].mp_TrickCluster = pCluster;
Dbg_MsgAssert( pCluster,( "cluster %s not found", Script::FindChecksumName(cluster_checksum) ));
m_TrickAliasCount++;
#endif
// printf("Adding trick alias %s\n", Script::FindChecksumName(alias_checksum));
return true;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void delete_trick_cluster(CTrickCluster* pCluster, void* pData)
{
Dbg_AssertPtr(pCluster);
delete pCluster;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObjectManager::DeleteAllTrickObjects( void )
{
#if 0
uint32 count = m_TrickClusterList.CountItems();
for ( uint32 i = 0; i < count; i++ )
{
Lst::Node< CTrickCluster >* pNode = m_TrickClusterList.GetItem( 0 );
Dbg_Assert( pNode );
CTrickCluster* pCluster = pNode->GetData();
Dbg_Assert( pCluster );
delete pCluster;
}
// now remove all the nodes from the list
m_TrickClusterList.RemoveAllNodes();
#endif
m_TrickClusterList.HandleCallback(delete_trick_cluster, NULL);
m_TrickClusterList.FlushAllItems();
m_NumTrickClusters = 0;
// m_TrickAliasCount = 0;
m_TrickAliasList.FlushAllItems();
return true;
}
struct STrickObjectScore
{
int running_score;
uint32 skater_id;
};
/******************************************************************/
/* */
/* */
/******************************************************************/
void count_score(CTrickCluster* pCluster, void* pData)
{
Dbg_AssertPtr(pCluster);
Dbg_AssertPtr(pData);
STrickObjectScore* pScore = (STrickObjectScore*)pData;
pScore->running_score += pCluster->GetScore( pScore->skater_id );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
int CTrickObjectManager::GetScore( uint32 skater_id )
{
STrickObjectScore theScore;
theScore.running_score = 0;
theScore.skater_id = skater_id;
m_TrickClusterList.HandleCallback(count_score, (void*)&theScore);
return theScore.running_score;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
struct SSearchInfo
{
uint32 checksum;
uint8 index;
bool found;
};
/******************************************************************/
/* */
/* */
/******************************************************************/
void find_compressed_index(CTrickCluster* pCluster, void* pData)
{
Dbg_AssertPtr(pCluster);
Dbg_AssertPtr(pData);
SSearchInfo* pInfo = (SSearchInfo*)pData;
if ( pInfo->found )
{
// already found...
return;
}
if ( pInfo->checksum == pCluster->GetNameChecksum() )
{
pInfo->found = true;
return;
}
// make sure it's less than 256
Dbg_MsgAssert( pInfo->index < 256, ( "Too many trick aliases" ) );
pInfo->index++;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void find_uncompressed_checksum(CTrickCluster* pCluster, void* pData)
{
Dbg_AssertPtr(pCluster);
Dbg_AssertPtr(pData);
SSearchInfo* pInfo = (SSearchInfo*)pData;
if ( pInfo->found )
{
// already found...
return;
}
if ( pInfo->index == 0 )
{
pInfo->found = true;
pInfo->checksum = pCluster->GetNameChecksum();
return;
}
pInfo->index--;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint8 CTrickObjectManager::GetCompressedTrickObjectIndex( uint32 name_checksum )
{
SSearchInfo theInfo;
theInfo.index = 0;
theInfo.checksum = name_checksum;
theInfo.found = false;
m_TrickClusterList.HandleCallback( find_compressed_index, (void*)&theInfo );
Dbg_Assert( theInfo.found );
return theInfo.index;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 CTrickObjectManager::GetUncompressedTrickObjectChecksum( uint8 compressed_index )
{
SSearchInfo theInfo;
theInfo.index = compressed_index;
theInfo.checksum = 0;
theInfo.found = false;
m_TrickClusterList.HandleCallback( find_uncompressed_checksum, (void*)&theInfo );
Dbg_Assert( theInfo.found );
return theInfo.checksum;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
struct SInitGraffitiStateInfo
{
uint32 skater_id;
int num_trick_objects;
GameNet::MsgInitGraffitiState* pMsg;
Obj::CTrickObjectManager* pManager;
};
/******************************************************************/
/* */
/* */
/******************************************************************/
void init_graffiti_state(CTrickCluster* pCluster, void* pData)
{
SInitGraffitiStateInfo* pInfo = (SInitGraffitiStateInfo*)pData;
if ( pCluster->m_IsOwned && pCluster->m_OwnerId == pInfo->skater_id )
{
// TODO: check whether it's already in the list?
Dbg_MsgAssert( pInfo->num_trick_objects < GameNet::vMAX_TRICK_OBJECTS_IN_LEVEL, ( "Too many trick objects in level" ) );
Obj::CTrickObjectManager* pManager = pInfo->pManager;
pInfo->pMsg->m_TrickObjectStream[pInfo->num_trick_objects] = pManager->GetCompressedTrickObjectIndex( pCluster->GetNameChecksum() );
pInfo->num_trick_objects++;
pInfo->pMsg->m_NumTrickObjects[pInfo->skater_id]++;
}
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CTrickObjectManager::SetObserverGraffitiState( Script::CScriptStructure* pScriptStructure )
{
mp_ObserverState->Clear();
if (pScriptStructure)
{
*mp_ObserverState+=*pScriptStructure;
}
#ifdef __NOPT_ASSERT__
Script::PrintContents(mp_ObserverState);
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CTrickObjectManager::ApplyObserverGraffitiState( void )
{
for( int i = 0; i < Mdl::Skate::vMAX_SKATERS; i++ )
{
Script::CArray* pArray;
char arrayName[32];
sprintf( arrayName, "Skater%d", i );
if ( mp_ObserverState->GetArray( arrayName, &pArray ) )
{
for ( int j = 0; j < (int)pArray->GetSize(); j++ )
{
uint32 checksum = pArray->GetNameChecksum( j );
#ifdef __NOPT_ASSERT__
printf( "Modulating array %s\n", Script::FindChecksumName(checksum) );
#endif
ModulateTrickObjectColor( checksum, i );
}
}
}
// now that we've done it, we can clear the observer state.
mp_ObserverState->Clear();
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 CTrickObjectManager::SetInitGraffitiStateMessage( void* pData )
{
SInitGraffitiStateInfo theInfo;
theInfo.pMsg = (GameNet::MsgInitGraffitiState*)pData;
theInfo.pManager = this;
theInfo.num_trick_objects = 0;
for ( uint32 i = 0; i < Mdl::Skate::vMAX_SKATERS; i++ )
{
theInfo.pMsg->m_NumTrickObjects[i] = 0;
theInfo.skater_id = i;
m_TrickClusterList.HandleCallback( init_graffiti_state, (void*)&theInfo );
printf( "Building graffiti state message %d\n", theInfo.pMsg->m_NumTrickObjects[i] );
}
return ( sizeof(uint8) * Mdl::Skate::vMAX_SKATERS ) + ( sizeof(uint8) * theInfo.num_trick_objects );
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CTrickObjectManager::ResetAllTrickObjects( void )
{
// TODO:
printf("Resetting all trick objects\n");
return false;
#if 0
uint32 count = m_TrickClusterList.CountItems();
// call the reset function on each trick object in the scene
for ( uint32 i = 0; i < count; i++ )
{
Lst::Node< CTrickCluster >* pNode = m_TrickClusterList.GetItem( i );
Dbg_Assert( pNode );
CTrickCluster* pCluster = pNode->GetData();
Dbg_Assert( pCluster );
pCluster->Reset();
}
#endif
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
void CTrickObjectManager::PrintContents( void )
{
// Remove this line if you need to see the contents
return;
printf("**********************\n");
printf("* TRICK CLUSTER LIST:\n");
printf("**********************\n");
#if 0
uint32 i;
// call the reset function on each trick object in the scene
for ( i = 0; i < m_TrickClusterList.CountItems(); i++ )
{
Lst::Node< CTrickCluster >* pNode = m_TrickClusterList.GetItem( i );
Dbg_Assert( pNode );
CTrickCluster* pCluster = pNode->GetData();
Dbg_Assert( pCluster );
printf( "Trick cluster %d of %d: %s\n", i, m_TrickClusterList.CountItems(), Script::FindChecksumName( pCluster->m_NameChecksum ) );
}
#endif
#if 0
printf("**********************\n");
printf("* TRICK ALIAS LIST:\n");
printf("**********************\n");
for ( i = 0; i < m_TrickAliasCount; i++ )
{
// printf( "%d: %s is aliased to %s\n", i, Script::FindChecksumName(m_TrickAliasList[i].m_AliasChecksum), Script::FindChecksumName(m_TrickAliasList[i].mp_TrickCluster->m_NameChecksum) );
}
#endif
}
/******************************************************************/
/* */
/* */
/******************************************************************/
CPendingTricks::CPendingTricks( void )
{
m_NumTrickItems = 0;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPendingTricks::TrickOffObject( uint32 checksum )
{
uint32 num_trick_items = m_NumTrickItems;
if ( num_trick_items > vMAX_PENDING_TRICKS )
num_trick_items = vMAX_PENDING_TRICKS;
// not a valid trick item
Mdl::Skate* skate_mod = Mdl::Skate::Instance();
CTrickObjectManager* pTrickObjectManager = skate_mod->GetTrickObjectManager();
Dbg_Assert( pTrickObjectManager );
checksum = pTrickObjectManager->TrickObjectExists( checksum );
if ( !checksum )
{
return false;
}
for ( uint32 i = 0; i < num_trick_items; i++ )
{
if ( m_Checksum[i] == checksum )
return false;
}
// printf( "Adding object %s to pending tricks:\n", Script::FindChecksumName(checksum) );
// circular buffer
m_Checksum[(m_NumTrickItems++)%vMAX_PENDING_TRICKS] = checksum;
return false;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
uint32 CPendingTricks::WriteToBuffer( uint32* p_buffer, uint32 max_size )
{
// TODO: Account for the circular buffer so that the buffer
// size can be bigger than the pending trick size
Dbg_Assert( ( vMAX_PENDING_TRICKS * sizeof(uint32) ) <= max_size );
uint32 num_trick_items = m_NumTrickItems;
if ( num_trick_items > vMAX_PENDING_TRICKS )
num_trick_items = vMAX_PENDING_TRICKS;
Mdl::Skate* skate_mod = Mdl::Skate::Instance();
CTrickObjectManager* pTrickObjectManager = skate_mod->GetTrickObjectManager();
Dbg_Assert( pTrickObjectManager );
uint32 size = 0;
for ( uint32 i = 0; i < num_trick_items; i++ )
{
#ifdef __NOPT_ASSERT__
printf( "Looking for %s\n", Script::FindChecksumName( m_Checksum[i] ) );
#endif
if ( pTrickObjectManager->TrickObjectExists( m_Checksum[i] ) )
{
*p_buffer = m_Checksum[i];
p_buffer++ ;
// increment the size
size += sizeof(uint32);
}
if ( size >= max_size )
break;
}
return size;
}
/******************************************************************/
/* */
/* */
/******************************************************************/
bool CPendingTricks::FlushTricks( void )
{
// player has bailed
m_NumTrickItems = 0;
return true;
}
} // namespace Obj