mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Separated game and battle callback (server & client only)
This commit is contained in:
parent
fc4dfda00f
commit
3a88180494
@ -390,7 +390,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
|
||||
for(auto & round : queue)
|
||||
{
|
||||
if(!firstRound)
|
||||
state->nextRound(0);//todo: set actual value?
|
||||
state->nextRound();
|
||||
for(auto unit : round)
|
||||
{
|
||||
if(!vstd::contains(values, unit->unitId()))
|
||||
|
@ -325,7 +325,7 @@ int32_t HypotheticBattle::getActiveStackID() const
|
||||
return activeUnitId;
|
||||
}
|
||||
|
||||
void HypotheticBattle::nextRound(int32_t roundNr)
|
||||
void HypotheticBattle::nextRound()
|
||||
{
|
||||
//TODO:HypotheticBattle::nextRound
|
||||
for(auto unit : battleAliveUnits())
|
||||
@ -462,6 +462,24 @@ int64_t HypotheticBattle::getActualDamage(const DamageRange & damage, int32_t at
|
||||
return (damage.min + damage.max) / 2;
|
||||
}
|
||||
|
||||
std::vector<SpellID> HypotheticBattle::getUsedSpells(ui8 side) const
|
||||
{
|
||||
// TODO
|
||||
return {};
|
||||
}
|
||||
|
||||
int3 HypotheticBattle::getLocation() const
|
||||
{
|
||||
// TODO
|
||||
return int3(-1, -1, -1);
|
||||
}
|
||||
|
||||
bool HypotheticBattle::isCreatureBank() const
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t HypotheticBattle::getTreeVersion() const
|
||||
{
|
||||
return getBonusBearer()->getTreeVersion() + bonusTreeVersion;
|
||||
@ -552,8 +570,9 @@ const Services * HypotheticBattle::HypotheticEnvironment::services() const
|
||||
return env->services();
|
||||
}
|
||||
|
||||
const Environment::BattleCb * HypotheticBattle::HypotheticEnvironment::battle() const
|
||||
const Environment::BattleCb * HypotheticBattle::HypotheticEnvironment::battle(const BattleID & battleID) const
|
||||
{
|
||||
assert(battleID == owner->getBattleID());
|
||||
return owner;
|
||||
}
|
||||
|
||||
|
@ -110,11 +110,13 @@ public:
|
||||
|
||||
std::shared_ptr<StackWithBonuses> getForUpdate(uint32_t id);
|
||||
|
||||
BattleID getBattleID() const override;
|
||||
|
||||
int32_t getActiveStackID() const override;
|
||||
|
||||
battle::Units getUnitsIf(battle::UnitFilter predicate) const override;
|
||||
|
||||
void nextRound(int32_t roundNr) override;
|
||||
void nextRound() override;
|
||||
void nextTurn(uint32_t unitId) override;
|
||||
|
||||
void addUnit(uint32_t id, const JsonNode & data) override;
|
||||
@ -136,6 +138,9 @@ 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;
|
||||
int3 getLocation() const override;
|
||||
bool isCreatureBank() const override;
|
||||
|
||||
int64_t getTreeVersion() const;
|
||||
|
||||
@ -177,7 +182,7 @@ private:
|
||||
HypotheticEnvironment(HypotheticBattle * owner_, const Environment * upperEnvironment);
|
||||
|
||||
const Services * services() const override;
|
||||
const BattleCb * battle() const override;
|
||||
const BattleCb * battle(const BattleID & battleID) const override;
|
||||
const GameCb * game() const override;
|
||||
vstd::CLoggerBase * logger() const override;
|
||||
events::EventBus * eventBus() const override;
|
||||
|
@ -16,6 +16,7 @@ class Services;
|
||||
|
||||
class IGameInfoCallback;
|
||||
class IBattleInfoCallback;
|
||||
class BattleID;
|
||||
|
||||
namespace events
|
||||
{
|
||||
@ -31,7 +32,7 @@ public:
|
||||
virtual ~Environment() = default;
|
||||
|
||||
virtual const Services * services() const = 0;
|
||||
virtual const BattleCb * battle() const = 0;
|
||||
virtual const BattleCb * battle(const BattleID & battleID) const = 0;
|
||||
virtual const GameCb * game() const = 0;
|
||||
virtual vstd::CLoggerBase * logger() const = 0;
|
||||
virtual events::EventBus * eventBus() const = 0;
|
||||
|
@ -39,6 +39,7 @@ struct StackLocation;
|
||||
struct ArtSlotInfo;
|
||||
struct QuestInfo;
|
||||
class IBattleState;
|
||||
class BattleInfo;
|
||||
|
||||
// This one teleport-specific, but has to be available everywhere in callbacks and netpacks
|
||||
// For now it's will be there till teleports code refactored and moved into own file
|
||||
@ -1478,7 +1479,6 @@ struct DLL_LINKAGE MapObjectSelectDialog : public Query
|
||||
}
|
||||
};
|
||||
|
||||
class BattleInfo;
|
||||
struct DLL_LINKAGE BattleStart : public CPackForClient
|
||||
{
|
||||
void applyGs(CGameState * gs) const;
|
||||
@ -1500,14 +1500,12 @@ struct DLL_LINKAGE BattleNextRound : public CPackForClient
|
||||
void applyGs(CGameState * gs) const;
|
||||
|
||||
BattleID battleID = BattleID::NONE;
|
||||
si32 round = 0;
|
||||
|
||||
virtual void visitTyped(ICPackVisitor & visitor) override;
|
||||
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & battleID;
|
||||
h & round;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2124,7 +2124,7 @@ void BattleStart::applyGs(CGameState * gs) const
|
||||
|
||||
void BattleNextRound::applyGs(CGameState * gs) const
|
||||
{
|
||||
gs->getBattle(battleID)->nextRound(round);
|
||||
gs->getBattle(battleID)->nextRound();
|
||||
}
|
||||
|
||||
void BattleSetActiveStack::applyGs(CGameState * gs) const
|
||||
|
@ -26,37 +26,6 @@
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
///BattleInfo
|
||||
std::pair< std::vector<BattleHex>, int > BattleInfo::getPath(BattleHex start, BattleHex dest, const battle::Unit * stack) const
|
||||
{
|
||||
auto reachability = getReachability(stack);
|
||||
|
||||
if(reachability.predecessors[dest] == -1) //cannot reach destination
|
||||
{
|
||||
return std::make_pair(std::vector<BattleHex>(), 0);
|
||||
}
|
||||
|
||||
//making the Path
|
||||
std::vector<BattleHex> path;
|
||||
BattleHex curElem = dest;
|
||||
while(curElem != start)
|
||||
{
|
||||
path.push_back(curElem);
|
||||
curElem = reachability.predecessors[curElem];
|
||||
}
|
||||
|
||||
return std::make_pair(path, reachability.distances[dest]);
|
||||
}
|
||||
|
||||
void BattleInfo::calculateCasualties(std::map<ui32,si32> * casualties) const
|
||||
{
|
||||
for(const auto & st : stacks) //setting casualties
|
||||
{
|
||||
si32 killed = st->getKilled();
|
||||
if(killed > 0)
|
||||
casualties[st->unitSide()][st->creatureId()] += killed;
|
||||
}
|
||||
}
|
||||
|
||||
CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base, ui8 side, const SlotID & slot, BattleHex position)
|
||||
{
|
||||
PlayerColor owner = sides[side].color;
|
||||
@ -560,10 +529,24 @@ BattleInfo::BattleInfo():
|
||||
tacticsSide(0),
|
||||
tacticDistance(0)
|
||||
{
|
||||
setBattle(this);
|
||||
setNodeType(BATTLE);
|
||||
}
|
||||
|
||||
BattleID BattleInfo::getBattleID() const
|
||||
{
|
||||
return battleID;
|
||||
}
|
||||
|
||||
const IBattleInfo * BattleInfo::getBattle() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
std::optional<PlayerColor> BattleInfo::getPlayerID() const
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
BattleInfo::~BattleInfo()
|
||||
{
|
||||
for (auto & elem : stacks)
|
||||
@ -689,14 +672,30 @@ int64_t BattleInfo::getActualDamage(const DamageRange & damage, int32_t attacker
|
||||
}
|
||||
}
|
||||
|
||||
void BattleInfo::nextRound(int32_t roundNr)
|
||||
int3 BattleInfo::getLocation() const
|
||||
{
|
||||
return tile;
|
||||
}
|
||||
|
||||
bool BattleInfo::isCreatureBank() const
|
||||
{
|
||||
return creatureBank;
|
||||
}
|
||||
|
||||
|
||||
std::vector<SpellID> BattleInfo::getUsedSpells(ui8 side) const
|
||||
{
|
||||
return sides.at(side).usedSpellsHistory;
|
||||
}
|
||||
|
||||
void BattleInfo::nextRound()
|
||||
{
|
||||
for(int i = 0; i < 2; ++i)
|
||||
{
|
||||
sides.at(i).castSpellsCount = 0;
|
||||
vstd::amax(--sides.at(i).enchanterCounter, 0);
|
||||
}
|
||||
round = roundNr;
|
||||
round += 1;
|
||||
|
||||
for(CStack * s : stacks)
|
||||
{
|
||||
|
@ -75,9 +75,14 @@ public:
|
||||
BattleInfo();
|
||||
virtual ~BattleInfo();
|
||||
|
||||
const IBattleInfo * getBattle() const override;
|
||||
std::optional<PlayerColor> getPlayerID() const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IBattleInfo
|
||||
|
||||
BattleID getBattleID() const override;
|
||||
|
||||
int32_t getActiveStackID() const override;
|
||||
|
||||
TStacks getStacksIf(TStackFilter predicate) const override;
|
||||
@ -109,10 +114,15 @@ public:
|
||||
|
||||
int64_t getActualDamage(const DamageRange & damage, int32_t attackerCount, vstd::RNG & rng) const override;
|
||||
|
||||
int3 getLocation() const override;
|
||||
bool isCreatureBank() const override;
|
||||
|
||||
std::vector<SpellID> getUsedSpells(ui8 side) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IBattleState
|
||||
|
||||
void nextRound(int32_t roundNr) override;
|
||||
void nextRound() override;
|
||||
void nextTurn(uint32_t unitId) override;
|
||||
|
||||
void addUnit(uint32_t id, const JsonNode & data) override;
|
||||
@ -140,10 +150,6 @@ public:
|
||||
using CBattleInfoEssentials::battleGetFightingHero;
|
||||
CGHeroInstance * battleGetFightingHero(ui8 side) const;
|
||||
|
||||
std::pair< std::vector<BattleHex>, int > getPath(BattleHex start, BattleHex dest, const battle::Unit * stack) const; //returned value: pair<path, length>; length may be different than number of elements in path since flying creatures jump between distant hexes
|
||||
|
||||
void calculateCasualties(std::map<ui32,si32> * casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
|
||||
|
||||
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);
|
||||
|
||||
|
@ -17,13 +17,20 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
BattleProxy::BattleProxy(Subject subject_):
|
||||
subject(std::move(subject_))
|
||||
{
|
||||
setBattle(this);
|
||||
player = subject->getPlayerID();
|
||||
}
|
||||
{}
|
||||
|
||||
BattleProxy::~BattleProxy() = default;
|
||||
|
||||
const IBattleInfo * BattleProxy::getBattle() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
std::optional<PlayerColor> BattleProxy::getPlayerID() const
|
||||
{
|
||||
return subject->getPlayerID();
|
||||
}
|
||||
|
||||
int32_t BattleProxy::getActiveStackID() const
|
||||
{
|
||||
const auto * ret = subject->battleActiveUnit();
|
||||
|
@ -24,6 +24,8 @@ public:
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// IBattleInfo
|
||||
const IBattleInfo * getBattle() const override;
|
||||
std::optional<PlayerColor> getPlayerID() const override;
|
||||
|
||||
int32_t getActiveStackID() const override;
|
||||
|
||||
|
@ -136,6 +136,27 @@ ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(const spells::Caster *
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
|
||||
std::pair< std::vector<BattleHex>, int > CBattleInfoCallback::getPath(BattleHex start, BattleHex dest, const battle::Unit * stack) const
|
||||
{
|
||||
auto reachability = getReachability(stack);
|
||||
|
||||
if(reachability.predecessors[dest] == -1) //cannot reach destination
|
||||
{
|
||||
return std::make_pair(std::vector<BattleHex>(), 0);
|
||||
}
|
||||
|
||||
//making the Path
|
||||
std::vector<BattleHex> path;
|
||||
BattleHex curElem = dest;
|
||||
while(curElem != start)
|
||||
{
|
||||
path.push_back(curElem);
|
||||
curElem = reachability.predecessors[curElem];
|
||||
}
|
||||
|
||||
return std::make_pair(path, reachability.distances[dest]);
|
||||
}
|
||||
|
||||
bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const
|
||||
{
|
||||
auto isTileBlocked = [&](BattleHex tile)
|
||||
|
@ -89,6 +89,8 @@ public:
|
||||
std::set<BattleHex> battleGetAttackedHexes(const battle::Unit * attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID) const;
|
||||
bool isEnemyUnitWithinSpecifiedRange(BattleHex attackerPosition, const battle::Unit * defenderUnit, unsigned int range) const;
|
||||
|
||||
std::pair< std::vector<BattleHex>, int > getPath(BattleHex start, BattleHex dest, const battle::Unit * stack) const;
|
||||
|
||||
bool battleCanAttack(const battle::Unit * stack, const battle::Unit * target, BattleHex dest) const; //determines if stack with given ID can attack target at the selected destination
|
||||
bool battleCanShoot(const battle::Unit * attacker, BattleHex dest) const; //determines if stack with given ID shoot at the selected destination
|
||||
bool battleCanShoot(const battle::Unit * attacker) const; //determines if stack with given ID shoot in principle
|
||||
|
@ -17,6 +17,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
bool CBattleInfoEssentials::duringBattle() const
|
||||
{
|
||||
return getBattle() != nullptr;
|
||||
}
|
||||
|
||||
TerrainId CBattleInfoEssentials::battleTerrainType() const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(TerrainId());
|
||||
@ -47,7 +52,7 @@ std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoEssentials::bat
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!!player && *perspective != battleGetMySide())
|
||||
if(!!getPlayerID() && *perspective != battleGetMySide())
|
||||
logGlobal->warn("Unauthorized obstacles access attempt, assuming massive spell");
|
||||
}
|
||||
|
||||
@ -157,14 +162,14 @@ const CGTownInstance * CBattleInfoEssentials::battleGetDefendedTown() const
|
||||
BattlePerspective::BattlePerspective CBattleInfoEssentials::battleGetMySide() const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(BattlePerspective::INVALID);
|
||||
if(!player || player->isSpectator())
|
||||
if(!getPlayerID() || getPlayerID()->isSpectator())
|
||||
return BattlePerspective::ALL_KNOWING;
|
||||
if(*player == getBattle()->getSidePlayer(BattleSide::ATTACKER))
|
||||
if(*getPlayerID() == getBattle()->getSidePlayer(BattleSide::ATTACKER))
|
||||
return BattlePerspective::LEFT_SIDE;
|
||||
if(*player == getBattle()->getSidePlayer(BattleSide::DEFENDER))
|
||||
if(*getPlayerID() == getBattle()->getSidePlayer(BattleSide::DEFENDER))
|
||||
return BattlePerspective::RIGHT_SIDE;
|
||||
|
||||
logGlobal->error("Cannot find player %s in battle!", player->toString());
|
||||
logGlobal->error("Cannot find player %s in battle!", getPlayerID()->toString());
|
||||
return BattlePerspective::INVALID;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ namespace BattlePerspective
|
||||
};
|
||||
}
|
||||
|
||||
class DLL_LINKAGE CBattleInfoEssentials : public virtual CCallbackBase, public IBattleInfoCallback
|
||||
class DLL_LINKAGE CBattleInfoEssentials : public IBattleInfoCallback
|
||||
{
|
||||
protected:
|
||||
bool battleDoWeKnowAbout(ui8 side) const;
|
||||
@ -45,6 +45,7 @@ public:
|
||||
ONLY_MINE, ONLY_ENEMY, MINE_AND_ENEMY
|
||||
};
|
||||
|
||||
bool duringBattle() const;
|
||||
BattlePerspective::BattlePerspective battleGetMySide() const;
|
||||
const IBonusBearer * getBonusBearer() const override;
|
||||
|
||||
|
@ -13,26 +13,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
bool CCallbackBase::duringBattle() const
|
||||
{
|
||||
return getBattle() != nullptr;
|
||||
}
|
||||
|
||||
const IBattleInfo * CCallbackBase::getBattle() const
|
||||
{
|
||||
return battle;
|
||||
}
|
||||
|
||||
CCallbackBase::CCallbackBase(std::optional<PlayerColor> Player):
|
||||
player(std::move(Player))
|
||||
{
|
||||
}
|
||||
|
||||
void CCallbackBase::setBattle(const IBattleInfo * B)
|
||||
{
|
||||
battle = B;
|
||||
}
|
||||
|
||||
std::optional<PlayerColor> CCallbackBase::getPlayerID() const
|
||||
{
|
||||
return player;
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "../GameConstants.h"
|
||||
|
||||
#define RETURN_IF_NOT_BATTLE(...) if(!duringBattle()) {logGlobal->error("%s called when no battle!", __FUNCTION__); return __VA_ARGS__; }
|
||||
#define ASSERT_IF_CALLED_WITH_PLAYER if(!player) {logGlobal->error(BOOST_CURRENT_FUNCTION); assert(0);}
|
||||
#define ASSERT_IF_CALLED_WITH_PLAYER if(!getPlayerID()) {logGlobal->error(BOOST_CURRENT_FUNCTION); assert(0);}
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -19,26 +19,17 @@ class IBattleInfo;
|
||||
class BattleInfo;
|
||||
class CBattleInfoEssentials;
|
||||
|
||||
|
||||
//Basic class for various callbacks (interfaces called by players to get info about game and so forth)
|
||||
class DLL_LINKAGE CCallbackBase
|
||||
{
|
||||
const IBattleInfo * battle = nullptr; //battle to which the player is engaged, nullptr if none or not applicable
|
||||
|
||||
protected:
|
||||
std::optional<PlayerColor> player; // not set gives access to all information, otherwise callback provides only information "visible" for player
|
||||
|
||||
CCallbackBase(std::optional<PlayerColor> Player);
|
||||
CCallbackBase() = default;
|
||||
|
||||
const IBattleInfo * getBattle() const;
|
||||
void setBattle(const IBattleInfo * B);
|
||||
bool duringBattle() const;
|
||||
|
||||
public:
|
||||
std::optional<PlayerColor> getPlayerID() const;
|
||||
|
||||
friend class CBattleInfoEssentials;
|
||||
};
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ bool CPlayerBattleCallback::battleCanFlee() const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(false);
|
||||
ASSERT_IF_CALLED_WITH_PLAYER
|
||||
return CBattleInfoEssentials::battleCanFlee(*player);
|
||||
return CBattleInfoEssentials::battleCanFlee(*getPlayerID());
|
||||
}
|
||||
|
||||
TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose, bool onlyAlive) const
|
||||
@ -30,8 +30,8 @@ TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose, bool onlyA
|
||||
|
||||
return battleGetStacksIf([=](const CStack * s){
|
||||
const bool ownerMatches = (whose == MINE_AND_ENEMY)
|
||||
|| (whose == ONLY_MINE && s->unitOwner() == player)
|
||||
|| (whose == ONLY_ENEMY && s->unitOwner() != player);
|
||||
|| (whose == ONLY_MINE && s->unitOwner() == getPlayerID())
|
||||
|| (whose == ONLY_ENEMY && s->unitOwner() != getPlayerID());
|
||||
|
||||
return ownerMatches && s->isValidTarget(!onlyAlive);
|
||||
});
|
||||
@ -41,7 +41,7 @@ int CPlayerBattleCallback::battleGetSurrenderCost() const
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(-3)
|
||||
ASSERT_IF_CALLED_WITH_PLAYER
|
||||
return CBattleInfoCallback::battleGetSurrenderCost(*player);
|
||||
return CBattleInfoCallback::battleGetSurrenderCost(*getPlayerID());
|
||||
}
|
||||
|
||||
const CGHeroInstance * CPlayerBattleCallback::battleGetMyHero() const
|
||||
|
@ -19,6 +19,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct CObstacleInstance;
|
||||
class BattleField;
|
||||
class IBattleInfo;
|
||||
|
||||
namespace battle
|
||||
{
|
||||
@ -54,6 +55,9 @@ public:
|
||||
virtual scripting::Pool * getContextPool() const = 0;
|
||||
#endif
|
||||
|
||||
virtual const IBattleInfo * getBattle() const = 0;
|
||||
virtual std::optional<PlayerColor> getPlayerID() const = 0;
|
||||
|
||||
virtual TerrainId battleTerrainType() const = 0;
|
||||
virtual BattleField battleGetBattlefieldType() const = 0;
|
||||
|
||||
|
@ -19,6 +19,7 @@ struct Bonus;
|
||||
class JsonNode;
|
||||
class JsonSerializeFormat;
|
||||
class BattleField;
|
||||
class int3;
|
||||
|
||||
namespace vstd
|
||||
{
|
||||
@ -37,6 +38,8 @@ public:
|
||||
|
||||
virtual ~IBattleInfo() = default;
|
||||
|
||||
virtual BattleID getBattleID() const = 0;
|
||||
|
||||
virtual int32_t getActiveStackID() const = 0;
|
||||
|
||||
virtual TStacks getStacksIf(TStackFilter predicate) const = 0;
|
||||
@ -55,6 +58,8 @@ public:
|
||||
virtual PlayerColor getSidePlayer(ui8 side) const = 0;
|
||||
virtual const CArmedInstance * getSideArmy(ui8 side) const = 0;
|
||||
virtual const CGHeroInstance * getSideHero(ui8 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 uint32_t getCastSpells(ui8 side) const = 0;
|
||||
virtual int32_t getEnchanterCounter(ui8 side) const = 0;
|
||||
@ -65,14 +70,15 @@ public:
|
||||
virtual uint32_t nextUnitId() const = 0;
|
||||
|
||||
virtual int64_t getActualDamage(const DamageRange & damage, int32_t attackerCount, vstd::RNG & rng) const = 0;
|
||||
|
||||
virtual int3 getLocation() const = 0;
|
||||
virtual bool isCreatureBank() const = 0;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IBattleState : public IBattleInfo
|
||||
{
|
||||
public:
|
||||
//TODO: add non-const API
|
||||
|
||||
virtual void nextRound(int32_t roundNr) = 0;
|
||||
virtual void nextRound() = 0;
|
||||
virtual void nextTurn(uint32_t unitId) = 0;
|
||||
|
||||
virtual void addUnit(uint32_t id, const JsonNode & data) = 0;
|
||||
|
@ -136,9 +136,9 @@ const Services * CGameHandler::services() const
|
||||
return VLC;
|
||||
}
|
||||
|
||||
const CGameHandler::BattleCb * CGameHandler::battle() const
|
||||
const CGameHandler::BattleCb * CGameHandler::battle(const BattleID & battleID) const
|
||||
{
|
||||
return this;
|
||||
return gs->getBattle(battleID);
|
||||
}
|
||||
|
||||
const CGameHandler::GameCb * CGameHandler::game() const
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <vcmi/Environment.h>
|
||||
|
||||
#include "../lib/IGameCallback.h"
|
||||
#include "../lib/battle/CBattleInfoCallback.h"
|
||||
#include "../lib/LoadProgress.h"
|
||||
#include "../lib/ScriptHandler.h"
|
||||
#include "TurnTimerHandler.h"
|
||||
@ -53,14 +52,12 @@ class TurnOrderProcessor;
|
||||
class QueriesProcessor;
|
||||
class CObjectVisitQuery;
|
||||
|
||||
class CGameHandler : public IGameCallback, public CBattleInfoCallback, public Environment
|
||||
class CGameHandler : public IGameCallback, public Environment
|
||||
{
|
||||
CVCMIServer * lobby;
|
||||
std::shared_ptr<CApplier<CBaseForGHApply>> applier;
|
||||
|
||||
public:
|
||||
using CCallbackBase::setBattle;
|
||||
|
||||
std::unique_ptr<HeroPoolProcessor> heroPool;
|
||||
std::unique_ptr<BattleProcessor> battles;
|
||||
std::unique_ptr<QueriesProcessor> queries;
|
||||
@ -84,7 +81,7 @@ public:
|
||||
TurnTimerHandler turnTimerHandler;
|
||||
|
||||
const Services * services() const override;
|
||||
const BattleCb * battle() const override;
|
||||
const BattleCb * battle(const BattleID & battleID) const override;
|
||||
const GameCb * game() const override;
|
||||
vstd::CLoggerBase * logger() const override;
|
||||
events::EventBus * eventBus() const override;
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "../lib/IGameCallback.h"
|
||||
#include "../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../lib/gameState/CGameState.h"
|
||||
#include "../lib/battle/BattleInfo.h"
|
||||
#include "../lib/battle/IBattleState.h"
|
||||
#include "../lib/battle/BattleAction.h"
|
||||
#include "../lib/battle/Unit.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
|
@ -17,7 +17,8 @@
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/CStack.h"
|
||||
#include "../../lib/GameSettings.h"
|
||||
#include "../../lib/battle/BattleInfo.h"
|
||||
#include "../../lib/battle/CBattleInfoCallback.h"
|
||||
#include "../../lib/battle/IBattleState.h"
|
||||
#include "../../lib/battle/BattleAction.h"
|
||||
#include "../../lib/gameState/CGameState.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
@ -37,19 +38,19 @@ void BattleActionProcessor::setGameHandler(CGameHandler * newGameHandler)
|
||||
gameHandler = newGameHandler;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doEmptyAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doEmptyAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doEndTacticsAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doEndTacticsAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doWaitAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doWaitAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
const CStack * stack = gameHandler->battleGetStackByID(ba.stackNumber);
|
||||
const CStack * stack = battle.battleGetStackByID(ba.stackNumber);
|
||||
|
||||
if (!canStackAct(battle, stack))
|
||||
return false;
|
||||
@ -57,9 +58,9 @@ bool BattleActionProcessor::doWaitAction(const BattleInfo & battle, const Battle
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doRetreatAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doRetreatAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
if (!battle.battleCanFlee(battle.sides.at(ba.side).color))
|
||||
if (!battle.battleCanFlee(battle.sideToPlayer(ba.side)))
|
||||
{
|
||||
gameHandler->complain("Cannot retreat!");
|
||||
return false;
|
||||
@ -69,9 +70,9 @@ bool BattleActionProcessor::doRetreatAction(const BattleInfo & battle, const Bat
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doSurrenderAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doSurrenderAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
PlayerColor player = battle.sides.at(ba.side).color;
|
||||
PlayerColor player = battle.sideToPlayer(ba.side);
|
||||
int cost = battle.battleGetSurrenderCost(player);
|
||||
if (cost < 0)
|
||||
{
|
||||
@ -90,7 +91,7 @@ bool BattleActionProcessor::doSurrenderAction(const BattleInfo & battle, const B
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doHeroSpellAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doHeroSpellAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
const CGHeroInstance *h = battle.battleGetFightingHero(ba.side);
|
||||
if (!h)
|
||||
@ -127,9 +128,9 @@ bool BattleActionProcessor::doHeroSpellAction(const BattleInfo & battle, const B
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doWalkAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doWalkAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
const CStack * stack = gameHandler->battleGetStackByID(ba.stackNumber);
|
||||
const CStack * stack = battle.battleGetStackByID(ba.stackNumber);
|
||||
battle::Target target = ba.getTarget(&battle);
|
||||
|
||||
if (!canStackAct(battle, stack))
|
||||
@ -150,9 +151,9 @@ bool BattleActionProcessor::doWalkAction(const BattleInfo & battle, const Battle
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doDefendAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doDefendAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
const CStack * stack = gameHandler->battleGetStackByID(ba.stackNumber);
|
||||
const CStack * stack = battle.battleGetStackByID(ba.stackNumber);
|
||||
|
||||
if (!canStackAct(battle, stack))
|
||||
return false;
|
||||
@ -199,9 +200,9 @@ bool BattleActionProcessor::doDefendAction(const BattleInfo & battle, const Batt
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doAttackAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doAttackAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
const CStack * stack = gameHandler->battleGetStackByID(ba.stackNumber);
|
||||
const CStack * stack = battle.battleGetStackByID(ba.stackNumber);
|
||||
battle::Target target = ba.getTarget(&battle);
|
||||
|
||||
if (!canStackAct(battle, stack))
|
||||
@ -302,9 +303,9 @@ bool BattleActionProcessor::doAttackAction(const BattleInfo & battle, const Batt
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doShootAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doShootAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
const CStack * stack = gameHandler->battleGetStackByID(ba.stackNumber);
|
||||
const CStack * stack = battle.battleGetStackByID(ba.stackNumber);
|
||||
battle::Target target = ba.getTarget(&battle);
|
||||
|
||||
if (!canStackAct(battle, stack))
|
||||
@ -369,7 +370,7 @@ bool BattleActionProcessor::doShootAction(const BattleInfo & battle, const Battl
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doCatapultAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doCatapultAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
const CStack * stack = battle.battleGetStackByID(ba.stackNumber);
|
||||
battle::Target target = ba.getTarget(&battle);
|
||||
@ -393,7 +394,7 @@ bool BattleActionProcessor::doCatapultAction(const BattleInfo & battle, const Ba
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doUnitSpellAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doUnitSpellAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
const CStack * stack = battle.battleGetStackByID(ba.stackNumber);
|
||||
battle::Target target = ba.getTarget(&battle);
|
||||
@ -406,8 +407,8 @@ bool BattleActionProcessor::doUnitSpellAction(const BattleInfo & battle, const B
|
||||
std::shared_ptr<const Bonus> spellcaster = stack->getBonus(Selector::typeSubtype(BonusType::SPELLCASTER, spellID));
|
||||
|
||||
//TODO special bonus for genies ability
|
||||
if (randSpellcaster && gameHandler->battleGetRandomStackSpell(gameHandler->getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_AIMED) == SpellID::NONE)
|
||||
spellID = gameHandler->battleGetRandomStackSpell(gameHandler->getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_GENIE);
|
||||
if (randSpellcaster && battle.battleGetRandomStackSpell(gameHandler->getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_AIMED) == SpellID::NONE)
|
||||
spellID = battle.battleGetRandomStackSpell(gameHandler->getRandomGenerator(), stack, CBattleInfoCallback::RANDOM_GENIE);
|
||||
|
||||
if (spellID == SpellID::NONE)
|
||||
gameHandler->complain("That stack can't cast spells!");
|
||||
@ -426,7 +427,7 @@ bool BattleActionProcessor::doUnitSpellAction(const BattleInfo & battle, const B
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::doHealAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::doHealAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
const CStack * stack = battle.battleGetStackByID(ba.stackNumber);
|
||||
battle::Target target = ba.getTarget(&battle);
|
||||
@ -463,7 +464,7 @@ bool BattleActionProcessor::doHealAction(const BattleInfo & battle, const Battle
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::canStackAct(const BattleInfo & battle, const CStack * stack)
|
||||
bool BattleActionProcessor::canStackAct(const CBattleInfoCallback & battle, const CStack * stack)
|
||||
{
|
||||
if (!stack)
|
||||
{
|
||||
@ -476,9 +477,9 @@ bool BattleActionProcessor::canStackAct(const BattleInfo & battle, const CStack
|
||||
return false;
|
||||
}
|
||||
|
||||
if (gameHandler->battleTacticDist())
|
||||
if (battle.battleTacticDist())
|
||||
{
|
||||
if (stack && stack->unitSide() != gameHandler->battleGetTacticsSide())
|
||||
if (stack && stack->unitSide() != battle.battleGetTacticsSide())
|
||||
{
|
||||
gameHandler->complain("This is not a stack of side that has tactics!");
|
||||
return false;
|
||||
@ -486,7 +487,7 @@ bool BattleActionProcessor::canStackAct(const BattleInfo & battle, const CStack
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stack->unitId() != battle.getActiveStackID())
|
||||
if (stack != battle.battleActiveUnit())
|
||||
{
|
||||
gameHandler->complain("Action has to be about active stack!");
|
||||
return false;
|
||||
@ -495,7 +496,7 @@ bool BattleActionProcessor::canStackAct(const BattleInfo & battle, const CStack
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::dispatchBattleAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::dispatchBattleAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
switch(ba.actionType)
|
||||
{
|
||||
@ -531,7 +532,7 @@ bool BattleActionProcessor::dispatchBattleAction(const BattleInfo & battle, cons
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::makeBattleActionImpl(const BattleInfo & battle, const BattleAction &ba)
|
||||
bool BattleActionProcessor::makeBattleActionImpl(const CBattleInfoCallback & battle, const BattleAction &ba)
|
||||
{
|
||||
logGlobal->trace("Making action: %s", ba.toString());
|
||||
const CStack * stack = battle.battleGetStackByID(ba.stackNumber);
|
||||
@ -552,22 +553,22 @@ bool BattleActionProcessor::makeBattleActionImpl(const BattleInfo & battle, cons
|
||||
}
|
||||
|
||||
if(ba.actionType == EActionType::WAIT || ba.actionType == EActionType::DEFEND || ba.actionType == EActionType::SHOOT || ba.actionType == EActionType::MONSTER_SPELL)
|
||||
gameHandler->handleObstacleTriggersForUnit(*gameHandler->spellEnv, *stack);
|
||||
battle.handleObstacleTriggersForUnit(*gameHandler->spellEnv, *stack);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int BattleActionProcessor::moveStack(const BattleInfo & battle, int stack, BattleHex dest)
|
||||
int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int stack, BattleHex dest)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
const CStack *curStack = gameHandler->battleGetStackByID(stack);
|
||||
const CStack *curStack = battle.battleGetStackByID(stack);
|
||||
const CStack *stackAtEnd = battle.battleGetStackByPos(dest);
|
||||
|
||||
assert(curStack);
|
||||
assert(dest < GameConstants::BFIELD_SIZE);
|
||||
|
||||
if (battle.tacticDistance)
|
||||
if (battle.battleGetTacticDist())
|
||||
{
|
||||
assert(battle.isInTacticRange(dest));
|
||||
}
|
||||
@ -577,7 +578,7 @@ int BattleActionProcessor::moveStack(const BattleInfo & battle, int stack, Battl
|
||||
return 0;
|
||||
|
||||
//initing necessary tables
|
||||
auto accessibility = gameHandler->getAccesibility(curStack);
|
||||
auto accessibility = battle.getAccesibility(curStack);
|
||||
std::set<BattleHex> passed;
|
||||
//Ignore obstacles on starting position
|
||||
passed.insert(curStack->getPosition());
|
||||
@ -600,8 +601,8 @@ int BattleActionProcessor::moveStack(const BattleInfo & battle, int stack, Battl
|
||||
}
|
||||
|
||||
bool canUseGate = false;
|
||||
auto dbState = battle.si.gateState;
|
||||
if(gameHandler->battleGetSiegeLevel() > 0 && curStack->unitSide() == BattleSide::DEFENDER &&
|
||||
auto dbState = battle.battleGetGateState();
|
||||
if(battle.battleGetSiegeLevel() > 0 && curStack->unitSide() == BattleSide::DEFENDER &&
|
||||
dbState != EGateState::DESTROYED &&
|
||||
dbState != EGateState::BLOCKED)
|
||||
{
|
||||
@ -614,10 +615,10 @@ int BattleActionProcessor::moveStack(const BattleInfo & battle, int stack, Battl
|
||||
|
||||
int creSpeed = curStack->speed(0, true);
|
||||
|
||||
if (battle.tacticDistance > 0 && creSpeed > 0)
|
||||
if (battle.battleGetTacticDist() > 0 && creSpeed > 0)
|
||||
creSpeed = GameConstants::BFIELD_SIZE;
|
||||
|
||||
bool hasWideMoat = vstd::contains_if(gameHandler->battleGetAllObstaclesOnPos(BattleHex(BattleHex::GATE_BRIDGE), false), [](const std::shared_ptr<const CObstacleInstance> & obst)
|
||||
bool hasWideMoat = vstd::contains_if(battle.battleGetAllObstaclesOnPos(BattleHex(BattleHex::GATE_BRIDGE), false), [](const std::shared_ptr<const CObstacleInstance> & obst)
|
||||
{
|
||||
return obst->obstacleType == CObstacleInstance::MOAT;
|
||||
});
|
||||
@ -772,14 +773,14 @@ int BattleActionProcessor::moveStack(const BattleInfo & battle, int stack, Battl
|
||||
}
|
||||
|
||||
//if we walked onto something, finalize this portion of stack movement check into obstacle
|
||||
if(!gameHandler->battleGetAllObstaclesOnPos(hex, false).empty())
|
||||
if(!battle.battleGetAllObstaclesOnPos(hex, false).empty())
|
||||
obstacleHit = true;
|
||||
|
||||
if (curStack->doubleWide())
|
||||
{
|
||||
BattleHex otherHex = curStack->occupiedHex(hex);
|
||||
//two hex creature hit obstacle by backside
|
||||
auto obstacle2 = gameHandler->battleGetAllObstaclesOnPos(otherHex, false);
|
||||
auto obstacle2 = battle.battleGetAllObstaclesOnPos(otherHex, false);
|
||||
if(otherHex.isValid() && !obstacle2.empty())
|
||||
obstacleHit = true;
|
||||
}
|
||||
@ -805,7 +806,7 @@ int BattleActionProcessor::moveStack(const BattleInfo & battle, int stack, Battl
|
||||
{
|
||||
if(stackIsMoving && start != curStack->getPosition())
|
||||
{
|
||||
stackIsMoving = gameHandler->handleObstacleTriggersForUnit(*gameHandler->spellEnv, *curStack, passed);
|
||||
stackIsMoving = battle.handleObstacleTriggersForUnit(*gameHandler->spellEnv, *curStack, passed);
|
||||
passed.insert(curStack->getPosition());
|
||||
if(curStack->doubleWide())
|
||||
passed.insert(curStack->occupiedHex());
|
||||
@ -843,12 +844,12 @@ int BattleActionProcessor::moveStack(const BattleInfo & battle, int stack, Battl
|
||||
passed.clear(); //Just empty passed, obstacles will handled automatically
|
||||
}
|
||||
//handling obstacle on the final field (separate, because it affects both flying and walking stacks)
|
||||
gameHandler->handleObstacleTriggersForUnit(*gameHandler->spellEnv, *curStack, passed);
|
||||
battle.handleObstacleTriggersForUnit(*gameHandler->spellEnv, *curStack, passed);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BattleActionProcessor::makeAttack(const BattleInfo & battle, const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter)
|
||||
void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter)
|
||||
{
|
||||
if(first && !counter)
|
||||
handleAttackBeforeCasting(battle, ranged, attacker, defender);
|
||||
@ -891,7 +892,7 @@ void BattleActionProcessor::makeAttack(const BattleInfo & battle, const CStack *
|
||||
bat.flags |= BattleAttack::DEATH_BLOW;
|
||||
}
|
||||
|
||||
const auto * owner = battle.getHero(attacker->unitOwner());
|
||||
const auto * owner = battle.battleGetFightingHero(attacker->unitOwner());
|
||||
if(owner)
|
||||
{
|
||||
int chance = owner->valOfBonuses(BonusType::BONUS_DAMAGE_CHANCE, attacker->creatureIndex());
|
||||
@ -1012,7 +1013,7 @@ void BattleActionProcessor::makeAttack(const BattleInfo & battle, const CStack *
|
||||
const CStack * actor = item.first;
|
||||
int64_t rawDamage = item.second;
|
||||
|
||||
const CGHeroInstance * actorOwner = battle.getHero(actor->unitOwner());
|
||||
const CGHeroInstance * actorOwner = battle.battleGetFightingHero(actor->unitOwner());
|
||||
|
||||
if(actorOwner)
|
||||
{
|
||||
@ -1058,7 +1059,7 @@ void BattleActionProcessor::makeAttack(const BattleInfo & battle, const CStack *
|
||||
handleAfterAttackCasting(battle, ranged, attacker, defender);
|
||||
}
|
||||
|
||||
void BattleActionProcessor::attackCasting(const BattleInfo & battle, bool ranged, BonusType attackMode, const battle::Unit * attacker, const battle::Unit * defender)
|
||||
void BattleActionProcessor::attackCasting(const CBattleInfoCallback & battle, bool ranged, BonusType attackMode, const battle::Unit * attacker, const battle::Unit * defender)
|
||||
{
|
||||
if(attacker->hasBonusOfType(attackMode))
|
||||
{
|
||||
@ -1126,12 +1127,12 @@ void BattleActionProcessor::attackCasting(const BattleInfo & battle, bool ranged
|
||||
}
|
||||
}
|
||||
|
||||
void BattleActionProcessor::handleAttackBeforeCasting(const BattleInfo & battle, bool ranged, const CStack * attacker, const CStack * defender)
|
||||
void BattleActionProcessor::handleAttackBeforeCasting(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender)
|
||||
{
|
||||
attackCasting(battle, ranged, BonusType::SPELL_BEFORE_ATTACK, attacker, defender); //no death stare / acid breath needed?
|
||||
}
|
||||
|
||||
void BattleActionProcessor::handleAfterAttackCasting(const BattleInfo & battle, bool ranged, const CStack * attacker, const CStack * defender)
|
||||
void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender)
|
||||
{
|
||||
if(!attacker->alive() || !defender->alive()) // can be already dead
|
||||
return;
|
||||
@ -1286,7 +1287,7 @@ void BattleActionProcessor::handleAfterAttackCasting(const BattleInfo & battle,
|
||||
}
|
||||
}
|
||||
|
||||
int64_t BattleActionProcessor::applyBattleEffects(const BattleInfo & battle, BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary)
|
||||
int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & battle, BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary)
|
||||
{
|
||||
BattleStackAttacked bsa;
|
||||
if(secondary)
|
||||
@ -1303,7 +1304,7 @@ int64_t BattleActionProcessor::applyBattleEffects(const BattleInfo & battle, Bat
|
||||
bai.unluckyStrike = bat.unlucky();
|
||||
|
||||
auto range = battle.calculateDmgRange(bai);
|
||||
bsa.damageAmount = battle.getActualDamage(range.damage, attackerState->getCount(), gameHandler->getRandomGenerator());
|
||||
bsa.damageAmount = battle.getBattle()->getActualDamage(range.damage, attackerState->getCount(), gameHandler->getRandomGenerator());
|
||||
CStack::prepareAttacked(bsa, gameHandler->getRandomGenerator(), bai.defender->acquireState()); //calculate casualties
|
||||
}
|
||||
|
||||
@ -1390,17 +1391,17 @@ void BattleActionProcessor::addGenericKilledLog(BattleLogMessage & blm, const CS
|
||||
}
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::makeAutomaticBattleAction(const BattleInfo & battle, const BattleAction & ba)
|
||||
bool BattleActionProcessor::makeAutomaticBattleAction(const CBattleInfoCallback & battle, const BattleAction & ba)
|
||||
{
|
||||
return makeBattleActionImpl(battle, ba);
|
||||
}
|
||||
|
||||
bool BattleActionProcessor::makePlayerBattleAction(const BattleInfo & battle, PlayerColor player, const BattleAction &ba)
|
||||
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!"))
|
||||
return false;
|
||||
|
||||
if(battle.tacticDistance != 0)
|
||||
if(battle.battleGetTacticDist() != 0)
|
||||
{
|
||||
if(!ba.isTacticsAction())
|
||||
{
|
||||
@ -1408,7 +1409,7 @@ bool BattleActionProcessor::makePlayerBattleAction(const BattleInfo & battle, Pl
|
||||
return false;
|
||||
}
|
||||
|
||||
if(player != battle.sides[ba.side].color)
|
||||
if(player != battle.sideToPlayer(ba.side))
|
||||
{
|
||||
gameHandler->complain("Can not make actions in battles you are not part of!");
|
||||
return false;
|
||||
@ -1416,16 +1417,16 @@ bool BattleActionProcessor::makePlayerBattleAction(const BattleInfo & battle, Pl
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ba.isUnitAction() && ba.stackNumber != battle.getActiveStackID())
|
||||
auto active = battle.battleActiveUnit();
|
||||
if(!active && gameHandler->complain("No active unit in battle!"))
|
||||
return false;
|
||||
|
||||
if (ba.isUnitAction() && ba.stackNumber != active->unitId())
|
||||
{
|
||||
gameHandler->complain("Can not make actions - stack is not active!");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto active = battle.battleActiveUnit();
|
||||
if(!active && gameHandler->complain("No active unit in battle!"))
|
||||
return false;
|
||||
|
||||
auto unitOwner = battle.battleGetOwner(active);
|
||||
|
||||
if(player != unitOwner && gameHandler->complain("Can not make actions in battles you are not part of!"))
|
||||
|
@ -14,7 +14,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
struct BattleLogMessage;
|
||||
struct BattleAttack;
|
||||
class BattleAction;
|
||||
class BattleInfo;
|
||||
class CBattleInfoCallback;
|
||||
struct BattleHex;
|
||||
class CStack;
|
||||
class PlayerColor;
|
||||
@ -39,42 +39,42 @@ class BattleActionProcessor : boost::noncopyable
|
||||
BattleProcessor * owner;
|
||||
CGameHandler * gameHandler;
|
||||
|
||||
int moveStack(const BattleInfo & battle, int stack, BattleHex dest); //returned value - travelled distance
|
||||
void makeAttack(const BattleInfo & battle, const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter);
|
||||
int moveStack(const CBattleInfoCallback & battle, int stack, BattleHex dest); //returned value - travelled distance
|
||||
void makeAttack(const CBattleInfoCallback & battle, const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter);
|
||||
|
||||
void handleAttackBeforeCasting(const BattleInfo & battle, bool ranged, const CStack * attacker, const CStack * defender);
|
||||
void handleAfterAttackCasting(const BattleInfo & battle, bool ranged, const CStack * attacker, const CStack * defender);
|
||||
void attackCasting(const BattleInfo & battle, bool ranged, BonusType attackMode, const battle::Unit * attacker, const battle::Unit * defender);
|
||||
void handleAttackBeforeCasting(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender);
|
||||
void handleAfterAttackCasting(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender);
|
||||
void attackCasting(const CBattleInfoCallback & battle, bool ranged, BonusType attackMode, const battle::Unit * attacker, const battle::Unit * defender);
|
||||
|
||||
// damage, drain life & fire shield; returns amount of drained life
|
||||
int64_t applyBattleEffects(const BattleInfo & battle, BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary);
|
||||
int64_t applyBattleEffects(const CBattleInfoCallback & battle, BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary);
|
||||
|
||||
void sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple);
|
||||
void addGenericKilledLog(BattleLogMessage & blm, const CStack * defender, int32_t killed, bool multiple);
|
||||
|
||||
bool canStackAct(const BattleInfo & battle, const CStack * stack);
|
||||
bool canStackAct(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
|
||||
bool doEmptyAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doEndTacticsAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doRetreatAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doSurrenderAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doHeroSpellAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doWalkAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doWaitAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doDefendAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doAttackAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doShootAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doCatapultAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doUnitSpellAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doHealAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool doEmptyAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doEndTacticsAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doRetreatAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doSurrenderAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doHeroSpellAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doWalkAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doWaitAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doDefendAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doAttackAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doShootAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doCatapultAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doUnitSpellAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool doHealAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
|
||||
bool dispatchBattleAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool makeBattleActionImpl(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool dispatchBattleAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool makeBattleActionImpl(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
|
||||
public:
|
||||
explicit BattleActionProcessor(BattleProcessor * owner);
|
||||
void setGameHandler(CGameHandler * newGameHandler);
|
||||
|
||||
bool makeAutomaticBattleAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool makePlayerBattleAction(const BattleInfo & battle, PlayerColor player, const BattleAction & ba);
|
||||
bool makeAutomaticBattleAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
bool makePlayerBattleAction(const CBattleInfoCallback & battle, PlayerColor player, const BattleAction & ba);
|
||||
};
|
||||
|
@ -16,7 +16,8 @@
|
||||
|
||||
#include "../../lib/CStack.h"
|
||||
#include "../../lib/GameSettings.h"
|
||||
#include "../../lib/battle/BattleInfo.h"
|
||||
#include "../../lib/battle/CBattleInfoCallback.h"
|
||||
#include "../../lib/battle/IBattleState.h"
|
||||
#include "../../lib/gameState/CGameState.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
@ -35,7 +36,7 @@ void BattleFlowProcessor::setGameHandler(CGameHandler * newGameHandler)
|
||||
gameHandler = newGameHandler;
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::summonGuardiansHelper(const BattleInfo & 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, ui8 side, bool targetIsTwoHex) //return hexes for summoning two hex monsters in output, target = unit to guard
|
||||
{
|
||||
int x = targetPosition.getX();
|
||||
int y = targetPosition.getY();
|
||||
@ -110,39 +111,39 @@ void BattleFlowProcessor::summonGuardiansHelper(const BattleInfo & battle, std::
|
||||
}
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::tryPlaceMoats(const BattleInfo & battle)
|
||||
void BattleFlowProcessor::tryPlaceMoats(const CBattleInfoCallback & battle)
|
||||
{
|
||||
const auto * town = battle.battleGetDefendedTown();
|
||||
|
||||
//Moat should be initialized here, because only here we can use spellcasting
|
||||
if (battle.town && battle.town->fortLevel() >= CGTownInstance::CITADEL)
|
||||
if (town && town->fortLevel() >= CGTownInstance::CITADEL)
|
||||
{
|
||||
const auto * h = battle.battleGetFightingHero(BattleSide::DEFENDER);
|
||||
const auto * actualCaster = h ? static_cast<const spells::Caster*>(h) : nullptr;
|
||||
auto moatCaster = spells::SilentCaster(battle.getSidePlayer(BattleSide::DEFENDER), actualCaster);
|
||||
auto cast = spells::BattleCast(&battle, &moatCaster, spells::Mode::PASSIVE, battle.town->town->moatAbility.toSpell());
|
||||
auto moatCaster = spells::SilentCaster(battle.sideToPlayer(BattleSide::DEFENDER), actualCaster);
|
||||
auto cast = spells::BattleCast(&battle, &moatCaster, spells::Mode::PASSIVE, town->town->moatAbility.toSpell());
|
||||
auto target = spells::Target();
|
||||
cast.cast(gameHandler->spellEnv, target);
|
||||
}
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::onBattleStarted(const BattleInfo & battle)
|
||||
void BattleFlowProcessor::onBattleStarted(const CBattleInfoCallback & battle)
|
||||
{
|
||||
gameHandler->setBattle(&battle);
|
||||
|
||||
tryPlaceMoats(battle);
|
||||
|
||||
gameHandler->turnTimerHandler.onBattleStart(battle.battleID);
|
||||
gameHandler->turnTimerHandler.onBattleStart(battle.getBattle()->getBattleID());
|
||||
|
||||
if (battle.tacticDistance == 0)
|
||||
if (battle.battleGetTacticDist() == 0)
|
||||
onTacticsEnded(battle);
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::trySummonGuardians(const BattleInfo & battle, const CStack * stack)
|
||||
void BattleFlowProcessor::trySummonGuardians(const CBattleInfoCallback & battle, const CStack * stack)
|
||||
{
|
||||
if (!stack->hasBonusOfType(BonusType::SUMMON_GUARDIANS))
|
||||
return;
|
||||
|
||||
std::shared_ptr<const Bonus> summonInfo = stack->getBonus(Selector::type()(BonusType::SUMMON_GUARDIANS));
|
||||
auto accessibility = gameHandler->getAccesibility();
|
||||
auto accessibility = battle.getAccesibility();
|
||||
CreatureID creatureData = CreatureID(summonInfo->subtype);
|
||||
std::vector<BattleHex> targetHexes;
|
||||
const bool targetIsBig = stack->unitType()->isDoubleWide(); //target = creature to guard
|
||||
@ -177,7 +178,7 @@ void BattleFlowProcessor::trySummonGuardians(const BattleInfo & battle, const CS
|
||||
}
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::castOpeningSpells(const BattleInfo & battle)
|
||||
void BattleFlowProcessor::castOpeningSpells(const CBattleInfoCallback & battle)
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
@ -202,12 +203,12 @@ void BattleFlowProcessor::castOpeningSpells(const BattleInfo & battle)
|
||||
}
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::onTacticsEnded(const BattleInfo & battle)
|
||||
void BattleFlowProcessor::onTacticsEnded(const CBattleInfoCallback & battle)
|
||||
{
|
||||
//initial stacks appearance triggers, e.g. built-in bonus spells
|
||||
auto initialStacks = battle.stacks; //use temporary variable to outclude summoned stacks added to battle.stacks from processing
|
||||
auto initialStacks = battle.battleGetAllStacks(true);
|
||||
|
||||
for (CStack * stack : initialStacks)
|
||||
for (const CStack * stack : initialStacks)
|
||||
{
|
||||
trySummonGuardians(battle, stack);
|
||||
stackEnchantedTrigger(battle, stack);
|
||||
@ -223,14 +224,14 @@ void BattleFlowProcessor::onTacticsEnded(const BattleInfo & battle)
|
||||
activateNextStack(battle);
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::startNextRound(const BattleInfo & battle, bool isFirstRound)
|
||||
void BattleFlowProcessor::startNextRound(const CBattleInfoCallback & battle, bool isFirstRound)
|
||||
{
|
||||
BattleNextRound bnr;
|
||||
bnr.round = battle.round + 1;
|
||||
logGlobal->debug("Round %d", bnr.round);
|
||||
logGlobal->debug("Next round starts");
|
||||
gameHandler->sendAndApply(&bnr);
|
||||
|
||||
auto obstacles = battle.obstacles; //we copy container, because we're going to modify it
|
||||
// operate on copy - removing obstacles will invalidate iterator on 'battle' container
|
||||
auto obstacles = battle.battleGetAllObstacles();
|
||||
for (auto &obstPtr : obstacles)
|
||||
{
|
||||
if (const SpellCreatedObstacle *sco = dynamic_cast<const SpellCreatedObstacle *>(obstPtr.get()))
|
||||
@ -238,16 +239,14 @@ void BattleFlowProcessor::startNextRound(const BattleInfo & battle, bool isFirst
|
||||
removeObstacle(battle, *obstPtr);
|
||||
}
|
||||
|
||||
const BattleInfo & curB = *&battle;
|
||||
|
||||
for(auto stack : curB.stacks)
|
||||
for(auto stack : battle.battleGetAllStacks(true))
|
||||
{
|
||||
if(stack->alive() && !isFirstRound)
|
||||
stackEnchantedTrigger(battle, stack);
|
||||
}
|
||||
}
|
||||
|
||||
const CStack * BattleFlowProcessor::getNextStack(const BattleInfo & battle)
|
||||
const CStack * BattleFlowProcessor::getNextStack(const CBattleInfoCallback & battle)
|
||||
{
|
||||
std::vector<battle::Units> q;
|
||||
battle.battleGetTurnOrder(q, 1, 0, -1); //todo: get rid of "turn -1"
|
||||
@ -283,7 +282,7 @@ const CStack * BattleFlowProcessor::getNextStack(const BattleInfo & battle)
|
||||
return stack;
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::activateNextStack(const BattleInfo & battle)
|
||||
void BattleFlowProcessor::activateNextStack(const CBattleInfoCallback & battle)
|
||||
{
|
||||
// Find next stack that requires manual control
|
||||
for (;;)
|
||||
@ -305,16 +304,17 @@ void BattleFlowProcessor::activateNextStack(const BattleInfo & battle)
|
||||
|
||||
BattleUnitsChanged removeGhosts;
|
||||
|
||||
for(auto stack : battle.stacks)
|
||||
{
|
||||
if(stack->ghostPending)
|
||||
removeGhosts.changedStacks.emplace_back(stack->unitId(), UnitChanges::EOperation::REMOVE);
|
||||
}
|
||||
auto pendingGhosts = battle.battleGetStacksIf([](const CStack * stack){
|
||||
return stack->ghostPending;
|
||||
});
|
||||
|
||||
for(auto stack : pendingGhosts)
|
||||
removeGhosts.changedStacks.emplace_back(stack->unitId(), UnitChanges::EOperation::REMOVE);
|
||||
|
||||
if(!removeGhosts.changedStacks.empty())
|
||||
gameHandler->sendAndApply(&removeGhosts);
|
||||
|
||||
gameHandler->turnTimerHandler.onBattleNextStack(battle.battleID, *next);
|
||||
gameHandler->turnTimerHandler.onBattleNextStack(battle.getBattle()->getBattleID(), *next);
|
||||
|
||||
if (!tryMakeAutomaticAction(battle, next))
|
||||
{
|
||||
@ -324,7 +324,7 @@ void BattleFlowProcessor::activateNextStack(const BattleInfo & battle)
|
||||
}
|
||||
}
|
||||
|
||||
bool BattleFlowProcessor::tryMakeAutomaticAction(const BattleInfo & battle, const CStack * next)
|
||||
bool BattleFlowProcessor::tryMakeAutomaticAction(const CBattleInfoCallback & battle, const CStack * next)
|
||||
{
|
||||
// check for bad morale => freeze
|
||||
int nextStackMorale = next->moraleVal();
|
||||
@ -370,7 +370,7 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const BattleInfo & battle, cons
|
||||
return true;
|
||||
}
|
||||
|
||||
const CGHeroInstance * curOwner = gameHandler->battleGetOwnerHero(next);
|
||||
const CGHeroInstance * curOwner = battle.battleGetOwnerHero(next);
|
||||
const int stackCreatureId = next->unitType()->getId();
|
||||
|
||||
if ((stackCreatureId == CreatureID::ARROW_TOWERS || stackCreatureId == CreatureID::BALLISTA)
|
||||
@ -385,7 +385,7 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const BattleInfo & battle, cons
|
||||
|
||||
const battle::Unit * target = nullptr;
|
||||
|
||||
for(auto & elem : battle.stacks)
|
||||
for(auto & elem : battle.battleGetAllStacks(true))
|
||||
{
|
||||
if(elem->unitType()->getId() != CreatureID::CATAPULT
|
||||
&& elem->unitOwner() != next->unitOwner()
|
||||
@ -433,7 +433,7 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const BattleInfo & battle, cons
|
||||
|
||||
if (next->unitType()->getId() == CreatureID::FIRST_AID_TENT)
|
||||
{
|
||||
TStacks possibleStacks = gameHandler->battleGetStacksIf([=](const CStack * s)
|
||||
TStacks possibleStacks = battle.battleGetStacksIf([=](const CStack * s)
|
||||
{
|
||||
return s->unitOwner() == next->unitOwner() && s->canBeHealed();
|
||||
});
|
||||
@ -470,7 +470,7 @@ bool BattleFlowProcessor::tryMakeAutomaticAction(const BattleInfo & battle, cons
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BattleFlowProcessor::rollGoodMorale(const BattleInfo & battle, const CStack * next)
|
||||
bool BattleFlowProcessor::rollGoodMorale(const CBattleInfoCallback & battle, const CStack * next)
|
||||
{
|
||||
//check for good morale
|
||||
auto nextStackMorale = next->moraleVal();
|
||||
@ -498,10 +498,10 @@ bool BattleFlowProcessor::rollGoodMorale(const BattleInfo & battle, const CStack
|
||||
return false;
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::onActionMade(const BattleInfo & battle, const BattleAction &ba)
|
||||
void BattleFlowProcessor::onActionMade(const CBattleInfoCallback & battle, const BattleAction &ba)
|
||||
{
|
||||
const CStack * actedStack = battle.battleGetStackByID(ba.stackNumber, false);
|
||||
const CStack * activeStack = battle.battleGetStackByID(battle.getActiveStackID(), false);
|
||||
const auto * actedStack = battle.battleGetStackByID(ba.stackNumber, false);
|
||||
const auto * activeStack = battle.battleActiveUnit();
|
||||
if (ba.actionType == EActionType::END_TACTIC_PHASE)
|
||||
{
|
||||
onTacticsEnded(battle);
|
||||
@ -516,7 +516,7 @@ void BattleFlowProcessor::onActionMade(const BattleInfo & battle, const BattleAc
|
||||
return;
|
||||
|
||||
// tactics - next stack will be selected by player
|
||||
if(battle.tacticDistance != 0)
|
||||
if(battle.battleGetTacticDist() != 0)
|
||||
return;
|
||||
|
||||
if (ba.isUnitAction())
|
||||
@ -545,7 +545,7 @@ void BattleFlowProcessor::onActionMade(const BattleInfo & battle, const BattleAc
|
||||
activateNextStack(battle);
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::makeStackDoNothing(const BattleInfo & battle, const CStack * next)
|
||||
void BattleFlowProcessor::makeStackDoNothing(const CBattleInfoCallback & battle, const CStack * next)
|
||||
{
|
||||
BattleAction doNothing;
|
||||
doNothing.actionType = EActionType::NO_ACTION;
|
||||
@ -555,7 +555,7 @@ void BattleFlowProcessor::makeStackDoNothing(const BattleInfo & battle, const CS
|
||||
makeAutomaticAction(battle, next, doNothing);
|
||||
}
|
||||
|
||||
bool BattleFlowProcessor::makeAutomaticAction(const BattleInfo & battle, const CStack *stack, BattleAction &ba)
|
||||
bool BattleFlowProcessor::makeAutomaticAction(const CBattleInfoCallback & battle, const CStack *stack, BattleAction &ba)
|
||||
{
|
||||
BattleSetActiveStack bsa;
|
||||
bsa.stack = stack->unitId();
|
||||
@ -566,7 +566,7 @@ bool BattleFlowProcessor::makeAutomaticAction(const BattleInfo & battle, const C
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::stackEnchantedTrigger(const BattleInfo & battle, const CStack * st)
|
||||
void BattleFlowProcessor::stackEnchantedTrigger(const CBattleInfoCallback & battle, const CStack * st)
|
||||
{
|
||||
auto bl = *(st->getBonuses(Selector::type()(BonusType::ENCHANTED)));
|
||||
for(auto b : bl)
|
||||
@ -587,7 +587,7 @@ void BattleFlowProcessor::stackEnchantedTrigger(const BattleInfo & battle, const
|
||||
if(val > 3)
|
||||
{
|
||||
for(auto s : battle.battleGetAllStacks())
|
||||
if(gameHandler->battleMatchOwner(st, s, true) && s->isValidTarget()) //all allied
|
||||
if(battle.battleMatchOwner(st, s, true) && s->isValidTarget()) //all allied
|
||||
target.emplace_back(s);
|
||||
}
|
||||
else
|
||||
@ -598,14 +598,14 @@ void BattleFlowProcessor::stackEnchantedTrigger(const BattleInfo & battle, const
|
||||
}
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::removeObstacle(const BattleInfo & battle, const CObstacleInstance & obstacle)
|
||||
void BattleFlowProcessor::removeObstacle(const CBattleInfoCallback & battle, const CObstacleInstance & obstacle)
|
||||
{
|
||||
BattleObstaclesChanged obsRem;
|
||||
obsRem.changes.emplace_back(obstacle.uniqueID, ObstacleChanges::EOperation::REMOVE);
|
||||
gameHandler->sendAndApply(&obsRem);
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::stackTurnTrigger(const BattleInfo & battle, const CStack *st)
|
||||
void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, const CStack *st)
|
||||
{
|
||||
BattleTriggerEffect bte;
|
||||
bte.stackID = st->unitId();
|
||||
@ -662,7 +662,7 @@ void BattleFlowProcessor::stackTurnTrigger(const BattleInfo & battle, const CSta
|
||||
if(st->hasBonusOfType(BonusType::MANA_DRAIN) && !st->drainedMana)
|
||||
{
|
||||
const PlayerColor opponent = battle.otherPlayer(battle.battleGetOwner(st));
|
||||
const CGHeroInstance * opponentHero = battle.getHero(opponent);
|
||||
const CGHeroInstance * opponentHero = battle.battleGetFightingHero(opponent);
|
||||
if(opponentHero)
|
||||
{
|
||||
ui32 manaDrained = st->valOfBonuses(BonusType::MANA_DRAIN);
|
||||
@ -679,9 +679,9 @@ void BattleFlowProcessor::stackTurnTrigger(const BattleInfo & battle, const CSta
|
||||
if (st->isLiving() && !st->hasBonusOfType(BonusType::FEARLESS))
|
||||
{
|
||||
bool fearsomeCreature = false;
|
||||
for (CStack * stack : battle.stacks)
|
||||
for (const CStack * stack : battle.battleGetAllStacks(true))
|
||||
{
|
||||
if (gameHandler->battleMatchOwner(st, stack) && stack->alive() && stack->hasBonusOfType(BonusType::FEAR))
|
||||
if (battle.battleMatchOwner(st, stack) && stack->alive() && stack->hasBonusOfType(BonusType::FEAR))
|
||||
{
|
||||
fearsomeCreature = true;
|
||||
break;
|
||||
@ -697,7 +697,7 @@ void BattleFlowProcessor::stackTurnTrigger(const BattleInfo & battle, const CSta
|
||||
}
|
||||
}
|
||||
BonusList bl = *(st->getBonuses(Selector::type()(BonusType::ENCHANTER)));
|
||||
int side = battle.whatSide(st->unitOwner());
|
||||
int side = *battle.playerToSide(st->unitOwner());
|
||||
if(st->canCast() && battle.battleGetEnchanterCounter(side) == 0)
|
||||
{
|
||||
bool cast = false;
|
||||
@ -732,11 +732,10 @@ void BattleFlowProcessor::stackTurnTrigger(const BattleInfo & battle, const CSta
|
||||
}
|
||||
}
|
||||
|
||||
void BattleFlowProcessor::setActiveStack(const BattleInfo & battle, const CStack * stack)
|
||||
void BattleFlowProcessor::setActiveStack(const CBattleInfoCallback & battle, const battle::Unit * stack)
|
||||
{
|
||||
assert(stack);
|
||||
|
||||
logGlobal->trace("Activating %s", stack->nodeName());
|
||||
BattleSetActiveStack sas;
|
||||
sas.stack = stack->unitId();
|
||||
gameHandler->sendAndApply(&sas);
|
||||
|
@ -13,8 +13,12 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CStack;
|
||||
struct BattleHex;
|
||||
class BattleAction;
|
||||
class BattleInfo;
|
||||
class CBattleInfoCallback;
|
||||
struct CObstacleInstance;
|
||||
namespace battle
|
||||
{
|
||||
class Unit;
|
||||
}
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class CGameHandler;
|
||||
@ -26,31 +30,31 @@ class BattleFlowProcessor : boost::noncopyable
|
||||
BattleProcessor * owner;
|
||||
CGameHandler * gameHandler;
|
||||
|
||||
const CStack * getNextStack(const BattleInfo & battle);
|
||||
const CStack * getNextStack(const CBattleInfoCallback & battle);
|
||||
|
||||
bool rollGoodMorale(const BattleInfo & battle, const CStack * stack);
|
||||
bool tryMakeAutomaticAction(const BattleInfo & battle, const CStack * stack);
|
||||
bool rollGoodMorale(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
bool tryMakeAutomaticAction(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
|
||||
void summonGuardiansHelper(const BattleInfo & battle, std::vector<BattleHex> & output, const BattleHex & targetPosition, ui8 side, bool targetIsTwoHex);
|
||||
void trySummonGuardians(const BattleInfo & battle, const CStack * stack);
|
||||
void tryPlaceMoats(const BattleInfo & battle);
|
||||
void castOpeningSpells(const BattleInfo & battle);
|
||||
void activateNextStack(const BattleInfo & battle);
|
||||
void startNextRound(const BattleInfo & battle, bool isFirstRound);
|
||||
void summonGuardiansHelper(const CBattleInfoCallback & battle, std::vector<BattleHex> & output, const BattleHex & targetPosition, ui8 side, bool targetIsTwoHex);
|
||||
void trySummonGuardians(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void tryPlaceMoats(const CBattleInfoCallback & battle);
|
||||
void castOpeningSpells(const CBattleInfoCallback & battle);
|
||||
void activateNextStack(const CBattleInfoCallback & battle);
|
||||
void startNextRound(const CBattleInfoCallback & battle, bool isFirstRound);
|
||||
|
||||
void stackEnchantedTrigger(const BattleInfo & battle, const CStack * stack);
|
||||
void removeObstacle(const BattleInfo & battle, const CObstacleInstance & obstacle);
|
||||
void stackTurnTrigger(const BattleInfo & battle, const CStack * stack);
|
||||
void setActiveStack(const BattleInfo & battle, const CStack * stack);
|
||||
void stackEnchantedTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void removeObstacle(const CBattleInfoCallback & battle, const CObstacleInstance & obstacle);
|
||||
void stackTurnTrigger(const CBattleInfoCallback & battle, const CStack * stack);
|
||||
void setActiveStack(const CBattleInfoCallback & battle, const battle::Unit * stack);
|
||||
|
||||
void makeStackDoNothing(const BattleInfo & battle, const CStack * next);
|
||||
bool makeAutomaticAction(const BattleInfo & battle, const CStack * stack, BattleAction & ba); //used when action is taken by stack without volition of player (eg. unguided catapult attack)
|
||||
void makeStackDoNothing(const CBattleInfoCallback & battle, const CStack * next);
|
||||
bool makeAutomaticAction(const CBattleInfoCallback & battle, const CStack * stack, BattleAction & ba); //used when action is taken by stack without volition of player (eg. unguided catapult attack)
|
||||
|
||||
public:
|
||||
explicit BattleFlowProcessor(BattleProcessor * owner);
|
||||
void setGameHandler(CGameHandler * newGameHandler);
|
||||
|
||||
void onBattleStarted(const BattleInfo & battle);
|
||||
void onTacticsEnded(const BattleInfo & battle);
|
||||
void onActionMade(const BattleInfo & battle, const BattleAction & ba);
|
||||
void onBattleStarted(const CBattleInfoCallback & battle);
|
||||
void onTacticsEnded(const CBattleInfoCallback & battle);
|
||||
void onActionMade(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
};
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "../queries/BattleQueries.h"
|
||||
|
||||
#include "../../lib/TerrainHandler.h"
|
||||
#include "../../lib/battle/CBattleInfoCallback.h"
|
||||
#include "../../lib/battle/BattleInfo.h"
|
||||
#include "../../lib/gameState/CGameState.h"
|
||||
#include "../../lib/mapping/CMap.h"
|
||||
@ -147,17 +148,17 @@ BattleID BattleProcessor::setupBattle(int3 tile, const CArmedInstance *armies[2]
|
||||
return bs.battleID;
|
||||
}
|
||||
|
||||
bool BattleProcessor::checkBattleStateChanges(const BattleInfo & battle)
|
||||
bool BattleProcessor::checkBattleStateChanges(const CBattleInfoCallback & battle)
|
||||
{
|
||||
//check if drawbridge state need to be changes
|
||||
if (gameHandler->battleGetSiegeLevel() > 0)
|
||||
if (battle.battleGetSiegeLevel() > 0)
|
||||
updateGateState(battle);
|
||||
|
||||
if (resultProcessor->battleIsEnding(battle))
|
||||
return true;
|
||||
|
||||
//check if battle ended
|
||||
if (auto result = gameHandler->battleIsFinished())
|
||||
if (auto result = battle.battleIsFinished())
|
||||
{
|
||||
setBattleResult(battle, EBattleResult::NORMAL, *result);
|
||||
return true;
|
||||
@ -166,7 +167,7 @@ bool BattleProcessor::checkBattleStateChanges(const BattleInfo & battle)
|
||||
return false;
|
||||
}
|
||||
|
||||
void BattleProcessor::updateGateState(const BattleInfo & battle)
|
||||
void BattleProcessor::updateGateState(const CBattleInfoCallback & battle)
|
||||
{
|
||||
// GATE_BRIDGE - leftmost tile, located over moat
|
||||
// GATE_OUTER - central tile, mostly covered by gate image
|
||||
@ -182,20 +183,20 @@ void BattleProcessor::updateGateState(const BattleInfo & battle)
|
||||
// - if Force Field is cast here, bridge can't open (but can close, in any town)
|
||||
// - deals moat damage to attacker if bridge is closed (fortress only)
|
||||
|
||||
bool hasForceFieldOnBridge = !gameHandler->battleGetAllObstaclesOnPos(BattleHex(BattleHex::GATE_BRIDGE), true).empty();
|
||||
bool hasForceFieldOnBridge = !battle.battleGetAllObstaclesOnPos(BattleHex(BattleHex::GATE_BRIDGE), true).empty();
|
||||
bool hasStackAtGateInner = battle.battleGetUnitByPos(BattleHex(BattleHex::GATE_INNER), false) != nullptr;
|
||||
bool hasStackAtGateOuter = battle.battleGetUnitByPos(BattleHex(BattleHex::GATE_OUTER), false) != nullptr;
|
||||
bool hasStackAtGateBridge = battle.battleGetUnitByPos(BattleHex(BattleHex::GATE_BRIDGE), false) != nullptr;
|
||||
bool hasWideMoat = vstd::contains_if(gameHandler->battleGetAllObstaclesOnPos(BattleHex(BattleHex::GATE_BRIDGE), false), [](const std::shared_ptr<const CObstacleInstance> & obst)
|
||||
bool hasWideMoat = vstd::contains_if(battle.battleGetAllObstaclesOnPos(BattleHex(BattleHex::GATE_BRIDGE), false), [](const std::shared_ptr<const CObstacleInstance> & obst)
|
||||
{
|
||||
return obst->obstacleType == CObstacleInstance::MOAT;
|
||||
});
|
||||
|
||||
BattleUpdateGateState db;
|
||||
db.state = battle.si.gateState;
|
||||
db.battleID = battle.battleID;
|
||||
db.state = battle.battleGetGateState();
|
||||
db.battleID = battle.getBattle()->getBattleID();
|
||||
|
||||
if (battle.si.wallState.at(EWallPart::GATE) == EWallState::DESTROYED)
|
||||
if (battle.battleGetWallState(EWallPart::GATE) == EWallState::DESTROYED)
|
||||
{
|
||||
db.state = EGateState::DESTROYED;
|
||||
}
|
||||
@ -219,7 +220,7 @@ void BattleProcessor::updateGateState(const BattleInfo & battle)
|
||||
db.state = EGateState::CLOSED;
|
||||
}
|
||||
|
||||
if (db.state != battle.si.gateState)
|
||||
if (db.state != battle.battleGetGateState())
|
||||
gameHandler->sendAndApply(&db);
|
||||
}
|
||||
|
||||
@ -236,13 +237,13 @@ bool BattleProcessor::makePlayerBattleAction(const BattleID & battleID, PlayerCo
|
||||
return result;
|
||||
}
|
||||
|
||||
void BattleProcessor::setBattleResult(const BattleInfo & battle, EBattleResult resultType, int victoriusSide)
|
||||
void BattleProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide)
|
||||
{
|
||||
resultProcessor->setBattleResult(battle, resultType, victoriusSide);
|
||||
resultProcessor->endBattle(battle);
|
||||
}
|
||||
|
||||
bool BattleProcessor::makeAutomaticBattleAction(const BattleInfo & battle, const BattleAction &ba)
|
||||
bool BattleProcessor::makeAutomaticBattleAction(const CBattleInfoCallback & battle, const BattleAction &ba)
|
||||
{
|
||||
return actionsProcessor->makeAutomaticBattleAction(battle, ba);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ class CGTownInstance;
|
||||
class CArmedInstance;
|
||||
class BattleAction;
|
||||
class int3;
|
||||
class BattleInfo;
|
||||
class CBattleInfoCallback;
|
||||
struct BattleResult;
|
||||
class BattleID;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
@ -40,16 +40,15 @@ class BattleProcessor : boost::noncopyable
|
||||
std::unique_ptr<BattleFlowProcessor> flowProcessor;
|
||||
std::unique_ptr<BattleResultProcessor> resultProcessor;
|
||||
|
||||
void onTacticsEnded();
|
||||
void updateGateState(const BattleInfo & battle);
|
||||
void updateGateState(const CBattleInfoCallback & battle);
|
||||
void engageIntoBattle(PlayerColor player);
|
||||
|
||||
bool checkBattleStateChanges(const BattleInfo & battle);
|
||||
bool checkBattleStateChanges(const CBattleInfoCallback & battle);
|
||||
BattleID setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance *heroes[2], bool creatureBank, const CGTownInstance *town);
|
||||
|
||||
bool makeAutomaticBattleAction(const BattleInfo & battle, const BattleAction & ba);
|
||||
bool makeAutomaticBattleAction(const CBattleInfoCallback & battle, const BattleAction & ba);
|
||||
|
||||
void setBattleResult(const BattleInfo & battle, EBattleResult resultType, int victoriusSide);
|
||||
void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide);
|
||||
|
||||
public:
|
||||
explicit BattleProcessor(CGameHandler * gameHandler);
|
||||
|
@ -18,7 +18,9 @@
|
||||
#include "../../lib/ArtifactUtils.h"
|
||||
#include "../../lib/CStack.h"
|
||||
#include "../../lib/GameSettings.h"
|
||||
#include "../../lib/battle/BattleInfo.h"
|
||||
#include "../../lib/battle/CBattleInfoCallback.h"
|
||||
#include "../../lib/battle/IBattleState.h"
|
||||
#include "../../lib/battle/SideInBattle.h"
|
||||
#include "../../lib/gameState/CGameState.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/serializer/Cast.h"
|
||||
@ -35,15 +37,19 @@ void BattleResultProcessor::setGameHandler(CGameHandler * newGameHandler)
|
||||
gameHandler = newGameHandler;
|
||||
}
|
||||
|
||||
CasualtiesAfterBattle::CasualtiesAfterBattle(const SideInBattle & battleSide, const BattleInfo * bat):
|
||||
army(battleSide.armyObject)
|
||||
CasualtiesAfterBattle::CasualtiesAfterBattle(const CBattleInfoCallback & battle, uint8_t sideInBattle):
|
||||
army(battle.battleGetArmyObject(sideInBattle))
|
||||
{
|
||||
heroWithDeadCommander = ObjectInstanceID();
|
||||
|
||||
PlayerColor color = battleSide.color;
|
||||
PlayerColor color = battle.sideToPlayer(sideInBattle);
|
||||
|
||||
for(CStack * st : bat->stacks)
|
||||
for(const CStack * stConst : battle.battleGetAllStacks(true))
|
||||
{
|
||||
// Use const cast - in order to call non-const "takeResurrected" for proper calculation of casualties
|
||||
// TODO: better solution
|
||||
CStack * st = const_cast<CStack*>(stConst);
|
||||
|
||||
if(st->summoned) //don't take into account temporary summoned stacks
|
||||
continue;
|
||||
if(st->unitOwner() != color) //remove only our stacks
|
||||
@ -181,11 +187,23 @@ FinishingBattleHelper::FinishingBattleHelper(std::shared_ptr<const CBattleQuery>
|
||||
auto &result = *Query->result;
|
||||
auto &info = *Query->bi;
|
||||
|
||||
winnerHero = result.winner != 0 ? info.sides[1].hero : info.sides[0].hero;
|
||||
loserHero = result.winner != 0 ? info.sides[0].hero : info.sides[1].hero;
|
||||
victor = info.sides[result.winner].color;
|
||||
loser = info.sides[!result.winner].color;
|
||||
if (result.winner == BattleSide::ATTACKER)
|
||||
{
|
||||
winnerHero = info.getSideHero(BattleSide::ATTACKER);
|
||||
loserHero = info.getSideHero(BattleSide::DEFENDER);
|
||||
victor = info.getSidePlayer(BattleSide::ATTACKER);
|
||||
loser = info.getSidePlayer(BattleSide::DEFENDER);
|
||||
}
|
||||
else
|
||||
{
|
||||
winnerHero = info.getSideHero(BattleSide::DEFENDER);
|
||||
loserHero = info.getSideHero(BattleSide::ATTACKER);
|
||||
victor = info.getSidePlayer(BattleSide::DEFENDER);
|
||||
loser = info.getSidePlayer(BattleSide::ATTACKER);
|
||||
}
|
||||
|
||||
winnerSide = result.winner;
|
||||
|
||||
this->remainingBattleQueriesCount = remainingBattleQueriesCount;
|
||||
}
|
||||
|
||||
@ -196,7 +214,7 @@ FinishingBattleHelper::FinishingBattleHelper()
|
||||
remainingBattleQueriesCount = 0;
|
||||
}
|
||||
|
||||
void BattleResultProcessor::endBattle(const BattleInfo & battle)
|
||||
void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle)
|
||||
{
|
||||
auto const & giveExp = [](BattleResult &r)
|
||||
{
|
||||
@ -215,9 +233,9 @@ void BattleResultProcessor::endBattle(const BattleInfo & battle)
|
||||
|
||||
LOG_TRACE(logGlobal);
|
||||
|
||||
auto * battleResult = battleResults.at(battle.battleID).get();
|
||||
const auto * heroAttacker = battle.getSideHero(BattleSide::ATTACKER);
|
||||
const auto * heroDefender = battle.getSideHero(BattleSide::DEFENDER);
|
||||
auto * battleResult = battleResults.at(battle.getBattle()->getBattleID()).get();
|
||||
const auto * heroAttacker = battle.battleGetFightingHero(BattleSide::ATTACKER);
|
||||
const auto * heroDefender = battle.battleGetFightingHero(BattleSide::DEFENDER);
|
||||
|
||||
//Fill BattleResult structure with exp info
|
||||
giveExp(*battleResult);
|
||||
@ -235,11 +253,11 @@ void BattleResultProcessor::endBattle(const BattleInfo & battle)
|
||||
if(heroDefender)
|
||||
battleResult->exp[1] = heroDefender->calculateXp(battleResult->exp[1]);
|
||||
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sides[0].color));
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(0)));
|
||||
if (!battleQuery)
|
||||
{
|
||||
logGlobal->error("Cannot find battle query!");
|
||||
gameHandler->complain("Player " + boost::lexical_cast<std::string>(battle.sides[0].color) + " has no battle query at the top!");
|
||||
gameHandler->complain("Player " + boost::lexical_cast<std::string>(battle.sideToPlayer(0)) + " has no battle query at the top!");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -248,13 +266,13 @@ void BattleResultProcessor::endBattle(const BattleInfo & battle)
|
||||
//Check how many battle gameHandler->queries were created (number of players blocked by battle)
|
||||
const int queriedPlayers = battleQuery ? (int)boost::count(gameHandler->queries->allQueries(), battleQuery) : 0;
|
||||
|
||||
assert(finishingBattles.count(battle.battleID) == 0);
|
||||
finishingBattles[battle.battleID] = std::make_unique<FinishingBattleHelper>(battleQuery, queriedPlayers);
|
||||
assert(finishingBattles.count(battle.getBattle()->getBattleID()) == 0);
|
||||
finishingBattles[battle.getBattle()->getBattleID()] = std::make_unique<FinishingBattleHelper>(battleQuery, queriedPlayers);
|
||||
|
||||
// in battles against neutrals, 1st player can ask to replay battle manually
|
||||
if (!battle.sides[1].color.isValidPlayer())
|
||||
if (!battle.sideToPlayer(1).isValidPlayer())
|
||||
{
|
||||
auto battleDialogQuery = std::make_shared<CBattleDialogQuery>(gameHandler, &battle);
|
||||
auto battleDialogQuery = std::make_shared<CBattleDialogQuery>(gameHandler, battle.getBattle());
|
||||
battleResult->queryID = battleDialogQuery->queryID;
|
||||
gameHandler->queries->addQuery(battleDialogQuery);
|
||||
}
|
||||
@ -275,21 +293,24 @@ void BattleResultProcessor::endBattle(const BattleInfo & battle)
|
||||
endBattleConfirm(battle);
|
||||
}
|
||||
|
||||
void BattleResultProcessor::endBattleConfirm(const BattleInfo & battle)
|
||||
void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
|
||||
{
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sides.at(0).color));
|
||||
auto battleQuery = std::dynamic_pointer_cast<CBattleQuery>(gameHandler->queries->topQuery(battle.sideToPlayer(0)));
|
||||
if(!battleQuery)
|
||||
{
|
||||
logGlobal->trace("No battle query, battle end was confirmed by another player");
|
||||
return;
|
||||
}
|
||||
|
||||
auto * battleResult = battleResults.at(battle.battleID).get();
|
||||
auto * finishingBattle = finishingBattles.at(battle.battleID).get();
|
||||
auto * battleResult = battleResults.at(battle.getBattle()->getBattleID()).get();
|
||||
auto * finishingBattle = finishingBattles.at(battle.getBattle()->getBattleID()).get();
|
||||
|
||||
const EBattleResult result = battleResult->result;
|
||||
|
||||
CasualtiesAfterBattle cab1(battle.sides.at(0), &battle), cab2(battle.sides.at(1), &battle); //calculate casualties before deleting battle
|
||||
//calculate casualties before deleting battle
|
||||
CasualtiesAfterBattle cab1(battle, BattleSide::ATTACKER);
|
||||
CasualtiesAfterBattle cab2(battle, BattleSide::DEFENDER);
|
||||
|
||||
ChangeSpells cs; //for Eagle Eye
|
||||
|
||||
if(!finishingBattle->isDraw() && finishingBattle->winnerHero)
|
||||
@ -297,7 +318,7 @@ void BattleResultProcessor::endBattleConfirm(const BattleInfo & battle)
|
||||
if (int eagleEyeLevel = finishingBattle->winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_LEVEL_LIMIT, -1))
|
||||
{
|
||||
double eagleEyeChance = finishingBattle->winnerHero->valOfBonuses(BonusType::LEARN_BATTLE_SPELL_CHANCE, 0);
|
||||
for(auto & spellId : battle.sides.at(!battleResult->winner).usedSpellsHistory)
|
||||
for(auto & spellId : battle.getBattle()->getUsedSpells(battle.otherSide(battleResult->winner)))
|
||||
{
|
||||
auto spell = spellId.toSpell(VLC->spells());
|
||||
if(spell && spell->getLevel() <= eagleEyeLevel && !finishingBattle->winnerHero->spellbookContainsSpell(spell->getId()) && gameHandler->getRandomGenerator().nextInt(99) < eagleEyeChance)
|
||||
@ -365,7 +386,10 @@ void BattleResultProcessor::endBattleConfirm(const BattleInfo & battle)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto armySlot : battle.sides.at(!battleResult->winner).armyObject->stacks)
|
||||
|
||||
auto loser = battle.otherSide(battleResult->winner);
|
||||
|
||||
for (auto armySlot : battle.battleGetArmyObject(loser)->stacks)
|
||||
{
|
||||
auto artifactsWorn = armySlot.second->artifactsWorn;
|
||||
for (auto artSlot : artifactsWorn)
|
||||
@ -466,10 +490,10 @@ void BattleResultProcessor::endBattleConfirm(const BattleInfo & battle)
|
||||
gameHandler->changePrimSkill(finishingBattle->winnerHero, PrimarySkill::EXPERIENCE, battleResult->exp[finishingBattle->winnerSide]);
|
||||
|
||||
BattleResultAccepted raccepted;
|
||||
raccepted.heroResult[0].army = const_cast<CArmedInstance*>(battle.sides.at(0).armyObject);
|
||||
raccepted.heroResult[1].army = const_cast<CArmedInstance*>(battle.sides.at(1).armyObject);
|
||||
raccepted.heroResult[0].hero = const_cast<CGHeroInstance*>(battle.sides.at(0).hero);
|
||||
raccepted.heroResult[1].hero = const_cast<CGHeroInstance*>(battle.sides.at(1).hero);
|
||||
raccepted.heroResult[0].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(0));
|
||||
raccepted.heroResult[1].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(1));
|
||||
raccepted.heroResult[0].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(0));
|
||||
raccepted.heroResult[1].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(1));
|
||||
raccepted.heroResult[0].exp = battleResult->exp[0];
|
||||
raccepted.heroResult[1].exp = battleResult->exp[1];
|
||||
raccepted.winnerSide = finishingBattle->winnerSide;
|
||||
@ -479,15 +503,15 @@ void BattleResultProcessor::endBattleConfirm(const BattleInfo & battle)
|
||||
//--> continuation (battleAfterLevelUp) occurs after level-up gameHandler->queries are handled or on removing query
|
||||
}
|
||||
|
||||
void BattleResultProcessor::battleAfterLevelUp(const BattleInfo & battle, const BattleResult & result)
|
||||
void BattleResultProcessor::battleAfterLevelUp(const CBattleInfoCallback & battle, const BattleResult & result)
|
||||
{
|
||||
LOG_TRACE(logGlobal);
|
||||
|
||||
assert(finishingBattles.count(battle.battleID) != 0);
|
||||
if(finishingBattles.count(battle.battleID) == 0)
|
||||
assert(finishingBattles.count(battle.getBattle()->getBattleID()) != 0);
|
||||
if(finishingBattles.count(battle.getBattle()->getBattleID()) == 0)
|
||||
return;
|
||||
|
||||
auto & finishingBattle = finishingBattles[battle.battleID];
|
||||
auto & finishingBattle = finishingBattles[battle.getBattle()->getBattleID()];
|
||||
|
||||
finishingBattle->remainingBattleQueriesCount--;
|
||||
logGlobal->trace("Decremented gameHandler->queries count to %d", finishingBattle->remainingBattleQueriesCount);
|
||||
@ -517,8 +541,6 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleInfo & battle, const
|
||||
resultsApplied.player2 = finishingBattle->loser;
|
||||
gameHandler->sendAndApply(&resultsApplied);
|
||||
|
||||
gameHandler->setBattle(nullptr);
|
||||
|
||||
//handle victory/loss of engaged players
|
||||
std::set<PlayerColor> playerColors = {finishingBattle->loser, finishingBattle->victor};
|
||||
gameHandler->checkVictoryLossConditions(playerColors);
|
||||
@ -539,23 +561,29 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleInfo & battle, const
|
||||
gameHandler->heroPool->onHeroEscaped(finishingBattle->victor, finishingBattle->winnerHero);
|
||||
}
|
||||
|
||||
finishingBattles.erase(battle.battleID);
|
||||
battleResults.erase(battle.battleID);
|
||||
finishingBattles.erase(battle.getBattle()->getBattleID());
|
||||
battleResults.erase(battle.getBattle()->getBattleID());
|
||||
}
|
||||
|
||||
void BattleResultProcessor::setBattleResult(const BattleInfo & battle, EBattleResult resultType, int victoriusSide)
|
||||
void BattleResultProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide)
|
||||
{
|
||||
assert(battleResults.count(battle.battleID) == 0);
|
||||
assert(battleResults.count(battle.getBattle()->getBattleID()) == 0);
|
||||
|
||||
battleResults[battle.battleID] = std::make_unique<BattleResult>();
|
||||
battleResults[battle.getBattle()->getBattleID()] = std::make_unique<BattleResult>();
|
||||
|
||||
auto & battleResult = battleResults[battle.battleID];
|
||||
auto & battleResult = battleResults[battle.getBattle()->getBattleID()];
|
||||
battleResult->result = resultType;
|
||||
battleResult->winner = victoriusSide; //surrendering side loses
|
||||
battle.calculateCasualties(battleResult->casualties);
|
||||
|
||||
for(const auto & st : battle.battleGetAllStacks(true)) //setting casualties
|
||||
{
|
||||
si32 killed = st->getKilled();
|
||||
if(killed > 0)
|
||||
battleResult->casualties[st->unitSide()][st->creatureId()] += killed;
|
||||
}
|
||||
}
|
||||
|
||||
bool BattleResultProcessor::battleIsEnding(const BattleInfo & battle) const
|
||||
bool BattleResultProcessor::battleIsEnding(const CBattleInfoCallback & battle) const
|
||||
{
|
||||
return battleResults.count(battle.battleID) != 0;
|
||||
return battleResults.count(battle.getBattle()->getBattleID()) != 0;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ struct CasualtiesAfterBattle
|
||||
TSummoned summoned;
|
||||
ObjectInstanceID heroWithDeadCommander; //TODO: unify stack locations
|
||||
|
||||
CasualtiesAfterBattle(const SideInBattle & battleSide, const BattleInfo * bat);
|
||||
CasualtiesAfterBattle(const CBattleInfoCallback & battle, uint8_t sideInBattle);
|
||||
void updateArmy(CGameHandler * gh);
|
||||
};
|
||||
|
||||
@ -71,10 +71,10 @@ public:
|
||||
explicit BattleResultProcessor(BattleProcessor * owner);
|
||||
void setGameHandler(CGameHandler * newGameHandler);
|
||||
|
||||
bool battleIsEnding(const BattleInfo & battle) const;
|
||||
bool battleIsEnding(const CBattleInfoCallback & battle) const;
|
||||
|
||||
void setBattleResult(const BattleInfo & battle, EBattleResult resultType, int victoriusSide);
|
||||
void endBattle(const BattleInfo & battle); //ends battle
|
||||
void endBattleConfirm(const BattleInfo & battle);
|
||||
void battleAfterLevelUp(const BattleInfo & battle, const BattleResult & result);
|
||||
void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide);
|
||||
void endBattle(const CBattleInfoCallback & battle); //ends battle
|
||||
void endBattleConfirm(const CBattleInfoCallback & battle);
|
||||
void battleAfterLevelUp(const CBattleInfoCallback & battle, const BattleResult & result);
|
||||
};
|
||||
|
0
server/battles/ServerBattleCallback.cpp
Normal file
0
server/battles/ServerBattleCallback.cpp
Normal file
0
server/battles/ServerBattleCallback.h
Normal file
0
server/battles/ServerBattleCallback.h
Normal file
@ -14,7 +14,7 @@
|
||||
#include "../CGameHandler.h"
|
||||
#include "../battles/BattleProcessor.h"
|
||||
|
||||
#include "../../lib/battle/BattleInfo.h"
|
||||
#include "../../lib/battle/IBattleState.h"
|
||||
|
||||
void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
|
||||
{
|
||||
@ -22,16 +22,15 @@ void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisi
|
||||
objectVisit.visitedObject->battleFinished(objectVisit.visitingHero, *result);
|
||||
}
|
||||
|
||||
CBattleQuery::CBattleQuery(CGameHandler * owner, const BattleInfo * Bi):
|
||||
CGhQuery(owner)
|
||||
CBattleQuery::CBattleQuery(CGameHandler * owner, const IBattleInfo * bi):
|
||||
CGhQuery(owner),
|
||||
bi(bi)
|
||||
{
|
||||
belligerents[0] = Bi->sides[0].armyObject;
|
||||
belligerents[1] = Bi->sides[1].armyObject;
|
||||
belligerents[0] = bi->getSideArmy(0);
|
||||
belligerents[1] = bi->getSideArmy(1);
|
||||
|
||||
bi = Bi;
|
||||
|
||||
for(auto & side : bi->sides)
|
||||
addPlayer(side.color);
|
||||
addPlayer(bi->getSidePlayer(0));
|
||||
addPlayer(bi->getSidePlayer(1));
|
||||
}
|
||||
|
||||
CBattleQuery::CBattleQuery(CGameHandler * owner):
|
||||
@ -49,16 +48,15 @@ bool CBattleQuery::blocksPack(const CPack * pack) const
|
||||
void CBattleQuery::onRemoval(PlayerColor color)
|
||||
{
|
||||
if(result)
|
||||
gh->battles->battleAfterLevelUp(bi->battleID, *result);
|
||||
gh->battles->battleAfterLevelUp(bi->getBattleID(), *result);
|
||||
}
|
||||
|
||||
CBattleDialogQuery::CBattleDialogQuery(CGameHandler * owner, const BattleInfo * Bi):
|
||||
CDialogQuery(owner)
|
||||
CBattleDialogQuery::CBattleDialogQuery(CGameHandler * owner, const IBattleInfo * bi):
|
||||
CDialogQuery(owner),
|
||||
bi(bi)
|
||||
{
|
||||
bi = Bi;
|
||||
|
||||
for(auto & side : bi->sides)
|
||||
addPlayer(side.color);
|
||||
addPlayer(bi->getSidePlayer(0));
|
||||
addPlayer(bi->getSidePlayer(1));
|
||||
}
|
||||
|
||||
void CBattleDialogQuery::onRemoval(PlayerColor color)
|
||||
@ -66,10 +64,18 @@ void CBattleDialogQuery::onRemoval(PlayerColor color)
|
||||
assert(answer);
|
||||
if(*answer == 1)
|
||||
{
|
||||
gh->startBattlePrimary(bi->sides[0].armyObject, bi->sides[1].armyObject, bi->tile, bi->sides[0].hero, bi->sides[1].hero, bi->creatureBank, bi->town);
|
||||
gh->startBattlePrimary(
|
||||
bi->getSideArmy(0),
|
||||
bi->getSideArmy(1),
|
||||
bi->getLocation(),
|
||||
bi->getSideHero(0),
|
||||
bi->getSideHero(1),
|
||||
bi->isCreatureBank(),
|
||||
bi->getDefendedTown()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
gh->battles->endBattleConfirm(bi->battleID);
|
||||
gh->battles->endBattleConfirm(bi->getBattleID());
|
||||
}
|
||||
}
|
||||
|
@ -13,17 +13,21 @@
|
||||
|
||||
#include "../../lib/NetPacks.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class IBattleInfo;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class CBattleQuery : public CGhQuery
|
||||
{
|
||||
public:
|
||||
std::array<const CArmedInstance *,2> belligerents;
|
||||
std::array<int, 2> initialHeroMana;
|
||||
|
||||
const BattleInfo *bi;
|
||||
const IBattleInfo *bi;
|
||||
std::optional<BattleResult> result;
|
||||
|
||||
CBattleQuery(CGameHandler * owner);
|
||||
CBattleQuery(CGameHandler * owner, const BattleInfo * Bi); //TODO
|
||||
CBattleQuery(CGameHandler * owner, const IBattleInfo * Bi); //TODO
|
||||
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override;
|
||||
virtual bool blocksPack(const CPack *pack) const override;
|
||||
virtual void onRemoval(PlayerColor color) override;
|
||||
@ -32,9 +36,9 @@ public:
|
||||
class CBattleDialogQuery : public CDialogQuery
|
||||
{
|
||||
public:
|
||||
CBattleDialogQuery(CGameHandler * owner, const BattleInfo * Bi);
|
||||
CBattleDialogQuery(CGameHandler * owner, const IBattleInfo * Bi);
|
||||
|
||||
const BattleInfo * bi;
|
||||
const IBattleInfo * bi;
|
||||
|
||||
virtual void onRemoval(PlayerColor color) override;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user