diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index ef732ccbe..95e5090d4 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -746,6 +746,7 @@ void CGameState::init(StartInfo * si, bool allowSavingRandomMap) buildBonusSystemTree(); initVisitingAndGarrisonedHeroes(); initFogOfWar(); + initSightMap(); // Explicitly initialize static variables for(auto & elem : players) @@ -1512,6 +1513,55 @@ void CGameState::giveCampaignBonusToHero(CGHeroInstance * hero) } } +void CGameState::removeSightnObj(const CGObjectInstance * obj) +{ + addSightObj(obj, false); +} + +void CGameState::addSightObj(const CGObjectInstance * obj, bool add) +{ + if(!vstd::contains(players, obj->tempOwner)) + return; + + auto p = getPlayer(obj->tempOwner); + if(p->status != EPlayerStatus::INGAME) + return; + + addSightObj(p->team, obj, add); +} + +void CGameState::addSightObj(TeamID team, const CGObjectInstance * obj, bool add) +{ + auto ts = getTeam(team); + std::unordered_set tiles; + getTilesInRange(tiles, obj->getSightCenter(), obj->getSightRadius()); + for(int3 t : tiles) + { + if(add) + { + if(ts->fogOfWarMap[t.x][t.y][t.z] == 0) + ts->fogOfWarMap[t.x][t.y][t.z] = 2; + else + ts->fogOfWarMap[t.x][t.y][t.z]++; + } + else + { + ts->fogOfWarMap[t.x][t.y][t.z]--; + } + } +} + +void CGameState::initSightMap() +{ + for(CGObjectInstance * obj : map->objects) + { + if(!obj) + continue; //not a flagged object + + addSightObj(obj); + } +} + void CGameState::initFogOfWar() { logGlobal->debug("\tFog of war"); //FIXME: should be initialized after all bonuses are set @@ -1529,18 +1579,6 @@ void CGameState::initFogOfWar() for(int h=0; hheight; ++h) for(int v = 0; v < (map->twoLevel ? 2 : 1); ++v) elem.second.fogOfWarMap[g][h][v] = 0; - - for(CGObjectInstance *obj : map->objects) - { - if(!obj || !vstd::contains(elem.second.players, obj->tempOwner)) continue; //not a flagged object - - std::unordered_set tiles; - getTilesInRange(tiles, obj->getSightCenter(), obj->getSightRadius(), obj->tempOwner, 1); - for(int3 tile : tiles) - { - elem.second.fogOfWarMap[tile.x][tile.y][tile.z] = 1; - } - } } } diff --git a/lib/CGameState.h b/lib/CGameState.h index cc75984ce..556e1334f 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -178,6 +178,10 @@ public: std::vector guardingCreatures (int3 pos) const; void updateRumor(); + void initSightMap(); + void addSightObj(const CGObjectInstance * obj, bool add = true); + void removeSightnObj(const CGObjectInstance * obj); + // ----- victory, loss condition checks ----- EVictoryLossCheckResult checkForVictoryAndLoss(PlayerColor player) const; @@ -268,6 +272,7 @@ private: void initStartingResources(); void initHeroes(); void giveCampaignBonusToHero(CGHeroInstance * hero); + void addSightObj(TeamID team, const CGObjectInstance * obj, bool add = true); void initFogOfWar(); void initStartingBonus(); void initTowns(); diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index 584ade005..6f0eb8615 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -78,8 +78,8 @@ void CPrivilagedInfoCallback::getTilesInRange(std::unordered_setfogOfWarMap[xd][yd][pos.z]==0) - || (mode == -1 && team->fogOfWarMap[xd][yd][pos.z]==1) + || (mode == 1 && team->fogOfWarMap[xd][yd][pos.z] == 0) + || (mode == -1 && team->fogOfWarMap[xd][yd][pos.z] > 0) ) tiles.insert(int3(xd,yd,pos.z)); } diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 85a187bdf..68c0daafe 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -220,29 +220,13 @@ DLL_LINKAGE void FoWChange::applyGs(CGameState *gs) { TeamState * team = gs->getPlayerTeam(player); for(int3 t : tiles) - team->fogOfWarMap[t.x][t.y][t.z] = mode; - if (mode == 0) //do not hide too much { - std::unordered_set tilesRevealed; - for (auto & elem : gs->map->objects) - { - const CGObjectInstance *o = elem; - if (o) - { - switch(o->ID) - { - case Obj::HERO: - case Obj::MINE: - case Obj::TOWN: - case Obj::ABANDONED_MINE: - if(vstd::contains(team->players, o->tempOwner)) //check owned observators - gs->getTilesInRange(tilesRevealed, o->getSightCenter(), o->getSightRadius(), o->tempOwner, 1); - break; - } - } - } - for(int3 t : tilesRevealed) //probably not the most optimal solution ever - team->fogOfWarMap[t.x][t.y][t.z] = 1; + if(mode == 0 && team->fogOfWarMap[t.x][t.y][t.z] > 1) + continue; + else if(mode == 1 && team->fogOfWarMap[t.x][t.y][t.z]) + continue; + + team->fogOfWarMap[t.x][t.y][t.z] = mode; } } @@ -309,9 +293,11 @@ DLL_LINKAGE void ChangeObjPos::applyGs(CGameState *gs) logNetwork->error("Wrong ChangeObjPos: object %d doesn't exist!", objid.getNum()); return; } + gs->removeSightnObj(obj); gs->map->removeBlockVisTiles(obj); obj->pos = nPos; gs->map->addBlockVisTiles(obj); + gs->addSightObj(obj); } DLL_LINKAGE void ChangeObjectVisitors::applyGs(CGameState *gs) @@ -386,6 +372,7 @@ DLL_LINKAGE void RemoveObject::applyGs(CGameState *gs) CGObjectInstance *obj = gs->getObjInstance(id); logGlobal->debug("removing object id=%d; address=%x; name=%s", id, (intptr_t)obj, obj->getObjectName()); //unblock tiles + gs->removeSightnObj(obj); gs->map->removeBlockVisTiles(obj); if(obj->ID==Obj::HERO) @@ -516,6 +503,8 @@ void TryMoveHero::applyGs(CGameState *gs) logGlobal->error("Attempt ot move unavailable hero %d", id.getNum()); return; } + if(start != end) + gs->removeSightnObj(h); h->movement = movePoints; @@ -547,17 +536,19 @@ void TryMoveHero::applyGs(CGameState *gs) h->boat = nullptr; } - if(start!=end && (result == SUCCESS || result == TELEPORTATION || result == EMBARK || result == DISEMBARK)) + if(start != end) { - gs->map->removeBlockVisTiles(h); - h->pos = end; - if(CGBoat *b = const_cast(h->boat)) - b->pos = end; - gs->map->addBlockVisTiles(h); - } + if(result == SUCCESS || result == TELEPORTATION || result == EMBARK || result == DISEMBARK) + { + gs->map->removeBlockVisTiles(h); + h->pos = end; + if(CGBoat *b = const_cast(h->boat)) + b->pos = end; + gs->map->addBlockVisTiles(h); + } - for(int3 t : fowRevealed) - gs->getPlayerTeam(h->getOwner())->fogOfWarMap[t.x][t.y][t.z] = 1; + gs->addSightObj(h); + } } DLL_LINKAGE void NewStructures::applyGs(CGameState *gs) @@ -571,7 +562,9 @@ DLL_LINKAGE void NewStructures::applyGs(CGameState *gs) t->updateAppearance(); } t->builded = builded; + gs->removeSightnObj(t); t->recreateBuildingsBonuses(); + gs->addSightObj(t); } DLL_LINKAGE void RazeStructures::applyGs(CGameState *gs) { @@ -583,7 +576,9 @@ DLL_LINKAGE void RazeStructures::applyGs(CGameState *gs) t->updateAppearance(); } t->destroyed = destroyed; //yeaha + gs->removeSightnObj(t); t->recreateBuildingsBonuses(); + gs->addSightObj(t); } DLL_LINKAGE void SetAvailableCreatures::applyGs(CGameState *gs) @@ -661,6 +656,7 @@ DLL_LINKAGE void HeroRecruited::applyGs(CGameState *gs) { t->setVisitingHero(h); } + gs->addSightObj(h); } DLL_LINKAGE void GiveHero::applyGs(CGameState *gs) @@ -720,6 +716,7 @@ DLL_LINKAGE void NewObject::applyGs(CGameState *gs) gs->map->addBlockVisTiles(o); o->initObj(gs->getRandomGenerator()); gs->map->calculateGuardingGreaturePositions(); + gs->addSightObj(o); logGlobal->debug("Added object id=%d; address=%x; name=%s", id, (intptr_t)o, o->getObjectName()); } @@ -1166,29 +1163,40 @@ DLL_LINKAGE void SetObjectProperty::applyGs(CGameState *gs) return; } - CArmedInstance *cai = dynamic_cast(obj); - if(what == ObjProperty::OWNER && cai) + if(what == ObjProperty::OWNER) { - if(obj->ID == Obj::TOWN) + CArmedInstance *cai = dynamic_cast(obj); + if(cai) { - CGTownInstance *t = static_cast(obj); - if(t->tempOwner < PlayerColor::PLAYER_LIMIT) - gs->getPlayer(t->tempOwner)->towns -= t; - if(val < PlayerColor::PLAYER_LIMIT_I) + if(obj->ID == Obj::TOWN) { - PlayerState * p = gs->getPlayer(PlayerColor(val)); - p->towns.push_back(t); + CGTownInstance *t = static_cast(obj); + if(t->tempOwner < PlayerColor::PLAYER_LIMIT) + gs->getPlayer(t->tempOwner)->towns -= t; + if(val < PlayerColor::PLAYER_LIMIT_I) + { + PlayerState * p = gs->getPlayer(PlayerColor(val)); + p->towns.push_back(t); - //reset counter before NewTurn to avoid no town message if game loaded at turn when one already captured - if(p->daysWithoutCastle) - p->daysWithoutCastle = boost::none; + //reset counter before NewTurn to avoid no town message if game loaded at turn when one already captured + if(p->daysWithoutCastle) + p->daysWithoutCastle = boost::none; + } } - } - CBonusSystemNode *nodeToMove = cai->whatShouldBeAttached(); - nodeToMove->detachFrom(cai->whereShouldBeAttached(gs)); - obj->setProperty(what,val); - nodeToMove->attachTo(cai->whereShouldBeAttached(gs)); + gs->removeSightnObj(obj); + CBonusSystemNode *nodeToMove = cai->whatShouldBeAttached(); + nodeToMove->detachFrom(cai->whereShouldBeAttached(gs)); + obj->setProperty(what,val); + nodeToMove->attachTo(cai->whereShouldBeAttached(gs)); + gs->addSightObj(obj); + } + else + { + gs->removeSightnObj(obj); + obj->setProperty(what, val); + gs->addSightObj(obj); + } } else //not an armed instance { diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index d34639483..a9cc44df7 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -6291,21 +6291,6 @@ void CGameHandler::changeFogOfWar(int3 center, ui32 radius, PlayerColor player, { std::unordered_set tiles; getTilesInRange(tiles, center, radius, player, hide? -1 : 1); - if (hide) - { - std::unordered_set observedTiles; //do not hide tiles observed by heroes. May lead to disastrous AI problems - auto p = getPlayer(player); - for (auto h : p->heroes) - { - getTilesInRange(observedTiles, h->getSightCenter(), h->getSightRadius(), h->tempOwner, -1); - } - for (auto t : p->towns) - { - getTilesInRange(observedTiles, t->getSightCenter(), t->getSightRadius(), t->tempOwner, -1); - } - for (auto tile : observedTiles) - vstd::erase_if_present (tiles, tile); - } changeFogOfWar(tiles, player, hide); }