1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Fix regressions in combat

This commit is contained in:
Ivan Savenko
2025-04-19 11:25:18 +03:00
parent a89cf280e3
commit ce436bd63e
7 changed files with 22 additions and 14 deletions

View File

@ -405,9 +405,9 @@ void CStack::spendMana(ServerCallback * server, const int spellCost) const
server->apply(ssp); server->apply(ssp);
} }
void CStack::postDeserialize(const CArmedInstance * army, const SlotID & extSlot) void CStack::postDeserialize(const CArmedInstance * army)
{ {
if(extSlot == SlotID::COMMANDER_SLOT_PLACEHOLDER) if(slot == SlotID::COMMANDER_SLOT_PLACEHOLDER)
{ {
const auto * hero = dynamic_cast<const CGHeroInstance *>(army); const auto * hero = dynamic_cast<const CGHeroInstance *>(army);
assert(hero); assert(hero);
@ -418,14 +418,13 @@ void CStack::postDeserialize(const CArmedInstance * army, const SlotID & extSlot
//no external slot possible, so no base stack //no external slot possible, so no base stack
base = nullptr; base = nullptr;
} }
else if(!army || extSlot == SlotID() || !army->hasStackAtSlot(extSlot)) else if(!army || slot == SlotID() || !army->hasStackAtSlot(slot))
{ {
base = nullptr; throw std::runtime_error(typeID.toEntity(LIBRARY)->getNameSingularTranslated() + " doesn't have a base stack!");
logGlobal->warn("%s doesn't have a base stack!", typeID.toEntity(LIBRARY)->getNameSingularTranslated());
} }
else else
{ {
base = &army->getStack(extSlot); base = &army->getStack(slot);
} }
doubleWideCached = battle::CUnitState::doubleWide(); doubleWideCached = battle::CUnitState::doubleWide();

View File

@ -37,8 +37,9 @@ private:
bool doubleWideCached = false; bool doubleWideCached = false;
void postDeserialize(const CArmedInstance * army, const SlotID & extSlot);
public: public:
void postDeserialize(const CArmedInstance * army);
const CStackInstance * base = nullptr; //garrison slot from which stack originates (nullptr for war machines, summoned cres, etc) const CStackInstance * base = nullptr; //garrison slot from which stack originates (nullptr for war machines, summoned cres, etc)
BattleHex initialPosition; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower BattleHex initialPosition; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower

View File

@ -959,6 +959,12 @@ CGHeroInstance * BattleInfo::battleGetFightingHero(BattleSide side) const
return const_cast<CGHeroInstance*>(CBattleInfoEssentials::battleGetFightingHero(side)); return const_cast<CGHeroInstance*>(CBattleInfoEssentials::battleGetFightingHero(side));
} }
void BattleInfo::postDeserialize()
{
for (auto & unit : stacks)
unit->postDeserialize(getSideArmy(unit->unitSide()));
}
#if SCRIPTING_ENABLED #if SCRIPTING_ENABLED
scripting::Pool * BattleInfo::getContextPool() const scripting::Pool * BattleInfo::getContextPool() const
{ {

View File

@ -31,6 +31,8 @@ class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallba
{ {
BattleSideArray<SideInBattle> sides; //sides[0] - attacker, sides[1] - defender BattleSideArray<SideInBattle> sides; //sides[0] - attacker, sides[1] - defender
std::unique_ptr<BattleLayout> layout; std::unique_ptr<BattleLayout> layout;
void postDeserialize();
public: public:
BattleID battleID = BattleID(0); BattleID battleID = BattleID(0);
@ -66,6 +68,9 @@ public:
h & tacticDistance; h & tacticDistance;
h & static_cast<CBonusSystemNode&>(*this); h & static_cast<CBonusSystemNode&>(*this);
h & replayAllowed; h & replayAllowed;
if(!h.saving)
postDeserialize();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -3439,12 +3439,10 @@ void CGameHandler::objectVisited(const CGObjectInstance * obj, const CGHeroInsta
queries->popIfTop(visitQuery); //visit ends here if no queries were created queries->popIfTop(visitQuery); //visit ends here if no queries were created
} }
void CGameHandler::objectVisitEnded(const CGHeroInstance *h, PlayerColor player) void CGameHandler::objectVisitEnded(const ObjectInstanceID & heroObjectID, PlayerColor player)
{ {
using events::ObjectVisitEnded; using events::ObjectVisitEnded;
logGlobal->debug("%s visit ends.\n", h->nodeName());
auto endVisit = [&](ObjectVisitEnded & event) auto endVisit = [&](ObjectVisitEnded & event)
{ {
HeroVisit hv; HeroVisit hv;
@ -3456,7 +3454,7 @@ void CGameHandler::objectVisitEnded(const CGHeroInstance *h, PlayerColor player)
//TODO: ObjectVisitEnded should also have id of visited object, //TODO: ObjectVisitEnded should also have id of visited object,
//but this requires object being deleted only by `removeAfterVisit()` but not `removeObject()` //but this requires object being deleted only by `removeAfterVisit()` but not `removeObject()`
ObjectVisitEnded::defaultExecute(serverEventBus.get(), endVisit, player, h->id); ObjectVisitEnded::defaultExecute(serverEventBus.get(), endVisit, player, heroObjectID);
} }
bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID) bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID)

View File

@ -238,7 +238,7 @@ public:
bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h ); void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
void objectVisitEnded(const CGHeroInstance *h, PlayerColor player); void objectVisitEnded(const ObjectInstanceID & heroObjectID, PlayerColor player);
bool dig(const CGHeroInstance *h); bool dig(const CGHeroInstance *h);
void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging); void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging);

View File

@ -53,9 +53,8 @@ MapObjectVisitQuery::MapObjectVisitQuery(CGameHandler * owner, const CGObjectIns
void MapObjectVisitQuery::onRemoval(PlayerColor color) void MapObjectVisitQuery::onRemoval(PlayerColor color)
{ {
auto object = gh->gameState()->getObjInstance(visitedObject); auto object = gh->gameState()->getObjInstance(visitedObject);
auto hero = gh->gameState()->getHero(visitingHero);
gh->objectVisitEnded(hero, players.front()); gh->objectVisitEnded(visitingHero, players.front());
//Can object visit affect 2 players and what would be desired behavior? //Can object visit affect 2 players and what would be desired behavior?
if(removeObjectAfterVisit) if(removeObjectAfterVisit)