1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

Battle Info uses ObjectInstanceID's instead of pointers

This commit is contained in:
Ivan Savenko
2025-03-30 18:32:07 +03:00
parent 9e6397d1f9
commit f03cc06176
8 changed files with 82 additions and 44 deletions

View File

@@ -388,7 +388,7 @@ void CClient::battleStarted(const BattleInfo * info)
auto callBattleStart = [&](PlayerColor color, BattleSide side)
{
if(vstd::contains(battleints, color))
battleints[color]->battleStart(info->battleID, leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side, info->replayAllowed);
battleints[color]->battleStart(info->battleID, leftSide.getArmy(), rightSide.getArmy(), info->tile, leftSide.getHero(), rightSide.getHero(), side, info->replayAllowed);
};
callBattleStart(leftSide.color, BattleSide::LEFT_SIDE);
@@ -433,14 +433,14 @@ void CClient::battleStarted(const BattleInfo * info)
{
if(att || def)
{
CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def);
CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.getArmy(), rightSide.getArmy(), leftSide.getHero(), rightSide.getHero(), att, def);
}
else if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool())
{
//TODO: This certainly need improvement
auto spectratorInt = std::dynamic_pointer_cast<CPlayerInterface>(playerint[PlayerColor::SPECTATOR]);
spectratorInt->cb->onBattleStarted(info);
CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def, spectratorInt);
CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.getArmy(), rightSide.getArmy(), leftSide.getHero(), rightSide.getHero(), att, def, spectratorInt);
}
}

View File

@@ -745,11 +745,11 @@ void ApplyFirstClientNetPackVisitor::visitBattleStart(BattleStart & pack)
{
// Cannot use the usual code because curB is not set yet
callOnlyThatBattleInterface(cl, pack.info->getSide(BattleSide::ATTACKER).color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSideArmy(BattleSide::ATTACKER), pack.info->getSideArmy(BattleSide::DEFENDER),
pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSideHero(BattleSide::DEFENDER));
pack.info->tile, pack.info->getSideHero(BattleSide::ATTACKER), pack.info->getSideHero(BattleSide::DEFENDER));
callOnlyThatBattleInterface(cl, pack.info->getSide(BattleSide::DEFENDER).color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSideArmy(BattleSide::ATTACKER), pack.info->getSideArmy(BattleSide::DEFENDER),
pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSideHero(BattleSide::DEFENDER));
pack.info->tile, pack.info->getSideHero(BattleSide::ATTACKER), pack.info->getSideHero(BattleSide::DEFENDER));
callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSideArmy(BattleSide::ATTACKER), pack.info->getSideArmy(BattleSide::DEFENDER),
pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSideHero(BattleSide::DEFENDER));
pack.info->tile, pack.info->getSideHero(BattleSide::ATTACKER), pack.info->getSideHero(BattleSide::DEFENDER));
}
void ApplyClientNetPackVisitor::visitBattleStart(BattleStart & pack)

View File

@@ -157,10 +157,10 @@ struct RangeGenerator
std::function<int()> myRand;
};
std::unique_ptr<BattleInfo> BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town)
std::unique_ptr<BattleInfo> BattleInfo::setupBattle(IGameCallback *cb, const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town)
{
CMP_stack cmpst;
auto currentBattle = std::make_unique<BattleInfo>(layout);
auto currentBattle = std::make_unique<BattleInfo>(cb, layout);
for(auto i : { BattleSide::LEFT_SIDE, BattleSide::RIGHT_SIDE})
currentBattle->sides[i].init(heroes[i], armies[i]);
@@ -171,7 +171,8 @@ std::unique_ptr<BattleInfo> BattleInfo::setupBattle(const int3 & tile, TerrainId
currentBattle->round = -2;
currentBattle->activeStack = -1;
currentBattle->replayAllowed = false;
currentBattle->town = town;
if (town)
currentBattle->townID = town->id;
//setting up siege obstacles
if (town && town->fortificationsLevel().wallsHealth != 0)
@@ -354,15 +355,15 @@ std::unique_ptr<BattleInfo> BattleInfo::setupBattle(const int3 & tile, TerrainId
}
}
if (currentBattle->town)
if (currentBattle->townID.hasValue())
{
if (currentBattle->town->fortificationsLevel().citadelHealth != 0)
if (currentBattle->getTown()->fortificationsLevel().citadelHealth != 0)
currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_CENTRAL_TOWER);
if (currentBattle->town->fortificationsLevel().upperTowerHealth != 0)
if (currentBattle->getTown()->fortificationsLevel().upperTowerHealth != 0)
currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_UPPER_TOWER);
if (currentBattle->town->fortificationsLevel().lowerTowerHealth != 0)
if (currentBattle->getTown()->fortificationsLevel().lowerTowerHealth != 0)
currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER);
//Moat generating is done on server
@@ -437,7 +438,7 @@ const CGHeroInstance * BattleInfo::getHero(const PlayerColor & player) const
{
for(const auto & side : sides)
if(side.color == player)
return side.hero;
return side.getHero();
logGlobal->error("Player %s is not in battle!", player.toString());
return nullptr;
@@ -458,17 +459,18 @@ CStack * BattleInfo::getStack(int stackID, bool onlyAlive)
return const_cast<CStack *>(battleGetStackByID(stackID, onlyAlive));
}
BattleInfo::BattleInfo(const BattleLayout & layout):
BattleInfo()
BattleInfo::BattleInfo(IGameCallback *cb, const BattleLayout & layout):
BattleInfo(cb)
{
*this->layout = layout;
}
BattleInfo::BattleInfo():
BattleInfo::BattleInfo(IGameCallback *cb)
:GameCallbackHolder(cb),
sides({SideInBattle(cb), SideInBattle(cb)}),
layout(std::make_unique<BattleLayout>()),
round(-1),
activeStack(-1),
town(nullptr),
tile(-1,-1,-1),
battlefieldType(BattleField::NONE),
tacticsSide(BattleSide::NONE),
@@ -557,12 +559,19 @@ PlayerColor BattleInfo::getSidePlayer(BattleSide side) const
const CArmedInstance * BattleInfo::getSideArmy(BattleSide side) const
{
return getSide(side).armyObject;
return getSide(side).getArmy();
}
const CGHeroInstance * BattleInfo::getSideHero(BattleSide side) const
{
return getSide(side).hero;
return getSide(side).getHero();
}
const CGTownInstance * BattleInfo::getTown() const
{
if (townID.hasValue())
return cb->getTown(townID);
return nullptr;
}
uint8_t BattleInfo::getTacticDist() const
@@ -577,7 +586,9 @@ BattleSide BattleInfo::getTacticsSide() const
const CGTownInstance * BattleInfo::getDefendedTown() const
{
return town;
if (townID.hasValue())
return cb->getTown(townID);
return nullptr;
}
EWallState BattleInfo::getWallState(EWallPart partOfWall) const

View File

@@ -8,13 +8,16 @@
*
*/
#pragma once
#include "../int3.h"
#include "../bonuses/Bonus.h"
#include "../bonuses/CBonusSystemNode.h"
#include "CBattleInfoCallback.h"
#include "IBattleState.h"
#include "SiegeInfo.h"
#include "SideInBattle.h"
#include "SiegeInfo.h"
#include "../GameCallbackHolder.h"
#include "../bonuses/Bonus.h"
#include "../bonuses/CBonusSystemNode.h"
#include "../int3.h"
VCMI_LIB_NAMESPACE_BEGIN
@@ -24,7 +27,7 @@ class CStackBasicDescriptor;
class BattleField;
struct BattleLayout;
class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState
class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState, public GameCallbackHolder
{
BattleSideArray<SideInBattle> sides; //sides[0] - attacker, sides[1] - defender
std::unique_ptr<BattleLayout> layout;
@@ -33,7 +36,7 @@ public:
si32 round;
si32 activeStack;
const CGTownInstance * town; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
ObjectInstanceID townID; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
int3 tile; //for background and bonuses
bool replayAllowed;
std::vector<std::unique_ptr<CStack>> stacks;
@@ -52,7 +55,7 @@ public:
h & sides;
h & round;
h & activeStack;
h & town;
h & townID;
h & tile;
h & stacks;
h & obstacles;
@@ -66,8 +69,8 @@ public:
}
//////////////////////////////////////////////////////////////////////////
BattleInfo(const BattleLayout & layout);
BattleInfo();
BattleInfo(IGameCallback *cb, const BattleLayout & layout);
BattleInfo(IGameCallback *cb);
virtual ~BattleInfo();
const IBattleInfo * getBattle() const override;
@@ -93,6 +96,8 @@ public:
const CArmedInstance * getSideArmy(BattleSide side) const override;
const CGHeroInstance * getSideHero(BattleSide side) const override;
const CGTownInstance * getTown() const;
ui8 getTacticDist() const override;
BattleSide getTacticsSide() const override;
@@ -154,7 +159,7 @@ public:
const CGHeroInstance * getHero(const PlayerColor & player) const; //returns fighting hero that belongs to given player
void localInit();
static std::unique_ptr<BattleInfo> setupBattle(const int3 & tile, TerrainId, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town);
static std::unique_ptr<BattleInfo> setupBattle(IGameCallback *cb, const int3 & tile, TerrainId, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town);
BattleSide whatSide(const PlayerColor & player) const;

View File

@@ -9,16 +9,19 @@
*/
#include "StdInc.h"
#include "SideInBattle.h"
#include "../mapObjects/CArmedInstance.h"
#include "../IGameCallback.h"
#include "../mapObjects/CGHeroInstance.h"
VCMI_LIB_NAMESPACE_BEGIN
void SideInBattle::init(const CGHeroInstance * Hero, const CArmedInstance * Army)
{
hero = Hero;
armyObject = Army;
armyObjectID = Army->id;
if (Hero)
heroID = Hero->id;
switch(armyObject->ID.toEnum())
switch(Army->ID.toEnum())
{
case Obj::CREATURE_GENERATOR1:
case Obj::CREATURE_GENERATOR2:
@@ -27,11 +30,25 @@ void SideInBattle::init(const CGHeroInstance * Hero, const CArmedInstance * Army
color = PlayerColor::NEUTRAL;
break;
default:
color = armyObject->getOwner();
color = Army->getOwner();
}
if(color == PlayerColor::UNFLAGGABLE)
color = PlayerColor::NEUTRAL;
}
const CArmedInstance * SideInBattle::getArmy() const
{
if (armyObjectID.hasValue())
return dynamic_cast<const CArmedInstance*>(cb->getObjInstance(armyObjectID));
return nullptr;
}
const CGHeroInstance * SideInBattle::getHero() const
{
if (heroID.hasValue())
return cb->getHero(heroID);
return nullptr;
}
VCMI_LIB_NAMESPACE_END

View File

@@ -8,31 +8,36 @@
*
*/
#pragma once
#include "../GameConstants.h"
#include "../GameCallbackHolder.h"
VCMI_LIB_NAMESPACE_BEGIN
class CGHeroInstance;
class CArmedInstance;
struct DLL_LINKAGE SideInBattle
struct DLL_LINKAGE SideInBattle : public GameCallbackHolder
{
using GameCallbackHolder::GameCallbackHolder;
PlayerColor color = PlayerColor::CANNOT_DETERMINE;
const CGHeroInstance * hero = nullptr; //may be NULL if army is not commanded by hero
const CArmedInstance * armyObject = nullptr; //adv. map object with army that participates in battle; may be same as hero
ObjectInstanceID heroID; //may be empty if army is not commanded by hero
ObjectInstanceID armyObjectID; //adv. map object with army that participates in battle; may be same as hero
uint32_t castSpellsCount = 0; //how many spells each side has been cast this turn
std::vector<SpellID> usedSpellsHistory; //every time hero casts spell, it's inserted here -> eagle eye skill
int32_t enchanterCounter = 0; //tends to pass through 0, so sign is needed
void init(const CGHeroInstance * Hero, const CArmedInstance * Army);
const CArmedInstance * getArmy() const;
const CGHeroInstance * getHero() const;
template <typename Handler> void serialize(Handler &h)
{
h & color;
h & hero;
h & armyObject;
h & heroID;
h & armyObjectID;
h & castSpellsCount;
h & usedSpellsHistory;
h & enchanterCounter;

View File

@@ -175,7 +175,7 @@ BattleID BattleProcessor::setupBattle(int3 tile, BattleSideArray<const CArmedIns
//send info about battles
BattleStart bs;
bs.info = BattleInfo::setupBattle(tile, terrain, battlefieldType, armies, heroes, layout, town);
bs.info = BattleInfo::setupBattle(gameHandler->gameState()->callback, tile, terrain, battlefieldType, armies, heroes, layout, town);
bs.battleID = gameHandler->gameState()->nextBattleID;
engageIntoBattle(bs.info->getSide(BattleSide::ATTACKER).color);

View File

@@ -200,7 +200,7 @@ public:
//send info about battles
auto battle = BattleInfo::setupBattle(tile, terrain, terType, armedInstancies, heroes, layout, nullptr);
auto battle = BattleInfo::setupBattle(gameState->callback, tile, terrain, terType, armedInstancies, heroes, layout, nullptr);
BattleStart bs;
bs.info = std::move(battle);