1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-30 23:18:08 +02:00

Added per-team tracking of scouted state of an object

This commit is contained in:
Ivan Savenko 2024-08-30 15:24:13 +00:00
parent 785036836c
commit cb5df096c1
6 changed files with 47 additions and 59 deletions

View File

@ -153,6 +153,8 @@ public:
//TODO: boost::array, bool if possible
boost::multi_array<ui8, 3> fogOfWarMap; //[z][x][y] true - visible, false - hidden
std::set<ObjectInstanceID> scoutedObjects;
TeamState();
template <typename Handler> void serialize(Handler &h)
@ -173,6 +175,9 @@ public:
h & fogOfWarMap;
h & static_cast<CBonusSystemNode&>(*this);
if (h.version >= Handler::Version::TEAM_STATE_SCOUTED_OBJECTS)
h & scoutedObjects;
}
};

View File

@ -137,7 +137,7 @@ bool CBank::wasVisited (PlayerColor player) const
void CBank::onHeroVisit(const CGHeroInstance * h) const
{
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_TEAM, id, h->id);
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_PLAYER, id, h->id);
cb->sendAndApply(&cov);
if(!bankConfig && (ID.toEnum() == Obj::CREATURE_BANK || ID.toEnum() == Obj::DRAGON_UTOPIA))

View File

@ -108,24 +108,30 @@ bool CRewardableObject::guardedPresently() const
return stacksCount() > 0;
}
void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const
void CRewardableObject::onHeroVisit(const CGHeroInstance *hero) const
{
if(!wasScouted(hero->getOwner()))
{
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_SCOUTED, id, hero->id);
cb->sendAndApply(&cov);
}
if (guardedPresently())
{
auto guardedIndexes = getAvailableRewards(h, Rewardable::EEventType::EVENT_GUARDED);
auto guardedIndexes = getAvailableRewards(hero, Rewardable::EEventType::EVENT_GUARDED);
auto guardedReward = configuration.info.at(guardedIndexes.at(0));
// ask player to confirm attack
BlockingDialog bd(true, false);
bd.player = h->getOwner();
bd.player = hero->getOwner();
bd.text = guardedReward.message;
bd.components = getPopupComponents(h->getOwner());
bd.components = getPopupComponents(hero->getOwner());
cb->showBlockingDialog(&bd);
}
else
{
doHeroVisit(h);
doHeroVisit(hero);
}
}
@ -192,7 +198,7 @@ void CRewardableObject::doHeroVisit(const CGHeroInstance *h) const
if(!objectRemovalPossible && getAvailableRewards(h, Rewardable::EEventType::EVENT_FIRST_VISIT).empty())
{
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_TEAM, id, h->id);
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_PLAYER, id, h->id);
cb->sendAndApply(&cov);
}
}
@ -202,7 +208,7 @@ void CRewardableObject::doHeroVisit(const CGHeroInstance *h) const
if (!wasVisited(h->getOwner()))
{
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_TEAM, id, h->id);
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_PLAYER, id, h->id);
cb->sendAndApply(&cov);
}
@ -236,27 +242,6 @@ void CRewardableObject::blockingDialogAnswered(const CGHeroInstance * hero, int3
}
else
{
if(answer == 0)
{
switch(configuration.visitMode)
{
case Rewardable::VISIT_UNLIMITED:
case Rewardable::VISIT_BONUS:
case Rewardable::VISIT_HERO:
case Rewardable::VISIT_LIMITER:
{
// workaround for object with refusable reward not getting marked as visited
// TODO: better solution that would also work for player-visitable objects
if(!wasScouted(hero->getOwner()))
{
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_TEAM, id, hero->id);
cb->sendAndApply(&cov);
}
}
}
return; // player refused
}
if(answer > 0 && answer - 1 < configuration.info.size())
{
auto list = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT);
@ -274,7 +259,7 @@ void CRewardableObject::markAsVisited(const CGHeroInstance * hero) const
{
cb->setObjPropertyValue(id, ObjProperty::REWARD_CLEARED, true);
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD, id, hero->id);
ChangeObjectVisitors cov(ChangeObjectVisitors::VISITOR_ADD_HERO, id, hero->id);
cb->sendAndApply(&cov);
}
@ -330,7 +315,7 @@ bool CRewardableObject::wasVisited(PlayerColor player) const
bool CRewardableObject::wasScouted(PlayerColor player) const
{
return vstd::contains(cb->getPlayerState(player)->visitedObjects, ObjectInstanceID(id));
return vstd::contains(cb->getPlayerTeam(player)->scoutedObjects, ObjectInstanceID(id));
}
bool CRewardableObject::wasVisited(const CGHeroInstance * h) const
@ -418,9 +403,6 @@ std::vector<Component> CRewardableObject::getPopupComponentsImpl(PlayerColor pla
if (!wasScouted(player))
return {};
if (!configuration.showScoutedPreview)
return {};
if (guardedPresently())
{
if (!VLC->settings()->getBoolean(EGameSettings::BANKS_SHOW_GUARDS_COMPOSITION))
@ -442,6 +424,9 @@ std::vector<Component> CRewardableObject::getPopupComponentsImpl(PlayerColor pla
}
else
{
if (!configuration.showScoutedPreview)
return {};
auto rewardIndices = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT);
if (rewardIndices.empty() && !configuration.info.empty())
{

View File

@ -1035,32 +1035,32 @@ void ChangeObjPos::applyGs(CGameState *gs)
void ChangeObjectVisitors::applyGs(CGameState *gs)
{
switch (mode) {
case VISITOR_ADD:
case VISITOR_ADD_HERO:
gs->getPlayerTeam(gs->getHero(hero)->tempOwner)->scoutedObjects.insert(object);
gs->getHero(hero)->visitedObjects.insert(object);
gs->getPlayerState(gs->getHero(hero)->tempOwner)->visitedObjects.insert(object);
break;
case VISITOR_ADD_TEAM:
{
TeamState *ts = gs->getPlayerTeam(gs->getHero(hero)->tempOwner);
for(const auto & color : ts->players)
{
gs->getPlayerState(color)->visitedObjects.insert(object);
}
}
case VISITOR_ADD_PLAYER:
gs->getPlayerTeam(gs->getHero(hero)->tempOwner)->scoutedObjects.insert(object);
for(const auto & color : gs->getPlayerTeam(gs->getHero(hero)->tempOwner)->players)
gs->getPlayerState(color)->visitedObjects.insert(object);
break;
case VISITOR_CLEAR:
// remove visit info from all heroes, including those that are not present on map
for (CGHeroInstance * hero : gs->map->allHeroes)
{
if (hero)
{
hero->visitedObjects.erase(object); // remove visit info from all heroes, including those that are not present on map
}
}
hero->visitedObjects.erase(object);
for(auto &elem : gs->players)
{
elem.second.visitedObjects.erase(object);
}
for(auto &elem : gs->teams)
elem.second.scoutedObjects.erase(object);
break;
case VISITOR_SCOUTED:
gs->getPlayerTeam(gs->getHero(hero)->tempOwner)->scoutedObjects.insert(object);
break;
case VISITOR_GLOBAL:
@ -1069,9 +1069,6 @@ void ChangeObjectVisitors::applyGs(CGameState *gs)
gs->getPlayerState(gs->getHero(hero)->tempOwner)->visitedObjectsGlobal.insert({objectPtr->ID, objectPtr->subID});
break;
}
case VISITOR_REMOVE:
gs->getHero(hero)->visitedObjects.erase(object);
break;
}
}

View File

@ -1216,11 +1216,11 @@ struct DLL_LINKAGE ChangeObjectVisitors : public CPackForClient
{
enum VisitMode
{
VISITOR_ADD, // mark hero as one that have visited this object
VISITOR_ADD_TEAM, // mark team as one that have visited this object
VISITOR_GLOBAL, // mark player as one that have visited object of this type
VISITOR_REMOVE, // unmark visitor, reversed to ADD
VISITOR_CLEAR // clear all visitors from this object (object reset)
VISITOR_ADD_HERO, // mark hero as one that have visited this object
VISITOR_ADD_PLAYER, // mark player as one that have visited this object instance
VISITOR_GLOBAL, // mark player as one that have visited object of this type
VISITOR_SCOUTED, // marks targeted team as having scouted this object
VISITOR_CLEAR, // clear all visitors from this object (object reset)
};
VisitMode mode = VISITOR_CLEAR; // uses VisitMode enum
ObjectInstanceID object;

View File

@ -59,6 +59,7 @@ enum class ESerializationVersion : int32_t
CHRONICLES_SUPPORT, // 860 - support for heroes chronicles
PER_MAP_GAME_SETTINGS, // 861 - game settings are now stored per-map
CAMPAIGN_OUTRO_SUPPORT, // 862 - support for campaign outro video
REWARDABLE_BANKS, // 863 - team state contains list of scouted objects, coast visitable rewardable objects
CURRENT = CAMPAIGN_OUTRO_SUPPORT
CURRENT = REWARDABLE_BANKS
};