diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index fc6819279..856553086 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -148,12 +148,6 @@ void VCAI::heroMoved(const TryMoveHero & details) } } -void VCAI::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute) -{ - LOG_TRACE_PARAMS(logAi, "isAbsolute '%i'", isAbsolute); - NET_EVENT_HANDLER; -} - void VCAI::heroInGarrisonChange(const CGTownInstance *town) { LOG_TRACE(logAi); @@ -246,19 +240,12 @@ void VCAI::artifactRemoved(const ArtifactLocation &al) NET_EVENT_HANDLER; } -void VCAI::stacksErased(const StackLocation &location) -{ - LOG_TRACE(logAi); - NET_EVENT_HANDLER; -} - void VCAI::artifactDisassembled(const ArtifactLocation &al) { LOG_TRACE(logAi); NET_EVENT_HANDLER; } - void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start) { LOG_TRACE_PARAMS(logAi, "start '%i'; obj '%s'", start % (visitedObj ? visitedObj->getObjectName() : std::string("n/a"))); @@ -377,13 +364,7 @@ void VCAI::heroMovePointsChanged(const CGHeroInstance * hero) NET_EVENT_HANDLER; } -void VCAI::stackChangedType(const StackLocation &location, const CCreature &newType) -{ - LOG_TRACE(logAi); - NET_EVENT_HANDLER; -} - -void VCAI::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) +void VCAI::garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2) { LOG_TRACE(logAi); NET_EVENT_HANDLER; @@ -452,12 +433,6 @@ void VCAI::playerBonusChanged(const Bonus &bonus, bool gain) NET_EVENT_HANDLER; } -void VCAI::newStackInserted(const StackLocation &location, const CStackInstance &stack) -{ - LOG_TRACE(logAi); - NET_EVENT_HANDLER; -} - void VCAI::heroCreated(const CGHeroInstance* h) { LOG_TRACE(logAi); @@ -501,12 +476,6 @@ void VCAI::receivedResource() NET_EVENT_HANDLER; } -void VCAI::stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) -{ - LOG_TRACE(logAi); - NET_EVENT_HANDLER; -} - void VCAI::showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) { LOG_TRACE(logAi); diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 98ac5a1dc..1e551a96f 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -203,7 +203,6 @@ public: virtual void availableCreaturesChanged(const CGDwelling *town) override; virtual void heroMoved(const TryMoveHero & details) override; - virtual void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute) override; virtual void heroInGarrisonChange(const CGTownInstance *town) override; virtual void centerView(int3 pos, int focusTime) override; virtual void tileHidden(const std::unordered_set &pos) override; @@ -217,7 +216,6 @@ public: virtual void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override; virtual void artifactPut(const ArtifactLocation &al) override; virtual void artifactRemoved(const ArtifactLocation &al) override; - virtual void stacksErased(const StackLocation &location) override; virtual void artifactDisassembled(const ArtifactLocation &al) override; virtual void heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start) override; virtual void availableArtifactsChanged(const CGBlackMarket *bm = nullptr) override; @@ -227,18 +225,15 @@ public: virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) override; virtual void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) override; virtual void heroMovePointsChanged(const CGHeroInstance * hero) override; - virtual void stackChangedType(const StackLocation &location, const CCreature &newType) override; - virtual void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) override; + virtual void garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2) override; virtual void newObject(const CGObjectInstance * obj) override; virtual void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor) override; virtual void playerBonusChanged(const Bonus &bonus, bool gain) override; - virtual void newStackInserted(const StackLocation &location, const CStackInstance &stack) override; virtual void heroCreated(const CGHeroInstance*) override; virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID) override; virtual void showInfoDialog(const std::string &text, const std::vector &components, int soundID) override; virtual void requestRealized(PackageApplied *pa) override; virtual void receivedResource() override; - virtual void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) override; virtual void objectRemoved(const CGObjectInstance *obj) override; virtual void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) override; virtual void heroManaPointsChanged(const CGHeroInstance * hero) override; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 1efdc6f3b..e8a61b402 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -609,6 +609,24 @@ void CPlayerInterface::heroVisitsTown(const CGHeroInstance* hero, const CGTownIn waitWhileDialog(); openTownWindow(town); } + +void CPlayerInterface::garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2) +{ + std::vector instances; + + if(auto obj = cb->getObj(id1)) + instances.push_back(obj); + + + if(id2 != ObjectInstanceID() && id2 != id1) + { + if(auto obj = cb->getObj(id2)) + instances.push_back(obj); + } + + garrisonsChanged(instances); +} + void CPlayerInterface::garrisonsChanged(std::vector objs) { boost::unique_lock un(*pim); @@ -2567,54 +2585,6 @@ void CPlayerInterface::sendCustomEvent( int code ) CGuiHandler::pushSDLEvent(SDL_USEREVENT, code); } -void CPlayerInterface::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute) -{ - EVENT_HANDLER_CALLED_BY_CLIENT; - garrisonChanged(location.army); -} - -void CPlayerInterface::stackChangedType(const StackLocation &location, const CCreature &newType) -{ - EVENT_HANDLER_CALLED_BY_CLIENT; - garrisonChanged(location.army); -} - -void CPlayerInterface::stacksErased(const StackLocation &location) -{ - EVENT_HANDLER_CALLED_BY_CLIENT; - garrisonChanged(location.army); -} - -void CPlayerInterface::stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) -{ - EVENT_HANDLER_CALLED_BY_CLIENT; - - std::vector objects; - objects.push_back(loc1.army); - if (loc2.army != loc1.army) - objects.push_back(loc2.army); - - garrisonsChanged(objects); -} - -void CPlayerInterface::newStackInserted(const StackLocation &location, const CStackInstance &stack) -{ - EVENT_HANDLER_CALLED_BY_CLIENT; - garrisonChanged(location.army); -} - -void CPlayerInterface::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) -{ - EVENT_HANDLER_CALLED_BY_CLIENT; - - std::vector objects; - objects.push_back(src.army); - if (src.army != dst.army) - objects.push_back(dst.army); - - garrisonsChanged(objects); -} - void CPlayerInterface::askToAssembleArtifact(const ArtifactLocation &al) { auto hero = boost::apply_visitor(HeroObjectRetriever(), al.artHolder); diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index 114155e00..ea8493891 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -131,13 +131,9 @@ public: int getLastIndex(std::string namePrefix); //overridden funcs from CGameInterface + void garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2) override; + void buildChanged(const CGTownInstance *town, BuildingID buildingID, int what) override; //what: 1 - built, 2 - demolished - void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute) override; //if absolute, change is the new count; otherwise count was modified by adding change - void stackChangedType(const StackLocation &location, const CCreature &newType) override; //used eg. when upgrading creatures - void stacksErased(const StackLocation &location) override; //stack removed from previously filled slot - void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) override; - void newStackInserted(const StackLocation &location, const CStackInstance &stack) override; //new stack inserted at given (previously empty position) - void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) override; //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks void artifactPut(const ArtifactLocation &al) override; void artifactRemoved(const ArtifactLocation &al) override; diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 6e21d4794..689e70862 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -199,38 +199,59 @@ void SetAvailableHeroes::applyCl(CClient *cl) //TODO: inform interface? } -void ChangeStackCount::applyCl(CClient *cl) +static void dispatchGarrisonChange(CClient * cl, ObjectInstanceID army1, ObjectInstanceID army2) { - callInterfaceIfPresent(cl, sl.army->tempOwner, &IGameEventsReceiver::stackChagedCount, sl, count, absoluteValue); + auto obj1 = cl->getObj(army1); + if(!obj1) + { + logNetwork->error("Cannot find army with ID %d", army1.getNum()); + return; + } + + callInterfaceIfPresent(cl, obj1->tempOwner, &IGameEventsReceiver::garrisonsChanged, army1, army2); + + if(army2 != ObjectInstanceID() && army2 != army1) + { + auto obj2 = cl->getObj(army2); + if(!obj2) + { + logNetwork->error("Cannot find army with ID %d", army2.getNum()); + return; + } + + if(obj1->tempOwner != obj2->tempOwner) + callInterfaceIfPresent(cl, obj2->tempOwner, &IGameEventsReceiver::garrisonsChanged, army1, army2); + } } -void SetStackType::applyCl(CClient *cl) +void ChangeStackCount::applyCl(CClient * cl) { - callInterfaceIfPresent(cl, sl.army->tempOwner, &IGameEventsReceiver::stackChangedType, sl, *type); + dispatchGarrisonChange(cl, army, ObjectInstanceID()); } -void EraseStack::applyCl(CClient *cl) +void SetStackType::applyCl(CClient * cl) { - callInterfaceIfPresent(cl, sl.army->tempOwner, &IGameEventsReceiver::stacksErased, sl); + dispatchGarrisonChange(cl, army, ObjectInstanceID()); } -void SwapStacks::applyCl(CClient *cl) +void EraseStack::applyCl(CClient * cl) { - callInterfaceIfPresent(cl, sl1.army->tempOwner, &IGameEventsReceiver::stacksSwapped, sl1, sl2); - if(sl1.army->tempOwner != sl2.army->tempOwner) - callInterfaceIfPresent(cl, sl2.army->tempOwner, &IGameEventsReceiver::stacksSwapped, sl1, sl2); + dispatchGarrisonChange(cl, army, ObjectInstanceID()); } -void InsertNewStack::applyCl(CClient *cl) +void SwapStacks::applyCl(CClient * cl) { - callInterfaceIfPresent(cl, sl.army->tempOwner, &IGameEventsReceiver::newStackInserted, sl, *sl.getStack()); + dispatchGarrisonChange(cl, srcArmy, dstArmy); } -void RebalanceStacks::applyCl(CClient *cl) +void InsertNewStack::applyCl(CClient * cl) { - callInterfaceIfPresent(cl, src.army->tempOwner, &IGameEventsReceiver::stacksRebalanced, src, dst, count); - if(src.army->tempOwner != dst.army->tempOwner) - callInterfaceIfPresent(cl, dst.army->tempOwner, &IGameEventsReceiver::stacksRebalanced, src, dst, count); + dispatchGarrisonChange(cl, army, ObjectInstanceID()); +} + +void RebalanceStacks::applyCl(CClient * cl) +{ + dispatchGarrisonChange(cl, srcArmy, dstArmy); } void PutArtifact::applyCl(CClient *cl) diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index e89e873cb..2fd029ae0 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -424,11 +424,11 @@ CStackInstance * CCreatureSet::detachStack(SlotID slot) return ret; } -void CCreatureSet::setStackType(SlotID slot, const CCreature *type) +void CCreatureSet::setStackType(SlotID slot, CreatureID type) { assert(hasStackAtSlot(slot)); CStackInstance *s = stacks[slot]; - s->setType(type->idNumber); + s->setType(type); armyChanged(); } diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index 9bf65df0b..9a814b122 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -185,7 +185,7 @@ public: void putStack(SlotID slot, CStackInstance *stack); //adds new stack to the army, slot must be empty void setStackCount(SlotID slot, TQuantity count); //stack must exist! CStackInstance *detachStack(SlotID slot); //removes stack from army but doesn't destroy it (so it can be moved somewhere else or safely deleted) - void setStackType(SlotID slot, const CCreature *type); + void setStackType(SlotID slot, CreatureID type); void giveStackExp(TExpType exp); void setStackExp(SlotID slot, TExpType exp); diff --git a/lib/CGameInfoCallback.h b/lib/CGameInfoCallback.h index 54ed8185d..4715a4f39 100644 --- a/lib/CGameInfoCallback.h +++ b/lib/CGameInfoCallback.h @@ -78,6 +78,7 @@ public: int64_t estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const; //estimates damage of given spell; returns 0 if spell causes no dmg const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const; const CGObjectInstance * getObjInstance(ObjectInstanceID oid) const; + const CGObjectInstance * getArmyInstance(ObjectInstanceID oid) const; //objects const CGObjectInstance* getObj(ObjectInstanceID objid, bool verbose = true) const; diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index 8f968a01e..16fde4418 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -224,12 +224,17 @@ PlayerState * CNonConstInfoCallback::getPlayer( PlayerColor color, bool verbose CArtifactInstance * CNonConstInfoCallback::getArtInstance( ArtifactInstanceID aid ) { - return gs->map->artInstances[aid.num]; + return gs->map->artInstances.at(aid.num); } CGObjectInstance * CNonConstInfoCallback::getObjInstance( ObjectInstanceID oid ) { - return gs->map->objects[oid.num]; + return gs->map->objects.at(oid.num); +} + +CArmedInstance * CNonConstInfoCallback::getArmyInstance(ObjectInstanceID oid) +{ + return dynamic_cast(getObjInstance(oid)); } const CGObjectInstance * IGameCallback::putNewObject(Obj ID, int subID, int3 pos) diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 445d5e49f..93b10250a 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -108,6 +108,7 @@ public: TerrainTile * getTile(int3 pos); CArtifactInstance * getArtInstance(ArtifactInstanceID aid); CGObjectInstance * getObjInstance(ObjectInstanceID oid); + CArmedInstance * getArmyInstance(ObjectInstanceID oid); }; /// Interface class for handling general game logic and actions diff --git a/lib/IGameEventsReceiver.h b/lib/IGameEventsReceiver.h index 9fe8fc005..bb319d5bb 100644 --- a/lib/IGameEventsReceiver.h +++ b/lib/IGameEventsReceiver.h @@ -80,14 +80,7 @@ public: virtual void battleResultsApplied(){}; //called when all effects of last battle are applied - //garrison operations - virtual void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute){}; //if absolute, change is the new count; otherwise count was modified by adding change - virtual void stackChangedType(const StackLocation &location, const CCreature &newType){}; //used eg. when upgrading creatures - virtual void stacksErased(const StackLocation &location){}; //stack removed from previously filled slot - virtual void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2){}; - virtual void newStackInserted(const StackLocation &location, const CStackInstance &stack){}; //new stack inserted at given (previously empty position) - virtual void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count){}; //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks - //virtual void garrisonChanged(const CGObjectInstance * obj){}; + virtual void garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2){}; //artifacts operations virtual void artifactPut(const ArtifactLocation &al){}; diff --git a/lib/NetPacks.h b/lib/NetPacks.h index fd4e1df8b..013c17f4b 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -798,16 +798,18 @@ struct CArtifactOperationPack : CPackForClient struct ChangeStackCount : CGarrisonOperationPack { - StackLocation sl; + ObjectInstanceID army; + SlotID slot; TQuantity count; - ui8 absoluteValue; //if not -> count will be added (or subtracted if negative) + bool absoluteValue; //if not -> count will be added (or subtracted if negative) - void applyCl(CClient *cl); - DLL_LINKAGE void applyGs(CGameState *gs); + void applyCl(CClient * cl); + DLL_LINKAGE void applyGs(CGameState * gs); - template void serialize(Handler &h, const int version) + template void serialize(Handler & h, const int version) { - h & sl; + h & army; + h & slot; h & count; h & absoluteValue; } @@ -815,65 +817,87 @@ struct ChangeStackCount : CGarrisonOperationPack struct SetStackType : CGarrisonOperationPack { - StackLocation sl; - const CCreature *type; + ObjectInstanceID army; + SlotID slot; + CreatureID type; void applyCl(CClient *cl); DLL_LINKAGE void applyGs(CGameState *gs); template void serialize(Handler &h, const int version) { - h & sl; + h & army; + h & slot; h & type; } }; struct EraseStack : CGarrisonOperationPack { - StackLocation sl; + ObjectInstanceID army; + SlotID slot; void applyCl(CClient *cl); DLL_LINKAGE void applyGs(CGameState *gs); template void serialize(Handler &h, const int version) { - h & sl; + h & army; + h & slot; } }; struct SwapStacks : CGarrisonOperationPack { - StackLocation sl1, sl2; + ObjectInstanceID srcArmy; + ObjectInstanceID dstArmy; + SlotID srcSlot; + SlotID dstSlot; - void applyCl(CClient *cl); - DLL_LINKAGE void applyGs(CGameState *gs); + void applyCl(CClient * cl); + DLL_LINKAGE void applyGs(CGameState * gs); - template void serialize(Handler &h, const int version) + template void serialize(Handler & h, const int version) { - h & sl1; - h & sl2; + h & srcArmy; + h & dstArmy; + h & srcSlot; + h & dstSlot; } }; struct InsertNewStack : CGarrisonOperationPack { - StackLocation sl; - CStackBasicDescriptor stack; + ObjectInstanceID army; + SlotID slot; + CreatureID type; + TQuantity count; - void applyCl(CClient *cl); - DLL_LINKAGE void applyGs(CGameState *gs); - - template void serialize(Handler &h, const int version) + InsertNewStack() + : count(0) { - h & sl; - h & stack; + } + + void applyCl(CClient * cl); + DLL_LINKAGE void applyGs(CGameState * gs); + + template void serialize(Handler & h, const int version) + { + h & army; + h & slot; + h & type; + h & count; } }; ///moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks struct RebalanceStacks : CGarrisonOperationPack { - StackLocation src, dst; + ObjectInstanceID srcArmy; + ObjectInstanceID dstArmy; + SlotID srcSlot; + SlotID dstSlot; + TQuantity count; void applyCl(CClient *cl); @@ -881,8 +905,10 @@ struct RebalanceStacks : CGarrisonOperationPack template void serialize(Handler &h, const int version) { - h & src; - h & dst; + h & srcArmy; + h & dstArmy; + h & srcSlot; + h & dstSlot; h & count; } }; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 7244f9bd0..ca7a28b61 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -826,42 +826,77 @@ DLL_LINKAGE const ArtSlotInfo *ArtifactLocation::getSlot() const return getHolderArtSet()->getSlot(slot); } -DLL_LINKAGE void ChangeStackCount::applyGs(CGameState *gs) +DLL_LINKAGE void ChangeStackCount::applyGs(CGameState * gs) { + auto srcObj = gs->getArmyInstance(army); + if(!srcObj) + logNetwork->error("[CRITICAL] ChangeStackCount: invalid army object %d, possible game state corruption.", army.getNum()); + if(absoluteValue) - sl.army->setStackCount(sl.slot, count); + srcObj->setStackCount(slot, count); else - sl.army->changeStackCount(sl.slot, count); + srcObj->changeStackCount(slot, count); } -DLL_LINKAGE void SetStackType::applyGs(CGameState *gs) +DLL_LINKAGE void SetStackType::applyGs(CGameState * gs) { - sl.army->setStackType(sl.slot, type); + auto srcObj = gs->getArmyInstance(army); + if(!srcObj) + logNetwork->error("[CRITICAL] SetStackType: invalid army object %d, possible game state corruption.", army.getNum()); + + srcObj->setStackType(slot, type); } -DLL_LINKAGE void EraseStack::applyGs(CGameState *gs) +DLL_LINKAGE void EraseStack::applyGs(CGameState * gs) { - sl.army->eraseStack(sl.slot); + auto srcObj = gs->getArmyInstance(army); + if(!srcObj) + logNetwork->error("[CRITICAL] EraseStack: invalid army object %d, possible game state corruption.", army.getNum()); + + srcObj->eraseStack(slot); } -DLL_LINKAGE void SwapStacks::applyGs(CGameState *gs) +DLL_LINKAGE void SwapStacks::applyGs(CGameState * gs) { - CStackInstance *s1 = sl1.army->detachStack(sl1.slot), - *s2 = sl2.army->detachStack(sl2.slot); + auto srcObj = gs->getArmyInstance(srcArmy); + if(!srcObj) + logNetwork->error("[CRITICAL] SwapStacks: invalid army object %d, possible game state corruption.", srcArmy.getNum()); - sl2.army->putStack(sl2.slot, s1); - sl1.army->putStack(sl1.slot, s2); + auto dstObj = gs->getArmyInstance(dstArmy); + if(!dstObj) + logNetwork->error("[CRITICAL] SwapStacks: invalid army object %d, possible game state corruption.", dstArmy.getNum()); + + CStackInstance * s1 = srcObj->detachStack(srcSlot); + CStackInstance * s2 = dstObj->detachStack(dstSlot); + + srcObj->putStack(srcSlot, s2); + dstObj->putStack(dstSlot, s1); } DLL_LINKAGE void InsertNewStack::applyGs(CGameState *gs) { - auto s = new CStackInstance(stack.type, stack.count); - sl.army->putStack(sl.slot, s); + auto s = new CStackInstance(type, count); + auto obj = gs->getArmyInstance(army); + if(obj) + obj->putStack(slot, s); + else + logNetwork->error("[CRITICAL] InsertNewStack: invalid army object %d, possible game state corruption.", army.getNum()); } -DLL_LINKAGE void RebalanceStacks::applyGs(CGameState *gs) +DLL_LINKAGE void RebalanceStacks::applyGs(CGameState * gs) { - const CCreature *srcType = src.army->getCreature(src.slot); + auto srcObj = gs->getArmyInstance(srcArmy); + if(!srcObj) + logNetwork->error("[CRITICAL] RebalanceStacks: invalid army object %d, possible game state corruption.", srcArmy.getNum()); + + auto dstObj = gs->getArmyInstance(dstArmy); + if(!dstObj) + logNetwork->error("[CRITICAL] RebalanceStacks: invalid army object %d, possible game state corruption.", dstArmy.getNum()); + + StackLocation src(srcObj, srcSlot); + StackLocation dst(dstObj, dstSlot); + + const CCreature * srcType = src.army->getCreature(src.slot); TQuantity srcCount = src.army->getStackCount(src.slot); bool stackExp = VLC->modh->modules.STACK_EXP; diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index 57a266bc8..7aee5494a 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -296,13 +296,13 @@ void CGDwelling::updateGuards() const for (auto creatureEntry : creatures) { const CCreature * crea = VLC->creh->creatures[creatureEntry.second.at(0)]; - SlotID slot = getSlotFor(crea->idNumber); - StackLocation stackLocation = StackLocation(this, slot); + if (hasStackAtSlot(slot)) //stack already exists, overwrite it { ChangeStackCount csc; - csc.sl = stackLocation; + csc.army = this->id; + csc.slot = slot; csc.count = crea->growth * 3; csc.absoluteValue = true; cb->sendAndApply(&csc); @@ -310,8 +310,10 @@ void CGDwelling::updateGuards() const else //slot is empty, create whole new stack { InsertNewStack ns; - ns.sl = stackLocation; - ns.stack = CStackBasicDescriptor(crea->idNumber, crea->growth * 3); + ns.army = this->id; + ns.slot = slot; + ns.type = crea->idNumber; + ns.count = crea->growth * 3; cb->sendAndApply(&ns); } } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index af2f2bc58..7e6f2ee82 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -3360,8 +3360,9 @@ bool CGameHandler::changeStackType(const StackLocation &sl, const CCreature *c) COMPLAIN_RET("Cannot find a stack to change type"); SetStackType sst; - sst.sl = sl; - sst.type = c; + sst.army = sl.army->id; + sst.slot = sl.slot; + sst.type = c->idNumber; sendAndApply(&sst); return true; } @@ -5799,8 +5800,10 @@ bool CGameHandler::insertNewStack(const StackLocation &sl, const CCreature *c, T COMPLAIN_RET("Cannot insert stack to that slot!"); InsertNewStack ins; - ins.sl = sl; - ins.stack = CStackBasicDescriptor(c, count); + ins.army = sl.army->id; + ins.slot = sl.slot; + ins.type = c->idNumber; + ins.count = count; sendAndApply(&ins); return true; } @@ -5818,7 +5821,8 @@ bool CGameHandler::eraseStack(const StackLocation &sl, bool forceRemoval) } EraseStack es; - es.sl = sl; + es.army = sl.army->id; + es.slot = sl.slot; sendAndApply(&es); return true; } @@ -5840,7 +5844,8 @@ bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bo else { ChangeStackCount csc; - csc.sl = sl; + csc.army = sl.army->id; + csc.slot = sl.slot; csc.count = count; csc.absoluteValue = absoluteValue; sendAndApply(&csc); @@ -5920,25 +5925,32 @@ bool CGameHandler::moveStack(const StackLocation &src, const StackLocation &dst, } RebalanceStacks rs; - rs.src = src; - rs.dst = dst; + rs.srcArmy = src.army->id; + rs.dstArmy = dst.army->id; + rs.srcSlot = src.slot; + rs.dstSlot = dst.slot; rs.count = count; sendAndApply(&rs); return true; } -bool CGameHandler::swapStacks(const StackLocation &sl1, const StackLocation &sl2) +bool CGameHandler::swapStacks(const StackLocation & sl1, const StackLocation & sl2) { - - if (!sl1.army->hasStackAtSlot(sl1.slot)) + if(!sl1.army->hasStackAtSlot(sl1.slot)) + { return moveStack(sl2, sl1); - else if (!sl2.army->hasStackAtSlot(sl2.slot)) + } + else if(!sl2.army->hasStackAtSlot(sl2.slot)) + { return moveStack(sl1, sl2); + } else { SwapStacks ss; - ss.sl1 = sl1; - ss.sl2 = sl2; + ss.srcArmy = sl1.army->id; + ss.dstArmy = sl2.army->id; + ss.srcSlot = sl1.slot; + ss.dstSlot = sl2.slot; sendAndApply(&ss); return true; }