//============================================================================= // Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. // // File: supersprintmanager.cpp // // Description: Implement SuperSprintManager // // History: 2/3/2003 + Created -- Cary Brisebois // //============================================================================= //======================================== // System Includes //======================================== // Foundation Tech #include #include #include #include #include //======================================== // Project Includes //======================================== #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //***************************************************************************** // // Global Data, Local Data, Local Classes // //***************************************************************************** const float MIN_SCALE = 0.01f; const float MAX_SCALE = 1.0f; const float MIN_DIST = 10.0f; const float MAX_DIST = 80.0f; SuperSprintManager* SuperSprintManager::spInstance = NULL; const int DNF_TIMEOUT_TIME = 10000; #define GET_TIME ::radTimeGetMicroseconds() static char CHEKPOINT_LIST_B01 [] = { 2, 3, 4, 5, 6, 7, 8, 1 }; static char CHEKPOINT_LIST_B01_R [] = { 8, 7, 6, 5, 4, 3, 2, 1 }; static char CHECKPOINT_LIST_B02 [] = { 2, 3, 4, 5, 6, 3, 8, 9, 1 }; static char CHECKPOINT_LIST_B02_R [] = { 9, 8, 3, 6, 5, 4, 3, 2, 1 }; static char CHECKPOINT_LIST_B03 [] = { 2, 3, 4, 5, 6, 7, 1 }; static char CHECKPOINT_LIST_B03_R [] = { 7, 6, 5, 4, 3, 2, 1 }; static char CHECKPOINT_LIST_B05 [] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 7, 3, 11, 1 }; static char CHECKPOINT_LIST_B05_R [] = { 11, 3, 7, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }; static char CHECKPOINT_LIST [] = { 2, 3, 1 }; static char CHECKPOINT_LIST_R [] = { 3, 2, 1 }; //***************************************************************************** // // Public Member Functions // //***************************************************************************** //From EventListener //============================================================================= // SuperSprintManager::HandleEvent //============================================================================= // Description: Comment // // Parameters: ( EventEnum id, void* pEventData ) // // Return: void // //============================================================================= void SuperSprintManager::HandleEvent( EventEnum id, void* pEventData ) { #if defined( RAD_DEBUG ) || defined( RAD_TUNE ) char errMsg[128]; #endif if ( id == EVENT_LOCATOR + LocatorEvent::CHECK_POINT ) { EventLocator* loc = static_cast(pEventData); char checkNum = static_cast( loc->GetData() ); if ( loc->GetPlayerEntered() && checkNum != 0 ) //Ignore the 0 ones. { //The idea here is to detect if the player is attempting to do the //checkpoints out of order. If the checkpoint passed is not the one we want //we test to see if the player has already hit a bad one and if not we decrement //where they are going (send them back) and mark them as cheaters. //Then, only when they pass the one they're supposed to do they get unmarked //as cheaters and get to move on to the next check point. The first checkpoint is a //bit tricky as the players start inside the last checkpoint and would thus be //considered cheaters. We can ignore cheaters cheating on checkpoint 2. //Indexes start at 1 int playerID = loc->GetPlayerID(); #if defined( RAD_DEBUG ) || defined( RAD_TUNE ) sprintf( errMsg, "Something wrong with player %d", playerID+1 ); rTuneAssertMsg( 0 <= playerID && playerID < 4, errMsg ); rTuneAssertMsg( 0 <= mPlayers[ playerID ].mNextCheckPoint && mPlayers[ playerID ].mNextCheckPoint < GetNumCheckpoints(), errMsg ); #endif // find the one we're supposed to be at const char nextCheck = mCheckPoints[ mPlayers[ playerID ].mNextCheckPoint ]; // find the one we were just at char lastCheckIdx = mPlayers[ playerID ].mNextCheckPoint; if ( lastCheckIdx == 0 ) { lastCheckIdx = GetNumCheckpoints() - 1; } else { lastCheckIdx--; } rTuneAssert( 0 <= lastCheckIdx && lastCheckIdx < GetNumCheckpoints() ); const char prevCheck = mCheckPoints[ lastCheckIdx ]; if ( checkNum != nextCheck ) { //This guy is possibly cheating if ( !mPlayers[ playerID ].mCheated && checkNum != prevCheck ) { //CHEATER! // we want to knock him back to aim for the previous check mPlayers[ playerID ].mNextCheckPoint = lastCheckIdx; /* if ( nextCheck == 1 ) { mPlayers[ playerID ].mNextCheckPoint = GetNumCheckpoints() - 1; } else { mPlayers[ playerID ].mNextCheckPoint = nextCheck - 1; } */ #if defined( RAD_DEBUG ) || defined( RAD_TUNE ) rTuneAssertMsg( 0 <= mPlayers[ playerID ].mNextCheckPoint && mPlayers[ playerID ].mNextCheckPoint < GetNumCheckpoints(), errMsg ); #endif mPlayers[ playerID ].mCheated = true; } } else { //Unmark the cheater bool previouslyCheated = mPlayers[ playerID ].mCheated; mPlayers[ playerID ].mCheated = false; if( nextCheck == 1 && !previouslyCheated ) //This is the finish line. { //This guy has completed a lap mPlayers[ playerID ].mNumLaps++; //Figure out his lap time. unsigned int endTime = GET_TIME; unsigned int time = endTime - mStartTime; unsigned int lapTime = time - mPlayers[ playerID ].mRaceTime; //Possibly set the best lap time if ( lapTime < mPlayers[ playerID ].mBestLap ) { mPlayers[ playerID ].mBestLap = lapTime; } //Set the lapTime mPlayers[ playerID ].mLapTime = lapTime; //Set the raceTime mPlayers[ playerID ].mRaceTime += lapTime; if ( static_cast( mPlayers[ playerID ].mNumLaps ) == mNumLaps - 1 ) { //Show the white flag for a few seconds. mWFlag->ShouldRender( true ); mWFlagTimeout = SuperSprintData::FLAG_TIMEOUT; } else if ( static_cast( mPlayers[ playerID ].mNumLaps ) == mNumLaps ) { //Show the finished flag for a few seconds. mFFlag->ShouldRender( true ); mFFlagTimeout = SuperSprintData::FLAG_TIMEOUT; //This guy is finished. if( !mVehicleSlots[ playerID ].mIsHuman ) { mVehicleSlots[ playerID ].mVehicleAI->SetActive( false ); } else { //Disable his controller mNumHumansFinished++; int controllerID = GetInputManager()->GetControllerIDforPlayer( playerID ); if( controllerID != -1 ) { GetInputManager()->GetController( controllerID )->SetGameState( Input::ACTIVE_SS_GAME ); } } mPlayers[ playerID ].mPosition = mCurrentPosition; //Only one guy left, or all humans done, go to DNF if ( mCurrentState != DNF_TIMEOUT && ( mCurrentPosition == mNumActivePlayers - 1 || mNumHumansFinished == mNumHumanPlayers ) ) { mCountDownTime = DNF_TIMEOUT_TIME; mDrawable->SetRenderState( SuperSprintDrawable::COUNT_DOWN ); mDrawable->SetTextScale( 2.0f ); sprintf( mTime, "%d", mCountDownTime / 1000 ); mDrawable->SetCountDownMSG( mTime ); SetState( DNF_TIMEOUT ); } else if ( mCurrentPosition == mNumActivePlayers ) { //We're done! mCountDownTime = 0; } mCurrentPosition++; } } mPlayers[ playerID ].mNextCheckPoint++; if ( mPlayers[ playerID ].mNextCheckPoint == GetNumCheckpoints() ) { mPlayers[ playerID ].mNextCheckPoint = 0; //Reset } #if defined( RAD_DEBUG ) || defined( RAD_TUNE ) rTuneAssertMsg( 0 <= mPlayers[ playerID ].mNextCheckPoint && mPlayers[ playerID ].mNextCheckPoint < GetNumCheckpoints(), errMsg ); #endif } } } else if ( id == EVENT_LOCATOR + LocatorEvent::TRAP ) { EventLocator* loc = static_cast(pEventData); if ( loc->GetPlayerEntered() ) { unsigned int locID = loc->GetData(); if ( !mTrapTriggered && mPositions[ loc->GetPlayerID() ] == 1 && ((!mGoLeft && locID == 0) || (mGoLeft && locID == 1)) ) { //This toggles on mTrapController->SetAnimationDirection( 1.0f ); mTrapTriggered = true; } else if ( mTrapTriggered && mPositions[ loc->GetPlayerID() ] == 1 && ((!mGoLeft && locID == 1) || (mGoLeft && locID == 0)) ) { //This toggles off mTrapController->SetAnimationDirection( -1.0f ); mTrapTriggered = false; } } } else if ( id == EVENT_ANIMATED_CAM_SHUTDOWN ) { DisableAllControllers(); } GameplayManager::HandleEvent( id, pEventData ); } //From LoadingManager::ProcessRequestsCallback //============================================================================= // SuperSprintManager::OnProcessRequestsComplete //============================================================================= // Description: Comment // // Parameters: ( void* pUserData ) // // Return: void // //============================================================================= void SuperSprintManager::OnProcessRequestsComplete( void* pUserData ) { PositionCharacters(); SetupIcons(); GetGameFlow()->SetContext( CONTEXT_SUPERSPRINT ); } //Local //============================================================================= // SuperSprintManager::GetInstance //============================================================================= // Description: Comment // // Parameters: () // // Return: SuperSprintManager // //============================================================================= SuperSprintManager* SuperSprintManager::GetInstance() { if ( spInstance == NULL ) { HeapMgr()->PushHeap( GMA_LEVEL_OTHER ); spInstance = new SuperSprintManager(); spInstance->AddRef(); HeapMgr()->PopHeap( GMA_LEVEL_OTHER ); } return spInstance; } //============================================================================= // SuperSprintManager::DestroyInstance //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::DestroyInstance() { if ( spInstance ) { spInstance->Release(); } spInstance = NULL; } //============================================================================= // SuperSprintManager::Initialize //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::Initialize() { GameplayManager::Initialize(); HeapMgr()->PushHeap( GMA_LEVEL_OTHER ); //Add the drawable to the views mDrawable = new SuperSprintDrawable(); rAssert( mDrawable ); mDrawable->AddRef(); RenderManager* rm = GetRenderManager(); RenderLayer* rloutside = rm->mpLayer( RenderEnums::LevelSlot ); rAssert( rloutside ); rloutside->AddGuts( mDrawable ); mDrawable->SetCarData( mVehicleSlots ); mDrawable->SetPlayerData( mPlayers ); int i; for( i = 0; i < SuperSprintData::NUM_PLAYERS; i++ ) { int controllerID = GetInputManager()->GetControllerIDforPlayer( i ); mVehicleSlots[ i ].mState = (controllerID != -1) ? SuperSprintData::CarData::SELECTED : SuperSprintData::CarData::WAITING; mVehicleSlots[ i ].mIsHuman = (controllerID != -1); mPlayers[ i ].mRacing = (controllerID != -1); } EnumerateControllers(); mNumCheckPoints = 0; GetEventManager()->AddListener( this, (EventEnum)(EVENT_LOCATOR + LocatorEvent::CHECK_POINT) ); GetEventManager()->AddListener( this, (EventEnum)(EVENT_LOCATOR + LocatorEvent::TRAP) ); GetEventManager()->AddListener( this, EVENT_ANIMATED_CAM_SHUTDOWN ); mFFlag = new AnimatedIcon(); mWFlag = new AnimatedIcon(); int j; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { for ( j = 0; j < SuperSprintData::NUM_PLAYERS; ++j ) { mPositionIcon[ i ][ j ] = new AnimatedIcon(); } mPlayerID[ i ] = new AnimatedIcon(); mNitroEffect[ i ] = new AnimatedIcon(); } for ( i = 0; i < MAX_AI_WAYPOINTS; ++i ) { mPathData[ i ].closestElem.elem = NULL; mPathData[ i ].roadT = 0.0f; mPathData[ i ].seg = NULL; mPathData[ i ].segT = 0.0f; mPathData[ i ].loc = NULL; } HeapMgr()->PopHeap( GMA_LEVEL_OTHER ); } //============================================================================= // SuperSprintManager::Finalize //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::Finalize() { //Remove the drawable from the views RenderManager* rm = GetRenderManager(); RenderLayer* rloutside = rm->mpLayer( RenderEnums::LevelSlot ); rAssert( rloutside ); rloutside->RemoveGuts( mDrawable ); //Shut down the controllers. InputManager* im = GetInputManager(); unsigned int i; for ( i = 0; i < Input::MaxControllers; ++i ) { im->UnregisterMappable( i, this ); } GetEventManager()->RemoveAll( this ); mDrawable->Release(); mDrawable = NULL; CleanUpCars(); delete mFFlag; mFFlag = NULL; delete mWFlag; mWFlag = NULL; int j; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { for ( j = 0; j < SuperSprintData::NUM_PLAYERS; ++j ) { delete mPositionIcon[ i ][ j ]; mPositionIcon[ i ][ j ] = NULL; } delete mPlayerID[ i ]; delete mNitroEffect[ i ]; } if ( mTrapController ) { mTrapController->Release(); mTrapController = NULL; } for ( i = 0; i < mNumCheckPointLocators; ++i ) { //mCheckPointLocators[ i ]->Release(); mCheckPointLocators[ i ] = NULL; } mNumCheckPointLocators = 0; GameplayManager::Finalize(); } //============================================================================= // SuperSprintManager::Update //============================================================================= // Description: Comment // // Parameters: ( unsigned int milliseconds ) // // Return: void // //============================================================================= void SuperSprintManager::Update( unsigned int milliseconds ) { int oldTimeSecs; int newTimeSecs; //Test the flags if ( mFFlagTimeout > 0 ) { if ( mFFlagTimeout <= milliseconds ) { mFFlag->ShouldRender( false ); mFFlagTimeout = 0; } else { mFFlagTimeout -= milliseconds; mFFlag->Update( milliseconds ); } } if ( mWFlagTimeout > 0 ) { if ( mWFlagTimeout <= milliseconds ) { mWFlag->ShouldRender( false ); mWFlagTimeout = 0; } else { mWFlagTimeout -= milliseconds; mWFlag->Update( milliseconds ); } } UpdatePositionIcons( milliseconds ); switch ( mCurrentState ) { case COUNT_DOWN: { // 3 - 2 - 1 - GO! oldTimeSecs = mCountDownTime / 1000; if ( mCountDownTime - static_cast(milliseconds) <= 0 ) { mCountDownTime = 0; } else { mCountDownTime -= milliseconds; } if ( mCountDownTime > 2000 ) { mDrawable->SetCountDownMSG( "3" ); } else if ( mCountDownTime > 1000 ) { mDrawable->SetCountDownMSG( "2" ); mDrawable->SetTextScale( 1.5f ); } else if ( mCountDownTime > 0 ) { mDrawable->SetCountDownMSG( "1" ); mDrawable->SetTextScale( 2.0f ); } else { mDrawable->SetCountDownMSG( "GO!" ); mDrawable->SetTextScale( 2.5f ); //Leave the go up for a little while. mCountDownTime = 500; mCurrentPosition = 1; mNumHumansFinished = 0; // Temp structures for turbo-on-start hack int aiIndices[ 3 ]; int numAIs = 0; int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { int controllerID = GetInputManager()->GetControllerIDforPlayer( i ); if( controllerID != -1 ) { GetInputManager()->GetController( controllerID )->SetGameState( Input::ACTIVE_ALL ); GetInputManager()->GetController( controllerID )->SetRumble( GetInputManager()->IsRumbleEnabled() ); } else { if( mVehicleSlots[ i ].mVehicleAI != NULL ) { mVehicleSlots[ i ].mVehicleAI->SetActive( true ); // Remember this AI index for turbo-on-start hack just below.. aiIndices[ numAIs ] = i; numAIs++; } } } ///////////////////////// // HACK: // For each AI, it has a "m-in-n" chance to turbo at the start. // This helps to avoid cluttering at the start, as well as adds // life to the game. // const int MAX_AIS_DOING_TURBO = numAIs - 1; int numAIsDoingTurbo = 0; for( int j=0; jUseTurbo(); numAIsDoingTurbo++; } } else { break; } } // If more than one AI, at least ONE AI will need to do turbo // so there's no cluttering near the start... if( numAIs > 1 && numAIsDoingTurbo == 0 ) { int randAI = rand() % numAIs; rAssert( 0 <= aiIndices[randAI] && aiIndices[randAI] < SuperSprintData::NUM_PLAYERS ); mVehicleSlots[ aiIndices[randAI] ].mVehicleAI->UseTurbo(); } ////////////////////////////// GetEventManager()->TriggerEvent( EVENT_FE_MENU_SELECT ); //record the starting time mStartTime = GET_TIME; SetState( RACING ); } // // Reuse the menu select sound for a countdown sound // newTimeSecs = mCountDownTime / 1000; if( oldTimeSecs != newTimeSecs ) { GetEventManager()->TriggerEvent( EVENT_FE_MENU_SELECT ); } break; } case RACING: { //Watch to see who crosses the finish line first! if ( mCountDownTime - static_cast(milliseconds) <= 0 ) { mDrawable->SetRenderState( SuperSprintDrawable::NONE ); mDrawable->SetTextScale( 1.0f ); mCountDownTime = 0; } else { mCountDownTime -= milliseconds; } break; } case DNF_TIMEOUT: { oldTimeSecs = mCountDownTime / 1000; if ( mCountDownTime - static_cast(milliseconds) <= 0 ) { //mDrawable->SetRenderState( SuperSprintDrawable::PLAYER_DATA ); //mDrawable->SetTextScale( 1.0f ); GetEventManager()->TriggerEvent( EVENT_FE_MENU_SELECT ); SetState( WINNER_CIRCLE ); mCountDownTime = 0; mDrawable->SetRenderState( SuperSprintDrawable::NONE ); DisableAllAI(); DisableAllControllers(); } else { mCountDownTime -= milliseconds; } sprintf( mTime, "%d", mCountDownTime / 1000 ); // // Reuse the menu select sound for a countdown sound // newTimeSecs = mCountDownTime / 1000; if( oldTimeSecs != newTimeSecs ) { GetEventManager()->TriggerEvent( EVENT_FE_MENU_SELECT ); } break; } case WINNER_CIRCLE: { //Display the winner! GetInputManager()->SetGameState( Input::ACTIVE_SS_GAME ); // go to Race Summary screen // GetGameFlow()->GetContext( CONTEXT_SUPERSPRINT )->Suspend(); GetGuiSystem()->GotoScreen( CGuiWindow::GUI_SCREEN_ID_MINI_SUMMARY, 0, 0, CLEAR_WINDOW_HISTORY ); //Calculate your score int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if ( mPositions[ i ] == 1 ) { mPlayers[ i ].mWins++; // // We've found a winner. Send the win/lose sound events // if( mVehicleSlots[i].mIsHuman ) { GetEventManager()->TriggerEvent( EVENT_SUPERSPRINT_WIN ); } else { GetEventManager()->TriggerEvent( EVENT_SUPERSPRINT_LOSE ); } } if ( mPlayers[ i ].mPosition == 0 ) { mPlayers[ i ].mPoints += 0; //Joel made me set it to 0 } else { mPlayers[ i ].mPoints += 5 - mPositions[ i ]; } } SetState( IDLE ); break; } default: { break; } } } //============================================================================= // SuperSprintManager::LoadScriptData //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::LoadScriptData() { HeapMgr()->PushHeap( GMA_LEVEL_OTHER ); // I choose other because this stuff will exist longer than a single mission char name[64]; sprintf( name, "scripts\\ssi.mfk" ); GetMissionScriptLoader()->SetFileHander( FILEHANDLER_LEVEL ); GetMissionScriptLoader()->LoadScriptAsync( name ); //Also load the carstarts and stuff. sprintf( name, "art\\B0%ddata.p3d", GetCurrentLevelIndex() ); //Hackish GetLoadingManager()->AddRequest( FILEHANDLER_LEVEL, name, GMA_LEVEL_OTHER ); HeapMgr()->PopHeap( GMA_LEVEL_OTHER ); //MOve this here so the car con files get loaded in time. SetUpCars(); GetLoadingManager()->AddCallback( this ); } //============================================================================= // SuperSprintManager::StartRace //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::StartRace() { PositionCars(); PositionAI(); InitRaceData(); PlaceCharactersInCars(); //TODO: texas scramble mCountDownTime = 5000; mDrawable->SetRenderState( SuperSprintDrawable::COUNT_DOWN ); mDrawable->SetTextScale( 1.0f ); InitCamera(); SetupTraps(); //Only do this once. PlayIntroCam(); SetState( COUNT_DOWN ); } //============================================================================= // SuperSprintManager::SetCharacter //============================================================================= // Description: Comment // // Parameters: ( int playerID, const char* name ) // // Return: void // //============================================================================= void SuperSprintManager::SetCharacter( int playerID, int index ) { mPlayers[ playerID ].mCharacterIndex = index; } //============================================================================= // SuperSprintManager::SetVehicle //============================================================================= // Description: Comment // // Parameters: ( int playerID, const char* name ) // // Return: void // //============================================================================= void SuperSprintManager::SetVehicle( int playerID, const char* name ) { rAssert( playerID >= 0 && playerID < SuperSprintData::NUM_PLAYERS ); strncpy( mVehicleSlots[ playerID ].mCarName, name, sizeof( mVehicleSlots[ playerID ].mCarName ) ); } //============================================================================= // SuperSprintManager::FindLeader //============================================================================= // Description: Comment // // Parameters: () // // Return: char // //============================================================================= char SuperSprintManager::FindLeader() { char leader = -1; unsigned char numLaps = 0; char nextCheckpoint = -1; //For now just figure out who's in the lead. char i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if ( mPlayers[ i ].mNumLaps > numLaps ) { //This guy is in the lead. leader = i; numLaps = mPlayers[ i ].mNumLaps; nextCheckpoint = mPlayers[ i ].mNextCheckPoint; } else if ( mPlayers[ i ].mNumLaps == numLaps ) { if ( mPlayers[ i ].mNextCheckPoint > nextCheckpoint ) { //This guys is in the lead. leader = i; numLaps = mPlayers[ i ].mNumLaps; nextCheckpoint = mPlayers[ i ].mNextCheckPoint; } } } return leader; } //============================================================================= // SuperSprintManager::CalculatePositions //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::CalculatePositions() { #if defined( RAD_DEBUG ) || defined( RAD_TUNE ) char errMsg[128]; #endif int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; i++ ) { if ( mPlayers[ i ].mNumLaps == mNumLaps ) { //No more updates for this guy. continue; } if ( !mVehicleSlots[ i ].mIsHuman ) { WaypointAI* ai = mVehicleSlots[ i ].mVehicleAI; rmt::Vector aiPos; ai->GetPosition( &aiPos ); /* // reset as necessary. rmt::Sphere aiSphere; ai->GetVehicle()->GetBoundingSphere( &aiSphere ); SuperCam* superCam = GetSuperCamManager()->GetSCC(0)->GetActiveSuperCam(); rAssert( superCam ); if( superCam->GetType() == SuperCam::SUPER_SPRINT_CAM && !superCam->GetCamera()->SphereVisible( aiPos, aiSphere.radius ) ) { ai->GetVehicle()->ResetOnSpot( false ); } */ ////////////////////////////////////////////////////// // Query the road manager to get the distance RoadManager::PathElement aiElem; aiElem.elem = NULL; RoadSegment* aiSeg = NULL; float aiSegT = 0.0f; float aiRoadT = 0.0f; ai->GetRacePathInfo( aiElem, aiSeg, aiSegT, aiRoadT ); // make sure the AI is on a path element #if defined( RAD_DEBUG ) || defined( RAD_TUNE ) sprintf( errMsg, "Something wrong with player %d!\n", i+1 ); rTuneAssertMsg( aiElem.elem != NULL, errMsg ); rTuneAssertMsg( 0 <= mPlayers[ i ].mNextCheckPoint && mPlayers[ i ].mNextCheckPoint < GetNumCheckpoints(), errMsg ); #endif char nextCheckpoint = mCheckPoints[ mPlayers[ i ].mNextCheckPoint ]; int path = GetPathDataWith( GetCheckpointWith( nextCheckpoint ) ); rAssert( path != -1 ); RoadManager::PathElement collectibleElem = mPathData[ path ].closestElem; float collectibleRoadT = mPathData[ path ].roadT; rmt::Vector collectiblePos; mPathData[ path ].loc->GetLocation( &collectiblePos ); // make sure the collectible is on a path element rAssert( collectibleElem.elem != NULL ); float aiDistToColl = NEAR_INFINITY; if( aiElem.elem != NULL && collectibleElem.elem != NULL ) { SwapArray dummy; HeapMgr()->PushHeap(GMA_TEMP); dummy.Allocate( RoadManager::GetInstance()->GetMaxPathElements() ); HeapMgr()->PopHeap(GMA_TEMP); aiDistToColl = RoadManager::GetInstance()->FindPathElementsBetween( false, aiElem, aiRoadT, aiPos, collectibleElem, collectibleRoadT, collectiblePos, dummy ); } ai->SetDistToCurrentCollectible( aiDistToColl ); mPlayers[ i ].mDistToCheckpoint = aiDistToColl; } else { //////////////////////////////////////////////////////// // Find out player's dist to mNextCollectible // Avatar* player = GetAvatarManager()->GetAvatarForPlayer( i ); rAssert( player ); rmt::Vector playerPos; player->GetPosition( playerPos ); /* // if player has gone out of bounds, reset to nearest segment rmt::Sphere playerSphere; player->GetVehicle()->GetBoundingSphere( &playerSphere ); SuperCam* superCam = GetSuperCamManager()->GetSCC(0)->GetActiveSuperCam(); rAssert( superCam ); if( superCam->GetType() == SuperCam::SUPER_SPRINT_CAM && !superCam->GetCamera()->SphereVisible( playerPos, playerSphere.radius ) ) { player->GetVehicle()->ResetOnSpot( false ); player->mHasBeenUpdatedThisFrame = false; } */ RoadManager::PathElement playerElem; playerElem.elem = NULL; RoadSegment* playerSeg = NULL; float playerSegT = 0.0f; float playerRoadT = 0.0f; player->GetLastPathInfo( playerElem, playerSeg, playerSegT, playerRoadT ); #if defined( RAD_DEBUG ) || defined( RAD_TUNE ) rTuneAssertMsg( playerElem.elem != NULL, errMsg ); rTuneAssertMsg( 0 <= mPlayers[ i ].mNextCheckPoint && mPlayers[ i ].mNextCheckPoint < GetNumCheckpoints(), errMsg ); #endif char nextCheckpoint = mCheckPoints[ mPlayers[ i ].mNextCheckPoint ]; int path = GetPathDataWith( GetCheckpointWith( nextCheckpoint ) ); rAssert( path != -1 ); RoadManager::PathElement collectibleElem = mPathData[ path ].closestElem; float collectibleRoadT = mPathData[ path ].roadT; rmt::Vector collectiblePos; mPathData[ path ].loc->GetLocation( &collectiblePos ); // make sure the collectible is on a path element rAssert( collectibleElem.elem != NULL ); float playerDistToCurrCollectible = NEAR_INFINITY; if( playerElem.elem != NULL && collectibleElem.elem != NULL ) { SwapArray dummy; HeapMgr()->PushHeap(GMA_TEMP); dummy.Allocate( RoadManager::GetInstance()->GetMaxPathElements() ); HeapMgr()->PopHeap(GMA_TEMP); playerDistToCurrCollectible = RoadManager::GetInstance()->FindPathElementsBetween( false, playerElem, playerRoadT, playerPos, collectibleElem, collectibleRoadT, collectiblePos, dummy ); } mPlayers[ i ].mDistToCheckpoint = playerDistToCurrCollectible; } } //////////////////////////////////////////////////////////////////// // Update my position // unsigned int j; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if ( mPlayers[ i ].mNumLaps == mNumLaps ) { //No more updates for this guy. continue; } unsigned int numInFront = 0; unsigned int vehiclesWithMe[ SuperSprintData::NUM_PLAYERS ]; unsigned int numWithMe = 0; unsigned int numFinished = 0; int whichOtherPlayer = (i + 1) % SuperSprintData::NUM_PLAYERS; for( j = 0; j < SuperSprintData::NUM_PLAYERS - 1; ++j ) { int numLapsCompleted = mPlayers[ whichOtherPlayer ].mNumLaps; if ( numLapsCompleted == mNumLaps ) { //They're finshed racing numFinished++; } else if ( numLapsCompleted > mPlayers[ i ].mNumLaps ) { //This guys finished more laps than I. numInFront++; } else if ( numLapsCompleted == mPlayers[ i ].mNumLaps ) { //We're racing the same lap number. char currCollectible = mPlayers[ whichOtherPlayer ].mNextCheckPoint; char playerCollectible = mPlayers[ i ].mNextCheckPoint; if( currCollectible > playerCollectible ) { numInFront++; } else if( currCollectible == playerCollectible ) { vehiclesWithMe[ numWithMe ] = whichOtherPlayer; numWithMe++; } } whichOtherPlayer = ( whichOtherPlayer + 1 ) % SuperSprintData::NUM_PLAYERS; } mPositions[ i ] = 1 + numInFront + numFinished; //Now, who is actually in front of me going to the same waypoint? const Locator* waypointLoc = GetCheckpointWith( mCheckPoints[ mPlayers[ i ].mNextCheckPoint ] ); if ( !waypointLoc ) { rAssert( false ); //Why? Because we've not started to race yet. return; } //////////////////////////////////////////////////////////// // The last set of vehicles to consider are the ones that // are headed to the same collectible (race checkpoint) and // are in the same lap as we are... // for( j = 0; j < numWithMe; ++j ) { int index = vehiclesWithMe[ j ]; //This guy and I are racing for the same collectible //Test the dist to the collectible. float aiDistToCurrCollectible = mPlayers[ index ].mDistToCheckpoint; float playerDistToCurrCollectible = mPlayers[ i ].mDistToCheckpoint; if( aiDistToCurrCollectible < playerDistToCurrCollectible ) { // blast! he's ahead of me... my pos is thus bumped even lower... mPositions[ i ] = mPositions[ i ] + 1; } } } } //============================================================================= // SuperSprintManager::LoadLevelData //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::LoadLevelData() { char name[64]; sprintf( name, "scripts\\ss.mfk" ); BillboardWrappedLoader::OverrideLoader( true ); HeapMgr()->PushHeap( GMA_LEVEL_OTHER ); // I choose other because this stuff will exist longer than a single mission GetMissionScriptLoader()->SetFileHander( FILEHANDLER_LEVEL ); GetMissionScriptLoader()->LoadScriptAsync( name ); HeapMgr()->PopHeap( GMA_LEVEL_OTHER ); BillboardWrappedLoader::OverrideLoader( false ); } //============================================================================= // SuperSprintManager::Reset //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::Reset() { //Reset the same race with all the existing cars and stuff. PositionCars(); PositionAI(); ResetRaceData(); mCountDownTime = 5000; mDrawable->SetRenderState( SuperSprintDrawable::COUNT_DOWN ); mDrawable->SetTextScale( 1.0f ); InitCamera(); PlayIntroCam(); SetState( COUNT_DOWN ); } //============================================================================= // SuperSprintManager::OnButton //============================================================================= // Description: Comment // // Parameters: ( int controllerId, int id, const Button* pButton ) // // Return: void // //============================================================================= void SuperSprintManager::OnButton( int controllerId, int id, const Button* pButton ) { } //============================================================================= // SuperSprintManager::OnButtonUp //============================================================================= // Description: Comment // // Parameters: ( int controllerId, int buttonId, const Button* pButton ) // // Return: void // //============================================================================= void SuperSprintManager::OnButtonUp( int controllerId, int buttonId, const Button* pButton ) { if ( buttonId == ShowPositions ) { int playerID = GetInputManager()->GetControllerPlayerIDforController( controllerId ); if ( playerID >= 0 && playerID < SuperSprintData::NUM_PLAYERS ) { mTogglePosition[ playerID ] = false; } } } //============================================================================= // SuperSprintManager::OnButtonDown //============================================================================= // Description: Comment // // Parameters: ( int controllerId, int buttonId, const Button* pButton ) // // Return: void // //============================================================================= void SuperSprintManager::OnButtonDown( int controllerId, int buttonId, const Button* pButton ) { switch ( mCurrentState ) { case RACING: { int playerID = GetInputManager()->GetControllerPlayerIDforController( controllerId ); if ( playerID == -1 ) { playerID = controllerId; rAssert( playerID < SuperSprintData::NUM_PLAYERS ); if( playerID >= SuperSprintData::NUM_PLAYERS ) { return; } } int controllerIDPlayer = GetInputManager()->GetControllerIDforPlayer( playerID ); if ( buttonId == CamSelect && mVehicleSlots[ playerID ].mIsHuman && !GetGameFlow()->GetContext( CONTEXT_SUPERSPRINT )->IsSuspended()) { unsigned int playerCount = 0; int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if ( mVehicleSlots[ i ].mIsHuman ) { ++playerCount; } } if ( playerCount == 1 ) { GetSuperCamManager()->GetSCC( 0 )->SetTarget( mVehicleSlots[ playerID ].mVehicle ); if ( GetSuperCamManager()->GetSCC( 0 )->GetActiveSuperCam()->GetType() == SuperCam::WRECKLESS_CAM ) { //Skip the animated cams. GetSuperCamManager()->GetSCC( 0 )->SelectSuperCam( (unsigned int)0 ); } else { GetSuperCamManager()->GetSCC( 0 )->ToggleSuperCam( true ); } } } break; } default: { break; } } if ( buttonId == ShowPositions ) { int playerID = GetInputManager()->GetControllerPlayerIDforController( controllerId ); if ( playerID >= 0 && playerID < SuperSprintData::NUM_PLAYERS ) { mTogglePosition[ playerID ] = true; } } } //============================================================================= // SuperSprintManager::LoadControllerMappings //============================================================================= // Description: Comment // // Parameters: ( unsigned int controllerId ) // // Return: void // //============================================================================= void SuperSprintManager::LoadControllerMappings( unsigned int controllerId ) { if ( GetInputManager()->GetController( controllerId )->IsConnected() ) { #ifdef RAD_XBOX ClearMap(0); Map( "Start", Start, 0, controllerId ); Map( "A", Select, 0, controllerId ); Map( "B", Back, 0, controllerId ); Map( "DPadRight", Right, 0, controllerId ); Map( "DPadLeft", Left, 0, controllerId ); Map( "LeftStickX", StickX, 0, controllerId ); Map( "LeftTrigger", L1, 0, controllerId ); Map( "Black", CamSelect, 0, controllerId ); Map( "Y", ShowPositions, 0, controllerId ); #endif #ifdef RAD_PS2 ClearMap(0); Map( "Start", Start, 0, controllerId ); Map( "X", Select, 0, controllerId ); Map( "Triangle", Back, 0, controllerId ); Map( "DPadRight", Right, 0, controllerId ); Map( "DPadLeft", Left, 0, controllerId ); Map( "LeftStickX", StickX, 0, controllerId ); Map( "L1", L1, 0, controllerId ); Map( "Select", CamSelect, 0, controllerId ); Map( "Triangle", ShowPositions, 0, controllerId ); #endif #ifdef RAD_GAMECUBE ClearMap(0); Map( "Menu", Start, 0, controllerId ); Map( "A", Select, 0, controllerId ); Map( "B", Back, 0, controllerId ); Map( "DPadRight", Right, 0, controllerId ); Map( "DPadLeft", Left, 0, controllerId ); Map( "LeftStickX", StickX, 0, controllerId ); Map( "AnalogTriggerL", L1, 0, controllerId ); Map( "DPadDown", CamSelect, 0, controllerId ); Map( "Y", ShowPositions, 0, controllerId ); #endif #ifdef RAD_WIN32 ClearMap(0); Map( "Pause", Start, 0, controllerId ); Map( "Attack", Select, 0, controllerId ); Map( "Jump", Back, 0, controllerId ); Map( "MoveRight", Right, 0, controllerId ); Map( "MoveLeft", Left, 0, controllerId ); Map( "MoveX", StickX, 0, controllerId ); //Map( "LeftTrigger", L1, 0, controllerId ); Map( "CameraToggle", CamSelect, 0, controllerId ); #endif } } //============================================================================= // SuperSprintManager::OnControllerConnect //============================================================================= // Description: Comment // // Parameters: ( int id ) // // Return: void // //============================================================================= void SuperSprintManager::OnControllerConnect( int id ) { int playerID = GetInputManager()->GetControllerPlayerIDforController( id ); if ( playerID != -1 && mVehicleSlots[ playerID ].mState == SuperSprintData::CarData::SELECTED && static_cast( mPlayers[ playerID ].mNumLaps ) < mNumLaps && mVehicleSlots[ playerID ].mIsHuman && (mCurrentState == RACING || mCurrentState == DNF_TIMEOUT) ) { GetInputManager()->GetController( id )->SetGameState( Input::ACTIVE_ALL ); GetInputManager()->GetController( id )->SetRumble( GetInputManager()->IsRumbleEnabled() ); } else { GetInputManager()->GetController( id )->SetGameState( Input::ACTIVE_SS_GAME ); } } //============================================================================= // SuperSprintManager::OnControllerDisconnect //============================================================================= // Description: Comment // // Parameters: ( int id ) // // Return: void // //============================================================================= void SuperSprintManager::OnControllerDisconnect( int id ) { } //============================================================================= // SuperSprintManager::GetNumCheckpoints //============================================================================= // Description: Comment // // Parameters: () // // Return: char // //============================================================================= char SuperSprintManager::GetNumCheckpoints() { if ( mNumCheckPoints == 0 ) { if ( (RenderEnums::LevelEnum)(GetCurrentLevelIndex() + RenderEnums::B00) == RenderEnums::B02 || (RenderEnums::LevelEnum)(GetCurrentLevelIndex() + RenderEnums::B00) == RenderEnums::B07 ) { if ( mGoLeft ) { mCheckPoints = CHECKPOINT_LIST_B02_R; } else { mCheckPoints = CHECKPOINT_LIST_B02; } mNumCheckPoints = sizeof( CHECKPOINT_LIST_B02 ) / sizeof( char ); } else if ( (RenderEnums::LevelEnum)(GetCurrentLevelIndex() + RenderEnums::B00) == RenderEnums::B05 ) { if ( mGoLeft ) { mCheckPoints = CHECKPOINT_LIST_B05_R; } else { mCheckPoints = CHECKPOINT_LIST_B05; } mNumCheckPoints = sizeof( CHECKPOINT_LIST_B05 ) / sizeof( char ); } else if ( (RenderEnums::LevelEnum)(GetCurrentLevelIndex() + RenderEnums::B00) == RenderEnums::B01 ) { if ( mGoLeft ) { mCheckPoints = CHEKPOINT_LIST_B01_R; } else { mCheckPoints = CHEKPOINT_LIST_B01; } mNumCheckPoints = sizeof( CHEKPOINT_LIST_B01 ) / sizeof( char ); } else if ( ((RenderEnums::LevelEnum)(GetCurrentLevelIndex() + RenderEnums::B00) == RenderEnums::B03 ) || ((RenderEnums::LevelEnum)(GetCurrentLevelIndex() + RenderEnums::B00) == RenderEnums::B04 )|| ((RenderEnums::LevelEnum)(GetCurrentLevelIndex() + RenderEnums::B00) == RenderEnums::B06 ) ) { if ( mGoLeft ) { mCheckPoints = CHECKPOINT_LIST_B03_R; } else { mCheckPoints = CHECKPOINT_LIST_B03; } mNumCheckPoints = sizeof( CHECKPOINT_LIST_B03 ) / sizeof( char ); } else { if ( mGoLeft ) { mCheckPoints = CHECKPOINT_LIST_R; } else { mCheckPoints = CHECKPOINT_LIST; } mNumCheckPoints = sizeof( CHECKPOINT_LIST ) / sizeof( char ); } } return mNumCheckPoints; } //***************************************************************************** // // Protected Member Functions // //***************************************************************************** //***************************************************************************** // // Private Member Functions // //***************************************************************************** //============================================================================= // SuperSprintManager::SetUpCars //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::SetUpCars() { unsigned int conFileIndex = 1; for( int i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if ( mVehicleSlots[ i ].mState == SuperSprintData::CarData::SELECTED ) { mNumActivePlayers++; char* carName = mVehicleSlots[i].mCarName; //Why does this have to be non-const? if( mVehicleSlots[ i ].mIsHuman ) { mNumHumanPlayers++; mVehicleSlots[ i ].mVehicle = GetVehicleCentral()->InitVehicle( carName, true, NULL, VT_USER, VehicleCentral::FORCE_NO_DRIVER, false, // playercar - I think this is chucks thing for the character sheet false); // one of the few rare cases where we start in the car } else { char scriptName[64]; sprintf( scriptName, "bonus/bg%d_%d.con", GetCurrentLevelIndex(), conFileIndex ); mVehicleSlots[ i ].mVehicle = GetVehicleCentral()->InitVehicle( carName, true, scriptName, VT_AI, VehicleCentral::FORCE_NO_DRIVER, false, false ); // see comments above ++conFileIndex; } rAssert( mVehicleSlots[ i ].mVehicle ); mVehicleSlots[ i ].mVehicle->AddRef(); int added = GetVehicleCentral()->AddVehicleToActiveList( mVehicleSlots[ i ].mVehicle ); rAssert( added != -1 ); mVehicleSlots[ i ].mActiveListIndex = added; } if( mVehicleSlots[ i ].mVehicle != NULL ) { GetSuperCamManager()->GetSCC( i )->SetTarget( mVehicleSlots[ i ].mVehicle ); GetSoundManager()->LoadCarSound( mVehicleSlots[ i ].mVehicle, false ); } } } //============================================================================= // SuperSprintManager::CleanUpCars //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::CleanUpCars() { int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if ( mVehicleSlots[ i ].mVehicle != NULL ) { // drop character out of the car... Character* playerCharacter = GetAvatarManager()->GetAvatarForPlayer( i )->GetCharacter(); //PlaceCharacterAtLocator( playerCharacter, this->m ); GetAvatarManager()->PutCharacterOnGround( playerCharacter, mVehicleSlots[ i ].mVehicle ); GetVehicleCentral()->RemoveVehicleFromActiveList( mVehicleSlots[ i ].mVehicle ); mVehicleSlots[ i ].mVehicle->Release(); mVehicleSlots[ i ].mVehicle = NULL; } if( mVehicleSlots[ i ].mVehicleAI != NULL ) { rAssert( mVehicleSlots[ i ].mActiveListIndex != -1 ); GetVehicleCentral()->SetVehicleController( mVehicleSlots[ i ].mActiveListIndex, NULL ); mVehicleSlots[ i ].mVehicleAI->SetActive( false ); mVehicleSlots[ i ].mVehicleAI->Finalize(); mVehicleSlots[ i ].mVehicleAI->Release(); mVehicleSlots[ i ].mVehicleAI = NULL; } mVehicleSlots[ i ].mActiveListIndex = -1; } //Dump the car geo. p3d::pddi->DrawSync(); for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { p3d::inventory->RemoveSectionElements( mVehicleSlots[ i ].mCarName ); p3d::inventory->DeleteSection( mVehicleSlots[ i ].mCarName ); } mNumActivePlayers = 0; mNumHumanPlayers = 0; mNumHumansFinished = 0; } //============================================================================= // SuperSprintManager::PositionCars //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::PositionCars() { unsigned int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { // figure out the start position ... char carlocator[32]; sprintf( carlocator, "car%d", i + 1 ); CarStartLocator* loc = p3d::find(carlocator); rAssert( loc ); if ( loc ) { rmt::Vector pos; float facing; loc->GetLocation( &pos ); facing = loc->GetRotation(); if ( mGoLeft ) { //We go Left. facing += rmt::PI; } rAssert( mVehicleSlots[ i ].mVehicle ); mVehicleSlots[ i ].mVehicle->SetInitialPosition( &pos ); mVehicleSlots[ i ].mVehicle->SetResetFacingInRadians( facing ); mVehicleSlots[ i ].mVehicle->Reset(); } } DisableAllControllers(); } //============================================================================= // SuperSprintManager::PositionAI //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::PositionAI() { /////////////////////////////////////////////////// // Go through all the waypoints, accumulating them... // Locator* waypoints[ MAX_AI_WAYPOINTS ]; int nWaypoints = 0; // can either drive left around the track or right around the track char waypointDir[4]; if( mGoLeft ) { sprintf( waypointDir, "WPL" ); } else { sprintf( waypointDir, "WPR" ); } // iterate from 1 to MAX_AI_WAYPOINTS (inclusive) char waypointName[8]; unsigned int i; for( i = 1; i <= MAX_AI_WAYPOINTS; ++i ) { if( i < 10 ) { sprintf( waypointName, "%s0%d", waypointDir, i ); } else { rAssert( i < 100 ); // keep it to 2 digits sprintf( waypointName, "%s%d", waypointDir, i ); } waypointName[5] = '\0'; Locator* wayloc = p3d::find( waypointName ); if( wayloc == NULL ) { // well... no more waypoints, just quit break; } waypoints[ nWaypoints ] = wayloc; nWaypoints++; } if( nWaypoints <= 0 ) { rDebugPrintf( "SUPERSPRINT WARNING: Uh... We didn't see any waypoints" "for AI. AI-controlled vehicles will not budge.\n" ); } mNumCheckPointLocators = 0; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { // Put in the AI here... const float smallTriggerRadius = 7.0f; if( !mVehicleSlots[ i ].mIsHuman ) { if ( mVehicleSlots[ i ].mVehicleAI == NULL ) { mVehicleSlots[ i ].mVehicleAI = new WaypointAI( mVehicleSlots[ i ].mVehicle, false, smallTriggerRadius, true ); // indicate false to segment optimization mVehicleSlots[ i ].mVehicleAI->SetUseMultiplier( false ); // no traffic in supersprint... no need for multiplier mVehicleSlots[ i ].mVehicleAI->AddRef(); // Corresponding call to Release() will already call delete if refcount<=1 } else { //Cleanup to restart mVehicleSlots[ i ].mVehicleAI->Finalize(); } mVehicleSlots[ i ].mVehicleAI->Initialize(); // Just before this, we obtained a list of waypoints... // Add them to the AIs here for( int j=0; j(mVehicleSlots[ i ].mVehicleAI)->AddWaypoint( waypoints[j] ); } } } DisableAllAI(); p3d::inventory->PushSection(); p3d::inventory->SelectSection( "Level" ); HeapMgr()->PushHeap( GMA_TEMP ); tInventory::Iterator it( p3d::inventory ); EventLocator* loc = it.First(); while( loc != NULL ) { if ( loc->GetEventType() == LocatorEvent::CHECK_POINT && loc->GetData() > 0 ) { mCheckPointLocators[ mNumCheckPointLocators ] = loc; //mCheckPointLocators[ mNumCheckPointLocators ]->AddRef(); ++mNumCheckPointLocators; } loc = it.Next(); } HeapMgr()->PopHeap( GMA_TEMP ); p3d::inventory->PopSection(); for( i = 0; i < mNumCheckPointLocators; i++ ) { rAssert( mCheckPointLocators[ i ] != NULL ); rmt::Vector locPos; mCheckPointLocators[ i ]->GetPosition( &locPos ); ////////////////////////////////////////////////// // Get what the locator was placed on & other info // // NOTE: We assume that a collectible isn't going to move.. // and that it's always either on a road segment or // an intersection... This is safe to do because // the information below is only going to be used // for race objectives (a subclass of collectibleobjective) // which requires that its collectibles don't move around. // It's not that bad to fix it if this changes... we // will simply need to re-invoke FindClosestPathElement // every frame, as the collectible moves around and // remember the last valid (non-off-road) values. // RoadSegment* seg = NULL; float segT = 0.0f; float roadT = 0.0f; RoadManager::PathElement closestElem; closestElem.elem = NULL; bool succeeded = VehicleAI::FindClosestPathElement( locPos, closestElem, seg, segT, roadT, true ); if( !succeeded ) { char msg[512]; sprintf( msg, "Locator at (%0.1f,%0.1f,%0.1f) must either be placed on a roadsegment " "or in an intersection! Woe be the designer who placed down this locator! " "For now, the closest road segment will be chosen instead.\n", locPos.x, locPos.y, -1 * locPos.z ); rAssertMsg( false, msg ); RoadSegment* closestSeg = NULL; float dummy; GetIntersectManager()->FindClosestRoad( locPos, 100.0f, closestSeg, dummy ); seg = (RoadSegment*) closestSeg; segT = RoadManager::DetermineSegmentT( locPos, seg ); roadT = RoadManager::DetermineRoadT( seg, segT ); closestElem.elem = seg->GetRoad(); closestElem.type = RoadManager::ET_NORMALROAD; } mPathData[ i ].closestElem = closestElem; mPathData[ i ].seg = seg; mPathData[ i ].segT = segT; mPathData[ i ].roadT = roadT; mPathData[ i ].loc = mCheckPointLocators[ i ]; rAssert( mPathData[ i ].closestElem.elem != NULL ); } } //============================================================================= // SuperSprintManager::DisableAllAI //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::DisableAllAI() { unsigned int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if ( !mVehicleSlots[ i ].mIsHuman ) { mVehicleSlots[ i ].mVehicleAI->SetActive( false ); } } } //============================================================================= // SuperSprintManager::DisableAllControllers //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::DisableAllControllers() { GetInputManager()->SetGameState( Input::ACTIVE_SS_GAME ); unsigned int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; i++ ) { int controllerID = GetInputManager()->GetControllerIDforPlayer( i ); if( controllerID != -1 ) { GetInputManager()->SetRumbleForDevice( controllerID, false ); } } } //============================================================================= // SuperSprintManager::InitRaceData //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::InitRaceData() { unsigned int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { //Reset the player race data. mPlayers[ i ].mBestLap = 0xffffffff; mPlayers[ i ].mBestLapEntry = 0; mPlayers[ i ].mBestTimeEntry = 0; mPlayers[ i ].mLapTime = 0; mPlayers[ i ].mNextCheckPoint = 0; mPlayers[ i ].mNumLaps = 0; mPlayers[ i ].mPosition = 0; mPlayers[ i ].mWins = 0; mPlayers[ i ].mRaceTime = 0; mPlayers[ i ].mPoints = 0; mPlayers[ i ].mDistToCheckpoint = NEAR_INFINITY; mVehicleSlots[ i ].mVehicle->mNumTurbos = SuperSprintData::DEFAULT_TURBO_NUM; mPositions[ i ] = i; } } //============================================================================= // SuperSprintManager::ResetRaceData //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::ResetRaceData() { unsigned int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { //Reset the player race data. mPlayers[ i ].mBestLap = 0xffffffff; mPlayers[ i ].mBestLapEntry = 0; mPlayers[ i ].mBestTimeEntry = 0; mPlayers[ i ].mLapTime = 0; mPlayers[ i ].mNextCheckPoint = 0; mPlayers[ i ].mNumLaps = 0; mPlayers[ i ].mPosition = 0; mPlayers[ i ].mRaceTime = 0; mPlayers[ i ].mDistToCheckpoint = NEAR_INFINITY; mVehicleSlots[ i ].mVehicle->mNumTurbos = SuperSprintData::DEFAULT_TURBO_NUM; mPositions[ i ] = i; } } //============================================================================= // SuperSprintManager::PlaceCharactersInCars //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::PlaceCharactersInCars() { int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if ( mVehicleSlots[ i ].mState == SuperSprintData::CarData::SELECTED ) { GetAvatarManager()->PutCharacterInCar( GetAvatarManager()->GetAvatarForPlayer( i )->GetCharacter(), mVehicleSlots[i].mVehicle ); if( !mVehicleSlots[ i ].mIsHuman ) { GetVehicleCentral()->SetVehicleController( mVehicleSlots[ i ].mActiveListIndex, mVehicleSlots[ i ].mVehicleAI ); } } } } //============================================================================= // SuperSprintManager::StartLoadingCars //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::LoadCars() { HeapMgr()->PushHeap( GMA_LEVEL_OTHER ); for( int i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { // Force unjoined positions to be AI-controlled if( mVehicleSlots[ i ].mState == SuperSprintData::CarData::WAITING ) { //Let's randomly pick a car. unsigned int carNum = rand() % SuperSprintData::NUM_NAMES; while ( strcmp( SuperSprintData::VEHICLE_NAMES[ carNum ].name, mVehicleSlots[ (i + 1) % SuperSprintData::NUM_PLAYERS ].mCarName ) == 0 || strcmp( SuperSprintData::VEHICLE_NAMES[ carNum ].name, mVehicleSlots[ (i + 2) % SuperSprintData::NUM_PLAYERS ].mCarName ) == 0 || strcmp( SuperSprintData::VEHICLE_NAMES[ carNum ].name, mVehicleSlots[ (i + 3) % SuperSprintData::NUM_PLAYERS ].mCarName ) == 0 ) { carNum = rand() % SuperSprintData::NUM_NAMES; } SetVehicle( i, SuperSprintData::VEHICLE_NAMES[ carNum ].name ); // transit to SELECTED, so that our car will get loaded, below mVehicleSlots[ i ].mState = SuperSprintData::CarData::SELECTED; } //Force undecided players to the current selection. if ( mVehicleSlots[ i ].mState == SuperSprintData::CarData::SELECTING ) { mVehicleSlots[ i ].mState = SuperSprintData::CarData::SELECTED; } if ( mVehicleSlots[ i ].mState == SuperSprintData::CarData::SELECTED ) { char fileName[64]; sprintf( fileName, "art\\cars\\%s.p3d", mVehicleSlots[ i ].mCarName ); p3d::inventory->AddSection( mVehicleSlots[ i ].mCarName ); GetLoadingManager()->AddRequest( FILEHANDLER_LEVEL, fileName, GMA_LEVEL_OTHER, mVehicleSlots[ i ].mCarName, mVehicleSlots[ i ].mCarName ); } } //When we get this callback, the loading of all cars is done. // GetLoadingManager()->AddCallback( this ); HeapMgr()->PopHeap( GMA_LEVEL_OTHER ); mDrawable->DoCountDownToo( false ); } //============================================================================= // SuperSprintManager::LoadCharacters //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::LoadCharacters() { unsigned int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if ( !mVehicleSlots[ i ].mIsHuman ) { //We need to select a character for this AI. unsigned int whichName = rand() % SuperSprintData::NUM_CHARACTER_NAMES; unsigned int j; for ( j = 0; j < SuperSprintData::NUM_CHARACTER_NAMES; ++j ) { bool found = false; unsigned int k; for ( k = 0; k < SuperSprintData::NUM_PLAYERS && !found; ++k ) { if ( SuperSprintData::CHARACTER_NAMES[ mPlayers[ k ].mCharacterIndex ] != '\0' && ( mPlayers[ k ].mCharacterIndex == static_cast( whichName ) ) ) { //This name is taken. found = true; break; } } if ( found ) { whichName = ( whichName + 1 ) % SuperSprintData::NUM_CHARACTER_NAMES; } else { //We have a winner! break; } } rAssert( j < SuperSprintData::NUM_CHARACTER_NAMES ); SetCharacter( i, whichName ); } GetCharacterManager()->AddPCCharacter( SuperSprintData::CHARACTER_NAMES[ mPlayers[ i ].mCharacterIndex ], "npd" ); } } //============================================================================= // SuperSprintManager::EnumerateControllers //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::EnumerateControllers() { //Set up the controllers. InputManager* im = GetInputManager(); unsigned int i; for ( i = 0; i < Input::MaxControllers; ++i ) { im->UnregisterMappable( i, this ); } for ( i = 0; i < Input::MaxControllers; ++i ) { int handle = im->RegisterMappable( i, this ); rAssert( handle != -1 ); } } //============================================================================= // SuperSprintManager::SetupIcons //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::SetupIcons() { //Get and init the two flags. mFFlag->Init( "fflag", rmt::Vector( 3.0f, 6.0f, -40.0f ), false, false ); mFFlag->ScaleByCameraDistance( 1.0f, 3.0f, 10.0f, 100.0f ); mWFlag->Init( "wflag", rmt::Vector( 1.8f, 6.0f, -40.0f ), false, false ); mWFlag->ScaleByCameraDistance( 1.0f, 3.0f, 10.0f, 100.0f ); int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { char name[64]; sprintf( name, "MiniArrow%dr", i + 1 ); //Start at 1 mPositionIcon[ 0 ][ i ]->Init( name, rmt::Vector( 0.0f, 0.0f, 0.0f ), true, false ); mPositionIcon[ 0 ][ i ]->ScaleByCameraDistance( MIN_SCALE, MAX_SCALE, MIN_DIST, MAX_DIST ); sprintf( name, "MiniArrow%db", i + 1 ); //Start at 1 mPositionIcon[ 1 ][ i ]->Init( name, rmt::Vector( 0.0f, 0.0f, 0.0f ), true, false ); mPositionIcon[ 1 ][ i ]->ScaleByCameraDistance( MIN_SCALE, MAX_SCALE, MIN_DIST, MAX_DIST ); sprintf( name, "MiniArrow%dy", i + 1 ); //Start at 1 mPositionIcon[ 2 ][ i ]->Init( name, rmt::Vector( 0.0f, 0.0f, 0.0f ), true, false ); mPositionIcon[ 2 ][ i ]->ScaleByCameraDistance( MIN_SCALE, MAX_SCALE, MIN_DIST, MAX_DIST ); sprintf( name, "MiniArrow%dg", i + 1 ); //Start at 1 mPositionIcon[ 3 ][ i ]->Init( name, rmt::Vector( 0.0f, 0.0f, 0.0f ), true, false ); mPositionIcon[ 3 ][ i ]->ScaleByCameraDistance( MIN_SCALE, MAX_SCALE, MIN_DIST, MAX_DIST ); sprintf( name, "MiniArrowP%d", i + 1 ); mPlayerID[ i ]->Init( name, rmt::Vector( 0.0f, 0.0f, 0.0f ), true, false ); mPlayerID[ i ]->ScaleByCameraDistance( MIN_SCALE, MAX_SCALE, MIN_DIST, MAX_DIST ); } char name[64]; sprintf( name, "MiniArrow%drGlow", 1 ); mNitroEffect[ 0 ]->Init( name, rmt::Vector( 0.0f, 0.0f, 0.0f ), true, false ); mNitroEffect[ 0 ]->ScaleByCameraDistance( MIN_SCALE, MAX_SCALE, MIN_DIST, MAX_DIST ); sprintf( name, "MiniArrow%dbGlow", 2 ); mNitroEffect[ 1 ]->Init( name, rmt::Vector( 0.0f, 0.0f, 0.0f ), true, false ); mNitroEffect[ 1 ]->ScaleByCameraDistance( MIN_SCALE, MAX_SCALE, MIN_DIST, MAX_DIST ); sprintf( name, "MiniArrow%dyGlow", 3 ); mNitroEffect[ 2 ]->Init( name, rmt::Vector( 0.0f, 0.0f, 0.0f ), true, false ); mNitroEffect[ 2 ]->ScaleByCameraDistance( MIN_SCALE, MAX_SCALE, MIN_DIST, MAX_DIST ); sprintf( name, "MiniArrow%dgGlow", 4 ); mNitroEffect[ 3 ]->Init( name, rmt::Vector( 0.0f, 0.0f, 0.0f ), true, false ); mNitroEffect[ 3 ]->ScaleByCameraDistance( MIN_SCALE, MAX_SCALE, MIN_DIST, MAX_DIST ); } //============================================================================= // SuperSprintManager::InitCamera //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::InitCamera() { for( int i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { SuperCamCentral* scc = GetSuperCamManager()->GetSCC( i ); rAssert( scc ); scc->SelectSuperCam( SuperCam::SUPER_SPRINT_CAM, SuperCamCentral::CUT | SuperCamCentral::QUICK, 0 ); } } int SuperSprintManager::GetOnlyHumanPlayerID() { int onlyHumanID = -1; int humanCount = 0; for( int i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { if( mVehicleSlots[ i ].mIsHuman ) { onlyHumanID = i; humanCount++; } } if( humanCount == 1 ) // only return the ID of the one human player { return onlyHumanID; } return -1; } //============================================================================= // SuperSprintManager::RestoreControllerState //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::RestoreControllerState() { unsigned int i; for ( i = 0; i < Input::MaxControllers; ++i ) { OnControllerConnect( i ); } } //============================================================================= // SuperSprintManager::SetupTraps //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::SetupTraps() { //Get the spikes if we need them if ( (RenderEnums::LevelEnum)(GetCurrentLevelIndex() + RenderEnums::B00) == RenderEnums::B07 ) { //Find the trap multicontroller. p3d::inventory->PushSection(); p3d::inventory->SelectSection( "Default" ); mTrapController = p3d::find( "spikes" ); mTrapController->AddRef(); //Set them running backwards so that it doesn't animate. mTrapController->SetAnimationDirection( -1.0f ); p3d::inventory->PopSection(); rAssert( mTrapController ); } else if ( (RenderEnums::LevelEnum)(GetCurrentLevelIndex() + RenderEnums::B00) == RenderEnums::B04 ) { //Find the trap multicontroller. p3d::inventory->PushSection(); p3d::inventory->SelectSection( "Default" ); mTrapController = p3d::find( "pistons" ); mTrapController->AddRef(); //Set them running backwards so that it doesn't animate. mTrapController->SetAnimationDirection( -1.0f ); p3d::inventory->PopSection(); rAssert( mTrapController ); } } //============================================================================= // SuperSprintManager::PlayIntroCam //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::PlayIntroCam() { AnimatedCam::SetMulticontroller( "minigamecam" ); AnimatedCam::SetCamera( "minigamecamShape" ); AnimatedCam::CheckPendingCameraSwitch(); AnimatedCam::SetCameraTransitionFlags( SuperCamCentral::CUT | SuperCamCentral::FORCE ); } //============================================================================= // SuperSprintManager::UpdatePositionIcons //============================================================================= // Description: Comment // // Parameters: ( unsigned int milliseconds ) // // Return: void // //============================================================================= void SuperSprintManager::UpdatePositionIcons( unsigned int milliseconds ) { CalculatePositions(); //Sort positions. int i, j; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { rmt::Vector carPos; mVehicleSlots[ i ].mVehicle->GetPosition( &carPos ); rmt::Box3D bbox; mVehicleSlots[ i ].mVehicle->GetBoundingBox( &bbox ); carPos.y = bbox.high.y; for ( j = 0; j < SuperSprintData::NUM_PLAYERS; ++j ) { mPositionIcon[ i ][ j ]->ShouldRender( false ); } mPlayerID[ i ]->ShouldRender( false ); mNitroEffect[ i ]->ShouldRender( false ); if ( mNumHumanPlayers == 1 ) { bool pressed = false; unsigned int k; for ( k = 0; k < SuperSprintData::NUM_PLAYERS; ++k ) { if ( mTogglePosition[ k ] && mVehicleSlots[ k ].mIsHuman ) { pressed = true; break; } } //If the toggle button is pressed, show all the positions if ( pressed ) { mPositionIcon[ i ][ mPositions[ i ] - 1 ]->Move( carPos ); mPositionIcon[ i ][ mPositions[ i ] - 1 ]->Update( milliseconds ); mPositionIcon[ i ][ mPositions[ i ] - 1 ]->ShouldRender( true ); } else { //If the camera is in top-view render otherwise don't if ( !mVehicleSlots[ i ].mIsHuman || GetSuperCamManager()->GetSCC( 0 )->GetActiveSuperCam()->GetType() == SuperCam::SUPER_SPRINT_CAM || GetSuperCamManager()->GetSCC( 0 )->GetActiveSuperCam()->GetType() == SuperCam::ANIMATED_CAM ) { if ( mVehicleSlots[ i ].mVehicle->mNumTurbos > 0 ) { mNitroEffect[ i ]->Move( carPos ); mNitroEffect[ i ]->Update( milliseconds ); mNitroEffect[ i ]->ShouldRender( true ); } else { mPlayerID[ i ]->Move( carPos ); mPlayerID[ i ]->Update( milliseconds ); mPlayerID[ i ]->ShouldRender( true ); } } } } else { //If the toggle button is pressed, show all the positions if ( mTogglePosition[ i ] && mVehicleSlots[ i ].mIsHuman ) { mPositionIcon[ i ][ mPositions[ i ] - 1 ]->Move( carPos ); mPositionIcon[ i ][ mPositions[ i ] - 1 ]->Update( milliseconds ); mPositionIcon[ i ][ mPositions[ i ] - 1 ]->ShouldRender( true ); } else { if ( mVehicleSlots[ i ].mVehicle->mNumTurbos > 0 ) { mNitroEffect[ i ]->Move( carPos ); mNitroEffect[ i ]->Update( milliseconds ); mNitroEffect[ i ]->ShouldRender( true ); } else { mPlayerID[ i ]->Move( carPos ); mPlayerID[ i ]->Update( milliseconds ); mPlayerID[ i ]->ShouldRender( true ); } } } } } //============================================================================= // SuperSprintManager::GetCheckpointWith //============================================================================= // Description: Comment // // Parameters: ( char data ) // // Return: Locator // //============================================================================= Locator* SuperSprintManager::GetCheckpointWith( char data ) { Locator* returnLoc = NULL; unsigned int i; for ( i = 0; i < mNumCheckPointLocators; ++i ) { if ( mCheckPointLocators[ i ]->GetData() == (unsigned int)data ) { returnLoc = mCheckPointLocators[ i ]; break; } } return returnLoc; } //============================================================================= // SuperSprintManager::GetPathDataWith //============================================================================= // Description: Comment // // Parameters: ( Locator* loc ) // // Return: int // //============================================================================= int SuperSprintManager::GetPathDataWith( Locator* loc ) { int i; for ( i = 0; i < MAX_AI_WAYPOINTS; ++i ) { if ( mPathData[ i ].loc == loc ) { return i; } } return -1; } //============================================================================= // SuperSprintManager::PositionCharacters //============================================================================= // Description: Comment // // Parameters: () // // Return: void // //============================================================================= void SuperSprintManager::PositionCharacters() { int i; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { char carlocator[32]; sprintf( carlocator, "car%d", i + 1 ); CarStartLocator* loc = p3d::find(carlocator); rAssert( loc ); if ( loc ) { Character* character = GetCharacterManager()->GetCharacterByName( tEntity::MakeUID( SuperSprintData::CHARACTER_NAMES[ mPlayers[ i ].mCharacterIndex ] ) ); rmt::Vector pos; loc->GetLocation( &pos ); character->RelocateAndReset( pos, 0.0f, true ); } } } //============================================================================= // SuperSprintManager::SuperSprintManager //============================================================================= // Description: Constructor. // // Parameters: None. // // Return: N/A. // //============================================================================= SuperSprintManager::SuperSprintManager() : Mappable( Input::ACTIVE_SS_GAME ), mCurrentState( IDLE ), mDrawable( NULL ), mCountDownTime( 3000 ), mCurrentPosition( 1 ), mStartTime( 0 ), mNumActivePlayers( 0 ), mNumHumanPlayers( 0 ), mNumHumansFinished( 0 ), mNumLaps( 1 ), mGoLeft( false ), mNumCheckPoints( 0 ), mCheckPoints( CHECKPOINT_LIST ), mFFlag( NULL ), mWFlag( NULL ), mFFlagTimeout( 0 ), mWFlagTimeout( 0 ), mTrapController( NULL ), mTrapTriggered( false ) { mGameType = GameplayManager::GT_SUPERSPRINT; SetNumPlayers( SuperSprintData::NUM_PLAYERS ); int i, j; for ( i = 0; i < SuperSprintData::NUM_PLAYERS; ++i ) { for ( j = 0; j < SuperSprintData::NUM_PLAYERS; ++j ) { mPositionIcon[ i ][ j ] = NULL; } mPlayerID[ i ] = NULL; mTogglePosition[ i ] = false; mNitroEffect[ i ] = NULL; } } //============================================================================= // SuperSprintManager::~SuperSprintManager //============================================================================= // Description: Destructor. // // Parameters: None. // // Return: N/A. // //============================================================================= SuperSprintManager::~SuperSprintManager() { }