1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Split map object visit from town building visit. Removes side effects

from building visit
This commit is contained in:
Ivan Savenko 2024-09-04 14:54:09 +00:00
parent 81af66d35b
commit d34b4a141e
5 changed files with 69 additions and 34 deletions

View File

@ -179,7 +179,6 @@
"period" : 7, "period" : 7,
"visitors" : true "visitors" : true
}, },
"visitMode" : "hero", // Should be 'once' to match (somewhat buggy) H3 logic
"visitMode" : "once", "visitMode" : "once",
"rewards" : [ "rewards" : [
{ {

View File

@ -2178,8 +2178,7 @@ bool CGameHandler::visitTownBuilding(ObjectInstanceID tid, BuildingID bid)
if (hero && t->town->buildings.at(bid)->manualHeroVisit) if (hero && t->town->buildings.at(bid)->manualHeroVisit)
{ {
// FIXME: query might produce unintended side effects, double check auto visitQuery = std::make_shared<TownBuildingVisitQuery>(this, t, hero, bid);
auto visitQuery = std::make_shared<CObjectVisitQuery>(this, t, hero);
queries->addQuery(visitQuery); queries->addQuery(visitQuery);
building->onHeroVisit(hero); building->onHeroVisit(hero);
queries->popIfTop(visitQuery); queries->popIfTop(visitQuery);
@ -3208,7 +3207,7 @@ void CGameHandler::objectVisited(const CGObjectInstance * obj, const CGHeroInsta
throw std::runtime_error("Can not visit object that is being visited"); throw std::runtime_error("Can not visit object that is being visited");
} }
std::shared_ptr<CObjectVisitQuery> visitQuery; std::shared_ptr<MapObjectVisitQuery> visitQuery;
auto startVisit = [&](ObjectVisitStarted & event) auto startVisit = [&](ObjectVisitStarted & event)
{ {
@ -3227,7 +3226,7 @@ void CGameHandler::objectVisited(const CGObjectInstance * obj, const CGHeroInsta
visitedObject = visitedTown; visitedObject = visitedTown;
} }
} }
visitQuery = std::make_shared<CObjectVisitQuery>(this, visitedObject, h); visitQuery = std::make_shared<MapObjectVisitQuery>(this, visitedObject, h);
queries->addQuery(visitQuery); //TODO real visit pos queries->addQuery(visitQuery); //TODO real visit pos
HeroVisit hv; HeroVisit hv;
@ -3246,11 +3245,11 @@ void CGameHandler::objectVisited(const CGObjectInstance * obj, const CGHeroInsta
queries->popIfTop(visitQuery); //visit ends here if no queries were created queries->popIfTop(visitQuery); //visit ends here if no queries were created
} }
void CGameHandler::objectVisitEnded(const CObjectVisitQuery & query) void CGameHandler::objectVisitEnded(const CGHeroInstance *h, PlayerColor player)
{ {
using events::ObjectVisitEnded; using events::ObjectVisitEnded;
logGlobal->debug("%s visit ends.\n", query.visitingHero->nodeName()); logGlobal->debug("%s visit ends.\n", h->nodeName());
auto endVisit = [&](ObjectVisitEnded & event) auto endVisit = [&](ObjectVisitEnded & event)
{ {
@ -3263,7 +3262,7 @@ void CGameHandler::objectVisitEnded(const CObjectVisitQuery & query)
//TODO: ObjectVisitEnded should also have id of visited object, //TODO: ObjectVisitEnded should also have id of visited object,
//but this requires object being deleted only by `removeAfterVisit()` but not `removeObject()` //but this requires object being deleted only by `removeAfterVisit()` but not `removeObject()`
ObjectVisitEnded::defaultExecute(serverEventBus.get(), endVisit, query.players.front(), query.visitingHero->id); ObjectVisitEnded::defaultExecute(serverEventBus.get(), endVisit, player, h->id);
} }
bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID) bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID)
@ -3874,7 +3873,7 @@ void CGameHandler::removeAfterVisit(const CGObjectInstance *object)
//If the object is being visited, there must be a matching query //If the object is being visited, there must be a matching query
for (const auto &query : queries->allQueries()) for (const auto &query : queries->allQueries())
{ {
if (auto someVistQuery = std::dynamic_pointer_cast<CObjectVisitQuery>(query)) if (auto someVistQuery = std::dynamic_pointer_cast<MapObjectVisitQuery>(query))
{ {
if (someVistQuery->visitedObject == object) if (someVistQuery->visitedObject == object)
{ {
@ -3938,7 +3937,7 @@ const CGHeroInstance * CGameHandler::getVisitingHero(const CGObjectInstance *obj
for(const auto & query : queries->allQueries()) for(const auto & query : queries->allQueries())
{ {
auto visit = std::dynamic_pointer_cast<const CObjectVisitQuery>(query); auto visit = std::dynamic_pointer_cast<const VisitQuery>(query);
if (visit && visit->visitedObject == obj) if (visit && visit->visitedObject == obj)
return visit->visitingHero; return visit->visitingHero;
} }
@ -3951,7 +3950,7 @@ const CGObjectInstance * CGameHandler::getVisitingObject(const CGHeroInstance *h
for(const auto & query : queries->allQueries()) for(const auto & query : queries->allQueries())
{ {
auto visit = std::dynamic_pointer_cast<const CObjectVisitQuery>(query); auto visit = std::dynamic_pointer_cast<const VisitQuery>(query);
if (visit && visit->visitingHero == hero) if (visit && visit->visitingHero == hero)
return visit->visitedObject; return visit->visitedObject;
} }
@ -3968,7 +3967,7 @@ bool CGameHandler::isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, con
// visitation query is covered by other query that must be answered first // visitation query is covered by other query that must be answered first
if (auto topQuery = queries->topQuery(hero->getOwner())) if (auto topQuery = queries->topQuery(hero->getOwner()))
if (auto visit = std::dynamic_pointer_cast<const CObjectVisitQuery>(topQuery)) if (auto visit = std::dynamic_pointer_cast<const VisitQuery>(topQuery))
return !(visit->visitedObject == obj && visit->visitingHero == hero); return !(visit->visitedObject == obj && visit->visitingHero == hero);
return true; return true;

View File

@ -232,7 +232,7 @@ public:
bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h ); void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
void objectVisitEnded(const CObjectVisitQuery &query); void objectVisitEnded(const CGHeroInstance *h, PlayerColor player);
bool dig(const CGHeroInstance *h); bool dig(const CGHeroInstance *h);
void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging); void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging);

View File

@ -10,34 +10,26 @@
#include "StdInc.h" #include "StdInc.h"
#include "VisitQueries.h" #include "VisitQueries.h"
#include "QueriesProcessor.h"
#include "../CGameHandler.h"
#include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h"
#include "../CGameHandler.h"
#include "QueriesProcessor.h"
CObjectVisitQuery::CObjectVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero): VisitQuery::VisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero)
CQuery(owner), visitedObject(Obj), visitingHero(Hero), removeObjectAfterVisit(false) : CQuery(owner)
, visitedObject(Obj)
, visitingHero(Hero)
{ {
addPlayer(Hero->tempOwner); addPlayer(Hero->tempOwner);
} }
bool CObjectVisitQuery::blocksPack(const CPack *pack) const bool VisitQuery::blocksPack(const CPack * pack) const
{ {
//During the visit itself ALL actions are blocked. //During the visit itself ALL actions are blocked.
//(However, the visit may trigger a query above that'll pass some.) //(However, the visit may trigger a query above that'll pass some.)
return true; return true;
} }
void CObjectVisitQuery::onRemoval(PlayerColor color) void VisitQuery::onExposure(QueryPtr topQuery)
{
gh->objectVisitEnded(*this);
//TODO or should it be destructor?
//Can object visit affect 2 players and what would be desired behavior?
if(removeObjectAfterVisit)
gh->removeObject(visitedObject, color);
}
void CObjectVisitQuery::onExposure(QueryPtr topQuery)
{ {
//Object may have been removed and deleted. //Object may have been removed and deleted.
if(gh->isValidObject(visitedObject)) if(gh->isValidObject(visitedObject))
@ -45,3 +37,30 @@ void CObjectVisitQuery::onExposure(QueryPtr topQuery)
owner->popIfTop(*this); owner->popIfTop(*this);
} }
MapObjectVisitQuery::MapObjectVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero)
: VisitQuery(owner, Obj, Hero)
, removeObjectAfterVisit(false)
{
}
void MapObjectVisitQuery::onRemoval(PlayerColor color)
{
gh->objectVisitEnded(visitingHero, players.front());
//TODO or should it be destructor?
//Can object visit affect 2 players and what would be desired behavior?
if(removeObjectAfterVisit)
gh->removeObject(visitedObject, color);
}
TownBuildingVisitQuery::TownBuildingVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero, BuildingID buildingToVisit)
: VisitQuery(owner, Obj, Hero)
, visitedBuilding(buildingToVisit)
{
}
void TownBuildingVisitQuery::onRemoval(PlayerColor color)
{
}

View File

@ -13,17 +13,35 @@
//Created when hero visits object. //Created when hero visits object.
//Removed when query above is resolved (or immediately after visit if no queries were created) //Removed when query above is resolved (or immediately after visit if no queries were created)
class CObjectVisitQuery : public CQuery class VisitQuery : public CQuery
{ {
protected:
VisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero);
public: public:
const CGObjectInstance *visitedObject; const CGObjectInstance *visitedObject;
const CGHeroInstance *visitingHero; const CGHeroInstance *visitingHero;
bool blocksPack(const CPack *pack) const final;
void onExposure(QueryPtr topQuery) final;
};
class MapObjectVisitQuery final : public VisitQuery
{
public:
bool removeObjectAfterVisit; bool removeObjectAfterVisit;
CObjectVisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero); MapObjectVisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero);
bool blocksPack(const CPack *pack) const override; void onRemoval(PlayerColor color) final;
void onRemoval(PlayerColor color) override; };
void onExposure(QueryPtr topQuery) override;
class TownBuildingVisitQuery final : public VisitQuery
{
public:
BuildingID visitedBuilding;
TownBuildingVisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero, BuildingID buildingToVisit);
void onRemoval(PlayerColor color) final;
}; };