// ============================================================== // This file is part of Glest (www.glest.org) // // Copyright (C) 2001-2008 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 "world.h" #include #include #include "config.h" #include "faction.h" #include "unit.h" #include "game.h" #include "core_data.h" #include "logger.h" #include "sound_renderer.h" #include "game_settings.h" #include "cache_manager.h" #include #include "sound.h" #include "sound_renderer.h" #include "leak_dumper.h" using namespace Shared::Graphics; using namespace Shared::Util; namespace Glest{ namespace Game{ // ===================================================== // class World // ===================================================== // This limit is to keep RAM use under control while offering better performance. int MaxExploredCellsLookupItemCache = 9500; //int MaxExploredCellsLookupItemCache = 0; time_t ExploredCellsLookupItem::lastDebug = 0; // ===================== PUBLIC ======================== World::World() : mutexFactionNextUnitId(new Mutex(CODE_AT_LINE)) { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Config &config= Config::getInstance(); unitParticlesEnabled=config.getBool("UnitParticles","true"); animatedTilesetObjectPosListLoaded = false; ExploredCellsLookupItemCache.clear(); ExploredCellsLookupItemCacheTimer.clear(); ExploredCellsLookupItemCacheTimerCount = 0; nextCommandGroupId = 0; techTree = NULL; fogOfWarOverride = false; fogOfWarSkillTypeValue = -1; fogOfWarSmoothing= config.getBool("FogOfWarSmoothing"); fogOfWarSmoothingFrameSkip= config.getInt("FogOfWarSmoothingFrameSkip"); frameCount= 0; scriptManager= NULL; this->game = NULL; thisFactionIndex=0; thisTeamIndex=0; fogOfWar=false; originalGameFogOfWar = fogOfWar; perfTimerEnabled=false; queuedScenarioName=""; queuedScenarioKeepFactions=false; disableAttackEffects = false; loadWorldNode = NULL; cacheFowAlphaTexture = false; cacheFowAlphaTextureFogOfWarValue = false; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void World::cleanup() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); animatedTilesetObjectPosListLoaded = false; ExploredCellsLookupItemCache.clear(); ExploredCellsLookupItemCacheTimer.clear(); //FowAlphaCellsLookupItemCache.clear(); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); for(int i= 0; i < (int)factions.size(); ++i){ factions[i]->end(); } masterController.clearSlaves(true); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); for(int i= 0; i < (int)factions.size(); ++i){ delete factions[i]; } factions.clear(); #ifdef LEAK_CHECK_UNITS printf("%s::%s\n",__FILE__,__FUNCTION__); Unit::dumpMemoryList(); UnitPathBasic::dumpMemoryList(); #endif if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); delete techTree; techTree = NULL; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); for(std::map::iterator iterMap = staticSoundList.begin(); iterMap != staticSoundList.end(); ++iterMap) { delete iterMap->second; } staticSoundList.clear(); for(std::map::iterator iterMap = streamSoundList.begin(); iterMap != streamSoundList.end(); ++iterMap) { delete iterMap->second; } streamSoundList.clear(); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } World::~World() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); cleanup(); delete mutexFactionNextUnitId; mutexFactionNextUnitId = NULL; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void World::endScenario() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameUnLoadingWorld","",true), true); animatedTilesetObjectPosListLoaded = false; ExploredCellsLookupItemCache.clear(); ExploredCellsLookupItemCacheTimer.clear(); fogOfWarOverride = false; originalGameFogOfWar = fogOfWar; fogOfWarSkillTypeValue = -1; cacheFowAlphaTexture = false; cacheFowAlphaTextureFogOfWarValue = false; map.end(); //stats will be deleted by BattleEnd if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void World::end(){ if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameUnLoadingWorld","",true), true); animatedTilesetObjectPosListLoaded = false; ExploredCellsLookupItemCache.clear(); ExploredCellsLookupItemCacheTimer.clear(); for(int i= 0; i < (int)factions.size(); ++i){ factions[i]->end(); } masterController.clearSlaves(true); for(int i= 0; i < (int)factions.size(); ++i){ delete factions[i]; } factions.clear(); #ifdef LEAK_CHECK_UNITS printf("%s::%s\n",__FILE__,__FUNCTION__); Unit::dumpMemoryList(); UnitPathBasic::dumpMemoryList(); #endif fogOfWarOverride = false; originalGameFogOfWar = fogOfWar; fogOfWarSkillTypeValue = -1; map.end(); cacheFowAlphaTexture = false; cacheFowAlphaTextureFogOfWarValue = false; //stats will be deleted by BattleEnd if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } // ========================== init =============================================== void World::addFogOfWarSkillType(const Unit *unit,const FogOfWarSkillType *fowst) { std::pair fowData; fowData.first = unit; fowData.second = fowst; mapFogOfWarUnitList[unit->getId()] = fowData; if((fowst->getApplyToTeam() == true && unit->getTeam() == this->getThisTeamIndex()) || (fowst->getApplyToTeam() == false && unit->getFactionIndex() == this->getThisFactionIndex())) { if((fowst->getFowEnable() == false && fogOfWarSkillTypeValue != 0) || (fowst->getFowEnable() == true && fogOfWarSkillTypeValue != 1)) { //printf("In [%s::%s Line: %d] current = %d new = %d\n",__FILE__,__FUNCTION__,__LINE__,fogOfWar,fowst->getFowEnable()); setFogOfWar(fowst->getFowEnable()); } } } bool World::removeFogOfWarSkillTypeFromList(const Unit *unit) { bool result = false; if(mapFogOfWarUnitList.find(unit->getId()) != mapFogOfWarUnitList.end()) { mapFogOfWarUnitList.erase(unit->getId()); result = true; } return result; } void World::removeFogOfWarSkillType(const Unit *unit) { bool removedFromList = removeFogOfWarSkillTypeFromList(unit); if(removedFromList == true) { if(mapFogOfWarUnitList.empty() == true) { //printf("In [%s::%s Line: %d] current = %d new = %d\n",__FILE__,__FUNCTION__,__LINE__,fogOfWar,originalGameFogOfWar); fogOfWarSkillTypeValue = -1; fogOfWarOverride = false; minimap.restoreFowTex(); } else { bool fowEnabled = false; for(std::map >::const_iterator iterMap = mapFogOfWarUnitList.begin(); iterMap != mapFogOfWarUnitList.end(); ++iterMap) { const Unit *unit = iterMap->second.first; const FogOfWarSkillType *fowst = iterMap->second.second; if((fowst->getApplyToTeam() == true && unit->getTeam() == this->getThisTeamIndex()) || (fowst->getApplyToTeam() == false && unit->getFactionIndex() == this->getThisFactionIndex())) { if(fowst->getFowEnable() == true) { fowEnabled = true; break; } } } if((fowEnabled == false && fogOfWarSkillTypeValue != 0) || (fowEnabled == true && fogOfWarSkillTypeValue != 1)) { //printf("In [%s::%s Line: %d] current = %d new = %d\n",__FILE__,__FUNCTION__,__LINE__,fogOfWar,fowEnabled); setFogOfWar(fowEnabled); } } } } void World::setFogOfWar(bool value) { //printf("In [%s::%s Line: %d] current = %d new = %d\n",__FILE__,__FUNCTION__,__LINE__,fogOfWar,value); if(fogOfWarOverride == false) { minimap.copyFowTex(); } if(value == true) { fogOfWarSkillTypeValue = 1; } else { fogOfWarSkillTypeValue = 0; } fogOfWarOverride = true; } void World::clearTileset() { tileset = Tileset(); } void World::restoreExploredFogOfWarCells() { for (int i = 0; i < map.getSurfaceW(); ++i) { for (int j = 0; j < map.getSurfaceH(); ++j) { for (int k = 0; k < GameConstants::maxPlayers + GameConstants::specialFactions; ++k) { if (k == thisTeamIndex) { if (map.getSurfaceCell(i, j)->isExplored(k) == true) { const Vec2i pos(i, j); Vec2i surfPos = pos; //compute max alpha float maxAlpha = 0.0f; if (surfPos.x > 1 && surfPos.y > 1 && surfPos.x < map.getSurfaceW() - 2 && surfPos.y < map.getSurfaceH() - 2) { maxAlpha = 1.f; } else if (surfPos.x > 0 && surfPos.y > 0 && surfPos.x < map.getSurfaceW() - 1 && surfPos.y < map.getSurfaceH() - 1) { maxAlpha = 0.3f; } //compute alpha float alpha = maxAlpha; minimap.incFowTextureAlphaSurface(surfPos, alpha); } } } } } } void World::init(Game *game, bool createUnits, bool initFactions){ if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); ExploredCellsLookupItemCache.clear(); ExploredCellsLookupItemCacheTimer.clear(); this->game = game; scriptManager= game->getScriptManager(); GameSettings *gs = game->getGameSettings(); if(fogOfWarOverride == false) { fogOfWar = gs->getFogOfWar(); } originalGameFogOfWar = fogOfWar; if(loadWorldNode != NULL) { timeFlow.loadGame(loadWorldNode); } if(initFactions == true) { initFactionTypes(gs); } initCells(fogOfWar); //must be done after knowing faction number and dimensions initMap(); initSplattedTextures(); unitUpdater.init(game); if(loadWorldNode != NULL) { unitUpdater.loadGame(loadWorldNode); } //minimap must be init after sum computation initMinimap(); bool gotError = false; bool skipStackTrace = false; string sErrBuf = ""; try { if(createUnits) { initUnits(); } } catch(const megaglest_runtime_error &ex) { gotError = true; if(ex.wantStackTrace() == true) { char szErrBuf[8096]=""; snprintf(szErrBuf,8096,"In [%s::%s %d]",__FILE__,__FUNCTION__,__LINE__); sErrBuf = string(szErrBuf) + string("\nerror [") + string(ex.what()) + string("]\n"); } else { skipStackTrace = true; sErrBuf = ex.what(); } SystemFlags::OutputDebug(SystemFlags::debugError,sErrBuf.c_str()); } catch(const std::exception &ex) { gotError = true; char szErrBuf[8096]=""; snprintf(szErrBuf,8096,"In [%s::%s %d]",__FILE__,__FUNCTION__,__LINE__); sErrBuf = string(szErrBuf) + string("\nerror [") + string(ex.what()) + string("]\n"); SystemFlags::OutputDebug(SystemFlags::debugError,sErrBuf.c_str()); } if(loadWorldNode != NULL) { map.loadGame(loadWorldNode,this); if(fogOfWar == false) { for(int i=0; i< map.getSurfaceW(); ++i) { for(int j=0; j< map.getSurfaceH(); ++j) { SurfaceCell *sc= map.getSurfaceCell(i, j); if(sc == NULL) { throw megaglest_runtime_error("sc == NULL"); } for (int k = 0; k < GameConstants::maxPlayers; k++) { //sc->setExplored(k, (game->getGameSettings()->getFlagTypes1() & ft1_show_map_resources) == ft1_show_map_resources); sc->setVisible(k, !fogOfWar); } for (int k = GameConstants::maxPlayers; k < GameConstants::maxPlayers + GameConstants::specialFactions; k++) { sc->setExplored(k, true); sc->setVisible(k, true); } } } } else { restoreExploredFogOfWarCells(); } //minimap.loadGame(loadWorldNode); } //initExplorationState(); ... was only for !fog-of-war, now handled in initCells() computeFow(); if(getFrameCount()>1){ // this is needed for games that are loaded to "switch the light on". // otherwise the FowTexture is completely black like in the beginning of a game. minimap.updateFowTex(1.f); } if(gotError == true) { throw megaglest_runtime_error(sErrBuf,!skipStackTrace); } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } //load tileset Checksum World::loadTileset(const vector pathList, const string &tilesetName, Checksum* checksum, std::map > > &loadedFileList) { Checksum tilsetChecksum; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); tilsetChecksum = tileset.loadTileset(pathList, tilesetName, checksum, loadedFileList); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); timeFlow.init(&tileset); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); return tilsetChecksum; } Checksum World::loadTileset(const string &dir, Checksum *checksum, std::map > > &loadedFileList) { Checksum tilesetChecksum; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); tileset.load(dir, checksum, &tilesetChecksum, loadedFileList); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); timeFlow.init(&tileset); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); return tilesetChecksum; } //load tech Checksum World::loadTech(const vector pathList, const string &techName, set &factions, Checksum *checksum, std::map > > &loadedFileList, bool validationMode) { Checksum techtreeChecksum; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); techTree = new TechTree(pathList); techtreeChecksum = techTree->loadTech( techName, factions, checksum,loadedFileList,validationMode); return techtreeChecksum; } std::vector World::validateFactionTypes() { return techTree->validateFactionTypes(); } std::vector World::validateResourceTypes() { return techTree->validateResourceTypes(); } //load map Checksum World::loadMap(const string &path, Checksum *checksum) { Checksum mapChecksum; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); checksum->addFile(path); mapChecksum = map.load(path, techTree, &tileset); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); return mapChecksum; } //load map Checksum World::loadScenario(const string &path, Checksum *checksum, bool resetCurrentScenario, const XmlNode *rootNode) { //printf("[%s:%s] Line: %d path [%s]\n",__FILE__,__FUNCTION__,__LINE__,path.c_str()); Checksum scenarioChecksum; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); checksum->addFile(path); //printf("[%s:%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); if(resetCurrentScenario == true) { scenario = Scenario(); if(scriptManager) scriptManager->init(this, this->getGame()->getGameCameraPtr(),rootNode); } scenarioChecksum = scenario.load(path); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); return scenarioChecksum; } // ==================== misc ==================== void World::setQueuedScenario(string scenarioName,bool keepFactions) { queuedScenarioName = scenarioName; queuedScenarioKeepFactions = keepFactions; } void World::updateAllTilesetObjects() { Gui *gui = this->game->getGuiPtr(); if(gui != NULL) { Object *selObj = gui->getHighlightedResourceObject(); if(selObj != NULL) { selObj->updateHighlight(); } } if(animatedTilesetObjectPosListLoaded == false) { animatedTilesetObjectPosListLoaded = true; animatedTilesetObjectPosList.clear(); for(int x = 0; x < map.getSurfaceW(); ++x) { for(int y = 0; y < map.getSurfaceH(); ++y) { SurfaceCell *sc = map.getSurfaceCell(x,y); if(sc != NULL) { Object *obj = sc->getObject(); if(obj != NULL && obj->isAnimated() == true) { //obj->update(); animatedTilesetObjectPosList.push_back(Vec2i(x,y)); } } } } } if(animatedTilesetObjectPosList.empty() == false) { for(unsigned int i = 0; i < animatedTilesetObjectPosList.size(); ++i) { const Vec2i &pos = animatedTilesetObjectPosList[i]; SurfaceCell *sc = map.getSurfaceCell(pos); if(sc != NULL) { Object *obj = sc->getObject(); if(obj != NULL && obj->isAnimated() == true) { obj->update(); } } } } // for(int x = 0; x < map.getSurfaceW(); ++x) { // for(int y = 0; y < map.getSurfaceH(); ++y) { // SurfaceCell *sc = map.getSurfaceCell(x,y); // if(sc != NULL) { // Object *obj = sc->getObject(); // if(obj != NULL) { // obj->update(); // } // } // } // } } void World::updateAllFactionUnits() { bool showPerfStats = Config::getInstance().getBool("ShowPerfStats","false"); Chrono chronoPerf; if(showPerfStats) chronoPerf.start(); char perfBuf[8096]=""; std::vector perfList; if(scriptManager) scriptManager->onTimerTriggerEvent(); // Prioritize grouped command units so closest units to target go first // units int factionCount = getFactionCount(); //printf("===== STARTING Frame: %d\n",frameCount); // Config &config= Config::getInstance(); // bool sortedUnitsAllowed = config.getBool("AllowGroupedUnitCommands","true"); // // int factionCount = getFactionCount(); // if(sortedUnitsAllowed == true) { // for(int i = 0; i < factionCount; ++i) { // Faction *faction = getFaction(i); // if(faction == NULL) { // throw megaglest_runtime_error("faction == NULL"); // } // // // Sort units by command groups // faction->sortUnitsByCommandGroups(); // } // } // Clear pathfinder list restrictions for(int i = 0; i < factionCount; ++i) { Faction *faction = getFaction(i); faction->clearUnitsPathfinding(); faction->clearWorldSynchThreadedLogList(); } if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } Chrono chrono; chrono.start(); const bool newThreadManager = Config::getInstance().getBool("EnableNewThreadManager","false"); if(newThreadManager == true) { masterController.signalSlaves(&frameCount); bool slavesCompleted = masterController.waitTillSlavesTrigger(20000); if(SystemFlags::VERBOSE_MODE_ENABLED && chrono.getMillis() >= 10) printf("In [%s::%s Line: %d] *** Faction thread preprocessing took [%lld] msecs for %d factions for frameCount = %d slavesCompleted = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),factionCount,frameCount,slavesCompleted); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } } else { // Signal the faction threads to do any pre-processing for(int i = 0; i < factionCount; ++i) { Faction *faction = getFaction(i); faction->signalWorkerThread(frameCount); } if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } Chrono chrono; chrono.start(); const int MAX_FACTION_THREAD_WAIT_MILLISECONDS = 20000; for(;chrono.getMillis() < MAX_FACTION_THREAD_WAIT_MILLISECONDS;) { bool workThreadsFinished = true; for(int i = 0; i < factionCount; ++i) { Faction *faction = getFaction(i); if(faction->isWorkerThreadSignalCompleted(frameCount) == false) { workThreadsFinished = false; break; } } if(workThreadsFinished == true) { break; } // WARNING... Sleep in here causes the server to lag a bit //if(chrono.getMillis() % 5 == 0) { // sleep(0); //} } if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } if(SystemFlags::VERBOSE_MODE_ENABLED && chrono.getMillis() >= 10) printf("In [%s::%s Line: %d] *** Faction thread preprocessing took [%lld] msecs for %d factions for frameCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),factionCount,frameCount); } if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } //units Chrono chronoPerfUnit; int totalUnitsChecked = 0; int totalUnitsProcessed = 0; for(int i = 0; i < factionCount; ++i) { Faction *faction = getFaction(i); faction->dumpWorldSynchThreadedLogList(); faction->clearUnitsPathfinding(); std::map mapCommandCount; std::map mapSkillCount; int unitCountStuck = 0; int unitCountUpdated = 0; int unitCount = faction->getUnitCount(); for(int j = 0; j < unitCount; ++j) { Unit *unit = faction->getUnit(j); if(unit == NULL) { throw megaglest_runtime_error("unit == NULL"); } CommandClass unitCommandClass = ccCount; if(unit->getCurrCommand() != NULL) { unitCommandClass = unit->getCurrCommand()->getCommandType()->getClass(); } SkillClass unitSkillClass = scCount; if(unit->getCurrSkill() != NULL) { unitSkillClass = unit->getCurrSkill()->getClass(); } if(showPerfStats) chronoPerfUnit.start(); int unitBlockCount = unit->getPath()->getBlockCount(); bool isStuck = unit->getPath()->isStuck(); //bool isStuckWithinTolerance = unit->isLastStuckFrameWithinCurrentFrameTolerance(false); //uint32 lastStuckFrame = unit->getLastStuckFrame(); if(unitUpdater.updateUnit(unit) == true) { unitCountUpdated++; if(unit->getLastStuckFrame() == (unsigned int)frameCount) { unitCountStuck++; } mapCommandCount[unitCommandClass] = mapCommandCount[unitCommandClass] + 1; mapSkillCount[unitSkillClass] = mapSkillCount[unitSkillClass] + 1; } totalUnitsChecked++; if(showPerfStats && chronoPerfUnit.getMillis() >= 10) { //sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER " stuck: %d [%d] for unit:\n%sBEFORE unitBlockCount = %d, AFTER = %d, BEFORE lastStuckFrame = %u, AFTER: %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerfUnit.getMillis(),isStuck,isStuckWithinTolerance,unit->toString().c_str(),unitBlockCount,unit->getPath()->getBlockCount(),lastStuckFrame,unit->getLastStuckFrame()); sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER " stuck: %d for unit:\n%sBEFORE unitBlockCount = %d, AFTER = %d, BEFORE , AFTER: %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerfUnit.getMillis(),isStuck,unit->toString().c_str(),unitBlockCount,unit->getPath()->getBlockCount(),unit->getLastStuckFrame()); perfList.push_back(perfBuf); } } totalUnitsProcessed += unitCountUpdated; if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER " faction: %d / %d unitCount = %d unitCountUpdated = %d unitCountStuck = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis(),i+1,factionCount,unitCount,unitCountUpdated,unitCountStuck); perfList.push_back(perfBuf); for(std::map::iterator iterMap = mapCommandCount.begin(); iterMap != mapCommandCount.end(); ++iterMap) { sprintf(perfBuf,"Command class = %d, count = %d\n",iterMap->first,iterMap->second); perfList.push_back(perfBuf); } for(std::map::iterator iterMap = mapSkillCount.begin(); iterMap != mapSkillCount.end(); ++iterMap) { sprintf(perfBuf,"Skill class = %d, count = %d\n",iterMap->first,iterMap->second); perfList.push_back(perfBuf); } } } if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER " totalUnitsProcessed = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis(),totalUnitsProcessed); perfList.push_back(perfBuf); } if(showPerfStats && chronoPerf.getMillis() >= 50) { for(unsigned int x = 0; x < perfList.size(); ++x) { printf("%s",perfList[x].c_str()); } } if(SystemFlags::VERBOSE_MODE_ENABLED && chrono.getMillis() >= 20) printf("In [%s::%s Line: %d] *** Faction MAIN thread processing took [%lld] msecs for %d factions for frameCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),factionCount,frameCount); } void World::underTakeDeadFactionUnits() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); int factionCount = getFactionCount(); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] factionCount = %d\n",__FILE__,__FUNCTION__,__LINE__,factionCount); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); //undertake the dead for(int i = 0; i< factionCount; ++i) { Faction *faction = getFaction(i); int unitCount = faction->getUnitCount(); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] i = %d, unitCount = %d\n",__FILE__,__FUNCTION__,__LINE__,i,unitCount); for(int j= unitCount - 1; j >= 0; j--) { Unit *unit= faction->getUnit(j); if(unit == NULL) { throw megaglest_runtime_error("unit == NULL"); } if(unit->getToBeUndertaken() == true) { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); unit->undertake(); delete unit; if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); } } } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); } void World::updateAllFactionConsumableCosts() { //food costs bool warningSoundNeeded=false; int resourceTypeCount = techTree->getResourceTypeCount(); int factionCount = getFactionCount(); for(int i = 0; i < resourceTypeCount; ++i) { const ResourceType *rt = techTree->getResourceType(i); if(rt != NULL && rt->getClass() == rcConsumable && frameCount % (rt->getInterval() * GameConstants::updateFps) == 0) { for(int j = 0; j < factionCount; ++j) { Faction *faction = getFaction(j); if(faction == NULL) { throw megaglest_runtime_error("faction == NULL"); } warningSoundNeeded = warningSoundNeeded || faction->applyCostsOnInterval(rt); } } } if (warningSoundNeeded) { CoreData &coreData = CoreData::getInstance(); //StaticSound *sound= static_cast(unit->getType()->getFirstStOfClass(scDie))->getSound(); SoundRenderer::getInstance().playFx(coreData.getHighlightSound()); } } void World::update() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); bool showPerfStats = Config::getInstance().getBool("ShowPerfStats","false"); Chrono chronoPerf; char perfBuf[8096]=""; std::vector perfList; if(showPerfStats) chronoPerf.start(); Chrono chronoGamePerformanceCounts; ++frameCount; //time timeFlow.update(); if(scriptManager) scriptManager->onDayNightTriggerEvent(); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } //water effects waterEffects.update(1.0f); // attack effects attackEffects.update(0.25f); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); // objects on the map from tilesets if(this->game) chronoGamePerformanceCounts.start(); updateAllTilesetObjects(); if(this->game) this->game->addPerformanceCount("updateAllTilesetObjects",chronoGamePerformanceCounts.getMillis()); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } //units if(getFactionCount() > 0) { if(this->game) chronoGamePerformanceCounts.start(); updateAllFactionUnits(); if(this->game) this->game->addPerformanceCount("updateAllFactionUnits",chronoGamePerformanceCounts.getMillis()); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } //undertake the dead if(this->game) chronoGamePerformanceCounts.start(); underTakeDeadFactionUnits(); if(this->game) this->game->addPerformanceCount("underTakeDeadFactionUnits",chronoGamePerformanceCounts.getMillis()); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); //food costs if(this->game) chronoGamePerformanceCounts.start(); updateAllFactionConsumableCosts(); if(this->game) this->game->addPerformanceCount("updateAllFactionConsumableCosts",chronoGamePerformanceCounts.getMillis()); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); //fow smoothing if(fogOfWarSmoothing && ((frameCount+1) % (fogOfWarSmoothingFrameSkip+1)) == 0) { if(this->game) chronoGamePerformanceCounts.start(); float fogFactor= static_cast(frameCount % GameConstants::updateFps) / GameConstants::updateFps; minimap.updateFowTex(clamp(fogFactor, 0.f, 1.f)); if(this->game) this->game->addPerformanceCount("minimap.updateFowTex",chronoGamePerformanceCounts.getMillis()); } if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); //tick bool needToTick = canTickWorld(); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } if(needToTick == true) { //printf("=========== World is about to be updated, current frameCount = %d\n",frameCount); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); if(this->game) chronoGamePerformanceCounts.start(); tick(); if(this->game) this->game->addPerformanceCount("world->tick",chronoGamePerformanceCounts.getMillis()); } if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } } if(showPerfStats && chronoPerf.getMillis() >= 50) { for(unsigned int x = 0; x < perfList.size(); ++x) { printf("%s",perfList[x].c_str()); } } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); } bool World::canTickWorld() const { //tick bool needToTick = (frameCount % GameConstants::updateFps == 0); return needToTick; } void World::tick() { bool showPerfStats = Config::getInstance().getBool("ShowPerfStats","false"); Chrono chronoPerf; char perfBuf[8096]=""; std::vector perfList; if(showPerfStats) chronoPerf.start(); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } Chrono chronoGamePerformanceCounts; if(this->game) chronoGamePerformanceCounts.start(); computeFow(); if(this->game) this->game->addPerformanceCount("world->computeFow",chronoGamePerformanceCounts.getMillis()); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER " fogOfWar: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis(),fogOfWar); perfList.push_back(perfBuf); } if(fogOfWarSmoothing == false) { if(this->game) chronoGamePerformanceCounts.start(); minimap.updateFowTex(1.f); if(this->game) this->game->addPerformanceCount("minimap.updateFowTex",chronoGamePerformanceCounts.getMillis()); } if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } //increase hp if(this->game) chronoGamePerformanceCounts.start(); int factionCount = getFactionCount(); for(int factionIndex = 0; factionIndex < factionCount; ++factionIndex) { Faction *faction = getFaction(factionIndex); int unitCount = faction->getUnitCount(); for(int unitIndex = 0; unitIndex < unitCount; ++unitIndex) { Unit *unit = faction->getUnit(unitIndex); if(unit == NULL) { throw megaglest_runtime_error("unit == NULL"); } unit->tick(); } } if(this->game) this->game->addPerformanceCount("world unit->tick()",chronoGamePerformanceCounts.getMillis()); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } //compute resources balance if(this->game) chronoGamePerformanceCounts.start(); std::map > resourceCostCache; factionCount = getFactionCount(); for(int factionIndex = 0; factionIndex < factionCount; ++factionIndex) { Faction *faction = getFaction(factionIndex); //for each resource for(int resourceTypeIndex = 0; resourceTypeIndex < techTree->getResourceTypeCount(); ++resourceTypeIndex) { const ResourceType *rt= techTree->getResourceType(resourceTypeIndex); //if consumable if(rt != NULL && rt->getClass() == rcConsumable) { int balance= 0; for(int unitIndex = 0; unitIndex < faction->getUnitCount(); ++unitIndex) { //if unit operative and has this cost const Unit *unit = faction->getUnit(unitIndex); if(unit != NULL && unit->isOperative()) { const UnitType *ut = unit->getType(); const Resource *resource = NULL; std::map >::iterator iterFind = resourceCostCache.find(ut); if(iterFind != resourceCostCache.end() && iterFind->second.find(rt) != iterFind->second.end()) { resource = iterFind->second.find(rt)->second; } else { resource = ut->getCost(rt); resourceCostCache[ut][rt] = resource; } if(resource != NULL) { balance -= resource->getAmount(); } } } faction->setResourceBalance(rt, balance); } } } if(this->game) this->game->addPerformanceCount("world faction->setResourceBalance()",chronoGamePerformanceCounts.getMillis()); if(showPerfStats) { sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); perfList.push_back(perfBuf); } if(showPerfStats && chronoPerf.getMillis() >= 50) { for(unsigned int x = 0; x < perfList.size(); ++x) { printf("%s",perfList[x].c_str()); } } } Unit* World::findUnitById(int id) const { for(int i= 0; ifindUnit(id); if(unit != NULL) { return unit; } } return NULL; } const UnitType* World::findUnitTypeById(const FactionType* factionType, int id) { if(factionType == NULL) { throw megaglest_runtime_error("factionType == NULL"); } for(int i= 0; i < factionType->getUnitTypeCount(); ++i) { const UnitType *unitType = factionType->getUnitType(i); if(unitType != NULL && unitType->getId() == id) { return unitType; } } return NULL; } const UnitType * World::findUnitTypeByName(const string factionName, const string unitTypeName) { const UnitType *unitTypeResult = NULL; for(int index = 0; unitTypeResult == NULL && index < getFactionCount(); ++index) { const Faction *faction = getFaction(index); if(factionName == "" || factionName == faction->getType()->getName(false)) { for(int unitIndex = 0; unitTypeResult == NULL && unitIndex < faction->getType()->getUnitTypeCount(); ++unitIndex) { const UnitType *unitType = faction->getType()->getUnitType(unitIndex); if(unitType != NULL && unitType->getName(false) == unitTypeName) { unitTypeResult = unitType; break; } } } } return unitTypeResult; } //looks for a place for a unit around a start location, returns true if succeded bool World::placeUnit(const Vec2i &startLoc, int radius, Unit *unit, bool spaciated, bool threaded) { if(unit == NULL) { throw megaglest_runtime_error("unit == NULL"); } bool freeSpace=false; int size= unit->getType()->getSize(); Field currField= unit->getCurrField(); for(int r = 1; r < radius; r++) { for(int i = -r; i < r; ++i) { for(int j = -r; j < r; ++j) { Vec2i pos= Vec2i(i,j) + startLoc; if(spaciated) { const int spacing = 2; freeSpace= map.isFreeCells(pos-Vec2i(spacing), size+spacing*2, currField); } else { freeSpace= map.isFreeCells(pos, size, currField); } if(freeSpace) { unit->setPos(pos, false, threaded); Vec2i meetingPos = pos-Vec2i(1); unit->setMeetingPos(meetingPos); return true; } } } } return false; } //clears a unit old position from map and places new position void World::moveUnitCells(Unit *unit, bool threaded) { if(unit == NULL) { throw megaglest_runtime_error("unit == NULL"); } Vec2i newPos= unit->getTargetPos(); //newPos must be free or the same pos as current // Only change cell placement in map if the new position is different // from the old one if(newPos != unit->getPos()) { map.clearUnitCells(unit, unit->getPos()); map.putUnitCells(unit, newPos, false, threaded); } // Add resources close by to the faction's cache unit->getFaction()->addCloseResourceTargetToCache(newPos); //water splash if(tileset.getWaterEffects() && unit->getCurrField() == fLand) { if(map.getSubmerged(map.getCell(unit->getLastPos()))) { if(Thread::isCurrentThreadMainThread() == false) { throw megaglest_runtime_error("#1 Invalid access to World random from outside main thread current id = " + intToStr(Thread::getCurrentThreadId()) + " main = " + intToStr(Thread::getMainThreadId())); } int unitSize= unit->getType()->getSize(); for(int i = 0; i < 3; ++i) { waterEffects.addWaterSplash( Vec2f(unit->getLastPos().x+(float)unitSize/2.0f+random.randRange(-0.9f, -0.1f), unit->getLastPos().y+random.randRange(-0.9f, -0.1f)+(float)unitSize/2.0f), unit->getType()->getSize()); } } } if(scriptManager) scriptManager->onCellTriggerEvent(unit); } void World::addAttackEffects(const Unit *unit) { attackEffects.addWaterSplash( Vec2f(unit->getPosNotThreadSafe().x, unit->getPosNotThreadSafe().y),1); } //returns the nearest unit that can store a type of resource given a position and a faction Unit *World::nearestStore(const Vec2i &pos, int factionIndex, const ResourceType *rt) { float currDist = infinity; Unit *currUnit= NULL; if(factionIndex >= getFactionCount()) { throw megaglest_runtime_error("factionIndex >= getFactionCount()"); } for(int i=0; i < getFaction(factionIndex)->getUnitCount(); ++i) { Unit *u= getFaction(factionIndex)->getUnit(i); if(u != NULL) { float tmpDist= u->getPos().dist(pos); if(tmpDist < currDist && u->getType() != NULL && u->getType()->getStore(rt) > 0 && u->isOperative()) { currDist= tmpDist; currUnit= u; } } } return currUnit; } bool World::toRenderUnit(const Unit *unit, const Quad2i &visibleQuad) const { if(unit == NULL) { throw megaglest_runtime_error("unit == NULL"); } //a unit is rendered if it is in a visible cell or is attacking a unit in a visible cell return visibleQuad.isInside(unit->getPosNotThreadSafe()) && toRenderUnit(unit); } bool World::toRenderUnit(const Unit *unit) const { if(unit == NULL) { throw megaglest_runtime_error("unit == NULL"); } if(showWorldForPlayer(thisFactionIndex) == true) { return true; } return (map.getSurfaceCell(Map::toSurfCoords(unit->getCenteredPos()))->isVisible(thisTeamIndex) && map.getSurfaceCell(Map::toSurfCoords(unit->getCenteredPos()))->isExplored(thisTeamIndex) ) || (unit->getCurrSkill()->getClass()==scAttack && map.getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->isVisible(thisTeamIndex) && map.getSurfaceCell(Map::toSurfCoords(unit->getTargetPos()))->isExplored(thisTeamIndex)); } bool World::toRenderUnit(const UnitBuildInfo &pendingUnit) const { if(pendingUnit.unit == NULL) { throw megaglest_runtime_error("unit == NULL"); } if(showWorldForPlayer(thisFactionIndex) == true) { return true; } if(pendingUnit.unit->getTeam() != thisTeamIndex) { return false; } return (map.getSurfaceCell(Map::toSurfCoords(pendingUnit.pos))->isVisible(thisTeamIndex) && map.getSurfaceCell(Map::toSurfCoords(pendingUnit.pos))->isExplored(thisTeamIndex) ); } void World::morphToUnit(int unitId,const string &morphName,bool ignoreRequirements) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] unit [%d] morphName [%s] forceUpgradesIfRequired = %d\n",__FILE__,__FUNCTION__,__LINE__,unitId,morphName.c_str(),ignoreRequirements); Unit* unit= findUnitById(unitId); if(unit != NULL) { for(int i = 0; i < unit->getType()->getCommandTypeCount(); ++i) { const CommandType *ct = unit->getType()->getCommandType(i); const MorphCommandType *mct = dynamic_cast(ct); if(mct != NULL && mct->getName(false) == morphName) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] unit [%d] morphName [%s] comparing mct [%s]\n",__FILE__,__FUNCTION__,__LINE__,unitId,morphName.c_str(),mct->getName(false).c_str()); std::pair cr(crFailUndefined,""); try { if(unit->getFaction()->reqsOk(mct) == false && ignoreRequirements == true) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] unit [%d] morphName [%s] comparing mct [%s] mct->getUpgradeReqCount() = %d\n",__FILE__,__FUNCTION__,__LINE__,unitId,morphName.c_str(),mct->getName(false).c_str(),mct->getUpgradeReqCount()); unit->setIgnoreCheckCommand(true); } const UnitType* unitType = mct->getMorphUnit(); cr = this->game->getCommander()->tryGiveCommand(unit, mct,unit->getPos(), unitType,CardinalDir(CardinalDir::NORTH)); } catch(const exception &ex) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->setIgnoreCheckCommand(false); throw megaglest_runtime_error(ex.what()); } if(cr.first == crSuccess) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } else { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] unit [%d] morphName [%s] comparing mct [%s] returned = %d\n",__FILE__,__FUNCTION__,__LINE__,unitId,morphName.c_str(),mct->getName(false).c_str(),cr.first); break; } } if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } } void World::createUnit(const string &unitName, int factionIndex, const Vec2i &pos, bool spaciated) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unitName [%s] factionIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,unitName.c_str(),factionIndex); if(factionIndex < (int)factions.size()) { Faction* faction= factions[factionIndex]; if(faction->getIndex() != factionIndex) { throw megaglest_runtime_error("faction->getIndex() != factionIndex",true); } const FactionType* ft= faction->getType(); const UnitType* ut= ft->getUnitType(unitName); UnitPathInterface *newpath = NULL; switch(game->getGameSettings()->getPathFinderType()) { case pfBasic: newpath = new UnitPathBasic(); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!",true); } Unit* unit= new Unit(getNextUnitId(faction), newpath, pos, ut, faction, &map, CardinalDir(CardinalDir::NORTH)); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str()); if(placeUnit(pos, generationArea, unit, spaciated)) { unit->create(true); unit->born(NULL); if(scriptManager) { scriptManager->onUnitCreated(unit); } if(game->getPaused()==true){ // new units added in pause mode might change the Fow. ( Scenarios do this ) computeFow(); minimap.updateFowTex(1.f); } } else { delete unit; unit = NULL; throw megaglest_runtime_error("Unit cant be placed",true); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str()); } else { throw megaglest_runtime_error("Invalid faction index in createUnitAtPosition: " + intToStr(factionIndex),true); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void World::giveResource(const string &resourceName, int factionIndex, int amount) { if(factionIndex < (int)factions.size()) { Faction* faction= factions[factionIndex]; const ResourceType* rt= techTree->getResourceType(resourceName); faction->incResourceAmount(rt, amount); } else { throw megaglest_runtime_error("Invalid faction index in giveResource: " + intToStr(factionIndex),true); } } int World::getUnitCurrentField(int unitId) { int field = -1; if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] unit [%d]\n",__FILE__,__FUNCTION__,__LINE__,unitId); Unit* unit= findUnitById(unitId); if(unit != NULL) { field = unit->getCurrField(); } return field; } bool World::getIsUnitAlive(int unitId) { bool result = false; if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] unit [%d]\n",__FILE__,__FUNCTION__,__LINE__,unitId); Unit* unit= findUnitById(unitId); if(unit != NULL) { result = unit->isAlive(); } return result; } vector World::getUnitsForFaction(int factionIndex,const string& commandTypeName, int field) { vector units; if(factionIndex < 0 || factionIndex > getFactionCount()) { throw megaglest_runtime_error("Invalid faction index in getUnitsForFaction: " + intToStr(factionIndex),true); } Faction *faction = getFaction(factionIndex); if(faction != NULL) { CommandType *commandType = NULL; if(commandTypeName != "") { commandType = CommandTypeFactory::getInstance().newInstance(commandTypeName); } int unitCount = faction->getUnitCount(); for(int i = 0; i < unitCount; ++i) { Unit *unit = faction->getUnit(i); if(unit != NULL) { bool addToList = true; if(commandType != NULL) { if(commandType->getClass() == ccAttack && field >= 0) { const AttackCommandType *act = unit->getType()->getFirstAttackCommand(static_cast(field)); addToList = (act != NULL); } else if(commandType->getClass() == ccAttackStopped && field >= 0) { const AttackStoppedCommandType *asct = unit->getType()->getFirstAttackStoppedCommand(static_cast(field)); addToList = (asct != NULL); } else { addToList = unit->getType()->hasCommandClass(commandType->getClass()); } } else if(field >= 0) { addToList = (unit->getCurrField() == static_cast(field)); } if(addToList == true) { units.push_back(unit->getId()); } } } delete commandType; commandType = NULL; } return units; } void World::givePositionCommand(int unitId, const string &commandName, const Vec2i &pos) { Unit* unit= findUnitById(unitId); if(unit != NULL) { CommandClass cc; if(commandName=="move") { cc= ccMove; } else if(commandName=="attack") { cc= ccAttack; } else { throw megaglest_runtime_error("Invalid position command: " + commandName,true); } if(unit->getType()->getFirstCtOfClass(cc) == NULL) { throw megaglest_runtime_error("Invalid command: [" + commandName + "] for unit: [" + unit->getType()->getName(false) + "] id [" + intToStr(unit->getId()) + "]",true); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] cc = %d Unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,cc,unit->getFullName(false).c_str()); unit->giveCommand(new Command( unit->getType()->getFirstCtOfClass(cc), pos )); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } else { throw megaglest_runtime_error("Invalid unitId index in givePositionCommand: " + intToStr(unitId) + " commandName = " + commandName,true); } } void World::giveStopCommand(int unitId) { Unit* unit= findUnitById(unitId); if(unit != NULL) { const CommandType *ct = unit->getType()->getFirstCtOfClass(ccStop); if(ct != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] Unit [%s] will stop\n",__FILE__,__FUNCTION__,__LINE__,unit->getFullName(false).c_str()); unit->giveCommand(new Command(ct)); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } else { throw megaglest_runtime_error("Invalid ct in giveStopCommand: " + intToStr(unitId),true); } } else { throw megaglest_runtime_error("Invalid unitId index in giveStopCommand: " + intToStr(unitId),true); } } bool World::selectUnit(int unitId) { bool result = false; Unit* unit= findUnitById(unitId); if(unit != NULL) { result = game->addUnitToSelection(unit); } return result; } void World::unselectUnit(int unitId) { Unit* unit= findUnitById(unitId); if(unit != NULL) { game->removeUnitFromSelection(unit); } } void World::addUnitToGroupSelection(int unitId,int groupIndex) { Unit* unit= findUnitById(unitId); if(unit != NULL) { game->addUnitToGroupSelection(unit,groupIndex); } } void World::removeUnitFromGroupSelection(int unitId,int groupIndex) { game->removeUnitFromGroupSelection(unitId,groupIndex); } void World::recallGroupSelection(int groupIndex) { game->recallGroupSelection(groupIndex); } void World::setAttackWarningsEnabled(bool enabled) { this->disableAttackEffects = !enabled; } bool World::getAttackWarningsEnabled() { return (this->disableAttackEffects == false); } void World::giveAttackCommand(int unitId, int unitToAttackId) { Unit* unit= findUnitById(unitId); if(unit != NULL) { Unit* targetUnit = findUnitById(unitToAttackId); if(targetUnit != NULL) { const CommandType *ct = unit->getType()->getFirstAttackCommand(targetUnit->getCurrField()); if(ct != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] Unit [%s] is attacking [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->getFullName(false).c_str(),targetUnit->getFullName(false).c_str()); unit->giveCommand(new Command(ct,targetUnit)); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } else { throw megaglest_runtime_error("Invalid ct in giveAttackCommand: " + intToStr(unitId) + " unitToAttackId = " + intToStr(unitToAttackId),true); } } else { throw megaglest_runtime_error("Invalid unitToAttackId index in giveAttackCommand: " + intToStr(unitId) + " unitToAttackId = " + intToStr(unitToAttackId),true); } } else { throw megaglest_runtime_error("Invalid unitId index in giveAttackCommand: " + intToStr(unitId) + " unitToAttackId = " + intToStr(unitToAttackId),true); } } void World::giveProductionCommand(int unitId, const string &producedName) { //printf("File: %s line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__); Unit *unit= findUnitById(unitId); //printf("File: %s line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__); if(unit != NULL) { //printf("File: %s line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__); const UnitType *ut= unit->getType(); //printf("File: %s line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__); //Search for a command that can produce the unit for(int i= 0; i< ut->getCommandTypeCount(); ++i) { const CommandType* ct= ut->getCommandType(i); if(ct != NULL && ct->getClass() == ccProduce) { const ProduceCommandType *pct= dynamic_cast(ct); if(pct != NULL && pct->getProducedUnit() != NULL && pct->getProducedUnit()->getName(false) == producedName) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); //printf("File: %s line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__); unit->giveCommand(new Command(pct)); //printf("File: %s line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); break; } } } } else { throw megaglest_runtime_error("Invalid unitId index in giveProductionCommand: " + intToStr(unitId) + " producedName = " + producedName,true); } //printf("File: %s line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__LINE__); } void World::giveAttackStoppedCommand(int unitId, const string &itemName, bool ignoreRequirements) { Unit *unit= findUnitById(unitId); if(unit != NULL) { const UnitType *ut= unit->getType(); //Search for a command that can produce the unit for(int i= 0; i < ut->getCommandTypeCount(); ++i) { const CommandType* ct= ut->getCommandType(i); if(ct != NULL && ct->getClass() == ccAttackStopped) { const AttackStoppedCommandType *act= static_cast(ct); if(act != NULL && act->getName(false) == itemName) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); try { if(unit->getFaction()->reqsOk(act) == false && ignoreRequirements == true) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->setIgnoreCheckCommand(true); } unit->giveCommand(new Command(act)); } catch(const exception &ex) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->setIgnoreCheckCommand(false); throw megaglest_runtime_error(ex.what()); } if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); break; } } } } else { throw megaglest_runtime_error("Invalid unitId index in giveAttackStoppedCommand: " + intToStr(unitId) + " itemName = " + itemName,true); } } void World::playStaticSound(const string &playSound) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] playSound [%s]\n",__FILE__,__FUNCTION__,__LINE__,playSound.c_str()); string calculatedFilePath = playSound; bool changed = Properties::applyTagsToValue(calculatedFilePath); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("\n\nPlay static sound changed: %d [%s] [%s]\n\n",changed, playSound.c_str(),calculatedFilePath.c_str()); if(staticSoundList.find(calculatedFilePath) == staticSoundList.end()) { StaticSound *sound = new StaticSound(); sound->load(calculatedFilePath); staticSoundList[calculatedFilePath] = sound; } StaticSound *playSoundItem = staticSoundList[calculatedFilePath]; SoundRenderer &soundRenderer= SoundRenderer::getInstance(); soundRenderer.playFx(playSoundItem); } void World::playStreamingSound(const string &playSound) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] playSound [%s]\n",__FILE__,__FUNCTION__,__LINE__,playSound.c_str()); string calculatedFilePath = playSound; bool changed = Properties::applyTagsToValue(calculatedFilePath); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("\n\nPlay streaming sound changed: %d [%s] [%s]\n\n",changed, playSound.c_str(),calculatedFilePath.c_str()); if(streamSoundList.find(calculatedFilePath) == streamSoundList.end()) { StrSound *sound = new StrSound(); sound->open(calculatedFilePath); sound->setNext(sound); streamSoundList[calculatedFilePath] = sound; } StrSound *playSoundItem = streamSoundList[calculatedFilePath]; SoundRenderer &soundRenderer= SoundRenderer::getInstance(); soundRenderer.playMusic(playSoundItem); } void World::stopStreamingSound(const string &playSound) { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d] playSound [%s]\n",__FILE__,__FUNCTION__,__LINE__,playSound.c_str()); string calculatedFilePath = playSound; bool changed = Properties::applyTagsToValue(calculatedFilePath); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("\n\nStop streaming sound changed: %d [%s] [%s]\n\n",changed, playSound.c_str(),calculatedFilePath.c_str()); if(streamSoundList.find(calculatedFilePath) != streamSoundList.end()) { StrSound *playSoundItem = streamSoundList[calculatedFilePath]; SoundRenderer &soundRenderer= SoundRenderer::getInstance(); soundRenderer.stopMusic(playSoundItem); } } void World::stopAllSound() { if(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled) SystemFlags::OutputDebug(SystemFlags::debugLUA,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); SoundRenderer &soundRenderer= SoundRenderer::getInstance(); soundRenderer.stopAllSounds(); } void World::moveToUnit(int unitId, int destUnitId) { Unit* unit= findUnitById(unitId); if(unit != NULL) { CommandClass cc= ccMove; if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] cc = %d Unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,cc,unit->getFullName(false).c_str()); Unit* destUnit = findUnitById(destUnitId); if(destUnit != NULL) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d] cc = %d Unit [%s] destUnit [%s]\n",__FILE__,__FUNCTION__,__LINE__,cc,unit->getFullName(false).c_str(),destUnit->getFullName(false).c_str()); unit->giveCommand(new Command( unit->getType()->getFirstCtOfClass(cc), destUnit)); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } } else { throw megaglest_runtime_error("Invalid unitId index in followUnit: " + intToStr(unitId),true); } } void World::clearCaches() { ExploredCellsLookupItemCache.clear(); ExploredCellsLookupItemCacheTimer.clear(); ExploredCellsLookupItemCacheTimerCount = 0; unitUpdater.clearCaches(); } void World::togglePauseGame(bool pauseStatus,bool forceAllowPauseStateChange) { game->setPaused(pauseStatus, forceAllowPauseStateChange, false, false); // ensures that the Fow is really up to date when the game switches to pause mode. ( mainly for scenarios ) computeFow(); minimap.updateFowTex(1.f); } void World::addConsoleText(const string &text) { game->getConsole()->addStdScenarioMessage(text); } void World::addConsoleTextWoLang(const string &text) { game->getConsole()->addLine(text); } const string World::getSystemMacroValue(const string key) { std::string result = key; bool tagApplied = Properties::applyTagsToValue(result); if(tagApplied == false) { result = ""; if(key == "$SCENARIO_PATH") { result = extractDirectoryPathFromFile(game->getGameSettings()->getScenarioDir()); } } if(SystemFlags::VERBOSE_MODE_ENABLED) printf("system macro key [%s] returning [%s]\n",key.c_str(),result.c_str()); return result; } const string World::getPlayerName(int factionIndex) { return game->getGameSettings()->getNetworkPlayerName(factionIndex); } void World::giveUpgradeCommand(int unitId, const string &upgradeName) { Unit *unit= findUnitById(unitId); if(unit != NULL) { const UnitType *ut= unit->getType(); //Search for a command that can produce the unit for(int i= 0; i < ut->getCommandTypeCount(); ++i) { const CommandType* ct= ut->getCommandType(i); if(ct != NULL && ct->getClass() == ccUpgrade) { const UpgradeCommandType *uct= static_cast(ct); if(uct != NULL && uct->getProducedUpgrade()->getName() == upgradeName) { if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); unit->giveCommand(new Command(uct)); if(SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled) SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); break; } } } } else { throw megaglest_runtime_error("Invalid unitId index in giveUpgradeCommand: " + intToStr(unitId) + " upgradeName = " + upgradeName,true); } } int World::getResourceAmount(const string &resourceName, int factionIndex) { if(factionIndex < (int)factions.size()) { Faction* faction= factions[factionIndex]; const ResourceType* rt= techTree->getResourceType(resourceName); return faction->getResource(rt)->getAmount(); } else { throw megaglest_runtime_error("Invalid faction index in giveResource: " + intToStr(factionIndex) + " resourceName = " + resourceName,true); } } Vec2i World::getStartLocation(int factionIndex) { if(factionIndex < (int)factions.size()) { Faction* faction= factions[factionIndex]; return map.getStartLocation(faction->getStartLocationIndex()); } else { printf("\n=================================================\n%s\n",game->getGameSettings()->toString().c_str()); throw megaglest_runtime_error("Invalid faction index in getStartLocation: " + intToStr(factionIndex) + " : " + intToStr(factions.size()),true); } } Vec2i World::getUnitPosition(int unitId) { Unit* unit= findUnitById(unitId); if(unit == NULL) { throw megaglest_runtime_error("Can not find unit to get position unitId = " + intToStr(unitId),true); } return unit->getPos(); } void World::setUnitPosition(int unitId, Vec2i pos) { Unit* unit= findUnitById(unitId); if(unit == NULL) { throw megaglest_runtime_error("Can not find unit to set position unitId = " + intToStr(unitId),true); } unit->setTargetPos(pos); this->moveUnitCells(unit, false); } void World::addCellMarker(Vec2i pos, int factionIndex, const string ¬e, const string textureFile) { const Faction *faction = NULL; if(factionIndex >= 0) { faction = this->getFaction(factionIndex); } Vec2i surfaceCellPos = map.toSurfCoords(pos); SurfaceCell *sc = map.getSurfaceCell(surfaceCellPos); if(sc == NULL) { throw megaglest_runtime_error("sc == NULL",true); } Vec3f vertex = sc->getVertex(); Vec2i targetPos(vertex.x,vertex.z); //printf("pos [%s] scPos [%s][%p] targetPos [%s]\n",pos.getString().c_str(),surfaceCellPos.getString().c_str(),sc,targetPos.getString().c_str()); MarkedCell mc(targetPos,faction,note,(faction != NULL ? faction->getStartLocationIndex() : -1)); game->addCellMarker(surfaceCellPos, mc); } void World::removeCellMarker(Vec2i pos, int factionIndex) { const Faction *faction = NULL; if(factionIndex >= 0) { faction = this->getFaction(factionIndex); } Vec2i surfaceCellPos = map.toSurfCoords(pos); game->removeCellMarker(surfaceCellPos, faction); } void World::showMarker(Vec2i pos, int factionIndex, const string ¬e, const string textureFile, int flashCount) { const Faction *faction = NULL; if(factionIndex >= 0) { faction = this->getFaction(factionIndex); } Vec2i surfaceCellPos = map.toSurfCoords(pos); SurfaceCell *sc = map.getSurfaceCell(surfaceCellPos); if(sc == NULL) { throw megaglest_runtime_error("sc == NULL",true); } Vec3f vertex = sc->getVertex(); Vec2i targetPos(vertex.x,vertex.z); //printf("pos [%s] scPos [%s][%p] targetPos [%s]\n",pos.getString().c_str(),surfaceCellPos.getString().c_str(),sc,targetPos.getString().c_str()); MarkedCell mc(targetPos,faction,note,(faction != NULL ? faction->getStartLocationIndex() : -1)); if(flashCount > 0) { mc.setAliveCount(flashCount); } game->showMarker(surfaceCellPos, mc); } void World::highlightUnit(int unitId,float radius, float thickness, Vec4f color) { Unit* unit= findUnitById(unitId); if(unit == NULL) { throw megaglest_runtime_error("Can not find unit to set highlight unitId = " + intToStr(unitId),true); } game->highlightUnit(unitId,radius, thickness, color); } void World::unhighlightUnit(int unitId) { Unit* unit= findUnitById(unitId); if(unit == NULL) { throw megaglest_runtime_error("Can not find unit to set highlight unitId = " + intToStr(unitId),true); } game->unhighlightUnit(unitId); } int World::getUnitFactionIndex(int unitId) { Unit* unit= findUnitById(unitId); if(unit == NULL) { throw megaglest_runtime_error("Can not find Faction unit to get position unitId = " + intToStr(unitId),true); } return unit->getFactionIndex(); } const string World::getUnitName(int unitId) { Unit* unit= findUnitById(unitId); if(unit == NULL) { throw megaglest_runtime_error("Can not find Faction unit to get position unitId = " + intToStr(unitId),true); } return unit->getFullName(game->showTranslatedTechTree()); } int World::getUnitCount(int factionIndex) { if(factionIndex < (int)factions.size()) { Faction* faction= factions[factionIndex]; int count= 0; for(int i= 0; i < faction->getUnitCount(); ++i) { const Unit* unit= faction->getUnit(i); if(unit != NULL && unit->isAlive()) { ++count; } } return count; } else { throw megaglest_runtime_error("Invalid faction index in getUnitCount: " + intToStr(factionIndex),true); } } int World::getUnitCountOfType(int factionIndex, const string &typeName) { if(factionIndex < (int)factions.size()) { Faction* faction= factions[factionIndex]; int count= 0; for(int i= 0; i< faction->getUnitCount(); ++i) { const Unit* unit= faction->getUnit(i); if(unit != NULL && unit->isAlive() && unit->getType()->getName(false) == typeName) { ++count; } } return count; } else { throw megaglest_runtime_error("Invalid faction index in getUnitCountOfType: " + intToStr(factionIndex),true); } } // ==================== PRIVATE ==================== // ==================== private init ==================== //init basic cell state void World::initCells(bool fogOfWar) { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameLoadingStateCells","",true), true); for(int i=0; i< map.getSurfaceW(); ++i) { for(int j=0; j< map.getSurfaceH(); ++j) { SurfaceCell *sc= map.getSurfaceCell(i, j); if(sc == NULL) { throw megaglest_runtime_error("sc == NULL"); } if(sc->getObject()!=NULL){ sc->getObject()->initParticles(); } sc->setFowTexCoord(Vec2f( i/(next2Power(map.getSurfaceW())-1.f), j/(next2Power(map.getSurfaceH())-1.f))); for (int k = 0; k < GameConstants::maxPlayers; k++) { sc->setExplored(k, (game->getGameSettings()->getFlagTypes1() & ft1_show_map_resources) == ft1_show_map_resources); sc->setVisible(k, !fogOfWar); } for (int k = GameConstants::maxPlayers; k < GameConstants::maxPlayers + GameConstants::specialFactions; k++) { sc->setExplored(k, true); sc->setVisible(k, true); } if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true) { char szBuf[8096]=""; snprintf(szBuf,8096,"In initCells() x = %d y = %d %s %s",i,j,sc->isVisibleString().c_str(),sc->isExploredString().c_str()); if(Thread::isCurrentThreadMainThread()) { //unit->logSynchDataThreaded(__FILE__,__LINE__,szBuf); SystemFlags::OutputDebug(SystemFlags::debugWorldSynch,szBuf); } } } } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } //init surface textures void World::initSplattedTextures() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); for(int i = 0; i < map.getSurfaceW() - 1; ++i) { for(int j = 0; j < map.getSurfaceH() - 1; ++j) { Vec2f coord; const Texture2D *texture=NULL; SurfaceCell *sc00= map.getSurfaceCell(i, j); SurfaceCell *sc10= map.getSurfaceCell(i+1, j); SurfaceCell *sc01= map.getSurfaceCell(i, j+1); SurfaceCell *sc11= map.getSurfaceCell(i+1, j+1); if(sc00 == NULL) { throw megaglest_runtime_error("sc00 == NULL"); } if(sc10 == NULL) { throw megaglest_runtime_error("sc10 == NULL"); } if(sc01 == NULL) { throw megaglest_runtime_error("sc01 == NULL"); } if(sc11 == NULL) { throw megaglest_runtime_error("sc11 == NULL"); } tileset.addSurfTex( sc00->getSurfaceType(), sc10->getSurfaceType(), sc01->getSurfaceType(), sc11->getSurfaceType(), coord, texture,j,i); sc00->setSurfTexCoord(coord); sc00->setSurfaceTexture(texture); } } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } //creates each faction looking at each faction name contained in GameSettings void World::initFactionTypes(GameSettings *gs) { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameLoadingFactionTypes","",true), true); if(gs == NULL) { throw megaglest_runtime_error("gs == NULL"); } if(gs->getFactionCount() > map.getMaxPlayers()) { throw megaglest_runtime_error("This map only supports "+intToStr(map.getMaxPlayers())+" players, factionCount is " + intToStr(gs->getFactionCount())); } //create stats //printf("World gs->getThisFactionIndex() = %d\n",gs->getThisFactionIndex()); if(this->game->isMasterserverMode() == true) { this->thisFactionIndex = -1; } else { this->thisFactionIndex= gs->getThisFactionIndex(); } stats.init(gs->getFactionCount(), this->thisFactionIndex, gs->getDescription(),gs->getTech()); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); //create factions //printf("this->thisFactionIndex = %d\n",this->thisFactionIndex); //factions.resize(gs->getFactionCount()); for(int i= 0; i < gs->getFactionCount(); ++i){ Faction *newFaction = new Faction(); factions.push_back(newFaction); } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] factions.size() = %d\n",__FILE__,__FUNCTION__,__LINE__,factions.size()); for(int i=0; i < (int)factions.size(); ++i) { FactionType *ft= techTree->getTypeByName(gs->getFactionTypeName(i)); if(ft == NULL) { throw megaglest_runtime_error("ft == NULL"); } factions[i]->init(ft, gs->getFactionControl(i), techTree, game, i, gs->getTeam(i), gs->getStartLocationIndex(i), i==thisFactionIndex, gs->getDefaultResources(),loadWorldNode); stats.setTeam(i, gs->getTeam(i)); stats.setFactionTypeName(i, formatString(gs->getFactionTypeName(i))); stats.setPersonalityType(i, getFaction(i)->getType()->getPersonalityType()); stats.setControl(i, gs->getFactionControl(i)); stats.setResourceMultiplier(i,(gs->getResourceMultiplierIndex(i)+5)*0.1f); stats.setPlayerName(i,gs->getNetworkPlayerName(i)); if(getFaction(i)->getTexture()) { stats.setPlayerColor(i,getFaction(i)->getTexture()->getPixmapConst()->getPixel3f(0, 0)); } } if(Config::getInstance().getBool("EnableNewThreadManager","false") == true) { std::vector slaveThreadList; for(unsigned int i = 0; i < factions.size(); ++i) { Faction *faction = factions[i]; slaveThreadList.push_back(faction->getWorkerThread()); } masterController.setSlaves(slaveThreadList); } if(loadWorldNode != NULL) { stats.loadGame(loadWorldNode); random.setLastNumber(loadWorldNode->getAttribute("random")->getIntValue()); thisFactionIndex = loadWorldNode->getAttribute("thisFactionIndex")->getIntValue(); // int thisTeamIndex; thisTeamIndex = loadWorldNode->getAttribute("thisTeamIndex")->getIntValue(); // int frameCount; frameCount = loadWorldNode->getAttribute("frameCount")->getIntValue(); //printf("**LOAD World thisFactionIndex = %d\n",thisFactionIndex); MutexSafeWrapper safeMutex(mutexFactionNextUnitId,string(__FILE__) + "_" + intToStr(__LINE__)); // std::map mapFactionNextUnitId; // for(std::map::iterator iterMap = mapFactionNextUnitId.begin(); // iterMap != mapFactionNextUnitId.end(); ++iterMap) { // XmlNode *factionNextUnitIdNode = worldNode->addChild("FactionNextUnitId"); // // factionNextUnitIdNode->addAttribute("key",intToStr(iterMap->first), mapTagReplacements); // factionNextUnitIdNode->addAttribute("value",intToStr(iterMap->second), mapTagReplacements); // } //!!! vector factionNextUnitIdNodeList = loadWorldNode->getChildList("FactionNextUnitId"); for(unsigned int i = 0; i < factionNextUnitIdNodeList.size(); ++i) { XmlNode *factionNextUnitIdNode = factionNextUnitIdNodeList[i]; int key = factionNextUnitIdNode->getAttribute("key")->getIntValue(); int value = factionNextUnitIdNode->getAttribute("value")->getIntValue(); mapFactionNextUnitId[key] = value; } safeMutex.ReleaseLock(); // //config // bool fogOfWarOverride; fogOfWarOverride = loadWorldNode->getAttribute("fogOfWarOverride")->getIntValue() != 0; // bool fogOfWar; fogOfWar = loadWorldNode->getAttribute("fogOfWar")->getIntValue() != 0; // int fogOfWarSmoothingFrameSkip; fogOfWarSmoothingFrameSkip = loadWorldNode->getAttribute("fogOfWarSmoothingFrameSkip")->getIntValue(); // bool fogOfWarSmoothing; fogOfWarSmoothing = loadWorldNode->getAttribute("fogOfWarSmoothing")->getIntValue() != 0; // Game *game; // Chrono chronoPerfTimer; // bool perfTimerEnabled; // // bool unitParticlesEnabled; unitParticlesEnabled = loadWorldNode->getAttribute("unitParticlesEnabled")->getIntValue() != 0; // std::map staticSoundList; // std::map streamSoundList; // // uint32 nextCommandGroupId; nextCommandGroupId = loadWorldNode->getAttribute("nextCommandGroupId")->getIntValue(); // string queuedScenarioName; queuedScenarioName = loadWorldNode->getAttribute("queuedScenarioName")->getValue(); // bool queuedScenarioKeepFactions; queuedScenarioKeepFactions = loadWorldNode->getAttribute("queuedScenarioKeepFactions")->getIntValue() != 0; if(loadWorldNode->hasAttribute("disableAttackEffects") == true) { disableAttackEffects = loadWorldNode->getAttribute("disableAttackEffects")->getIntValue() != 0; } } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(factions.empty() == false) { if(this->game->isMasterserverMode() == true) { thisTeamIndex = -1; } else { thisTeamIndex = getFaction(thisFactionIndex)->getTeam(); } } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void World::initMinimap() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); minimap.init(map.getW(), map.getH(), this, game->getGameSettings()->getFogOfWar()); Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameLoadingMinimapSurface","",true), true); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void World::initUnitsForScenario() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameLoadingGenerateGameElements","",true), true); //put starting units for(int i = 0; i < getFactionCount(); ++i) { Faction *f= factions[i]; const FactionType *ft= f->getType(); for(int j = 0; j < f->getUnitCount(); ++j) { Unit *unit = f->getUnit(j); int startLocationIndex= f->getStartLocationIndex(); if(placeUnit(map.getStartLocation(startLocationIndex), generationArea, unit, true)) { map.putUnitCells(unit, unit->getPos()); unit->setCurrSkill(scStop); //unit->create(true); //unit->born(); } else { string unitName = unit->getType()->getName(false); delete unit; unit = NULL; throw megaglest_runtime_error("Unit: " + unitName + " can't be placed, this error is caused because there\nis not enough room to put all units near their start location.\nmake a better/larger map. Faction: #" + intToStr(i) + " name: " + ft->getName(false)); } if (unit->getType()->hasSkillClass(scBeBuilt)) { map.flatternTerrain(unit); } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str()); } // Ensure Starting Resource Amount are adjusted to max store levels //f->limitResourcesToStore(); } map.computeNormals(); map.computeInterpolatedHeights(); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void World::placeUnitAtLocation(const Vec2i &location, int radius, Unit *unit, bool spaciated) { if(placeUnit(location, generationArea, unit, spaciated)) { unit->create(true); unit->born(NULL); } else { string unitName = unit->getType()->getName(false); string unitFactionName = unit->getFaction()->getType()->getName(false); int unitFactionIndex = unit->getFactionIndex(); delete unit; unit = NULL; char szBuf[8096]=""; snprintf(szBuf,8096,"Unit: [%s] can't be placed, this error is caused because there\nis not enough room to put all units near their start location.\nmake a better/larger map. Faction: #%d name: [%s]", unitName.c_str(),unitFactionIndex,unitFactionName.c_str()); throw megaglest_runtime_error(szBuf,false); } if (unit->getType()->hasSkillClass(scBeBuilt)) { map.flatternTerrain(unit); } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str()); } //place units randomly aroud start location void World::initUnits() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); Logger::getInstance().add(Lang::getInstance().getString("LogScreenGameLoadingGenerateGameElements","",true), true); bool gotError = false; bool skipStackTrace = false; string sErrBuf=""; try { //put starting units if(loadWorldNode == NULL) { for(int i = 0; i < getFactionCount(); ++i) { Faction *f= factions[i]; const FactionType *ft= f->getType(); for(int j = 0; j < ft->getStartingUnitCount(); ++j) { const UnitType *ut= ft->getStartingUnit(j); int initNumber= ft->getStartingUnitAmount(j); for(int l = 0; l < initNumber; l++) { UnitPathInterface *newpath = NULL; switch(game->getGameSettings()->getPathFinderType()) { case pfBasic: newpath = new UnitPathBasic(); break; default: throw megaglest_runtime_error("detected unsupported pathfinder type!"); } Unit *unit= new Unit(getNextUnitId(f), newpath, Vec2i(0), ut, f, &map, CardinalDir(CardinalDir::NORTH)); int startLocationIndex= f->getStartLocationIndex(); placeUnitAtLocation(map.getStartLocation(startLocationIndex), generationArea, unit, true); } } } // the following is done here in an extra loop and not in the loop above, because shared resources games // need to load all factions first, before calculating limitResourcesToStore() for(int i = 0; i < getFactionCount(); ++i) { Faction *f= factions[i]; // Ensure Starting Resource Amount are adjusted to max store levels f->limitResourcesToStore(); } } else { //printf("Load game setting unit pos\n"); refreshAllUnitExplorations(); } } catch(const megaglest_runtime_error &ex) { gotError = true; if(ex.wantStackTrace() == true) { char szErrBuf[8096]=""; snprintf(szErrBuf,8096,"In [%s::%s %d]",__FILE__,__FUNCTION__,__LINE__); sErrBuf = string(szErrBuf) + string("\nerror [") + string(ex.what()) + string("]\n"); } else { skipStackTrace = true; sErrBuf = ex.what(); } SystemFlags::OutputDebug(SystemFlags::debugError,sErrBuf.c_str()); } catch(const std::exception &ex) { gotError = true; char szErrBuf[8096]=""; snprintf(szErrBuf,8096,"In [%s::%s %d]",__FILE__,__FUNCTION__,__LINE__); sErrBuf = string(szErrBuf) + string("\nerror [") + string(ex.what()) + string("]\n"); SystemFlags::OutputDebug(SystemFlags::debugError,sErrBuf.c_str()); } map.computeNormals(); map.computeInterpolatedHeights(); if(gotError == true) { throw megaglest_runtime_error(sErrBuf,!skipStackTrace); } if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void World::refreshAllUnitExplorations() { for(unsigned int i = 0; i < (unsigned int)getFactionCount(); ++i) { Faction *faction = factions[i]; for(unsigned int j = 0; j < (unsigned int)faction->getUnitCount(); ++j) { Unit *unit = faction->getUnit(j); unit->refreshPos(); } } } void World::initMap() { if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); map.init(&tileset); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } void World::exploreCells(int teamIndex, ExploredCellsLookupItem &exploredCellsCache) { std::vector &cellList = exploredCellsCache.exploredCellList; for (int idx2 = 0; idx2 < (int)cellList.size(); ++idx2) { SurfaceCell* sc = cellList[idx2]; sc->setExplored(teamIndex, true); } cellList = exploredCellsCache.visibleCellList; for (int idx2 = 0; idx2 < (int)cellList.size(); ++idx2) { SurfaceCell* sc = cellList[idx2]; sc->setVisible(teamIndex, true); } } // ==================== exploration ==================== ExploredCellsLookupItem World::exploreCells(const Vec2i &newPos, int sightRange, int teamIndex, Unit *unit) { // cache lookup of previously calculated cells + sight range if(MaxExploredCellsLookupItemCache > 0) { if(difftime(time(NULL),ExploredCellsLookupItem::lastDebug) >= 10) { ExploredCellsLookupItem::lastDebug = time(NULL); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] ExploredCellsLookupItemCache.size() = %d\n",__FILE__,__FUNCTION__,__LINE__,ExploredCellsLookupItemCache.size()); if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] ExploredCellsLookupItemCache.size() = %d\n",__FILE__,__FUNCTION__,__LINE__,ExploredCellsLookupItemCache.size()); } // Ok we limit the cache size due to possible RAM constraints when // the threshold is met bool MaxExploredCellsLookupItemCacheTriggered = false; if((int)ExploredCellsLookupItemCache.size() >= MaxExploredCellsLookupItemCache) { MaxExploredCellsLookupItemCacheTriggered = true; // Snag the oldest entry in the list std::map::reverse_iterator purgeItem = ExploredCellsLookupItemCacheTimer.rbegin(); ExploredCellsLookupItemCache[purgeItem->second.pos].erase(purgeItem->second.sightRange); if(ExploredCellsLookupItemCache[purgeItem->second.pos].empty() == true) { ExploredCellsLookupItemCache.erase(purgeItem->second.pos); } ExploredCellsLookupItemCacheTimer.erase(purgeItem->first); } // Check the cache for the pos, sightrange and use from // cache if already found std::map >::iterator iterFind = ExploredCellsLookupItemCache.find(newPos); if(iterFind != ExploredCellsLookupItemCache.end()) { std::map::iterator iterFind2 = iterFind->second.find(sightRange); if(iterFind2 != iterFind->second.end()) { ExploredCellsLookupItem &exploredCellsCache = iterFind2->second; exploreCells(teamIndex, exploredCellsCache); // Only start worrying about updating the cache timer if we // have hit the threshold if(MaxExploredCellsLookupItemCacheTriggered == true) { // Remove the old timer entry since the search key id is stale ExploredCellsLookupItemCacheTimer.erase(exploredCellsCache.ExploredCellsLookupItemCacheTimerCountIndex); exploredCellsCache.ExploredCellsLookupItemCacheTimerCountIndex = ExploredCellsLookupItemCacheTimerCount++; ExploredCellsLookupKey lookupKey; lookupKey.pos = newPos; lookupKey.sightRange = sightRange; lookupKey.teamIndex = teamIndex; // Add a new search key since we just used this exploredCellsCache ExploredCellsLookupItemCacheTimer[exploredCellsCache.ExploredCellsLookupItemCacheTimerCountIndex] = lookupKey; } return exploredCellsCache; } } } Vec2i newSurfPos= Map::toSurfCoords(newPos); int surfSightRange= sightRange / Map::cellScale+1; // Explore, this code is quite expensive when we have lots of units ExploredCellsLookupItem exploredCellsCache; exploredCellsCache.exploredCellList.reserve(surfSightRange + indirectSightRange * 4); exploredCellsCache.visibleCellList.reserve(surfSightRange + indirectSightRange * 4); //int loopCount = 0; for(int i = -surfSightRange - indirectSightRange -1; i <= surfSightRange + indirectSightRange +1; ++i) { for(int j = -surfSightRange - indirectSightRange -1; j <= surfSightRange + indirectSightRange +1; ++j) { //loopCount++; Vec2i currRelPos= Vec2i(i, j); Vec2i currPos= newSurfPos + currRelPos; if(map.isInsideSurface(currPos) == true){ SurfaceCell *sc= map.getSurfaceCell(currPos); if(sc == NULL) { throw megaglest_runtime_error("sc == NULL"); } //explore float posLength = currRelPos.length(); bool updateExplored = (posLength < surfSightRange + indirectSightRange + 1); bool updateVisible = (posLength < surfSightRange); if(SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled == true && SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynchMax).enabled == true) { char szBuf[8096]=""; snprintf(szBuf,8096,"In exploreCells() currRelPos = %s currPos = %s posLength = %f updateExplored = %d updateVisible = %d sightRange = %d teamIndex = %d", currRelPos.getString().c_str(), currPos.getString().c_str(),posLength,updateExplored, updateVisible, sightRange, teamIndex); if(Thread::isCurrentThreadMainThread() == false) { unit->logSynchDataThreaded(__FILE__,__LINE__,szBuf); } else { unit->logSynchData(__FILE__,__LINE__,szBuf); } } if(updateExplored) { sc->setExplored(teamIndex, true); exploredCellsCache.exploredCellList.push_back(sc); } //visible if(updateVisible) { sc->setVisible(teamIndex, true); exploredCellsCache.visibleCellList.push_back(sc); } } } } // Ok update our caches with the latest info for this position, sight and team if(MaxExploredCellsLookupItemCache > 0) { if(exploredCellsCache.exploredCellList.empty() == false || exploredCellsCache.visibleCellList.empty() == false) { exploredCellsCache.ExploredCellsLookupItemCacheTimerCountIndex = ExploredCellsLookupItemCacheTimerCount++; ExploredCellsLookupItemCache[newPos][sightRange] = exploredCellsCache; ExploredCellsLookupKey lookupKey; lookupKey.pos = newPos; lookupKey.sightRange = sightRange; lookupKey.teamIndex = teamIndex; ExploredCellsLookupItemCacheTimer[exploredCellsCache.ExploredCellsLookupItemCacheTimerCountIndex] = lookupKey; } } return exploredCellsCache; } bool World::showWorldForPlayer(int factionIndex, bool excludeFogOfWarCheck) const { bool ret = false; if(factionIndex >= 0) { if(excludeFogOfWarCheck == false && fogOfWarSkillTypeValue == 0 && fogOfWarOverride == true) { ret = true; } else if(factionIndex == thisFactionIndex && game != NULL) { //printf("Show FOW thisTeamIndex = %d (%d) game->getGameOver() = %d game->getGameSettings()->isNetworkGame() = %d game->getGameSettings()->getEnableObserverModeAtEndGame() = %d thisFactionIndex = %d Is Winning Faction = %d\n", // thisTeamIndex,(GameConstants::maxPlayers -1 + fpt_Observer),game->getGameOver(), // game->getGameSettings()->isNetworkGame(),game->getGameSettings()->getEnableObserverModeAtEndGame(), // thisFactionIndex,getStats()->getVictory(thisFactionIndex)); // Player is an Observer if(thisTeamIndex == GameConstants::maxPlayers -1 + fpt_Observer) { ret = true; } // Game over and not a network game else if(game->getGameOver() == true && game->getGameSettings()->isNetworkGame() == false) { ret = true; } // Game is over but playing a Network game so check if we can // turn off fog of war? else if(game->getGameOver() == true && game->getGameSettings()->isNetworkGame() == true && game->getGameSettings()->getEnableObserverModeAtEndGame() == true) { ret = true; // If the faction is NOT on the winning team, don't let them see the map // until all mobile units are dead if(getStats()->getVictory(factionIndex) == false) { // If the player has at least 1 Unit alive that is mobile (can move) // then we cannot turn off fog of war const Faction *faction = getFaction(factionIndex); // for(int i = 0; i < faction->getUnitCount(); ++i) { // Unit *unit = getFaction(factionIndex)->getUnit(i); // if(unit != NULL && unit->isAlive() && unit->getType()->isMobile() == true) { // ret = false; // break; // } // } if(faction->hasAliveUnits(true,false) == true) { ret = false; } } } } } //printf("showWorldForPlayer for %d is: %d\n",factionIndex,ret); return ret; } //computes the fog of war texture, contained in the minimap void World::computeFow() { if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s] Line: %d in frame: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,getFrameCount()); Chrono chronoGamePerformanceCounts; if(this->game) chronoGamePerformanceCounts.start(); minimap.resetFowTex(); if(this->game) this->game->addPerformanceCount("world minimap.resetFowTex",chronoGamePerformanceCounts.getMillis()); // reset cells if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s] Line: %d in frame: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,getFrameCount()); if(this->game) chronoGamePerformanceCounts.start(); // Once we have calculated fog of war texture alpha, they are cached so we // restore the default texture in one shot for speed if(fogOfWar && cacheFowAlphaTexture == true) { if(cacheFowAlphaTextureFogOfWarValue != fogOfWar) { cacheFowAlphaTexture = false; } else { minimap.restoreFowTexAlphaSurface(); } } int resetFowAlphaFactionCount = 0; for(int factionIndex = 0; factionIndex < GameConstants::maxPlayers + GameConstants::specialFactions; ++factionIndex) { if(factionIndex >= getFactionCount()) { continue; } Faction *faction = getFaction(factionIndex); // for(int indexTeamFaction = 0; // indexTeamFaction < GameConstants::maxPlayers + GameConstants::specialFactions; // ++indexTeamFaction) { // If fog of war enabled set cell visible to false and later set those close to units to true if(fogOfWar) { for(int indexSurfaceW = 0; indexSurfaceW < map.getSurfaceW(); ++indexSurfaceW) { for(int indexSurfaceH = 0; indexSurfaceH < map.getSurfaceH(); ++indexSurfaceH) { // set all cells to not visible map.getSurfaceCell(indexSurfaceW, indexSurfaceH)->setVisible(faction->getTeam(), false); } } } // Remove fog of war for factions NOT on my team which i can see if(!fogOfWar || (faction->getTeam() != thisTeamIndex)) { bool showWorldForFaction = showWorldForPlayer(factionIndex); //printf("showWorldForFaction indexFaction = %d thisTeamIndex = %d showWorldForFaction = %d\n",indexFaction,thisTeamIndex,showWorldForFaction); if(showWorldForFaction == true) { resetFowAlphaFactionCount++; } for(int indexSurfaceW = 0; indexSurfaceW < map.getSurfaceW(); ++indexSurfaceW) { for(int indexSurfaceH = 0; indexSurfaceH < map.getSurfaceH(); ++indexSurfaceH) { // reset fog of ware texture alpha values if(!fogOfWar || (cacheFowAlphaTexture == false && showWorldForFaction == true && resetFowAlphaFactionCount <= 1)) { const Vec2i surfPos(indexSurfaceW,indexSurfaceH); //compute max alpha float maxAlpha= 0.0f; if(surfPos.x > 1 && surfPos.y > 1 && surfPos.x < map.getSurfaceW() - 2 && surfPos.y < map.getSurfaceH() - 2) { maxAlpha= 1.f; } else if(surfPos.x > 0 && surfPos.y > 0 && surfPos.x < map.getSurfaceW() - 1 && surfPos.y < map.getSurfaceH() - 1){ maxAlpha= 0.3f; } // compute alpha float alpha = maxAlpha; minimap.incFowTextureAlphaSurface(surfPos, alpha); } } } } // Remove fog of war for factions on my team else if(fogOfWar && (faction->getTeam() == thisTeamIndex)) { bool showWorldForFaction = showWorldForPlayer(factionIndex); //printf("#2 showWorldForFaction thisFactionIndex = %d thisTeamIndex = %d showWorldForFaction = %d\n",thisFactionIndex,thisTeamIndex,showWorldForFaction); if(showWorldForFaction == true) { for(int indexSurfaceW = 0; indexSurfaceW < map.getSurfaceW(); ++indexSurfaceW) { for(int indexSurfaceH = 0; indexSurfaceH < map.getSurfaceH(); ++indexSurfaceH) { // reset fog of ware texture alpha values if(!fogOfWar || (cacheFowAlphaTexture == false && showWorldForFaction == true)) { const Vec2i surfPos(indexSurfaceW,indexSurfaceH); //compute max alpha float maxAlpha= 0.0f; if(surfPos.x > 1 && surfPos.y > 1 && surfPos.x < map.getSurfaceW() - 2 && surfPos.y < map.getSurfaceH() - 2) { maxAlpha= 1.f; } else if(surfPos.x > 0 && surfPos.y > 0 && surfPos.x < map.getSurfaceW() - 1 && surfPos.y < map.getSurfaceH() - 1){ maxAlpha= 0.3f; } // compute alpha float alpha = maxAlpha; minimap.incFowTextureAlphaSurface(surfPos, alpha); } } } } } if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s] Line: %d in frame: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,getFrameCount()); } // Once we have calculated fog of war texture alpha, will we cache it so that we // can restore it later if(fogOfWar && cacheFowAlphaTexture == false && resetFowAlphaFactionCount > 0) { cacheFowAlphaTexture = true; cacheFowAlphaTextureFogOfWarValue = fogOfWar; minimap.copyFowTexAlphaSurface(); } if(this->game) this->game->addPerformanceCount("world reset cells",chronoGamePerformanceCounts.getMillis()); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s] Line: %d in frame: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,getFrameCount()); //compute cells if(this->game) chronoGamePerformanceCounts.start(); for(int factionIndex = 0; factionIndex < getFactionCount(); ++factionIndex) { Faction *faction = getFaction(factionIndex); bool cellVisibleForFaction = showWorldForPlayer(thisFactionIndex); //printf("computeFow thisFactionIndex = %d factionIndex = %d thisTeamIndex = %d faction->getTeam() = %d cellVisibleForFaction = %d\n",thisFactionIndex,factionIndex,thisTeamIndex,faction->getTeam(),cellVisibleForFaction); int unitCount = faction->getUnitCount(); for(int unitIndex = 0; unitIndex < unitCount; ++unitIndex) { Unit *unit= faction->getUnit(unitIndex); // exploration unit->exploreCells(); // fire particle visible ParticleSystem *fire = unit->getFire(); if(fire != NULL) { bool cellVisible = cellVisibleForFaction; if(cellVisible == false) { Vec2i sCoords = Map::toSurfCoords(unit->getPos()); SurfaceCell *sc = map.getSurfaceCell(sCoords); if(sc != NULL) { cellVisible = sc->isVisible(thisTeamIndex); } } fire->setActive(cellVisible); } // compute fog of war render texture if(fogOfWar == true && faction->getTeam() == thisTeamIndex && unit->isOperative() == true) { //printf("computeFow unit->isOperative() == true\n"); const FowAlphaCellsLookupItem &cellList = unit->getCachedFow(); for(std::map::const_iterator iterMap = cellList.surfPosAlphaList.begin(); iterMap != cellList.surfPosAlphaList.end(); ++iterMap) { const Vec2i &surfPos = iterMap->first; const float &alpha = iterMap->second; minimap.incFowTextureAlphaSurface(surfPos, alpha, true); } } } } if(this->game) this->game->addPerformanceCount("world compute cells",chronoGamePerformanceCounts.getMillis()); } GameSettings * World::getGameSettingsPtr() { return (game != NULL ? game->getGameSettings() : NULL); } const GameSettings * World::getGameSettings() const { return (game != NULL ? game->getReadOnlyGameSettings() : NULL); } // WARNING! This id is critical! Make sure it fits inside the network packet // (currently cannot be larger than 2,147,483,647) // Make sure each faction has their own unique section of id #'s for proper // multi-platform play // Calculates the unit unit ID for each faction // int World::getNextUnitId(Faction *faction) { MutexSafeWrapper safeMutex(mutexFactionNextUnitId,string(__FILE__) + "_" + intToStr(__LINE__)); if(mapFactionNextUnitId.find(faction->getIndex()) == mapFactionNextUnitId.end()) { mapFactionNextUnitId[faction->getIndex()] = faction->getIndex() * 100000; } return mapFactionNextUnitId[faction->getIndex()]++; } // Get a unique commandid when sending commands to a group of units int World::getNextCommandGroupId() { return ++nextCommandGroupId; } void World::playStaticVideo(const string &playVideo) { string calculatedFilePath = playVideo; bool changed = Properties::applyTagsToValue(calculatedFilePath); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("\n\nPlay static video changed: %d [%s] [%s]\n\n",changed, playVideo.c_str(),calculatedFilePath.c_str()); this->game->playStaticVideo(calculatedFilePath); } void World::playStreamingVideo(const string &playVideo) { string calculatedFilePath = playVideo; bool changed = Properties::applyTagsToValue(calculatedFilePath); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("\n\nPlay streaming video changed: %d [%s] [%s]\n\n",changed, playVideo.c_str(),calculatedFilePath.c_str()); this->game->playStreamingVideo(calculatedFilePath); } void World::stopStreamingVideo(const string &playVideo) { string calculatedFilePath = playVideo; bool changed = Properties::applyTagsToValue(calculatedFilePath); if(SystemFlags::VERBOSE_MODE_ENABLED) printf("\n\nStop streaming video changed: %d [%s] [%s]\n\n",changed, playVideo.c_str(),calculatedFilePath.c_str()); this->game->stopStreamingVideo(calculatedFilePath); } void World::stopAllVideo() { this->game->stopAllVideo(); } void World::initTeamResource(const ResourceType *rt,int teamIndex, int value) { std::string resourceTypeName = rt->getName(false); TeamResources[teamIndex][resourceTypeName].init(rt,value); } const Resource *World::getResourceForTeam(const ResourceType *rt, int teamIndex) { if(rt == NULL) { return NULL; } std::map &resourceList = TeamResources[teamIndex]; std::string resourceTypeName = rt->getName(false); resourceList[resourceTypeName].init(rt,0); Resource &teamResource = resourceList[resourceTypeName]; for(int index = 0; index < (int)factions.size(); ++index) { Faction *faction = factions[index]; if(faction != NULL && faction->getTeam() == teamIndex) { const Resource *factionResource = faction->getResource(rt,true); if(factionResource != NULL && factionResource->getType() != NULL) { int teamResourceAmount = teamResource.getAmount(); int teamResourceBalance = teamResource.getBalance(); teamResource.setAmount(teamResourceAmount + factionResource->getAmount()); teamResource.setBalance(teamResourceBalance + factionResource->getBalance()); } } } return &teamResource; } int World::getStoreAmountForTeam(const ResourceType *rt, int teamIndex) const { int teamStoreAmount = 0; for(int index = 0; index < (int)factions.size(); ++index) { Faction *faction = factions[index]; if(faction != NULL && faction->getTeam() == teamIndex) { teamStoreAmount += faction->getStoreAmount(rt,true); } } return teamStoreAmount; } bool World::showResourceTypeForTeam(const ResourceType *rt, int teamIndex) const { //if any unit produces the resource bool showResource = false; for(int index = 0; showResource == false && index < (int)factions.size(); ++index) { const Faction *teamFaction = factions[index]; if(teamFaction != NULL && teamFaction->getTeam() == teamIndex) { if(teamFaction->hasUnitTypeWithResourceCostInCache(rt) == true) { showResource = true; } } } return showResource; } bool World::showResourceTypeForFaction(const ResourceType *rt, const Faction *faction) const { //if any unit produces the resource bool showResource = false; for(int factionUnitTypeIndex = 0; factionUnitTypeIndex < faction->getType()->getUnitTypeCount(); ++factionUnitTypeIndex) { const UnitType *ut = faction->getType()->getUnitType(factionUnitTypeIndex); if(ut->getCost(rt) != NULL) { showResource = true; break; } } return showResource; } void World::removeResourceTargetFromCache(const Vec2i &pos) { for(int i= 0; i < (int)factions.size(); ++i) { factions[i]->removeResourceTargetFromCache(pos); } } string World::getExploredCellsLookupItemCacheStats() { string result = ""; int posCount = 0; int sightCount = 0; int exploredCellCount = 0; int visibleCellCount = 0; for(std::map >::iterator iterMap1 = ExploredCellsLookupItemCache.begin(); iterMap1 != ExploredCellsLookupItemCache.end(); ++iterMap1) { posCount++; for(std::map::iterator iterMap2 = iterMap1->second.begin(); iterMap2 != iterMap1->second.end(); ++iterMap2) { sightCount++; exploredCellCount += (int)iterMap2->second.exploredCellList.size(); visibleCellCount += (int)iterMap2->second.visibleCellList.size(); } } uint64 totalBytes = exploredCellCount * sizeof(SurfaceCell *); totalBytes += visibleCellCount * sizeof(SurfaceCell *); totalBytes /= 1000; char szBuf[8096]=""; snprintf(szBuf,8096,"pos [%d] sight [%d] [%d][%d] total KB: %s",posCount,sightCount,exploredCellCount,visibleCellCount,formatNumber(totalBytes).c_str()); result = szBuf; return result; } string World::getFowAlphaCellsLookupItemCacheStats() { string result = ""; int surfPosAlphaCount = 0; for(int factionIndex = 0; factionIndex < getFactionCount(); ++factionIndex) { Faction *faction= getFaction(factionIndex); if(faction->getTeam() == thisTeamIndex) { for(int unitIndex = 0; unitIndex < faction->getUnitCount(); ++unitIndex) { const Unit *unit= faction->getUnit(unitIndex); const FowAlphaCellsLookupItem &cache = unit->getCachedFow(); surfPosAlphaCount += (int)cache.surfPosAlphaList.size(); } } } uint64 totalBytes = surfPosAlphaCount * sizeof(Vec2i); totalBytes += surfPosAlphaCount * sizeof(float); totalBytes /= 1000; char szBuf[8096]=""; snprintf(szBuf,8096,"surface count [%d] total KB: %s",surfPosAlphaCount,formatNumber(totalBytes).c_str()); result = szBuf; return result; } string World::getAllFactionsCacheStats() { string result = ""; uint64 totalBytes = 0; uint64 totalCache1Size = 0; uint64 totalCache2Size = 0; uint64 totalCache3Size = 0; uint64 totalCache4Size = 0; uint64 totalCache5Size = 0; for(int i = 0; i < getFactionCount(); ++i) { uint64 cache1Size = 0; uint64 cache2Size = 0; uint64 cache3Size = 0; uint64 cache4Size = 0; uint64 cache5Size = 0; totalBytes += getFaction(i)->getCacheKBytes(&cache1Size,&cache2Size,&cache3Size,&cache4Size,&cache5Size); totalCache1Size += cache1Size; totalCache2Size += cache2Size; totalCache3Size += cache3Size; totalCache4Size += cache4Size; totalCache5Size += cache5Size; } char szBuf[8096]=""; snprintf(szBuf,8096,"Cache1 [%llu] Cache2 [%llu] Cache3 [%llu] Cache4 [%llu] Cache5 [%llu] total KB: %s", (long long unsigned)totalCache1Size,(long long unsigned)totalCache2Size,(long long unsigned)totalCache3Size, (long long unsigned)totalCache4Size,(long long unsigned)totalCache5Size,formatNumber(totalBytes).c_str()); result = szBuf; return result; } bool World::factionLostGame(int factionIndex) { if(this->game != NULL) { return this->game->factionLostGame(factionIndex); } return false; } std::string World::DumpWorldToLog(bool consoleBasicInfoOnly) const { string debugWorldLogFile = Config::getInstance().getString("DebugWorldLogFile","debugWorld.log"); if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") { debugWorldLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugWorldLogFile; } else { string userData = Config::getInstance().getString("UserData_Root",""); if(userData != "") { endPathWithSlash(userData); } debugWorldLogFile = userData + debugWorldLogFile; } if(consoleBasicInfoOnly == true) { std::cout << "World debug information:" << std::endl; std::cout << "========================" << std::endl; //factions (and their related info) for(int i = 0; i < getFactionCount(); ++i) { std::cout << "Faction detail for index: " << i << std::endl; std::cout << "--------------------------" << std::endl; std::cout << "FactionName = " << getFaction(i)->getType()->getName(false) << std::endl; std::cout << "FactionIndex = " << intToStr(getFaction(i)->getIndex()) << std::endl; std::cout << "teamIndex = " << intToStr(getFaction(i)->getTeam()) << std::endl; std::cout << "startLocationIndex = " << intToStr(getFaction(i)->getStartLocationIndex()) << std::endl; std::cout << "thisFaction = " << intToStr(getFaction(i)->getThisFaction()) << std::endl; std::cout << "control = " << intToStr(getFaction(i)->getControlType()) << std::endl; } } else { #if defined(WIN32) && !defined(__MINGW32__) FILE *fp = _wfopen(utf8_decode(debugWorldLogFile).c_str(), L"w"); std::ofstream logFile(fp); #else std::ofstream logFile; logFile.open(debugWorldLogFile.c_str(), ios_base::out | ios_base::trunc); #endif logFile << "World debug information:" << std::endl; logFile << "========================" << std::endl; //factions (and their related info) for(int i = 0; i < getFactionCount(); ++i) { logFile << "Faction detail for index: " << i << std::endl; logFile << "--------------------------" << std::endl; logFile << getFaction(i)->toString() << std::endl; } //undertake the dead logFile << "Undertake stats:" << std::endl; for(int i = 0; i < getFactionCount(); ++i){ logFile << "Faction: " << getFaction(i)->getType()->getName(false) << std::endl; int unitCount = getFaction(i)->getUnitCount(); for(int j= unitCount - 1; j >= 0; j--){ Unit *unit= getFaction(i)->getUnit(j); if(unit->getToBeUndertaken()) { logFile << "Undertake unit index = " << j << unit->getFullName(false) << std::endl; } } } logFile.close(); #if defined(WIN32) && !defined(__MINGW32__) if(fp) { fclose(fp); } #endif } //printf("Check savegame\n"); if(this->game != NULL) { //printf("Saving...\n"); this->game->saveGame(GameConstants::saveGameFileDefault); } return debugWorldLogFile; } void World::saveGame(XmlNode *rootNode) { std::map mapTagReplacements; XmlNode *worldNode = rootNode->addChild("World"); // Map map; map.saveGame(worldNode); // Tileset tileset; worldNode->addAttribute("tileset",tileset.getName(), mapTagReplacements); // //TechTree techTree; // TechTree *techTree; if(techTree != NULL) { techTree->saveGame(worldNode); } worldNode->addAttribute("techTree",(techTree != NULL ? techTree->getName() : ""), mapTagReplacements); // TimeFlow timeFlow; timeFlow.saveGame(worldNode); // Scenario scenario; // // UnitUpdater unitUpdater; unitUpdater.saveGame(worldNode); // WaterEffects waterEffects; // WaterEffects attackEffects; // onMiniMap // Minimap minimap; minimap.saveGame(worldNode); // Stats stats; //BattleEnd will delete this object stats.saveGame(worldNode); // // Factions factions; for(unsigned int i = 0; i < factions.size(); ++i) { factions[i]->saveGame(worldNode); } // RandomGen random; worldNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements); // ScriptManager* scriptManager; // // int thisFactionIndex; worldNode->addAttribute("thisFactionIndex",intToStr(thisFactionIndex), mapTagReplacements); // int thisTeamIndex; worldNode->addAttribute("thisTeamIndex",intToStr(thisTeamIndex), mapTagReplacements); // int frameCount; worldNode->addAttribute("frameCount",intToStr(frameCount), mapTagReplacements); // //int nextUnitId; // Mutex mutexFactionNextUnitId; MutexSafeWrapper safeMutex(mutexFactionNextUnitId,string(__FILE__) + "_" + intToStr(__LINE__)); // std::map mapFactionNextUnitId; for(std::map::iterator iterMap = mapFactionNextUnitId.begin(); iterMap != mapFactionNextUnitId.end(); ++iterMap) { XmlNode *factionNextUnitIdNode = worldNode->addChild("FactionNextUnitId"); factionNextUnitIdNode->addAttribute("key",intToStr(iterMap->first), mapTagReplacements); factionNextUnitIdNode->addAttribute("value",intToStr(iterMap->second), mapTagReplacements); } safeMutex.ReleaseLock(); // //config // bool fogOfWarOverride; worldNode->addAttribute("fogOfWarOverride",intToStr(fogOfWarOverride), mapTagReplacements); // bool fogOfWar; worldNode->addAttribute("fogOfWar",intToStr(fogOfWar), mapTagReplacements); // int fogOfWarSmoothingFrameSkip; worldNode->addAttribute("fogOfWarSmoothingFrameSkip",intToStr(fogOfWarSmoothingFrameSkip), mapTagReplacements); // bool fogOfWarSmoothing; worldNode->addAttribute("fogOfWarSmoothing",intToStr(fogOfWarSmoothing), mapTagReplacements); // Game *game; // Chrono chronoPerfTimer; // bool perfTimerEnabled; // // bool unitParticlesEnabled; worldNode->addAttribute("unitParticlesEnabled",intToStr(unitParticlesEnabled), mapTagReplacements); // std::map staticSoundList; // std::map streamSoundList; // // uint32 nextCommandGroupId; worldNode->addAttribute("nextCommandGroupId",intToStr(nextCommandGroupId), mapTagReplacements); // string queuedScenarioName; worldNode->addAttribute("queuedScenarioName",queuedScenarioName, mapTagReplacements); // bool queuedScenarioKeepFactions; worldNode->addAttribute("queuedScenarioKeepFactions",intToStr(queuedScenarioKeepFactions), mapTagReplacements); worldNode->addAttribute("disableAttackEffects",intToStr(disableAttackEffects), mapTagReplacements); } void World::loadGame(const XmlNode *rootNode) { loadWorldNode = rootNode; } }}//end namespace