1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Added Query to track visit duration for Taverns and Markets

This commit is contained in:
Ivan Savenko 2023-09-28 01:17:05 +03:00
parent e322d0a084
commit 898733eed7
27 changed files with 230 additions and 113 deletions

View File

@ -154,10 +154,13 @@ void AIGateway::artifactAssembled(const ArtifactLocation & al)
NET_EVENT_HANDLER;
}
void AIGateway::showTavernWindow(const CGObjectInstance * townOrTavern)
void AIGateway::showTavernWindow(const CGObjectInstance * object, const CGHeroInstance * visitor, QueryID queryID)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;
status.addQuery(queryID, "TavernWindow");
requestActionASAP([=](){ answerQuery(queryID, 0); });
}
void AIGateway::showThievesGuildWindow(const CGObjectInstance * obj)
@ -425,10 +428,13 @@ void AIGateway::receivedResource()
NET_EVENT_HANDLER;
}
void AIGateway::showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor)
void AIGateway::showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;
status.addQuery(queryID, "UniversityWindow");
requestActionASAP([=](){ answerQuery(queryID, 0); });
}
void AIGateway::heroManaPointsChanged(const CGHeroInstance * hero)
@ -498,10 +504,13 @@ void AIGateway::heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonu
NET_EVENT_HANDLER;
}
void AIGateway::showMarketWindow(const IMarket * market, const CGHeroInstance * visitor)
void AIGateway::showMarketWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;
status.addQuery(queryID, "MarketWindow");
requestActionASAP([=](){ answerQuery(queryID, 0); });
}
void AIGateway::showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain)

View File

@ -130,7 +130,7 @@ public:
void tileHidden(const std::unordered_set<int3> & pos) override;
void artifactMoved(const ArtifactLocation & src, const ArtifactLocation & dst) override;
void artifactAssembled(const ArtifactLocation & al) override;
void showTavernWindow(const CGObjectInstance * townOrTavern) override;
void showTavernWindow(const CGObjectInstance * object, const CGHeroInstance * visitor, QueryID queryID) override;
void showThievesGuildWindow(const CGObjectInstance * obj) override;
void playerBlocked(int reason, bool start) override;
void showPuzzleMap() override;
@ -157,7 +157,7 @@ public:
void requestRealized(PackageApplied * pa) override;
void receivedResource() override;
void objectRemoved(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor) override;
void showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID) override;
void heroManaPointsChanged(const CGHeroInstance * hero) override;
void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;
void battleResultsApplied() override;
@ -165,7 +165,7 @@ public:
void objectPropertyChanged(const SetObjectProperty * sop) override;
void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override;
void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override;
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID) override;
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;

View File

@ -165,10 +165,13 @@ void VCAI::artifactAssembled(const ArtifactLocation & al)
NET_EVENT_HANDLER;
}
void VCAI::showTavernWindow(const CGObjectInstance * townOrTavern)
void VCAI::showTavernWindow(const CGObjectInstance * object, const CGHeroInstance * visitor, QueryID queryID)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;
status.addQuery(queryID, "TavernWindow");
requestActionASAP([=](){ answerQuery(queryID, 0); });
}
void VCAI::showThievesGuildWindow(const CGObjectInstance * obj)
@ -512,10 +515,13 @@ void VCAI::receivedResource()
NET_EVENT_HANDLER;
}
void VCAI::showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor)
void VCAI::showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;
status.addQuery(queryID, "UniversityWindow");
requestActionASAP([=](){ answerQuery(queryID, 0); });
}
void VCAI::heroManaPointsChanged(const CGHeroInstance * hero)
@ -577,10 +583,13 @@ void VCAI::heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bo
NET_EVENT_HANDLER;
}
void VCAI::showMarketWindow(const IMarket * market, const CGHeroInstance * visitor)
void VCAI::showMarketWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID)
{
LOG_TRACE(logAi);
NET_EVENT_HANDLER;
status.addQuery(queryID, "MarketWindow");
requestActionASAP([=](){ answerQuery(queryID, 0); });
}
void VCAI::showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain)

View File

@ -163,7 +163,7 @@ public:
void tileHidden(const std::unordered_set<int3> & pos) override;
void artifactMoved(const ArtifactLocation & src, const ArtifactLocation & dst) override;
void artifactAssembled(const ArtifactLocation & al) override;
void showTavernWindow(const CGObjectInstance * townOrTavern) override;
void showTavernWindow(const CGObjectInstance * object, const CGHeroInstance * visitor, QueryID queryID) override;
void showThievesGuildWindow(const CGObjectInstance * obj) override;
void playerBlocked(int reason, bool start) override;
void showPuzzleMap() override;
@ -190,7 +190,7 @@ public:
void requestRealized(PackageApplied * pa) override;
void receivedResource() override;
void objectRemoved(const CGObjectInstance * obj, const PlayerColor & initiator) override;
void showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor) override;
void showUniversityWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID) override;
void heroManaPointsChanged(const CGHeroInstance * hero) override;
void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val) override;
void battleResultsApplied() override;
@ -198,7 +198,7 @@ public:
void objectPropertyChanged(const SetObjectProperty * sop) override;
void buildChanged(const CGTownInstance * town, BuildingID buildingID, int what) override;
void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override;
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID) override;
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override;

View File

@ -1621,24 +1621,30 @@ void CPlayerInterface::battleNewRoundFirst(const BattleID & battleID)
battleInt->newRoundFirst();
}
void CPlayerInterface::showMarketWindow(const IMarket *market, const CGHeroInstance *visitor)
void CPlayerInterface::showMarketWindow(const IMarket *market, const CGHeroInstance *visitor, QueryID queryID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
auto onWindowClosed = [this, queryID](){
cb->selectionMade(0, queryID);
};
if(market->allowsTrade(EMarketMode::ARTIFACT_EXP) && visitor->getAlignment() != EAlignment::EVIL)
GH.windows().createAndPushWindow<CAltarWindow>(market, visitor, EMarketMode::ARTIFACT_EXP);
GH.windows().createAndPushWindow<CAltarWindow>(market, visitor, onWindowClosed, EMarketMode::ARTIFACT_EXP);
else if(market->allowsTrade(EMarketMode::CREATURE_EXP) && visitor->getAlignment() != EAlignment::GOOD)
GH.windows().createAndPushWindow<CAltarWindow>(market, visitor, EMarketMode::CREATURE_EXP);
GH.windows().createAndPushWindow<CAltarWindow>(market, visitor, onWindowClosed, EMarketMode::CREATURE_EXP);
else if(market->allowsTrade(EMarketMode::CREATURE_UNDEAD))
GH.windows().createAndPushWindow<CTransformerWindow>(market, visitor);
GH.windows().createAndPushWindow<CTransformerWindow>(market, visitor, onWindowClosed);
else if(!market->availableModes().empty())
GH.windows().createAndPushWindow<CMarketplaceWindow>(market, visitor, market->availableModes().front());
GH.windows().createAndPushWindow<CMarketplaceWindow>(market, visitor, onWindowClosed, market->availableModes().front());
}
void CPlayerInterface::showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor)
void CPlayerInterface::showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor, QueryID queryID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
GH.windows().createAndPushWindow<CUniversityWindow>(visitor, market);
auto onWindowClosed = [this, queryID](){
cb->selectionMade(0, queryID);
};
GH.windows().createAndPushWindow<CUniversityWindow>(visitor, market, onWindowClosed);
}
void CPlayerInterface::showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor)
@ -1654,10 +1660,13 @@ void CPlayerInterface::availableArtifactsChanged(const CGBlackMarket * bm)
cmw->artifactsChanged(false);
}
void CPlayerInterface::showTavernWindow(const CGObjectInstance *townOrTavern)
void CPlayerInterface::showTavernWindow(const CGObjectInstance * object, const CGHeroInstance * visitor, QueryID queryID)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
GH.windows().createAndPushWindow<CTavernWindow>(townOrTavern);
auto onWindowClosed = [this, queryID](){
cb->selectionMade(0, queryID);
};
GH.windows().createAndPushWindow<CTavernWindow>(object, onWindowClosed);
}
void CPlayerInterface::showThievesGuildWindow (const CGObjectInstance * obj)

View File

@ -122,8 +122,8 @@ protected: // Call-ins from server, should not be called directly, but only via
void showTeleportDialog(const CGHeroInstance * hero, TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override;
void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) override;
void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) override;
void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) override;
void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor, QueryID queryID) override;
void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor, QueryID queryID) override;
void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor) override;
void advmapSpellCast(const CGHeroInstance * caster, SpellID spellID) override; //called when a hero casts a spell
void tileHidden(const std::unordered_set<int3> &pos) override; //called when given tiles become hidden under fog of war
@ -179,7 +179,7 @@ public: // public interface for use by client via LOCPLINT access
void viewWorldMap() override;
void showQuestLog() override;
void showThievesGuildWindow (const CGObjectInstance * obj) override;
void showTavernWindow(const CGObjectInstance *townOrTavern) override;
void showTavernWindow(const CGObjectInstance * object, const CGHeroInstance * visitor, QueryID queryID) override;
void showShipyardDialog(const IShipyard *obj) override; //obj may be town or shipyard;
void showHeroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2);

View File

@ -170,7 +170,7 @@ public:
void showBlockingDialog(BlockingDialog * iw) override {};
void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) override {};
void showTeleportDialog(TeleportDialog * iw) override {};
void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) override {};
void showObjectWindow(const CGObjectInstance * object, EOpenWindowMode window, const CGHeroInstance * visitor, bool addQuery) override {};
void giveResource(PlayerColor player, GameResID which, int val) override {};
virtual void giveResources(PlayerColor player, TResources resources) override {};

View File

@ -936,58 +936,67 @@ void ApplyClientNetPackVisitor::visitOpenWindow(OpenWindow & pack)
case EOpenWindowMode::RECRUITMENT_FIRST:
case EOpenWindowMode::RECRUITMENT_ALL:
{
const CGDwelling *dw = dynamic_cast<const CGDwelling*>(cl.getObj(ObjectInstanceID(pack.id1)));
const CArmedInstance *dst = dynamic_cast<const CArmedInstance*>(cl.getObj(ObjectInstanceID(pack.id2)));
assert(pack.queryID == QueryID::NONE);
const CGDwelling *dw = dynamic_cast<const CGDwelling*>(cl.getObj(ObjectInstanceID(pack.object)));
const CArmedInstance *dst = dynamic_cast<const CArmedInstance*>(cl.getObj(ObjectInstanceID(pack.visitor)));
callInterfaceIfPresent(cl, dst->tempOwner, &IGameEventsReceiver::showRecruitmentDialog, dw, dst, pack.window == EOpenWindowMode::RECRUITMENT_FIRST ? 0 : -1);
}
break;
case EOpenWindowMode::SHIPYARD_WINDOW:
{
const IShipyard *sy = IShipyard::castFrom(cl.getObj(ObjectInstanceID(pack.id1)));
assert(pack.queryID == QueryID::NONE);
const IShipyard *sy = IShipyard::castFrom(cl.getObj(ObjectInstanceID(pack.object)));
callInterfaceIfPresent(cl, sy->getObject()->getOwner(), &IGameEventsReceiver::showShipyardDialog, sy);
}
break;
case EOpenWindowMode::THIEVES_GUILD:
{
assert(pack.queryID == QueryID::NONE);
//displays Thieves' Guild window (when hero enters Den of Thieves)
const CGObjectInstance *obj = cl.getObj(ObjectInstanceID(pack.id2));
callInterfaceIfPresent(cl, PlayerColor(pack.id1), &IGameEventsReceiver::showThievesGuildWindow, obj);
const CGObjectInstance *obj = cl.getObj(ObjectInstanceID(pack.object));
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.visitor));
callInterfaceIfPresent(cl, hero->getOwner(), &IGameEventsReceiver::showThievesGuildWindow, obj);
}
break;
case EOpenWindowMode::UNIVERSITY_WINDOW:
{
//displays University window (when hero enters University on adventure map)
const IMarket *market = IMarket::castFrom(cl.getObj(ObjectInstanceID(pack.id1)));
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.id2));
callInterfaceIfPresent(cl, hero->tempOwner, &IGameEventsReceiver::showUniversityWindow, market, hero);
const IMarket *market = IMarket::castFrom(cl.getObj(ObjectInstanceID(pack.object)));
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.visitor));
callInterfaceIfPresent(cl, hero->tempOwner, &IGameEventsReceiver::showUniversityWindow, market, hero, pack.queryID);
}
break;
case EOpenWindowMode::MARKET_WINDOW:
{
//displays Thieves' Guild window (when hero enters Den of Thieves)
const CGObjectInstance *obj = cl.getObj(ObjectInstanceID(pack.id1));
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.id2));
const CGObjectInstance *obj = cl.getObj(ObjectInstanceID(pack.object));
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.visitor));
const IMarket *market = IMarket::castFrom(obj);
callInterfaceIfPresent(cl, cl.getTile(obj->visitablePos())->visitableObjects.back()->tempOwner, &IGameEventsReceiver::showMarketWindow, market, hero);
callInterfaceIfPresent(cl, cl.getTile(obj->visitablePos())->visitableObjects.back()->tempOwner, &IGameEventsReceiver::showMarketWindow, market, hero, pack.queryID);
}
break;
case EOpenWindowMode::HILL_FORT_WINDOW:
{
assert(pack.queryID == QueryID::NONE);
//displays Hill fort window
const CGObjectInstance *obj = cl.getObj(ObjectInstanceID(pack.id1));
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.id2));
const CGObjectInstance *obj = cl.getObj(ObjectInstanceID(pack.object));
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.visitor));
callInterfaceIfPresent(cl, cl.getTile(obj->visitablePos())->visitableObjects.back()->tempOwner, &IGameEventsReceiver::showHillFortWindow, obj, hero);
}
break;
case EOpenWindowMode::PUZZLE_MAP:
{
callInterfaceIfPresent(cl, PlayerColor(pack.id1), &IGameEventsReceiver::showPuzzleMap);
assert(pack.queryID == QueryID::NONE);
const CGHeroInstance *hero = cl.getHero(ObjectInstanceID(pack.visitor));
callInterfaceIfPresent(cl, hero->getOwner(), &IGameEventsReceiver::showPuzzleMap);
}
break;
case EOpenWindowMode::TAVERN_WINDOW:
const CGObjectInstance *obj1 = cl.getObj(ObjectInstanceID(pack.id1)),
*obj2 = cl.getObj(ObjectInstanceID(pack.id2));
callInterfaceIfPresent(cl, obj1->tempOwner, &IGameEventsReceiver::showTavernWindow, obj2);
{
const CGObjectInstance *obj1 = cl.getObj(ObjectInstanceID(pack.object));
const CGHeroInstance * hero = cl.getHero(ObjectInstanceID(pack.visitor));
callInterfaceIfPresent(cl, hero->tempOwner, &IGameEventsReceiver::showTavernWindow, obj1, hero, pack.queryID);
}
break;
}
}

View File

@ -342,7 +342,7 @@ void AdventureMapShortcuts::showMarketplace()
}
if(townWithMarket) //if any town has marketplace, open window
GH.windows().createAndPushWindow<CMarketplaceWindow>(townWithMarket);
GH.windows().createAndPushWindow<CMarketplaceWindow>(townWithMarket, nullptr, nullptr, EMarketMode::RESOURCE_RESOURCE);
else //if not - complain
LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.adventureMap.noTownWithMarket"));
}

View File

@ -674,7 +674,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
break;
case BuildingID::TAVERN:
LOCPLINT->showTavernWindow(town);
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
break;
case BuildingID::SHIPYARD:
@ -700,7 +700,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
case BuildingID::MARKETPLACE:
// can't use allied marketplace
if (town->getOwner() == LOCPLINT->playerID)
GH.windows().createAndPushWindow<CMarketplaceWindow>(town, town->visitingHero);
GH.windows().createAndPushWindow<CMarketplaceWindow>(town, town->visitingHero, nullptr, EMarketMode::RESOURCE_RESOURCE);
else
enterBuilding(building);
break;
@ -728,7 +728,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
case BuildingSubID::ARTIFACT_MERCHANT:
if(town->visitingHero)
GH.windows().createAndPushWindow<CMarketplaceWindow>(town, town->visitingHero, EMarketMode::RESOURCE_ARTIFACT);
GH.windows().createAndPushWindow<CMarketplaceWindow>(town, town->visitingHero, nullptr, EMarketMode::RESOURCE_ARTIFACT);
else
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % b->getNameTranslated())); //Only visiting heroes may use the %s.
break;
@ -739,21 +739,21 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
case BuildingSubID::FREELANCERS_GUILD:
if(getHero())
GH.windows().createAndPushWindow<CMarketplaceWindow>(town, getHero(), EMarketMode::CREATURE_RESOURCE);
GH.windows().createAndPushWindow<CMarketplaceWindow>(town, getHero(), nullptr, EMarketMode::CREATURE_RESOURCE);
else
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % b->getNameTranslated())); //Only visiting heroes may use the %s.
break;
case BuildingSubID::MAGIC_UNIVERSITY:
if (getHero())
GH.windows().createAndPushWindow<CUniversityWindow>(getHero(), town);
GH.windows().createAndPushWindow<CUniversityWindow>(getHero(), town, nullptr);
else
enterBuilding(building);
break;
case BuildingSubID::BROTHERHOOD_OF_SWORD:
if(upgrades == BuildingID::TAVERN)
LOCPLINT->showTavernWindow(town);
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
else
enterBuilding(building);
break;
@ -763,7 +763,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil
break;
case BuildingSubID::CREATURE_TRANSFORMER: //Skeleton Transformer
GH.windows().createAndPushWindow<CTransformerWindow>(town, getHero());
GH.windows().createAndPushWindow<CTransformerWindow>(town, getHero(), nullptr);
break;
case BuildingSubID::PORTAL_OF_SUMMONING:
@ -1319,7 +1319,7 @@ void CCastleInterface::keyPressed(EShortcut key)
break;
case EShortcut::TOWN_OPEN_TAVERN:
if(town->hasBuilt(BuildingID::TAVERN))
LOCPLINT->showTavernWindow(town);
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
break;
default:
break;

View File

@ -317,9 +317,10 @@ void CTradeWindow::CTradeableItem::setArtInstance(const CArtifactInstance *art)
setID(-1);
}
CTradeWindow::CTradeWindow(const ImagePath & bgName, const IMarket *Market, const CGHeroInstance *Hero, EMarketMode Mode):
CTradeWindow::CTradeWindow(const ImagePath & bgName, const IMarket *Market, const CGHeroInstance *Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode):
CWindowObject(PLAYER_COLORED, bgName),
market(Market),
onWindowClosed(onWindowClosed),
hero(Hero),
readyToTrade(false)
{
@ -561,6 +562,14 @@ void CTradeWindow::showAll(Canvas & to)
}
}
void CTradeWindow::close()
{
if (onWindowClosed)
onWindowClosed();
CWindowObject::close();
}
void CTradeWindow::removeItems(const std::set<std::shared_ptr<CTradeableItem>> & toRemove)
{
for(auto item : toRemove)
@ -589,17 +598,19 @@ void CTradeWindow::setMode(EMarketMode Mode)
{
const IMarket *m = market;
const CGHeroInstance *h = hero;
const auto functor = onWindowClosed;
onWindowClosed = nullptr; // don't call on closing of this window - pass it to next window
close();
switch(Mode)
{
case EMarketMode::CREATURE_EXP:
case EMarketMode::ARTIFACT_EXP:
GH.windows().createAndPushWindow<CAltarWindow>(m, h, Mode);
GH.windows().createAndPushWindow<CAltarWindow>(m, h, functor, Mode);
break;
default:
GH.windows().createAndPushWindow<CMarketplaceWindow>(m, h, Mode);
GH.windows().createAndPushWindow<CMarketplaceWindow>(m, h, functor, Mode);
break;
}
}
@ -635,8 +646,8 @@ ImagePath CMarketplaceWindow::getBackgroundForMode(EMarketMode mode)
return {};
}
CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInstance * Hero, EMarketMode Mode)
: CTradeWindow(getBackgroundForMode(Mode), Market, Hero, Mode)
CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInstance * Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode)
: CTradeWindow(getBackgroundForMode(Mode), Market, Hero, onWindowClosed, Mode)
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
@ -1093,8 +1104,8 @@ void CMarketplaceWindow::updateTraderText()
traderText->setText(CGI->generaltexth->allTexts[gnrtxtnr]);
}
CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero, EMarketMode Mode)
: CTradeWindow(ImagePath::builtin(Mode == EMarketMode::CREATURE_EXP ? "ALTARMON.bmp" : "ALTRART2.bmp"), Market, Hero, Mode)
CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode)
: CTradeWindow(ImagePath::builtin(Mode == EMarketMode::CREATURE_EXP ? "ALTARMON.bmp" : "ALTRART2.bmp"), Market, Hero, onWindowClosed, Mode)
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);

View File

@ -83,9 +83,10 @@ public:
std::shared_ptr<CSlider> slider; //for choosing amount to be exchanged
bool readyToTrade;
CTradeWindow(const ImagePath & bgName, const IMarket * Market, const CGHeroInstance * Hero, EMarketMode Mode); //c
CTradeWindow(const ImagePath & bgName, const IMarket * Market, const CGHeroInstance * Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode); //c
void showAll(Canvas & to) override;
void close();
void initSubs(bool Left);
void initTypes();
@ -106,6 +107,7 @@ public:
virtual void garrisonChanged() = 0;
virtual void artifactsChanged(bool left) = 0;
protected:
std::function<void()> onWindowClosed;
std::shared_ptr<CGStatusBar> statusBar;
std::vector<std::shared_ptr<CLabel>> labels;
std::vector<std::shared_ptr<CPicture>> images;
@ -130,7 +132,7 @@ public:
void sliderMoved(int to);
void makeDeal();
void selectionChanged(bool side) override; //true == left
CMarketplaceWindow(const IMarket * Market, const CGHeroInstance * Hero = nullptr, EMarketMode Mode = EMarketMode::RESOURCE_RESOURCE);
CMarketplaceWindow(const IMarket * Market, const CGHeroInstance * Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode);
~CMarketplaceWindow();
Point selectionOffset(bool Left) const override;
@ -157,7 +159,7 @@ public:
std::shared_ptr<CLabel> expOnAltar;
std::shared_ptr<CArtifactsOfHeroAltar> arts;
CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero, EMarketMode Mode);
CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode);
~CAltarWindow();
void getExpValues();

View File

@ -430,8 +430,9 @@ CLevelWindow::~CLevelWindow()
LOCPLINT->showingDialog->setn(false);
}
CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj)
CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::function<void()> & onWindowClosed)
: CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("TPTAVERN")),
onWindowClosed(onWindowClosed),
tavernObj(TavernObj)
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
@ -500,8 +501,9 @@ void CTavernWindow::recruitb()
{
const CGHeroInstance *toBuy = (selected ? h2 : h1)->h;
const CGObjectInstance *obj = tavernObj;
close();
LOCPLINT->cb->recruitHero(obj, toBuy);
close();
}
void CTavernWindow::thievesguildb()
@ -509,6 +511,14 @@ void CTavernWindow::thievesguildb()
GH.windows().createAndPushWindow<CThievesGuildWindow>(tavernObj);
}
void CTavernWindow::close()
{
if (onWindowClosed)
onWindowClosed();
CStatusbarWindow::close();
}
CTavernWindow::~CTavernWindow()
{
CCS->videoh->close();
@ -993,9 +1003,10 @@ void CTransformerWindow::updateGarrisons()
item->update();
}
CTransformerWindow::CTransformerWindow(const IMarket * _market, const CGHeroInstance * _hero)
CTransformerWindow::CTransformerWindow(const IMarket * _market, const CGHeroInstance * _hero, const std::function<void()> & onWindowClosed)
: CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("SKTRNBK")),
hero(_hero),
onWindowClosed(onWindowClosed),
market(_market)
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
@ -1024,6 +1035,14 @@ CTransformerWindow::CTransformerWindow(const IMarket * _market, const CGHeroInst
helpRight = std::make_shared<CTextBox>(CGI->generaltexth->allTexts[488], Rect(320, 56, 255, 40), 0, FONT_MEDIUM, ETextAlignment::CENTER, Colors::YELLOW);//creatures here will become skeletons
}
void CTransformerWindow::close()
{
if (onWindowClosed)
onWindowClosed();
CStatusbarWindow::close();
}
CUniversityWindow::CItem::CItem(CUniversityWindow * _parent, int _ID, int X, int Y)
: CIntObject(LCLICK | SHOW_POPUP | HOVER),
ID(_ID),
@ -1083,9 +1102,10 @@ void CUniversityWindow::CItem::showAll(Canvas & to)
CIntObject::showAll(to);
}
CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket * _market)
CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket * _market, const std::function<void()> & onWindowClosed)
: CStatusbarWindow(PLAYER_COLORED, ImagePath::builtin("UNIVERS1")),
hero(_hero),
onWindowClosed(onWindowClosed),
market(_market)
{
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
@ -1130,6 +1150,14 @@ CUniversityWindow::CUniversityWindow(const CGHeroInstance * _hero, const IMarket
statusbar = CGStatusBar::create(std::make_shared<CPicture>(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
}
void CUniversityWindow::close()
{
if (onWindowClosed)
onWindowClosed();
CStatusbarWindow::close();
}
void CUniversityWindow::makeDeal(int skill)
{
LOCPLINT->cb->trade(market, EMarketMode::RESOURCE_SKILL, 6, skill, 1, hero);

View File

@ -193,6 +193,8 @@ public:
class CTavernWindow : public CStatusbarWindow
{
std::function<void()> onWindowClosed;
public:
class HeroPortrait : public CIntObject
{
@ -233,9 +235,10 @@ public:
std::shared_ptr<CTextBox> rumor;
CTavernWindow(const CGObjectInstance * TavernObj);
CTavernWindow(const CGObjectInstance * TavernObj, const std::function<void()> & onWindowClosed);
~CTavernWindow();
void close();
void recruitb();
void thievesguildb();
void show(Canvas & to) override;
@ -349,12 +352,15 @@ class CTransformerWindow : public CStatusbarWindow, public IGarrisonHolder
std::shared_ptr<CButton> all;
std::shared_ptr<CButton> convert;
std::shared_ptr<CButton> cancel;
std::function<void()> onWindowClosed;
public:
void makeDeal();
void addAll();
void close();
void updateGarrisons() override;
CTransformerWindow(const IMarket * _market, const CGHeroInstance * _hero);
CTransformerWindow(const IMarket * _market, const CGHeroInstance * _hero, const std::function<void()> & onWindowClosed);
};
class CUniversityWindow : public CStatusbarWindow
@ -390,10 +396,13 @@ class CUniversityWindow : public CStatusbarWindow
std::shared_ptr<CLabel> title;
std::shared_ptr<CTextBox> clerkSpeech;
std::function<void()> onWindowClosed;
public:
CUniversityWindow(const CGHeroInstance * _hero, const IMarket * _market);
CUniversityWindow(const CGHeroInstance * _hero, const IMarket * _market, const std::function<void()> & onWindowClosed);
void makeDeal(int skill);
void close();
};
/// Confirmation window for University

View File

@ -25,6 +25,7 @@ struct ArtifactLocation;
class CCreatureSet;
class CStackBasicDescriptor;
class CGCreature;
enum class EOpenWindowMode : uint8_t;
namespace spells
{
@ -96,7 +97,7 @@ public:
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 showTeleportDialog(TeleportDialog *iw) =0;
virtual void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) =0;
virtual void showObjectWindow(const CGObjectInstance * object, EOpenWindowMode window, const CGHeroInstance * visitor, bool addQuery) = 0;
virtual void giveResource(PlayerColor player, GameResID which, int val)=0;
virtual void giveResources(PlayerColor player, TResources resources)=0;

View File

@ -110,11 +110,11 @@ public:
virtual void showPuzzleMap(){};
virtual void viewWorldMap(){};
virtual void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor){};
virtual void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor){};
virtual void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor, QueryID queryID){};
virtual void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor, QueryID queryID){};
virtual void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor){};
virtual void showTavernWindow(const CGObjectInstance *townOrTavern){};
virtual void showThievesGuildWindow (const CGObjectInstance * obj){};
virtual void showTavernWindow(const CGObjectInstance * object, const CGHeroInstance * visitor, QueryID queryID) {};
virtual void showQuestLog(){};
virtual void advmapSpellCast(const CGHeroInstance * caster, SpellID spellID){}; //called when a hero casts a spell
virtual void tileHidden(const std::unordered_set<int3> &pos){};

View File

@ -786,19 +786,20 @@ struct DLL_LINKAGE GiveHero : public CPackForClient
}
};
struct DLL_LINKAGE OpenWindow : public CPackForClient
struct DLL_LINKAGE OpenWindow : public Query
{
EOpenWindowMode window;
si32 id1 = -1;
si32 id2 = -1;
ObjectInstanceID object;
ObjectInstanceID visitor;
virtual void visitTyped(ICPackVisitor & visitor) override;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & queryID;
h & window;
h & id1;
h & id2;
h & object;
h & visitor;
}
};

View File

@ -393,13 +393,8 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const
cb->sendAndApply(&sac);
}
OpenWindow ow;
ow.id1 = id.getNum();
ow.id2 = h->id.getNum();
ow.window = (ID == Obj::CREATURE_GENERATOR1 || ID == Obj::REFUGEE_CAMP)
? EOpenWindowMode::RECRUITMENT_FIRST
: EOpenWindowMode::RECRUITMENT_ALL;
cb->sendAndApply(&ow);
auto windowMode = (ID == Obj::CREATURE_GENERATOR1 || ID == Obj::REFUGEE_CAMP) ? EOpenWindowMode::RECRUITMENT_FIRST : EOpenWindowMode::RECRUITMENT_ALL;
cb->showObjectWindow(this, windowMode, h, false);
}
}

View File

@ -30,7 +30,7 @@ void CGMarket::initObj(CRandomGenerator & rand)
void CGMarket::onHeroVisit(const CGHeroInstance * h) const
{
openWindow(EOpenWindowMode::MARKET_WINDOW, id.getNum(), h->id.getNum());
cb->showObjectWindow(this, EOpenWindowMode::MARKET_WINDOW, h, true);
}
int CGMarket::getMarketEfficiency() const
@ -124,7 +124,7 @@ std::vector<int> CGUniversity::availableItemsIds(EMarketMode mode) const
void CGUniversity::onHeroVisit(const CGHeroInstance * h) const
{
openWindow(EOpenWindowMode::UNIVERSITY_WINDOW,id.getNum(),h->id.getNum());
cb->showObjectWindow(this, EOpenWindowMode::UNIVERSITY_WINDOW, h, true);
}
VCMI_LIB_NAMESPACE_END

View File

@ -283,7 +283,7 @@ void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
break;
case Obj::TAVERN:
{
openWindow(EOpenWindowMode::TAVERN_WINDOW,h->id.getNum(),id.getNum());
cb->showObjectWindow(this, EOpenWindowMode::TAVERN_WINDOW, h, true);
}
break;
}

View File

@ -22,16 +22,6 @@ VCMI_LIB_NAMESPACE_BEGIN
IGameCallback * IObjectInterface::cb = nullptr;
///helpers
void IObjectInterface::openWindow(const EOpenWindowMode type, const int id1, const int id2)
{
OpenWindow ow;
ow.window = type;
ow.id1 = id1;
ow.id2 = id2;
IObjectInterface::cb->sendAndApply(&ow);
}
void IObjectInterface::showInfoDialog(const ui32 txtID, const ui16 soundID, EInfoWindowMode mode) const
{
InfoWindow iw;

View File

@ -52,9 +52,6 @@ public:
//unified helper to show info dialog for object owner
virtual void showInfoDialog(const ui32 txtID, const ui16 soundID = 0, EInfoWindowMode mode = EInfoWindowMode::AUTO) const;
//unified helper to show a specific window
static void openWindow(const EOpenWindowMode type, const int id1, const int id2 = -1);
//unified interface, AI helpers
virtual bool wasVisited (PlayerColor player) const;
virtual bool wasVisited (const CGHeroInstance * h) const;

View File

@ -1399,7 +1399,7 @@ void CGShipyard::onHeroVisit( const CGHeroInstance * h ) const
}
else
{
openWindow(EOpenWindowMode::SHIPYARD_WINDOW,id.getNum(),h->id.getNum());
cb->showObjectWindow(this, EOpenWindowMode::SHIPYARD_WINDOW, h, false);
}
}
@ -1488,7 +1488,7 @@ void CCartographer::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answ
void CGDenOfthieves::onHeroVisit (const CGHeroInstance * h) const
{
cb->showThievesGuildWindow(h->tempOwner, id);
cb->showObjectWindow(this, EOpenWindowMode::THIEVES_GUILD, h, false);
}
void CGObelisk::onHeroVisit( const CGHeroInstance * h ) const
@ -1507,8 +1507,7 @@ void CGObelisk::onHeroVisit( const CGHeroInstance * h ) const
// increment general visited obelisks counter
cb->setObjProperty(id, CGObelisk::OBJPROP_INC, team.getNum());
openWindow(EOpenWindowMode::PUZZLE_MAP, h->tempOwner.getNum());
cb->showObjectWindow(this, EOpenWindowMode::PUZZLE_MAP, h, false);
// mark that particular obelisk as visited for all players in the team
for(const auto & color : ts->players)
@ -1619,7 +1618,7 @@ void CGLighthouse::serializeJsonOptions(JsonSerializeFormat& handler)
void HillFort::onHeroVisit(const CGHeroInstance * h) const
{
openWindow(EOpenWindowMode::HILL_FORT_WINDOW,id.getNum(),h->id.getNum());
cb->showObjectWindow(this, EOpenWindowMode::HILL_FORT_WINDOW, h, false);
}
void HillFort::fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const

View File

@ -3364,13 +3364,20 @@ void CGameHandler::showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID h
sendAndApply(&gd);
}
void CGameHandler::showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId)
void CGameHandler::showObjectWindow(const CGObjectInstance * object, EOpenWindowMode window, const CGHeroInstance * visitor, bool addQuery)
{
OpenWindow ow;
ow.window = EOpenWindowMode::THIEVES_GUILD;
ow.id1 = player.getNum();
ow.id2 = requestingObjId.getNum();
sendAndApply(&ow);
OpenWindow pack;
pack.window = window;
pack.object = object->id;
pack.visitor = visitor->id;
if (addQuery)
{
auto windowQuery = std::make_shared<OpenWindowQuery>(this, visitor, window);
pack.queryID = windowQuery->queryID;
queries->addQuery(windowQuery);
}
sendAndApply(&pack);
}
bool CGameHandler::isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2)

View File

@ -109,7 +109,7 @@ public:
void showBlockingDialog(BlockingDialog *iw) override;
void showTeleportDialog(TeleportDialog *iw) override;
void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits) override;
void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) override;
void showObjectWindow(const CGObjectInstance * object, EOpenWindowMode window, const CGHeroInstance * visitor, bool addQuery) override;
void giveResource(PlayerColor player, GameResID which, int val) override;
void giveResources(PlayerColor player, TResources resources) override;

View File

@ -157,6 +157,39 @@ CBlockingDialogQuery::CBlockingDialogQuery(CGameHandler * owner, const BlockingD
addPlayer(bd.player);
}
OpenWindowQuery::OpenWindowQuery(CGameHandler * owner, const CGHeroInstance *hero, EOpenWindowMode mode):
CDialogQuery(owner),
mode(mode)
{
addPlayer(hero->getOwner());
}
bool OpenWindowQuery::blocksPack(const CPack *pack) const
{
if (mode == EOpenWindowMode::TAVERN_WINDOW)
{
if(dynamic_ptr_cast<HireHero>(pack) != nullptr)
return false;
}
if (mode == EOpenWindowMode::MARKET_WINDOW)
{
if(dynamic_ptr_cast<ExchangeArtifacts>(pack) != nullptr)
return false;
if(dynamic_ptr_cast<AssembleArtifacts>(pack))
return false;
if(dynamic_ptr_cast<EraseArtifactByClient>(pack))
return false;
if(dynamic_ptr_cast<TradeOnMarketplace>(pack) != nullptr)
return false;
}
return CDialogQuery::blocksPack(pack);
}
void CTeleportDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
{
// do not change to dynamic_ptr_cast - SIGSEGV!

View File

@ -61,7 +61,6 @@ public:
virtual void onRemoval(PlayerColor color) override;
};
class CGarrisonDialogQuery : public CDialogQuery //used also for hero exchange dialogs
{
public:
@ -83,6 +82,15 @@ public:
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override;
};
class OpenWindowQuery : public CDialogQuery
{
EOpenWindowMode mode;
public:
OpenWindowQuery(CGameHandler * owner, const CGHeroInstance *hero, EOpenWindowMode mode);
virtual bool blocksPack(const CPack *pack) const override;
};
class CTeleportDialogQuery : public CDialogQuery
{
public: