#include "precompiled.h" #include "Game.h" #include "GameAttributes.h" #include "CLogger.h" #ifndef NO_GUI #include "gui/CGUI.h" #endif #include "lib/timer.h" #include "Profile.h" #include "Loader.h" #include "CStr.h" #include "simulation/EntityManager.h" #include "CConsole.h" #include "ps/World.h" #include "simulation/Simulation.h" #include "graphics/GameView.h" extern CConsole* g_Console; CGame *g_Game=NULL; // Disable "warning C4355: 'this' : used in base member initializer list". // "The base-class constructors and class member constructors are called before // this constructor. In effect, you've passed a pointer to an unconstructed // object to another constructor. If those other constructors access any // members or call member functions on this, the result will be undefined." // In this case, the pointers are simply stored for later use, so there // should be no problem. #if MSC_VERSION # pragma warning (disable: 4355) #endif CGame::CGame(): m_World(new CWorld(this)), m_Simulation(new CSimulation(this)), m_GameView(new CGameView(this)), m_pLocalPlayer(NULL), m_GameStarted(false), m_Paused(false), m_Time(0), m_SimRate(1.0f) { debug_printf("CGame::CGame(): Game object CREATED; initializing..\n"); } #if MSC_VERSION # pragma warning (default: 4355) #endif CGame::~CGame() { // Again, the in-game call tree is going to be different to the main menu one. g_Profiler.StructuralReset(); delete m_GameView; delete m_Simulation; delete m_World; debug_printf("CGame::~CGame(): Game object DESTROYED\n"); } PSRETURN CGame::RegisterInit(CGameAttributes* pAttribs) { LDR_BeginRegistering(); // RC, 040804 - GameView needs to be initialised before World, otherwise GameView initialisation // overwrites anything stored in the map file that gets loaded by CWorld::Initialize with default // values. At the minute, it's just lighting settings, but could be extended to store camera position. // Storing lighting settings in the gameview seems a little odd, but it's no big deal; maybe move it at // some point to be stored in the world object? m_GameView->RegisterInit(pAttribs); m_World->RegisterInit(pAttribs); m_Simulation->RegisterInit(pAttribs); LDR_EndRegistering(); return 0; } PSRETURN CGame::ReallyStartGame() { #ifndef NO_GUI // Call the reallyStartGame function, but only if it exists jsval fval, rval; JSBool ok = JS_GetProperty(g_ScriptingHost.getContext(), g_GUI.GetScriptObject(), "reallyStartGame", &fval); debug_assert(ok); if (ok && !JSVAL_IS_VOID(fval)) { ok = JS_CallFunctionValue(g_ScriptingHost.getContext(), g_GUI.GetScriptObject(), fval, 0, NULL, &rval); debug_assert(ok); } #endif debug_printf("GAME STARTED, ALL INIT COMPLETE\n"); m_GameStarted=true; // The call tree we've built for pregame probably isn't useful in-game. g_Profiler.StructuralReset(); #ifndef NO_GUI g_GUI.SendEventToAll("sessionstart"); #endif return 0; } PSRETURN CGame::StartGame(CGameAttributes *pAttribs) { try { // JW: this loop is taken from ScEd and fixes lack of player color. // TODO: determine proper number of players. for (int i=1; i<8; ++i) pAttribs->GetSlot(i)->AssignLocal(); pAttribs->FinalizeSlots(); m_NumPlayers=pAttribs->GetSlotCount(); // Player 0 = Gaia - allocate one extra m_Players.resize(m_NumPlayers + 1); for (uint i=0;i <= m_NumPlayers;i++) m_Players[i]=pAttribs->GetPlayer(i); m_pLocalPlayer=m_Players[1]; RegisterInit(pAttribs); } catch (PSERROR_Game& e) { return e.getCode(); } return 0; } void CGame::Update(double deltaTime) { if( m_Paused ) { return; } deltaTime *= m_SimRate; m_Time += deltaTime; m_Simulation->Update(deltaTime); // TODO Detect game over and bring up the summary screen or something // ^ Quick game over hack is implemented, no summary screen however if ( m_World->GetEntityManager()->GetDeath() ) { UpdateGameStatus(); if (GameStatus != 0) EndGame(); } //reset death event flag m_World->GetEntityManager()->SetDeath(false); } void CGame::UpdateGameStatus() { bool EOG_lose = true; bool EOG_win = true; CPlayer *local = GetLocalPlayer(); for (int i=0; iGetEntityManager()->getHandle(i); if ( !handle ) continue; CPlayer *tmpPlayer = handle->m_entity->GetPlayer(); //Are we still alive? if ( local == tmpPlayer && handle->m_entity->m_extant ) { EOG_lose = false; if (EOG_win == false) break; } //Are they still alive? else if ( handle->m_entity->m_extant ) { EOG_win = false; if (EOG_lose == false) break; } } if (EOG_lose && EOG_win) GameStatus = EOG_SPECIAL_DRAW; else if (EOG_win) GameStatus = EOG_WIN; else if (EOG_lose) GameStatus = EOG_LOSE; else GameStatus = EOG_NEUTRAL; } void CGame::EndGame() { g_Console->InsertMessage( L"It's the end of the game as we know it!"); switch (GameStatus) { case EOG_DRAW: g_Console->InsertMessage( L"A diplomatic draw ain't so bad, eh?"); break; case EOG_SPECIAL_DRAW: g_Console->InsertMessage( L"Amazingly, you managed to draw from dieing at the same time as your opponent...you have my respect."); break; case EOG_LOSE: g_Console->InsertMessage( L"My condolences on your loss."); break; case EOG_WIN: g_Console->InsertMessage( L"Thou art victorious!"); break; default: break; } } CPlayer *CGame::GetPlayer(uint idx) { if (idx > m_NumPlayers) { // debug_warn("Invalid player ID"); // LOG(ERROR, "", "Invalid player ID %d (outside 0..%d)", idx, m_NumPlayers); return m_Players[0]; } // Be a bit more paranoid - maybe m_Players hasn't been set large enough else if (idx >= m_Players.size()) { debug_warn("Invalid player ID"); LOG(ERROR, "", "Invalid player ID %d (not <=%d - internal error?)", idx, m_Players.size()); if (m_Players.size() != 0) return m_Players[0]; else return NULL; // the caller will probably crash because of this, // but at least we've reported the error } else return m_Players[idx]; }