mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-23 22:37:55 +02:00
Rewardable objects may now define guards. Converted Crypt to rewardable.
This commit is contained in:
@@ -10,16 +10,19 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "CRewardableObject.h"
|
||||
#include "../gameState/CGameState.h"
|
||||
#include "../texts/CGeneralTextHandler.h"
|
||||
|
||||
#include "../CPlayerState.h"
|
||||
#include "../GameSettings.h"
|
||||
#include "../IGameCallback.h"
|
||||
#include "../gameState/CGameState.h"
|
||||
#include "../mapObjectConstructors/AObjectTypeHandler.h"
|
||||
#include "../mapObjectConstructors/CObjectClassesHandler.h"
|
||||
#include "../mapObjectConstructors/CRewardableConstructor.h"
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../networkPacks/PacksForClient.h"
|
||||
#include "../networkPacks/PacksForClientBattle.h"
|
||||
#include "../serializer/JsonSerializeFormat.h"
|
||||
#include "../texts/CGeneralTextHandler.h"
|
||||
|
||||
#include <vstd/RNG.h>
|
||||
|
||||
@@ -91,7 +94,42 @@ std::vector<Component> CRewardableObject::loadComponents(const CGHeroInstance *
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CRewardableObject::guardedPotentially() const
|
||||
{
|
||||
for (auto const & visitInfo : configuration.info)
|
||||
if (!visitInfo.reward.guards.empty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CRewardableObject::guardedPresently() const
|
||||
{
|
||||
return stacksCount() > 0;
|
||||
}
|
||||
|
||||
void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const
|
||||
{
|
||||
if (guardedPresently())
|
||||
{
|
||||
auto guardedIndexes = getAvailableRewards(h, 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.text = guardedReward.message;
|
||||
bd.components = getPopupComponents(h->getOwner());
|
||||
|
||||
cb->showBlockingDialog(&bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
doHeroVisit(h);
|
||||
}
|
||||
}
|
||||
|
||||
void CRewardableObject::doHeroVisit(const CGHeroInstance *h) const
|
||||
{
|
||||
if(!wasVisitedBefore(h))
|
||||
{
|
||||
@@ -181,39 +219,54 @@ void CRewardableObject::heroLevelUpDone(const CGHeroInstance *hero) const
|
||||
grantRewardAfterLevelup(cb, configuration.info.at(selectedReward), this, hero);
|
||||
}
|
||||
|
||||
void CRewardableObject::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
void CRewardableObject::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{
|
||||
if(answer == 0)
|
||||
if (result.winner == BattleSide::ATTACKER)
|
||||
{
|
||||
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
|
||||
doHeroVisit(hero);
|
||||
}
|
||||
}
|
||||
|
||||
if(answer > 0 && answer-1 < configuration.info.size())
|
||||
void CRewardableObject::blockingDialogAnswered(const CGHeroInstance * hero, int32_t answer) const
|
||||
{
|
||||
if(guardedPresently())
|
||||
{
|
||||
auto list = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT);
|
||||
markAsVisited(hero);
|
||||
grantReward(list[answer - 1], hero);
|
||||
if (answer)
|
||||
cb->startBattleI(hero, this, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Unhandled choice");
|
||||
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);
|
||||
markAsVisited(hero);
|
||||
grantReward(list[answer - 1], hero);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Unhandled choice");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,19 +421,41 @@ std::vector<Component> CRewardableObject::getPopupComponentsImpl(PlayerColor pla
|
||||
if (!configuration.showScoutedPreview)
|
||||
return {};
|
||||
|
||||
auto rewardIndices = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT);
|
||||
if (rewardIndices.empty() && !configuration.info.empty())
|
||||
if (guardedPresently())
|
||||
{
|
||||
// Object has valid config, but current hero has no rewards that he can receive.
|
||||
// Usually this happens if hero has already visited this object -> show reward using context without any hero
|
||||
// since reward may be context-sensitive - e.g. Witch Hut that gives 1 skill, but always at basic level
|
||||
return loadComponents(nullptr, {0});
|
||||
if (!VLC->settings()->getBoolean(EGameSettings::BANKS_SHOW_GUARDS_COMPOSITION))
|
||||
return {};
|
||||
|
||||
std::map<CreatureID, int> guardsAmounts;
|
||||
std::vector<Component> result;
|
||||
|
||||
for (auto const & slot : Slots())
|
||||
if (slot.second)
|
||||
guardsAmounts[slot.second->getCreatureID()] += slot.second->getCount();
|
||||
|
||||
for (auto const & guard : guardsAmounts)
|
||||
{
|
||||
Component comp(ComponentType::CREATURE, guard.first, guard.second);
|
||||
result.push_back(comp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto rewardIndices = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT);
|
||||
if (rewardIndices.empty() && !configuration.info.empty())
|
||||
{
|
||||
// Object has valid config, but current hero has no rewards that he can receive.
|
||||
// Usually this happens if hero has already visited this object -> show reward using context without any hero
|
||||
// since reward may be context-sensitive - e.g. Witch Hut that gives 1 skill, but always at basic level
|
||||
return loadComponents(nullptr, {0});
|
||||
}
|
||||
|
||||
if (rewardIndices.empty())
|
||||
return {};
|
||||
if (rewardIndices.empty())
|
||||
return {};
|
||||
|
||||
return loadComponents(hero, rewardIndices);
|
||||
return loadComponents(hero, rewardIndices);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Component> CRewardableObject::getPopupComponents(PlayerColor player) const
|
||||
@@ -440,4 +515,21 @@ void CRewardableObject::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
handler.serializeStruct("rewardable", static_cast<Rewardable::Interface&>(*this));
|
||||
}
|
||||
|
||||
void CRewardableObject::initializeGuards()
|
||||
{
|
||||
clearSlots();
|
||||
|
||||
for (auto const & visitInfo : configuration.info)
|
||||
{
|
||||
for (auto const & guard : visitInfo.reward.guards)
|
||||
{
|
||||
auto slotID = getFreeSlot();
|
||||
if (!slotID.validSlot())
|
||||
return;
|
||||
|
||||
putStack(slotID, new CStackInstance(guard.getId(), guard.getCount()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
Reference in New Issue
Block a user