diff --git a/lib/CStack.cpp b/lib/CStack.cpp index df2a38fa2..c788d7be3 100644 --- a/lib/CStack.cpp +++ b/lib/CStack.cpp @@ -35,6 +35,7 @@ CStack::CStack(const CStackInstance * Base, const PlayerColor & O, int I, Battle side(Side) { health.init(); //??? + doubleWideCached = battle::CUnitState::doubleWide(); } CStack::CStack(): @@ -55,6 +56,7 @@ CStack::CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I side(Side) { health.init(); //??? + doubleWideCached = battle::CUnitState::doubleWide(); } void CStack::localInit(BattleInfo * battleInfo) @@ -404,4 +406,30 @@ void CStack::spendMana(ServerCallback * server, const int spellCost) const server->apply(ssp); } +void CStack::postDeserialize(const CArmedInstance * army, const SlotID & extSlot) +{ + if(extSlot == SlotID::COMMANDER_SLOT_PLACEHOLDER) + { + const auto * hero = dynamic_cast(army); + assert(hero); + base = hero->commander; + } + else if(slot == SlotID::SUMMONED_SLOT_PLACEHOLDER || slot == SlotID::ARROW_TOWERS_SLOT || slot == SlotID::WAR_MACHINES_SLOT) + { + //no external slot possible, so no base stack + base = nullptr; + } + else if(!army || extSlot == SlotID() || !army->hasStackAtSlot(extSlot)) + { + base = nullptr; + logGlobal->warn("%s doesn't have a base stack!", typeID.toEntity(VLC)->getNameSingularTranslated()); + } + else + { + base = &army->getStack(extSlot); + } + + doubleWideCached = battle::CUnitState::doubleWide(); +} + VCMI_LIB_NAMESPACE_END diff --git a/lib/CStack.h b/lib/CStack.h index 23f22cf4f..1faca6104 100644 --- a/lib/CStack.h +++ b/lib/CStack.h @@ -23,7 +23,7 @@ struct BattleStackAttacked; class BattleInfo; //Represents STACK_BATTLE nodes -class DLL_LINKAGE CStack : public CBonusSystemNode, public battle::CUnitState, public battle::IUnitEnvironment +class DLL_LINKAGE CStack final : public CBonusSystemNode, public battle::CUnitState, public battle::IUnitEnvironment { private: ui32 ID = -1; //unique ID of stack @@ -36,6 +36,9 @@ private: SlotID slot; //slot - position in garrison (may be 255 for neutrals/called creatures) + bool doubleWideCached = false; + + void postDeserialize(const CArmedInstance * army, const SlotID & extSlot); public: const CStackInstance * base = nullptr; //garrison slot from which stack originates (nullptr for war machines, summoned cres, etc) @@ -77,6 +80,7 @@ public: BattleSide unitSide() const override; PlayerColor unitOwner() const override; SlotID unitSlot() const override; + bool doubleWide() const override { return doubleWideCached;}; std::string getDescription() const override; @@ -119,26 +123,7 @@ public: h & army; h & extSlot; - if(extSlot == SlotID::COMMANDER_SLOT_PLACEHOLDER) - { - const auto * hero = dynamic_cast(army); - assert(hero); - base = hero->commander; - } - else if(slot == SlotID::SUMMONED_SLOT_PLACEHOLDER || slot == SlotID::ARROW_TOWERS_SLOT || slot == SlotID::WAR_MACHINES_SLOT) - { - //no external slot possible, so no base stack - base = nullptr; - } - else if(!army || extSlot == SlotID() || !army->hasStackAtSlot(extSlot)) - { - base = nullptr; - logGlobal->warn("%s doesn't have a base stack!", typeID.toEntity(VLC)->getNameSingularTranslated()); - } - else - { - base = &army->getStack(extSlot); - } + postDeserialize(army, extSlot); } } @@ -146,4 +131,4 @@ private: const BattleInfo * battle; //do not serialize }; -VCMI_LIB_NAMESPACE_END \ No newline at end of file +VCMI_LIB_NAMESPACE_END diff --git a/lib/battle/CUnitState.h b/lib/battle/CUnitState.h index d018c6625..f07ba27f3 100644 --- a/lib/battle/CUnitState.h +++ b/lib/battle/CUnitState.h @@ -269,7 +269,7 @@ private: void reset(); }; -class DLL_LINKAGE CUnitStateDetached : public CUnitState +class DLL_LINKAGE CUnitStateDetached final : public CUnitState { public: explicit CUnitStateDetached(const IUnitInfo * unit_, const IBonusBearer * bonus_); diff --git a/lib/battle/Unit.cpp b/lib/battle/Unit.cpp index 57a36eb6a..b33eda0f4 100644 --- a/lib/battle/Unit.cpp +++ b/lib/battle/Unit.cpp @@ -107,24 +107,34 @@ const BattleHexArray & Unit::getHexes(BattleHex assumedPos) const return getHexes(assumedPos, doubleWide(), unitSide()); } +BattleHexArray::ArrayOfBattleHexArrays Unit::precomputeUnitHexes(BattleSide side, bool twoHex) +{ + BattleHexArray::ArrayOfBattleHexArrays result; + + for (BattleHex assumedPos = 0; assumedPos < GameConstants::BFIELD_SIZE; ++assumedPos) + { + BattleHexArray hexes; + hexes.insert(assumedPos); + + if(twoHex) + hexes.insert(occupiedHex(assumedPos, twoHex, side)); + + result[assumedPos.toInt()] = std::move(hexes); + } + + return result; +} + const BattleHexArray & Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleSide side) { - static BattleHexArray::ArrayOfBattleHexArrays precomputed[4]; + static const std::array precomputed = { + precomputeUnitHexes(BattleSide::ATTACKER, false), + precomputeUnitHexes(BattleSide::ATTACKER, true), + precomputeUnitHexes(BattleSide::DEFENDER, false), + precomputeUnitHexes(BattleSide::DEFENDER, true), + }; + int index = side == BattleSide::ATTACKER ? 0 : 2; - - if(!precomputed[index + twoHex][assumedPos.toInt()].empty()) - return precomputed[index + twoHex][assumedPos.toInt()]; - - // first run, compute - - BattleHexArray hexes; - hexes.insert(assumedPos); - - if(twoHex) - hexes.insert(occupiedHex(assumedPos, twoHex, side)); - - precomputed[index + twoHex][assumedPos.toInt()] = std::move(hexes); - return precomputed[index + twoHex][assumedPos.toInt()]; } diff --git a/lib/battle/Unit.h b/lib/battle/Unit.h index 9708b124f..794e14b94 100644 --- a/lib/battle/Unit.h +++ b/lib/battle/Unit.h @@ -64,6 +64,8 @@ class CUnitState; class DLL_LINKAGE Unit : public IUnitInfo, public spells::Caster, public virtual IBonusBearer, public ACreature { + static BattleHexArray::ArrayOfBattleHexArrays precomputeUnitHexes(BattleSide side, bool twoHex); + public: virtual ~Unit();