/***************************************************************************** ** ** ** 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 #include #include #include #include #include #include #include #include #include #include #include #include #include // just needed in mygetassociatednetworkconnection #include #include #ifdef __NOPT_ASSERT__ //#include #endif /***************************************************************************** ** Externals ** *****************************************************************************/ /***************************************************************************** ** Defines ** *****************************************************************************/ DefinePoolableClass(Lst::HashItem); 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