From cb16636fcee532dec0b34df67c6e2e0369418cb7 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 11 Jul 2023 23:37:17 +0300 Subject: [PATCH] Implemented preserving hero on retreat on 7th day after end of turn --- lib/gameState/TavernHeroesPool.cpp | 9 +++++ lib/gameState/TavernSlot.h | 6 +-- server/CGameHandler.h | 7 ++-- server/HeroPoolProcessor.cpp | 63 ++++++++++++++++++++++++++---- server/HeroPoolProcessor.h | 3 +- 5 files changed, 73 insertions(+), 15 deletions(-) diff --git a/lib/gameState/TavernHeroesPool.cpp b/lib/gameState/TavernHeroesPool.cpp index b8f0f2636..d66690ffd 100644 --- a/lib/gameState/TavernHeroesPool.cpp +++ b/lib/gameState/TavernHeroesPool.cpp @@ -113,6 +113,15 @@ void TavernHeroesPool::onNewDay() hero.second->setMovementPoints(hero.second->movementPointsLimit(true)); hero.second->mana = hero.second->manaLimit(); } + + for (auto & slot : currentTavern) + { + if (slot.role == TavernSlotRole::RETREATED_TODAY) + slot.role = TavernSlotRole::RETREATED; + + if (slot.role == TavernSlotRole::SURRENDERED_TODAY) + slot.role = TavernSlotRole::SURRENDERED; + } } void TavernHeroesPool::addHeroToPool(CGHeroInstance * hero) diff --git a/lib/gameState/TavernSlot.h b/lib/gameState/TavernSlot.h index 0e5a7b35c..192fd047d 100644 --- a/lib/gameState/TavernSlot.h +++ b/lib/gameState/TavernSlot.h @@ -26,10 +26,10 @@ enum class TavernSlotRole : int8_t FULL_ARMY, // hero was added to tavern on new week and still has full army RETREATED, // hero was owned by player before, but have retreated from battle and only has 1 creature in army - SURRENDERED, // hero was owned by player before, but have surrendered in battle and kept some troops + RETREATED_TODAY, -// SURRENDERED_DAY7, // helper value for heroes that surrendered after 7th day during enemy turn -// RETREATED_DAY7, + SURRENDERED, // hero was owned by player before, but have surrendered in battle and kept some troops + SURRENDERED_TODAY, }; VCMI_LIB_NAMESPACE_END diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 2d9f24c6e..af01e43c1 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -99,8 +99,6 @@ class CGameHandler : public IGameCallback, public CBattleInfoCallback, public En std::shared_ptr> applier; std::unique_ptr battleThread; - void deserializationFix(); - public: std::unique_ptr heroPool; @@ -365,6 +363,8 @@ public: scripting::Pool * getContextPool() const override; #endif + std::list generatePlayerTurnOrder() const; + friend class CVCMIServer; private: std::unique_ptr serverEventBus; @@ -373,8 +373,9 @@ private: #endif void reinitScripting(); + void deserializationFix(); + - std::list generatePlayerTurnOrder() const; void makeStackDoNothing(const CStack * next); void getVictoryLossMessage(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult, InfoWindow & out) const; diff --git a/server/HeroPoolProcessor.cpp b/server/HeroPoolProcessor.cpp index 572cc4e3b..61cd683f6 100644 --- a/server/HeroPoolProcessor.cpp +++ b/server/HeroPoolProcessor.cpp @@ -32,6 +32,29 @@ HeroPoolProcessor::HeroPoolProcessor(CGameHandler * gameHandler) { } +bool HeroPoolProcessor::playerEndedTurn(const PlayerColor & player) +{ + // our player is acting right now and have not ended turn + if (player == gameHandler->gameState()->currentPlayer) + return false; + + auto turnOrder = gameHandler->generatePlayerTurnOrder(); + + for (auto const & entry : turnOrder) + { + // our player is yet to start turn + if (entry == gameHandler->gameState()->currentPlayer) + return false; + + // our player have finished turn + if (entry == player) + return true; + } + + assert(false); + return false; +} + TavernHeroSlot HeroPoolProcessor::selectSlotForRole(const PlayerColor & player, TavernSlotRole roleID) { const auto & hpool = gameHandler->gameState()->hpool; @@ -67,8 +90,12 @@ TavernHeroSlot HeroPoolProcessor::selectSlotForRole(const PlayerColor & player, void HeroPoolProcessor::onHeroSurrendered(const PlayerColor & color, const CGHeroInstance * hero) { SetAvailableHero sah; - sah.slotID = selectSlotForRole(color, TavernSlotRole::SURRENDERED); - sah.roleID = TavernSlotRole::SURRENDERED; + if (playerEndedTurn(color)) + sah.roleID = TavernSlotRole::SURRENDERED_TODAY; + else + sah.roleID = TavernSlotRole::SURRENDERED; + + sah.slotID = selectSlotForRole(color, sah.roleID); sah.player = color; sah.hid = hero->subID; sah.army.clear(); @@ -79,8 +106,12 @@ void HeroPoolProcessor::onHeroSurrendered(const PlayerColor & color, const CGHer void HeroPoolProcessor::onHeroEscaped(const PlayerColor & color, const CGHeroInstance * hero) { SetAvailableHero sah; - sah.slotID = selectSlotForRole(color, TavernSlotRole::RETREATED); - sah.roleID = TavernSlotRole::RETREATED; + if (playerEndedTurn(color)) + sah.roleID = TavernSlotRole::RETREATED_TODAY; + else + sah.roleID = TavernSlotRole::RETREATED; + + sah.slotID = selectSlotForRole(color, sah.roleID); sah.player = color; sah.hid = hero->subID; @@ -131,10 +162,26 @@ void HeroPoolProcessor::selectNewHeroForSlot(const PlayerColor & color, TavernHe void HeroPoolProcessor::onNewWeek(const PlayerColor & color) { - clearHeroFromSlot(color, TavernHeroSlot::NATIVE); - clearHeroFromSlot(color, TavernHeroSlot::RANDOM); - selectNewHeroForSlot(color, TavernHeroSlot::NATIVE, true, true); - selectNewHeroForSlot(color, TavernHeroSlot::RANDOM, false, true); + const auto & hpool = gameHandler->gameState()->hpool; + const auto & heroes = hpool->getHeroesFor(color); + + const auto nativeSlotRole = heroes.size() < 1 ? TavernSlotRole::NONE : hpool->getSlotRole(heroes[0]->type->getId()); + const auto randomSlotRole = heroes.size() < 2 ? TavernSlotRole::NONE : hpool->getSlotRole(heroes[1]->type->getId()); + + bool resetNativeSlot = nativeSlotRole != TavernSlotRole::RETREATED_TODAY && nativeSlotRole != TavernSlotRole::SURRENDERED_TODAY; + bool resetRandomSlot = randomSlotRole != TavernSlotRole::RETREATED_TODAY && randomSlotRole != TavernSlotRole::SURRENDERED_TODAY; + + if (resetNativeSlot) + clearHeroFromSlot(color, TavernHeroSlot::NATIVE); + + if (resetRandomSlot) + clearHeroFromSlot(color, TavernHeroSlot::RANDOM); + + if (resetNativeSlot) + selectNewHeroForSlot(color, TavernHeroSlot::NATIVE, true, true); + + if (resetRandomSlot) + selectNewHeroForSlot(color, TavernHeroSlot::RANDOM, false, true); } bool HeroPoolProcessor::hireHero(const CGObjectInstance *obj, const HeroTypeID & heroToRecruit, const PlayerColor & player) diff --git a/server/HeroPoolProcessor.h b/server/HeroPoolProcessor.h index 3b61f369f..38b24bb32 100644 --- a/server/HeroPoolProcessor.h +++ b/server/HeroPoolProcessor.h @@ -17,7 +17,6 @@ class PlayerColor; class CGHeroInstance; class HeroTypeID; class CGObjectInstance; -class FactionID; class CRandomGenerator; class CHeroClass; @@ -43,6 +42,8 @@ class HeroPoolProcessor : boost::noncopyable CRandomGenerator & getRandomGenerator(const PlayerColor & player); TavernHeroSlot selectSlotForRole(const PlayerColor & player, TavernSlotRole roleID); + + bool playerEndedTurn(const PlayerColor & player); public: CGameHandler * gameHandler;