diff options
Diffstat (limited to 'game/code/supersprint')
-rw-r--r-- | game/code/supersprint/allsupersprint.cpp | 3 | ||||
-rw-r--r-- | game/code/supersprint/supersprintdata.cpp | 94 | ||||
-rw-r--r-- | game/code/supersprint/supersprintdata.h | 151 | ||||
-rw-r--r-- | game/code/supersprint/supersprintdrawable.h | 524 | ||||
-rw-r--r-- | game/code/supersprint/supersprintmanager.cpp | 2668 | ||||
-rw-r--r-- | game/code/supersprint/supersprintmanager.h | 383 |
6 files changed, 3823 insertions, 0 deletions
diff --git a/game/code/supersprint/allsupersprint.cpp b/game/code/supersprint/allsupersprint.cpp new file mode 100644 index 0000000..d4354d1 --- /dev/null +++ b/game/code/supersprint/allsupersprint.cpp @@ -0,0 +1,3 @@ +#include <supersprint/supersprintmanager.cpp> +#include <supersprint/supersprintdata.cpp> + diff --git a/game/code/supersprint/supersprintdata.cpp b/game/code/supersprint/supersprintdata.cpp new file mode 100644 index 0000000..f691409 --- /dev/null +++ b/game/code/supersprint/supersprintdata.cpp @@ -0,0 +1,94 @@ +#include <supersprint/supersprintdata.h> + +const char* SuperSprintData::CHARACTER_NAMES[] = +{ + "lisa", + "bart", + "homer", + "marge", + "apu" +}; +const unsigned int SuperSprintData::NUM_CHARACTER_NAMES = sizeof( SuperSprintData::CHARACTER_NAMES ) / sizeof( SuperSprintData::CHARACTER_NAMES[0] ); + +const SuperSprintData::DisplayNames SuperSprintData::VEHICLE_NAMES[] = +{ + // + // SYNTAX: + // { "<vehicle name>", "<display name>" }, + // + { "snake_v", "" }, + { "bookb_v", "" }, + { "marge_v", "" }, + { "carhom_v", "" }, + { "krust_v", "" }, + { "bbman_v", "" }, + { "elect_v", "" }, + { "famil_v", "" }, + { "bart_v", "" }, + { "scorp_v", "" }, + { "honor_v", "" }, + { "hbike_v", "" }, + { "frink_v", "" }, + { "comic_v", "" }, + { "lisa_v", "" }, + { "smith_v", "" }, + { "mrplo_v", "" }, + { "fone_v", "" }, + { "cletu_v", "" }, + { "apu_v", "" }, + { "plowk_v", "" }, + { "wiggu_v", "" }, + { "otto_v", "" }, + { "moe_v", "" }, + { "skinn_v", "Sedan (Skinner - Lvl 3)" }, + { "homer_v", "" }, + { "zombi_v", "" }, + { "burns_v", "" }, + { "willi_v", "" }, + { "gramp_v", "" }, + { "gramR_v", "" }, + + { "atv_v", "" }, + { "knigh_v", "" }, + { "mono_v", "" }, + { "oblit_v", "" }, + { "hype_v", "" }, + { "rocke_v", "" }, + + { "cArmor", "" }, + { "cCellA", "" }, + { "cSedan", "" }, + { "cCola", "" }, + { "cCube", "" }, + { "cCurator", "" }, + { "cDonut", "" }, + { "cDuff", "" }, + { "cBlbart", "" }, + { "cHears", "" }, + { "cKlimo", "" }, + { "cLimo", "" }, + { "cMilk", "" }, + { "cNerd", "" }, + { "cNonup", "" }, + { "cPolice", "" }, + { "cVan", "" }, + { "cBone", "" }, + +// { "huskA", "Charred Husk (Traffic)" }, + { "compactA", "" }, + { "minivanA", "" }, + { "pickupA", "" }, + { "sedanA", "" }, + { "sedanB", "" }, + { "sportsA", "" }, + { "sportsB", "" }, + { "wagonA", "" }, + { "SUVA", "" }, + { "taxiA", "" }, + { "coffin", "" }, +// { "ship", "Ghost Ship (Halloween Traffic)" }, + { "hallo", "" }, +// { "witchcar", "Witch Broom (Halloween Traffic)" }, + +}; +const unsigned int SuperSprintData::NUM_NAMES = sizeof( SuperSprintData::VEHICLE_NAMES ) / sizeof( SuperSprintData::VEHICLE_NAMES[0] ); diff --git a/game/code/supersprint/supersprintdata.h b/game/code/supersprint/supersprintdata.h new file mode 100644 index 0000000..dc7e25b --- /dev/null +++ b/game/code/supersprint/supersprintdata.h @@ -0,0 +1,151 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: supersprintdata.h +// +// Description: Blahblahblah +// +// History: 2/8/2003 + Created -- Cary Brisebois +// +//============================================================================= + +#ifndef SUPERSPRINTDATA_H +#define SUPERSPRINTDATA_H + +//======================================== +// Nested Includes +//======================================== +#include <constants/maxplayers.h> + +#include <p3d/p3dtypes.hpp> + +//======================================== +// Forward References +//======================================== + +class Vehicle; +class WaypointAI; + +//============================================================================= +// +// Synopsis: Blahblahblah +// +//============================================================================= + +namespace SuperSprintData +{ + enum + { +#ifdef RAD_PS2 + NUM_PLAYERS = 4, +#else + NUM_PLAYERS = 4, +#endif + DEFAULT_TURBO_NUM = 3, + DEFAULT_NUM_LAPS = 3, + MIN_NUM_LAPS = 1, + MAX_NUM_LAPS = 5, + FLAG_TIMEOUT = 4000, + MAX_CHARACTER_NAME_LEN = 32 + }; + + struct CarData + { + enum State + { + WAITING, + SELECTING, + SELECTED + }; + + CarData() : + mVehicle( NULL ), + mVehicleAI( NULL ), + mState( WAITING ), + mActiveListIndex( -1 ), + mIsHuman(false) + { + mCarName[ 0 ] = '\0'; + }; + + Vehicle* mVehicle; + WaypointAI* mVehicleAI; + State mState; + char mCarName[ 16 ]; + int mActiveListIndex; + bool mIsHuman; + }; + + struct PlayerData + { + PlayerData() : + mLapTime( 0 ), + mBestLap( 0xffffffff ), + mRaceTime( 0 ), + mNumLaps( 0 ), + mPosition( 0 ), + mPoints( 0 ), + mWins( 0 ), + mNextCheckPoint( 0 ), + mBestTimeEntry( -1 ), + mBestLapEntry( -1 ), + mRacing( false ), + mCheated( false ), + mCharacterIndex( -1 ), + mDistToCheckpoint( 10000000.0f ) { mCharacterName[0] = '\0'; }; + + unsigned int mLapTime; + unsigned int mBestLap; + unsigned int mRaceTime; + unsigned char mNumLaps; + unsigned char mPosition; + unsigned char mPoints; + unsigned char mWins; + char mNextCheckPoint; + int mBestTimeEntry; + int mBestLapEntry; + bool mRacing; + bool mCheated; + char mCharacterName[MAX_CHARACTER_NAME_LEN]; + int mCharacterIndex; + float mDistToCheckpoint; + }; + + struct DisplayNames + { + const char* name; + const char* text; + }; + + extern const DisplayNames VEHICLE_NAMES[]; + extern const unsigned int NUM_NAMES; + + extern const char* CHARACTER_NAMES[]; + extern const unsigned int NUM_CHARACTER_NAMES; + + const tColour PLAYER_COLOURS[] = + { + tColour( 213, 74, 33 ), + tColour( 36, 232, 255 ), + tColour( 246, 255, 5 ), + tColour( 35, 209, 14 ), + + tColour( 0, 0, 0 ) // dummy terminator + }; + + struct HighScore + { + char name[4]; + unsigned int carNum; + unsigned int score; + enum { NUM_HIGH_SCORE = 10 }; + }; +}; + +//***************************************************************************** +// +//Inline Public Member Functions +// +//***************************************************************************** + +#endif //SUPERSPRINTDATA_H diff --git a/game/code/supersprint/supersprintdrawable.h b/game/code/supersprint/supersprintdrawable.h new file mode 100644 index 0000000..9eeca00 --- /dev/null +++ b/game/code/supersprint/supersprintdrawable.h @@ -0,0 +1,524 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: supersprintdrawable.h +// +// Description: Blahblahblah +// +// History: 2/8/2003 + Created -- Cary Brisebois +// +//============================================================================= + +#ifndef SUPERSPRINTDRAWABLE_H +#define SUPERSPRINTDRAWABLE_H + +//======================================== +// Nested Includes +//======================================== +#include <radmath/radmath.hpp> +#include <p3d/debugdraw.hpp> +#include <p3d/drawable.hpp> +#include <p3d/sprite.hpp> +#include <p3d/utility.hpp> +#include <p3d/texture.hpp> +#include <p3d/file.hpp> +#include <p3d/shader.hpp> +#include <p3d/matrixstack.hpp> +#include <p3d/memory.hpp> +#include <p3d/bmp.hpp> +#include <p3d/png.hpp> +#include <p3d/targa.hpp> +#include <p3d/font.hpp> +#include <p3d/texturefont.hpp> +#include <p3d/unicode.hpp> +#include <radfile.hpp> + +#include <string.h> + +#include <supersprint/supersprintdata.h> + +#include <mission/gameplaymanager.h> + +#include <camera/supercammanager.h> + +#include <debug/debuginfo.h> + +//======================================== +// Forward References +//======================================== + +extern unsigned char gFont[]; + +//============================================================================= +// +// Synopsis: Blahblahblah +// +//============================================================================= + +class SuperSprintDrawable : public tDrawable +{ +public: + SuperSprintDrawable(); + virtual ~SuperSprintDrawable(); + + void SetCarData( const SuperSprintData::CarData* carData ); + void SetPlayerData( const SuperSprintData::PlayerData* playerData ); + void SetCountDownMSG( const char* text ); + void SetTextScale( float scale ); + void DoCountDownToo( bool enable ); + + void Display(); + + enum RenderState + { + CAR_DATA, + PLAYER_DATA, + COUNT_DOWN, + HIGH_SCORES, + NONE + }; + + void SetRenderState( RenderState state ); + +private: + + const SuperSprintData::CarData* mCarData; + const SuperSprintData::PlayerData* mPlayerData; + + RenderState mRenderState; + + tTextureFont* mFont; + + const char* mCountDownText; + + float mTextScale; + + bool mCountDownToo; + + bool mILoadedThefont; + + inline void DisplayCarData(); + inline void DisplayPlayerData(); + inline void DisplayCountDown(); + inline void DisplayHighScores(); + + //Prevent wasteful constructor creation. + SuperSprintDrawable( const SuperSprintDrawable& supersprintdrawable ); + SuperSprintDrawable& operator=( const SuperSprintDrawable& supersprintdrawable ); +}; + +//***************************************************************************** +// +//Inline Public Member Functions +// +//***************************************************************************** + +//============================================================================= +// SuperSprintDrawable::SuperSprintDrawable +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: none +// +//============================================================================= +inline SuperSprintDrawable::SuperSprintDrawable() : + mCarData( NULL ), + mPlayerData( NULL ), + mRenderState( CAR_DATA ), + mFont( NULL ), + mCountDownText( NULL ), + mTextScale( 1.0f ), + mCountDownToo( false ), + mILoadedThefont( false ) +{ + p3d::inventory->PushSection(); + + p3d::inventory->SelectSection( "Default" ); + mFont = p3d::find<tTextureFont>("adlibn_20"); + + if ( mFont == NULL ) + { + tFileMem* file = new tFileMem( gFont , 61075 ); //HACK + file->AddRef(); + file->SetFilename("memfile.p3d"); + p3d::loadManager->GetP3DHandler()->Load( file, p3d::inventory ); + file->Release(); + + mILoadedThefont = true; + mFont = p3d::find<tTextureFont>("adlibn_20"); + } + + rAssert( mFont ); + + mFont->AddRef(); + tShader* fontShader = mFont->GetShader(); + fontShader->SetInt(PDDI_SP_BLENDMODE,PDDI_BLEND_ALPHA); + fontShader->SetInt(PDDI_SP_FILTER,PDDI_FILTER_BILINEAR); + + // Make the missing letter into somthing I can see + // + mFont->SetMissingLetter(p3d::ConvertCharToUnicode('j')); + + p3d::inventory->PopSection(); +} + +//============================================================================= +// ::~SuperSprintDrawable +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: none +// +//============================================================================= +inline SuperSprintDrawable::~SuperSprintDrawable() +{ + if ( mILoadedThefont ) + { +#ifndef DEBUGINFO_ENABLED + p3d::inventory->Remove( mFont ); //Debuginfo uses this too. +#endif + mILoadedThefont = false; + } + mFont->Release(); + mFont = NULL; +} + +//============================================================================= +// SuperSprintDrawable::SetCarData +//============================================================================= +// Description: Comment +// +// Parameters: ( const SuperSprintData::CarData* carData ) +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::SetCarData( const SuperSprintData::CarData* carData ) +{ + mCarData = carData; +} + +//============================================================================= +// SuperSprintDrawable::SetPlayerData +//============================================================================= +// Description: Comment +// +// Parameters: ( const SuperSprintData::PlayerData* playerData ) +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::SetPlayerData( const SuperSprintData::PlayerData* playerData ) +{ + mPlayerData = playerData; +} + +//============================================================================= +// SuperSprintDrawable::SetCountDownMSG +//============================================================================= +// Description: Comment +// +// Parameters: ( const char* text ) +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::SetCountDownMSG( const char* text ) +{ + mCountDownText = text; +} + +//============================================================================= +// SuperSprintDrawable::SetTextScale +//============================================================================= +// Description: Comment +// +// Parameters: ( float scale ) +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::SetTextScale( float scale ) +{ + mTextScale = scale; +} + +//============================================================================= +// SuperSprintDrawable::DoCountDownToo +//============================================================================= +// Description: Comment +// +// Parameters: ( bool enable ) +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::DoCountDownToo( bool enable ) +{ + mCountDownToo = enable; +} + +//============================================================================= +// SuperSprintDrawable::DisplayCarData +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::DisplayCarData() +{ + char displayText[1024]; + + const char* seperator; + unsigned int position; + if ( GetGameplayManager()->GetNumPlayers() == 2 ) + { + seperator = "\n\n"; + position = 2; + } + else + { + seperator = "\n"; + position = 1; + } + + sprintf( displayText, seperator); + + int i; + for ( i = 0; i < GetGameplayManager()->GetNumPlayers(); ++ i ) + { + char text[256]; + if ( mCarData[i].mState == SuperSprintData::CarData::WAITING ) + { + sprintf( text, "Player %d\n%s%s", i + 1, "PRESS START", seperator ); + } + else if ( mCarData[i].mState == SuperSprintData::CarData::SELECTING ) + { + sprintf( text, "Player %d\n%s%s", i + 1, mCarData[ i ].mCarName, seperator ); + } + else if ( mCarData[i].mState == SuperSprintData::CarData::SELECTED ) + { + sprintf( text, "Player %d\n%s%s", i + 1, "READY", seperator ); + } + + strncpy( &displayText[position], text, strlen( text ) ); + position += strlen( text ); + } + + P3D_UNICODE unicodeText[1024]; + p3d::AsciiToUnicode( displayText, unicodeText, position + 1 ); + + mFont->DisplayText( unicodeText, 3 ); +} + +//============================================================================= +// SuperSprintDrawable::DisplayCountDown +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::DisplayCountDown() +{ + P3D_UNICODE unicodeText[256]; + + p3d::AsciiToUnicode( mCountDownText, unicodeText, 256 ); + + mFont->DisplayText( unicodeText, 3 ); +} + +//============================================================================= +// SuperSprintDrawable::DisplayPlayerData +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::DisplayPlayerData() +{ + char displayText[1024]; + const char* seperator = "\n"; + sprintf( displayText, seperator); + + unsigned int position = 1; + + int i; + for ( i = 0; i < GetGameplayManager()->GetNumPlayers(); ++ i ) + { + char text[256]; + + if( !mPlayerData[ i ].mRacing ) + { + sprintf( text, "Player %d%s", i + 1, seperator ); + } + else + { + if ( mPlayerData[ i ].mPosition == 0 ) + { + sprintf( text, "Player %d %s%sDNF%sLOSER!%s", i + 1, "PRESS START", seperator, seperator, seperator ); + } + else + { + sprintf( text, "Player %d %s%sRace Time: %.2f%sBest Lap: %.2f%s", i + 1, "PRESS START", seperator, rmt::LtoF(mPlayerData[ i ].mRaceTime) / 1000000.0f, seperator, rmt::LtoF(mPlayerData[ i ].mBestLap) / 1000000.0f, seperator ); + } + } + + strncpy( &displayText[position], text, strlen( text ) ); + position += strlen( text ); + } + + P3D_UNICODE unicodeText[1024]; + p3d::AsciiToUnicode( displayText, unicodeText, position + 1 ); + + mFont->DisplayText( unicodeText, 3 ); +} + +//============================================================================= +// SuperSprintDrawable::DisplayHighScores +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +/* +inline void SuperSprintDrawable::DisplayHighScores() +{ + char displayText[1024]; + displayText[0] = '\0'; + + const char* seperator = "\n"; + + sprintf( displayText, seperator); + + unsigned int position = 1; + + char text[256]; + + sprintf( text, "BEST TIME BEST LAP%s=================++==========%s", seperator, seperator ); + strncpy( &displayText[position], text, strlen( text ) ); + position += strlen( text ); + + int j; + for ( j = 0; j < SuperSprintData::HighScore::NUM_HIGH_SCORE; ++j ) + { + sprintf( text, "%8s %5s %.2f %8s %5s %.2f%s", SuperSprintData::BEST_TIME[j].name, + SuperSprintData::VEHICLE_NAMES[SuperSprintData::BEST_TIME[j].carNum].name, + SuperSprintData::BEST_TIME[j].score / 1000000.0f, + SuperSprintData::BEST_LAP[j].name, + SuperSprintData::VEHICLE_NAMES[SuperSprintData::BEST_LAP[j].carNum].name, + SuperSprintData::BEST_LAP[j].score / 1000000.0f, + seperator ); + + strncpy( &displayText[position], text, strlen( text ) ); + position += strlen( text ); + } + + P3D_UNICODE unicodeText[1024]; + p3d::AsciiToUnicode( displayText, unicodeText, position + 1 ); + + mFont->DisplayText( unicodeText, 3 ); +} +*/ + +//============================================================================= +// SuperSprintDrawable::Display +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::Display() +{ + tColour colour( 240, 240, 0 ); + colour.SetAlpha( 255 ); + + mFont->SetColour( colour ); + + p3d::pddi->PushState( PDDI_STATE_VIEW ); + p3d::pddi->SetProjectionMode( PDDI_PROJECTION_ORTHOGRAPHIC ); + + p3d::stack->Push(); + p3d::stack->LoadIdentity(); + + float textPosX, textPosY; + textPosX = textPosY = 0.0f; + + tPointCamera* pPtCam = (tPointCamera*)GetSuperCamManager()->GetSCC(0)->GetCamera(); + + p3d::stack->Translate( textPosX, textPosY, pPtCam->GetNearPlane()+0.5f); + float scaleSize = 1.0f / 480.0f; //This is likely good for 528 also. + + float fontScale = 0.5f * mTextScale; + p3d::stack->Scale(scaleSize * fontScale, scaleSize * fontScale , 1.0f); + + switch ( mRenderState ) + { + case CAR_DATA: + { + DisplayCarData(); + + if ( mCountDownToo ) + { + DisplayCountDown(); + } + break; + } + case PLAYER_DATA: + { +// DisplayPlayerData(); + break; + } + case COUNT_DOWN: + { + DisplayCountDown(); + break; + } + case HIGH_SCORES: + { +// DisplayHighScores(); + break; + } + default: + { + break; + } + } + + p3d::stack->Pop(); + p3d::pddi->PopState( PDDI_STATE_VIEW ); +} + +//============================================================================= +// SuperSprintDrawable::SetRenderState +//============================================================================= +// Description: Comment +// +// Parameters: ( RenderState state ) +// +// Return: void +// +//============================================================================= +inline void SuperSprintDrawable::SetRenderState( RenderState state ) +{ + mRenderState = state; +} +#endif //SUPERSPRINTDRAWABLE_H diff --git a/game/code/supersprint/supersprintmanager.cpp b/game/code/supersprint/supersprintmanager.cpp new file mode 100644 index 0000000..d9c75b8 --- /dev/null +++ b/game/code/supersprint/supersprintmanager.cpp @@ -0,0 +1,2668 @@ +//============================================================================= +// 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 <raddebug.hpp> +#include <radtime.hpp> +#include <p3d/utility.hpp> +#include <p3d/anim/multicontroller.hpp> +#include <string.h> + +//======================================== +// Project Includes +//======================================== + +#include <memory/srrmemory.h> +#include <loading/loadingmanager.h> +#include <gameflow/gameflow.h> +#include <camera/supercammanager.h> +#include <camera/supercamcentral.h> +#include <camera/animatedcam.h> +#include <mission/missionscriptloader.h> +#include <render/loaders/billboardwrappedloader.h> +#include <render/dsg/animcollisionentitydsg.h> +#include <worldsim/vehiclecentral.h> +#include <worldsim/avatarmanager.h> +#include <worldsim/character/character.h> +#include <worldsim/character/charactermanager.h> +#include <meta/carstartlocator.h> +#include <render/rendermanager/rendermanager.h> +#include <render/rendermanager/renderlayer.h> +#include <input/inputmanager.h> +#include <events/eventmanager.h> +#include <meta/eventlocator.h> +#include <contexts/supersprint/supersprintcontext.h> +#include <gameflow/gameflow.h> +#include <presentation/gui/guisystem.h> +#include <presentation/gui/guimanager.h> +#include <sound/soundmanager.h> + +#include <roads/roadmanager.h> +#include <roads/roadsegment.h> +#include <worldsim/avatarmanager.h> +#include <worldsim/avatar.h> +#include <render/intersectmanager/intersectmanager.h> + +#include <supersprint/supersprintmanager.h> + +#include <mission/gameplaymanager.h> + +//***************************************************************************** +// +// 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<EventLocator*>(pEventData); + + char checkNum = static_cast<char>( 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<int>( mPlayers[ playerID ].mNumLaps ) == mNumLaps - 1 ) + { + //Show the white flag for a few seconds. + mWFlag->ShouldRender( true ); + mWFlagTimeout = SuperSprintData::FLAG_TIMEOUT; + } + else if ( static_cast<int>( 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<EventLocator*>(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<int>(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; j<numAIs; j++ ) + { + if( numAIsDoingTurbo < MAX_AIS_DOING_TURBO ) + { + int coinflip = rand() % 7; + if( coinflip == 0 || coinflip == 1 || coinflip == 2 ) + { + rAssert( 0 <= aiIndices[j] && aiIndices[j] < SuperSprintData::NUM_PLAYERS ); + mVehicleSlots[ aiIndices[j] ].mVehicleAI->UseTurbo(); + 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<int>(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<int>(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<RoadManager::PathElement> 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<RoadManager::PathElement> 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<int>( 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<CarStartLocator>(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<Locator>( 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<nWaypoints; j++ ) + { + static_cast<WaypointAI*>(mVehicleSlots[ i ].mVehicleAI)->AddWaypoint( waypoints[j] ); + } + } + } + + DisableAllAI(); + + p3d::inventory->PushSection(); + p3d::inventory->SelectSection( "Level" ); + + HeapMgr()->PushHeap( GMA_TEMP ); + tInventory::Iterator<EventLocator> 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<int>( 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<AnimCollisionEntityDSG>( "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<AnimCollisionEntityDSG>( "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<CarStartLocator>(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() +{ +} diff --git a/game/code/supersprint/supersprintmanager.h b/game/code/supersprint/supersprintmanager.h new file mode 100644 index 0000000..cbd3a11 --- /dev/null +++ b/game/code/supersprint/supersprintmanager.h @@ -0,0 +1,383 @@ +//============================================================================= +// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved. +// +// File: supersprintmanager.h +// +// Description: Blahblahblah +// +// History: 2/3/2003 + Created -- Cary Brisebois +// +//============================================================================= + +#ifndef SUPERSPRINTMANAGER_H +#define SUPERSPRINTMANAGER_H + +//======================================== +// Nested Includes +//======================================== +#include <events/eventlistener.h> +#include <input/mappable.h> +#include <mission/gameplaymanager.h> +#include <mission/animatedicon.h> +#include <loading/loadingmanager.h> +#include <supersprint/supersprintdata.h> +#include <supersprint/supersprintdrawable.h> + +#include <roads/roadmanager.h> + +//======================================== +// Forward References +//======================================== +class Vehicle; +class AnimCollisionEntityDSG; +class RoadSegment; +class EventLocator; + +//============================================================================= +// +// Synopsis: Blahblahblah +// +//============================================================================= + +class SuperSprintManager : public Mappable, + public GameplayManager, + public LoadingManager::ProcessRequestsCallback +{ +public: + + enum + { + MAX_AI_WAYPOINTS = 20, + MAX_CHECKPOINT_LOCATORS = 16 + }; + + //------------- S T A T E + + enum State + { + IDLE, //idle, doing nothing + + COUNT_DOWN, //Start of race 3, 2, 1 countdown + + RACING, //Racing until everyone crosses the finish line. Anyone who has crossed the finish + //line is disabled until the end of the race. The last player has 30 seconds from the + //previous player finishing or they are DNF + + DNF_TIMEOUT, //When this starts, anyone who does not finish in the remaining time gets a DNF + + WINNER_CIRCLE, //Race stats and display of the winner and their time to finish + + PAUSED //Get it? + + // + // Goes IDLE -> COUNT_DOWN -> RACING -> WINNER_CIRCLE + // -> DNF_TIMEOUT ->WINNER_CIRCLE + // + // At anytime we can quit back to the game through the pause menu. + // + }; + //From EventListener + void HandleEvent( EventEnum id, void* pEventData ); + + //From LoadingManager::ProcessRequestsCallback + void OnProcessRequestsComplete( void* pUserData ); + + //From GamePlayManager + virtual void LoadLevelData(); + virtual void InitLevelData() {}; + virtual void CleanMissionData() {}; + virtual bool IsSundayDrive() { return true; }; + virtual bool IsSuperSprint(); + virtual void PerformLoading() {}; + virtual void Reset(); + + //From Mappable + virtual void OnButton( int controllerId, int id, const Button* pButton ); + virtual void OnButtonUp( int controllerId, int buttonId, const Button* pButton ); + virtual void OnButtonDown( int controllerId, int buttonId, const Button* pButton ); + virtual void LoadControllerMappings( unsigned int controllerId ); + virtual void OnControllerConnect( int id ); + virtual void OnControllerDisconnect( int id ); + + char GetNumCheckpoints(); + + //Local + static SuperSprintManager* GetInstance(); + static void DestroyInstance(); + + void Initialize(); + void Finalize(); + void Update( unsigned int milliseconds ); + + void LoadScriptData(); + void LoadCars(); + void LoadCharacters(); + void StartRace(); + + void SetCurrentLevel( int level ); + void SetNumLaps( int numLaps ); + void SetTrackDirection( bool reverse ); + bool IsTrackReversed() const; + void SetCharacter( int playerID, int index ); + void SetVehicle( int playerID, const char* name ); + + char FindLeader(); //Returns who's in the lead + + void CalculatePositions(); + + const SuperSprintData::CarData* GetVehicleData( int playerID ) const; + const SuperSprintData::PlayerData* GetPlayerData( int playerID ) const; + + int GetOnlyHumanPlayerID(); + + State GetState() const {return mCurrentState;}; + + void RestoreControllerState(); + +protected: + void LoadMission() {}; + +private: + + + + enum ButtonMap + { + Start, + Select, + Back, + Left, + Right, + StickX, + CamSelect, + L1, + ShowPositions + }; + + static SuperSprintManager* spInstance; + + State mCurrentState; + + void SetState( State state ); + + + //------------- P L A Y E R C A R S + + SuperSprintData::CarData mVehicleSlots[ SuperSprintData::NUM_PLAYERS ]; + + + //------------- P L A Y E R D A T A + + SuperSprintData::PlayerData mPlayers[ SuperSprintData::NUM_PLAYERS ]; + + //------------- D R A W A B L E + + SuperSprintDrawable* mDrawable; + + int mCountDownTime; + char mTime[32]; + + int mCurrentPosition; + + unsigned int mStartTime; + + int mNumActivePlayers; + int mNumHumanPlayers; + int mNumHumansFinished; + + int mCurrentLevel; + int mNumLaps; + + // can either drive left around the track or right around the track + // default to FALSE (i.e. going "left" is going backwards) + bool mGoLeft; + + char mNumCheckPoints; //Use the accessor please. + char* mCheckPoints; + + AnimatedIcon* mFFlag; + AnimatedIcon* mWFlag; + unsigned int mFFlagTimeout; + unsigned int mWFlagTimeout; + + AnimCollisionEntityDSG* mTrapController; + bool mTrapTriggered; + + char mPositions[ SuperSprintData::NUM_PLAYERS ]; //This is an array of player IDs. + AnimatedIcon* mPositionIcon[ SuperSprintData::NUM_PLAYERS ][ SuperSprintData::NUM_PLAYERS ]; + AnimatedIcon* mPlayerID[ SuperSprintData::NUM_PLAYERS ]; + bool mTogglePosition[ SuperSprintData::NUM_PLAYERS ]; + AnimatedIcon* mNitroEffect[ SuperSprintData::NUM_PLAYERS ]; + + struct PathData + { + PathData() : seg( NULL ), segT( 0.0f ), roadT( 0.0f ), loc( NULL ) {}; + RoadSegment* seg; + float segT; + float roadT; + RoadManager::PathElement closestElem; + EventLocator* loc; + }; + + PathData mPathData[ MAX_AI_WAYPOINTS ]; + EventLocator* mCheckPointLocators[ MAX_CHECKPOINT_LOCATORS ]; + unsigned int mNumCheckPointLocators; + + void PositionCharacters(); + void SetUpCars(); + void CleanUpCars(); + void PositionCars(); + void PositionAI(); + void DisableAllAI(); + void DisableAllControllers(); + void InitRaceData(); + void ResetRaceData(); + void PlaceCharactersInCars(); + void EnumerateControllers(); + void SetupIcons(); + void InitCamera(); + void SetupTraps(); + void PlayIntroCam(); + void UpdatePositionIcons( unsigned int milliseconds ); + Locator* GetCheckpointWith( char data ); + int GetPathDataWith( Locator* loc ); + + SuperSprintManager(); + virtual ~SuperSprintManager(); + + //Prevent wasteful constructor creation. + SuperSprintManager( const SuperSprintManager& supersprintmanager ); + SuperSprintManager& operator=( const SuperSprintManager& supersprintmanager ); + +}; + +//***************************************************************************** +// +//Inline Public Member Functions +// +//***************************************************************************** + +inline SuperSprintManager* GetSSM() { return SuperSprintManager::GetInstance(); }; + +//***************************************************************************** +// +//Inline Private Member Functions +// +//***************************************************************************** +inline void SuperSprintManager::SetState( SuperSprintManager::State state ) +{ + mCurrentState = state; +} + +//============================================================================= +// SuperSprintManager::IsSuperSprint +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: inline +// +//============================================================================= +inline bool SuperSprintManager::IsSuperSprint() +{ + return( true ); +} + +//============================================================================= +// SuperSprintManager::SetCurrentLevel +//============================================================================= +// Description: Comment +// +// Parameters: ( int level ) +// +// Return: void +// +//============================================================================= +inline void SuperSprintManager::SetCurrentLevel( int level ) +{ + mCurrentLevel = level; +} + +//============================================================================= +// SuperSprintManager::SetNumLaps +//============================================================================= +// Description: Comment +// +// Parameters: ( int level ) +// +// Return: void +// +//============================================================================= +inline void SuperSprintManager::SetNumLaps( int numLaps ) +{ + mNumLaps = numLaps; +} + +//============================================================================= +// SuperSprintManager::SetTrackDirection +//============================================================================= +// Description: Comment +// +// Parameters: ( int level ) +// +// Return: void +// +//============================================================================= +inline void SuperSprintManager::SetTrackDirection( bool reverse ) +{ + mGoLeft = reverse; +} + +//============================================================================= +// SuperSprintManager::IsTrackReversed +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: bool +// +//============================================================================= +inline bool SuperSprintManager::IsTrackReversed() const +{ + return mGoLeft; +} + +//============================================================================= +// SuperSprintManager::GetPlayerData +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: +// +//============================================================================= +inline const SuperSprintData::PlayerData* +SuperSprintManager::GetPlayerData( int playerID ) const +{ + rAssert( playerID >= 0 && playerID < SuperSprintData::NUM_PLAYERS ); + + return &( mPlayers[ playerID ] ); +} + +//============================================================================= +// SuperSprintManager::GetVehicleData +//============================================================================= +// Description: Comment +// +// Parameters: () +// +// Return: +// +//============================================================================= +inline const SuperSprintData::CarData* +SuperSprintManager::GetVehicleData( int playerID ) const +{ + rAssert( playerID >= 0 && playerID < SuperSprintData::NUM_PLAYERS ); + + return &( mVehicleSlots[ playerID ] ); +} + +#endif //SUPERSPRINTMANAGER_H |