|
@@ -10,142 +10,192 @@
|
|
|
#include "StdInc.h"
|
|
|
#include "TurnInfo.h"
|
|
|
|
|
|
+#include "../IGameCallback.h"
|
|
|
+#include "../IGameSettings.h"
|
|
|
#include "../TerrainHandler.h"
|
|
|
#include "../VCMI_Lib.h"
|
|
|
#include "../bonuses/BonusList.h"
|
|
|
+#include "../json/JsonNode.h"
|
|
|
#include "../mapObjects/CGHeroInstance.h"
|
|
|
#include "../mapObjects/MiscObjects.h"
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_BEGIN
|
|
|
|
|
|
-TurnInfo::BonusCache::BonusCache(const TConstBonusListPtr & bl)
|
|
|
+TConstBonusListPtr TurnInfoBonusList::getBonusList(const CGHeroInstance * target, const CSelector & bonusSelector)
|
|
|
{
|
|
|
- for(const auto & terrain : VLC->terrainTypeHandler->objects)
|
|
|
- {
|
|
|
- auto selector = Selector::typeSubtype(BonusType::NO_TERRAIN_PENALTY, BonusSubtypeID(terrain->getId()));
|
|
|
- if (bl->getFirst(selector))
|
|
|
- noTerrainPenalty.insert(terrain->getId());
|
|
|
- }
|
|
|
+ std::lock_guard guard(bonusListMutex);
|
|
|
+
|
|
|
+ if (target->getTreeVersion() == bonusListVersion)
|
|
|
+ return bonusList;
|
|
|
|
|
|
- freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::FREE_SHIP_BOARDING)));
|
|
|
- flyingMovement = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::FLYING_MOVEMENT)));
|
|
|
- flyingMovementVal = bl->valOfBonuses(Selector::type()(BonusType::FLYING_MOVEMENT));
|
|
|
- waterWalking = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::WATER_WALKING)));
|
|
|
- waterWalkingVal = bl->valOfBonuses(Selector::type()(BonusType::WATER_WALKING));
|
|
|
- pathfindingVal = bl->valOfBonuses(Selector::type()(BonusType::ROUGH_TERRAIN_DISCOUNT));
|
|
|
+ bonusList = target->getBonuses(bonusSelector);
|
|
|
+ bonusListVersion = target->getTreeVersion();
|
|
|
+
|
|
|
+ return bonusList;
|
|
|
}
|
|
|
|
|
|
-TurnInfo::TurnInfo(const CGHeroInstance * Hero, const int turn):
|
|
|
- hero(Hero),
|
|
|
- maxMovePointsLand(-1),
|
|
|
- maxMovePointsWater(-1),
|
|
|
- turn(turn)
|
|
|
+int TurnInfo::hasWaterWalking() const
|
|
|
{
|
|
|
- bonuses = hero->getAllBonuses(Selector::days(turn), Selector::all, "all_days" + std::to_string(turn));
|
|
|
- bonusCache = std::make_unique<BonusCache>(bonuses);
|
|
|
- nativeTerrain = hero->getNativeTerrain();
|
|
|
+ return waterWalkingTest;
|
|
|
}
|
|
|
|
|
|
-bool TurnInfo::isLayerAvailable(const EPathfindingLayer & layer) const
|
|
|
+int TurnInfo::hasFlyingMovement() const
|
|
|
{
|
|
|
- switch(layer.toEnum())
|
|
|
- {
|
|
|
- case EPathfindingLayer::AIR:
|
|
|
- if(hero && hero->boat && hero->boat->layer == EPathfindingLayer::AIR)
|
|
|
- break;
|
|
|
+ return flyingMovementTest;
|
|
|
+}
|
|
|
|
|
|
- if(!hasBonusOfType(BonusType::FLYING_MOVEMENT))
|
|
|
- return false;
|
|
|
+int TurnInfo::hasNoTerrainPenalty(const TerrainId &terrain) const
|
|
|
+{
|
|
|
+ return noterrainPenalty[terrain.num];
|
|
|
+}
|
|
|
|
|
|
- break;
|
|
|
+int TurnInfo::hasFreeShipBoarding() const
|
|
|
+{
|
|
|
+ return freeShipBoardingTest;
|
|
|
+}
|
|
|
|
|
|
- case EPathfindingLayer::WATER:
|
|
|
- if(hero && hero->boat && hero->boat->layer == EPathfindingLayer::WATER)
|
|
|
- break;
|
|
|
+int TurnInfo::getFlyingMovementValue() const
|
|
|
+{
|
|
|
+ return flyingMovementValue;
|
|
|
+}
|
|
|
|
|
|
- if(!hasBonusOfType(BonusType::WATER_WALKING))
|
|
|
- return false;
|
|
|
+int TurnInfo::getWaterWalkingValue() const
|
|
|
+{
|
|
|
+ return waterWalkingValue;
|
|
|
+}
|
|
|
|
|
|
- break;
|
|
|
- }
|
|
|
+int TurnInfo::getRoughTerrainDiscountValue() const
|
|
|
+{
|
|
|
+ return roughTerrainDiscountValue;
|
|
|
+}
|
|
|
|
|
|
- return true;
|
|
|
+int TurnInfo::getMovePointsLimitLand() const
|
|
|
+{
|
|
|
+ return movePointsLimitLand;
|
|
|
}
|
|
|
|
|
|
-bool TurnInfo::hasBonusOfType(BonusType type) const
|
|
|
+int TurnInfo::getMovePointsLimitWater() const
|
|
|
{
|
|
|
- return hasBonusOfType(type, BonusSubtypeID());
|
|
|
+ return movePointsLimitWater;
|
|
|
}
|
|
|
|
|
|
-bool TurnInfo::hasBonusOfType(BonusType type, BonusSubtypeID subtype) const
|
|
|
+TurnInfo::TurnInfo(TurnInfoCache * sharedCache, const CGHeroInstance * target, int Turn)
|
|
|
+ : target(target)
|
|
|
+ , noterrainPenalty(VLC->terrainTypeHandler->size())
|
|
|
{
|
|
|
- switch(type)
|
|
|
+ CSelector daySelector = Selector::days(Turn);
|
|
|
+
|
|
|
+ int lowestSpeed;
|
|
|
+ if (target->getTreeVersion() == sharedCache->heroLowestSpeedVersion)
|
|
|
{
|
|
|
- case BonusType::FREE_SHIP_BOARDING:
|
|
|
- return bonusCache->freeShipBoarding;
|
|
|
- case BonusType::FLYING_MOVEMENT:
|
|
|
- return bonusCache->flyingMovement;
|
|
|
- case BonusType::WATER_WALKING:
|
|
|
- return bonusCache->waterWalking;
|
|
|
- case BonusType::NO_TERRAIN_PENALTY:
|
|
|
- return bonusCache->noTerrainPenalty.count(subtype.as<TerrainId>());
|
|
|
+ lowestSpeed = sharedCache->heroLowestSpeedValue;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ lowestSpeed = target->getLowestCreatureSpeed();
|
|
|
+ sharedCache->heroLowestSpeedValue = lowestSpeed;
|
|
|
+ sharedCache->heroLowestSpeedVersion = target->getTreeVersion();
|
|
|
}
|
|
|
|
|
|
- return static_cast<bool>(
|
|
|
- bonuses->getFirst(Selector::type()(type).And(Selector::subtype()(subtype))));
|
|
|
-}
|
|
|
+ {
|
|
|
+ static const CSelector selector = Selector::type()(BonusType::WATER_WALKING);
|
|
|
+ const auto & bonuses = sharedCache->waterWalking.getBonusList(target, selector);
|
|
|
+ waterWalkingTest = bonuses->getFirst(daySelector) != nullptr;
|
|
|
+ waterWalkingValue = bonuses->valOfBonuses(daySelector);
|
|
|
+ }
|
|
|
|
|
|
-int TurnInfo::valOfBonuses(BonusType type) const
|
|
|
-{
|
|
|
- return valOfBonuses(type, BonusSubtypeID());
|
|
|
-}
|
|
|
+ {
|
|
|
+ static const CSelector selector = Selector::type()(BonusType::FLYING_MOVEMENT);
|
|
|
+ const auto & bonuses = sharedCache->flyingMovement.getBonusList(target, selector);
|
|
|
+ flyingMovementTest = bonuses->getFirst(daySelector) != nullptr;
|
|
|
+ flyingMovementValue = bonuses->valOfBonuses(daySelector);
|
|
|
+ }
|
|
|
|
|
|
-int TurnInfo::valOfBonuses(BonusType type, BonusSubtypeID subtype) const
|
|
|
-{
|
|
|
- switch(type)
|
|
|
{
|
|
|
- case BonusType::FLYING_MOVEMENT:
|
|
|
- return bonusCache->flyingMovementVal;
|
|
|
- case BonusType::WATER_WALKING:
|
|
|
- return bonusCache->waterWalkingVal;
|
|
|
- case BonusType::ROUGH_TERRAIN_DISCOUNT:
|
|
|
- return bonusCache->pathfindingVal;
|
|
|
+ static const CSelector selector = Selector::type()(BonusType::FREE_SHIP_BOARDING);
|
|
|
+ const auto & bonuses = sharedCache->freeShipBoarding.getBonusList(target, selector);
|
|
|
+ freeShipBoardingTest = bonuses->getFirst(daySelector) != nullptr;
|
|
|
}
|
|
|
|
|
|
- return bonuses->valOfBonuses(Selector::type()(type).And(Selector::subtype()(subtype)));
|
|
|
-}
|
|
|
+ {
|
|
|
+ static const CSelector selector = Selector::type()(BonusType::ROUGH_TERRAIN_DISCOUNT);
|
|
|
+ const auto & bonuses = sharedCache->roughTerrainDiscount.getBonusList(target, selector);
|
|
|
+ roughTerrainDiscountValue = bonuses->getFirst(daySelector) != nullptr;
|
|
|
+ }
|
|
|
|
|
|
-int TurnInfo::getMaxMovePoints(const EPathfindingLayer & layer) const
|
|
|
-{
|
|
|
- if(maxMovePointsLand == -1)
|
|
|
- maxMovePointsLand = hero->movementPointsLimitCached(true, this);
|
|
|
- if(maxMovePointsWater == -1)
|
|
|
- maxMovePointsWater = hero->movementPointsLimitCached(false, this);
|
|
|
+ {
|
|
|
+ static const CSelector selector = Selector::typeSubtype(BonusType::MOVEMENT, BonusCustomSubtype::heroMovementSea);
|
|
|
+ const auto & vectorSea = target->cb->getSettings().getValue(EGameSettings::HEROES_MOVEMENT_POINTS_SEA).Vector();
|
|
|
+ const auto & bonuses = sharedCache->movementPointsLimitWater.getBonusList(target, selector);
|
|
|
+ int baseMovementPointsSea;
|
|
|
+ if (lowestSpeed < vectorSea.size())
|
|
|
+ baseMovementPointsSea = vectorSea[lowestSpeed].Integer();
|
|
|
+ else
|
|
|
+ baseMovementPointsSea = vectorSea.back().Integer();
|
|
|
+
|
|
|
+ movePointsLimitWater = bonuses->valOfBonuses(daySelector, baseMovementPointsSea);
|
|
|
+ }
|
|
|
|
|
|
- return layer == EPathfindingLayer::SAIL ? maxMovePointsWater : maxMovePointsLand;
|
|
|
+ {
|
|
|
+ static const CSelector selector = Selector::typeSubtype(BonusType::MOVEMENT, BonusCustomSubtype::heroMovementSea);
|
|
|
+ const auto & vectorLand = target->cb->getSettings().getValue(EGameSettings::HEROES_MOVEMENT_POINTS_LAND).Vector();
|
|
|
+ const auto & bonuses = sharedCache->movementPointsLimitLand.getBonusList(target, selector);
|
|
|
+ int baseMovementPointsLand;
|
|
|
+ if (lowestSpeed < vectorLand.size())
|
|
|
+ baseMovementPointsLand = vectorLand[lowestSpeed].Integer();
|
|
|
+ else
|
|
|
+ baseMovementPointsLand = vectorLand.back().Integer();
|
|
|
+
|
|
|
+ movePointsLimitLand = bonuses->valOfBonuses(daySelector, baseMovementPointsLand);
|
|
|
+ }
|
|
|
+
|
|
|
+ {
|
|
|
+ static const CSelector selector = Selector::type()(BonusType::NO_TERRAIN_PENALTY);
|
|
|
+ const auto & bonuses = sharedCache->noTerrainPenalty.getBonusList(target, selector);
|
|
|
+ for (const auto & bonus : *bonuses)
|
|
|
+ {
|
|
|
+ TerrainId affectedTerrain = bonus->subtype.as<TerrainId>();
|
|
|
+ noterrainPenalty.at(affectedTerrain.num) = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ const auto nativeTerrain = target->getNativeTerrain();
|
|
|
+ if (nativeTerrain.hasValue())
|
|
|
+ noterrainPenalty.at(nativeTerrain.num) = true;
|
|
|
+
|
|
|
+ if (nativeTerrain == ETerrainId::ANY_TERRAIN)
|
|
|
+ boost::range::fill(noterrainPenalty, true);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-void TurnInfo::updateHeroBonuses(BonusType type) const
|
|
|
+bool TurnInfo::isLayerAvailable(const EPathfindingLayer & layer) const
|
|
|
{
|
|
|
- switch(type)
|
|
|
+ switch(layer.toEnum())
|
|
|
{
|
|
|
- case BonusType::FREE_SHIP_BOARDING:
|
|
|
- bonusCache->freeShipBoarding = static_cast<bool>(bonuses->getFirst(Selector::type()(BonusType::FREE_SHIP_BOARDING)));
|
|
|
- break;
|
|
|
- case BonusType::FLYING_MOVEMENT:
|
|
|
- bonusCache->flyingMovement = static_cast<bool>(bonuses->getFirst(Selector::type()(BonusType::FLYING_MOVEMENT)));
|
|
|
- bonusCache->flyingMovementVal = bonuses->valOfBonuses(Selector::type()(BonusType::FLYING_MOVEMENT));
|
|
|
- break;
|
|
|
- case BonusType::WATER_WALKING:
|
|
|
- bonusCache->waterWalking = static_cast<bool>(bonuses->getFirst(Selector::type()(BonusType::WATER_WALKING)));
|
|
|
- bonusCache->waterWalkingVal = bonuses->valOfBonuses(Selector::type()(BonusType::WATER_WALKING));
|
|
|
+ case EPathfindingLayer::AIR:
|
|
|
+ if(target && target->boat && target->boat->layer == EPathfindingLayer::AIR)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if(!hasFlyingMovement())
|
|
|
+ return false;
|
|
|
+
|
|
|
break;
|
|
|
- case BonusType::ROUGH_TERRAIN_DISCOUNT:
|
|
|
- bonusCache->pathfindingVal = bonuses->valOfBonuses(Selector::type()(BonusType::ROUGH_TERRAIN_DISCOUNT));
|
|
|
+
|
|
|
+ case EPathfindingLayer::WATER:
|
|
|
+ if(target && target->boat && target->boat->layer == EPathfindingLayer::WATER)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if(!hasWaterWalking())
|
|
|
+ return false;
|
|
|
+
|
|
|
break;
|
|
|
- default:
|
|
|
- bonuses = hero->getAllBonuses(Selector::days(turn), Selector::all, "all_days" + std::to_string(turn));
|
|
|
}
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+int TurnInfo::getMaxMovePoints(const EPathfindingLayer & layer) const
|
|
|
+{
|
|
|
+ return layer == EPathfindingLayer::SAIL ? getMovePointsLimitWater() : getMovePointsLimitLand();
|
|
|
}
|
|
|
|
|
|
VCMI_LIB_NAMESPACE_END
|