// ============================================================== // This file is part of Glest (www.glest.org) // // Copyright (C) 2001-2005 Martiņo Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #include "game.h" #include "config.h" #include "renderer.h" #include "particle_renderer.h" #include "commander.h" #include "battle_end.h" #include "sound_renderer.h" #include "profiler.h" #include "core_data.h" #include "metrics.h" #include "faction.h" #include "leak_dumper.h" using namespace Shared::Graphics; using namespace Shared::Util; namespace Glest{ namespace Game{ // ===================================================== // class Game // ===================================================== // ===================== PUBLIC ======================== Game::Game(Program *program, const GameSettings *gameSettings): ProgramState(program) { this->gameSettings= *gameSettings; mouseX=0; mouseY=0; mouse2d= 0; loadingText=""; weatherParticleSystem= NULL; updateFps=0; renderFps=0; lastUpdateFps=0; lastRenderFps=0; paused= false; gameOver= false; speed= sNormal; exitMessageBox= NULL; } Game::~Game(){ Logger &logger= Logger::getInstance(); Renderer &renderer= Renderer::getInstance(); logger.setState(Lang::getInstance().get("Deleting")); logger.add("Game", true); renderer.endGame(); SoundRenderer::getInstance().stopAllSounds(); delete exitMessageBox; deleteValues(aiInterfaces.begin(), aiInterfaces.end()); gui.end(); //selection must be cleared before deleting units world.end(); //must die before selection because of referencers } // ==================== init and load ==================== void Game::load(){ Logger::getInstance().setState(Lang::getInstance().get("Loading")); //tileset world.loadTileset(gameSettings.getTilesetPath()); //tech, load before map because of resources world.loadTech(gameSettings.getTechPath()); //map world.loadMap(gameSettings.getMapPath()); } void Game::init(){ Logger &logger= Logger::getInstance(); CoreData &coreData= CoreData::getInstance(); Renderer &renderer= Renderer::getInstance(); Map *map= world.getMap(); int updateFps= Config::getInstance().getInt("UpdateFps"); logger.setState(Lang::getInstance().get("Initializing")); //init world, and place camera commander.init(&world); world.init(this); gui.init(this); const Vec2i &v= map->getStartLocation(world.getThisFaction()->getStartLocationIndex()); gameCamera.init(map->getW(), map->getH()); gameCamera.setPos(Vec2f(v.x, v.y)); //create IAs aiInterfaces.resize(world.getFactionCount()); for(int i=0; igetCpuControl()){ aiInterfaces[i]= new AiInterface(*this, i, faction->getTeam()); logger.add("Creating AI for faction " + intToStr(i), true); } else{ aiInterfaces[i]= NULL; } } //wheather particle systems if(world.getTileset()->getWeather() == wRainy){ logger.add("Creating rain particle system", true); weatherParticleSystem= new RainParticleSystem(); weatherParticleSystem->setSpeed(12.f/updateFps); weatherParticleSystem->setPos(gameCamera.getPos()); renderer.manageParticleSystem(weatherParticleSystem, rsGame); } else if(world.getTileset()->getWeather() == wSnowy){ logger.add("Creating snow particle system", true); weatherParticleSystem= new SnowParticleSystem(1200); weatherParticleSystem->setSpeed(1.5f/updateFps); weatherParticleSystem->setPos(gameCamera.getPos()); weatherParticleSystem->setTexture(coreData.getSnowTexture()); renderer.manageParticleSystem(weatherParticleSystem, rsGame); } //init renderer state logger.add("Initializing renderer", true); renderer.initGame(this); //sounds SoundRenderer &soundRenderer= SoundRenderer::getInstance(); Tileset *tileset= world.getTileset(); AmbientSounds *ambientSounds= tileset->getAmbientSounds(); //rain if(tileset->getWeather()==wRainy && ambientSounds->isEnabledRain()){ logger.add("Starting ambient stream", true); soundRenderer.playAmbient(ambientSounds->getRain()); } //snow if(tileset->getWeather()==wSnowy && ambientSounds->isEnabledSnow()){ logger.add("Starting ambient stream", true); soundRenderer.playAmbient(ambientSounds->getSnow()); } logger.add("Starting music stream", true); StrSound *gameMusic= world.getThisFaction()->getType()->getMusic(); soundRenderer.playMusic(gameMusic); } // ==================== update ==================== //update void Game::update(){ // a) Updates non dependant on speed //misc updateFps++; mouse2d= (mouse2d+1) % Renderer::maxMouse2dAnim; //console console.update(); // b) Updates depandant on speed int updateLoops= getUpdateLoops(); //update for(int i=0; igetCpuControl()){ aiInterfaces[i]->update(); } } //World world.update(); //Gui gui.update(); //Particle systems if(weatherParticleSystem != NULL){ weatherParticleSystem->setPos(gameCamera.getPos()); } renderer.updateParticleManager(rsGame); } } void Game::updateCamera(){ gameCamera.update(); } // ==================== render ==================== //render void Game::render(){ renderFps++; render3d(); render2d(); Renderer::getInstance().swapBuffers(); } // ==================== tick ==================== void Game::tick(){ lastUpdateFps= updateFps; lastRenderFps= renderFps; updateFps= 0; renderFps= 0; //Win/lose check checkWinner(); int updateLoops= getUpdateLoops(); world.computeFow(); for(int i=0; i(xm * (static_cast(map->getW()) / metrics.getMinimapW())); int yCell= static_cast(map->getH() - ym * (static_cast(map->getH()) / metrics.getMinimapH())); if(map->isInside(xCell, yCell)){ SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(Vec2i(xCell, yCell))); if(!gui.isSelectingPos() && sc->isExplored(world.getThisTeamIndex())){ gameCamera.setPos(Vec2f(static_cast(xCell), static_cast(yCell))); } } } //display panel else if(metrics.isInDisplay(x, y) && !gui.isSelectingPos()){ int xd= x - metrics.getDisplayX(); int yd= y - metrics.getDisplayY(); if(gui.mouseValid(xd, yd)){ gui.mouseDownLeftDisplay(xd, yd); } else{ gui.mouseDownLeftGraphics(x, y); } } //graphics panel else{ gui.mouseDownLeftGraphics(x, y); } //exit message box if(exitMessageBox!=NULL){ int button= 1; if(exitMessageBox->mouseClick(x, y, button)){ if(button==1){ //exit game program->setState(new BattleEnd(program, world.getStats())); } else{ //close message box delete exitMessageBox; exitMessageBox= NULL; } } } } void Game::mouseDownRight(int x, int y){ gui.mouseDownRightGraphics(x, y); } void Game::mouseUpLeft(int x, int y){ gui.mouseUpLeftGraphics(x, y); } void Game::mouseDoubleClickLeft(int x, int y){ const Metrics &metrics= Metrics::getInstance(); //display panel if(metrics.isInDisplay(x, y) && !gui.isSelectingPos()){ int xd= x - metrics.getDisplayX(); int yd= y - metrics.getDisplayY(); if(gui.mouseValid(xd, yd)){ return; } } //graphics panel gui.mouseDoubleClickLeftGraphics(x, y); } void Game::mouseMove(int x, int y, const MouseState *ms){ Config &config= Config::getInstance(); const Metrics &metrics= Metrics::getInstance(); mouseX= x; mouseY= y; //main window if(y<10){ gameCamera.setMoveZ(-1); } else if(y> metrics.getVirtualH()-10){ gameCamera.setMoveZ(1); } else{ gameCamera.stopMoveZ(); } if(x<10){ gameCamera.setMoveX(-1); } else if(x> metrics.getVirtualW()-10){ gameCamera.setMoveX(1); } else{ gameCamera.stopMoveX(); } if(exitMessageBox!=NULL){ exitMessageBox->mouseMove(x, y); } //graphics gui.mouseMoveGraphics(x, y); //display if(metrics.isInDisplay(x, y) && !gui.isSelecting() && !gui.isSelectingPos()){ if(!gui.isSelectingPos()){ gui.mouseMoveDisplay(x - metrics.getDisplayX(), y - metrics.getDisplayY()); } } } void Game::keyDown(char key){ Lang &lang= Lang::getInstance(); //move camera left if(key==vkLeft){ gameCamera.setMoveX(-1); } //move camera right else if(key==vkRight){ gameCamera.setMoveX(1); } //move camera up else if(key==vkUp){ gameCamera.setMoveZ(1); } //move camera down else if(key==vkDown){ gameCamera.setMoveZ(-1); } //rotate camera leftt else if(key=='A'){ gameCamera.setRotate(-1); } //rotate camera right else if(key=='D'){ gameCamera.setRotate(1); } //camera up else if(key=='S'){ gameCamera.setMoveY(1); } //camera down else if(key=='W'){ gameCamera.setMoveY(-1); } //switch display color else if(key=='C'){ gui.switchToNextDisplayColor(); } //change camera mode else if(key=='M'){ gameCamera.switchState(); string stateString= gameCamera.getState()==GameCamera::sGame? lang.get("GameCamera"): lang.get("FreeCamera"); console.addLine(lang.get("CameraModeSet")+" "+ stateString); } //pause else if(key=='P'){ if(paused){ console.addLine(lang.get("GameResumed")); paused= false; } else{ console.addLine(lang.get("GamePaused")); paused= true; } } //increment speed else if(key==vkAdd){ incSpeed(); } //decrement speed else if(key==vkSubtract){ decSpeed(); } //exit else if(key==vkEscape){ showExitMessageBox(lang.get("ExitGame?"), true); } //group else if(key>='0' && key<'0'+Selection::maxGroups){ gui.groupKey(key-'0'); } } void Game::keyUp(char key){ switch(key){ case 'A': case 'D': gameCamera.setRotate(0); break; case 'W': case 'S': gameCamera.stopMoveY(); break; case vkUp: case vkDown: gameCamera.stopMoveZ(); break; case vkLeft: case vkRight: gameCamera.stopMoveX(); break; } } // ==================== PRIVATE ==================== // ==================== render ==================== void Game::render3d(){ Renderer &renderer= Renderer::getInstance(); //init renderer.reset3d(); renderer.computeVisibleQuad(); renderer.loadGameCameraMatrix(); renderer.setupLighting(); //shadow map renderer.renderShadowsToTexture(); //clear buffers renderer.clearBuffers(); //surface renderer.renderSurface(); //selection circles renderer.renderSelectionEffects(); //units renderer.renderUnits(); //objects renderer.renderObjects(); //water renderer.renderWater(); renderer.renderWaterEffects(); //particles renderer.renderParticleManager(rsGame); //mouse 3d renderer.renderMouse3d(); } void Game::render2d(){ Renderer &renderer= Renderer::getInstance(); Config &config= Config::getInstance(); CoreData &coreData= CoreData::getInstance(); //init renderer.reset2d(); //display renderer.renderDisplay(); //minimap if(!config.getBool("PhotoMode")){ renderer.renderMinimap(); } //selection renderer.renderSelectionQuad(); //exit message box if(exitMessageBox!=NULL){ renderer.renderMessageBox(exitMessageBox); } //debug info if(config.getBool("DebugMode")){ string str; str+= "MouseXY: " + intToStr(mouseX) + "," + intToStr(mouseY)+"\n"; str+= "Render FPS: "+intToStr(lastRenderFps)+"\n"; str+= "Update FPS: "+intToStr(lastUpdateFps)+"\n"; str+= "GameCamera pos: "+floatToStr(gameCamera.getPos().x)+","+floatToStr(gameCamera.getPos().y)+","+floatToStr(gameCamera.getPos().z)+"\n"; str+= "Time: "+floatToStr(world.getTimeFlow()->getTime())+"\n"; str+= "Triangle count: "+intToStr(renderer.getTriangleCount())+"\n"; str+= "Vertex count: "+intToStr(renderer.getPointCount())+"\n"; for(int i=0; igetResourceTypeCount(); ++j){ str+= intToStr(world.getFaction(i)->getResource(j)->getAmount()); str+=" "; } str+="\n"; } Renderer::getInstance().renderText( str, coreData.getMenuFontNormal(), gui.getDisplay()->getColor(), 10, 500, false); } //resource info if(!config.getBool("PhotoMode")){ renderer.renderResourceStatus(); renderer.renderConsole(console); } //2d mouse renderer.renderMouse2d(mouseX, mouseY, mouse2d, gui.isSelectingPos()? 1.f: 0.f); } // ==================== misc ==================== void Game::checkWinner(){ if(!gameOver){ Lang &lang= Lang::getInstance(); //lose bool lose= false; if(!hasBuilding(world.getThisFaction())){ lose= true; for(int i=0; iisAlly(world.getThisFaction())){ world.getStats()->setVictorious(i); } } gameOver= true; showExitMessageBox(lang.get("YouLose")+", "+lang.get("ExitGame?"), false); } //win if(!lose){ bool win= true; for(int i=0; iisAlly(world.getThisFaction())){ win= false; } } } //if win if(win){ for(int i=0; i< world.getFactionCount(); ++i){ if(world.getFaction(i)->isAlly(world.getThisFaction())){ world.getStats()->setVictorious(i); } } gameOver= true; showExitMessageBox(lang.get("YouWin")+", "+lang.get("ExitGame?"), false); } } } } bool Game::hasBuilding(const Faction *faction){ for(int i=0; igetUnitCount(); ++i){ if(faction->getUnit(i)->getType()->hasSkillClass(scBeBuilt)){ return true; } } return false; } void Game::incSpeed(){ Lang &lang= Lang::getInstance(); switch(speed){ case sSlow: speed= sNormal; console.addLine(lang.get("GameSpeedSet")+" "+lang.get("Normal")); break; case sNormal: speed= sFast; console.addLine(lang.get("GameSpeedSet")+" "+lang.get("Fast")); break; default: break; } } void Game::decSpeed(){ Lang &lang= Lang::getInstance(); switch(speed){ case sNormal: speed= sSlow; console.addLine(lang.get("GameSpeedSet")+" "+lang.get("Slow")); break; case sFast: speed= sNormal; console.addLine(lang.get("GameSpeedSet")+" "+lang.get("Normal")); break; default: break; } } int Game::getUpdateLoops(){ if(paused){ return 0; } else if(speed==sFast){ return Config::getInstance().getInt("FastSpeedLoops"); } else if(speed==sSlow){ return updateFps % 2 == 0? 1: 0; } return 1; } void Game::showExitMessageBox(const string &text, bool toggle){ Lang &lang= Lang::getInstance(); if(!toggle){ delete exitMessageBox; exitMessageBox= NULL; } if(exitMessageBox==NULL){ exitMessageBox= new GraphicMessageBox(); exitMessageBox->init(lang.get("Yes"), lang.get("No")); exitMessageBox->setText(text); } else{ delete exitMessageBox; exitMessageBox= NULL; } } }}//end namespace