From 927ce4e60e625d9eee813559082a9267198ef8eb Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Mon, 16 Oct 2023 23:55:37 +0300 Subject: [PATCH] Improvements to rewardable objects popups --- client/windows/InfoWindows.cpp | 14 +++++- lib/mapObjects/CGObjectInstance.cpp | 10 +++++ lib/mapObjects/CGObjectInstance.h | 3 ++ lib/mapObjects/CRewardableObject.cpp | 67 ++++++++++++++++++++++++---- lib/mapObjects/CRewardableObject.h | 5 +++ lib/rewardable/Reward.cpp | 10 ++--- lib/rewardable/Reward.h | 4 +- 7 files changed, 94 insertions(+), 19 deletions(-) diff --git a/client/windows/InfoWindows.cpp b/client/windows/InfoWindows.cpp index f015c779b..8a298cdc8 100644 --- a/client/windows/InfoWindows.cpp +++ b/client/windows/InfoWindows.cpp @@ -351,10 +351,20 @@ void CRClickPopup::createAndPush(const CGObjectInstance * obj, const Point & p, } else { + std::vector components; if(LOCPLINT->localState->getCurrentHero()) - CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->localState->getCurrentHero())); + components = obj->getPopupComponents(LOCPLINT->localState->getCurrentHero()); else - CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID)); + components = obj->getPopupComponents(LOCPLINT->playerID); + + std::vector> guiComponents; + for (auto & component : components) + guiComponents.push_back(std::make_shared(component)); + + if(LOCPLINT->localState->getCurrentHero()) + CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->localState->getCurrentHero()), guiComponents); + else + CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID), guiComponents); } } diff --git a/lib/mapObjects/CGObjectInstance.cpp b/lib/mapObjects/CGObjectInstance.cpp index 1b2f0f92a..e4ed862c9 100644 --- a/lib/mapObjects/CGObjectInstance.cpp +++ b/lib/mapObjects/CGObjectInstance.cpp @@ -271,6 +271,16 @@ std::string CGObjectInstance::getHoverText(const CGHeroInstance * hero) const return getHoverText(hero->tempOwner); } +std::vector CGObjectInstance::getPopupComponents(PlayerColor player) const +{ + return {}; +} + +std::vector CGObjectInstance::getPopupComponents(const CGHeroInstance * hero) const +{ + return {}; +} + void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const { switch(ID) diff --git a/lib/mapObjects/CGObjectInstance.h b/lib/mapObjects/CGObjectInstance.h index fdbefa545..fb093bbd1 100644 --- a/lib/mapObjects/CGObjectInstance.h +++ b/lib/mapObjects/CGObjectInstance.h @@ -112,6 +112,9 @@ public: /// Returns hero-specific hover name, including visited/not visited info. Default = player-specific name virtual std::string getHoverText(const CGHeroInstance * hero) const; + virtual std::vector getPopupComponents(PlayerColor player) const; + virtual std::vector getPopupComponents(const CGHeroInstance * hero) const; + /** OVERRIDES OF IObjectInterface **/ void initObj(CRandomGenerator & rand) override; diff --git a/lib/mapObjects/CRewardableObject.cpp b/lib/mapObjects/CRewardableObject.cpp index 3d75e6097..f59a0ac68 100644 --- a/lib/mapObjects/CRewardableObject.cpp +++ b/lib/mapObjects/CRewardableObject.cpp @@ -47,15 +47,22 @@ void CRewardableObject::selectRewardWthMessage(const CGHeroInstance * contextHer BlockingDialog sd(configuration.canRefuse, rewardIndices.size() > 1); sd.player = contextHero->tempOwner; sd.text = dialog; + sd.components = loadComponents(contextHero, rewardIndices); + cb->showBlockingDialog(&sd); +} + +std::vector CRewardableObject::loadComponents(const CGHeroInstance * contextHero, const std::vector & rewardIndices) const +{ + std::vector result; if (rewardIndices.size() > 1) for (auto index : rewardIndices) - sd.components.push_back(configuration.info.at(index).reward.getDisplayedComponent(contextHero)); + result.push_back(configuration.info.at(index).reward.getDisplayedComponent(contextHero)); if (rewardIndices.size() == 1) - configuration.info.at(rewardIndices.front()).reward.loadComponents(sd.components, contextHero); + configuration.info.at(rewardIndices.front()).reward.loadComponents(result, contextHero); - cb->showBlockingDialog(&sd); + return result; } void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const @@ -233,26 +240,68 @@ bool CRewardableObject::wasVisited(const CGHeroInstance * h) const std::string CRewardableObject::getHoverText(PlayerColor player) const { + std::string result = getObjectName(); + + if (!configuration.description.empty()) + result += "\n" + configuration.description.toString(); + if(configuration.visitMode == Rewardable::VISIT_PLAYER || configuration.visitMode == Rewardable::VISIT_ONCE) { if (wasVisited(player)) - return getObjectName() + "\n" + configuration.visitedTooltip.toString() + "\n\n" + configuration.description.toString(); + result += "\n\n" + configuration.visitedTooltip.toString(); else - return getObjectName() + "\n" + configuration.notVisitedTooltip.toString() + "\n\n" + configuration.description.toString(); + result += "\n\n" + configuration.notVisitedTooltip.toString(); } - return getObjectName() + "\n\n" + configuration.description.toString(); + return result; } std::string CRewardableObject::getHoverText(const CGHeroInstance * hero) const { + std::string result = getObjectName(); + + if (!configuration.description.empty()) + result += "\n" + configuration.description.toString(); + if(configuration.visitMode != Rewardable::VISIT_UNLIMITED) { if (wasVisited(hero)) - return getObjectName() + "\n" + configuration.visitedTooltip.toString() + "\n\n" + configuration.description.toString(); + result += "\n\n" + configuration.visitedTooltip.toString(); else - return getObjectName() + "\n" + configuration.notVisitedTooltip.toString() + "\n\n" + configuration.description.toString(); + result += "\n\n" + configuration.notVisitedTooltip.toString(); } - return getObjectName() + "\n\n" + configuration.description.toString(); + return result; +} + +std::vector CRewardableObject::getPopupComponents(PlayerColor player) const +{ + if (!wasScouted(player)) + return {}; + + auto rewardIndices = getAvailableRewards(nullptr, Rewardable::EEventType::EVENT_FIRST_VISIT); + + if (rewardIndices.empty() && !configuration.info.empty()) + rewardIndices.push_back(0); + + if (rewardIndices.empty()) + return {}; + + return loadComponents(nullptr, rewardIndices); +} + +std::vector CRewardableObject::getPopupComponents(const CGHeroInstance * hero) const +{ + if (!wasScouted(hero->getOwner())) + return {}; + + auto rewardIndices = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT); + + if (rewardIndices.empty() && !configuration.info.empty()) + rewardIndices.push_back(0); + + if (rewardIndices.empty()) + return {}; + + return loadComponents(nullptr, rewardIndices); } void CRewardableObject::setPropertyDer(ui8 what, ui32 val) diff --git a/lib/mapObjects/CRewardableObject.h b/lib/mapObjects/CRewardableObject.h index f6199bdda..725b869ef 100644 --- a/lib/mapObjects/CRewardableObject.h +++ b/lib/mapObjects/CRewardableObject.h @@ -37,6 +37,8 @@ protected: virtual void grantRewardWithMessage(const CGHeroInstance * contextHero, int rewardIndex, bool markAsVisit) const; virtual void selectRewardWthMessage(const CGHeroInstance * contextHero, const std::vector & rewardIndices, const MetaString & dialog) const; + std::vector loadComponents(const CGHeroInstance * contextHero, const std::vector & rewardIndices) const; + public: /// Visitability checks. Note that hero check includes check for hero owner (returns true if object was visited by player) bool wasVisited(PlayerColor player) const override; @@ -66,6 +68,9 @@ public: std::string getHoverText(PlayerColor player) const override; std::string getHoverText(const CGHeroInstance * hero) const override; + std::vector getPopupComponents(PlayerColor player) const override; + std::vector getPopupComponents(const CGHeroInstance * hero) const override; + template void serialize(Handler &h, const int version) { h & static_cast(*this); diff --git a/lib/rewardable/Reward.cpp b/lib/rewardable/Reward.cpp index dad53105a..71480aae1 100644 --- a/lib/rewardable/Reward.cpp +++ b/lib/rewardable/Reward.cpp @@ -61,8 +61,7 @@ Component Rewardable::Reward::getDisplayedComponent(const CGHeroInstance * h) co return comps.front(); } -void Rewardable::Reward::loadComponents(std::vector & comps, - const CGHeroInstance * h) const +void Rewardable::Reward::loadComponents(std::vector & comps, const CGHeroInstance * h) const { for (auto comp : extraComponents) comps.push_back(comp); @@ -76,14 +75,13 @@ void Rewardable::Reward::loadComponents(std::vector & comps, } if (heroExperience) - { - comps.emplace_back(Component::EComponentType::EXPERIENCE, 0, static_cast(h->calculateXp(heroExperience)), 0); - } + comps.emplace_back(Component::EComponentType::EXPERIENCE, 0, static_cast(h ? h->calculateXp(heroExperience) : heroExperience), 0); + if (heroLevel) comps.emplace_back(Component::EComponentType::EXPERIENCE, 1, heroLevel, 0); if (manaDiff || manaPercentage >= 0) - comps.emplace_back(Component::EComponentType::PRIM_SKILL, 5, calculateManaPoints(h) - h->mana, 0); + comps.emplace_back(Component::EComponentType::PRIM_SKILL, 5, h ? (calculateManaPoints(h) - h->mana) : manaDiff, 0); for (size_t i=0; i & comps, - const CGHeroInstance * h) const; + /// If hero is nullptr, then rewards will be generated without accounting for hero + void loadComponents(std::vector & comps, const CGHeroInstance * h) const; Component getDisplayedComponent(const CGHeroInstance * h) const;