mirror of
https://github.com/glest/glest-source.git
synced 2025-02-25 04:02:30 +01:00
3113 lines
126 KiB
C++
3113 lines
126 KiB
C++
//
|
|
// world.cpp:
|
|
//
|
|
// This file is part of ZetaGlest <https://github.com/ZetaGlest>
|
|
//
|
|
// Copyright (C) 2018 The ZetaGlest team
|
|
//
|
|
// ZetaGlest is a fork of MegaGlest <https://megaglest.org>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>
|
|
|
|
#include "world.h"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
|
|
#include "config.h"
|
|
#include "faction.h"
|
|
#include "unit.h"
|
|
#include "game.h"
|
|
#include "logger.h"
|
|
#include "sound_renderer.h"
|
|
#include "game_settings.h"
|
|
#include "cache_manager.h"
|
|
#include <iostream>
|
|
#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<string, ::Shared::Sound::StaticSound *>::iterator iterMap = staticSoundList.begin();
|
|
iterMap != staticSoundList.end(); ++iterMap) {
|
|
delete iterMap->second;
|
|
}
|
|
staticSoundList.clear();
|
|
|
|
for (std::map<string, ::Shared::Sound::StrSound *>::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<const Unit *, const FogOfWarSkillType *> 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<int, std::pair<const Unit *, const FogOfWarSkillType *> >::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<string> pathList, const string &tilesetName,
|
|
Checksum* checksum, std::map<string, vector<pair<string, string> > > &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<string, vector<pair<string, string> > > &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<string> pathList, const string &techName,
|
|
set<string> &factions, Checksum *checksum,
|
|
std::map<string, vector<pair<string, string> > > &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);
|
|
XmlTree xmlTree;
|
|
string currentPath = techTree->findPath(techName, pathList);
|
|
endPathWithSlash(currentPath);
|
|
string path = currentPath + lastDir(currentPath) + ".xml";
|
|
const XmlNode *techTreeNode = xmlTree.getRootNode();
|
|
if (scriptManager) scriptManager->init(this, this->getGame()->getGameCameraPtr(), techTreeNode);
|
|
return techtreeChecksum;
|
|
}
|
|
|
|
std::vector<std::string> World::validateFactionTypes() {
|
|
return techTree->validateFactionTypes();
|
|
}
|
|
|
|
std::vector<std::string> 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<string> 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<CommandClass, int> mapCommandCount;
|
|
std::map<SkillClass, int> 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<CommandClass, int>::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<SkillClass, int>::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
|
|
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");
|
|
}
|
|
|
|
faction->applyCostsOnInterval(rt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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<string> 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<float>(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<string> 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<const UnitType *, std::map<const ResourceType *, const Resource *> > 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<const UnitType *, std::map<const ResourceType *, const Resource *> >::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; i < getFactionCount(); ++i) {
|
|
const Faction* faction = getFaction(i);
|
|
Unit* unit = faction->findUnit(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<const MorphCommandType *>(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<CommandResult, string> 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<int> World::getUnitsForFaction(int factionIndex, const string& commandTypeName, int field) {
|
|
vector<int> 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>(field));
|
|
addToList = (act != NULL);
|
|
} else if (commandType->getClass() == ccAttackStopped && field >= 0) {
|
|
const AttackStoppedCommandType *asct = unit->getType()->getFirstAttackStoppedCommand(static_cast<Field>(field));
|
|
addToList = (asct != NULL);
|
|
} else {
|
|
addToList = unit->getType()->hasCommandClass(commandType->getClass());
|
|
}
|
|
} else if (field >= 0) {
|
|
addToList = (unit->getCurrField() == static_cast<Field>(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;
|
|
}
|
|
|
|
bool World::isBuilding(int unitId) {
|
|
bool result = false;
|
|
Unit* unit = findUnitById(unitId);
|
|
if (unit != NULL) {
|
|
result = unit->getType()->hasSkillClass(scBeBuilt);
|
|
}
|
|
|
|
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<const ProduceCommandType*>(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<const AttackStoppedCommandType*>(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);
|
|
}
|
|
string World::translate(const string &text) {
|
|
return Lang::getInstance().getScenarioString(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);
|
|
}
|
|
|
|
const string World::getFactionName(int factionIndex) {
|
|
return game->getGameSettings()->getFactionTypeName(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<const UpgradeCommandType*>(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");
|
|
}
|
|
|
|
// FIXME: This was commented out while working on issue 13
|
|
// <https://github.com/ZetaGlest/zetaglest-source/issues/13>
|
|
//
|
|
// The check may not be needed or it may need to be re-written
|
|
|
|
// 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()->getPixel4f(0, 0));
|
|
}
|
|
}
|
|
|
|
if (Config::getInstance().getBool("EnableNewThreadManager", "false") == true) {
|
|
std::vector<SlaveThreadControllerInterface *> 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<int,int> mapFactionNextUnitId;
|
|
// for(std::map<int,int>::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<XmlNode *> 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<string,StaticSound *> staticSoundList;
|
|
// std::map<string,StrSound *> 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<SurfaceCell*> &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<int, ExploredCellsLookupKey>::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<Vec2i, std::map<int, ExploredCellsLookupItem> >::iterator iterFind = ExploredCellsLookupItemCache.find(newPos);
|
|
if (iterFind != ExploredCellsLookupItemCache.end()) {
|
|
|
|
std::map<int, ExploredCellsLookupItem>::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<Vec2i, float>::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<std::string, Resource> &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<Vec2i, std::map<int, ExploredCellsLookupItem > >::iterator iterMap1 = ExploredCellsLookupItemCache.begin();
|
|
iterMap1 != ExploredCellsLookupItemCache.end(); ++iterMap1) {
|
|
posCount++;
|
|
|
|
for (std::map<int, ExploredCellsLookupItem >::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<string, string> 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<int,int> mapFactionNextUnitId;
|
|
for (std::map<int, int>::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<string,StaticSound *> staticSoundList;
|
|
// std::map<string,StrSound *> 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
|