diff --git a/CCallback.h b/CCallback.h index 34475f6b6..e9a61cc54 100644 --- a/CCallback.h +++ b/CCallback.h @@ -1,7 +1,7 @@ #pragma once -#include "lib/IGameCallback.h" +#include "lib/IGameCallback2.h" /* * CCallback.h, part of VCMI engine diff --git a/lib/CGameState.h b/lib/CGameState.h index 5ab648b74..2be6a72ca 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -11,11 +11,11 @@ #include "HeroBonus.h" #include "CCreatureSet.h" #include "ConstTransitivePtr.h" -#include "IGameCallback.h" +#include "IGameCallback2.h" #include "ResourceSet.h" #include "int3.h" #include "CObjectHandler.h" -#include "IGameCallback.h" +//#include "IGameCallback.h" #include "CRandomGenerator.h" /* diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 54ee9da33..1eba08d08 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -7,6 +7,7 @@ include_directories(${Boost_INCLUDE_DIRS} ${SDL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} set(lib_SRCS StdInc.cpp IGameCallback.cpp + IGameCallback2.cpp CGameState.cpp CObjectHandler.cpp Connection.cpp diff --git a/lib/CScriptingModule.h b/lib/CScriptingModule.h index cfb6402cb..2b7b9f4a4 100644 --- a/lib/CScriptingModule.h +++ b/lib/CScriptingModule.h @@ -2,7 +2,7 @@ #include "IGameEventsReceiver.h" -#include "IGameCallback.h" +#include "IGameCallback2.h" /* * CScriptingModule.h, part of VCMI engine @@ -24,4 +24,4 @@ public: CScriptingModule(){} virtual ~CScriptingModule(){} -}; \ No newline at end of file +}; diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index cd47cc630..eaae72fcf 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -11,7 +11,7 @@ #include "StdInc.h" #include "IGameCallback.h" -#include "CGameState.h" +/*#include "CGameState.h" #include "mapping/CMap.h" #include "CObjectHandler.h" #include "CHeroHandler.h" @@ -20,934 +20,21 @@ #include "CSpellHandler.h" #include "VCMI_Lib.h" #include "CTownHandler.h" -#include "BattleState.h" +#include "BattleState.h"*/ #include "NetPacks.h" -#include "CBuildingHandler.h" +/*#include "CBuildingHandler.h" #include "GameConstants.h" #include "CModHandler.h" #include "CDefObjInfoHandler.h" #include "CBonusTypeHandler.h" -#include "Connection.h" +#include "Connection.h"*/ //TODO make clean -#define ERROR_SILENT_RET_VAL_IF(cond, txt, retVal) do {if(cond){return retVal;}} while(0) +/*#define ERROR_SILENT_RET_VAL_IF(cond, txt, retVal) do {if(cond){return retVal;}} while(0) #define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0) #define ERROR_RET_IF(cond, txt) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return;}} while(0) -#define ERROR_RET_VAL_IF(cond, txt, retVal) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0) - -CGameState * CPrivilagedInfoCallback::gameState () -{ - return gs; -} - -PlayerColor CGameInfoCallback::getOwner(ObjectInstanceID heroID) const -{ - const CGObjectInstance *obj = getObj(heroID); - ERROR_RET_VAL_IF(!obj, "No such object!", PlayerColor::CANNOT_DETERMINE); - return obj->tempOwner; -} - -int CGameInfoCallback::getResource(PlayerColor Player, Res::ERes which) const -{ - const PlayerState *p = getPlayer(Player); - ERROR_RET_VAL_IF(!p, "No player info!", -1); - ERROR_RET_VAL_IF(p->resources.size() <= which || which < 0, "No such resource!", -1); - return p->resources[which]; -} - -const CGHeroInstance* CGameInfoCallback::getSelectedHero( PlayerColor Player ) const -{ - const PlayerState *p = getPlayer(Player); - ERROR_RET_VAL_IF(!p, "No player info!", nullptr); - return getHero(p->currentSelection); -} - -const CGHeroInstance* CGameInfoCallback::getSelectedHero() const -{ - return getSelectedHero(gs->currentPlayer); -} - -const PlayerSettings * CGameInfoCallback::getPlayerSettings(PlayerColor color) const -{ - return &gs->scenarioOps->getIthPlayersSettings(color); -} - -void CPrivilagedInfoCallback::getTilesInRange( std::unordered_set &tiles, int3 pos, int radious, boost::optional player/*=uninit*/, int mode/*=0*/ ) const -{ - if(!!player && *player >= PlayerColor::PLAYER_LIMIT) - { - logGlobal->errorStream() << "Illegal call to getTilesInRange!"; - return; - } - if (radious == -1) //reveal entire map - getAllTiles (tiles, player, -1, 0); - else - { - const TeamState * team = !player ? nullptr : gs->getPlayerTeam(*player); - for (int xd = std::max(pos.x - radious , 0); xd <= std::min(pos.x + radious, gs->map->width - 1); xd++) - { - for (int yd = std::max(pos.y - radious, 0); yd <= std::min(pos.y + radious, gs->map->height - 1); yd++) - { - double distance = pos.dist2d(int3(xd,yd,pos.z)) - 0.5; - if(distance <= radious) - { - if(!player - || (mode == 1 && team->fogOfWarMap[xd][yd][pos.z]==0) - || (mode == -1 && team->fogOfWarMap[xd][yd][pos.z]==1) - ) - tiles.insert(int3(xd,yd,pos.z)); - } - } - } - } -} - -void CPrivilagedInfoCallback::getAllTiles (std::unordered_set &tiles, boost::optional Player/*=uninit*/, int level, int surface ) const -{ - if(!!Player && *Player >= PlayerColor::PLAYER_LIMIT) - { - logGlobal->errorStream() << "Illegal call to getAllTiles !"; - return; - } - bool water = surface == 0 || surface == 2, - land = surface == 0 || surface == 1; - - std::vector floors; - if(level == -1) - { - for(int b = 0; b < (gs->map->twoLevel ? 2 : 1); ++b) - { - floors.push_back(b); - } - } - else - floors.push_back(level); - - for (auto zd : floors) - { - - for (int xd = 0; xd < gs->map->width; xd++) - { - for (int yd = 0; yd < gs->map->height; yd++) - { - if ((getTile (int3 (xd,yd,zd))->terType == ETerrainType::WATER && water) - || (getTile (int3 (xd,yd,zd))->terType != ETerrainType::WATER && land)) - tiles.insert(int3(xd,yd,zd)); - } - } - } -} - -void CPrivilagedInfoCallback::getFreeTiles (std::vector &tiles) const -{ - std::vector floors; - for (int b = 0; b < (gs->map->twoLevel ? 2 : 1); ++b) - { - floors.push_back(b); - } - const TerrainTile *tinfo; - for (auto zd : floors) - { - - for (int xd = 0; xd < gs->map->width; xd++) - { - for (int yd = 0; yd < gs->map->height; yd++) - { - tinfo = getTile(int3 (xd,yd,zd)); - if (tinfo->terType != ETerrainType::WATER && !tinfo->blocked) //land and free - tiles.push_back (int3 (xd,yd,zd)); - } - } - } -} - -bool CGameInfoCallback::isAllowed( int type, int id ) -{ - switch(type) - { - case 0: - return gs->map->allowedSpell[id]; - case 1: - return gs->map->allowedArtifact[id]; - case 2: - return gs->map->allowedAbilities[id]; - default: - ERROR_RET_VAL_IF(1, "Wrong type!", false); - } -} - -void CPrivilagedInfoCallback::pickAllowedArtsSet(std::vector &out) -{ - for (int j = 0; j < 3 ; j++) - out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_TREASURE)]); - for (int j = 0; j < 3 ; j++) - out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_MINOR)]); - - out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_MAJOR)]); -} - -void CPrivilagedInfoCallback::getAllowedSpells(std::vector &out, ui16 level) -{ - for (ui32 i = 0; i < gs->map->allowedSpell.size(); i++) //spellh size appears to be greater (?) - { - - const CSpell *spell = SpellID(i).toSpell(); - if (isAllowed (0, spell->id) && spell->level == level) - { - out.push_back(spell->id); - } - } -} - - -template -void CPrivilagedInfoCallback::loadCommonState(Loader &in) -{ - logGlobal->infoStream() << "Loading lib part of game..."; - in.checkMagicBytes(SAVEGAME_MAGIC); - - CMapHeader dum; - StartInfo *si; - - logGlobal->infoStream() <<"\tReading header"; - in >> dum; - - logGlobal->infoStream() << "\tReading options"; - in >> si; - - logGlobal->infoStream() <<"\tReading handlers"; - in >> *VLC; - - logGlobal->infoStream() <<"\tReading gamestate"; - in >> gs; -} - -template -void CPrivilagedInfoCallback::saveCommonState(Saver &out) const -{ - logGlobal->infoStream() << "Saving lib part of game..."; - out.putMagicBytes(SAVEGAME_MAGIC); - logGlobal->infoStream() <<"\tSaving header"; - out << static_cast(*gs->map); - logGlobal->infoStream() << "\tSaving options"; - out << gs->scenarioOps; - logGlobal->infoStream() << "\tSaving handlers"; - out << *VLC; - logGlobal->infoStream() << "\tSaving gamestate"; - out << gs; -} - -template DLL_LINKAGE void CPrivilagedInfoCallback::loadCommonState(CLoadIntegrityValidator&); -template DLL_LINKAGE void CPrivilagedInfoCallback::loadCommonState(CLoadFile&); -template DLL_LINKAGE void CPrivilagedInfoCallback::saveCommonState(CSaveFile&) const; - -TerrainTile * CNonConstInfoCallback::getTile( int3 pos ) -{ - if(!gs->map->isInTheMap(pos)) - return nullptr; - return &gs->map->getTile(pos); -} - -const PlayerState * CGameInfoCallback::getPlayer(PlayerColor color, bool verbose) const -{ - ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!hasAccess(color), verbose, "Cannot access player " << color << "info!", nullptr); - ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!vstd::contains(gs->players,color), verbose, "Cannot find player " << color << "info!", nullptr); - return &gs->players[color]; -} - -const CTown * CGameInfoCallback::getNativeTown(PlayerColor color) const -{ - const PlayerSettings *ps = getPlayerSettings(color); - ERROR_RET_VAL_IF(!ps, "There is no such player!", nullptr); - return VLC->townh->factions[ps->castle]->town; -} - -const CGObjectInstance * CGameInfoCallback::getObjByQuestIdentifier(int identifier) const -{ - ERROR_RET_VAL_IF(!vstd::contains(gs->map->questIdentifierToId, identifier), "There is no object with such quest identifier!", nullptr); - return getObj(gs->map->questIdentifierToId[identifier]); -} - -/************************************************************************/ -/* */ -/************************************************************************/ - -const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool verbose) const -{ - si32 oid = objid.num; - if(oid < 0 || oid >= gs->map->objects.size()) - { - if(verbose) - logGlobal->errorStream() << "Cannot get object with id " << oid; - return nullptr; - } - - const CGObjectInstance *ret = gs->map->objects[oid]; - if(!ret) - { - if(verbose) - logGlobal->errorStream() << "Cannot get object with id " << oid << ". Object was removed."; - return nullptr; - } - - if(!isVisible(ret, player)) - { - if(verbose) - logGlobal->errorStream() << "Cannot get object with id " << oid << ". Object is not visible."; - return nullptr; - } - - return ret; -} - -const CGHeroInstance* CGameInfoCallback::getHero(ObjectInstanceID objid) const -{ - const CGObjectInstance *obj = getObj(objid, false); - if(obj) - return dynamic_cast(obj); - else - return nullptr; -} -const CGTownInstance* CGameInfoCallback::getTown(ObjectInstanceID objid) const -{ - const CGObjectInstance *obj = getObj(objid, false); - if(obj) - return dynamic_cast(obj); - else - return nullptr; -} - -void CGameInfoCallback::getUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out) const -{ - //boost::shared_lock lock(*gs->mx); - ERROR_RET_IF(!canGetFullInfo(obj), "Cannot get info about not owned object!"); - ERROR_RET_IF(!obj->hasStackAtSlot(stackPos), "There is no such stack!"); - out = gs->getUpgradeInfo(obj->getStack(stackPos)); - //return gs->getUpgradeInfo(obj->getStack(stackPos)); -} - -const StartInfo * CGameInfoCallback::getStartInfo(bool beforeRandomization /*= false*/) const -{ - //boost::shared_lock lock(*gs->mx); - if(beforeRandomization) - return gs->initialOpts; - else - return gs->scenarioOps; -} - -int CGameInfoCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const -{ - //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(!canGetFullInfo(caster), "Cannot get info about caster!", -1); - //if there is a battle - if(gs->curB) - return gs->curB->battleGetSpellCost(sp, caster); - - //if there is no battle - return caster->getSpellCost(sp); -} - -int CGameInfoCallback::estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const -{ - //boost::shared_lock lock(*gs->mx); - - ERROR_RET_VAL_IF(hero && !canGetFullInfo(hero), "Cannot get info about caster!", -1); - if(!gs->curB) //no battle - { - if (hero) //but we see hero's spellbook - return gs->curB->calculateSpellDmg( - sp, hero, nullptr, hero->getSpellSchoolLevel(sp), hero->getPrimSkillLevel(PrimarySkill::SPELL_POWER)); - else - return 0; //mage guild - } - //gs->getHero(gs->currentPlayer) - //const CGHeroInstance * ourHero = gs->curB->heroes[0]->tempOwner == player ? gs->curB->heroes[0] : gs->curB->heroes[1]; - const CGHeroInstance * ourHero = hero; - return gs->curB->calculateSpellDmg( - sp, ourHero, nullptr, ourHero->getSpellSchoolLevel(sp), ourHero->getPrimSkillLevel(PrimarySkill::SPELL_POWER)); -} - -void CGameInfoCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj) -{ - //boost::shared_lock lock(*gs->mx); - ERROR_RET_IF(!obj, "No guild object!"); - ERROR_RET_IF(obj->ID == Obj::TOWN && !canGetFullInfo(obj), "Cannot get info about town guild object!"); - //TODO: advmap object -> check if they're visited by our hero - - if(obj->ID == Obj::TOWN || obj->ID == Obj::TAVERN) - { - gs->obtainPlayersStats(thi, gs->players[obj->tempOwner].towns.size()); - } - else if(obj->ID == Obj::DEN_OF_THIEVES) - { - gs->obtainPlayersStats(thi, 20); - } -} - -int CGameInfoCallback::howManyTowns(PlayerColor Player) const -{ - ERROR_RET_VAL_IF(!hasAccess(Player), "Access forbidden!", -1); - return gs->players[Player].towns.size(); -} - -bool CGameInfoCallback::getTownInfo( const CGObjectInstance *town, InfoAboutTown &dest ) const -{ - ERROR_RET_VAL_IF(!isVisible(town, player), "Town is not visible!", false); //it's not a town or it's not visible for layer - bool detailed = hasAccess(town->tempOwner); - - //TODO vision support - if(town->ID == Obj::TOWN) - dest.initFromTown(static_cast(town), detailed); - else if(town->ID == Obj::GARRISON || town->ID == Obj::GARRISON2) - dest.initFromArmy(static_cast(town), detailed); - else - return false; - return true; -} - -int3 CGameInfoCallback::guardingCreaturePosition (int3 pos) const //FIXME: redundant? -{ - ERROR_RET_VAL_IF(!isVisible(pos), "Tile is not visible!", int3(-1,-1,-1)); - return gs->guardingCreaturePosition(pos); -} - -std::vector CGameInfoCallback::getGuardingCreatures (int3 pos) const -{ - ERROR_RET_VAL_IF(!isVisible(pos), "Tile is not visible!", std::vector()); - std::vector ret; - for(auto cr : gs->guardingCreatures(pos)) - { - ret.push_back(cr); - } - return ret; -} - -bool CGameInfoCallback::getHeroInfo( const CGObjectInstance *hero, InfoAboutHero &dest ) const -{ - const CGHeroInstance *h = dynamic_cast(hero); - - ERROR_RET_VAL_IF(!h, "That's not a hero!", false); - ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false); - - //TODO vision support - dest.initFromHero(h, hasAccess(h->tempOwner)); - return true; -} - -int CGameInfoCallback::getDate(Date::EDateType mode) const -{ - //boost::shared_lock lock(*gs->mx); - return gs->getDate(mode); -} -std::vector < std::string > CGameInfoCallback::getObjDescriptions(int3 pos) const -{ - //boost::shared_lock lock(*gs->mx); - std::vector ret; - const TerrainTile *t = getTile(pos); - ERROR_RET_VAL_IF(!t, "Not a valid tile given!", ret); - - - for(const CGObjectInstance * obj : t->blockingObjects) - ret.push_back(obj->getHoverText()); - return ret; -} - -bool CGameInfoCallback::isVisible(int3 pos, boost::optional Player) const -{ - //boost::shared_lock lock(*gs->mx); - return gs->map->isInTheMap(pos) && (!Player || gs->isVisible(pos, *Player)); -} - -bool CGameInfoCallback::isVisible(int3 pos) const -{ - return isVisible(pos, player); -} - -bool CGameInfoCallback::isVisible( const CGObjectInstance *obj, boost::optional Player ) const -{ - return gs->isVisible(obj, Player); -} - -bool CGameInfoCallback::isVisible(const CGObjectInstance *obj) const -{ - return isVisible(obj, player); -} -// const CCreatureSet* CInfoCallback::getGarrison(const CGObjectInstance *obj) const -// { -// //boost::shared_lock lock(*gs->mx); -// if() -// const CArmedInstance *armi = dynamic_cast(obj); -// if(!armi) -// return nullptr; -// else -// return armi; -// } - -std::vector < const CGObjectInstance * > CGameInfoCallback::getBlockingObjs( int3 pos ) const -{ - std::vector ret; - const TerrainTile *t = getTile(pos); - ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret); - - for(const CGObjectInstance * obj : t->blockingObjects) - ret.push_back(obj); - return ret; -} - -std::vector CGameInfoCallback::getVisitableObjs(int3 pos, bool verbose /*= true*/) const -{ - std::vector ret; - const TerrainTile *t = getTile(pos, verbose); - ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!t, verbose, pos << " is not visible!", ret); - - for(const CGObjectInstance * obj : t->visitableObjects) - { - if(player < nullptr || obj->ID != Obj::EVENT) //hide events from players - ret.push_back(obj); - } - - return ret; -} -const CGObjectInstance * CGameInfoCallback::getTopObj (int3 pos) const -{ - return vstd::backOrNull(getVisitableObjs(pos)); -} - -std::vector < const CGObjectInstance * > CGameInfoCallback::getFlaggableObjects(int3 pos) const -{ - std::vector ret; - const TerrainTile *t = getTile(pos); - ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret); - for(const CGObjectInstance *obj : t->blockingObjects) - if(obj->tempOwner != PlayerColor::UNFLAGGABLE) - ret.push_back(obj); -// const std::vector < std::pair > & objs = CGI->mh->ttiles[pos.x][pos.y][pos.z].objects; -// for(size_t b=0; btempOwner!=254 && !((objs[b].first->defInfo->blockMap[pos.y - objs[b].first->pos.y + 5] >> (objs[b].first->pos.x - pos.x)) & 1)) -// ret.push_back(CGI->mh->ttiles[pos.x][pos.y][pos.z].objects[b].first); -// } - return ret; -} - -int3 CGameInfoCallback::getMapSize() const -{ - return int3(gs->map->width, gs->map->height, gs->map->twoLevel ? 2 : 1); -} - -std::vector CGameInfoCallback::getAvailableHeroes(const CGObjectInstance * townOrTavern) const -{ - ASSERT_IF_CALLED_WITH_PLAYER - std::vector ret; - //ERROR_RET_VAL_IF(!isOwnedOrVisited(townOrTavern), "Town or tavern must be owned or visited!", ret); - //TODO: town needs to be owned, advmap tavern needs to be visited; to be reimplemented when visit tracking is done - range::copy(gs->players[*player].availableHeroes, std::back_inserter(ret)); - vstd::erase_if(ret, [](const CGHeroInstance *h) { return h == nullptr; }); - return ret; -} - -const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const -{ - ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!isVisible(tile), verbose, tile << " is not visible!", nullptr); - - //boost::shared_lock lock(*gs->mx); - return &gs->map->getTile(tile); -} - -EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, BuildingID ID ) -{ - ERROR_RET_VAL_IF(!canGetFullInfo(t), "Town is not owned!", EBuildingState::TOWN_NOT_OWNED); - - if(!t->town->buildings.count(ID)) - return EBuildingState::BUILDING_ERROR; - - const CBuilding * building = t->town->buildings.at(ID); - - - if(t->hasBuilt(ID)) //already built - return EBuildingState::ALREADY_PRESENT; - - //can we build it? - if(vstd::contains(t->forbiddenBuildings, ID)) - return EBuildingState::FORBIDDEN; //forbidden - - if(ID == BuildingID::CAPITOL) - { - const PlayerState *ps = getPlayer(t->tempOwner); - if(ps) - { - for(const CGTownInstance *t : ps->towns) - { - if(t->hasBuilt(BuildingID::CAPITOL)) - { - return EBuildingState::HAVE_CAPITAL; //no more than one capitol - } - } - } - } - else if(ID == BuildingID::SHIPYARD) - { - const TerrainTile *tile = getTile(t->bestLocation(), false); - - if(!tile || tile->terType != ETerrainType::WATER) - return EBuildingState::NO_WATER; //lack of water - } - - auto buildTest = [&](const BuildingID & id) - { - return t->hasBuilt(id); - }; - - if(t->builded >= VLC->modh->settings.MAX_BUILDING_PER_TURN) - return EBuildingState::CANT_BUILD_TODAY; //building limit - - if (!building->requirements.test(buildTest)) - return EBuildingState::PREREQUIRES; - - if (building->upgrade != BuildingID::NONE && !t->hasBuilt(building->upgrade)) - return EBuildingState::MISSING_BASE; - - //checking resources - if(!building->resources.canBeAfforded(getPlayer(t->tempOwner)->resources)) - return EBuildingState::NO_RESOURCES; //lack of res - - return EBuildingState::ALLOWED; -} - -const CMapHeader * CGameInfoCallback::getMapHeader() const -{ - return gs->map; -} - -bool CGameInfoCallback::hasAccess(boost::optional playerId) const -{ - return !player || gs->getPlayerRelations( *playerId, *player ) != PlayerRelations::ENEMIES; -} - -EPlayerStatus::EStatus CGameInfoCallback::getPlayerStatus(PlayerColor player, bool verbose) const -{ - const PlayerState *ps = gs->getPlayer(player, verbose); - ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!ps, verbose, "No such player!", EPlayerStatus::WRONG); - - return ps->status; -} - -std::string CGameInfoCallback::getTavernGossip(const CGObjectInstance * townOrTavern) const -{ - return "GOSSIP TEST"; -} - -PlayerRelations::PlayerRelations CGameInfoCallback::getPlayerRelations( PlayerColor color1, PlayerColor color2 ) const -{ - return gs->getPlayerRelations(color1, color2); -} - -bool CGameInfoCallback::canGetFullInfo(const CGObjectInstance *obj) const -{ - return !obj || hasAccess(obj->tempOwner); -} - -int CGameInfoCallback::getHeroCount( PlayerColor player, bool includeGarrisoned ) const -{ - int ret = 0; - const PlayerState *p = gs->getPlayer(player); - ERROR_RET_VAL_IF(!p, "No such player!", -1); - - if(includeGarrisoned) - return p->heroes.size(); - else - for(auto & elem : p->heroes) - if(!elem->inTownGarrison) - ret++; - return ret; -} - -bool CGameInfoCallback::isOwnedOrVisited(const CGObjectInstance *obj) const -{ - if(canGetFullInfo(obj)) - return true; - - const TerrainTile *t = getTile(obj->visitablePos()); //get entrance tile - const CGObjectInstance *visitor = t->visitableObjects.back(); //visitong hero if present or the obejct itself at last - return visitor->ID == Obj::HERO && canGetFullInfo(visitor); //owned or allied hero is a visitor -} - -PlayerColor CGameInfoCallback::getCurrentPlayer() const -{ - return gs->currentPlayer; -} - -CGameInfoCallback::CGameInfoCallback() -{ -} - -CGameInfoCallback::CGameInfoCallback(CGameState *GS, boost::optional Player) -{ - gs = GS; - player = Player; -} - -const std::vector< std::vector< std::vector > > & CPlayerSpecificInfoCallback::getVisibilityMap() const -{ - //boost::shared_lock lock(*gs->mx); - return gs->getPlayerTeam(*player)->fogOfWarMap; -} - -int CPlayerSpecificInfoCallback::howManyTowns() const -{ - //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1); - return CGameInfoCallback::howManyTowns(*player); -} - -std::vector < const CGTownInstance *> CPlayerSpecificInfoCallback::getTownsInfo(bool onlyOur) const -{ - //boost::shared_lock lock(*gs->mx); - std::vector < const CGTownInstance *> ret = std::vector < const CGTownInstance *>(); - for(const auto & i : gs->players) - { - for(const auto & town : i.second.towns) - { - if (i.first==player || (isVisible(town, player) && !onlyOur)) - { - ret.push_back(town); - } - } - } // for ( std::map::iterator i=gs->players.begin() ; i!=gs->players.end();i++) - return ret; -} -std::vector < const CGHeroInstance *> CPlayerSpecificInfoCallback::getHeroesInfo(bool onlyOur) const -{ - //boost::shared_lock lock(*gs->mx); - std::vector < const CGHeroInstance *> ret; - for(auto hero : gs->map->heroesOnMap) - { - if( !player || (hero->tempOwner == *player) || - (isVisible(hero->getPosition(false), player) && !onlyOur) ) - { - ret.push_back(hero); - } - } - return ret; -} - -boost::optional CPlayerSpecificInfoCallback::getMyColor() const -{ - return player; -} - -int CPlayerSpecificInfoCallback::getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned) const -{ - if (hero->inTownGarrison && !includeGarrisoned) - return -1; - - size_t index = 0; - auto & heroes = gs->players[*player].heroes; - - for (auto & heroe : heroes) - { - if (includeGarrisoned || !(heroe)->inTownGarrison) - index++; - - if (heroe == hero) - return index; - } - return -1; -} - -int3 CPlayerSpecificInfoCallback::getGrailPos( double &outKnownRatio ) -{ - if (!player || CGObelisk::obeliskCount == 0) - { - outKnownRatio = 0.0; - } - else - { - outKnownRatio = static_cast(CGObelisk::visited[gs->getPlayerTeam(*player)->id]) / CGObelisk::obeliskCount; - } - return gs->map->grailPos; -} - -std::vector < const CGObjectInstance * > CPlayerSpecificInfoCallback::getMyObjects() const -{ - std::vector < const CGObjectInstance * > ret; - for(const CGObjectInstance * obj : gs->map->objects) - { - if(obj && obj->tempOwner == player) - ret.push_back(obj); - } - return ret; -} - -std::vector < const CGDwelling * > CPlayerSpecificInfoCallback::getMyDwellings() const -{ - ASSERT_IF_CALLED_WITH_PLAYER - std::vector < const CGDwelling * > ret; - for(CGDwelling * dw : gs->getPlayer(*player)->dwellings) - { - ret.push_back(dw); - } - return ret; -} - -std::vector CPlayerSpecificInfoCallback::getMyQuests() const -{ - std::vector ret; - for (auto quest : gs->getPlayer(*player)->quests) - { - ret.push_back (quest); - } - return ret; -} - -int CPlayerSpecificInfoCallback::howManyHeroes(bool includeGarrisoned) const -{ - //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1); - return getHeroCount(*player,includeGarrisoned); -} - -const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId, bool includeGarrisoned) const -{ - ASSERT_IF_CALLED_WITH_PLAYER - const PlayerState *p = getPlayer(*player); - ERROR_RET_VAL_IF(!p, "No player info", nullptr); - - if (!includeGarrisoned) - { - for(ui32 i = 0; i < p->heroes.size() && i<=serialId; i++) - if(p->heroes[i]->inTownGarrison) - serialId++; - } - ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->heroes.size(), "No player info", nullptr); - return p->heroes[serialId]; -} - -const CGTownInstance* CPlayerSpecificInfoCallback::getTownBySerial(int serialId) const -{ - ASSERT_IF_CALLED_WITH_PLAYER - const PlayerState *p = getPlayer(*player); - ERROR_RET_VAL_IF(!p, "No player info", nullptr); - ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->towns.size(), "No player info", nullptr); - return p->towns[serialId]; -} - -int CPlayerSpecificInfoCallback::getResourceAmount(Res::ERes type) const -{ - //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1); - return getResource(*player, type); -} - -TResources CPlayerSpecificInfoCallback::getResourceAmount() const -{ - //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", TResources()); - return gs->players[*player].resources; -} - -CGHeroInstance *CNonConstInfoCallback::getHero(ObjectInstanceID objid) -{ - return const_cast(CGameInfoCallback::getHero(objid)); -} - -CGTownInstance *CNonConstInfoCallback::getTown(ObjectInstanceID objid) -{ - return const_cast(CGameInfoCallback::getTown(objid)); -} - -TeamState *CNonConstInfoCallback::getTeam(TeamID teamID) -{ - return const_cast(CGameInfoCallback::getTeam(teamID)); -} - -TeamState *CNonConstInfoCallback::getPlayerTeam(PlayerColor color) -{ - return const_cast(CGameInfoCallback::getPlayerTeam(color)); -} - -PlayerState * CNonConstInfoCallback::getPlayer( PlayerColor color, bool verbose ) -{ - return const_cast(CGameInfoCallback::getPlayer(color, verbose)); -} - -CArtifactInstance * CNonConstInfoCallback::getArtInstance( ArtifactInstanceID aid ) -{ - return gs->map->artInstances[aid.num]; -} - -CGObjectInstance * CNonConstInfoCallback::getObjInstance( ObjectInstanceID oid ) -{ - return gs->map->objects[oid.num]; -} - -const TeamState * CGameInfoCallback::getTeam( TeamID teamID ) const -{ - ERROR_RET_VAL_IF(!vstd::contains(gs->teams, teamID), "Cannot find info for team " << teamID, nullptr); - const TeamState *ret = &gs->teams[teamID]; - ERROR_RET_VAL_IF(!!player && !vstd::contains(ret->players, *player), "Illegal attempt to access team data!", nullptr); - return ret; -} - -const TeamState * CGameInfoCallback::getPlayerTeam( PlayerColor color ) const -{ - const PlayerState * ps = getPlayer(color); - if (ps) - return getTeam(ps->team); - return nullptr; -} - -const CGHeroInstance* CGameInfoCallback::getHeroWithSubid( int subid ) const -{ - for(const CGHeroInstance *h : gs->map->heroesOnMap) - if(h->subID == subid) - return h; - - return nullptr; -} - -PlayerColor CGameInfoCallback::getLocalPlayer() const -{ - return getCurrentPlayer(); -} - -bool CGameInfoCallback::isInTheMap(const int3 &pos) const -{ - return gs->map->isInTheMap(pos); -} - -const CArtifactInstance * CGameInfoCallback::getArtInstance( ArtifactInstanceID aid ) const -{ - return gs->map->artInstances[aid.num]; -} - -const CGObjectInstance * CGameInfoCallback::getObjInstance( ObjectInstanceID oid ) const -{ - return gs->map->objects[oid.num]; -} - -void IGameEventRealizer::showInfoDialog( InfoWindow *iw ) -{ - commitPackage(iw); -} - -void IGameEventRealizer::showInfoDialog(const std::string &msg, PlayerColor player) -{ - InfoWindow iw; - iw.player = player; - iw.text << msg; - showInfoDialog(&iw); -} - -void IGameEventRealizer::setObjProperty(ObjectInstanceID objid, int prop, si64 val) -{ - SetObjectProperty sob; - sob.id = objid; - sob.what = prop; - sob.val = static_cast(val); - commitPackage(&sob); -} +#define ERROR_RET_VAL_IF(cond, txt, retVal) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0)*/ const CGObjectInstance * IGameCallback::putNewObject(Obj ID, int subID, int3 pos) { diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 164e11d30..84808af85 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -1,11 +1,12 @@ #pragma once +#include "IGameCallback2.h" // for CPrivilagedInfoCallback, IGameEventCallback -#include "BattleHex.h" +/*#include "BattleHex.h" #include "ResourceSet.h" #include "int3.h" #include "GameConstants.h" -#include "CBattleCallback.h" +#include "CBattleCallback.h"*/ /* * IGameCallback.h, part of VCMI engine @@ -17,7 +18,7 @@ * */ -struct SetMovePoints; +/*struct SetMovePoints; struct GiveBonus; class CGObjectInstance; class CGTownInstance; @@ -55,210 +56,10 @@ class CCreatureSet; class CCreature; class CStackBasicDescriptor; struct TeamState; -struct QuestInfo; +struct QuestInfo;*/ class CGCreature; -class CSaveFile; -class CLoadFile; - -class DLL_LINKAGE CGameInfoCallback : public virtual CCallbackBase -{ -protected: - CGameInfoCallback(); - CGameInfoCallback(CGameState *GS, boost::optional Player); - bool hasAccess(boost::optional playerId) const; - bool isVisible(int3 pos, boost::optional Player) const; - bool isVisible(const CGObjectInstance *obj, boost::optional Player) const; - bool isVisible(const CGObjectInstance *obj) const; - - bool canGetFullInfo(const CGObjectInstance *obj) const; //true we player owns obj or ally owns obj or privileged mode - bool isOwnedOrVisited(const CGObjectInstance *obj) const; - -public: - //various - int getDate(Date::EDateType mode=Date::DAY)const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month - const StartInfo * getStartInfo(bool beforeRandomization = false)const; - bool isAllowed(int type, int id); //type: 0 - spell; 1- artifact; 2 - secondary skill - - //player - const PlayerState * getPlayer(PlayerColor color, bool verbose = true) const; - int getResource(PlayerColor Player, Res::ERes which) const; - bool isVisible(int3 pos) const; - PlayerRelations::PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2) const; - void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj); //get thieves' guild info obtainable while visiting given object - EPlayerStatus::EStatus getPlayerStatus(PlayerColor player, bool verbose = true) const; //-1 if no such player - PlayerColor getCurrentPlayer() const; //player that currently makes move // TODO synchronous turns - virtual PlayerColor getLocalPlayer() const; //player that is currently owning given client (if not a client, then returns current player) - const PlayerSettings * getPlayerSettings(PlayerColor color) const; - - - //armed object - void getUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out)const; - - //hero - const CGHeroInstance* getHero(ObjectInstanceID objid) const; - const CGHeroInstance* getHeroWithSubid(int subid) const; - int getHeroCount(PlayerColor player, bool includeGarrisoned) const; - bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const; - int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //when called during battle, takes into account creatures' spell cost reduction - int estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const; //estimates damage of given spell; returns 0 if spell causes no dmg - const CGHeroInstance* getSelectedHero(PlayerColor player) const; //nullptr if no hero is selected - const CGHeroInstance* getSelectedHero() const; //of current (active) player - const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const; - const CGObjectInstance * getObjInstance(ObjectInstanceID oid) const; - - //objects - const CGObjectInstance* getObj(ObjectInstanceID objid, bool verbose = true) const; - std::vector getBlockingObjs(int3 pos)const; - std::vector getVisitableObjs(int3 pos, bool verbose = true)const; - std::vector getFlaggableObjects(int3 pos) const; - const CGObjectInstance * getTopObj (int3 pos) const; - std::vector getObjDescriptions(int3 pos)const; //returns descriptions of objects at pos in order from the lowest to the highest - PlayerColor getOwner(ObjectInstanceID heroID) const; - const CGObjectInstance *getObjByQuestIdentifier(int identifier) const; //nullptr if object has been removed (eg. killed) - - //map - int3 guardingCreaturePosition (int3 pos) const; - std::vector getGuardingCreatures (int3 pos) const; - const CMapHeader * getMapHeader()const; - int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map - const TerrainTile * getTile(int3 tile, bool verbose = true) const; - bool isInTheMap(const int3 &pos) const; - - //town - const CGTownInstance* getTown(ObjectInstanceID objid) const; - int howManyTowns(PlayerColor Player) const; - const CGTownInstance * getTownInfo(int val, bool mode)const; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial) - std::vector getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited - std::string getTavernGossip(const CGObjectInstance * townOrTavern) const; - EBuildingState::EBuildingState canBuildStructure(const CGTownInstance *t, BuildingID ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements - virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const; - const CTown *getNativeTown(PlayerColor color) const; - - //from gs - const TeamState *getTeam(TeamID teamID) const; - const TeamState *getPlayerTeam(PlayerColor color) const; - EBuildingState::EBuildingState canBuildStructure(const CGTownInstance *t, BuildingID ID) const;// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements -}; - - -class DLL_LINKAGE CPlayerSpecificInfoCallback : public CGameInfoCallback -{ -public: - int howManyTowns() const; - int howManyHeroes(bool includeGarrisoned = true) const; - int3 getGrailPos(double &outKnownRatio); - boost::optional getMyColor() const; - - std::vector getTownsInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible - int getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned=true) const; - const CGTownInstance* getTownBySerial(int serialId) const; // serial id is [0, number of towns) - const CGHeroInstance* getHeroBySerial(int serialId, bool includeGarrisoned=true) const; // serial id is [0, number of heroes) - std::vector getHeroesInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible - std::vector getMyDwellings() const; //returns all dwellings that belong to player - std::vector getMyObjects() const; //returns all objects flagged by belonging player - std::vector getMyQuests() const; - - int getResourceAmount(Res::ERes type) const; - TResources getResourceAmount() const; - const std::vector< std::vector< std::vector > > & getVisibilityMap()const; //returns visibility map - const PlayerSettings * getPlayerSettings(PlayerColor color) const; -}; - -class DLL_LINKAGE CPrivilagedInfoCallback : public CGameInfoCallback -{ -public: - CGameState * gameState(); - void getFreeTiles (std::vector &tiles) const; //used for random spawns - void getTilesInRange(std::unordered_set &tiles, int3 pos, int radious, boost::optional player = boost::optional(), int mode=0) const; //mode 1 - only unrevealed tiles; mode 0 - all, mode -1 - only unrevealed - void getAllTiles (std::unordered_set &tiles, boost::optional player = boost::optional(), int level=-1, int surface=0) const; //returns all tiles on given level (-1 - both levels, otherwise number of level); surface: 0 - land and water, 1 - only land, 2 - only water - void pickAllowedArtsSet(std::vector &out); //gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant - void getAllowedSpells(std::vector &out, ui16 level); - - template - void saveCommonState(Saver &out) const; //stores GS and VLC - - template - void loadCommonState(Loader &in); //loads GS and VLC -}; - -class DLL_LINKAGE CNonConstInfoCallback : public CPrivilagedInfoCallback -{ -public: - PlayerState *getPlayer(PlayerColor color, bool verbose = true); - TeamState *getTeam(TeamID teamID);//get team by team ID - TeamState *getPlayerTeam(PlayerColor color);// get team by player color - CGHeroInstance *getHero(ObjectInstanceID objid); - CGTownInstance *getTown(ObjectInstanceID objid); - TerrainTile * getTile(int3 pos); - CArtifactInstance * getArtInstance(ArtifactInstanceID aid); - CGObjectInstance * getObjInstance(ObjectInstanceID oid); -}; - -class DLL_LINKAGE IGameEventRealizer -{ -public: - virtual void commitPackage(CPackForClient *pack) = 0; - - virtual void showInfoDialog(InfoWindow *iw); - virtual void setObjProperty(ObjectInstanceID objid, int prop, si64 val); - - - virtual void showInfoDialog(const std::string &msg, PlayerColor player); -}; - -class DLL_LINKAGE IGameEventCallback : public IGameEventRealizer -{ -public: - virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set &spells)=0; - virtual bool removeObject(const CGObjectInstance * obj)=0; - virtual void setBlockVis(ObjectInstanceID objid, bool bv)=0; - virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0; - virtual void setHoverName(const CGObjectInstance * obj, MetaString * name)=0; - virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false)=0; - virtual void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false)=0; - virtual void showBlockingDialog(BlockingDialog *iw) =0; - virtual void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) =0; //cb will be called when player closes garrison window - virtual void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) =0; - virtual void giveResource(PlayerColor player, Res::ERes which, int val)=0; - virtual void giveResources(PlayerColor player, TResources resources)=0; - - virtual void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0; - virtual void takeCreatures(ObjectInstanceID objid, const std::vector &creatures) =0; - virtual bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0; - virtual bool changeStackType(const StackLocation &sl, CCreature *c) =0; - virtual bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count = -1) =0; //count -1 => moves whole stack - virtual bool eraseStack(const StackLocation &sl, bool forceRemoval = false) =0; - virtual bool swapStacks(const StackLocation &sl1, const StackLocation &sl2) =0; - virtual bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count) =0; //makes new stack or increases count of already existing - virtual void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging) =0; //merges army from src do dst or opens a garrison window - virtual bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count) = 0; - - virtual void removeAfterVisit(const CGObjectInstance *object) = 0; //object will be destroyed when interaction is over. Do not call when interaction is not ongoing! - - virtual void giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact *artType, ArtifactPosition pos) = 0; - virtual void giveHeroArtifact(const CGHeroInstance *h, const CArtifactInstance *a, ArtifactPosition pos) = 0; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack - virtual void putArtifact(const ArtifactLocation &al, const CArtifactInstance *a) = 0; - virtual void removeArtifact(const ArtifactLocation &al) = 0; - virtual bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) = 0; - virtual void synchronizeArtifactHandlerLists() = 0; - - virtual void showCompInfo(ShowInInfobox * comp)=0; - virtual void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0; - virtual void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0; - virtual void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = nullptr)=0; //use hero=nullptr for no hero - virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank = false)=0; //if any of armies is hero, hero will be used - virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle - virtual void setAmount(ObjectInstanceID objid, ui32 val)=0; - virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL)=0; - virtual void giveHeroBonus(GiveBonus * bonus)=0; - virtual void setMovePoints(SetMovePoints * smp)=0; - virtual void setManaPoints(ObjectInstanceID hid, int val)=0; - virtual void giveHero(ObjectInstanceID id, PlayerColor player)=0; - virtual void changeObjPos(ObjectInstanceID objid, int3 newPos, ui8 flags)=0; - virtual void sendAndApply(CPackForClient * info)=0; - virtual void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)=0; //when two heroes meet on adventure map - virtual void addQuest(int player, QuestInfo & quest){}; -}; +/*class CSaveFile; +class CLoadFile;*/ /// Interface class for handling general game logic and actions class DLL_LINKAGE IGameCallback : public CPrivilagedInfoCallback, public IGameEventCallback @@ -277,3 +78,4 @@ public: friend struct CPackForClient; friend struct CPackForServer; }; + diff --git a/lib/IGameCallback2.cpp b/lib/IGameCallback2.cpp new file mode 100644 index 000000000..6b7621392 --- /dev/null +++ b/lib/IGameCallback2.cpp @@ -0,0 +1,951 @@ +/* + * IGameCallback.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "StdInc.h" +#include "IGameCallback2.h" + +#include "CGameState.h" +/*#include "mapping/CMap.h"*/ +#include "CObjectHandler.h" +#include "CHeroHandler.h" +#include "StartInfo.h" +/*#include "CArtHandler.h"*/ +#include "CSpellHandler.h" +/*#include "VCMI_Lib.h" +#include "CTownHandler.h"*/ +#include "BattleState.h" +#include "NetPacks.h" +/*#include "CBuildingHandler.h" +#include "GameConstants.h" +#include "CModHandler.h" +#include "CDefObjInfoHandler.h"*/ +#include "CBonusTypeHandler.h" + +#include "Connection.h" + +//TODO make clean +/*#define ERROR_SILENT_RET_VAL_IF(cond, txt, retVal) do {if(cond){return retVal;}} while(0)*/ +#define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0) +#define ERROR_RET_IF(cond, txt) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return;}} while(0) +#define ERROR_RET_VAL_IF(cond, txt, retVal) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0) + +CGameState * CPrivilagedInfoCallback::gameState () +{ + return gs; +} + +PlayerColor CGameInfoCallback::getOwner(ObjectInstanceID heroID) const +{ + const CGObjectInstance *obj = getObj(heroID); + ERROR_RET_VAL_IF(!obj, "No such object!", PlayerColor::CANNOT_DETERMINE); + return obj->tempOwner; +} + +int CGameInfoCallback::getResource(PlayerColor Player, Res::ERes which) const +{ + const PlayerState *p = getPlayer(Player); + ERROR_RET_VAL_IF(!p, "No player info!", -1); + ERROR_RET_VAL_IF(p->resources.size() <= which || which < 0, "No such resource!", -1); + return p->resources[which]; +} + +const CGHeroInstance* CGameInfoCallback::getSelectedHero( PlayerColor Player ) const +{ + const PlayerState *p = getPlayer(Player); + ERROR_RET_VAL_IF(!p, "No player info!", nullptr); + return getHero(p->currentSelection); +} + +const CGHeroInstance* CGameInfoCallback::getSelectedHero() const +{ + return getSelectedHero(gs->currentPlayer); +} + +const PlayerSettings * CGameInfoCallback::getPlayerSettings(PlayerColor color) const +{ + return &gs->scenarioOps->getIthPlayersSettings(color); +} + +void CPrivilagedInfoCallback::getTilesInRange( std::unordered_set &tiles, int3 pos, int radious, boost::optional player/*=uninit*/, int mode/*=0*/ ) const +{ + if(!!player && *player >= PlayerColor::PLAYER_LIMIT) + { + logGlobal->errorStream() << "Illegal call to getTilesInRange!"; + return; + } + if (radious == -1) //reveal entire map + getAllTiles (tiles, player, -1, 0); + else + { + const TeamState * team = !player ? nullptr : gs->getPlayerTeam(*player); + for (int xd = std::max(pos.x - radious , 0); xd <= std::min(pos.x + radious, gs->map->width - 1); xd++) + { + for (int yd = std::max(pos.y - radious, 0); yd <= std::min(pos.y + radious, gs->map->height - 1); yd++) + { + double distance = pos.dist2d(int3(xd,yd,pos.z)) - 0.5; + if(distance <= radious) + { + if(!player + || (mode == 1 && team->fogOfWarMap[xd][yd][pos.z]==0) + || (mode == -1 && team->fogOfWarMap[xd][yd][pos.z]==1) + ) + tiles.insert(int3(xd,yd,pos.z)); + } + } + } + } +} + +void CPrivilagedInfoCallback::getAllTiles (std::unordered_set &tiles, boost::optional Player/*=uninit*/, int level, int surface ) const +{ + if(!!Player && *Player >= PlayerColor::PLAYER_LIMIT) + { + logGlobal->errorStream() << "Illegal call to getAllTiles !"; + return; + } + bool water = surface == 0 || surface == 2, + land = surface == 0 || surface == 1; + + std::vector floors; + if(level == -1) + { + for(int b = 0; b < (gs->map->twoLevel ? 2 : 1); ++b) + { + floors.push_back(b); + } + } + else + floors.push_back(level); + + for (auto zd : floors) + { + + for (int xd = 0; xd < gs->map->width; xd++) + { + for (int yd = 0; yd < gs->map->height; yd++) + { + if ((getTile (int3 (xd,yd,zd))->terType == ETerrainType::WATER && water) + || (getTile (int3 (xd,yd,zd))->terType != ETerrainType::WATER && land)) + tiles.insert(int3(xd,yd,zd)); + } + } + } +} + +void CPrivilagedInfoCallback::getFreeTiles (std::vector &tiles) const +{ + std::vector floors; + for (int b = 0; b < (gs->map->twoLevel ? 2 : 1); ++b) + { + floors.push_back(b); + } + const TerrainTile *tinfo; + for (auto zd : floors) + { + + for (int xd = 0; xd < gs->map->width; xd++) + { + for (int yd = 0; yd < gs->map->height; yd++) + { + tinfo = getTile(int3 (xd,yd,zd)); + if (tinfo->terType != ETerrainType::WATER && !tinfo->blocked) //land and free + tiles.push_back (int3 (xd,yd,zd)); + } + } + } +} + +bool CGameInfoCallback::isAllowed( int type, int id ) +{ + switch(type) + { + case 0: + return gs->map->allowedSpell[id]; + case 1: + return gs->map->allowedArtifact[id]; + case 2: + return gs->map->allowedAbilities[id]; + default: + ERROR_RET_VAL_IF(1, "Wrong type!", false); + } +} + +void CPrivilagedInfoCallback::pickAllowedArtsSet(std::vector &out) +{ + for (int j = 0; j < 3 ; j++) + out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_TREASURE)]); + for (int j = 0; j < 3 ; j++) + out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_MINOR)]); + + out.push_back(VLC->arth->artifacts[VLC->arth->pickRandomArtifact(gameState()->getRandomGenerator(), CArtifact::ART_MAJOR)]); +} + +void CPrivilagedInfoCallback::getAllowedSpells(std::vector &out, ui16 level) +{ + for (ui32 i = 0; i < gs->map->allowedSpell.size(); i++) //spellh size appears to be greater (?) + { + + const CSpell *spell = SpellID(i).toSpell(); + if (isAllowed (0, spell->id) && spell->level == level) + { + out.push_back(spell->id); + } + } +} + + +template +void CPrivilagedInfoCallback::loadCommonState(Loader &in) +{ + logGlobal->infoStream() << "Loading lib part of game..."; + in.checkMagicBytes(SAVEGAME_MAGIC); + + CMapHeader dum; + StartInfo *si; + + logGlobal->infoStream() <<"\tReading header"; + in >> dum; + + logGlobal->infoStream() << "\tReading options"; + in >> si; + + logGlobal->infoStream() <<"\tReading handlers"; + in >> *VLC; + + logGlobal->infoStream() <<"\tReading gamestate"; + in >> gs; +} + +template +void CPrivilagedInfoCallback::saveCommonState(Saver &out) const +{ + logGlobal->infoStream() << "Saving lib part of game..."; + out.putMagicBytes(SAVEGAME_MAGIC); + logGlobal->infoStream() <<"\tSaving header"; + out << static_cast(*gs->map); + logGlobal->infoStream() << "\tSaving options"; + out << gs->scenarioOps; + logGlobal->infoStream() << "\tSaving handlers"; + out << *VLC; + logGlobal->infoStream() << "\tSaving gamestate"; + out << gs; +} + +template DLL_LINKAGE void CPrivilagedInfoCallback::loadCommonState(CLoadIntegrityValidator&); +template DLL_LINKAGE void CPrivilagedInfoCallback::loadCommonState(CLoadFile&); +template DLL_LINKAGE void CPrivilagedInfoCallback::saveCommonState(CSaveFile&) const; + +TerrainTile * CNonConstInfoCallback::getTile( int3 pos ) +{ + if(!gs->map->isInTheMap(pos)) + return nullptr; + return &gs->map->getTile(pos); +} + +const PlayerState * CGameInfoCallback::getPlayer(PlayerColor color, bool verbose) const +{ + ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!hasAccess(color), verbose, "Cannot access player " << color << "info!", nullptr); + ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!vstd::contains(gs->players,color), verbose, "Cannot find player " << color << "info!", nullptr); + return &gs->players[color]; +} + +const CTown * CGameInfoCallback::getNativeTown(PlayerColor color) const +{ + const PlayerSettings *ps = getPlayerSettings(color); + ERROR_RET_VAL_IF(!ps, "There is no such player!", nullptr); + return VLC->townh->factions[ps->castle]->town; +} + +const CGObjectInstance * CGameInfoCallback::getObjByQuestIdentifier(int identifier) const +{ + ERROR_RET_VAL_IF(!vstd::contains(gs->map->questIdentifierToId, identifier), "There is no object with such quest identifier!", nullptr); + return getObj(gs->map->questIdentifierToId[identifier]); +} + +/************************************************************************/ +/* */ +/************************************************************************/ + +const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool verbose) const +{ + si32 oid = objid.num; + if(oid < 0 || oid >= gs->map->objects.size()) + { + if(verbose) + logGlobal->errorStream() << "Cannot get object with id " << oid; + return nullptr; + } + + const CGObjectInstance *ret = gs->map->objects[oid]; + if(!ret) + { + if(verbose) + logGlobal->errorStream() << "Cannot get object with id " << oid << ". Object was removed."; + return nullptr; + } + + if(!isVisible(ret, player)) + { + if(verbose) + logGlobal->errorStream() << "Cannot get object with id " << oid << ". Object is not visible."; + return nullptr; + } + + return ret; +} + +const CGHeroInstance* CGameInfoCallback::getHero(ObjectInstanceID objid) const +{ + const CGObjectInstance *obj = getObj(objid, false); + if(obj) + return dynamic_cast(obj); + else + return nullptr; +} +const CGTownInstance* CGameInfoCallback::getTown(ObjectInstanceID objid) const +{ + const CGObjectInstance *obj = getObj(objid, false); + if(obj) + return dynamic_cast(obj); + else + return nullptr; +} + +void CGameInfoCallback::getUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out) const +{ + //boost::shared_lock lock(*gs->mx); + ERROR_RET_IF(!canGetFullInfo(obj), "Cannot get info about not owned object!"); + ERROR_RET_IF(!obj->hasStackAtSlot(stackPos), "There is no such stack!"); + out = gs->getUpgradeInfo(obj->getStack(stackPos)); + //return gs->getUpgradeInfo(obj->getStack(stackPos)); +} + +const StartInfo * CGameInfoCallback::getStartInfo(bool beforeRandomization /*= false*/) const +{ + //boost::shared_lock lock(*gs->mx); + if(beforeRandomization) + return gs->initialOpts; + else + return gs->scenarioOps; +} + +int CGameInfoCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const +{ + //boost::shared_lock lock(*gs->mx); + ERROR_RET_VAL_IF(!canGetFullInfo(caster), "Cannot get info about caster!", -1); + //if there is a battle + if(gs->curB) + return gs->curB->battleGetSpellCost(sp, caster); + + //if there is no battle + return caster->getSpellCost(sp); +} + +int CGameInfoCallback::estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const +{ + //boost::shared_lock lock(*gs->mx); + + ERROR_RET_VAL_IF(hero && !canGetFullInfo(hero), "Cannot get info about caster!", -1); + if(!gs->curB) //no battle + { + if (hero) //but we see hero's spellbook + return gs->curB->calculateSpellDmg( + sp, hero, nullptr, hero->getSpellSchoolLevel(sp), hero->getPrimSkillLevel(PrimarySkill::SPELL_POWER)); + else + return 0; //mage guild + } + //gs->getHero(gs->currentPlayer) + //const CGHeroInstance * ourHero = gs->curB->heroes[0]->tempOwner == player ? gs->curB->heroes[0] : gs->curB->heroes[1]; + const CGHeroInstance * ourHero = hero; + return gs->curB->calculateSpellDmg( + sp, ourHero, nullptr, ourHero->getSpellSchoolLevel(sp), ourHero->getPrimSkillLevel(PrimarySkill::SPELL_POWER)); +} + +void CGameInfoCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj) +{ + //boost::shared_lock lock(*gs->mx); + ERROR_RET_IF(!obj, "No guild object!"); + ERROR_RET_IF(obj->ID == Obj::TOWN && !canGetFullInfo(obj), "Cannot get info about town guild object!"); + //TODO: advmap object -> check if they're visited by our hero + + if(obj->ID == Obj::TOWN || obj->ID == Obj::TAVERN) + { + gs->obtainPlayersStats(thi, gs->players[obj->tempOwner].towns.size()); + } + else if(obj->ID == Obj::DEN_OF_THIEVES) + { + gs->obtainPlayersStats(thi, 20); + } +} + +int CGameInfoCallback::howManyTowns(PlayerColor Player) const +{ + ERROR_RET_VAL_IF(!hasAccess(Player), "Access forbidden!", -1); + return gs->players[Player].towns.size(); +} + +bool CGameInfoCallback::getTownInfo( const CGObjectInstance *town, InfoAboutTown &dest ) const +{ + ERROR_RET_VAL_IF(!isVisible(town, player), "Town is not visible!", false); //it's not a town or it's not visible for layer + bool detailed = hasAccess(town->tempOwner); + + //TODO vision support + if(town->ID == Obj::TOWN) + dest.initFromTown(static_cast(town), detailed); + else if(town->ID == Obj::GARRISON || town->ID == Obj::GARRISON2) + dest.initFromArmy(static_cast(town), detailed); + else + return false; + return true; +} + +int3 CGameInfoCallback::guardingCreaturePosition (int3 pos) const //FIXME: redundant? +{ + ERROR_RET_VAL_IF(!isVisible(pos), "Tile is not visible!", int3(-1,-1,-1)); + return gs->guardingCreaturePosition(pos); +} + +std::vector CGameInfoCallback::getGuardingCreatures (int3 pos) const +{ + ERROR_RET_VAL_IF(!isVisible(pos), "Tile is not visible!", std::vector()); + std::vector ret; + for(auto cr : gs->guardingCreatures(pos)) + { + ret.push_back(cr); + } + return ret; +} + +bool CGameInfoCallback::getHeroInfo( const CGObjectInstance *hero, InfoAboutHero &dest ) const +{ + const CGHeroInstance *h = dynamic_cast(hero); + + ERROR_RET_VAL_IF(!h, "That's not a hero!", false); + ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false); + + //TODO vision support + dest.initFromHero(h, hasAccess(h->tempOwner)); + return true; +} + +int CGameInfoCallback::getDate(Date::EDateType mode) const +{ + //boost::shared_lock lock(*gs->mx); + return gs->getDate(mode); +} +std::vector < std::string > CGameInfoCallback::getObjDescriptions(int3 pos) const +{ + //boost::shared_lock lock(*gs->mx); + std::vector ret; + const TerrainTile *t = getTile(pos); + ERROR_RET_VAL_IF(!t, "Not a valid tile given!", ret); + + + for(const CGObjectInstance * obj : t->blockingObjects) + ret.push_back(obj->getHoverText()); + return ret; +} + +bool CGameInfoCallback::isVisible(int3 pos, boost::optional Player) const +{ + //boost::shared_lock lock(*gs->mx); + return gs->map->isInTheMap(pos) && (!Player || gs->isVisible(pos, *Player)); +} + +bool CGameInfoCallback::isVisible(int3 pos) const +{ + return isVisible(pos, player); +} + +bool CGameInfoCallback::isVisible( const CGObjectInstance *obj, boost::optional Player ) const +{ + return gs->isVisible(obj, Player); +} + +bool CGameInfoCallback::isVisible(const CGObjectInstance *obj) const +{ + return isVisible(obj, player); +} +// const CCreatureSet* CInfoCallback::getGarrison(const CGObjectInstance *obj) const +// { +// //boost::shared_lock lock(*gs->mx); +// if() +// const CArmedInstance *armi = dynamic_cast(obj); +// if(!armi) +// return nullptr; +// else +// return armi; +// } + +std::vector < const CGObjectInstance * > CGameInfoCallback::getBlockingObjs( int3 pos ) const +{ + std::vector ret; + const TerrainTile *t = getTile(pos); + ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret); + + for(const CGObjectInstance * obj : t->blockingObjects) + ret.push_back(obj); + return ret; +} + +std::vector CGameInfoCallback::getVisitableObjs(int3 pos, bool verbose /*= true*/) const +{ + std::vector ret; + const TerrainTile *t = getTile(pos, verbose); + ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!t, verbose, pos << " is not visible!", ret); + + for(const CGObjectInstance * obj : t->visitableObjects) + { + if(player < nullptr || obj->ID != Obj::EVENT) //hide events from players + ret.push_back(obj); + } + + return ret; +} +const CGObjectInstance * CGameInfoCallback::getTopObj (int3 pos) const +{ + return vstd::backOrNull(getVisitableObjs(pos)); +} + +std::vector < const CGObjectInstance * > CGameInfoCallback::getFlaggableObjects(int3 pos) const +{ + std::vector ret; + const TerrainTile *t = getTile(pos); + ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret); + for(const CGObjectInstance *obj : t->blockingObjects) + if(obj->tempOwner != PlayerColor::UNFLAGGABLE) + ret.push_back(obj); +// const std::vector < std::pair > & objs = CGI->mh->ttiles[pos.x][pos.y][pos.z].objects; +// for(size_t b=0; btempOwner!=254 && !((objs[b].first->defInfo->blockMap[pos.y - objs[b].first->pos.y + 5] >> (objs[b].first->pos.x - pos.x)) & 1)) +// ret.push_back(CGI->mh->ttiles[pos.x][pos.y][pos.z].objects[b].first); +// } + return ret; +} + +int3 CGameInfoCallback::getMapSize() const +{ + return int3(gs->map->width, gs->map->height, gs->map->twoLevel ? 2 : 1); +} + +std::vector CGameInfoCallback::getAvailableHeroes(const CGObjectInstance * townOrTavern) const +{ + ASSERT_IF_CALLED_WITH_PLAYER + std::vector ret; + //ERROR_RET_VAL_IF(!isOwnedOrVisited(townOrTavern), "Town or tavern must be owned or visited!", ret); + //TODO: town needs to be owned, advmap tavern needs to be visited; to be reimplemented when visit tracking is done + range::copy(gs->players[*player].availableHeroes, std::back_inserter(ret)); + vstd::erase_if(ret, [](const CGHeroInstance *h) { return h == nullptr; }); + return ret; +} + +const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const +{ + ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!isVisible(tile), verbose, tile << " is not visible!", nullptr); + + //boost::shared_lock lock(*gs->mx); + return &gs->map->getTile(tile); +} + +EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, BuildingID ID ) +{ + ERROR_RET_VAL_IF(!canGetFullInfo(t), "Town is not owned!", EBuildingState::TOWN_NOT_OWNED); + + if(!t->town->buildings.count(ID)) + return EBuildingState::BUILDING_ERROR; + + const CBuilding * building = t->town->buildings.at(ID); + + + if(t->hasBuilt(ID)) //already built + return EBuildingState::ALREADY_PRESENT; + + //can we build it? + if(vstd::contains(t->forbiddenBuildings, ID)) + return EBuildingState::FORBIDDEN; //forbidden + + if(ID == BuildingID::CAPITOL) + { + const PlayerState *ps = getPlayer(t->tempOwner); + if(ps) + { + for(const CGTownInstance *t : ps->towns) + { + if(t->hasBuilt(BuildingID::CAPITOL)) + { + return EBuildingState::HAVE_CAPITAL; //no more than one capitol + } + } + } + } + else if(ID == BuildingID::SHIPYARD) + { + const TerrainTile *tile = getTile(t->bestLocation(), false); + + if(!tile || tile->terType != ETerrainType::WATER) + return EBuildingState::NO_WATER; //lack of water + } + + auto buildTest = [&](const BuildingID & id) + { + return t->hasBuilt(id); + }; + + if(t->builded >= VLC->modh->settings.MAX_BUILDING_PER_TURN) + return EBuildingState::CANT_BUILD_TODAY; //building limit + + if (!building->requirements.test(buildTest)) + return EBuildingState::PREREQUIRES; + + if (building->upgrade != BuildingID::NONE && !t->hasBuilt(building->upgrade)) + return EBuildingState::MISSING_BASE; + + //checking resources + if(!building->resources.canBeAfforded(getPlayer(t->tempOwner)->resources)) + return EBuildingState::NO_RESOURCES; //lack of res + + return EBuildingState::ALLOWED; +} + +const CMapHeader * CGameInfoCallback::getMapHeader() const +{ + return gs->map; +} + +bool CGameInfoCallback::hasAccess(boost::optional playerId) const +{ + return !player || gs->getPlayerRelations( *playerId, *player ) != PlayerRelations::ENEMIES; +} + +EPlayerStatus::EStatus CGameInfoCallback::getPlayerStatus(PlayerColor player, bool verbose) const +{ + const PlayerState *ps = gs->getPlayer(player, verbose); + ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!ps, verbose, "No such player!", EPlayerStatus::WRONG); + + return ps->status; +} + +std::string CGameInfoCallback::getTavernGossip(const CGObjectInstance * townOrTavern) const +{ + return "GOSSIP TEST"; +} + +PlayerRelations::PlayerRelations CGameInfoCallback::getPlayerRelations( PlayerColor color1, PlayerColor color2 ) const +{ + return gs->getPlayerRelations(color1, color2); +} + +bool CGameInfoCallback::canGetFullInfo(const CGObjectInstance *obj) const +{ + return !obj || hasAccess(obj->tempOwner); +} + +int CGameInfoCallback::getHeroCount( PlayerColor player, bool includeGarrisoned ) const +{ + int ret = 0; + const PlayerState *p = gs->getPlayer(player); + ERROR_RET_VAL_IF(!p, "No such player!", -1); + + if(includeGarrisoned) + return p->heroes.size(); + else + for(auto & elem : p->heroes) + if(!elem->inTownGarrison) + ret++; + return ret; +} + +bool CGameInfoCallback::isOwnedOrVisited(const CGObjectInstance *obj) const +{ + if(canGetFullInfo(obj)) + return true; + + const TerrainTile *t = getTile(obj->visitablePos()); //get entrance tile + const CGObjectInstance *visitor = t->visitableObjects.back(); //visitong hero if present or the obejct itself at last + return visitor->ID == Obj::HERO && canGetFullInfo(visitor); //owned or allied hero is a visitor +} + +PlayerColor CGameInfoCallback::getCurrentPlayer() const +{ + return gs->currentPlayer; +} + +CGameInfoCallback::CGameInfoCallback() +{ +} + +CGameInfoCallback::CGameInfoCallback(CGameState *GS, boost::optional Player) +{ + gs = GS; + player = Player; +} + +const std::vector< std::vector< std::vector > > & CPlayerSpecificInfoCallback::getVisibilityMap() const +{ + //boost::shared_lock lock(*gs->mx); + return gs->getPlayerTeam(*player)->fogOfWarMap; +} + +int CPlayerSpecificInfoCallback::howManyTowns() const +{ + //boost::shared_lock lock(*gs->mx); + ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1); + return CGameInfoCallback::howManyTowns(*player); +} + +std::vector < const CGTownInstance *> CPlayerSpecificInfoCallback::getTownsInfo(bool onlyOur) const +{ + //boost::shared_lock lock(*gs->mx); + std::vector < const CGTownInstance *> ret = std::vector < const CGTownInstance *>(); + for(const auto & i : gs->players) + { + for(const auto & town : i.second.towns) + { + if (i.first==player || (isVisible(town, player) && !onlyOur)) + { + ret.push_back(town); + } + } + } // for ( std::map::iterator i=gs->players.begin() ; i!=gs->players.end();i++) + return ret; +} +std::vector < const CGHeroInstance *> CPlayerSpecificInfoCallback::getHeroesInfo(bool onlyOur) const +{ + //boost::shared_lock lock(*gs->mx); + std::vector < const CGHeroInstance *> ret; + for(auto hero : gs->map->heroesOnMap) + { + if( !player || (hero->tempOwner == *player) || + (isVisible(hero->getPosition(false), player) && !onlyOur) ) + { + ret.push_back(hero); + } + } + return ret; +} + +boost::optional CPlayerSpecificInfoCallback::getMyColor() const +{ + return player; +} + +int CPlayerSpecificInfoCallback::getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned) const +{ + if (hero->inTownGarrison && !includeGarrisoned) + return -1; + + size_t index = 0; + auto & heroes = gs->players[*player].heroes; + + for (auto & heroe : heroes) + { + if (includeGarrisoned || !(heroe)->inTownGarrison) + index++; + + if (heroe == hero) + return index; + } + return -1; +} + +int3 CPlayerSpecificInfoCallback::getGrailPos( double &outKnownRatio ) +{ + if (!player || CGObelisk::obeliskCount == 0) + { + outKnownRatio = 0.0; + } + else + { + outKnownRatio = static_cast(CGObelisk::visited[gs->getPlayerTeam(*player)->id]) / CGObelisk::obeliskCount; + } + return gs->map->grailPos; +} + +std::vector < const CGObjectInstance * > CPlayerSpecificInfoCallback::getMyObjects() const +{ + std::vector < const CGObjectInstance * > ret; + for(const CGObjectInstance * obj : gs->map->objects) + { + if(obj && obj->tempOwner == player) + ret.push_back(obj); + } + return ret; +} + +std::vector < const CGDwelling * > CPlayerSpecificInfoCallback::getMyDwellings() const +{ + ASSERT_IF_CALLED_WITH_PLAYER + std::vector < const CGDwelling * > ret; + for(CGDwelling * dw : gs->getPlayer(*player)->dwellings) + { + ret.push_back(dw); + } + return ret; +} + +std::vector CPlayerSpecificInfoCallback::getMyQuests() const +{ + std::vector ret; + for (auto quest : gs->getPlayer(*player)->quests) + { + ret.push_back (quest); + } + return ret; +} + +int CPlayerSpecificInfoCallback::howManyHeroes(bool includeGarrisoned) const +{ + //boost::shared_lock lock(*gs->mx); + ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1); + return getHeroCount(*player,includeGarrisoned); +} + +const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId, bool includeGarrisoned) const +{ + ASSERT_IF_CALLED_WITH_PLAYER + const PlayerState *p = getPlayer(*player); + ERROR_RET_VAL_IF(!p, "No player info", nullptr); + + if (!includeGarrisoned) + { + for(ui32 i = 0; i < p->heroes.size() && i<=serialId; i++) + if(p->heroes[i]->inTownGarrison) + serialId++; + } + ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->heroes.size(), "No player info", nullptr); + return p->heroes[serialId]; +} + +const CGTownInstance* CPlayerSpecificInfoCallback::getTownBySerial(int serialId) const +{ + ASSERT_IF_CALLED_WITH_PLAYER + const PlayerState *p = getPlayer(*player); + ERROR_RET_VAL_IF(!p, "No player info", nullptr); + ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->towns.size(), "No player info", nullptr); + return p->towns[serialId]; +} + +int CPlayerSpecificInfoCallback::getResourceAmount(Res::ERes type) const +{ + //boost::shared_lock lock(*gs->mx); + ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1); + return getResource(*player, type); +} + +TResources CPlayerSpecificInfoCallback::getResourceAmount() const +{ + //boost::shared_lock lock(*gs->mx); + ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", TResources()); + return gs->players[*player].resources; +} + +CGHeroInstance *CNonConstInfoCallback::getHero(ObjectInstanceID objid) +{ + return const_cast(CGameInfoCallback::getHero(objid)); +} + +CGTownInstance *CNonConstInfoCallback::getTown(ObjectInstanceID objid) +{ + return const_cast(CGameInfoCallback::getTown(objid)); +} + +TeamState *CNonConstInfoCallback::getTeam(TeamID teamID) +{ + return const_cast(CGameInfoCallback::getTeam(teamID)); +} + +TeamState *CNonConstInfoCallback::getPlayerTeam(PlayerColor color) +{ + return const_cast(CGameInfoCallback::getPlayerTeam(color)); +} + +PlayerState * CNonConstInfoCallback::getPlayer( PlayerColor color, bool verbose ) +{ + return const_cast(CGameInfoCallback::getPlayer(color, verbose)); +} + +CArtifactInstance * CNonConstInfoCallback::getArtInstance( ArtifactInstanceID aid ) +{ + return gs->map->artInstances[aid.num]; +} + +CGObjectInstance * CNonConstInfoCallback::getObjInstance( ObjectInstanceID oid ) +{ + return gs->map->objects[oid.num]; +} + +const TeamState * CGameInfoCallback::getTeam( TeamID teamID ) const +{ + ERROR_RET_VAL_IF(!vstd::contains(gs->teams, teamID), "Cannot find info for team " << teamID, nullptr); + const TeamState *ret = &gs->teams[teamID]; + ERROR_RET_VAL_IF(!!player && !vstd::contains(ret->players, *player), "Illegal attempt to access team data!", nullptr); + return ret; +} + +const TeamState * CGameInfoCallback::getPlayerTeam( PlayerColor color ) const +{ + const PlayerState * ps = getPlayer(color); + if (ps) + return getTeam(ps->team); + return nullptr; +} + +const CGHeroInstance* CGameInfoCallback::getHeroWithSubid( int subid ) const +{ + for(const CGHeroInstance *h : gs->map->heroesOnMap) + if(h->subID == subid) + return h; + + return nullptr; +} + +PlayerColor CGameInfoCallback::getLocalPlayer() const +{ + return getCurrentPlayer(); +} + +bool CGameInfoCallback::isInTheMap(const int3 &pos) const +{ + return gs->map->isInTheMap(pos); +} + +const CArtifactInstance * CGameInfoCallback::getArtInstance( ArtifactInstanceID aid ) const +{ + return gs->map->artInstances[aid.num]; +} + +const CGObjectInstance * CGameInfoCallback::getObjInstance( ObjectInstanceID oid ) const +{ + return gs->map->objects[oid.num]; +} + +void IGameEventRealizer::showInfoDialog( InfoWindow *iw ) +{ + commitPackage(iw); +} + +void IGameEventRealizer::showInfoDialog(const std::string &msg, PlayerColor player) +{ + InfoWindow iw; + iw.player = player; + iw.text << msg; + showInfoDialog(&iw); +} + +void IGameEventRealizer::setObjProperty(ObjectInstanceID objid, int prop, si64 val) +{ + SetObjectProperty sob; + sob.id = objid; + sob.what = prop; + sob.val = static_cast(val); + commitPackage(&sob); +} + diff --git a/lib/IGameCallback2.h b/lib/IGameCallback2.h new file mode 100644 index 000000000..e5d00819c --- /dev/null +++ b/lib/IGameCallback2.h @@ -0,0 +1,262 @@ +#pragma once + + +/*#include "BattleHex.h"*/ +#include "ResourceSet.h" +#include "int3.h" +/*#include "GameConstants.h"*/ +#include "CBattleCallback.h" //for CCallbackBase + +/* + * IGameCallback.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +struct SetMovePoints; +struct GiveBonus; +class CGObjectInstance; +/*class CGTownInstance; +class CGHeroInstance;*/ +struct BlockingDialog; +struct InfoWindow; +struct MetaString; +struct ShowInInfobox; +/*struct BattleResult; +struct Component; +class CGameState;*/ +struct PlayerSettings; +struct CPackForClient; +/*class CArtHandler; +class CArtifact; +class CArmedInstance;*/ +struct TerrainTile; +struct PlayerState; +class CTown; +struct StackLocation; +struct ArtifactLocation; +/*class CArtifactInstance;*/ +struct StartInfo; +struct InfoAboutTown; +struct UpgradeInfo; +struct SThievesGuildInfo; +/*struct CPath;*/ +class CGDwelling; +/*struct InfoAboutHero;*/ +class CMapHeader; +/*struct BattleAction; +class CStack; +class CSpell;*/ +class CCreatureSet; +/*class CCreature;*/ +class CStackBasicDescriptor; +struct TeamState; +struct QuestInfo; +/*class CGCreature; +class CSaveFile; +class CLoadFile; +*/ +class DLL_LINKAGE CGameInfoCallback : public virtual CCallbackBase +{ +protected: + CGameInfoCallback(); + CGameInfoCallback(CGameState *GS, boost::optional Player); + bool hasAccess(boost::optional playerId) const; + bool isVisible(int3 pos, boost::optional Player) const; + bool isVisible(const CGObjectInstance *obj, boost::optional Player) const; + bool isVisible(const CGObjectInstance *obj) const; + + bool canGetFullInfo(const CGObjectInstance *obj) const; //true we player owns obj or ally owns obj or privileged mode + bool isOwnedOrVisited(const CGObjectInstance *obj) const; + +public: + //various + int getDate(Date::EDateType mode=Date::DAY)const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month + const StartInfo * getStartInfo(bool beforeRandomization = false)const; + bool isAllowed(int type, int id); //type: 0 - spell; 1- artifact; 2 - secondary skill + + //player + const PlayerState * getPlayer(PlayerColor color, bool verbose = true) const; + int getResource(PlayerColor Player, Res::ERes which) const; + bool isVisible(int3 pos) const; + PlayerRelations::PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2) const; + void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj); //get thieves' guild info obtainable while visiting given object + EPlayerStatus::EStatus getPlayerStatus(PlayerColor player, bool verbose = true) const; //-1 if no such player + PlayerColor getCurrentPlayer() const; //player that currently makes move // TODO synchronous turns + virtual PlayerColor getLocalPlayer() const; //player that is currently owning given client (if not a client, then returns current player) + const PlayerSettings * getPlayerSettings(PlayerColor color) const; + + + //armed object + void getUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out)const; + + //hero + const CGHeroInstance* getHero(ObjectInstanceID objid) const; + const CGHeroInstance* getHeroWithSubid(int subid) const; + int getHeroCount(PlayerColor player, bool includeGarrisoned) const; + bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const; + int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //when called during battle, takes into account creatures' spell cost reduction + int estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const; //estimates damage of given spell; returns 0 if spell causes no dmg + const CGHeroInstance* getSelectedHero(PlayerColor player) const; //nullptr if no hero is selected + const CGHeroInstance* getSelectedHero() const; //of current (active) player + const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const; + const CGObjectInstance * getObjInstance(ObjectInstanceID oid) const; + + //objects + const CGObjectInstance* getObj(ObjectInstanceID objid, bool verbose = true) const; + std::vector getBlockingObjs(int3 pos)const; + std::vector getVisitableObjs(int3 pos, bool verbose = true)const; + std::vector getFlaggableObjects(int3 pos) const; + const CGObjectInstance * getTopObj (int3 pos) const; + std::vector getObjDescriptions(int3 pos)const; //returns descriptions of objects at pos in order from the lowest to the highest + PlayerColor getOwner(ObjectInstanceID heroID) const; + const CGObjectInstance *getObjByQuestIdentifier(int identifier) const; //nullptr if object has been removed (eg. killed) + + //map + int3 guardingCreaturePosition (int3 pos) const; + std::vector getGuardingCreatures (int3 pos) const; + const CMapHeader * getMapHeader()const; + int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map + const TerrainTile * getTile(int3 tile, bool verbose = true) const; + bool isInTheMap(const int3 &pos) const; + + //town + const CGTownInstance* getTown(ObjectInstanceID objid) const; + int howManyTowns(PlayerColor Player) const; + const CGTownInstance * getTownInfo(int val, bool mode)const; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial) + std::vector getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited + std::string getTavernGossip(const CGObjectInstance * townOrTavern) const; + EBuildingState::EBuildingState canBuildStructure(const CGTownInstance *t, BuildingID ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements + virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const; + const CTown *getNativeTown(PlayerColor color) const; + + //from gs + const TeamState *getTeam(TeamID teamID) const; + const TeamState *getPlayerTeam(PlayerColor color) const; + EBuildingState::EBuildingState canBuildStructure(const CGTownInstance *t, BuildingID ID) const;// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements +}; + + +class DLL_LINKAGE CPlayerSpecificInfoCallback : public CGameInfoCallback +{ +public: + int howManyTowns() const; + int howManyHeroes(bool includeGarrisoned = true) const; + int3 getGrailPos(double &outKnownRatio); + boost::optional getMyColor() const; + + std::vector getTownsInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible + int getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned=true) const; + const CGTownInstance* getTownBySerial(int serialId) const; // serial id is [0, number of towns) + const CGHeroInstance* getHeroBySerial(int serialId, bool includeGarrisoned=true) const; // serial id is [0, number of heroes) + std::vector getHeroesInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible + std::vector getMyDwellings() const; //returns all dwellings that belong to player + std::vector getMyObjects() const; //returns all objects flagged by belonging player + std::vector getMyQuests() const; + + int getResourceAmount(Res::ERes type) const; + TResources getResourceAmount() const; + const std::vector< std::vector< std::vector > > & getVisibilityMap()const; //returns visibility map + const PlayerSettings * getPlayerSettings(PlayerColor color) const; +}; + +class DLL_LINKAGE CPrivilagedInfoCallback : public CGameInfoCallback +{ +public: + CGameState * gameState(); + void getFreeTiles (std::vector &tiles) const; //used for random spawns + void getTilesInRange(std::unordered_set &tiles, int3 pos, int radious, boost::optional player = boost::optional(), int mode=0) const; //mode 1 - only unrevealed tiles; mode 0 - all, mode -1 - only unrevealed + void getAllTiles (std::unordered_set &tiles, boost::optional player = boost::optional(), int level=-1, int surface=0) const; //returns all tiles on given level (-1 - both levels, otherwise number of level); surface: 0 - land and water, 1 - only land, 2 - only water + void pickAllowedArtsSet(std::vector &out); //gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant + void getAllowedSpells(std::vector &out, ui16 level); + + template + void saveCommonState(Saver &out) const; //stores GS and VLC + + template + void loadCommonState(Loader &in); //loads GS and VLC +}; + +class DLL_LINKAGE CNonConstInfoCallback : public CPrivilagedInfoCallback +{ +public: + PlayerState *getPlayer(PlayerColor color, bool verbose = true); + TeamState *getTeam(TeamID teamID);//get team by team ID + TeamState *getPlayerTeam(PlayerColor color);// get team by player color + CGHeroInstance *getHero(ObjectInstanceID objid); + CGTownInstance *getTown(ObjectInstanceID objid); + TerrainTile * getTile(int3 pos); + CArtifactInstance * getArtInstance(ArtifactInstanceID aid); + CGObjectInstance * getObjInstance(ObjectInstanceID oid); +}; + +class DLL_LINKAGE IGameEventRealizer +{ +public: + virtual void commitPackage(CPackForClient *pack) = 0; + + virtual void showInfoDialog(InfoWindow *iw); + virtual void setObjProperty(ObjectInstanceID objid, int prop, si64 val); + + + virtual void showInfoDialog(const std::string &msg, PlayerColor player); +}; + +class DLL_LINKAGE IGameEventCallback : public IGameEventRealizer +{ +public: + virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set &spells)=0; + virtual bool removeObject(const CGObjectInstance * obj)=0; + virtual void setBlockVis(ObjectInstanceID objid, bool bv)=0; + virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0; + virtual void setHoverName(const CGObjectInstance * obj, MetaString * name)=0; + virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false)=0; + virtual void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false)=0; + virtual void showBlockingDialog(BlockingDialog *iw) =0; + virtual void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) =0; //cb will be called when player closes garrison window + virtual void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) =0; + virtual void giveResource(PlayerColor player, Res::ERes which, int val)=0; + virtual void giveResources(PlayerColor player, TResources resources)=0; + + virtual void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0; + virtual void takeCreatures(ObjectInstanceID objid, const std::vector &creatures) =0; + virtual bool changeStackCount(const StackLocation &sl, TQuantity count, bool absoluteValue = false) =0; + virtual bool changeStackType(const StackLocation &sl, CCreature *c) =0; + virtual bool insertNewStack(const StackLocation &sl, const CCreature *c, TQuantity count = -1) =0; //count -1 => moves whole stack + virtual bool eraseStack(const StackLocation &sl, bool forceRemoval = false) =0; + virtual bool swapStacks(const StackLocation &sl1, const StackLocation &sl2) =0; + virtual bool addToSlot(const StackLocation &sl, const CCreature *c, TQuantity count) =0; //makes new stack or increases count of already existing + virtual void tryJoiningArmy(const CArmedInstance *src, const CArmedInstance *dst, bool removeObjWhenFinished, bool allowMerging) =0; //merges army from src do dst or opens a garrison window + virtual bool moveStack(const StackLocation &src, const StackLocation &dst, TQuantity count) = 0; + + virtual void removeAfterVisit(const CGObjectInstance *object) = 0; //object will be destroyed when interaction is over. Do not call when interaction is not ongoing! + + virtual void giveHeroNewArtifact(const CGHeroInstance *h, const CArtifact *artType, ArtifactPosition pos) = 0; + virtual void giveHeroArtifact(const CGHeroInstance *h, const CArtifactInstance *a, ArtifactPosition pos) = 0; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack + virtual void putArtifact(const ArtifactLocation &al, const CArtifactInstance *a) = 0; + virtual void removeArtifact(const ArtifactLocation &al) = 0; + virtual bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) = 0; + virtual void synchronizeArtifactHandlerLists() = 0; + + virtual void showCompInfo(ShowInInfobox * comp)=0; + virtual void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0; + virtual void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0; + virtual void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = nullptr)=0; //use hero=nullptr for no hero + virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank = false)=0; //if any of armies is hero, hero will be used + virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle + virtual void setAmount(ObjectInstanceID objid, ui32 val)=0; + virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL)=0; + virtual void giveHeroBonus(GiveBonus * bonus)=0; + virtual void setMovePoints(SetMovePoints * smp)=0; + virtual void setManaPoints(ObjectInstanceID hid, int val)=0; + virtual void giveHero(ObjectInstanceID id, PlayerColor player)=0; + virtual void changeObjPos(ObjectInstanceID objid, int3 newPos, ui8 flags)=0; + virtual void sendAndApply(CPackForClient * info)=0; + virtual void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)=0; //when two heroes meet on adventure map + virtual void addQuest(int player, QuestInfo & quest){}; +}; + diff --git a/lib/filesystem/CFileInputStream.cpp b/lib/filesystem/CFileInputStream.cpp index 8b9d1ce47..66b70e11d 100644 --- a/lib/filesystem/CFileInputStream.cpp +++ b/lib/filesystem/CFileInputStream.cpp @@ -55,7 +55,7 @@ si64 CFileInputStream::seek(si64 position) si64 CFileInputStream::tell() { - return fileStream.tellg() - dataStart; + return static_cast(fileStream.tellg()) - dataStart; } si64 CFileInputStream::skip(si64 delta) diff --git a/scripting/erm/ERMInterpreter.cpp b/scripting/erm/ERMInterpreter.cpp index bbd67507a..f5a2c9fdd 100644 --- a/scripting/erm/ERMInterpreter.cpp +++ b/scripting/erm/ERMInterpreter.cpp @@ -547,6 +547,7 @@ bool ERMInterpreter::isATrigger( const ERM::TLine & line ) break; } assert(0); + return false; } ERM::EVOtions ERMInterpreter::getExpType( const ERM::TVOption & opt )