mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge pull request #4437 from IvanSavenko/battle_sides
Unified handling of battle sides ID's
This commit is contained in:
commit
49c5f650f7
@ -26,7 +26,7 @@ void DamageCache::cacheDamage(const battle::Unit * attacker, const battle::Unit
|
||||
}
|
||||
|
||||
|
||||
void DamageCache::buildDamageCache(std::shared_ptr<HypotheticBattle> hb, int side)
|
||||
void DamageCache::buildDamageCache(std::shared_ptr<HypotheticBattle> hb, BattleSide side)
|
||||
{
|
||||
auto stacks = hb->battleGetUnitsIf([=](const battle::Unit * u) -> bool
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
void cacheDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> hb);
|
||||
int64_t getDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> hb);
|
||||
int64_t getOriginalDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> hb);
|
||||
void buildDamageCache(std::shared_ptr<HypotheticBattle> hb, int side);
|
||||
void buildDamageCache(std::shared_ptr<HypotheticBattle> hb, BattleSide side);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
@ -32,7 +32,7 @@
|
||||
#define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl))
|
||||
|
||||
CBattleAI::CBattleAI()
|
||||
: side(-1),
|
||||
: side(BattleSide::NONE),
|
||||
wasWaitingForRealize(false),
|
||||
wasUnlockingGs(false)
|
||||
{
|
||||
@ -100,7 +100,7 @@ void CBattleAI::yourTacticPhase(const BattleID & battleID, int distance)
|
||||
cb->battleMakeTacticAction(battleID, BattleAction::makeEndOFTacticPhase(cb->getBattle(battleID)->battleGetTacticsSide()));
|
||||
}
|
||||
|
||||
static float getStrengthRatio(std::shared_ptr<CBattleInfoCallback> cb, int side)
|
||||
static float getStrengthRatio(std::shared_ptr<CBattleInfoCallback> cb, BattleSide side)
|
||||
{
|
||||
auto stacks = cb->battleGetAllStacks();
|
||||
auto our = 0;
|
||||
@ -243,7 +243,7 @@ BattleAction CBattleAI::useCatapult(const BattleID & battleID, const CStack * st
|
||||
return attack;
|
||||
}
|
||||
|
||||
void CBattleAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed)
|
||||
void CBattleAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide Side, bool replayAllowed)
|
||||
{
|
||||
LOG_TRACE(logAi);
|
||||
side = Side;
|
||||
|
@ -27,7 +27,7 @@ struct CurrentOffensivePotential
|
||||
std::map<const CStack *, PotentialTargets> ourAttacks;
|
||||
std::map<const CStack *, PotentialTargets> enemyAttacks;
|
||||
|
||||
CurrentOffensivePotential(ui8 side)
|
||||
CurrentOffensivePotential(BattleSide side)
|
||||
{
|
||||
for(auto stack : cbc->battleGetStacks())
|
||||
{
|
||||
@ -54,7 +54,7 @@ struct CurrentOffensivePotential
|
||||
|
||||
class CBattleAI : public CBattleGameInterface
|
||||
{
|
||||
int side;
|
||||
BattleSide side;
|
||||
std::shared_ptr<CBattleCallback> cb;
|
||||
std::shared_ptr<Environment> env;
|
||||
|
||||
@ -80,7 +80,7 @@ public:
|
||||
BattleAction useCatapult(const BattleID & battleID, const CStack *stack);
|
||||
BattleAction useHealingTent(const BattleID & battleID, const CStack *stack);
|
||||
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side, bool replayAllowed) override;
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) override;
|
||||
//void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero
|
||||
//void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero
|
||||
//void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack
|
||||
@ -93,7 +93,7 @@ public:
|
||||
//void battleSpellCast(const BattleSpellCast *sc) override;
|
||||
//void battleStacksEffectsSet(const SetStackEffect & sse) override;//called when a specific effect is set to stacks
|
||||
//void battleTriggerEffect(const BattleTriggerEffect & bte) override;
|
||||
//void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
//void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
//void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||
AutocombatPreferences autobattlePreferences = AutocombatPreferences();
|
||||
};
|
||||
|
@ -686,7 +686,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
|
||||
spellcast.spell = castToPerform.spell->id;
|
||||
spellcast.setTarget(castToPerform.dest);
|
||||
spellcast.side = side;
|
||||
spellcast.stackNumber = (!side) ? -1 : -2;
|
||||
spellcast.stackNumber = -1;
|
||||
cb->battleMakeSpellAction(battleID, spellcast);
|
||||
activeActionMade = true;
|
||||
|
||||
|
@ -33,7 +33,7 @@ class BattleEvaluator
|
||||
std::optional<AttackPossibility> cachedAttack;
|
||||
PlayerColor playerID;
|
||||
BattleID battleID;
|
||||
int side;
|
||||
BattleSide side;
|
||||
float cachedScore;
|
||||
DamageCache damageCache;
|
||||
float strengthRatio;
|
||||
@ -54,7 +54,7 @@ public:
|
||||
const battle::Unit * activeStack,
|
||||
PlayerColor playerID,
|
||||
BattleID battleID,
|
||||
int side,
|
||||
BattleSide side,
|
||||
float strengthRatio)
|
||||
:scoreEvaluator(cb->getBattle(battleID), env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), strengthRatio(strengthRatio), battleID(battleID)
|
||||
{
|
||||
@ -73,7 +73,7 @@ public:
|
||||
const battle::Unit * activeStack,
|
||||
PlayerColor playerID,
|
||||
BattleID battleID,
|
||||
int side,
|
||||
BattleSide side,
|
||||
float strengthRatio)
|
||||
:scoreEvaluator(cb->getBattle(battleID), env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), hb(hb), damageCache(damageCache), strengthRatio(strengthRatio), battleID(battleID)
|
||||
{
|
||||
|
@ -500,7 +500,7 @@ BattleScore BattleExchangeEvaluator::calculateExchange(
|
||||
logAi->trace("Battle exchange at %d", ap.attack.shooting ? ap.dest.hex : ap.from.hex);
|
||||
#endif
|
||||
|
||||
if(cb->battleGetMySide() == BattlePerspective::LEFT_SIDE
|
||||
if(cb->battleGetMySide() == BattleSide::LEFT_SIDE
|
||||
&& cb->battleGetGateState() == EGateState::BLOCKED
|
||||
&& ap.attack.defender->coversPos(BattleHex::GATE_BRIDGE))
|
||||
{
|
||||
|
@ -116,7 +116,7 @@ uint32_t StackWithBonuses::unitId() const
|
||||
return id;
|
||||
}
|
||||
|
||||
ui8 StackWithBonuses::unitSide() const
|
||||
BattleSide StackWithBonuses::unitSide() const
|
||||
{
|
||||
return side;
|
||||
}
|
||||
@ -467,7 +467,7 @@ int64_t HypotheticBattle::getActualDamage(const DamageRange & damage, int32_t at
|
||||
return (damage.min + damage.max) / 2;
|
||||
}
|
||||
|
||||
std::vector<SpellID> HypotheticBattle::getUsedSpells(ui8 side) const
|
||||
std::vector<SpellID> HypotheticBattle::getUsedSpells(BattleSide side) const
|
||||
{
|
||||
// TODO
|
||||
return {};
|
||||
|
@ -85,7 +85,7 @@ public:
|
||||
int32_t unitBaseAmount() const override;
|
||||
|
||||
uint32_t unitId() const override;
|
||||
ui8 unitSide() const override;
|
||||
BattleSide unitSide() const override;
|
||||
PlayerColor unitOwner() const override;
|
||||
SlotID unitSlot() const override;
|
||||
|
||||
@ -111,7 +111,7 @@ private:
|
||||
const CCreature * type;
|
||||
ui32 baseAmount;
|
||||
uint32_t id;
|
||||
ui8 side;
|
||||
BattleSide side;
|
||||
PlayerColor player;
|
||||
SlotID slot;
|
||||
};
|
||||
@ -158,7 +158,7 @@ public:
|
||||
uint32_t nextUnitId() const override;
|
||||
|
||||
int64_t getActualDamage(const DamageRange & damage, int32_t attackerCount, vstd::RNG & rng) const override;
|
||||
std::vector<SpellID> getUsedSpells(ui8 side) const override;
|
||||
std::vector<SpellID> getUsedSpells(BattleSide side) const override;
|
||||
int3 getLocation() const override;
|
||||
bool isCreatureBank() const override;
|
||||
|
||||
|
@ -1148,7 +1148,7 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re
|
||||
}
|
||||
}
|
||||
|
||||
void AIGateway::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed)
|
||||
void AIGateway::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed)
|
||||
{
|
||||
NET_EVENT_HANDLER;
|
||||
assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE);
|
||||
|
@ -156,7 +156,7 @@ public:
|
||||
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
|
||||
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;
|
||||
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override;
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) override;
|
||||
void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override;
|
||||
|
||||
void makeTurn();
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "../../lib/CRandomGenerator.h"
|
||||
|
||||
CStupidAI::CStupidAI()
|
||||
: side(-1)
|
||||
: side(BattleSide::NONE)
|
||||
, wasWaitingForRealize(false)
|
||||
, wasUnlockingGs(false)
|
||||
{
|
||||
@ -262,7 +262,7 @@ void CStupidAI::battleStacksEffectsSet(const BattleID & battleID, const SetStack
|
||||
print("battleStacksEffectsSet called");
|
||||
}
|
||||
|
||||
void CStupidAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed)
|
||||
void CStupidAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide Side, bool replayAllowed)
|
||||
{
|
||||
print("battleStart called");
|
||||
side = Side;
|
||||
|
@ -17,7 +17,7 @@ class EnemyInfo;
|
||||
|
||||
class CStupidAI : public CBattleGameInterface
|
||||
{
|
||||
int side;
|
||||
BattleSide side;
|
||||
std::shared_ptr<CBattleCallback> cb;
|
||||
std::shared_ptr<Environment> env;
|
||||
|
||||
@ -47,7 +47,7 @@ public:
|
||||
void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override;
|
||||
void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override;//called when a specific effect is set to stacks
|
||||
//void battleTriggerEffect(const BattleTriggerEffect & bte) override;
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||
|
||||
private:
|
||||
|
@ -1566,7 +1566,7 @@ void VCAI::completeGoal(Goals::TSubgoal goal)
|
||||
|
||||
}
|
||||
|
||||
void VCAI::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed)
|
||||
void VCAI::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed)
|
||||
{
|
||||
NET_EVENT_HANDLER;
|
||||
assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE);
|
||||
|
@ -187,7 +187,7 @@ public:
|
||||
void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor, QueryID queryID) override;
|
||||
void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
|
||||
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override;
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed) override;
|
||||
void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override;
|
||||
std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override;
|
||||
|
||||
|
@ -624,7 +624,7 @@ void CPlayerInterface::battleStartBefore(const BattleID & battleID, const CCreat
|
||||
waitForAllDialogs();
|
||||
}
|
||||
|
||||
void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed)
|
||||
void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
|
||||
|
@ -160,7 +160,7 @@ protected: // Call-ins from server, should not be called directly, but only via
|
||||
void battleTriggerEffect(const BattleID & battleID, const BattleTriggerEffect & bte) override; //various one-shot effect
|
||||
void battleStacksAttacked(const BattleID & battleID, const std::vector<BattleStackAttacked> & bsa, bool ranged) override;
|
||||
void battleStartBefore(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) override; //called by engine just before battle starts; side=0 - left, side=1 - right
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
void battleUnitsChanged(const BattleID & battleID, const std::vector<UnitChanges> & units) override;
|
||||
void battleObstaclesChanged(const BattleID & battleID, const std::vector<ObstacleChanges> & obstacles) override;
|
||||
void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||
|
@ -443,8 +443,8 @@ void CClient::battleStarted(const BattleInfo * info)
|
||||
{
|
||||
std::shared_ptr<CPlayerInterface> att;
|
||||
std::shared_ptr<CPlayerInterface> def;
|
||||
auto & leftSide = info->sides[0];
|
||||
auto & rightSide = info->sides[1];
|
||||
const auto & leftSide = info->getSide(BattleSide::LEFT_SIDE);
|
||||
const auto & rightSide = info->getSide(BattleSide::RIGHT_SIDE);
|
||||
|
||||
for(auto & battleCb : battleCallbacks)
|
||||
{
|
||||
@ -453,17 +453,17 @@ void CClient::battleStarted(const BattleInfo * info)
|
||||
}
|
||||
|
||||
//If quick combat is not, do not prepare interfaces for battleint
|
||||
auto callBattleStart = [&](PlayerColor color, ui8 side)
|
||||
auto callBattleStart = [&](PlayerColor color, BattleSide side)
|
||||
{
|
||||
if(vstd::contains(battleints, color))
|
||||
battleints[color]->battleStart(info->battleID, leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side, info->replayAllowed);
|
||||
};
|
||||
|
||||
callBattleStart(leftSide.color, 0);
|
||||
callBattleStart(rightSide.color, 1);
|
||||
callBattleStart(PlayerColor::UNFLAGGABLE, 1);
|
||||
callBattleStart(leftSide.color, BattleSide::LEFT_SIDE);
|
||||
callBattleStart(rightSide.color, BattleSide::RIGHT_SIDE);
|
||||
callBattleStart(PlayerColor::UNFLAGGABLE, BattleSide::RIGHT_SIDE);
|
||||
if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool())
|
||||
callBattleStart(PlayerColor::SPECTATOR, 1);
|
||||
callBattleStart(PlayerColor::SPECTATOR, BattleSide::RIGHT_SIDE);
|
||||
|
||||
if(vstd::contains(playerint, leftSide.color) && playerint[leftSide.color]->human)
|
||||
att = std::dynamic_pointer_cast<CPlayerInterface>(playerint[leftSide.color]);
|
||||
@ -480,9 +480,9 @@ void CClient::battleStarted(const BattleInfo * info)
|
||||
{
|
||||
auto side = interface->cb->getBattle(info->battleID)->playerToSide(interface->playerID);
|
||||
|
||||
if(interface->playerID == info->sides[info->tacticsSide].color)
|
||||
if(interface->playerID == info->getSide(info->tacticsSide).color)
|
||||
{
|
||||
auto action = BattleAction::makeEndOFTacticPhase(*side);
|
||||
auto action = BattleAction::makeEndOFTacticPhase(side);
|
||||
interface->cb->battleMakeTacticAction(info->battleID, action);
|
||||
}
|
||||
}
|
||||
@ -514,7 +514,7 @@ void CClient::battleStarted(const BattleInfo * info)
|
||||
|
||||
if(info->tacticDistance)
|
||||
{
|
||||
auto tacticianColor = info->sides[info->tacticsSide].color;
|
||||
auto tacticianColor = info->getSide(info->tacticsSide).color;
|
||||
|
||||
if (vstd::contains(battleints, tacticianColor))
|
||||
battleints[tacticianColor]->yourTacticPhase(info->battleID, info->tacticDistance);
|
||||
@ -523,9 +523,11 @@ void CClient::battleStarted(const BattleInfo * info)
|
||||
|
||||
void CClient::battleFinished(const BattleID & battleID)
|
||||
{
|
||||
for(auto & side : gs->getBattle(battleID)->sides)
|
||||
if(battleCallbacks.count(side.color))
|
||||
battleCallbacks[side.color]->onBattleEnded(battleID);
|
||||
for(auto side : { BattleSide::ATTACKER, BattleSide::DEFENDER })
|
||||
{
|
||||
if(battleCallbacks.count(gs->getBattle(battleID)->getSide(side).color))
|
||||
battleCallbacks[gs->getBattle(battleID)->getSide(side).color]->onBattleEnded(battleID);
|
||||
}
|
||||
|
||||
if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool())
|
||||
battleCallbacks[PlayerColor::SPECTATOR]->onBattleEnded(battleID);
|
||||
|
@ -108,8 +108,8 @@ void callBattleInterfaceIfPresentForBothSides(CClient & cl, const BattleID & bat
|
||||
return;
|
||||
}
|
||||
|
||||
callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->sides[0].color, ptr, std::forward<Args2>(args)...);
|
||||
callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->sides[1].color, ptr, std::forward<Args2>(args)...);
|
||||
callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->getSide(BattleSide::ATTACKER).color, ptr, std::forward<Args2>(args)...);
|
||||
callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->getSide(BattleSide::DEFENDER).color, ptr, std::forward<Args2>(args)...);
|
||||
if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool() && LOCPLINT->battleInt)
|
||||
{
|
||||
callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, ptr, std::forward<Args2>(args)...);
|
||||
@ -769,12 +769,12 @@ void ApplyClientNetPackVisitor::visitMapObjectSelectDialog(MapObjectSelectDialog
|
||||
void ApplyFirstClientNetPackVisitor::visitBattleStart(BattleStart & pack)
|
||||
{
|
||||
// Cannot use the usual code because curB is not set yet
|
||||
callOnlyThatBattleInterface(cl, pack.info->sides[0].color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject,
|
||||
pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero);
|
||||
callOnlyThatBattleInterface(cl, pack.info->sides[1].color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject,
|
||||
pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero);
|
||||
callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject,
|
||||
pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero);
|
||||
callOnlyThatBattleInterface(cl, pack.info->getSide(BattleSide::ATTACKER).color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSide(BattleSide::ATTACKER).armyObject, pack.info->getSide(BattleSide::DEFENDER).armyObject,
|
||||
pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSide(BattleSide::DEFENDER).hero);
|
||||
callOnlyThatBattleInterface(cl, pack.info->getSide(BattleSide::DEFENDER).color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSide(BattleSide::ATTACKER).armyObject, pack.info->getSide(BattleSide::DEFENDER).armyObject,
|
||||
pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSide(BattleSide::DEFENDER).hero);
|
||||
callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSide(BattleSide::ATTACKER).armyObject, pack.info->getSide(BattleSide::DEFENDER).armyObject,
|
||||
pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSide(BattleSide::DEFENDER).hero);
|
||||
}
|
||||
|
||||
void ApplyClientNetPackVisitor::visitBattleStart(BattleStart & pack)
|
||||
@ -801,9 +801,9 @@ void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack &
|
||||
PlayerColor playerToCall; //pack.player that will move activated stack
|
||||
if (activated->hasBonusOfType(BonusType::HYPNOTIZED))
|
||||
{
|
||||
playerToCall = (gs.getBattle(pack.battleID)->sides[0].color == activated->unitOwner()
|
||||
? gs.getBattle(pack.battleID)->sides[1].color
|
||||
: gs.getBattle(pack.battleID)->sides[0].color);
|
||||
playerToCall = gs.getBattle(pack.battleID)->getSide(BattleSide::ATTACKER).color == activated->unitOwner()
|
||||
? gs.getBattle(pack.battleID)->getSide(BattleSide::DEFENDER).color
|
||||
: gs.getBattle(pack.battleID)->getSide(BattleSide::ATTACKER).color;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -312,8 +312,8 @@ void BattleActionsController::castThisSpell(SpellID spellID)
|
||||
heroSpellToCast = std::make_shared<BattleAction>();
|
||||
heroSpellToCast->actionType = EActionType::HERO_SPELL;
|
||||
heroSpellToCast->spell = spellID;
|
||||
heroSpellToCast->stackNumber = (owner.attackingHeroInstance->tempOwner == owner.curInt->playerID) ? -1 : -2;
|
||||
heroSpellToCast->side = owner.defendingHeroInstance ? (owner.curInt->playerID == owner.defendingHeroInstance->tempOwner) : false;
|
||||
heroSpellToCast->stackNumber = -1;
|
||||
heroSpellToCast->side = owner.curInt->cb->getBattle(owner.getBattleID())->battleGetMySide();
|
||||
|
||||
//choosing possible targets
|
||||
const CGHeroInstance *castingHero = (owner.attackingHeroInstance->tempOwner == owner.curInt->playerID) ? owner.attackingHeroInstance : owner.defendingHeroInstance;
|
||||
|
@ -229,19 +229,19 @@ void BattleInterface::stacksAreAttacked(std::vector<StackAttackedInfo> attackedI
|
||||
{
|
||||
stacksController->stacksAreAttacked(attackedInfos);
|
||||
|
||||
std::array<int, 2> killedBySide = {0, 0};
|
||||
BattleSideArray<int> killedBySide;
|
||||
|
||||
for(const StackAttackedInfo & attackedInfo : attackedInfos)
|
||||
{
|
||||
ui8 side = attackedInfo.defender->unitSide();
|
||||
BattleSide side = attackedInfo.defender->unitSide();
|
||||
killedBySide.at(side) += attackedInfo.amountKilled;
|
||||
}
|
||||
|
||||
for(ui8 side = 0; side < 2; side++)
|
||||
for(BattleSide side : { BattleSide::ATTACKER, BattleSide::DEFENDER })
|
||||
{
|
||||
if(killedBySide.at(side) > killedBySide.at(1-side))
|
||||
if(killedBySide.at(side) > killedBySide.at(getBattle()->otherSide(side)))
|
||||
setHeroAnimation(side, EHeroAnimType::DEFEAT);
|
||||
else if(killedBySide.at(side) < killedBySide.at(1-side))
|
||||
else if(killedBySide.at(side) < killedBySide.at(getBattle()->otherSide(side)))
|
||||
setHeroAnimation(side, EHeroAnimType::VICTORY);
|
||||
}
|
||||
}
|
||||
@ -271,14 +271,14 @@ void BattleInterface::giveCommand(EActionType action, BattleHex tile, SpellID sp
|
||||
}
|
||||
|
||||
auto side = getBattle()->playerToSide(curInt->playerID);
|
||||
if(!side)
|
||||
if(side == BattleSide::NONE)
|
||||
{
|
||||
logGlobal->error("Player %s is not in battle", curInt->playerID.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
BattleAction ba;
|
||||
ba.side = side.value();
|
||||
ba.side = side;
|
||||
ba.actionType = action;
|
||||
ba.aimToHex(tile);
|
||||
ba.spell = spell;
|
||||
@ -409,7 +409,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
|
||||
}
|
||||
else
|
||||
{
|
||||
auto hero = sc->side ? defendingHero : attackingHero;
|
||||
auto hero = sc->side == BattleSide::DEFENDER ? defendingHero : attackingHero;
|
||||
assert(hero);
|
||||
|
||||
addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]()
|
||||
@ -466,11 +466,11 @@ void BattleInterface::spellCast(const BattleSpellCast * sc)
|
||||
{
|
||||
Point leftHero = Point(15, 30);
|
||||
Point rightHero = Point(755, 30);
|
||||
bool side = sc->side;
|
||||
BattleSide side = sc->side;
|
||||
|
||||
addToAnimationStage(EAnimationEvents::AFTER_HIT, [=](){
|
||||
stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side ? "SP07_A.DEF" : "SP07_B.DEF"), leftHero));
|
||||
stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side ? "SP07_B.DEF" : "SP07_A.DEF"), rightHero));
|
||||
stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side == BattleSide::DEFENDER ? "SP07_A.DEF" : "SP07_B.DEF"), leftHero));
|
||||
stacksController->addNewAnim(new EffectAnimation(*this, AnimationPath::builtin(side == BattleSide::DEFENDER ? "SP07_B.DEF" : "SP07_A.DEF"), rightHero));
|
||||
});
|
||||
}
|
||||
|
||||
@ -483,7 +483,7 @@ void BattleInterface::battleStacksEffectsSet(const SetStackEffect & sse)
|
||||
fieldController->redrawBackgroundWithHexes();
|
||||
}
|
||||
|
||||
void BattleInterface::setHeroAnimation(ui8 side, EHeroAnimType phase)
|
||||
void BattleInterface::setHeroAnimation(BattleSide side, EHeroAnimType phase)
|
||||
{
|
||||
if(side == BattleSide::ATTACKER)
|
||||
{
|
||||
@ -656,7 +656,7 @@ void BattleInterface::tacticPhaseEnd()
|
||||
tacticsMode = false;
|
||||
|
||||
auto side = tacticianInterface->cb->getBattle(battleID)->playerToSide(tacticianInterface->playerID);
|
||||
auto action = BattleAction::makeEndOFTacticPhase(*side);
|
||||
auto action = BattleAction::makeEndOFTacticPhase(side);
|
||||
|
||||
tacticianInterface->cb->battleMakeTacticAction(battleID, action);
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ public:
|
||||
|
||||
void showInterface(Canvas & to);
|
||||
|
||||
void setHeroAnimation(ui8 side, EHeroAnimType phase);
|
||||
void setHeroAnimation(BattleSide side, EHeroAnimType phase);
|
||||
|
||||
void executeSpellCast(); //called when a hero casts a spell
|
||||
|
||||
|
@ -746,7 +746,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
|
||||
labels.push_back(std::make_shared<CLabel>(232, 520, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->translate("vcmi.battleResultsWindow.applyResultsLabel")));
|
||||
}
|
||||
|
||||
if(br.winner == 0) //attacker won
|
||||
if(br.winner == BattleSide::ATTACKER)
|
||||
{
|
||||
labels.push_back(std::make_shared<CLabel>(59, 124, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[410]));
|
||||
}
|
||||
@ -754,8 +754,8 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
|
||||
{
|
||||
labels.push_back(std::make_shared<CLabel>(59, 124, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[411]));
|
||||
}
|
||||
|
||||
if(br.winner == 1)
|
||||
|
||||
if(br.winner == BattleSide::DEFENDER)
|
||||
{
|
||||
labels.push_back(std::make_shared<CLabel>(412, 124, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[410]));
|
||||
}
|
||||
@ -770,15 +770,15 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
|
||||
|
||||
std::string sideNames[2] = {"N/A", "N/A"};
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
{
|
||||
auto heroInfo = owner.cb->getBattle(br.battleID)->battleGetHeroInfo(i);
|
||||
const int xs[] = {21, 392};
|
||||
|
||||
if(heroInfo.portraitSource.isValid()) //attacking hero
|
||||
{
|
||||
icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), heroInfo.getIconIndex(), 0, xs[i], 38));
|
||||
sideNames[i] = heroInfo.name;
|
||||
icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), heroInfo.getIconIndex(), 0, xs[static_cast<int>(i)], 38));
|
||||
sideNames[static_cast<int>(i)] = heroInfo.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -795,8 +795,8 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
|
||||
|
||||
if(best != stacks.end()) //should be always but to be safe...
|
||||
{
|
||||
icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), (*best)->unitType()->getIconIndex(), 0, xs[i], 38));
|
||||
sideNames[i] = (*best)->unitType()->getNamePluralTranslated();
|
||||
icons.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), (*best)->unitType()->getIconIndex(), 0, xs[static_cast<int>(i)], 38));
|
||||
sideNames[static_cast<int>(i)] = (*best)->unitType()->getNamePluralTranslated();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -806,16 +806,16 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
|
||||
labels.push_back(std::make_shared<CLabel>(381, 53, FONT_SMALL, ETextAlignment::BOTTOMRIGHT, Colors::WHITE, sideNames[1]));
|
||||
|
||||
//printing casualties
|
||||
for(int step = 0; step < 2; ++step)
|
||||
for(auto step : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
{
|
||||
if(br.casualties[step].size()==0)
|
||||
{
|
||||
labels.push_back(std::make_shared<CLabel>(235, 360 + 97 * step, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[523]));
|
||||
labels.push_back(std::make_shared<CLabel>(235, 360 + 97 * static_cast<int>(step), FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[523]));
|
||||
}
|
||||
else
|
||||
{
|
||||
int xPos = 235 - ((int)br.casualties[step].size()*32 + ((int)br.casualties[step].size() - 1)*10)/2; //increment by 42 with each picture
|
||||
int yPos = 344 + step * 97;
|
||||
int yPos = 344 + static_cast<int>(step) * 97;
|
||||
for(auto & elem : br.casualties[step])
|
||||
{
|
||||
auto creature = CGI->creatures()->getByIndex(elem.first);
|
||||
@ -842,9 +842,9 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
|
||||
BattleResultResources BattleResultWindow::getResources(const BattleResult & br)
|
||||
{
|
||||
//printing result description
|
||||
bool weAreAttacker = !(owner.cb->getBattle(br.battleID)->battleGetMySide());
|
||||
bool weAreAttacker = owner.cb->getBattle(br.battleID)->battleGetMySide() == BattleSide::ATTACKER;
|
||||
bool weAreDefender = !weAreAttacker;
|
||||
bool weWon = (br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker);
|
||||
bool weWon = (br.winner == BattleSide::ATTACKER && weAreAttacker) || (br.winner == BattleSide::DEFENDER && !weAreAttacker);
|
||||
bool isSiege = owner.cb->getBattle(br.battleID)->battleGetDefendedTown() != nullptr;
|
||||
|
||||
BattleResultResources resources;
|
||||
@ -884,7 +884,7 @@ BattleResultResources BattleResultWindow::getResources(const BattleResult & br)
|
||||
{
|
||||
resources.resultText.appendTextID("core.genrltxt.305");
|
||||
resources.resultText.replaceTextID(ourHero->getNameTranslated());
|
||||
resources.resultText.replaceNumber(br.exp[weAreAttacker ? 0 : 1]);
|
||||
resources.resultText.replaceNumber(br.exp[weAreAttacker ? BattleSide::ATTACKER : BattleSide::DEFENDER]);
|
||||
}
|
||||
}
|
||||
else // we lose
|
||||
|
@ -102,7 +102,7 @@ void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<
|
||||
{
|
||||
auto side = owner.getBattle()->playerToSide(owner.curInt->playerID);
|
||||
|
||||
if(!oi->visibleForSide(side.value(), owner.getBattle()->battleHasNativeStack(side.value())))
|
||||
if(!oi->visibleForSide(side, owner.getBattle()->battleHasNativeStack(side)))
|
||||
continue;
|
||||
|
||||
auto animation = GH.renderHandler().loadAnimation(oi->getAppearAnimation(), EImageBlitMode::ALPHA);
|
||||
|
@ -168,7 +168,7 @@ void CAdventureAI::battleCatapultAttacked(const BattleID & battleID, const Catap
|
||||
}
|
||||
|
||||
void CAdventureAI::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile,
|
||||
const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed)
|
||||
const CGHeroInstance * hero1, const CGHeroInstance * hero2, BattleSide side, bool replayAllowed)
|
||||
{
|
||||
assert(!battleAI);
|
||||
assert(cbc);
|
||||
|
@ -146,7 +146,7 @@ public:
|
||||
|
||||
void battleNewRound(const BattleID & battleID) override;
|
||||
void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override;
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override;
|
||||
void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed) override;
|
||||
void battleStacksAttacked(const BattleID & battleID, const std::vector<BattleStackAttacked> & bsa, bool ranged) override;
|
||||
void actionStarted(const BattleID & battleID, const BattleAction &action) override;
|
||||
void battleNewRoundFirst(const BattleID & battleID) override;
|
||||
|
@ -403,6 +403,7 @@ set(lib_MAIN_HEADERS
|
||||
battle/BattleAttackInfo.h
|
||||
battle/BattleHex.h
|
||||
battle/BattleInfo.h
|
||||
battle/BattleSide.h
|
||||
battle/BattleStateInfoForRetreat.h
|
||||
battle/BattleProxy.h
|
||||
battle/CBattleInfoCallback.h
|
||||
|
@ -24,7 +24,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
///CStack
|
||||
CStack::CStack(const CStackInstance * Base, const PlayerColor & O, int I, ui8 Side, const SlotID & S):
|
||||
CStack::CStack(const CStackInstance * Base, const PlayerColor & O, int I, BattleSide Side, const SlotID & S):
|
||||
CBonusSystemNode(STACK_BATTLE),
|
||||
base(Base),
|
||||
ID(I),
|
||||
@ -45,7 +45,7 @@ CStack::CStack():
|
||||
{
|
||||
}
|
||||
|
||||
CStack::CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I, ui8 Side, const SlotID & S):
|
||||
CStack::CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I, BattleSide Side, const SlotID & S):
|
||||
CBonusSystemNode(STACK_BATTLE),
|
||||
ID(I),
|
||||
type(stack->type),
|
||||
@ -367,7 +367,7 @@ uint32_t CStack::unitId() const
|
||||
return ID;
|
||||
}
|
||||
|
||||
ui8 CStack::unitSide() const
|
||||
BattleSide CStack::unitSide() const
|
||||
{
|
||||
return side;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ private:
|
||||
ui32 baseAmount = -1;
|
||||
|
||||
PlayerColor owner; //owner - player color (255 for neutrals)
|
||||
ui8 side = 1;
|
||||
BattleSide side = BattleSide::NONE;
|
||||
|
||||
SlotID slot; //slot - position in garrison (may be 255 for neutrals/called creatures)
|
||||
|
||||
@ -41,8 +41,8 @@ public:
|
||||
|
||||
BattleHex initialPosition; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
|
||||
|
||||
CStack(const CStackInstance * base, const PlayerColor & O, int I, ui8 Side, const SlotID & S);
|
||||
CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I, ui8 Side, const SlotID & S = SlotID(255));
|
||||
CStack(const CStackInstance * base, const PlayerColor & O, int I, BattleSide Side, const SlotID & S);
|
||||
CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I, BattleSide Side, const SlotID & S = SlotID(255));
|
||||
CStack();
|
||||
~CStack();
|
||||
|
||||
@ -74,7 +74,7 @@ public:
|
||||
int32_t unitBaseAmount() const override;
|
||||
|
||||
uint32_t unitId() const override;
|
||||
ui8 unitSide() const override;
|
||||
BattleSide unitSide() const override;
|
||||
PlayerColor unitOwner() const override;
|
||||
SlotID unitSlot() const override;
|
||||
|
||||
|
@ -68,7 +68,7 @@ public:
|
||||
virtual void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse){};//called when a specific effect is set to stacks
|
||||
virtual void battleTriggerEffect(const BattleID & battleID, const BattleTriggerEffect & bte){}; //called for various one-shot effects
|
||||
virtual void battleStartBefore(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) {}; //called just before battle start
|
||||
virtual void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed){}; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
virtual void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, BattleSide side, bool replayAllowed){}; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||
virtual void battleUnitsChanged(const BattleID & battleID, const std::vector<UnitChanges> & units){};
|
||||
virtual void battleObstaclesChanged(const BattleID & battleID, const std::vector<ObstacleChanges> & obstacles){};
|
||||
virtual void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca){}; //called when catapult makes an attack
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
bool AccessibilityInfo::tileAccessibleWithGate(BattleHex tile, ui8 side) const
|
||||
bool AccessibilityInfo::tileAccessibleWithGate(BattleHex tile, BattleSide side) const
|
||||
{
|
||||
//at(otherHex) != EAccessibility::ACCESSIBLE && (at(otherHex) != EAccessibility::GATE || side != BattleSide::DEFENDER)
|
||||
if(at(tile) != EAccessibility::ACCESSIBLE)
|
||||
@ -29,7 +29,7 @@ bool AccessibilityInfo::accessible(BattleHex tile, const battle::Unit * stack) c
|
||||
return accessible(tile, stack->doubleWide(), stack->unitSide());
|
||||
}
|
||||
|
||||
bool AccessibilityInfo::accessible(BattleHex tile, bool doubleWide, ui8 side) const
|
||||
bool AccessibilityInfo::accessible(BattleHex tile, bool doubleWide, BattleSide side) const
|
||||
{
|
||||
// All hexes that stack would cover if standing on tile have to be accessible.
|
||||
//do not use getHexes for speed reasons
|
||||
|
@ -37,9 +37,9 @@ struct DLL_LINKAGE AccessibilityInfo : TAccessibilityArray
|
||||
{
|
||||
public:
|
||||
bool accessible(BattleHex tile, const battle::Unit * stack) const; //checks for both tiles if stack is double wide
|
||||
bool accessible(BattleHex tile, bool doubleWide, ui8 side) const; //checks for both tiles if stack is double wide
|
||||
bool accessible(BattleHex tile, bool doubleWide, BattleSide side) const; //checks for both tiles if stack is double wide
|
||||
private:
|
||||
bool tileAccessibleWithGate(BattleHex tile, ui8 side) const;
|
||||
bool tileAccessibleWithGate(BattleHex tile, BattleSide side) const;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -18,7 +18,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
static const int32_t INVALID_UNIT_ID = -1000;
|
||||
|
||||
BattleAction::BattleAction():
|
||||
side(-1),
|
||||
side(BattleSide::NONE),
|
||||
stackNumber(-1),
|
||||
actionType(EActionType::NO_ACTION)
|
||||
{
|
||||
@ -96,7 +96,7 @@ BattleAction BattleAction::makeMove(const battle::Unit * stack, BattleHex dest)
|
||||
return ba;
|
||||
}
|
||||
|
||||
BattleAction BattleAction::makeEndOFTacticPhase(ui8 side)
|
||||
BattleAction BattleAction::makeEndOFTacticPhase(BattleSide side)
|
||||
{
|
||||
BattleAction ba;
|
||||
ba.side = side;
|
||||
@ -104,7 +104,7 @@ BattleAction BattleAction::makeEndOFTacticPhase(ui8 side)
|
||||
return ba;
|
||||
}
|
||||
|
||||
BattleAction BattleAction::makeSurrender(ui8 side)
|
||||
BattleAction BattleAction::makeSurrender(BattleSide side)
|
||||
{
|
||||
BattleAction ba;
|
||||
ba.side = side;
|
||||
@ -112,7 +112,7 @@ BattleAction BattleAction::makeSurrender(ui8 side)
|
||||
return ba;
|
||||
}
|
||||
|
||||
BattleAction BattleAction::makeRetreat(ui8 side)
|
||||
BattleAction BattleAction::makeRetreat(BattleSide side)
|
||||
{
|
||||
BattleAction ba;
|
||||
ba.side = side;
|
||||
|
@ -24,7 +24,7 @@ namespace battle
|
||||
class DLL_LINKAGE BattleAction
|
||||
{
|
||||
public:
|
||||
ui8 side; //who made this action
|
||||
BattleSide side; //who made this action
|
||||
ui32 stackNumber; //stack ID, -1 left hero, -2 right hero,
|
||||
EActionType actionType; //use ActionType enum for values
|
||||
|
||||
@ -39,9 +39,9 @@ public:
|
||||
static BattleAction makeShotAttack(const battle::Unit * shooter, const battle::Unit * target);
|
||||
static BattleAction makeCreatureSpellcast(const battle::Unit * stack, const battle::Target & target, const SpellID & spellID);
|
||||
static BattleAction makeMove(const battle::Unit * stack, BattleHex dest);
|
||||
static BattleAction makeEndOFTacticPhase(ui8 side);
|
||||
static BattleAction makeRetreat(ui8 side);
|
||||
static BattleAction makeSurrender(ui8 side);
|
||||
static BattleAction makeEndOFTacticPhase(BattleSide side);
|
||||
static BattleAction makeRetreat(BattleSide side);
|
||||
static BattleAction makeSurrender(BattleSide side);
|
||||
|
||||
bool isTacticsAction() const;
|
||||
bool isUnitAction() const;
|
||||
|
@ -184,7 +184,7 @@ void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret)
|
||||
ret.push_back(tile);
|
||||
}
|
||||
|
||||
BattleHex BattleHex::getClosestTile(ui8 side, BattleHex initialPos, std::set<BattleHex> & possibilities)
|
||||
BattleHex BattleHex::getClosestTile(BattleSide side, BattleHex initialPos, std::set<BattleHex> & possibilities)
|
||||
{
|
||||
std::vector<BattleHex> sortedTiles (possibilities.begin(), possibilities.end()); //set can't be sorted properly :(
|
||||
BattleHex initialHex = BattleHex(initialPos);
|
||||
|
@ -9,19 +9,12 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
//TODO: change to enum class
|
||||
|
||||
namespace BattleSide
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
ATTACKER = 0,
|
||||
DEFENDER = 1
|
||||
};
|
||||
}
|
||||
|
||||
namespace GameConstants
|
||||
{
|
||||
const int BFIELD_WIDTH = 17;
|
||||
@ -29,8 +22,6 @@ namespace GameConstants
|
||||
const int BFIELD_SIZE = BFIELD_WIDTH * BFIELD_HEIGHT;
|
||||
}
|
||||
|
||||
using BattleSideOpt = std::optional<ui8>;
|
||||
|
||||
// for battle stacks' positions
|
||||
struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class for better code design
|
||||
{
|
||||
@ -102,7 +93,7 @@ struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class f
|
||||
static EDir mutualPosition(BattleHex hex1, BattleHex hex2);
|
||||
static uint8_t getDistance(BattleHex hex1, BattleHex hex2);
|
||||
static void checkAndPush(BattleHex tile, std::vector<BattleHex> & ret);
|
||||
static BattleHex getClosestTile(ui8 side, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad
|
||||
static BattleHex getClosestTile(BattleSide side, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad
|
||||
|
||||
template <typename Handler>
|
||||
void serialize(Handler &h)
|
||||
|
@ -27,10 +27,20 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
///BattleInfo
|
||||
CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base, ui8 side, const SlotID & slot, BattleHex position)
|
||||
const SideInBattle & BattleInfo::getSide(BattleSide side) const
|
||||
{
|
||||
PlayerColor owner = sides[side].color;
|
||||
return sides.at(side);
|
||||
}
|
||||
|
||||
SideInBattle & BattleInfo::getSide(BattleSide side)
|
||||
{
|
||||
return sides.at(side);
|
||||
}
|
||||
|
||||
///BattleInfo
|
||||
CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base, BattleSide side, const SlotID & slot, BattleHex position)
|
||||
{
|
||||
PlayerColor owner = getSide(side).color;
|
||||
assert(!owner.isValidPlayer() || (base.armyObj && base.armyObj->tempOwner == owner));
|
||||
|
||||
auto * ret = new CStack(&base, owner, id, side, slot);
|
||||
@ -39,9 +49,9 @@ CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base,
|
||||
return ret;
|
||||
}
|
||||
|
||||
CStack * BattleInfo::generateNewStack(uint32_t id, const CStackBasicDescriptor & base, ui8 side, const SlotID & slot, BattleHex position)
|
||||
CStack * BattleInfo::generateNewStack(uint32_t id, const CStackBasicDescriptor & base, BattleSide side, const SlotID & slot, BattleHex position)
|
||||
{
|
||||
PlayerColor owner = sides[side].color;
|
||||
PlayerColor owner = getSide(side).color;
|
||||
auto * ret = new CStack(&base, owner, id, side, slot);
|
||||
ret->initialPosition = position;
|
||||
stacks.push_back(ret);
|
||||
@ -50,7 +60,7 @@ CStack * BattleInfo::generateNewStack(uint32_t id, const CStackBasicDescriptor &
|
||||
|
||||
void BattleInfo::localInit()
|
||||
{
|
||||
for(int i = 0; i < 2; i++)
|
||||
for(BattleSide i : { BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
{
|
||||
auto * armyObj = battleGetArmyObject(i);
|
||||
armyObj->battle = this;
|
||||
@ -162,12 +172,12 @@ struct RangeGenerator
|
||||
std::function<int()> myRand;
|
||||
};
|
||||
|
||||
BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town)
|
||||
BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, bool creatureBank, const CGTownInstance * town)
|
||||
{
|
||||
CMP_stack cmpst;
|
||||
auto * curB = new BattleInfo();
|
||||
|
||||
for(auto i = 0u; i < curB->sides.size(); i++)
|
||||
for(auto i : { BattleSide::LEFT_SIDE, BattleSide::RIGHT_SIDE})
|
||||
curB->sides[i].init(heroes[i], armies[i]);
|
||||
|
||||
|
||||
@ -315,36 +325,32 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
|
||||
//reading battleStartpos - add creatures AFTER random obstacles are generated
|
||||
//TODO: parse once to some structure
|
||||
std::vector<std::vector<int>> looseFormations[2];
|
||||
std::vector<std::vector<int>> tightFormations[2];
|
||||
std::vector<std::vector<int>> creBankFormations[2];
|
||||
std::vector<int> commanderField;
|
||||
std::vector<int> commanderBank;
|
||||
BattleSideArray<std::vector<std::vector<int>>> looseFormations;
|
||||
BattleSideArray<std::vector<std::vector<int>>> tightFormations;
|
||||
BattleSideArray<std::vector<std::vector<int>>> creBankFormations;
|
||||
BattleSideArray<int> commanderField;
|
||||
BattleSideArray<int> commanderBank;
|
||||
const JsonNode config(JsonPath::builtin("config/battleStartpos.json"));
|
||||
const JsonVector &positions = config["battle_positions"].Vector();
|
||||
|
||||
CGH::readBattlePositions(positions[0]["levels"], looseFormations[0]);
|
||||
CGH::readBattlePositions(positions[1]["levels"], looseFormations[1]);
|
||||
CGH::readBattlePositions(positions[2]["levels"], tightFormations[0]);
|
||||
CGH::readBattlePositions(positions[3]["levels"], tightFormations[1]);
|
||||
CGH::readBattlePositions(positions[4]["levels"], creBankFormations[0]);
|
||||
CGH::readBattlePositions(positions[5]["levels"], creBankFormations[1]);
|
||||
CGH::readBattlePositions(positions[0]["levels"], looseFormations[BattleSide::ATTACKER]);
|
||||
CGH::readBattlePositions(positions[1]["levels"], looseFormations[BattleSide::DEFENDER]);
|
||||
CGH::readBattlePositions(positions[2]["levels"], tightFormations[BattleSide::ATTACKER]);
|
||||
CGH::readBattlePositions(positions[3]["levels"], tightFormations[BattleSide::DEFENDER]);
|
||||
CGH::readBattlePositions(positions[4]["levels"], creBankFormations[BattleSide::ATTACKER]);
|
||||
CGH::readBattlePositions(positions[5]["levels"], creBankFormations[BattleSide::DEFENDER]);
|
||||
|
||||
for (auto position : config["commanderPositions"]["field"].Vector())
|
||||
{
|
||||
commanderField.push_back(static_cast<int>(position.Float()));
|
||||
}
|
||||
for (auto position : config["commanderPositions"]["creBank"].Vector())
|
||||
{
|
||||
commanderBank.push_back(static_cast<int>(position.Float()));
|
||||
}
|
||||
commanderField[BattleSide::ATTACKER] = config["commanderPositions"]["field"][0].Integer();
|
||||
commanderField[BattleSide::DEFENDER] = config["commanderPositions"]["field"][1].Integer();
|
||||
|
||||
commanderBank[BattleSide::ATTACKER] = config["commanderPositions"]["creBank"][0].Integer();
|
||||
commanderBank[BattleSide::DEFENDER] = config["commanderPositions"]["creBank"][1].Integer();
|
||||
|
||||
//adding war machines
|
||||
if(!creatureBank)
|
||||
{
|
||||
//Checks if hero has artifact and create appropriate stack
|
||||
auto handleWarMachine = [&](int side, const ArtifactPosition & artslot, BattleHex hex)
|
||||
auto handleWarMachine = [&](BattleSide side, const ArtifactPosition & artslot, BattleHex hex)
|
||||
{
|
||||
const CArtifactInstance * warMachineArt = heroes[side]->getArt(artslot);
|
||||
|
||||
@ -357,28 +363,28 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
}
|
||||
};
|
||||
|
||||
if(heroes[0])
|
||||
if(heroes[BattleSide::ATTACKER])
|
||||
{
|
||||
|
||||
handleWarMachine(0, ArtifactPosition::MACH1, 52);
|
||||
handleWarMachine(0, ArtifactPosition::MACH2, 18);
|
||||
handleWarMachine(0, ArtifactPosition::MACH3, 154);
|
||||
handleWarMachine(BattleSide::ATTACKER, ArtifactPosition::MACH1, 52);
|
||||
handleWarMachine(BattleSide::ATTACKER, ArtifactPosition::MACH2, 18);
|
||||
handleWarMachine(BattleSide::ATTACKER, ArtifactPosition::MACH3, 154);
|
||||
if(town && town->hasFort())
|
||||
handleWarMachine(0, ArtifactPosition::MACH4, 120);
|
||||
handleWarMachine(BattleSide::ATTACKER, ArtifactPosition::MACH4, 120);
|
||||
}
|
||||
|
||||
if(heroes[1])
|
||||
if(heroes[BattleSide::DEFENDER])
|
||||
{
|
||||
if(!town) //defending hero shouldn't receive ballista (bug #551)
|
||||
handleWarMachine(1, ArtifactPosition::MACH1, 66);
|
||||
handleWarMachine(1, ArtifactPosition::MACH2, 32);
|
||||
handleWarMachine(1, ArtifactPosition::MACH3, 168);
|
||||
handleWarMachine(BattleSide::DEFENDER, ArtifactPosition::MACH1, 66);
|
||||
handleWarMachine(BattleSide::DEFENDER, ArtifactPosition::MACH2, 32);
|
||||
handleWarMachine(BattleSide::DEFENDER, ArtifactPosition::MACH3, 168);
|
||||
}
|
||||
}
|
||||
//war machines added
|
||||
|
||||
//battleStartpos read
|
||||
for(int side = 0; side < 2; side++)
|
||||
for(BattleSide side : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
{
|
||||
int formationNo = armies[side]->stacksCount() - 1;
|
||||
vstd::abetween(formationNo, 0, GameConstants::ARMY_SIZE - 1);
|
||||
@ -397,14 +403,14 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
|
||||
BattleHex pos = (k < formationVector->size() ? formationVector->at(k) : 0);
|
||||
if(creatureBank && i->second->type->isDoubleWide())
|
||||
pos += side ? BattleHex::LEFT : BattleHex::RIGHT;
|
||||
pos += side == BattleSide::RIGHT_SIDE ? BattleHex::LEFT : BattleHex::RIGHT;
|
||||
|
||||
curB->generateNewStack(curB->nextUnitId(), *i->second, side, i->first, pos);
|
||||
}
|
||||
}
|
||||
|
||||
//adding commanders
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for(BattleSide i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
{
|
||||
if (heroes[i] && heroes[i]->commander && heroes[i]->commander->alive)
|
||||
{
|
||||
@ -416,14 +422,14 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
if (curB->town && curB->town->fortLevel() >= CGTownInstance::CITADEL)
|
||||
{
|
||||
// keep tower
|
||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_CENTRAL_TOWER);
|
||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_CENTRAL_TOWER);
|
||||
|
||||
if (curB->town->fortLevel() >= CGTownInstance::CASTLE)
|
||||
{
|
||||
// lower tower + upper tower
|
||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_UPPER_TOWER);
|
||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_UPPER_TOWER);
|
||||
|
||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), 1, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER);
|
||||
curB->generateNewStack(curB->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER);
|
||||
}
|
||||
|
||||
//Moat generating is done on server
|
||||
@ -453,11 +459,9 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
|
||||
//tactics
|
||||
bool isTacticsAllowed = !creatureBank; //no tactics in creature banks
|
||||
|
||||
constexpr int sideSize = 2;
|
||||
|
||||
std::array<int, sideSize> battleRepositionHex = {};
|
||||
std::array<int, sideSize> battleRepositionHexBlock = {};
|
||||
for(int i = 0; i < sideSize; i++)
|
||||
BattleSideArray<int> battleRepositionHex = {};
|
||||
BattleSideArray<int> battleRepositionHexBlock = {};
|
||||
for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
{
|
||||
if(heroes[i])
|
||||
{
|
||||
@ -508,14 +512,14 @@ const CGHeroInstance * BattleInfo::getHero(const PlayerColor & player) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ui8 BattleInfo::whatSide(const PlayerColor & player) const
|
||||
BattleSide BattleInfo::whatSide(const PlayerColor & player) const
|
||||
{
|
||||
for(int i = 0; i < sides.size(); i++)
|
||||
for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
if(sides[i].color == player)
|
||||
return i;
|
||||
|
||||
logGlobal->warn("BattleInfo::whatSide: Player %s is not in battle!", player.toString());
|
||||
return -1;
|
||||
return BattleSide::NONE;
|
||||
}
|
||||
|
||||
CStack * BattleInfo::getStack(int stackID, bool onlyAlive)
|
||||
@ -529,7 +533,7 @@ BattleInfo::BattleInfo():
|
||||
town(nullptr),
|
||||
tile(-1,-1,-1),
|
||||
battlefieldType(BattleField::NONE),
|
||||
tacticsSide(0),
|
||||
tacticsSide(BattleSide::NONE),
|
||||
tacticDistance(0)
|
||||
{
|
||||
setNodeType(BATTLE);
|
||||
@ -555,7 +559,7 @@ BattleInfo::~BattleInfo()
|
||||
for (auto & elem : stacks)
|
||||
delete elem;
|
||||
|
||||
for(int i = 0; i < 2; i++)
|
||||
for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
if(auto * _armyObj = battleGetArmyObject(i))
|
||||
_armyObj->battle = nullptr;
|
||||
}
|
||||
@ -600,27 +604,27 @@ IBattleInfo::ObstacleCList BattleInfo::getAllObstacles() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
PlayerColor BattleInfo::getSidePlayer(ui8 side) const
|
||||
PlayerColor BattleInfo::getSidePlayer(BattleSide side) const
|
||||
{
|
||||
return sides.at(side).color;
|
||||
return getSide(side).color;
|
||||
}
|
||||
|
||||
const CArmedInstance * BattleInfo::getSideArmy(ui8 side) const
|
||||
const CArmedInstance * BattleInfo::getSideArmy(BattleSide side) const
|
||||
{
|
||||
return sides.at(side).armyObject;
|
||||
return getSide(side).armyObject;
|
||||
}
|
||||
|
||||
const CGHeroInstance * BattleInfo::getSideHero(ui8 side) const
|
||||
const CGHeroInstance * BattleInfo::getSideHero(BattleSide side) const
|
||||
{
|
||||
return sides.at(side).hero;
|
||||
return getSide(side).hero;
|
||||
}
|
||||
|
||||
ui8 BattleInfo::getTacticDist() const
|
||||
uint8_t BattleInfo::getTacticDist() const
|
||||
{
|
||||
return tacticDistance;
|
||||
}
|
||||
|
||||
ui8 BattleInfo::getTacticsSide() const
|
||||
BattleSide BattleInfo::getTacticsSide() const
|
||||
{
|
||||
return tacticsSide;
|
||||
}
|
||||
@ -640,14 +644,14 @@ EGateState BattleInfo::getGateState() const
|
||||
return si.gateState;
|
||||
}
|
||||
|
||||
uint32_t BattleInfo::getCastSpells(ui8 side) const
|
||||
uint32_t BattleInfo::getCastSpells(BattleSide side) const
|
||||
{
|
||||
return sides.at(side).castSpellsCount;
|
||||
return getSide(side).castSpellsCount;
|
||||
}
|
||||
|
||||
int32_t BattleInfo::getEnchanterCounter(ui8 side) const
|
||||
int32_t BattleInfo::getEnchanterCounter(BattleSide side) const
|
||||
{
|
||||
return sides.at(side).enchanterCounter;
|
||||
return getSide(side).enchanterCounter;
|
||||
}
|
||||
|
||||
const IBonusBearer * BattleInfo::getBonusBearer() const
|
||||
@ -685,14 +689,14 @@ bool BattleInfo::isCreatureBank() const
|
||||
}
|
||||
|
||||
|
||||
std::vector<SpellID> BattleInfo::getUsedSpells(ui8 side) const
|
||||
std::vector<SpellID> BattleInfo::getUsedSpells(BattleSide side) const
|
||||
{
|
||||
return sides.at(side).usedSpellsHistory;
|
||||
return getSide(side).usedSpellsHistory;
|
||||
}
|
||||
|
||||
void BattleInfo::nextRound()
|
||||
{
|
||||
for(int i = 0; i < 2; ++i)
|
||||
for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
{
|
||||
sides.at(i).castSpellsCount = 0;
|
||||
vstd::amax(--sides.at(i).enchanterCounter, 0);
|
||||
@ -994,12 +998,12 @@ void BattleInfo::removeObstacle(uint32_t id)
|
||||
}
|
||||
}
|
||||
|
||||
CArmedInstance * BattleInfo::battleGetArmyObject(ui8 side) const
|
||||
CArmedInstance * BattleInfo::battleGetArmyObject(BattleSide side) const
|
||||
{
|
||||
return const_cast<CArmedInstance*>(CBattleInfoEssentials::battleGetArmyObject(side));
|
||||
}
|
||||
|
||||
CGHeroInstance * BattleInfo::battleGetFightingHero(ui8 side) const
|
||||
CGHeroInstance * BattleInfo::battleGetFightingHero(BattleSide side) const
|
||||
{
|
||||
return const_cast<CGHeroInstance*>(CBattleInfoEssentials::battleGetFightingHero(side));
|
||||
}
|
||||
@ -1009,7 +1013,7 @@ scripting::Pool * BattleInfo::getContextPool() const
|
||||
{
|
||||
//this is real battle, use global scripting context pool
|
||||
//TODO: make this line not ugly
|
||||
return battleGetFightingHero(0)->cb->getGlobalContextPool();
|
||||
return battleGetFightingHero(BattleSide::ATTACKER)->cb->getGlobalContextPool();
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1045,7 +1049,7 @@ bool CMP_stack::operator()(const battle::Unit * a, const battle::Unit * b) const
|
||||
return false;
|
||||
}
|
||||
|
||||
CMP_stack::CMP_stack(int Phase, int Turn, uint8_t Side):
|
||||
CMP_stack::CMP_stack(int Phase, int Turn, BattleSide Side):
|
||||
phase(Phase),
|
||||
turn(Turn),
|
||||
side(Side)
|
||||
|
@ -25,15 +25,10 @@ class BattleField;
|
||||
|
||||
class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState
|
||||
{
|
||||
BattleSideArray<SideInBattle> sides; //sides[0] - attacker, sides[1] - defender
|
||||
public:
|
||||
BattleID battleID = BattleID(0);
|
||||
|
||||
enum BattleSide
|
||||
{
|
||||
ATTACKER = 0,
|
||||
DEFENDER
|
||||
};
|
||||
std::array<SideInBattle, 2> sides; //sides[0] - attacker, sides[1] - defender
|
||||
si32 round;
|
||||
si32 activeStack;
|
||||
const CGTownInstance * town; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
|
||||
@ -47,7 +42,7 @@ public:
|
||||
BattleField battlefieldType; //like !!BA:B
|
||||
TerrainId terrainType; //used for some stack nativity checks (not the bonus limiters though that have their own copy)
|
||||
|
||||
ui8 tacticsSide; //which side is requested to play tactics phase
|
||||
BattleSide tacticsSide; //which side is requested to play tactics phase
|
||||
ui8 tacticDistance; //how many hexes we can go forward (1 = only hexes adjacent to margin line)
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
@ -92,19 +87,19 @@ public:
|
||||
|
||||
ObstacleCList getAllObstacles() const override;
|
||||
|
||||
PlayerColor getSidePlayer(ui8 side) const override;
|
||||
const CArmedInstance * getSideArmy(ui8 side) const override;
|
||||
const CGHeroInstance * getSideHero(ui8 side) const override;
|
||||
PlayerColor getSidePlayer(BattleSide side) const override;
|
||||
const CArmedInstance * getSideArmy(BattleSide side) const override;
|
||||
const CGHeroInstance * getSideHero(BattleSide side) const override;
|
||||
|
||||
ui8 getTacticDist() const override;
|
||||
ui8 getTacticsSide() const override;
|
||||
BattleSide getTacticsSide() const override;
|
||||
|
||||
const CGTownInstance * getDefendedTown() const override;
|
||||
EWallState getWallState(EWallPart partOfWall) const override;
|
||||
EGateState getGateState() const override;
|
||||
|
||||
uint32_t getCastSpells(ui8 side) const override;
|
||||
int32_t getEnchanterCounter(ui8 side) const override;
|
||||
uint32_t getCastSpells(BattleSide side) const override;
|
||||
int32_t getEnchanterCounter(BattleSide side) const override;
|
||||
|
||||
const IBonusBearer * getBonusBearer() const override;
|
||||
|
||||
@ -115,7 +110,7 @@ public:
|
||||
int3 getLocation() const override;
|
||||
bool isCreatureBank() const override;
|
||||
|
||||
std::vector<SpellID> getUsedSpells(ui8 side) const override;
|
||||
std::vector<SpellID> getUsedSpells(BattleSide side) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IBattleState
|
||||
@ -144,19 +139,22 @@ public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CStack * getStack(int stackID, bool onlyAlive = true);
|
||||
using CBattleInfoEssentials::battleGetArmyObject;
|
||||
CArmedInstance * battleGetArmyObject(ui8 side) const;
|
||||
CArmedInstance * battleGetArmyObject(BattleSide side) const;
|
||||
using CBattleInfoEssentials::battleGetFightingHero;
|
||||
CGHeroInstance * battleGetFightingHero(ui8 side) const;
|
||||
CGHeroInstance * battleGetFightingHero(BattleSide side) const;
|
||||
|
||||
CStack * generateNewStack(uint32_t id, const CStackInstance & base, ui8 side, const SlotID & slot, BattleHex position);
|
||||
CStack * generateNewStack(uint32_t id, const CStackBasicDescriptor & base, ui8 side, const SlotID & slot, BattleHex position);
|
||||
CStack * generateNewStack(uint32_t id, const CStackInstance & base, BattleSide side, const SlotID & slot, BattleHex position);
|
||||
CStack * generateNewStack(uint32_t id, const CStackBasicDescriptor & base, BattleSide side, const SlotID & slot, BattleHex position);
|
||||
|
||||
const SideInBattle & getSide(BattleSide side) const;
|
||||
SideInBattle & getSide(BattleSide side);
|
||||
|
||||
const CGHeroInstance * getHero(const PlayerColor & player) const; //returns fighting hero that belongs to given player
|
||||
|
||||
void localInit();
|
||||
static BattleInfo * setupBattle(const int3 & tile, TerrainId, const BattleField & battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town);
|
||||
static BattleInfo * setupBattle(const int3 & tile, TerrainId, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, bool creatureBank, const CGTownInstance * town);
|
||||
|
||||
ui8 whatSide(const PlayerColor & player) const;
|
||||
BattleSide whatSide(const PlayerColor & player) const;
|
||||
|
||||
protected:
|
||||
#if SCRIPTING_ENABLED
|
||||
@ -169,10 +167,10 @@ class DLL_LINKAGE CMP_stack
|
||||
{
|
||||
int phase; //rules of which phase will be used
|
||||
int turn;
|
||||
uint8_t side;
|
||||
BattleSide side;
|
||||
public:
|
||||
bool operator()(const battle::Unit * a, const battle::Unit * b) const;
|
||||
CMP_stack(int Phase = 1, int Turn = 0, uint8_t Side = BattleSide::ATTACKER);
|
||||
CMP_stack(int Phase = 1, int Turn = 0, BattleSide Side = BattleSide::ATTACKER);
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -65,17 +65,17 @@ IBattleInfo::ObstacleCList BattleProxy::getAllObstacles() const
|
||||
return subject->battleGetAllObstacles();
|
||||
}
|
||||
|
||||
PlayerColor BattleProxy::getSidePlayer(ui8 side) const
|
||||
PlayerColor BattleProxy::getSidePlayer(BattleSide side) const
|
||||
{
|
||||
return subject->sideToPlayer(side);
|
||||
}
|
||||
|
||||
const CArmedInstance * BattleProxy::getSideArmy(ui8 side) const
|
||||
const CArmedInstance * BattleProxy::getSideArmy(BattleSide side) const
|
||||
{
|
||||
return subject->battleGetArmyObject(side);
|
||||
}
|
||||
|
||||
const CGHeroInstance * BattleProxy::getSideHero(ui8 side) const
|
||||
const CGHeroInstance * BattleProxy::getSideHero(BattleSide side) const
|
||||
{
|
||||
return subject->battleGetFightingHero(side);
|
||||
}
|
||||
@ -85,7 +85,7 @@ ui8 BattleProxy::getTacticDist() const
|
||||
return subject->battleTacticDist();
|
||||
}
|
||||
|
||||
ui8 BattleProxy::getTacticsSide() const
|
||||
BattleSide BattleProxy::getTacticsSide() const
|
||||
{
|
||||
return subject->battleGetTacticsSide();
|
||||
}
|
||||
@ -105,12 +105,12 @@ EGateState BattleProxy::getGateState() const
|
||||
return subject->battleGetGateState();
|
||||
}
|
||||
|
||||
uint32_t BattleProxy::getCastSpells(ui8 side) const
|
||||
uint32_t BattleProxy::getCastSpells(BattleSide side) const
|
||||
{
|
||||
return subject->battleCastSpells(side);
|
||||
}
|
||||
|
||||
int32_t BattleProxy::getEnchanterCounter(ui8 side) const
|
||||
int32_t BattleProxy::getEnchanterCounter(BattleSide side) const
|
||||
{
|
||||
return subject->battleGetEnchanterCounter(side);
|
||||
}
|
||||
|
@ -38,19 +38,19 @@ public:
|
||||
|
||||
ObstacleCList getAllObstacles() const override;
|
||||
|
||||
PlayerColor getSidePlayer(ui8 side) const override;
|
||||
const CArmedInstance * getSideArmy(ui8 side) const override;
|
||||
const CGHeroInstance * getSideHero(ui8 side) const override;
|
||||
PlayerColor getSidePlayer(BattleSide side) const override;
|
||||
const CArmedInstance * getSideArmy(BattleSide side) const override;
|
||||
const CGHeroInstance * getSideHero(BattleSide side) const override;
|
||||
|
||||
ui8 getTacticDist() const override;
|
||||
ui8 getTacticsSide() const override;
|
||||
BattleSide getTacticsSide() const override;
|
||||
|
||||
const CGTownInstance * getDefendedTown() const override;
|
||||
EWallState getWallState(EWallPart partOfWall) const override;
|
||||
EGateState getGateState() const override;
|
||||
|
||||
uint32_t getCastSpells(ui8 side) const override;
|
||||
int32_t getEnchanterCounter(ui8 side) const override;
|
||||
uint32_t getCastSpells(BattleSide side) const override;
|
||||
int32_t getEnchanterCounter(BattleSide side) const override;
|
||||
|
||||
const IBonusBearer * getBonusBearer() const override;
|
||||
protected:
|
||||
|
53
lib/battle/BattleSide.h
Normal file
53
lib/battle/BattleSide.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* BattleSide.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
enum class BattleSide : int8_t
|
||||
{
|
||||
NONE = -1,
|
||||
INVALID = -2,
|
||||
ALL_KNOWING = -3,
|
||||
|
||||
ATTACKER = 0,
|
||||
DEFENDER = 1,
|
||||
|
||||
// Aliases for convenience
|
||||
LEFT_SIDE = ATTACKER,
|
||||
RIGHT_SIDE = DEFENDER,
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class BattleSideArray : public std::array<T, 2>
|
||||
{
|
||||
public:
|
||||
const T & at(BattleSide side) const
|
||||
{
|
||||
return std::array<T, 2>::at(static_cast<int>(side));
|
||||
}
|
||||
|
||||
T & at(BattleSide side)
|
||||
{
|
||||
return std::array<T, 2>::at(static_cast<int>(side));
|
||||
}
|
||||
|
||||
const T & operator[](BattleSide side) const
|
||||
{
|
||||
return std::array<T, 2>::at(static_cast<int>(side));
|
||||
}
|
||||
|
||||
T & operator[](BattleSide side)
|
||||
{
|
||||
return std::array<T, 2>::at(static_cast<int>(side));
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -23,7 +23,7 @@ BattleStateInfoForRetreat::BattleStateInfoForRetreat():
|
||||
isLastTurnBeforeDie(false),
|
||||
ourHero(nullptr),
|
||||
enemyHero(nullptr),
|
||||
ourSide(-1)
|
||||
ourSide(BattleSide::NONE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace battle
|
||||
@ -24,7 +26,7 @@ public:
|
||||
bool canFlee;
|
||||
bool canSurrender;
|
||||
bool isLastTurnBeforeDie;
|
||||
ui8 ourSide;
|
||||
BattleSide ourSide;
|
||||
std::vector<const battle::Unit *> ourStacks;
|
||||
std::vector<const battle::Unit *> enemyStacks;
|
||||
const CGHeroInstance * ourHero;
|
||||
|
@ -110,9 +110,9 @@ ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(const spells::Caster *
|
||||
}
|
||||
const PlayerColor player = caster->getCasterOwner();
|
||||
const auto side = playerToSide(player);
|
||||
if(!side)
|
||||
if(side == BattleSide::NONE)
|
||||
return ESpellCastProblem::INVALID;
|
||||
if(!battleDoWeKnowAbout(side.value()))
|
||||
if(!battleDoWeKnowAbout(side))
|
||||
{
|
||||
logGlobal->warn("You can't check if enemy can cast given spell!");
|
||||
return ESpellCastProblem::INVALID;
|
||||
@ -125,7 +125,7 @@ ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(const spells::Caster *
|
||||
{
|
||||
case spells::Mode::HERO:
|
||||
{
|
||||
if(battleCastSpells(side.value()) > 0)
|
||||
if(battleCastSpells(side) > 0)
|
||||
return ESpellCastProblem::CASTS_PER_TURN_LIMIT;
|
||||
|
||||
const auto * hero = dynamic_cast<const CGHeroInstance *>(caster);
|
||||
@ -376,7 +376,7 @@ battle::Units CBattleInfoCallback::battleAliveUnits() const
|
||||
});
|
||||
}
|
||||
|
||||
battle::Units CBattleInfoCallback::battleAliveUnits(ui8 side) const
|
||||
battle::Units CBattleInfoCallback::battleAliveUnits(BattleSide side) const
|
||||
{
|
||||
return battleGetUnitsIf([=](const battle::Unit * unit)
|
||||
{
|
||||
@ -388,7 +388,7 @@ using namespace battle;
|
||||
|
||||
//T is battle::Unit descendant
|
||||
template <typename T>
|
||||
const T * takeOneUnit(std::vector<const T*> & allUnits, const int turn, int8_t & sideThatLastMoved, int phase)
|
||||
const T * takeOneUnit(std::vector<const T*> & allUnits, const int turn, BattleSide & sideThatLastMoved, int phase)
|
||||
{
|
||||
const T * returnedUnit = nullptr;
|
||||
size_t currentUnitIndex = 0;
|
||||
@ -417,13 +417,13 @@ const T * takeOneUnit(std::vector<const T*> & allUnits, const int turn, int8_t &
|
||||
}
|
||||
else if(currentUnitInitiative == returnedUnitInitiative)
|
||||
{
|
||||
if(sideThatLastMoved == -1 && turn <= 0 && currentUnit->unitSide() == BattleSide::ATTACKER
|
||||
if(sideThatLastMoved == BattleSide::NONE && turn <= 0 && currentUnit->unitSide() == BattleSide::ATTACKER
|
||||
&& !(returnedUnit->unitSide() == currentUnit->unitSide() && returnedUnit->unitSlot() < currentUnit->unitSlot())) // Turn 0 attacker priority
|
||||
{
|
||||
returnedUnit = currentUnit;
|
||||
currentUnitIndex = i;
|
||||
}
|
||||
else if(sideThatLastMoved != -1 && currentUnit->unitSide() != sideThatLastMoved
|
||||
else if(sideThatLastMoved != BattleSide::NONE && currentUnit->unitSide() != sideThatLastMoved
|
||||
&& !(returnedUnit->unitSide() == currentUnit->unitSide() && returnedUnit->unitSlot() < currentUnit->unitSlot())) // Alternate equal speeds units
|
||||
{
|
||||
returnedUnit = currentUnit;
|
||||
@ -438,7 +438,7 @@ const T * takeOneUnit(std::vector<const T*> & allUnits, const int turn, int8_t &
|
||||
returnedUnit = currentUnit;
|
||||
currentUnitIndex = i;
|
||||
}
|
||||
else if(currentUnitInitiative == returnedUnitInitiative && sideThatLastMoved != -1 && currentUnit->unitSide() != sideThatLastMoved
|
||||
else if(currentUnitInitiative == returnedUnitInitiative && sideThatLastMoved != BattleSide::NONE && currentUnit->unitSide() != sideThatLastMoved
|
||||
&& !(returnedUnit->unitSide() == currentUnit->unitSide() && returnedUnit->unitSlot() < currentUnit->unitSlot())) // Alternate equal speeds units
|
||||
{
|
||||
returnedUnit = currentUnit;
|
||||
@ -458,7 +458,7 @@ const T * takeOneUnit(std::vector<const T*> & allUnits, const int turn, int8_t &
|
||||
return returnedUnit;
|
||||
}
|
||||
|
||||
void CBattleInfoCallback::battleGetTurnOrder(std::vector<battle::Units> & turns, const size_t maxUnits, const int maxTurns, const int turn, int8_t sideThatLastMoved) const
|
||||
void CBattleInfoCallback::battleGetTurnOrder(std::vector<battle::Units> & turns, const size_t maxUnits, const int maxTurns, const int turn, BattleSide sideThatLastMoved) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE();
|
||||
|
||||
@ -500,7 +500,7 @@ void CBattleInfoCallback::battleGetTurnOrder(std::vector<battle::Units> & turns,
|
||||
|
||||
//its first or current turn, turn priority for active stack side
|
||||
//TODO: what if active stack mind-controlled?
|
||||
if(turn <= 0 && sideThatLastMoved < 0)
|
||||
if(turn <= 0 && sideThatLastMoved == BattleSide::NONE)
|
||||
sideThatLastMoved = activeUnit->unitSide();
|
||||
}
|
||||
|
||||
@ -560,7 +560,7 @@ void CBattleInfoCallback::battleGetTurnOrder(std::vector<battle::Units> & turns,
|
||||
}
|
||||
}
|
||||
|
||||
if(sideThatLastMoved < 0)
|
||||
if(sideThatLastMoved == BattleSide::NONE)
|
||||
sideThatLastMoved = BattleSide::ATTACKER;
|
||||
|
||||
if(!turnsIsFull() && (maxTurns == 0 || turns.size() < maxTurns))
|
||||
@ -887,7 +887,7 @@ bool CBattleInfoCallback::handleObstacleTriggersForUnit(SpellCastEnvironment & s
|
||||
spellEnv.apply(&bocp);
|
||||
};
|
||||
const auto side = unit.unitSide();
|
||||
auto shouldReveal = !spellObstacle->hidden || !battleIsObstacleVisibleForSide(*obstacle, (BattlePerspective::BattlePerspective)side);
|
||||
auto shouldReveal = !spellObstacle->hidden || !battleIsObstacleVisibleForSide(*obstacle, side);
|
||||
const auto * hero = battleGetFightingHero(spellObstacle->casterSide);
|
||||
auto caster = spells::ObstacleCasterProxy(getBattle()->getSidePlayer(spellObstacle->casterSide), hero, *spellObstacle);
|
||||
|
||||
@ -1098,7 +1098,7 @@ bool CBattleInfoCallback::isInObstacle(
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<BattleHex> CBattleInfoCallback::getStoppers(BattlePerspective::BattlePerspective whichSidePerspective) const
|
||||
std::set<BattleHex> CBattleInfoCallback::getStoppers(BattleSide whichSidePerspective) const
|
||||
{
|
||||
std::set<BattleHex> ret;
|
||||
RETURN_IF_NOT_BATTLE(ret);
|
||||
@ -1161,7 +1161,7 @@ std::pair<const battle::Unit *, BattleHex> CBattleInfoCallback::getNearestStack(
|
||||
return std::make_pair<const battle::Unit * , BattleHex>(nullptr, BattleHex::INVALID);
|
||||
}
|
||||
|
||||
BattleHex CBattleInfoCallback::getAvailableHex(const CreatureID & creID, ui8 side, int initialPos) const
|
||||
BattleHex CBattleInfoCallback::getAvailableHex(const CreatureID & creID, BattleSide side, int initialPos) const
|
||||
{
|
||||
bool twoHex = VLC->creatures()->getById(creID)->isDoubleWide();
|
||||
|
||||
@ -1208,8 +1208,13 @@ bool CBattleInfoCallback::isInTacticRange(BattleHex dest) const
|
||||
auto side = battleGetTacticsSide();
|
||||
auto dist = battleGetTacticDist();
|
||||
|
||||
return ((!side && dest.getX() > 0 && dest.getX() <= dist)
|
||||
|| (side && dest.getX() < GameConstants::BFIELD_WIDTH - 1 && dest.getX() >= GameConstants::BFIELD_WIDTH - dist - 1));
|
||||
if (side == BattleSide::ATTACKER && dest.getX() > 0 && dest.getX() <= dist)
|
||||
return true;
|
||||
|
||||
if (side == BattleSide::DEFENDER && dest.getX() < GameConstants::BFIELD_WIDTH - 1 && dest.getX() >= GameConstants::BFIELD_WIDTH - dist - 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ReachabilityInfo CBattleInfoCallback::getReachability(const battle::Unit * unit) const
|
||||
@ -1452,7 +1457,7 @@ std::set<const CStack*> CBattleInfoCallback::getAttackedCreatures(const CStack*
|
||||
return attackedCres;
|
||||
}
|
||||
|
||||
static bool isHexInFront(BattleHex hex, BattleHex testHex, BattleSide::Type side )
|
||||
static bool isHexInFront(BattleHex hex, BattleHex testHex, BattleSide side )
|
||||
{
|
||||
static const std::set<BattleHex::EDir> rightDirs { BattleHex::BOTTOM_RIGHT, BattleHex::TOP_RIGHT, BattleHex::RIGHT };
|
||||
static const std::set<BattleHex::EDir> leftDirs { BattleHex::BOTTOM_LEFT, BattleHex::TOP_LEFT, BattleHex::LEFT };
|
||||
@ -1477,7 +1482,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl
|
||||
if (attackerHex < 0 ) //turret
|
||||
return false;
|
||||
|
||||
if(isHexInFront(attackerHex, defenderHex, static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
if(isHexInFront(attackerHex, defenderHex, attacker->unitSide()))
|
||||
return false;
|
||||
|
||||
auto defenderOtherHex = defenderHex;
|
||||
@ -1487,7 +1492,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl
|
||||
{
|
||||
defenderOtherHex = battle::Unit::occupiedHex(defenderHex, true, defender->unitSide());
|
||||
|
||||
if(isHexInFront(attackerHex, defenderOtherHex, static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
if(isHexInFront(attackerHex, defenderOtherHex, attacker->unitSide()))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1495,7 +1500,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl
|
||||
{
|
||||
attackerOtherHex = battle::Unit::occupiedHex(attackerHex, true, attacker->unitSide());
|
||||
|
||||
if(isHexInFront(attackerOtherHex, defenderHex, static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
if(isHexInFront(attackerOtherHex, defenderHex, attacker->unitSide()))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1503,7 +1508,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl
|
||||
// but this is how H3 handles it which is important, e.g. for direction of dragon breath attacks
|
||||
if (attacker->doubleWide() && defender->doubleWide())
|
||||
{
|
||||
if(isHexInFront(attackerOtherHex, defenderOtherHex, static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
if(isHexInFront(attackerOtherHex, defenderOtherHex, attacker->unitSide()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -1762,7 +1767,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(vstd::RNG & rand, const ba
|
||||
case SpellID::PROTECTION_FROM_FIRE:
|
||||
case SpellID::PROTECTION_FROM_WATER:
|
||||
{
|
||||
const ui8 enemySide = 1 - subject->unitSide();
|
||||
const BattleSide enemySide = otherSide(subject->unitSide());
|
||||
//todo: only if enemy has spellbook
|
||||
if (!battleHasHero(enemySide)) //only if there is enemy hero
|
||||
continue;
|
||||
@ -1853,10 +1858,9 @@ int CBattleInfoCallback::battleGetSurrenderCost(const PlayerColor & Player) cons
|
||||
if(!battleCanSurrender(Player))
|
||||
return -1;
|
||||
|
||||
const auto sideOpt = playerToSide(Player);
|
||||
if(!sideOpt)
|
||||
const BattleSide side = playerToSide(Player);
|
||||
if(side == BattleSide::NONE)
|
||||
return -1;
|
||||
const auto side = sideOpt.value();
|
||||
|
||||
int ret = 0;
|
||||
double discount = 0;
|
||||
@ -1872,7 +1876,7 @@ int CBattleInfoCallback::battleGetSurrenderCost(const PlayerColor & Player) cons
|
||||
return ret;
|
||||
}
|
||||
|
||||
si8 CBattleInfoCallback::battleMinSpellLevel(ui8 side) const
|
||||
si8 CBattleInfoCallback::battleMinSpellLevel(BattleSide side) const
|
||||
{
|
||||
const IBonusBearer * node = nullptr;
|
||||
if(const CGHeroInstance * h = battleGetFightingHero(side))
|
||||
@ -1890,7 +1894,7 @@ si8 CBattleInfoCallback::battleMinSpellLevel(ui8 side) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
si8 CBattleInfoCallback::battleMaxSpellLevel(ui8 side) const
|
||||
si8 CBattleInfoCallback::battleMaxSpellLevel(BattleSide side) const
|
||||
{
|
||||
const IBonusBearer *node = nullptr;
|
||||
if(const CGHeroInstance * h = battleGetFightingHero(side))
|
||||
@ -1909,21 +1913,21 @@ si8 CBattleInfoCallback::battleMaxSpellLevel(ui8 side) const
|
||||
return GameConstants::SPELL_LEVELS;
|
||||
}
|
||||
|
||||
std::optional<int> CBattleInfoCallback::battleIsFinished() const
|
||||
std::optional<BattleSide> CBattleInfoCallback::battleIsFinished() const
|
||||
{
|
||||
auto units = battleGetUnitsIf([=](const battle::Unit * unit)
|
||||
{
|
||||
return unit->alive() && !unit->isTurret() && !unit->hasBonusOfType(BonusType::SIEGE_WEAPON);
|
||||
});
|
||||
|
||||
std::array<bool, 2> hasUnit = {false, false}; //index is BattleSide
|
||||
BattleSideArray<bool> hasUnit = {false, false}; //index is BattleSide
|
||||
|
||||
for(auto & unit : units)
|
||||
{
|
||||
//todo: move SIEGE_WEAPON check to Unit state
|
||||
hasUnit.at(unit->unitSide()) = true;
|
||||
|
||||
if(hasUnit[0] && hasUnit[1])
|
||||
if(hasUnit[BattleSide::ATTACKER] && hasUnit[BattleSide::DEFENDER])
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@ -1937,12 +1941,12 @@ std::optional<int> CBattleInfoCallback::battleIsFinished() const
|
||||
}
|
||||
}
|
||||
|
||||
if(!hasUnit[0] && !hasUnit[1])
|
||||
return 2;
|
||||
if(!hasUnit[1])
|
||||
return 0;
|
||||
if(!hasUnit[BattleSide::ATTACKER] && !hasUnit[BattleSide::DEFENDER])
|
||||
return BattleSide::NONE;
|
||||
if(!hasUnit[BattleSide::DEFENDER])
|
||||
return BattleSide::ATTACKER;
|
||||
else
|
||||
return 1;
|
||||
return BattleSide::DEFENDER;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -56,7 +56,7 @@ struct DLL_LINKAGE BattleClientInterfaceData
|
||||
class DLL_LINKAGE CBattleInfoCallback : public virtual CBattleInfoEssentials
|
||||
{
|
||||
public:
|
||||
std::optional<int> battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
|
||||
std::optional<BattleSide> battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
|
||||
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const override;
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set<BattleHex> & passed) const override;
|
||||
@ -70,9 +70,9 @@ public:
|
||||
///returns all alive units excluding turrets
|
||||
battle::Units battleAliveUnits() const;
|
||||
///returns all alive units from particular side excluding turrets
|
||||
battle::Units battleAliveUnits(ui8 side) const;
|
||||
battle::Units battleAliveUnits(BattleSide side) const;
|
||||
|
||||
void battleGetTurnOrder(std::vector<battle::Units> & out, const size_t maxUnits, const int maxTurns, const int turn = 0, int8_t lastMoved = -1) const;
|
||||
void battleGetTurnOrder(std::vector<battle::Units> & out, const size_t maxUnits, const int maxTurns, const int turn = 0, BattleSide lastMoved = BattleSide::NONE) const;
|
||||
|
||||
///returns reachable hexes (valid movement destinations), DOES contain stack current position
|
||||
std::vector<BattleHex> battleGetAvailableHexes(const battle::Unit * unit, bool obtainMovementRange, bool addOccupiable, std::vector<BattleHex> * attackable) const;
|
||||
@ -116,8 +116,8 @@ public:
|
||||
bool isWallPartAttackable(EWallPart wallPart) const; // returns true if the wall part is actually attackable, false if not
|
||||
std::vector<BattleHex> getAttackableBattleHexes() const;
|
||||
|
||||
si8 battleMinSpellLevel(ui8 side) const; //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned
|
||||
si8 battleMaxSpellLevel(ui8 side) const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned
|
||||
si8 battleMinSpellLevel(BattleSide side) const; //calculates maximum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned
|
||||
si8 battleMaxSpellLevel(BattleSide side) const; //calculates minimum spell level possible to be cast on battlefield - takes into account artifacts of both heroes; if no effects are set, 0 is returned
|
||||
int32_t battleGetSpellCost(const spells::Spell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
|
||||
ESpellCastProblem battleCanCastSpell(const spells::Caster * caster, spells::Mode mode) const; //returns true if there are no general issues preventing from casting a spell
|
||||
|
||||
@ -163,12 +163,12 @@ public:
|
||||
AccessibilityInfo getAccessibility(const std::vector<BattleHex> & accessibleHexes) const; //given hexes will be marked as accessible
|
||||
std::pair<const battle::Unit *, BattleHex> getNearestStack(const battle::Unit * closest) const;
|
||||
|
||||
BattleHex getAvailableHex(const CreatureID & creID, ui8 side, int initialPos = -1) const; //find place for adding new stack
|
||||
BattleHex getAvailableHex(const CreatureID & creID, BattleSide side, int initialPos = -1) const; //find place for adding new stack
|
||||
protected:
|
||||
ReachabilityInfo getFlyingReachability(const ReachabilityInfo::Parameters & params) const;
|
||||
ReachabilityInfo makeBFS(const AccessibilityInfo & accessibility, const ReachabilityInfo::Parameters & params) const;
|
||||
bool isInObstacle(BattleHex hex, const std::set<BattleHex> & obstacles, const ReachabilityInfo::Parameters & params) const;
|
||||
std::set<BattleHex> getStoppers(BattlePerspective::BattlePerspective whichSidePerspective) const; //get hexes with stopping obstacles (quicksands)
|
||||
std::set<BattleHex> getStoppers(BattleSide whichSidePerspective) const; //get hexes with stopping obstacles (quicksands)
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -35,13 +35,13 @@ BattleField CBattleInfoEssentials::battleGetBattlefieldType() const
|
||||
return getBattle()->getBattlefieldType();
|
||||
}
|
||||
|
||||
int32_t CBattleInfoEssentials::battleGetEnchanterCounter(ui8 side) const
|
||||
int32_t CBattleInfoEssentials::battleGetEnchanterCounter(BattleSide side) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(0);
|
||||
return getBattle()->getEnchanterCounter(side);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoEssentials::battleGetAllObstacles(std::optional<BattlePerspective::BattlePerspective> perspective) const
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoEssentials::battleGetAllObstacles(std::optional<BattleSide> perspective) const
|
||||
{
|
||||
std::vector<std::shared_ptr<const CObstacleInstance> > ret;
|
||||
RETURN_IF_NOT_BATTLE(ret);
|
||||
@ -82,13 +82,13 @@ std::shared_ptr<const CObstacleInstance> CBattleInfoEssentials::battleGetObstacl
|
||||
return std::shared_ptr<const CObstacleInstance>();
|
||||
}
|
||||
|
||||
bool CBattleInfoEssentials::battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattlePerspective::BattlePerspective side) const
|
||||
bool CBattleInfoEssentials::battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattleSide side) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
return side == BattlePerspective::ALL_KNOWING || coi.visibleForSide(side, battleHasNativeStack(side));
|
||||
return side == BattleSide::ALL_KNOWING || coi.visibleForSide(side, battleHasNativeStack(side));
|
||||
}
|
||||
|
||||
bool CBattleInfoEssentials::battleHasNativeStack(ui8 side) const
|
||||
bool CBattleInfoEssentials::battleHasNativeStack(BattleSide side) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
|
||||
@ -160,18 +160,18 @@ const CGTownInstance * CBattleInfoEssentials::battleGetDefendedTown() const
|
||||
return getBattle()->getDefendedTown();
|
||||
}
|
||||
|
||||
BattlePerspective::BattlePerspective CBattleInfoEssentials::battleGetMySide() const
|
||||
BattleSide CBattleInfoEssentials::battleGetMySide() const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(BattlePerspective::INVALID);
|
||||
RETURN_IF_NOT_BATTLE(BattleSide::INVALID);
|
||||
if(!getPlayerID() || getPlayerID()->isSpectator())
|
||||
return BattlePerspective::ALL_KNOWING;
|
||||
return BattleSide::ALL_KNOWING;
|
||||
if(*getPlayerID() == getBattle()->getSidePlayer(BattleSide::ATTACKER))
|
||||
return BattlePerspective::LEFT_SIDE;
|
||||
return BattleSide::LEFT_SIDE;
|
||||
if(*getPlayerID() == getBattle()->getSidePlayer(BattleSide::DEFENDER))
|
||||
return BattlePerspective::RIGHT_SIDE;
|
||||
return BattleSide::RIGHT_SIDE;
|
||||
|
||||
logGlobal->error("Cannot find player %s in battle!", getPlayerID()->toString());
|
||||
return BattlePerspective::INVALID;
|
||||
return BattleSide::INVALID;
|
||||
}
|
||||
|
||||
const CStack* CBattleInfoEssentials::battleGetStackByID(int ID, bool onlyAlive) const
|
||||
@ -189,11 +189,11 @@ const CStack* CBattleInfoEssentials::battleGetStackByID(int ID, bool onlyAlive)
|
||||
return stacks[0];
|
||||
}
|
||||
|
||||
bool CBattleInfoEssentials::battleDoWeKnowAbout(ui8 side) const
|
||||
bool CBattleInfoEssentials::battleDoWeKnowAbout(BattleSide side) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
auto p = battleGetMySide();
|
||||
return p == BattlePerspective::ALL_KNOWING || p == side;
|
||||
return p == BattleSide::ALL_KNOWING || p == side;
|
||||
}
|
||||
|
||||
si8 CBattleInfoEssentials::battleTacticDist() const
|
||||
@ -202,16 +202,16 @@ si8 CBattleInfoEssentials::battleTacticDist() const
|
||||
return getBattle()->getTacticDist();
|
||||
}
|
||||
|
||||
si8 CBattleInfoEssentials::battleGetTacticsSide() const
|
||||
BattleSide CBattleInfoEssentials::battleGetTacticsSide() const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(-1);
|
||||
RETURN_IF_NOT_BATTLE(BattleSide::NONE);
|
||||
return getBattle()->getTacticsSide();
|
||||
}
|
||||
|
||||
const CGHeroInstance * CBattleInfoEssentials::battleGetFightingHero(ui8 side) const
|
||||
const CGHeroInstance * CBattleInfoEssentials::battleGetFightingHero(BattleSide side) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(nullptr);
|
||||
if(side > 1)
|
||||
if(side != BattleSide::DEFENDER && side != BattleSide::ATTACKER)
|
||||
{
|
||||
logGlobal->error("FIXME: %s wrong argument!", __FUNCTION__);
|
||||
return nullptr;
|
||||
@ -226,10 +226,10 @@ const CGHeroInstance * CBattleInfoEssentials::battleGetFightingHero(ui8 side) co
|
||||
return getBattle()->getSideHero(side);
|
||||
}
|
||||
|
||||
const CArmedInstance * CBattleInfoEssentials::battleGetArmyObject(ui8 side) const
|
||||
const CArmedInstance * CBattleInfoEssentials::battleGetArmyObject(BattleSide side) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(nullptr);
|
||||
if(side > 1)
|
||||
if(side != BattleSide::DEFENDER && side != BattleSide::ATTACKER)
|
||||
{
|
||||
logGlobal->error("FIXME: %s wrong argument!", __FUNCTION__);
|
||||
return nullptr;
|
||||
@ -242,7 +242,7 @@ const CArmedInstance * CBattleInfoEssentials::battleGetArmyObject(ui8 side) cons
|
||||
return getBattle()->getSideArmy(side);
|
||||
}
|
||||
|
||||
InfoAboutHero CBattleInfoEssentials::battleGetHeroInfo(ui8 side) const
|
||||
InfoAboutHero CBattleInfoEssentials::battleGetHeroInfo(BattleSide side) const
|
||||
{
|
||||
const auto * hero = getBattle()->getSideHero(side);
|
||||
if(!hero)
|
||||
@ -253,7 +253,7 @@ InfoAboutHero CBattleInfoEssentials::battleGetHeroInfo(ui8 side) const
|
||||
return InfoAboutHero(hero, infoLevel);
|
||||
}
|
||||
|
||||
uint32_t CBattleInfoEssentials::battleCastSpells(ui8 side) const
|
||||
uint32_t CBattleInfoEssentials::battleCastSpells(BattleSide side) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(-1);
|
||||
return getBattle()->getCastSpells(side);
|
||||
@ -268,10 +268,10 @@ bool CBattleInfoEssentials::battleCanFlee(const PlayerColor & player) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
const auto side = playerToSide(player);
|
||||
if(!side)
|
||||
if(side == BattleSide::NONE)
|
||||
return false;
|
||||
|
||||
const CGHeroInstance * myHero = battleGetFightingHero(side.value());
|
||||
const CGHeroInstance * myHero = battleGetFightingHero(side);
|
||||
|
||||
//current player have no hero
|
||||
if(!myHero)
|
||||
@ -292,28 +292,28 @@ bool CBattleInfoEssentials::battleCanFlee(const PlayerColor & player) const
|
||||
return true;
|
||||
}
|
||||
|
||||
BattleSideOpt CBattleInfoEssentials::playerToSide(const PlayerColor & player) const
|
||||
BattleSide CBattleInfoEssentials::playerToSide(const PlayerColor & player) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(std::nullopt);
|
||||
RETURN_IF_NOT_BATTLE(BattleSide::NONE);
|
||||
|
||||
if(getBattle()->getSidePlayer(BattleSide::ATTACKER) == player)
|
||||
return BattleSideOpt(BattleSide::ATTACKER);
|
||||
return BattleSide::ATTACKER;
|
||||
|
||||
if(getBattle()->getSidePlayer(BattleSide::DEFENDER) == player)
|
||||
return BattleSideOpt(BattleSide::DEFENDER);
|
||||
return BattleSide::DEFENDER;
|
||||
|
||||
logGlobal->warn("Cannot find side for player %s", player.toString());
|
||||
|
||||
return std::nullopt;
|
||||
return BattleSide::INVALID;
|
||||
}
|
||||
|
||||
PlayerColor CBattleInfoEssentials::sideToPlayer(ui8 side) const
|
||||
PlayerColor CBattleInfoEssentials::sideToPlayer(BattleSide side) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(PlayerColor::CANNOT_DETERMINE);
|
||||
return getBattle()->getSidePlayer(side);
|
||||
}
|
||||
|
||||
ui8 CBattleInfoEssentials::otherSide(ui8 side) const
|
||||
BattleSide CBattleInfoEssentials::otherSide(BattleSide side)
|
||||
{
|
||||
if(side == BattleSide::ATTACKER)
|
||||
return BattleSide::DEFENDER;
|
||||
@ -326,19 +326,19 @@ PlayerColor CBattleInfoEssentials::otherPlayer(const PlayerColor & player) const
|
||||
RETURN_IF_NOT_BATTLE(PlayerColor::CANNOT_DETERMINE);
|
||||
|
||||
auto side = playerToSide(player);
|
||||
if(!side)
|
||||
if(side == BattleSide::NONE)
|
||||
return PlayerColor::CANNOT_DETERMINE;
|
||||
|
||||
return getBattle()->getSidePlayer(otherSide(side.value()));
|
||||
return getBattle()->getSidePlayer(otherSide(side));
|
||||
}
|
||||
|
||||
bool CBattleInfoEssentials::playerHasAccessToHeroInfo(const PlayerColor & player, const CGHeroInstance * h) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
const auto side = playerToSide(player);
|
||||
if(side)
|
||||
if(side != BattleSide::NONE)
|
||||
{
|
||||
auto opponentSide = otherSide(side.value());
|
||||
auto opponentSide = otherSide(side);
|
||||
if(getBattle()->getSideHero(opponentSide) == h)
|
||||
return true;
|
||||
}
|
||||
@ -355,14 +355,14 @@ bool CBattleInfoEssentials::battleCanSurrender(const PlayerColor & player) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
const auto side = playerToSide(player);
|
||||
if(!side)
|
||||
if(side == BattleSide::NONE)
|
||||
return false;
|
||||
bool iAmSiegeDefender = (side.value() == BattleSide::DEFENDER && getBattle()->getDefendedTown() != nullptr);
|
||||
bool iAmSiegeDefender = (side == BattleSide::DEFENDER && getBattle()->getDefendedTown() != nullptr);
|
||||
//conditions like for fleeing (except escape tunnel presence) + enemy must have a hero
|
||||
return battleCanFlee(player) && !iAmSiegeDefender && battleHasHero(otherSide(side.value()));
|
||||
return battleCanFlee(player) && !iAmSiegeDefender && battleHasHero(otherSide(side));
|
||||
}
|
||||
|
||||
bool CBattleInfoEssentials::battleHasHero(ui8 side) const
|
||||
bool CBattleInfoEssentials::battleHasHero(BattleSide side) const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
return getBattle()->getSideHero(side) != nullptr;
|
||||
@ -413,9 +413,9 @@ const CGHeroInstance * CBattleInfoEssentials::battleGetOwnerHero(const battle::U
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(nullptr);
|
||||
const auto side = playerToSide(battleGetOwner(unit));
|
||||
if(!side)
|
||||
if(side == BattleSide::NONE)
|
||||
return nullptr;
|
||||
return getBattle()->getSideHero(side.value());
|
||||
return getBattle()->getSideHero(side);
|
||||
}
|
||||
|
||||
bool CBattleInfoEssentials::battleMatchOwner(const battle::Unit * attacker, const battle::Unit * defender, const boost::logic::tribool positivness) const
|
||||
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
#include "IBattleInfoCallback.h"
|
||||
#include "BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -22,21 +23,10 @@ class CArmedInstance;
|
||||
using TStacks = std::vector<const CStack *>;
|
||||
using TStackFilter = std::function<bool (const CStack *)>;
|
||||
|
||||
namespace BattlePerspective
|
||||
{
|
||||
enum BattlePerspective
|
||||
{
|
||||
INVALID = -2,
|
||||
ALL_KNOWING = -1,
|
||||
LEFT_SIDE,
|
||||
RIGHT_SIDE
|
||||
};
|
||||
}
|
||||
|
||||
class DLL_LINKAGE CBattleInfoEssentials : public IBattleInfoCallback
|
||||
{
|
||||
protected:
|
||||
bool battleDoWeKnowAbout(ui8 side) const;
|
||||
bool battleDoWeKnowAbout(BattleSide side) const;
|
||||
|
||||
public:
|
||||
enum EStackOwnership
|
||||
@ -45,14 +35,14 @@ public:
|
||||
};
|
||||
|
||||
bool duringBattle() const;
|
||||
BattlePerspective::BattlePerspective battleGetMySide() const;
|
||||
BattleSide battleGetMySide() const;
|
||||
const IBonusBearer * getBonusBearer() const override;
|
||||
|
||||
TerrainId battleTerrainType() const override;
|
||||
BattleField battleGetBattlefieldType() const override;
|
||||
int32_t battleGetEnchanterCounter(ui8 side) const;
|
||||
int32_t battleGetEnchanterCounter(BattleSide side) const;
|
||||
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstacles(std::optional<BattlePerspective::BattlePerspective> perspective = std::nullopt) const; //returns all obstacles on the battlefield
|
||||
std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstacles(std::optional<BattleSide> perspective = std::nullopt) const; //returns all obstacles on the battlefield
|
||||
|
||||
std::shared_ptr<const CObstacleInstance> battleGetObstacleByID(uint32_t ID) const;
|
||||
|
||||
@ -70,27 +60,27 @@ public:
|
||||
|
||||
uint32_t battleNextUnitId() const override;
|
||||
|
||||
bool battleHasNativeStack(ui8 side) const;
|
||||
bool battleHasNativeStack(BattleSide side) const;
|
||||
const CGTownInstance * battleGetDefendedTown() const; //returns defended town if current battle is a siege, nullptr instead
|
||||
|
||||
si8 battleTacticDist() const override; //returns tactic distance in current tactics phase; 0 if not in tactics phase
|
||||
si8 battleGetTacticsSide() const override; //returns which side is in tactics phase, undefined if none (?)
|
||||
BattleSide battleGetTacticsSide() const override; //returns which side is in tactics phase, undefined if none (?)
|
||||
|
||||
bool battleCanFlee(const PlayerColor & player) const;
|
||||
bool battleCanSurrender(const PlayerColor & player) const;
|
||||
|
||||
ui8 otherSide(ui8 side) const;
|
||||
static BattleSide otherSide(BattleSide side);
|
||||
PlayerColor otherPlayer(const PlayerColor & player) const;
|
||||
|
||||
BattleSideOpt playerToSide(const PlayerColor & player) const;
|
||||
PlayerColor sideToPlayer(ui8 side) const;
|
||||
BattleSide playerToSide(const PlayerColor & player) const;
|
||||
PlayerColor sideToPlayer(BattleSide side) const;
|
||||
bool playerHasAccessToHeroInfo(const PlayerColor & player, const CGHeroInstance * h) const;
|
||||
ui8 battleGetSiegeLevel() const; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
||||
bool battleHasHero(ui8 side) const;
|
||||
uint32_t battleCastSpells(ui8 side) const; //how many spells has given side cast
|
||||
const CGHeroInstance * battleGetFightingHero(ui8 side) const; //deprecated for players callback, easy to get wrong
|
||||
const CArmedInstance * battleGetArmyObject(ui8 side) const;
|
||||
InfoAboutHero battleGetHeroInfo(ui8 side) const;
|
||||
bool battleHasHero(BattleSide side) const;
|
||||
uint32_t battleCastSpells(BattleSide side) const; //how many spells has given side cast
|
||||
const CGHeroInstance * battleGetFightingHero(BattleSide side) const; //deprecated for players callback, easy to get wrong
|
||||
const CArmedInstance * battleGetArmyObject(BattleSide side) const;
|
||||
InfoAboutHero battleGetHeroInfo(BattleSide side) const;
|
||||
|
||||
// for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall,
|
||||
// [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
||||
@ -103,7 +93,7 @@ public:
|
||||
TStacks battleGetAllStacks(bool includeTurrets = false) const;
|
||||
|
||||
const CStack * battleGetStackByID(int ID, bool onlyAlive = true) const; //returns stack info by given ID
|
||||
bool battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattlePerspective::BattlePerspective side) const;
|
||||
bool battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattleSide side) const;
|
||||
|
||||
///returns player that controls given stack; mind control included
|
||||
PlayerColor battleGetOwner(const battle::Unit * unit) const;
|
||||
|
@ -52,7 +52,7 @@ std::vector<BattleHex> CObstacleInstance::getAffectedTiles() const
|
||||
}
|
||||
}
|
||||
|
||||
bool CObstacleInstance::visibleForSide(ui8 side, bool hasNativeStack) const
|
||||
bool CObstacleInstance::visibleForSide(BattleSide side, bool hasNativeStack) const
|
||||
{
|
||||
//by default obstacle is visible for everyone
|
||||
return true;
|
||||
@ -134,7 +134,7 @@ SpellCreatedObstacle::SpellCreatedObstacle()
|
||||
: turnsRemaining(-1),
|
||||
casterSpellPower(0),
|
||||
spellLevel(0),
|
||||
casterSide(0),
|
||||
casterSide(BattleSide::NONE),
|
||||
hidden(false),
|
||||
passable(false),
|
||||
trigger(false),
|
||||
@ -148,7 +148,7 @@ SpellCreatedObstacle::SpellCreatedObstacle()
|
||||
obstacleType = SPELL_CREATED;
|
||||
}
|
||||
|
||||
bool SpellCreatedObstacle::visibleForSide(ui8 side, bool hasNativeStack) const
|
||||
bool SpellCreatedObstacle::visibleForSide(BattleSide side, bool hasNativeStack) const
|
||||
{
|
||||
//we hide mines and not discovered quicksands
|
||||
//quicksands are visible to the caster or if owned unit stepped into that particular patch
|
||||
|
@ -50,7 +50,7 @@ struct DLL_LINKAGE CObstacleInstance : public Serializeable
|
||||
virtual SpellID getTrigger() const;
|
||||
|
||||
virtual std::vector<BattleHex> getAffectedTiles() const;
|
||||
virtual bool visibleForSide(ui8 side, bool hasNativeStack) const; //0 attacker
|
||||
virtual bool visibleForSide(BattleSide side, bool hasNativeStack) const; //0 attacker
|
||||
|
||||
virtual void battleTurnPassed(){};
|
||||
|
||||
@ -80,7 +80,7 @@ struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
|
||||
int32_t casterSpellPower;
|
||||
int32_t spellLevel;
|
||||
int32_t minimalDamage; //How many damage should it do regardless of power and level of caster
|
||||
si8 casterSide; //0 - obstacle created by attacker; 1 - by defender
|
||||
BattleSide casterSide;
|
||||
|
||||
SpellID trigger;
|
||||
|
||||
@ -102,7 +102,7 @@ struct DLL_LINKAGE SpellCreatedObstacle : CObstacleInstance
|
||||
SpellCreatedObstacle();
|
||||
|
||||
std::vector<BattleHex> getAffectedTiles() const override;
|
||||
bool visibleForSide(ui8 side, bool hasNativeStack) const override;
|
||||
bool visibleForSide(BattleSide side, bool hasNativeStack) const override;
|
||||
|
||||
bool blocksTiles() const override;
|
||||
bool stopsMovement() const override;
|
||||
|
@ -76,7 +76,7 @@ const CGHeroInstance * CPlayerBattleCallback::battleGetMyHero() const
|
||||
|
||||
InfoAboutHero CPlayerBattleCallback::battleGetEnemyHero() const
|
||||
{
|
||||
return battleGetHeroInfo(!battleGetMySide());
|
||||
return battleGetHeroInfo(otherSide(battleGetMySide()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -921,7 +921,7 @@ uint32_t CUnitStateDetached::unitId() const
|
||||
return unit->unitId();
|
||||
}
|
||||
|
||||
ui8 CUnitStateDetached::unitSide() const
|
||||
BattleSide CUnitStateDetached::unitSide() const
|
||||
{
|
||||
return unit->unitSide();
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ public:
|
||||
CUnitStateDetached & operator= (const CUnitState & other);
|
||||
|
||||
uint32_t unitId() const override;
|
||||
ui8 unitSide() const override;
|
||||
BattleSide unitSide() const override;
|
||||
|
||||
const CCreature * unitType() const override;
|
||||
PlayerColor unitOwner() const override;
|
||||
|
@ -65,10 +65,10 @@ public:
|
||||
virtual BattleField battleGetBattlefieldType() const = 0;
|
||||
|
||||
///return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
|
||||
virtual std::optional<int> battleIsFinished() const = 0;
|
||||
virtual std::optional<BattleSide> battleIsFinished() const = 0;
|
||||
|
||||
virtual si8 battleTacticDist() const = 0; //returns tactic distance in current tactics phase; 0 if not in tactics phase
|
||||
virtual si8 battleGetTacticsSide() const = 0; //returns which side is in tactics phase, undefined if none (?)
|
||||
virtual BattleSide battleGetTacticsSide() const = 0; //returns which side is in tactics phase, undefined if none (?)
|
||||
|
||||
virtual uint32_t battleNextUnitId() const = 0;
|
||||
|
||||
|
@ -55,17 +55,17 @@ public:
|
||||
virtual EWallState getWallState(EWallPart partOfWall) const = 0;
|
||||
virtual EGateState getGateState() const = 0;
|
||||
|
||||
virtual PlayerColor getSidePlayer(ui8 side) const = 0;
|
||||
virtual const CArmedInstance * getSideArmy(ui8 side) const = 0;
|
||||
virtual const CGHeroInstance * getSideHero(ui8 side) const = 0;
|
||||
virtual PlayerColor getSidePlayer(BattleSide side) const = 0;
|
||||
virtual const CArmedInstance * getSideArmy(BattleSide side) const = 0;
|
||||
virtual const CGHeroInstance * getSideHero(BattleSide side) const = 0;
|
||||
/// Returns list of all spells used by specified side (and that can be learned by opposite hero)
|
||||
virtual std::vector<SpellID> getUsedSpells(ui8 side) const = 0;
|
||||
virtual std::vector<SpellID> getUsedSpells(BattleSide side) const = 0;
|
||||
|
||||
virtual uint32_t getCastSpells(ui8 side) const = 0;
|
||||
virtual int32_t getEnchanterCounter(ui8 side) const = 0;
|
||||
virtual uint32_t getCastSpells(BattleSide side) const = 0;
|
||||
virtual int32_t getEnchanterCounter(BattleSide side) const = 0;
|
||||
|
||||
virtual ui8 getTacticDist() const = 0;
|
||||
virtual ui8 getTacticsSide() const = 0;
|
||||
virtual BattleSide getTacticsSide() const = 0;
|
||||
|
||||
virtual uint32_t nextUnitId() const = 0;
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../GameConstants.h"
|
||||
#include "BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -35,7 +36,7 @@ public:
|
||||
virtual int32_t unitBaseAmount() const = 0;
|
||||
|
||||
virtual uint32_t unitId() const = 0;
|
||||
virtual ui8 unitSide() const = 0;
|
||||
virtual BattleSide unitSide() const = 0;
|
||||
virtual PlayerColor unitOwner() const = 0;
|
||||
virtual SlotID unitSlot() const = 0;
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
ReachabilityInfo::Parameters::Parameters(const battle::Unit * Stack, BattleHex StartPosition):
|
||||
perspective(static_cast<BattlePerspective::BattlePerspective>(Stack->unitSide())),
|
||||
perspective(static_cast<BattleSide>(Stack->unitSide())),
|
||||
startPosition(StartPosition),
|
||||
doubleWide(Stack->doubleWide()),
|
||||
side(Stack->unitSide()),
|
||||
|
@ -25,14 +25,14 @@ struct DLL_LINKAGE ReachabilityInfo
|
||||
|
||||
struct DLL_LINKAGE Parameters
|
||||
{
|
||||
ui8 side = 0;
|
||||
BattleSide side = BattleSide::NONE;
|
||||
bool doubleWide = false;
|
||||
bool flying = false;
|
||||
bool ignoreKnownAccessible = false; //Ignore obstacles if it is in accessible hexes
|
||||
std::vector<BattleHex> knownAccessible; //hexes that will be treated as accessible, even if they're occupied by stack (by default - tiles occupied by stack we do reachability for, so it doesn't block itself)
|
||||
|
||||
BattleHex startPosition; //assumed position of stack
|
||||
BattlePerspective::BattlePerspective perspective = BattlePerspective::ALL_KNOWING; //some obstacles (eg. quicksands) may be invisible for some side
|
||||
BattleSide perspective = BattleSide::ALL_KNOWING; //some obstacles (eg. quicksands) may be invisible for some side
|
||||
|
||||
Parameters() = default;
|
||||
Parameters(const battle::Unit * Stack, BattleHex StartPosition);
|
||||
|
@ -41,7 +41,7 @@ bool Unit::isTurret() const
|
||||
std::string Unit::getDescription() const
|
||||
{
|
||||
boost::format fmt("Unit %d of side %d");
|
||||
fmt % unitId() % unitSide();
|
||||
fmt % unitId() % static_cast<int>(unitSide());
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ std::vector<BattleHex> Unit::getSurroundingHexes(BattleHex assumedPosition) cons
|
||||
return getSurroundingHexes(hex, doubleWide(), unitSide());
|
||||
}
|
||||
|
||||
std::vector<BattleHex> Unit::getSurroundingHexes(BattleHex position, bool twoHex, ui8 side)
|
||||
std::vector<BattleHex> Unit::getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side)
|
||||
{
|
||||
std::vector<BattleHex> hexes;
|
||||
if(twoHex)
|
||||
@ -135,7 +135,7 @@ std::vector<BattleHex> Unit::getHexes(BattleHex assumedPos) const
|
||||
return getHexes(assumedPos, doubleWide(), unitSide());
|
||||
}
|
||||
|
||||
std::vector<BattleHex> Unit::getHexes(BattleHex assumedPos, bool twoHex, ui8 side)
|
||||
std::vector<BattleHex> Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleSide side)
|
||||
{
|
||||
std::vector<BattleHex> hexes;
|
||||
hexes.push_back(assumedPos);
|
||||
@ -156,7 +156,7 @@ BattleHex Unit::occupiedHex(BattleHex assumedPos) const
|
||||
return occupiedHex(assumedPos, doubleWide(), unitSide());
|
||||
}
|
||||
|
||||
BattleHex Unit::occupiedHex(BattleHex assumedPos, bool twoHex, ui8 side)
|
||||
BattleHex Unit::occupiedHex(BattleHex assumedPos, bool twoHex, BattleSide side)
|
||||
{
|
||||
if(twoHex)
|
||||
{
|
||||
|
@ -129,17 +129,17 @@ public:
|
||||
|
||||
std::vector<BattleHex> getSurroundingHexes(BattleHex assumedPosition = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
|
||||
std::vector<BattleHex> getAttackableHexes(const Unit * attacker) const;
|
||||
static std::vector<BattleHex> getSurroundingHexes(BattleHex position, bool twoHex, ui8 side);
|
||||
static std::vector<BattleHex> getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side);
|
||||
|
||||
bool coversPos(BattleHex position) const; //checks also if unit is double-wide
|
||||
|
||||
std::vector<BattleHex> getHexes() const; //up to two occupied hexes, starting from front
|
||||
std::vector<BattleHex> getHexes(BattleHex assumedPos) const; //up to two occupied hexes, starting from front
|
||||
static std::vector<BattleHex> getHexes(BattleHex assumedPos, bool twoHex, ui8 side);
|
||||
static std::vector<BattleHex> getHexes(BattleHex assumedPos, bool twoHex, BattleSide side);
|
||||
|
||||
BattleHex occupiedHex() const; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1
|
||||
BattleHex occupiedHex(BattleHex assumedPos) const; //returns number of occupied hex (not the position) if stack is double wide and would stand on assumedPos; otherwise -1
|
||||
static BattleHex occupiedHex(BattleHex assumedPos, bool twoHex, ui8 side);
|
||||
static BattleHex occupiedHex(BattleHex assumedPos, bool twoHex, BattleSide side);
|
||||
|
||||
///MetaStrings
|
||||
void addText(MetaString & text, EMetaText type, int32_t serial, const boost::logic::tribool & plural = boost::logic::indeterminate) const;
|
||||
@ -166,7 +166,7 @@ public:
|
||||
uint32_t id = 0;
|
||||
TQuantity count = 0;
|
||||
CreatureID type;
|
||||
ui8 side = 0;
|
||||
BattleSide side = BattleSide::NONE;
|
||||
BattleHex position;
|
||||
bool summoned = false;
|
||||
|
||||
|
@ -1020,7 +1020,7 @@ const BattleInfo * CGameState::getBattle(const PlayerColor & player) const
|
||||
return nullptr;
|
||||
|
||||
for (const auto & battlePtr : currentBattles)
|
||||
if (battlePtr->sides[0].color == player || battlePtr->sides[1].color == player)
|
||||
if (battlePtr->getSide(BattleSide::ATTACKER).color == player || battlePtr->getSide(BattleSide::DEFENDER).color == player)
|
||||
return battlePtr.get();
|
||||
|
||||
return nullptr;
|
||||
|
@ -387,7 +387,7 @@ void CBank::doVisit(const CGHeroInstance * hero) const
|
||||
|
||||
void CBank::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{
|
||||
if (result.winner == 0)
|
||||
if (result.winner == BattleSide::ATTACKER)
|
||||
{
|
||||
doVisit(hero);
|
||||
}
|
||||
|
@ -480,12 +480,12 @@ void CGCreature::flee( const CGHeroInstance * h ) const
|
||||
|
||||
void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{
|
||||
if(result.winner == 0)
|
||||
if(result.winner == BattleSide::ATTACKER)
|
||||
{
|
||||
giveReward(hero);
|
||||
cb->removeObject(this, hero->getOwner());
|
||||
}
|
||||
else if(result.winner > 1) // draw
|
||||
else if(result.winner == BattleSide::NONE) // draw
|
||||
{
|
||||
// guarded reward is lost forever on draw
|
||||
cb->removeObject(this, hero->getOwner());
|
||||
|
@ -510,7 +510,7 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h) const
|
||||
|
||||
void CGDwelling::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{
|
||||
if (result.winner == 0)
|
||||
if (result.winner == BattleSide::ATTACKER)
|
||||
{
|
||||
onHeroVisit(hero);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "../StartInfo.h"
|
||||
#include "CGTownInstance.h"
|
||||
#include "../entities/faction/CTownHandler.h"
|
||||
#include "../battle/CBattleInfoEssentials.h"
|
||||
#include "../campaign/CampaignState.h"
|
||||
#include "../json/JsonBonus.h"
|
||||
#include "../pathfinder/TurnInfo.h"
|
||||
@ -880,7 +881,7 @@ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &b
|
||||
double necromancySkill = valOfBonuses(BonusType::UNDEAD_RAISE_PERCENTAGE) / 100.0;
|
||||
const ui8 necromancyLevel = valOfBonuses(BonusType::IMPROVED_NECROMANCY);
|
||||
vstd::amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all...
|
||||
const std::map<CreatureID,si32> &casualties = battleResult.casualties[!battleResult.winner];
|
||||
const std::map<CreatureID,si32> &casualties = battleResult.casualties[CBattleInfoEssentials::otherSide(battleResult.winner)];
|
||||
// figure out what to raise - pick strongest creature meeting requirements
|
||||
CreatureID creatureTypeRaised = CreatureID::NONE; //now we always have IMPROVED_NECROMANCY, no need for hardcode
|
||||
int requiredCasualtyLevel = 1;
|
||||
|
@ -180,7 +180,7 @@ void CGPandoraBox::onHeroVisit(const CGHeroInstance * h) const
|
||||
|
||||
void CGPandoraBox::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{
|
||||
if(result.winner == 0)
|
||||
if(result.winner == BattleSide::ATTACKER)
|
||||
{
|
||||
CRewardableObject::onHeroVisit(hero);
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ ui32 CGMine::getProducedQuantity() const
|
||||
|
||||
void CGMine::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{
|
||||
if(result.winner == 0) //attacker won
|
||||
if(result.winner == BattleSide::ATTACKER) //attacker won
|
||||
{
|
||||
if(isAbandoned())
|
||||
{
|
||||
@ -344,7 +344,7 @@ void CGResource::collectRes(const PlayerColor & player) const
|
||||
|
||||
void CGResource::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{
|
||||
if(result.winner == 0) //attacker won
|
||||
if(result.winner == BattleSide::ATTACKER) //attacker won
|
||||
collectRes(hero->getOwner());
|
||||
}
|
||||
|
||||
@ -911,7 +911,7 @@ BattleField CGArtifact::getBattlefield() const
|
||||
|
||||
void CGArtifact::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{
|
||||
if(result.winner == 0) //attacker won
|
||||
if(result.winner == BattleSide::ATTACKER) //attacker won
|
||||
pick(hero);
|
||||
}
|
||||
|
||||
@ -1010,7 +1010,7 @@ bool CGGarrison::passableFor(PlayerColor player) const
|
||||
|
||||
void CGGarrison::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{
|
||||
if (result.winner == 0)
|
||||
if (result.winner == BattleSide::ATTACKER)
|
||||
onHeroVisit(hero);
|
||||
}
|
||||
|
||||
|
@ -2114,7 +2114,7 @@ void BattleResultAccepted::applyGs(CGameState * gs) const
|
||||
res.hero->removeBonusesRecursive(Bonus::OneBattle);
|
||||
}
|
||||
|
||||
if(winnerSide != 2)
|
||||
if(winnerSide != BattleSide::NONE)
|
||||
{
|
||||
// Grow up growing artifacts
|
||||
const auto hero = heroResult[winnerSide].hero;
|
||||
@ -2135,10 +2135,10 @@ void BattleResultAccepted::applyGs(CGameState * gs) const
|
||||
|
||||
if(VLC->settings()->getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
|
||||
{
|
||||
if(heroResult[0].army)
|
||||
heroResult[0].army->giveStackExp(heroResult[0].exp);
|
||||
if(heroResult[1].army)
|
||||
heroResult[1].army->giveStackExp(heroResult[1].exp);
|
||||
if(heroResult[BattleSide::ATTACKER].army)
|
||||
heroResult[BattleSide::ATTACKER].army->giveStackExp(heroResult[BattleSide::ATTACKER].exp);
|
||||
if(heroResult[BattleSide::DEFENDER].army)
|
||||
heroResult[BattleSide::DEFENDER].army->giveStackExp(heroResult[BattleSide::DEFENDER].exp);
|
||||
CBonusSystemNode::treeHasChanged();
|
||||
}
|
||||
|
||||
@ -2242,19 +2242,14 @@ void StartAction::applyGs(CGameState *gs)
|
||||
else
|
||||
{
|
||||
if(ba.actionType == EActionType::HERO_SPELL)
|
||||
gs->getBattle(battleID)->sides[ba.side].usedSpellsHistory.push_back(ba.spell);
|
||||
gs->getBattle(battleID)->getSide(ba.side).usedSpellsHistory.push_back(ba.spell);
|
||||
}
|
||||
}
|
||||
|
||||
void BattleSpellCast::applyGs(CGameState * gs) const
|
||||
{
|
||||
if(castByHero)
|
||||
{
|
||||
if(side < 2)
|
||||
{
|
||||
gs->getBattle(battleID)->sides[side].castSpellsCount++;
|
||||
}
|
||||
}
|
||||
if(castByHero && side != BattleSide::NONE)
|
||||
gs->getBattle(battleID)->getSide(side).castSpellsCount++;
|
||||
}
|
||||
|
||||
void SetStackEffect::applyGs(CGameState *gs)
|
||||
@ -2388,7 +2383,7 @@ void BattleSetStackProperty::applyGs(CGameState * gs) const
|
||||
}
|
||||
case ENCHANTER_COUNTER:
|
||||
{
|
||||
auto & counter = gs->getBattle(battleID)->sides[gs->getBattle(battleID)->whatSide(stack->unitOwner())].enchanterCounter;
|
||||
auto & counter = gs->getBattle(battleID)->getSide(gs->getBattle(battleID)->whatSide(stack->unitOwner())).enchanterCounter;
|
||||
if(absolute)
|
||||
counter = val;
|
||||
else
|
||||
|
@ -109,8 +109,8 @@ struct DLL_LINKAGE BattleResultAccepted : public CPackForClient
|
||||
};
|
||||
|
||||
BattleID battleID = BattleID::NONE;
|
||||
std::array<HeroBattleResults, 2> heroResult;
|
||||
ui8 winnerSide;
|
||||
BattleSideArray<HeroBattleResults> heroResult;
|
||||
BattleSide winnerSide;
|
||||
|
||||
template <typename Handler> void serialize(Handler & h)
|
||||
{
|
||||
@ -127,9 +127,9 @@ struct DLL_LINKAGE BattleResult : public Query
|
||||
|
||||
BattleID battleID = BattleID::NONE;
|
||||
EBattleResult result = EBattleResult::NORMAL;
|
||||
ui8 winner = 2; //0 - attacker, 1 - defender, [2 - draw (should be possible?)]
|
||||
std::map<CreatureID, si32> casualties[2]; //first => casualties of attackers - map crid => number
|
||||
TExpType exp[2] = {0, 0}; //exp for attacker and defender
|
||||
BattleSide winner = BattleSide::NONE; //0 - attacker, 1 - defender, [2 - draw (should be possible?)]
|
||||
BattleSideArray<std::map<CreatureID, si32>> casualties; //first => casualties of attackers - map crid => number
|
||||
BattleSideArray<TExpType> exp{0,0}; //exp for attacker and defender
|
||||
std::set<ArtifactInstanceID> artifacts; //artifacts taken from loser to winner - currently unused
|
||||
|
||||
void visitTyped(ICPackVisitor & visitor) override;
|
||||
@ -140,8 +140,7 @@ struct DLL_LINKAGE BattleResult : public Query
|
||||
h & queryID;
|
||||
h & result;
|
||||
h & winner;
|
||||
h & casualties[0];
|
||||
h & casualties[1];
|
||||
h & casualties;
|
||||
h & exp;
|
||||
h & artifacts;
|
||||
assert(battleID != BattleID::NONE);
|
||||
@ -369,7 +368,7 @@ struct DLL_LINKAGE BattleSpellCast : public CPackForClient
|
||||
|
||||
BattleID battleID = BattleID::NONE;
|
||||
bool activeCast = true;
|
||||
ui8 side = 0; //which hero did cast spell: 0 - attacker, 1 - defender
|
||||
BattleSide side = BattleSide::NONE; //which hero did cast spell
|
||||
SpellID spellID; //id of spell
|
||||
ui8 manaGained = 0; //mana channeling ability
|
||||
BattleHex tile; //destination tile (may not be set in some global/mass spells
|
||||
|
@ -193,16 +193,16 @@ bool BattleSpellMechanics::canBeCast(Problem & problem) const
|
||||
return adaptProblem(ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL, problem);
|
||||
|
||||
const PlayerColor player = caster->getCasterOwner();
|
||||
const auto side = battle()->playerToSide(player);
|
||||
const BattleSide side = battle()->playerToSide(player);
|
||||
|
||||
if(!side)
|
||||
if(side == BattleSide::NONE)
|
||||
return adaptProblem(ESpellCastProblem::INVALID, problem);
|
||||
|
||||
//effect like Recanter's Cloak. Blocks also passive casting.
|
||||
//TODO: check creature abilities to block
|
||||
//TODO: check any possible caster
|
||||
|
||||
if(battle()->battleMaxSpellLevel(side.value()) < getSpellLevel() || battle()->battleMinSpellLevel(side.value()) > getSpellLevel())
|
||||
if(battle()->battleMaxSpellLevel(side) < getSpellLevel() || battle()->battleMinSpellLevel(side) > getSpellLevel())
|
||||
return adaptProblem(ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED, problem);
|
||||
|
||||
return effects->applicable(problem, this);
|
||||
@ -284,7 +284,7 @@ void BattleSpellMechanics::cast(ServerCallback * server, const Target & target)
|
||||
const CGHeroInstance * otherHero = nullptr;
|
||||
{
|
||||
//check it there is opponent hero
|
||||
const ui8 otherSide = battle()->otherSide(casterSide);
|
||||
const BattleSide otherSide = battle()->otherSide(casterSide);
|
||||
|
||||
if(battle()->battleHasHero(otherSide))
|
||||
otherHero = battle()->battleGetFightingHero(otherSide);
|
||||
|
@ -397,7 +397,7 @@ std::unique_ptr<ISpellMechanicsFactory> ISpellMechanicsFactory::get(const CSpell
|
||||
///Mechanics
|
||||
Mechanics::Mechanics()
|
||||
: caster(nullptr),
|
||||
casterSide(0)
|
||||
casterSide(BattleSide::NONE)
|
||||
{
|
||||
|
||||
}
|
||||
@ -413,8 +413,7 @@ BaseMechanics::BaseMechanics(const IBattleCast * event):
|
||||
{
|
||||
caster = event->getCaster();
|
||||
|
||||
//FIXME: do not crash on invalid side
|
||||
casterSide = cb->playerToSide(caster->getCasterOwner()).value();
|
||||
casterSide = cb->playerToSide(caster->getCasterOwner());
|
||||
|
||||
{
|
||||
auto value = event->getSpellLevel();
|
||||
|
@ -252,7 +252,7 @@ public:
|
||||
|
||||
const Caster * caster;
|
||||
|
||||
ui8 casterSide;
|
||||
BattleSide casterSide;
|
||||
|
||||
protected:
|
||||
Mechanics();
|
||||
|
@ -134,7 +134,7 @@ void Moat::placeObstacles(ServerCallback * server, const Mechanics * m, const Ef
|
||||
BattleObstaclesChanged pack;
|
||||
pack.battleID = m->battle()->getBattle()->getBattleID();
|
||||
|
||||
auto all = m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING);
|
||||
auto all = m->battle()->battleGetAllObstacles(BattleSide::ALL_KNOWING);
|
||||
|
||||
int obstacleIdToGive = 1;
|
||||
for(auto & one : all)
|
||||
|
@ -274,7 +274,7 @@ void Obstacle::placeObstacles(ServerCallback * server, const Mechanics * m, cons
|
||||
BattleObstaclesChanged pack;
|
||||
pack.battleID = m->battle()->getBattle()->getBattleID();
|
||||
|
||||
auto all = m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING);
|
||||
auto all = m->battle()->battleGetAllObstacles(BattleSide::ALL_KNOWING);
|
||||
|
||||
int obstacleIdToGive = 1;
|
||||
for(auto & one : all)
|
||||
|
@ -66,7 +66,7 @@ private:
|
||||
bool passable = false;
|
||||
int32_t turnsRemaining = -1;
|
||||
|
||||
std::array<ObstacleSideOptions, 2> sideOptions;
|
||||
BattleSideArray<ObstacleSideOptions> sideOptions;
|
||||
|
||||
static bool isHexAvailable(const CBattleInfoCallback * cb, const BattleHex & hex, const bool mustBeClear);
|
||||
static bool noRoomToPlace(Problem & problem, const Mechanics * m);
|
||||
|
@ -90,7 +90,7 @@ std::set<const CObstacleInstance *> RemoveObstacle::getTargets(const Mechanics *
|
||||
std::set<const CObstacleInstance *> possibleTargets;
|
||||
if(m->isMassive() || alwaysMassive)
|
||||
{
|
||||
for(const auto & obstacle : m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING))
|
||||
for(const auto & obstacle : m->battle()->battleGetAllObstacles(BattleSide::ALL_KNOWING))
|
||||
if(canRemove(obstacle.get()))
|
||||
possibleTargets.insert(obstacle.get());
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ void TurnTimerHandler::onBattleLoop(const BattleID & battleID, int waitTime)
|
||||
if (!si->turnTimerInfo.isBattleEnabled())
|
||||
return;
|
||||
|
||||
ui8 side = 0;
|
||||
BattleSide side = BattleSide::NONE;
|
||||
const CStack * stack = nullptr;
|
||||
bool isTactisPhase = gs->getBattle(battleID)->battleTacticDist() > 0;
|
||||
|
||||
|
@ -65,7 +65,7 @@ bool BattleActionProcessor::doRetreatAction(const CBattleInfoCallback & battle,
|
||||
return false;
|
||||
}
|
||||
|
||||
owner->setBattleResult(battle, EBattleResult::ESCAPE, !ba.side);
|
||||
owner->setBattleResult(battle, EBattleResult::ESCAPE, battle.otherSide(ba.side));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ bool BattleActionProcessor::doSurrenderAction(const CBattleInfoCallback & battle
|
||||
}
|
||||
|
||||
gameHandler->giveResource(player, EGameResID::GOLD, -cost);
|
||||
owner->setBattleResult(battle, EBattleResult::SURRENDER, !ba.side);
|
||||
owner->setBattleResult(battle, EBattleResult::SURRENDER, battle.otherSide(ba.side));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1574,7 +1574,7 @@ bool BattleActionProcessor::makeAutomaticBattleAction(const CBattleInfoCallback
|
||||
|
||||
bool BattleActionProcessor::makePlayerBattleAction(const CBattleInfoCallback & battle, PlayerColor player, const BattleAction &ba)
|
||||
{
|
||||
if (ba.side != 0 && ba.side != 1 && gameHandler->complain("Can not make action - invalid battle side!"))
|
||||
if (ba.side != BattleSide::ATTACKER && ba.side != BattleSide::DEFENDER && gameHandler->complain("Can not make action - invalid battle side!"))
|
||||
return false;
|
||||
|
||||
if(battle.battleGetTacticDist() != 0)
|
||||
|
@ -34,7 +34,7 @@ BattleFlowProcessor::BattleFlowProcessor(BattleProcessor * owner, CGameHandler *
|
||||
{
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::summonGuardiansHelper(const CBattleInfoCallback & battle, std::vector<BattleHex> & output, const BattleHex & targetPosition, ui8 side, bool targetIsTwoHex) //return hexes for summoning two hex monsters in output, target = unit to guard
|
||||
void BattleFlowProcessor::summonGuardiansHelper(const CBattleInfoCallback & battle, std::vector<BattleHex> & output, const BattleHex & targetPosition, BattleSide side, bool targetIsTwoHex) //return hexes for summoning two hex monsters in output, target = unit to guard
|
||||
{
|
||||
int x = targetPosition.getX();
|
||||
int y = targetPosition.getY();
|
||||
@ -185,7 +185,7 @@ void BattleFlowProcessor::trySummonGuardians(const CBattleInfoCallback & battle,
|
||||
|
||||
void BattleFlowProcessor::castOpeningSpells(const CBattleInfoCallback & battle)
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
{
|
||||
auto h = battle.battleGetFightingHero(i);
|
||||
if (!h)
|
||||
@ -742,7 +742,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
|
||||
return b->subtype.as<SpellID>() == SpellID::NONE;
|
||||
});
|
||||
|
||||
int side = *battle.playerToSide(st->unitOwner());
|
||||
BattleSide side = battle.playerToSide(st->unitOwner());
|
||||
if(st->canCast() && battle.battleGetEnchanterCounter(side) == 0)
|
||||
{
|
||||
bool cast = false;
|
||||
|
@ -9,6 +9,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../lib/battle/BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CStack;
|
||||
struct BattleHex;
|
||||
@ -35,7 +37,7 @@ class BattleFlowProcessor : boost::noncopyable
|
||||
bool rollGoodMorale(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
bool tryMakeAutomaticAction(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
|
||||
void summonGuardiansHelper(const CBattleInfoCallback & battle, std::vector<BattleHex> & output, const BattleHex & targetPosition, ui8 side, bool targetIsTwoHex);
|
||||
void summonGuardiansHelper(const CBattleInfoCallback & battle, std::vector<BattleHex> & output, const BattleHex & targetPosition, BattleSide side, bool targetIsTwoHex);
|
||||
void trySummonGuardians(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void tryPlaceMoats(const CBattleInfoCallback & battle);
|
||||
void castOpeningSpells(const CBattleInfoCallback & battle);
|
||||
|
@ -57,20 +57,18 @@ void BattleProcessor::restartBattlePrimary(const BattleID & battleID, const CArm
|
||||
{
|
||||
auto battle = gameHandler->gameState()->getBattle(battleID);
|
||||
|
||||
auto lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle->sides[0].color));
|
||||
auto lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle->getSide(BattleSide::ATTACKER).color));
|
||||
if(!lastBattleQuery)
|
||||
lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle->sides[1].color));
|
||||
lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle->getSide(BattleSide::DEFENDER).color));
|
||||
|
||||
assert(lastBattleQuery);
|
||||
|
||||
//existing battle query for retying auto-combat
|
||||
if(lastBattleQuery)
|
||||
{
|
||||
const CGHeroInstance*heroes[2];
|
||||
heroes[0] = hero1;
|
||||
heroes[1] = hero2;
|
||||
BattleSideArray<const CGHeroInstance*> heroes{hero1, hero2};
|
||||
|
||||
for(int i : {0, 1})
|
||||
for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
{
|
||||
if(heroes[i])
|
||||
{
|
||||
@ -83,8 +81,8 @@ void BattleProcessor::restartBattlePrimary(const BattleID & battleID, const CArm
|
||||
|
||||
lastBattleQuery->result = std::nullopt;
|
||||
|
||||
assert(lastBattleQuery->belligerents[0] == battle->sides[0].armyObject);
|
||||
assert(lastBattleQuery->belligerents[1] == battle->sides[1].armyObject);
|
||||
assert(lastBattleQuery->belligerents[BattleSide::ATTACKER] == battle->getSide(BattleSide::ATTACKER).armyObject);
|
||||
assert(lastBattleQuery->belligerents[BattleSide::DEFENDER] == battle->getSide(BattleSide::DEFENDER).armyObject);
|
||||
}
|
||||
|
||||
BattleCancelled bc;
|
||||
@ -101,12 +99,8 @@ void BattleProcessor::startBattlePrimary(const CArmedInstance *army1, const CArm
|
||||
assert(gameHandler->gameState()->getBattle(army1->getOwner()) == nullptr);
|
||||
assert(gameHandler->gameState()->getBattle(army2->getOwner()) == nullptr);
|
||||
|
||||
const CArmedInstance *armies[2];
|
||||
armies[0] = army1;
|
||||
armies[1] = army2;
|
||||
const CGHeroInstance*heroes[2];
|
||||
heroes[0] = hero1;
|
||||
heroes[1] = hero2;
|
||||
BattleSideArray<const CArmedInstance *> armies{army1, army2};
|
||||
BattleSideArray<const CGHeroInstance*>heroes{hero1, hero2};
|
||||
|
||||
auto battleID = setupBattle(tile, armies, heroes, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
|
||||
|
||||
@ -126,9 +120,9 @@ void BattleProcessor::startBattlePrimary(const CArmedInstance *army1, const CArm
|
||||
}
|
||||
}
|
||||
|
||||
auto lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle->sides[0].color));
|
||||
auto lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle->getSide(BattleSide::ATTACKER).color));
|
||||
if(!lastBattleQuery)
|
||||
lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle->sides[1].color));
|
||||
lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle->getSide(BattleSide::DEFENDER).color));
|
||||
|
||||
if (lastBattleQuery)
|
||||
{
|
||||
@ -139,7 +133,7 @@ void BattleProcessor::startBattlePrimary(const CArmedInstance *army1, const CArm
|
||||
auto newBattleQuery = std::make_shared<CBattleQuery>(gameHandler, battle);
|
||||
|
||||
// store initial mana to reset if battle has been restarted
|
||||
for(int i : {0, 1})
|
||||
for(auto i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
|
||||
if(heroes[i])
|
||||
newBattleQuery->initialHeroMana[i] = heroes[i]->mana;
|
||||
|
||||
@ -162,7 +156,7 @@ void BattleProcessor::startBattleI(const CArmedInstance *army1, const CArmedInst
|
||||
startBattleI(army1, army2, army2->visitablePos(), creatureBank);
|
||||
}
|
||||
|
||||
BattleID BattleProcessor::setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance *heroes[2], bool creatureBank, const CGTownInstance *town)
|
||||
BattleID BattleProcessor::setupBattle(int3 tile, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, bool creatureBank, const CGTownInstance *town)
|
||||
{
|
||||
const auto & t = *gameHandler->getTile(tile);
|
||||
TerrainId terrain = t.terType->getId();
|
||||
@ -170,7 +164,7 @@ BattleID BattleProcessor::setupBattle(int3 tile, const CArmedInstance *armies[2]
|
||||
terrain = ETerrainId::SAND;
|
||||
|
||||
BattleField terType = gameHandler->gameState()->battleGetBattlefieldType(tile, gameHandler->getRandomGenerator());
|
||||
if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat)
|
||||
if (heroes[BattleSide::ATTACKER] && heroes[BattleSide::ATTACKER]->boat && heroes[BattleSide::DEFENDER] && heroes[BattleSide::DEFENDER]->boat)
|
||||
terType = BattleField(*VLC->identifiers()->getIdentifier("core", "battlefield.ship_to_ship"));
|
||||
|
||||
//send info about battles
|
||||
@ -178,14 +172,14 @@ BattleID BattleProcessor::setupBattle(int3 tile, const CArmedInstance *armies[2]
|
||||
bs.info = BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town);
|
||||
bs.battleID = gameHandler->gameState()->nextBattleID;
|
||||
|
||||
engageIntoBattle(bs.info->sides[0].color);
|
||||
engageIntoBattle(bs.info->sides[1].color);
|
||||
engageIntoBattle(bs.info->getSide(BattleSide::ATTACKER).color);
|
||||
engageIntoBattle(bs.info->getSide(BattleSide::DEFENDER).color);
|
||||
|
||||
auto lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(bs.info->sides[0].color));
|
||||
auto lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(bs.info->getSide(BattleSide::ATTACKER).color));
|
||||
if(!lastBattleQuery)
|
||||
lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(bs.info->sides[1].color));
|
||||
bool isDefenderHuman = bs.info->sides[1].color.isValidPlayer() && gameHandler->getPlayerState(bs.info->sides[1].color)->isHuman();
|
||||
bool isAttackerHuman = gameHandler->getPlayerState(bs.info->sides[0].color)->isHuman();
|
||||
lastBattleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(bs.info->getSide(BattleSide::DEFENDER).color));
|
||||
bool isDefenderHuman = bs.info->getSide(BattleSide::DEFENDER).color.isValidPlayer() && gameHandler->getPlayerState(bs.info->getSide(BattleSide::DEFENDER).color)->isHuman();
|
||||
bool isAttackerHuman = gameHandler->getPlayerState(bs.info->getSide(BattleSide::ATTACKER).color)->isHuman();
|
||||
|
||||
bool onlyOnePlayerHuman = isDefenderHuman != isAttackerHuman;
|
||||
bs.info->replayAllowed = lastBattleQuery == nullptr && onlyOnePlayerHuman;
|
||||
@ -284,7 +278,7 @@ bool BattleProcessor::makePlayerBattleAction(const BattleID & battleID, PlayerCo
|
||||
return result;
|
||||
}
|
||||
|
||||
void BattleProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide)
|
||||
void BattleProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, BattleSide victoriusSide)
|
||||
{
|
||||
resultProcessor->setBattleResult(battle, resultType, victoriusSide);
|
||||
resultProcessor->endBattle(battle);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/GameConstants.h"
|
||||
#include "../../lib/battle/BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CGHeroInstance;
|
||||
@ -44,11 +45,11 @@ class BattleProcessor : boost::noncopyable
|
||||
void engageIntoBattle(PlayerColor player);
|
||||
|
||||
bool checkBattleStateChanges(const CBattleInfoCallback & battle);
|
||||
BattleID setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance *heroes[2], bool creatureBank, const CGTownInstance *town);
|
||||
BattleID setupBattle(int3 tile, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, bool creatureBank, const CGTownInstance *town);
|
||||
|
||||
bool makeAutomaticBattleAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
|
||||
void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide);
|
||||
void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, BattleSide victoriusSide);
|
||||
|
||||
public:
|
||||
explicit BattleProcessor(CGameHandler * gameHandler);
|
||||
|
@ -38,7 +38,7 @@ BattleResultProcessor::BattleResultProcessor(BattleProcessor * owner, CGameHandl
|
||||
{
|
||||
}
|
||||
|
||||
CasualtiesAfterBattle::CasualtiesAfterBattle(const CBattleInfoCallback & battle, uint8_t sideInBattle):
|
||||
CasualtiesAfterBattle::CasualtiesAfterBattle(const CBattleInfoCallback & battle, BattleSide sideInBattle):
|
||||
army(battle.battleGetArmyObject(sideInBattle))
|
||||
{
|
||||
heroWithDeadCommander = ObjectInstanceID();
|
||||
@ -205,25 +205,18 @@ FinishingBattleHelper::FinishingBattleHelper(const CBattleInfoCallback & info, c
|
||||
this->remainingBattleQueriesCount = remainingBattleQueriesCount;
|
||||
}
|
||||
|
||||
//FinishingBattleHelper::FinishingBattleHelper()
|
||||
//{
|
||||
// winnerHero = loserHero = nullptr;
|
||||
// winnerSide = 0;
|
||||
// remainingBattleQueriesCount = 0;
|
||||
//}
|
||||
|
||||
void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle)
|
||||
{
|
||||
auto const & giveExp = [](BattleResult &r)
|
||||
auto const & giveExp = [&battle](BattleResult &r)
|
||||
{
|
||||
if (r.winner > 1)
|
||||
if (r.winner == BattleSide::NONE)
|
||||
{
|
||||
// draw
|
||||
return;
|
||||
}
|
||||
r.exp[0] = 0;
|
||||
r.exp[1] = 0;
|
||||
for (auto i = r.casualties[!r.winner].begin(); i!=r.casualties[!r.winner].end(); i++)
|
||||
r.exp[BattleSide::ATTACKER] = 0;
|
||||
r.exp[BattleSide::DEFENDER] = 0;
|
||||
for (auto i = r.casualties[battle.otherSide(r.winner)].begin(); i!=r.casualties[battle.otherSide(r.winner)].end(); i++)
|
||||
{
|
||||
r.exp[r.winner] += VLC->creh->objects.at(i->first)->valOfBonuses(BonusType::STACK_HEALTH) * i->second;
|
||||
}
|
||||
@ -241,9 +234,9 @@ void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle)
|
||||
if (battleResult->result == EBattleResult::NORMAL) // give 500 exp for defeating hero, unless he escaped
|
||||
{
|
||||
if(heroAttacker)
|
||||
battleResult->exp[1] += 500;
|
||||
battleResult->exp[BattleSide::DEFENDER] += 500;
|
||||
if(heroDefender)
|
||||
battleResult->exp[0] += 500;
|
||||
battleResult->exp[BattleSide::ATTACKER] += 500;
|
||||
}
|
||||
|
||||
// Give 500 exp to winner if a town was conquered during the battle
|
||||
@ -252,17 +245,17 @@ void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle)
|
||||
battleResult->exp[BattleSide::ATTACKER] += 500;
|
||||
|
||||
if(heroAttacker)
|
||||
battleResult->exp[0] = heroAttacker->calculateXp(battleResult->exp[0]);//scholar skill
|
||||
battleResult->exp[BattleSide::ATTACKER] = heroAttacker->calculateXp(battleResult->exp[BattleSide::ATTACKER]);//scholar skill
|
||||
if(heroDefender)
|
||||
battleResult->exp[1] = heroDefender->calculateXp(battleResult->exp[1]);
|
||||
battleResult->exp[BattleSide::DEFENDER] = heroDefender->calculateXp(battleResult->exp[BattleSide::DEFENDER]);
|
||||
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(0)));
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::ATTACKER)));
|
||||
if(!battleQuery)
|
||||
battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(1)));
|
||||
battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::DEFENDER)));
|
||||
if (!battleQuery)
|
||||
{
|
||||
logGlobal->error("Cannot find battle query!");
|
||||
gameHandler->complain("Player " + boost::lexical_cast<std::string>(battle.sideToPlayer(0)) + " has no battle query at the top!");
|
||||
gameHandler->complain("Player " + boost::lexical_cast<std::string>(battle.sideToPlayer(BattleSide::ATTACKER)) + " has no battle query at the top!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -307,9 +300,9 @@ void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle)
|
||||
|
||||
void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
|
||||
{
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(0)));
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::ATTACKER)));
|
||||
if(!battleQuery)
|
||||
battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(1)));
|
||||
battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(BattleSide::DEFENDER)));
|
||||
if(!battleQuery)
|
||||
{
|
||||
logGlobal->trace("No battle query, battle end was confirmed by another player");
|
||||
@ -498,29 +491,29 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
|
||||
}
|
||||
|
||||
// add statistic
|
||||
if(battle.sideToPlayer(0) == PlayerColor::NEUTRAL || battle.sideToPlayer(1) == PlayerColor::NEUTRAL)
|
||||
if(battle.sideToPlayer(BattleSide::ATTACKER) == PlayerColor::NEUTRAL || battle.sideToPlayer(BattleSide::DEFENDER) == PlayerColor::NEUTRAL)
|
||||
{
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(0)].numBattlesNeutral++;
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(1)].numBattlesNeutral++;
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(BattleSide::ATTACKER)].numBattlesNeutral++;
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(BattleSide::DEFENDER)].numBattlesNeutral++;
|
||||
if(!finishingBattle->isDraw())
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(finishingBattle->winnerSide)].numWinBattlesNeutral++;
|
||||
}
|
||||
else
|
||||
{
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(0)].numBattlesPlayer++;
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(1)].numBattlesPlayer++;
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(BattleSide::ATTACKER)].numBattlesPlayer++;
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(BattleSide::DEFENDER)].numBattlesPlayer++;
|
||||
if(!finishingBattle->isDraw())
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(finishingBattle->winnerSide)].numWinBattlesPlayer++;
|
||||
}
|
||||
|
||||
BattleResultAccepted raccepted;
|
||||
raccepted.battleID = battle.getBattle()->getBattleID();
|
||||
raccepted.heroResult[0].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(BattleSide::ATTACKER));
|
||||
raccepted.heroResult[1].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(BattleSide::DEFENDER));
|
||||
raccepted.heroResult[0].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(BattleSide::ATTACKER));
|
||||
raccepted.heroResult[1].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(BattleSide::DEFENDER));
|
||||
raccepted.heroResult[0].exp = battleResult->exp[0];
|
||||
raccepted.heroResult[1].exp = battleResult->exp[1];
|
||||
raccepted.heroResult[BattleSide::ATTACKER].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(BattleSide::ATTACKER));
|
||||
raccepted.heroResult[BattleSide::DEFENDER].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(BattleSide::DEFENDER));
|
||||
raccepted.heroResult[BattleSide::ATTACKER].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(BattleSide::ATTACKER));
|
||||
raccepted.heroResult[BattleSide::DEFENDER].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(BattleSide::DEFENDER));
|
||||
raccepted.heroResult[BattleSide::ATTACKER].exp = battleResult->exp[BattleSide::ATTACKER];
|
||||
raccepted.heroResult[BattleSide::DEFENDER].exp = battleResult->exp[BattleSide::DEFENDER];
|
||||
raccepted.winnerSide = finishingBattle->winnerSide;
|
||||
gameHandler->sendAndApply(&raccepted);
|
||||
|
||||
@ -583,7 +576,7 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const
|
||||
gameHandler->heroPool->onHeroEscaped(finishingBattle->loser, finishingBattle->loserHero);
|
||||
}
|
||||
|
||||
if (result.winner != 2 && finishingBattle->winnerHero && finishingBattle->winnerHero->stacks.empty()
|
||||
if (result.winner != BattleSide::NONE && finishingBattle->winnerHero && finishingBattle->winnerHero->stacks.empty()
|
||||
&& (!finishingBattle->winnerHero->commander || !finishingBattle->winnerHero->commander->alive))
|
||||
{
|
||||
RemoveObject ro(finishingBattle->winnerHero->id, finishingBattle->winnerHero->getOwner());
|
||||
@ -597,7 +590,7 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const
|
||||
battleResults.erase(battleID);
|
||||
}
|
||||
|
||||
void BattleResultProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide)
|
||||
void BattleResultProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, BattleSide victoriusSide)
|
||||
{
|
||||
assert(battleResults.count(battle.getBattle()->getBattleID()) == 0);
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "../../lib/GameConstants.h"
|
||||
#include "../../lib/networkPacks/StackLocation.h"
|
||||
#include "../../lib/networkPacks/ArtifactLocation.h"
|
||||
#include "../../lib/battle/BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
struct SideInBattle;
|
||||
@ -34,7 +35,7 @@ struct CasualtiesAfterBattle
|
||||
TSummoned summoned;
|
||||
ObjectInstanceID heroWithDeadCommander; //TODO: unify stack locations
|
||||
|
||||
CasualtiesAfterBattle(const CBattleInfoCallback & battle, uint8_t sideInBattle);
|
||||
CasualtiesAfterBattle(const CBattleInfoCallback & battle, BattleSide sideInBattle);
|
||||
void updateArmy(CGameHandler * gh);
|
||||
};
|
||||
|
||||
@ -42,11 +43,11 @@ struct FinishingBattleHelper
|
||||
{
|
||||
FinishingBattleHelper(const CBattleInfoCallback & battle, const BattleResult & result, int RemainingBattleQueriesCount);
|
||||
|
||||
inline bool isDraw() const {return winnerSide == 2;}
|
||||
inline bool isDraw() const {return winnerSide == BattleSide::NONE;}
|
||||
|
||||
const CGHeroInstance *winnerHero, *loserHero;
|
||||
PlayerColor victor, loser;
|
||||
ui8 winnerSide;
|
||||
BattleSide winnerSide;
|
||||
|
||||
int remainingBattleQueriesCount;
|
||||
|
||||
@ -74,7 +75,7 @@ public:
|
||||
|
||||
bool battleIsEnding(const CBattleInfoCallback & battle) const;
|
||||
|
||||
void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide);
|
||||
void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, BattleSide victoriusSide);
|
||||
void endBattle(const CBattleInfoCallback & battle); //ends battle
|
||||
void endBattleConfirm(const CBattleInfoCallback & battle);
|
||||
void battleAfterLevelUp(const BattleID & battleID, const BattleResult & result);
|
||||
|
@ -35,17 +35,18 @@ CBattleQuery::CBattleQuery(CGameHandler * owner, const IBattleInfo * bi):
|
||||
CQuery(owner),
|
||||
battleID(bi->getBattleID())
|
||||
{
|
||||
belligerents[0] = bi->getSideArmy(0);
|
||||
belligerents[1] = bi->getSideArmy(1);
|
||||
belligerents[BattleSide::ATTACKER] = bi->getSideArmy(BattleSide::ATTACKER);
|
||||
belligerents[BattleSide::DEFENDER] = bi->getSideArmy(BattleSide::DEFENDER);
|
||||
|
||||
addPlayer(bi->getSidePlayer(0));
|
||||
addPlayer(bi->getSidePlayer(1));
|
||||
addPlayer(bi->getSidePlayer(BattleSide::ATTACKER));
|
||||
addPlayer(bi->getSidePlayer(BattleSide::DEFENDER));
|
||||
}
|
||||
|
||||
CBattleQuery::CBattleQuery(CGameHandler * owner):
|
||||
CQuery(owner)
|
||||
{
|
||||
belligerents[0] = belligerents[1] = nullptr;
|
||||
belligerents[BattleSide::ATTACKER] = nullptr;
|
||||
belligerents[BattleSide::DEFENDER] = nullptr;
|
||||
}
|
||||
|
||||
bool CBattleQuery::blocksPack(const CPack * pack) const
|
||||
@ -81,8 +82,8 @@ CBattleDialogQuery::CBattleDialogQuery(CGameHandler * owner, const IBattleInfo *
|
||||
bi(bi),
|
||||
result(Br)
|
||||
{
|
||||
addPlayer(bi->getSidePlayer(0));
|
||||
addPlayer(bi->getSidePlayer(1));
|
||||
addPlayer(bi->getSidePlayer(BattleSide::ATTACKER));
|
||||
addPlayer(bi->getSidePlayer(BattleSide::DEFENDER));
|
||||
}
|
||||
|
||||
void CBattleDialogQuery::onRemoval(PlayerColor color)
|
||||
@ -97,11 +98,11 @@ void CBattleDialogQuery::onRemoval(PlayerColor color)
|
||||
{
|
||||
gh->battles->restartBattlePrimary(
|
||||
bi->getBattleID(),
|
||||
bi->getSideArmy(0),
|
||||
bi->getSideArmy(1),
|
||||
bi->getSideArmy(BattleSide::ATTACKER),
|
||||
bi->getSideArmy(BattleSide::DEFENDER),
|
||||
bi->getLocation(),
|
||||
bi->getSideHero(0),
|
||||
bi->getSideHero(1),
|
||||
bi->getSideHero(BattleSide::ATTACKER),
|
||||
bi->getSideHero(BattleSide::DEFENDER),
|
||||
bi->isCreatureBank(),
|
||||
bi->getDefendedTown()
|
||||
);
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "CQuery.h"
|
||||
#include "../../lib/networkPacks/PacksForClientBattle.h"
|
||||
#include "../../lib/battle/BattleSide.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class IBattleInfo;
|
||||
@ -20,8 +21,8 @@ VCMI_LIB_NAMESPACE_END
|
||||
class CBattleQuery : public CQuery
|
||||
{
|
||||
public:
|
||||
std::array<const CArmedInstance *,2> belligerents;
|
||||
std::array<int, 2> initialHeroMana;
|
||||
BattleSideArray<const CArmedInstance *> belligerents;
|
||||
BattleSideArray<int> initialHeroMana;
|
||||
|
||||
BattleID battleID;
|
||||
std::optional<BattleResult> result;
|
||||
|
@ -92,16 +92,16 @@ TEST(BattleHexTest, getClosestTile)
|
||||
possibilities.insert(119);
|
||||
possibilities.insert(186);
|
||||
|
||||
EXPECT_EQ(mainHex.getClosestTile(0,mainHex,possibilities), 3);
|
||||
EXPECT_EQ(mainHex.getClosestTile(BattleSide::ATTACKER,mainHex,possibilities), 3);
|
||||
mainHex = 139;
|
||||
EXPECT_EQ(mainHex.getClosestTile(1,mainHex,possibilities), 119);
|
||||
EXPECT_EQ(mainHex.getClosestTile(BattleSide::DEFENDER,mainHex,possibilities), 119);
|
||||
mainHex = 16;
|
||||
EXPECT_EQ(mainHex.getClosestTile(1,mainHex,possibilities), 100);
|
||||
EXPECT_EQ(mainHex.getClosestTile(BattleSide::DEFENDER,mainHex,possibilities), 100);
|
||||
mainHex = 166;
|
||||
EXPECT_EQ(mainHex.getClosestTile(0,mainHex,possibilities), 186);
|
||||
EXPECT_EQ(mainHex.getClosestTile(BattleSide::ATTACKER,mainHex,possibilities), 186);
|
||||
mainHex = 76;
|
||||
EXPECT_EQ(mainHex.getClosestTile(1,mainHex,possibilities), 3);
|
||||
EXPECT_EQ(mainHex.getClosestTile(0,mainHex,possibilities), 100);
|
||||
EXPECT_EQ(mainHex.getClosestTile(BattleSide::DEFENDER,mainHex,possibilities), 3);
|
||||
EXPECT_EQ(mainHex.getClosestTile(BattleSide::ATTACKER,mainHex,possibilities), 100);
|
||||
}
|
||||
|
||||
TEST(BattleHexTest, moveEDir)
|
||||
|
@ -104,7 +104,7 @@ class UnitsFake
|
||||
public:
|
||||
std::vector<std::shared_ptr<UnitFake>> allUnits;
|
||||
|
||||
UnitFake & add(ui8 side)
|
||||
UnitFake & add(BattleSide side)
|
||||
{
|
||||
auto * unit = new UnitFake();
|
||||
EXPECT_CALL(*unit, unitSide()).WillRepeatedly(Return(side));
|
||||
@ -207,7 +207,7 @@ public:
|
||||
class AttackableHexesTest : public CBattleInfoCallbackTest
|
||||
{
|
||||
public:
|
||||
UnitFake & addRegularMelee(BattleHex hex, uint8_t side)
|
||||
UnitFake & addRegularMelee(BattleHex hex, BattleSide side)
|
||||
{
|
||||
auto & unit = unitsFake.add(side);
|
||||
|
||||
@ -219,7 +219,7 @@ public:
|
||||
return unit;
|
||||
}
|
||||
|
||||
UnitFake & addDragon(BattleHex hex, uint8_t side)
|
||||
UnitFake & addDragon(BattleHex hex, BattleSide side)
|
||||
{
|
||||
auto & unit = addRegularMelee(hex, side);
|
||||
|
||||
@ -245,9 +245,9 @@ public:
|
||||
TEST_F(AttackableHexesTest, DragonRightRegular_RightHorithontalBreath)
|
||||
{
|
||||
// X A D #
|
||||
UnitFake & attacker = addDragon(35, 0);
|
||||
UnitFake & defender = addRegularMelee(36, 1);
|
||||
UnitFake & next = addRegularMelee(37, 1);
|
||||
UnitFake & attacker = addDragon(35, BattleSide::ATTACKER);
|
||||
UnitFake & defender = addRegularMelee(36, BattleSide::DEFENDER);
|
||||
UnitFake & next = addRegularMelee(37, BattleSide::DEFENDER);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
@ -259,9 +259,9 @@ TEST_F(AttackableHexesTest, DragonDragonBottomRightHead_BottomRightBreathFromHea
|
||||
// X A
|
||||
// D X target D
|
||||
// #
|
||||
UnitFake & attacker = addDragon(35, 0);
|
||||
UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
UnitFake & attacker = addDragon(35, BattleSide::ATTACKER);
|
||||
UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
@ -273,9 +273,9 @@ TEST_F(AttackableHexesTest, DragonDragonVerticalDownHead_VerticalDownBreathFromH
|
||||
// X A
|
||||
// D X target D
|
||||
// #
|
||||
UnitFake & attacker = addDragon(35, 0);
|
||||
UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
UnitFake & attacker = addDragon(35, BattleSide::ATTACKER);
|
||||
UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::DEFENDER);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
@ -287,9 +287,9 @@ TEST_F(AttackableHexesTest, DragonDragonVerticalDownHeadReverse_VerticalDownBrea
|
||||
// A X
|
||||
// X D target D
|
||||
// #
|
||||
UnitFake & attacker = addDragon(36, 1);
|
||||
UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 0);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 0);
|
||||
UnitFake & attacker = addDragon(36, BattleSide::DEFENDER);
|
||||
UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::ATTACKER);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::ATTACKER);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
@ -301,9 +301,9 @@ TEST_F(AttackableHexesTest, DragonDragonVerticalDownBack_VerticalDownBreath)
|
||||
// X A
|
||||
// D X target X
|
||||
// #
|
||||
UnitFake & attacker = addDragon(37, 0);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
UnitFake & attacker = addDragon(37, BattleSide::ATTACKER);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::DEFENDER);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.occupiedHex());
|
||||
|
||||
@ -315,9 +315,9 @@ TEST_F(AttackableHexesTest, DragonDragonHeadBottomRight_BottomRightBreathFromHea
|
||||
// X A
|
||||
// D X target D
|
||||
// #
|
||||
UnitFake & attacker = addDragon(37, 0);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
UnitFake & attacker = addDragon(37, BattleSide::ATTACKER);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::DEFENDER);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
@ -329,9 +329,9 @@ TEST_F(AttackableHexesTest, DragonVerticalDownDragonBackReverse_VerticalDownBrea
|
||||
// A X
|
||||
// X D target X
|
||||
// #
|
||||
UnitFake & attacker = addDragon(36, 1);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), 0);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 0);
|
||||
UnitFake & attacker = addDragon(36, BattleSide::DEFENDER);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::ATTACKER);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::ATTACKER);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.occupiedHex());
|
||||
|
||||
@ -342,9 +342,9 @@ TEST_F(AttackableHexesTest, DragonRightBottomDragonHeadReverse_RightBottomBreath
|
||||
{
|
||||
// A X
|
||||
// X D target D
|
||||
UnitFake & attacker = addDragon(36, 1);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), 0);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 0);
|
||||
UnitFake & attacker = addDragon(36, BattleSide::DEFENDER);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::ATTACKER);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), BattleSide::ATTACKER);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
@ -356,9 +356,9 @@ TEST_F(AttackableHexesTest, DragonLeftBottomDragonBackToBack_LeftBottomBreathFro
|
||||
// X A
|
||||
// D X target X
|
||||
// #
|
||||
UnitFake & attacker = addDragon(8, 0);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT).cloneInDirection(BattleHex::LEFT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
UnitFake & attacker = addDragon(8, BattleSide::ATTACKER);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT).cloneInDirection(BattleHex::LEFT), BattleSide::DEFENDER);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), BattleSide::DEFENDER);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.occupiedHex());
|
||||
|
||||
@ -370,9 +370,9 @@ TEST_F(AttackableHexesTest, DefenderPositionOverride_BreathCountsHypoteticDefend
|
||||
// # N
|
||||
// X D target D
|
||||
// A X
|
||||
UnitFake & attacker = addDragon(35, 1);
|
||||
UnitFake & defender = addDragon(8, 0);
|
||||
UnitFake & next = addDragon(2, 0);
|
||||
UnitFake & attacker = addDragon(35, BattleSide::DEFENDER);
|
||||
UnitFake & defender = addDragon(8, BattleSide::ATTACKER);
|
||||
UnitFake & next = addDragon(2, BattleSide::ATTACKER);
|
||||
|
||||
startBattle();
|
||||
redirectUnitsToFake();
|
||||
@ -402,10 +402,10 @@ public:
|
||||
auto ret = subject.battleIsFinished();
|
||||
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_EQ(*ret, 2);
|
||||
EXPECT_EQ(*ret, BattleSide::NONE);
|
||||
}
|
||||
|
||||
void expectBattleWinner(ui8 side)
|
||||
void expectBattleWinner(BattleSide side)
|
||||
{
|
||||
auto ret = subject.battleIsFinished();
|
||||
|
||||
@ -413,12 +413,12 @@ public:
|
||||
EXPECT_EQ(*ret, side);
|
||||
}
|
||||
|
||||
void expectBattleLooser(ui8 side)
|
||||
void expectBattleLooser(BattleSide side)
|
||||
{
|
||||
auto ret = subject.battleIsFinished();
|
||||
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_NE(*ret, (int)side);
|
||||
EXPECT_NE(*ret, side);
|
||||
}
|
||||
|
||||
void setDefaultExpectations()
|
||||
@ -443,21 +443,21 @@ TEST_F(BattleFinishedTest, EmptyBattleIsDraw)
|
||||
|
||||
TEST_F(BattleFinishedTest, LastAliveUnitWins)
|
||||
{
|
||||
UnitFake & unit = unitsFake.add(1);
|
||||
UnitFake & unit = unitsFake.add(BattleSide::DEFENDER);
|
||||
unit.makeAlive();
|
||||
unit.setDefaultState();
|
||||
|
||||
setDefaultExpectations();
|
||||
startBattle();
|
||||
expectBattleWinner(1);
|
||||
expectBattleWinner(BattleSide::DEFENDER);
|
||||
}
|
||||
|
||||
TEST_F(BattleFinishedTest, TwoUnitsContinueFight)
|
||||
{
|
||||
UnitFake & unit1 = unitsFake.add(0);
|
||||
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
||||
unit1.makeAlive();
|
||||
|
||||
UnitFake & unit2 = unitsFake.add(1);
|
||||
UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
|
||||
unit2.makeAlive();
|
||||
|
||||
setDefaultExpectations();
|
||||
@ -468,7 +468,7 @@ TEST_F(BattleFinishedTest, TwoUnitsContinueFight)
|
||||
|
||||
TEST_F(BattleFinishedTest, LastWarMachineNotWins)
|
||||
{
|
||||
UnitFake & unit = unitsFake.add(0);
|
||||
UnitFake & unit = unitsFake.add(BattleSide::ATTACKER);
|
||||
unit.makeAlive();
|
||||
unit.makeWarMachine();
|
||||
unit.setDefaultState();
|
||||
@ -476,18 +476,18 @@ TEST_F(BattleFinishedTest, LastWarMachineNotWins)
|
||||
setDefaultExpectations();
|
||||
startBattle();
|
||||
|
||||
expectBattleLooser(0);
|
||||
expectBattleLooser(BattleSide::ATTACKER);
|
||||
}
|
||||
|
||||
TEST_F(BattleFinishedTest, LastWarMachineLoose)
|
||||
{
|
||||
try
|
||||
{
|
||||
UnitFake & unit1 = unitsFake.add(0);
|
||||
UnitFake & unit1 = unitsFake.add(BattleSide::ATTACKER);
|
||||
unit1.makeAlive();
|
||||
unit1.setDefaultState();
|
||||
|
||||
UnitFake & unit2 = unitsFake.add(1);
|
||||
UnitFake & unit2 = unitsFake.add(BattleSide::DEFENDER);
|
||||
unit2.makeAlive();
|
||||
unit2.makeWarMachine();
|
||||
unit2.setDefaultState();
|
||||
@ -495,7 +495,7 @@ TEST_F(BattleFinishedTest, LastWarMachineLoose)
|
||||
setDefaultExpectations();
|
||||
startBattle();
|
||||
|
||||
expectBattleWinner(0);
|
||||
expectBattleWinner(BattleSide::ATTACKER);
|
||||
}
|
||||
catch(const std::exception & e)
|
||||
{
|
||||
|
@ -15,7 +15,7 @@ TEST(battle_Unit_getSurroundingHexes, oneWide)
|
||||
{
|
||||
BattleHex position(77);
|
||||
|
||||
auto actual = battle::Unit::getSurroundingHexes(position, false, 0);
|
||||
auto actual = battle::Unit::getSurroundingHexes(position, false, BattleSide::ATTACKER);
|
||||
|
||||
EXPECT_EQ(actual, position.neighbouringTiles());
|
||||
}
|
||||
@ -24,7 +24,7 @@ TEST(battle_Unit_getSurroundingHexes, oneWideLeftCorner)
|
||||
{
|
||||
BattleHex position(34);
|
||||
|
||||
auto actual = battle::Unit::getSurroundingHexes(position, false, 0);
|
||||
auto actual = battle::Unit::getSurroundingHexes(position, false, BattleSide::ATTACKER);
|
||||
|
||||
EXPECT_EQ(actual, position.neighbouringTiles());
|
||||
}
|
||||
@ -33,7 +33,7 @@ TEST(battle_Unit_getSurroundingHexes, oneWideRightCorner)
|
||||
{
|
||||
BattleHex position(117);
|
||||
|
||||
auto actual = battle::Unit::getSurroundingHexes(position, false, 0);
|
||||
auto actual = battle::Unit::getSurroundingHexes(position, false, BattleSide::ATTACKER);
|
||||
|
||||
EXPECT_EQ(actual, position.neighbouringTiles());
|
||||
}
|
||||
|
@ -188,8 +188,8 @@ public:
|
||||
|
||||
void startTestBattle(const CGHeroInstance * attacker, const CGHeroInstance * defender)
|
||||
{
|
||||
const CGHeroInstance * heroes[2] = {attacker, defender};
|
||||
const CArmedInstance * armedInstancies[2] = {attacker, defender};
|
||||
BattleSideArray<const CGHeroInstance *> heroes = {attacker, defender};
|
||||
BattleSideArray<const CArmedInstance *> armedInstancies = {attacker, defender};
|
||||
|
||||
int3 tile(4,4,0);
|
||||
|
||||
|
@ -44,7 +44,7 @@ void UnitFake::expectAnyBonusSystemCall()
|
||||
EXPECT_CALL(*this, getTreeVersion()).Times(AtLeast(0));
|
||||
}
|
||||
|
||||
UnitFake & UnitsFake::add(ui8 side)
|
||||
UnitFake & UnitsFake::add(BattleSide side)
|
||||
{
|
||||
auto * unit = new UnitFake();
|
||||
ON_CALL(*unit, unitSide()).WillByDefault(Return(side));
|
||||
|
@ -52,7 +52,7 @@ class UnitsFake
|
||||
public:
|
||||
std::vector<std::shared_ptr<UnitFake>> allUnits;
|
||||
|
||||
UnitFake & add(ui8 side);
|
||||
UnitFake & add(BattleSide side);
|
||||
|
||||
battle::Units getUnitsIf(battle::UnitFilter predicate) const;
|
||||
|
||||
|
@ -22,10 +22,10 @@ public:
|
||||
MOCK_CONST_METHOD0(battleTerrainType, TerrainId());
|
||||
MOCK_CONST_METHOD0(battleGetBattlefieldType, BattleField());
|
||||
|
||||
MOCK_CONST_METHOD0(battleIsFinished, std::optional<int>());
|
||||
MOCK_CONST_METHOD0(battleIsFinished, std::optional<BattleSide>());
|
||||
|
||||
MOCK_CONST_METHOD0(battleTacticDist, si8());
|
||||
MOCK_CONST_METHOD0(battleGetTacticsSide, si8());
|
||||
MOCK_CONST_METHOD0(battleGetTacticsSide, BattleSide());
|
||||
|
||||
MOCK_CONST_METHOD0(battleNextUnitId, uint32_t());
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
MOCK_CONST_METHOD0(unitBaseAmount, int32_t());
|
||||
|
||||
MOCK_CONST_METHOD0(unitId, uint32_t());
|
||||
MOCK_CONST_METHOD0(unitSide, ui8());
|
||||
MOCK_CONST_METHOD0(unitSide, BattleSide());
|
||||
MOCK_CONST_METHOD0(unitOwner, PlayerColor());
|
||||
|
||||
MOCK_CONST_METHOD0(unitSlot, SlotID());
|
||||
|
@ -25,20 +25,20 @@ public:
|
||||
MOCK_CONST_METHOD0(getDefendedTown, const CGTownInstance *());
|
||||
MOCK_CONST_METHOD1(getWallState, EWallState(EWallPart));
|
||||
MOCK_CONST_METHOD0(getGateState, EGateState());
|
||||
MOCK_CONST_METHOD1(getSidePlayer, PlayerColor(ui8));
|
||||
MOCK_CONST_METHOD1(getSideArmy, const CArmedInstance *(ui8));
|
||||
MOCK_CONST_METHOD1(getSideHero, const CGHeroInstance *(ui8));
|
||||
MOCK_CONST_METHOD1(getCastSpells, uint32_t(ui8));
|
||||
MOCK_CONST_METHOD1(getEnchanterCounter, int32_t(ui8));
|
||||
MOCK_CONST_METHOD1(getSidePlayer, PlayerColor(BattleSide));
|
||||
MOCK_CONST_METHOD1(getSideArmy, const CArmedInstance *(BattleSide));
|
||||
MOCK_CONST_METHOD1(getSideHero, const CGHeroInstance *(BattleSide));
|
||||
MOCK_CONST_METHOD1(getCastSpells, uint32_t(BattleSide));
|
||||
MOCK_CONST_METHOD1(getEnchanterCounter, int32_t(BattleSide));
|
||||
MOCK_CONST_METHOD0(getTacticDist, ui8());
|
||||
MOCK_CONST_METHOD0(getTacticsSide, ui8());
|
||||
MOCK_CONST_METHOD0(getTacticsSide, BattleSide());
|
||||
MOCK_CONST_METHOD0(getBonusBearer, const IBonusBearer *());
|
||||
MOCK_CONST_METHOD0(nextUnitId, uint32_t());
|
||||
MOCK_CONST_METHOD3(getActualDamage, int64_t(const DamageRange &, int32_t, vstd::RNG &));
|
||||
MOCK_CONST_METHOD0(getBattleID, BattleID());
|
||||
MOCK_CONST_METHOD0(getLocation, int3());
|
||||
MOCK_CONST_METHOD0(isCreatureBank, bool());
|
||||
MOCK_CONST_METHOD1(getUsedSpells, std::vector<SpellID>(ui8));
|
||||
MOCK_CONST_METHOD1(getUsedSpells, std::vector<SpellID>(BattleSide));
|
||||
|
||||
MOCK_METHOD0(nextRound, void());
|
||||
MOCK_METHOD1(nextTurn, void(uint32_t));
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
|
||||
MOCK_CONST_METHOD0(unitBaseAmount, int32_t());
|
||||
MOCK_CONST_METHOD0(unitId, uint32_t());
|
||||
MOCK_CONST_METHOD0(unitSide, ui8());
|
||||
MOCK_CONST_METHOD0(unitSide, BattleSide());
|
||||
MOCK_CONST_METHOD0(unitOwner, PlayerColor());
|
||||
MOCK_CONST_METHOD0(unitSlot, SlotID());
|
||||
MOCK_CONST_METHOD0(unitType, const CCreature * ());
|
||||
|
Loading…
Reference in New Issue
Block a user