From a83f290e1397c620fa25694f8d18069afce9d9b1 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Mon, 24 Jul 2023 19:09:17 +0300 Subject: [PATCH 1/4] bulk move artifacts only equipped, only backpack --- CCallback.cpp | 4 +-- CCallback.h | 4 +-- client/windows/GUIClasses.cpp | 16 +++++++--- lib/CArtHandler.cpp | 26 ++++++++++------ lib/CArtHandler.h | 6 ++-- lib/CArtifactInstance.cpp | 12 +++++++- lib/CArtifactInstance.h | 2 ++ lib/CCreatureSet.cpp | 7 ++--- lib/CCreatureSet.h | 2 +- lib/NetPacks.h | 8 ++++- lib/mapObjects/CGHeroInstance.cpp | 4 +-- lib/mapObjects/CGHeroInstance.h | 2 +- lib/mapping/MapFormatH3M.cpp | 6 ++-- server/CGameHandler.cpp | 49 +++++++++++++++++++------------ server/CGameHandler.h | 2 +- server/NetPacksServer.cpp | 2 +- 16 files changed, 99 insertions(+), 53 deletions(-) diff --git a/CCallback.cpp b/CCallback.cpp index 4768aaae8..7f6db4874 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -174,9 +174,9 @@ void CCallback::assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition sendRequest(&aa); } -void CCallback::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) +void CCallback::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap, bool equipped, bool backpack) { - BulkExchangeArtifacts bma(srcHero, dstHero, swap); + BulkExchangeArtifacts bma(srcHero, dstHero, swap, equipped, backpack); sendRequest(&bma); } diff --git a/CCallback.h b/CCallback.h index 8fb7970f9..2e94c9f2e 100644 --- a/CCallback.h +++ b/CCallback.h @@ -108,7 +108,7 @@ public: // Moves all artifacts from one hero to another - virtual void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) = 0; + virtual void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap, bool equipped, bool backpack) = 0; }; class CBattleCallback : public IBattleCallback @@ -171,7 +171,7 @@ public: bool dismissHero(const CGHeroInstance * hero) override; bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2) override; void assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo) override; - void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) override; + void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap, bool equipped = true, bool backpack = true) override; void eraseArtifactByClient(const ArtifactLocation & al) override; bool buildBuilding(const CGTownInstance *town, BuildingID buildingID) override; void recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1) override; diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 4b8b23c77..8f7126005 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -654,7 +654,12 @@ std::function CExchangeController::onSwapArtifacts() { return [&]() { - cb->bulkMoveArtifacts(left->id, right->id, true); + if(GH.isKeyboardCtrlDown()) + cb->bulkMoveArtifacts(left->id, right->id, true, true, false); + else if(GH.isKeyboardShiftDown()) + cb->bulkMoveArtifacts(left->id, right->id, true, false, true); + else + cb->bulkMoveArtifacts(left->id, right->id, true); }; } @@ -810,11 +815,14 @@ void CExchangeController::moveArtifacts(bool leftToRight) const CGHeroInstance * target = leftToRight ? right : left; if(source->tempOwner != cb->getPlayerID()) - { return; - } - cb->bulkMoveArtifacts(source->id, target->id, false); + if(GH.isKeyboardCtrlDown()) + cb->bulkMoveArtifacts(source->id, target->id, false, true, false); + else if(GH.isKeyboardShiftDown()) + cb->bulkMoveArtifacts(source->id, target->id, false, false, true); + else + cb->bulkMoveArtifacts(source->id, target->id, false); } void CExchangeController::moveArtifact( diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index 5eeebb5e4..66ccfe060 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -9,7 +9,6 @@ */ #include "StdInc.h" -#include "CArtHandler.h" #include "ArtifactUtils.h" #include "CGeneralTextHandler.h" @@ -925,8 +924,10 @@ unsigned CArtifactSet::getArtPosCount(const ArtifactID & aid, bool onlyWorn, boo return 0; } -void CArtifactSet::putArtifact(ArtifactPosition slot, CArtifactInstance * art) +CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(ArtifactPosition slot, CArtifactInstance * art) { + ArtPlacementMap resArtPlacement; + setNewArtSlot(slot, art, false); if(art->artType->isCombined() && ArtifactUtils::isSlotEquipment(slot)) { @@ -938,19 +939,26 @@ void CArtifactSet::putArtifact(ArtifactPosition slot, CArtifactInstance * art) mainPart = part.art; break; } - - for(auto & part : art->getPartsInfo()) + + for(const auto & part : art->getPartsInfo()) { if(part.art != mainPart) { - if(!part.art->artType->canBePutAt(this, part.slot)) - part.slot = ArtifactUtils::getArtAnyPosition(this, part.art->getTypeId()); + auto partSlot = part.slot; + if(!part.art->artType->canBePutAt(this, partSlot)) + partSlot = ArtifactUtils::getArtAnyPosition(this, part.art->getTypeId()); - assert(ArtifactUtils::isSlotEquipment(part.slot)); - setNewArtSlot(part.slot, part.art, true); + assert(ArtifactUtils::isSlotEquipment(partSlot)); + setNewArtSlot(partSlot, part.art, true); + resArtPlacement.emplace(std::make_pair(part.art, partSlot)); + } + else + { + resArtPlacement.emplace(std::make_pair(part.art, part.slot)); } } } + return resArtPlacement; } void CArtifactSet::removeArtifact(ArtifactPosition slot) @@ -1031,7 +1039,7 @@ bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockChe return true; //no slot means not used } -void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked) +void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, ConstTransitivePtr art, bool locked) { assert(!vstd::contains(artifactsWorn, slot)); diff --git a/lib/CArtHandler.h b/lib/CArtHandler.h index dad6e88e5..37056f426 100644 --- a/lib/CArtHandler.h +++ b/lib/CArtHandler.h @@ -246,11 +246,13 @@ struct DLL_LINKAGE ArtSlotInfo class DLL_LINKAGE CArtifactSet { public: + using ArtPlacementMap = std::map; + std::vector artifactsInBackpack; //hero's artifacts from bag std::map artifactsWorn; //map; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5 std::vector artifactsTransitionPos; // Used as transition position for dragAndDrop artifact exchange - void setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked); + void setNewArtSlot(const ArtifactPosition & slot, ConstTransitivePtr art, bool locked); void eraseArtSlot(const ArtifactPosition & slot); const ArtSlotInfo * getSlot(const ArtifactPosition & pos) const; @@ -275,7 +277,7 @@ public: unsigned getArtPosCount(const ArtifactID & aid, bool onlyWorn = true, bool searchBackpackAssemblies = true, bool allowLocked = true) const; virtual ArtBearer::ArtBearer bearerType() const = 0; - virtual void putArtifact(ArtifactPosition slot, CArtifactInstance * art); + virtual ArtPlacementMap putArtifact(ArtifactPosition slot, CArtifactInstance * art); virtual void removeArtifact(ArtifactPosition slot); virtual ~CArtifactSet(); diff --git a/lib/CArtifactInstance.cpp b/lib/CArtifactInstance.cpp index 81d475ad6..2c99d90b8 100644 --- a/lib/CArtifactInstance.cpp +++ b/lib/CArtifactInstance.cpp @@ -55,6 +55,16 @@ const std::vector & CCombinedArtifactInstan return partsInfo; } +void CCombinedArtifactInstance::addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap) +{ + if(!placementMap.empty()) + for(auto& part : partsInfo) + { + assert(placementMap.find(part.art) != placementMap.end()); + part.slot = placementMap.at(part.art); + } +} + SpellID CScrollArtifactInstance::getScrollSpellID() const { auto artInst = static_cast(this); @@ -163,7 +173,7 @@ bool CArtifactInstance::isCombined() const void CArtifactInstance::putAt(const ArtifactLocation & al) { - al.getHolderArtSet()->putArtifact(al.slot, this); + addPlacementMap(al.getHolderArtSet()->putArtifact(al.slot, this)); } void CArtifactInstance::removeFrom(const ArtifactLocation & al) diff --git a/lib/CArtifactInstance.h b/lib/CArtifactInstance.h index 66e405328..30ef2865b 100644 --- a/lib/CArtifactInstance.h +++ b/lib/CArtifactInstance.h @@ -12,6 +12,7 @@ #include "bonuses/CBonusSystemNode.h" #include "GameConstants.h" #include "ConstTransitivePtr.h" +#include "CArtHandler.h" VCMI_LIB_NAMESPACE_BEGIN @@ -39,6 +40,7 @@ public: bool isPart(const CArtifactInstance * supposedPart) const; std::vector & getPartsInfo(); const std::vector & getPartsInfo() const; + void addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap); template void serialize(Handler & h, const int version) { diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index ec09548c0..e9b81c4f6 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -867,14 +867,13 @@ ArtBearer::ArtBearer CStackInstance::bearerType() const return ArtBearer::CREATURE; } -void CStackInstance::putArtifact(ArtifactPosition pos, CArtifactInstance * art) +CStackInstance::ArtPlacementMap CStackInstance::putArtifact(ArtifactPosition pos, CArtifactInstance * art) { assert(!getArt(pos)); assert(art->artType->canBePutAt(this, pos)); - CArtifactSet::putArtifact(pos, art); - if(ArtifactUtils::isSlotEquipment(pos)) - attachTo(*art); + attachTo(*art); + return CArtifactSet::putArtifact(pos, art); } void CStackInstance::removeArtifact(ArtifactPosition pos) diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index e72d0eb14..d15d6c35e 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -121,7 +121,7 @@ public: void setArmyObj(const CArmedInstance *ArmyObj); virtual void giveStackExp(TExpType exp); bool valid(bool allowUnrandomized) const; - void putArtifact(ArtifactPosition pos, CArtifactInstance * art) override;//from CArtifactSet + ArtPlacementMap putArtifact(ArtifactPosition pos, CArtifactInstance * art) override;//from CArtifactSet void removeArtifact(ArtifactPosition pos) override; ArtBearer::ArtBearer bearerType() const override; //from CArtifactSet virtual std::string nodeName() const override; //from CBonusSystemnode diff --git a/lib/NetPacks.h b/lib/NetPacks.h index 3fa84933f..0075c9642 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -2413,12 +2413,16 @@ struct DLL_LINKAGE BulkExchangeArtifacts : public CPackForServer ObjectInstanceID srcHero; ObjectInstanceID dstHero; bool swap = false; + bool equipped = true; + bool backpack = true; BulkExchangeArtifacts() = default; - BulkExchangeArtifacts(const ObjectInstanceID & srcHero, const ObjectInstanceID & dstHero, bool swap) + BulkExchangeArtifacts(const ObjectInstanceID & srcHero, const ObjectInstanceID & dstHero, bool swap, bool equipped, bool backpack) : srcHero(srcHero) , dstHero(dstHero) , swap(swap) + , equipped(equipped) + , backpack(backpack) { } @@ -2430,6 +2434,8 @@ struct DLL_LINKAGE BulkExchangeArtifacts : public CPackForServer h & srcHero; h & dstHero; h & swap; + h & equipped; + h & backpack; } }; diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index e8cde5e39..c0a4bb0c6 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -1066,13 +1066,13 @@ std::string CGHeroInstance::getBiographyTextID() const return ""; } -void CGHeroInstance::putArtifact(ArtifactPosition pos, CArtifactInstance *art) +CGHeroInstance::ArtPlacementMap CGHeroInstance::putArtifact(ArtifactPosition pos, CArtifactInstance * art) { assert(art->artType->canBePutAt(this, pos)); - CArtifactSet::putArtifact(pos, art); if(ArtifactUtils::isSlotEquipment(pos)) attachTo(*art); + return CArtifactSet::putArtifact(pos, art); } void CGHeroInstance::removeArtifact(ArtifactPosition pos) diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index 65be37cef..c8aaad4fa 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -229,7 +229,7 @@ public: void initHero(CRandomGenerator & rand); void initHero(CRandomGenerator & rand, const HeroTypeID & SUBID); - void putArtifact(ArtifactPosition pos, CArtifactInstance * art) override; + ArtPlacementMap putArtifact(ArtifactPosition pos, CArtifactInstance * art) override; void removeArtifact(ArtifactPosition pos) override; void initExp(CRandomGenerator & rand); void initArmy(CRandomGenerator & rand, IArmyDescriptor *dst = nullptr); diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 3352f8b1c..175728fbf 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -927,10 +927,10 @@ bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot) // He has Shackles of War (normally - MISC slot artifact) in LEFT_HAND slot set in editor // Artifact seems to be missing in game, so skip artifacts that don't fit target slot auto * artifact = ArtifactUtils::createArtifact(map, artifactID); - auto artifactPos = ArtifactPosition(slot); - if(artifact->canBePutAt(ArtifactLocation(hero, artifactPos))) + auto dstLoc = ArtifactLocation(hero, ArtifactPosition(slot)); + if(artifact->canBePutAt(dstLoc)) { - hero->putArtifact(artifactPos, artifact); + artifact->putAt(dstLoc); } else { diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 960b8031d..cffa32d1b 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2690,7 +2690,7 @@ bool CGameHandler::moveArtifact(const ArtifactLocation &al1, const ArtifactLocat return true; } -bool CGameHandler::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) +bool CGameHandler::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap, bool equipped, bool backpack) { // Make sure exchange is even possible between the two heroes. if(!isAllowedExchange(srcHero, dstHero)) @@ -2745,34 +2745,45 @@ bool CGameHandler::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID slots.push_back(BulkMoveArtifacts::LinkedSlots(slot, slot)); } }; - // Move over artifacts that are worn srcHero -> dstHero - moveArtsWorn(psrcHero, pdstHero, slotsSrcDst); - artFittingSet.artifactsWorn.clear(); - // Move over artifacts that are worn dstHero -> srcHero - moveArtsWorn(pdstHero, psrcHero, slotsDstSrc); - // Move over artifacts that are in backpack srcHero -> dstHero - moveArtsInBackpack(psrcHero, slotsSrcDst); - // Move over artifacts that are in backpack dstHero -> srcHero - moveArtsInBackpack(pdstHero, slotsDstSrc); + if(equipped) + { + // Move over artifacts that are worn srcHero -> dstHero + moveArtsWorn(psrcHero, pdstHero, slotsSrcDst); + artFittingSet.artifactsWorn.clear(); + // Move over artifacts that are worn dstHero -> srcHero + moveArtsWorn(pdstHero, psrcHero, slotsDstSrc); + } + if(backpack) + { + // Move over artifacts that are in backpack srcHero -> dstHero + moveArtsInBackpack(psrcHero, slotsSrcDst); + // Move over artifacts that are in backpack dstHero -> srcHero + moveArtsInBackpack(pdstHero, slotsDstSrc); + } } else { artFittingSet.artifactsInBackpack = pdstHero->artifactsInBackpack; artFittingSet.artifactsWorn = pdstHero->artifactsWorn; - - // Move over artifacts that are worn - for(auto & artInfo : psrcHero->artifactsWorn) + if(equipped) { - if(ArtifactUtils::isArtRemovable(artInfo)) + // Move over artifacts that are worn + for(auto & artInfo : psrcHero->artifactsWorn) { - moveArtifact(psrcHero->getArt(artInfo.first), artInfo.first, pdstHero, slotsSrcDst); + if(ArtifactUtils::isArtRemovable(artInfo)) + { + moveArtifact(psrcHero->getArt(artInfo.first), artInfo.first, pdstHero, slotsSrcDst); + } } } - // Move over artifacts that are in backpack - for(auto & slotInfo : psrcHero->artifactsInBackpack) + if(backpack) { - moveArtifact(psrcHero->getArt(psrcHero->getArtPos(slotInfo.artifact)), - psrcHero->getArtPos(slotInfo.artifact), pdstHero, slotsSrcDst); + // Move over artifacts that are in backpack + for(auto & slotInfo : psrcHero->artifactsInBackpack) + { + moveArtifact(psrcHero->getArt(psrcHero->getArtPos(slotInfo.artifact)), + psrcHero->getArtPos(slotInfo.artifact), pdstHero, slotsSrcDst); + } } } sendAndApply(&ma); diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 3103003e3..53a395362 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -131,7 +131,7 @@ public: void putArtifact(const ArtifactLocation &al, const CArtifactInstance *a) override; void removeArtifact(const ArtifactLocation &al) override; bool moveArtifact(const ArtifactLocation & al1, const ArtifactLocation & al2) override; - bool bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap); + bool bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap, bool equipped, bool backpack); bool eraseArtifactByClient(const ArtifactLocation & al); void synchronizeArtifactHandlerLists(); diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index a2f70f294..286935383 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -132,7 +132,7 @@ void ApplyGhNetPackVisitor::visitExchangeArtifacts(ExchangeArtifacts & pack) void ApplyGhNetPackVisitor::visitBulkExchangeArtifacts(BulkExchangeArtifacts & pack) { gh.throwIfWrongOwner(&pack, pack.srcHero); - result = gh.bulkMoveArtifacts(pack.srcHero, pack.dstHero, pack.swap); + result = gh.bulkMoveArtifacts(pack.srcHero, pack.dstHero, pack.swap, pack.equipped, pack.backpack); } void ApplyGhNetPackVisitor::visitAssembleArtifacts(AssembleArtifacts & pack) From f47def3588a5fd51d6a8471ed7ea9dbd15526e47 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Sun, 17 Sep 2023 18:40:14 +0300 Subject: [PATCH 2/4] refactoring --- client/CMakeLists.txt | 2 + client/widgets/CArtifactHolder.cpp | 4 +- client/widgets/CArtifactHolder.h | 6 +- client/widgets/CArtifactsOfHeroBackpack.cpp | 2 +- client/widgets/CArtifactsOfHeroBase.cpp | 18 +- client/widgets/CArtifactsOfHeroBase.h | 12 +- client/widgets/CArtifactsOfHeroKingdom.cpp | 4 +- client/widgets/CExchangeController.cpp | 119 +++++++++ client/widgets/CExchangeController.h | 30 +++ client/widgets/CWindowWithArtifacts.cpp | 2 +- client/windows/GUIClasses.cpp | 280 +++----------------- client/windows/GUIClasses.h | 36 +-- lib/ArtifactUtils.cpp | 1 - lib/CArtifactInstance.cpp | 6 - lib/CArtifactInstance.h | 1 - lib/mapping/CMap.cpp | 2 +- lib/mapping/CMap.h | 2 +- 17 files changed, 213 insertions(+), 314 deletions(-) create mode 100644 client/widgets/CExchangeController.cpp create mode 100644 client/widgets/CExchangeController.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index ae542146d..bd05be4d1 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -94,6 +94,7 @@ set(client_SRCS widgets/Buttons.cpp widgets/CArtifactHolder.cpp widgets/CComponent.cpp + widgets/CExchangeController.cpp widgets/CGarrisonInt.cpp widgets/CreatureCostBox.cpp widgets/ComboBox.cpp @@ -255,6 +256,7 @@ set(client_HEADERS widgets/Buttons.h widgets/CArtifactHolder.h widgets/CComponent.h + widgets/CExchangeController.h widgets/CGarrisonInt.h widgets/CreatureCostBox.h widgets/ComboBox.h diff --git a/client/widgets/CArtifactHolder.cpp b/client/widgets/CArtifactHolder.cpp index b53237c9a..afb385b2d 100644 --- a/client/widgets/CArtifactHolder.cpp +++ b/client/widgets/CArtifactHolder.cpp @@ -186,8 +186,8 @@ void CHeroArtPlace::clickPressed(const Point & cursorPosition) void CHeroArtPlace::showPopupWindow(const Point & cursorPosition) { - if(rightClickCallback) - rightClickCallback(*this); + if(showPopupCallback) + showPopupCallback(*this); } void CHeroArtPlace::showAll(Canvas & to) diff --git a/client/widgets/CArtifactHolder.h b/client/widgets/CArtifactHolder.h index d8cc43aba..24995f48f 100644 --- a/client/widgets/CArtifactHolder.h +++ b/client/widgets/CArtifactHolder.h @@ -65,11 +65,11 @@ public: class CHeroArtPlace: public CArtPlace { public: - using ClickHandler = std::function; + using ClickFunctor = std::function; ArtifactPosition slot; - ClickHandler leftClickCallback; - ClickHandler rightClickCallback; + ClickFunctor leftClickCallback; + ClickFunctor showPopupCallback; CHeroArtPlace(Point position, const CArtifactInstance * Art = nullptr); void lockSlot(bool on); diff --git a/client/widgets/CArtifactsOfHeroBackpack.cpp b/client/widgets/CArtifactsOfHeroBackpack.cpp index 20c4c53cc..0b38d5dfa 100644 --- a/client/widgets/CArtifactsOfHeroBackpack.cpp +++ b/client/widgets/CArtifactsOfHeroBackpack.cpp @@ -42,7 +42,7 @@ CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack(const Point & position) artPlace = std::make_shared(pos); artPlace->setArtifact(nullptr); artPlace->leftClickCallback = std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1); - artPlace->rightClickCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1); + artPlace->showPopupCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1); artPlaceIdx++; } diff --git a/client/widgets/CArtifactsOfHeroBase.cpp b/client/widgets/CArtifactsOfHeroBase.cpp index b8d175226..dd0723fd5 100644 --- a/client/widgets/CArtifactsOfHeroBase.cpp +++ b/client/widgets/CArtifactsOfHeroBase.cpp @@ -55,10 +55,10 @@ void CArtifactsOfHeroBase::setPutBackPickedArtifactCallback(PutBackPickedArtCall } void CArtifactsOfHeroBase::init( - CHeroArtPlace::ClickHandler lClickCallback, - CHeroArtPlace::ClickHandler rClickCallback, + CHeroArtPlace::ClickFunctor lClickCallback, + CHeroArtPlace::ClickFunctor showPopupCallback, const Point & position, - BpackScrollHandler scrollHandler) + BpackScrollFunctor scrollCallback) { // CArtifactsOfHeroBase::init may be transform to CArtifactsOfHeroBase::CArtifactsOfHeroBase if OBJECT_CONSTRUCTION_CAPTURING is removed OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); @@ -78,16 +78,16 @@ void CArtifactsOfHeroBase::init( artPlace.second->slot = artPlace.first; artPlace.second->setArtifact(nullptr); artPlace.second->leftClickCallback = lClickCallback; - artPlace.second->rightClickCallback = rClickCallback; + artPlace.second->showPopupCallback = showPopupCallback; } for(auto artPlace : backpack) { artPlace->setArtifact(nullptr); artPlace->leftClickCallback = lClickCallback; - artPlace->rightClickCallback = rClickCallback; + artPlace->showPopupCallback = showPopupCallback; } - leftBackpackRoll = std::make_shared(Point(379, 364), AnimationPath::builtin("hsbtns3.def"), CButton::tooltip(), [scrollHandler]() { scrollHandler(-1); }, EShortcut::MOVE_LEFT); - rightBackpackRoll = std::make_shared(Point(632, 364), AnimationPath::builtin("hsbtns5.def"), CButton::tooltip(), [scrollHandler]() { scrollHandler(+1); }, EShortcut::MOVE_RIGHT); + leftBackpackRoll = std::make_shared(Point(379, 364), AnimationPath::builtin("hsbtns3.def"), CButton::tooltip(), [scrollCallback]() {scrollCallback(-1);}, EShortcut::MOVE_LEFT); + rightBackpackRoll = std::make_shared(Point(632, 364), AnimationPath::builtin("hsbtns5.def"), CButton::tooltip(), [scrollCallback]() {scrollCallback(+1);}, EShortcut::MOVE_RIGHT); leftBackpackRoll->block(true); rightBackpackRoll->block(true); @@ -102,8 +102,8 @@ void CArtifactsOfHeroBase::leftClickArtPlace(CHeroArtPlace & artPlace) void CArtifactsOfHeroBase::rightClickArtPlace(CHeroArtPlace & artPlace) { - if(rightClickCallback) - rightClickCallback(*this, artPlace); + if(showPopupCallback) + showPopupCallback(*this, artPlace); } void CArtifactsOfHeroBase::setHero(const CGHeroInstance * hero) diff --git a/client/widgets/CArtifactsOfHeroBase.h b/client/widgets/CArtifactsOfHeroBase.h index d2d2a9a95..aeacc10fa 100644 --- a/client/widgets/CArtifactsOfHeroBase.h +++ b/client/widgets/CArtifactsOfHeroBase.h @@ -15,15 +15,15 @@ class CArtifactsOfHeroBase : public CIntObject { protected: using ArtPlacePtr = std::shared_ptr; - using BpackScrollHandler = std::function; + using BpackScrollFunctor = std::function; public: using ArtPlaceMap = std::map; - using ClickHandler = std::function; + using ClickFunctor = std::function; using PutBackPickedArtCallback = std::function; - ClickHandler leftClickCallback; - ClickHandler rightClickCallback; + ClickFunctor leftClickCallback; + ClickFunctor showPopupCallback; CArtifactsOfHeroBase(); virtual void putBackPickedArtifact(); @@ -61,8 +61,8 @@ protected: Point(381,296) //18 }; - virtual void init(CHeroArtPlace::ClickHandler lClickCallback, CHeroArtPlace::ClickHandler rClickCallback, - const Point & position, BpackScrollHandler scrollHandler); + virtual void init(CHeroArtPlace::ClickFunctor lClickCallback, CHeroArtPlace::ClickFunctor showPopupCallback, + const Point & position, BpackScrollFunctor scrollCallback); // Assigns an artifacts to an artifact place depending on it's new slot ID virtual void setSlotData(ArtPlacePtr artPlace, const ArtifactPosition & slot, const CArtifactSet & artSet); virtual void scrollBackpackForArtSet(int offset, const CArtifactSet & artSet); diff --git a/client/widgets/CArtifactsOfHeroKingdom.cpp b/client/widgets/CArtifactsOfHeroKingdom.cpp index 96c6f2cf9..ff365e0ef 100644 --- a/client/widgets/CArtifactsOfHeroKingdom.cpp +++ b/client/widgets/CArtifactsOfHeroKingdom.cpp @@ -29,13 +29,13 @@ CArtifactsOfHeroKingdom::CArtifactsOfHeroKingdom(ArtPlaceMap ArtWorn, std::vecto artPlace.second->slot = artPlace.first; artPlace.second->setArtifact(nullptr); artPlace.second->leftClickCallback = std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1); - artPlace.second->rightClickCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1); + artPlace.second->showPopupCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1); } for(auto artPlace : backpack) { artPlace->setArtifact(nullptr); artPlace->leftClickCallback = std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1); - artPlace->rightClickCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1); + artPlace->showPopupCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1); } leftBackpackRoll->addCallback(std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, -1)); rightBackpackRoll->addCallback(std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, +1)); diff --git a/client/widgets/CExchangeController.cpp b/client/widgets/CExchangeController.cpp new file mode 100644 index 000000000..10888ea5b --- /dev/null +++ b/client/widgets/CExchangeController.cpp @@ -0,0 +1,119 @@ +/* + * CExchangeController.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#include "CExchangeController.h" + +#include "../CPlayerInterface.h" + +#include "../widgets/CGarrisonInt.h" + +#include "../../CCallback.h" + +#include "../lib/mapObjects/CGHeroInstance.h" + +CExchangeController::CExchangeController(ObjectInstanceID hero1, ObjectInstanceID hero2) + : left(LOCPLINT->cb->getHero(hero1)) + , right(LOCPLINT->cb->getHero(hero2)) +{ +} + +void CExchangeController::swapArmy() +{ + auto getStacks = [](const CArmedInstance * source) -> std::vector> + { + auto slots = source->Slots(); + return std::vector>(slots.begin(), slots.end()); + }; + + auto leftSlots = getStacks(left); + auto rightSlots = getStacks(right); + + auto i = leftSlots.begin(), j = rightSlots.begin(); + + for(; i != leftSlots.end() && j != rightSlots.end(); i++, j++) + { + LOCPLINT->cb->swapCreatures(left, right, i->first, j->first); + } + + if(i != leftSlots.end()) + { + auto freeSlots = right->getFreeSlots(); + auto slot = freeSlots.begin(); + + for(; i != leftSlots.end() && slot != freeSlots.end(); i++, slot++) + { + LOCPLINT->cb->swapCreatures(left, right, i->first, *slot); + } + } + else if(j != rightSlots.end()) + { + auto freeSlots = left->getFreeSlots(); + auto slot = freeSlots.begin(); + + for(; j != rightSlots.end() && slot != freeSlots.end(); j++, slot++) + { + LOCPLINT->cb->swapCreatures(left, right, *slot, j->first); + } + } +} + +void CExchangeController::moveArmy(bool leftToRight, std::optional heldSlot) +{ + const auto source = leftToRight ? left : right; + const auto target = leftToRight ? right : left; + + if(!heldSlot.has_value()) + { + auto weakestSlot = vstd::minElementByFun(source->Slots(), + [](const std::pair & s) -> int + { + return s.second->getCreatureID().toCreature()->getAIValue(); + }); + heldSlot = weakestSlot->first; + } + LOCPLINT->cb->bulkMoveArmy(source->id, target->id, heldSlot.value()); +} + +void CExchangeController::moveStack(bool leftToRight, SlotID sourceSlot) +{ + const auto source = leftToRight ? left : right; + const auto target = leftToRight ? right : left; + auto creature = source->getCreature(sourceSlot); + + if(creature == nullptr) + return; + + SlotID targetSlot = target->getSlotFor(creature); + if(targetSlot.validSlot()) + { + if(source->stacksCount() == 1 && source->needsLastStack()) + { + LOCPLINT->cb->splitStack(source, target, sourceSlot, targetSlot, + target->getStackCount(targetSlot) + source->getStackCount(sourceSlot) - 1); + } + else + { + LOCPLINT->cb->mergeOrSwapStacks(source, target, sourceSlot, targetSlot); + } + } +} + +void CExchangeController::swapArtifacts(bool equipped, bool baclpack) +{ + LOCPLINT->cb->bulkMoveArtifacts(left->id, right->id, true, equipped, baclpack); +} + +void CExchangeController::moveArtifacts(bool leftToRight, bool equipped, bool baclpack) +{ + const auto source = leftToRight ? left : right; + const auto target = leftToRight ? right : left; + + LOCPLINT->cb->bulkMoveArtifacts(source->id, target->id, false, equipped, baclpack); +} diff --git a/client/widgets/CExchangeController.h b/client/widgets/CExchangeController.h new file mode 100644 index 000000000..928725f1b --- /dev/null +++ b/client/widgets/CExchangeController.h @@ -0,0 +1,30 @@ +/* + * CExchangeController.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + #pragma once + + #include "../windows/CWindowObject.h" + #include "CWindowWithArtifacts.h" + +class CCallback; + +class CExchangeController +{ +public: + CExchangeController(ObjectInstanceID hero1, ObjectInstanceID hero2); + void swapArmy(); + void moveArmy(bool leftToRight, std::optional heldSlot); + void moveStack(bool leftToRight, SlotID sourceSlot); + void swapArtifacts(bool equipped, bool baclpack); + void moveArtifacts(bool leftToRight, bool equipped, bool baclpack); + +private: + const CGHeroInstance * left; + const CGHeroInstance * right; +}; diff --git a/client/widgets/CWindowWithArtifacts.cpp b/client/widgets/CWindowWithArtifacts.cpp index 7725c16c3..e37815019 100644 --- a/client/widgets/CWindowWithArtifacts.cpp +++ b/client/widgets/CWindowWithArtifacts.cpp @@ -38,7 +38,7 @@ void CWindowWithArtifacts::addSet(CArtifactsOfHeroPtr artSet) { auto artSet = artSetWeak.lock(); artSet->leftClickCallback = std::bind(&CWindowWithArtifacts::leftClickArtPlaceHero, this, _1, _2); - artSet->rightClickCallback = std::bind(&CWindowWithArtifacts::rightClickArtPlaceHero, this, _1, _2); + artSet->showPopupCallback = std::bind(&CWindowWithArtifacts::rightClickArtPlaceHero, this, _1, _2); artSet->setPutBackPickedArtifactCallback(artPutBackHandler); }, artSet); } diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 8f7126005..071663af0 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -19,62 +19,40 @@ #include "../CMusicHandler.h" #include "../CPlayerInterface.h" #include "../CVideoHandler.h" -#include "../CServerHandler.h" - -#include "../battle/BattleInterfaceClasses.h" -#include "../battle/BattleInterface.h" #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" -#include "../gui/TextAlignment.h" #include "../gui/Shortcut.h" #include "../gui/WindowHandler.h" #include "../widgets/CComponent.h" #include "../widgets/CGarrisonInt.h" -#include "../widgets/MiscWidgets.h" #include "../widgets/CreatureCostBox.h" #include "../widgets/Buttons.h" #include "../widgets/Slider.h" #include "../widgets/TextControls.h" #include "../widgets/ObjectLists.h" -#include "../lobby/CSavingScreen.h" #include "../render/Canvas.h" #include "../render/CAnimation.h" #include "../render/IRenderHandler.h" -#include "../CMT.h" #include "../../CCallback.h" -#include "../lib/mapObjectConstructors/AObjectTypeHandler.h" #include "../lib/mapObjectConstructors/CObjectClassesHandler.h" #include "../lib/mapObjectConstructors/CommonConstructors.h" #include "../lib/mapObjects/CGHeroInstance.h" #include "../lib/mapObjects/CGMarket.h" -#include "../lib/ArtifactUtils.h" #include "../lib/mapObjects/CGTownInstance.h" #include "../lib/mapObjects/ObjectTemplate.h" #include "../lib/gameState/CGameState.h" -#include "../lib/gameState/InfoAboutArmy.h" #include "../lib/gameState/SThievesGuildInfo.h" -#include "../lib/CArtHandler.h" -#include "../lib/CBuildingHandler.h" -#include "../lib/CConfigHandler.h" -#include "../lib/CCreatureHandler.h" #include "../lib/CGeneralTextHandler.h" #include "../lib/CHeroHandler.h" #include "../lib/GameSettings.h" #include "../lib/CondSh.h" #include "../lib/CSkillHandler.h" -#include "../lib/spells/CSpellHandler.h" #include "../lib/filesystem/Filesystem.h" -#include "../lib/CStopWatch.h" -#include "../lib/CTownHandler.h" -#include "../lib/GameConstants.h" -#include "../lib/bonuses/Bonus.h" -#include "../lib/NetPacksBase.h" -#include "../lib/StartInfo.h" #include "../lib/TextOperations.h" CRecruitmentWindow::CCreatureCard::CCreatureCard(CRecruitmentWindow * window, const CCreature * crea, int totalAmount) @@ -623,223 +601,9 @@ static bool isQuickExchangeLayoutAvailable() return CResourceHandler::get()->existsResource(ImagePath::builtin("SPRITES/" + QUICK_EXCHANGE_BG)); } -CExchangeController::CExchangeController(CExchangeWindow * view, ObjectInstanceID hero1, ObjectInstanceID hero2) - :left(LOCPLINT->cb->getHero(hero1)), right(LOCPLINT->cb->getHero(hero2)), cb(LOCPLINT->cb), view(view) -{ -} - -std::function CExchangeController::onMoveArmyToLeft() -{ - return [&]() { moveArmy(false); }; -} - -std::function CExchangeController::onMoveArmyToRight() -{ - return [&]() { moveArmy(true); }; -} - -std::vector getBackpackArts(const CGHeroInstance * hero) -{ - std::vector result; - - for(auto slot : hero->artifactsInBackpack) - { - result.push_back(slot.artifact); - } - - return result; -} - -std::function CExchangeController::onSwapArtifacts() -{ - return [&]() - { - if(GH.isKeyboardCtrlDown()) - cb->bulkMoveArtifacts(left->id, right->id, true, true, false); - else if(GH.isKeyboardShiftDown()) - cb->bulkMoveArtifacts(left->id, right->id, true, false, true); - else - cb->bulkMoveArtifacts(left->id, right->id, true); - }; -} - -std::function CExchangeController::onMoveArtifactsToLeft() -{ - return [&]() { moveArtifacts(false); }; -} - -std::function CExchangeController::onMoveArtifactsToRight() -{ - return [&]() { moveArtifacts(true); }; -} - -std::vector> getStacks(const CArmedInstance * source) -{ - auto slots = source->Slots(); - - return std::vector>(slots.begin(), slots.end()); -} - -std::function CExchangeController::onSwapArmy() -{ - return [&]() - { - if(left->tempOwner != cb->getPlayerID() - || right->tempOwner != cb->getPlayerID()) - { - return; - } - - auto leftSlots = getStacks(left); - auto rightSlots = getStacks(right); - - auto i = leftSlots.begin(), j = rightSlots.begin(); - - for(; i != leftSlots.end() && j != rightSlots.end(); i++, j++) - { - cb->swapCreatures(left, right, i->first, j->first); - } - - if(i != leftSlots.end()) - { - auto freeSlots = right->getFreeSlots(); - auto slot = freeSlots.begin(); - - for(; i != leftSlots.end() && slot != freeSlots.end(); i++, slot++) - { - cb->swapCreatures(left, right, i->first, *slot); - } - } - else if(j != rightSlots.end()) - { - auto freeSlots = left->getFreeSlots(); - auto slot = freeSlots.begin(); - - for(; j != rightSlots.end() && slot != freeSlots.end(); j++, slot++) - { - cb->swapCreatures(left, right, *slot, j->first); - } - } - }; -} - -std::function CExchangeController::onMoveStackToLeft(SlotID slotID) -{ - return [=]() - { - if(right->tempOwner != cb->getPlayerID()) - { - return; - } - - moveStack(right, left, slotID); - }; -} - -std::function CExchangeController::onMoveStackToRight(SlotID slotID) -{ - return [=]() - { - if(left->tempOwner != cb->getPlayerID()) - { - return; - } - - moveStack(left, right, slotID); - }; -} - -void CExchangeController::moveStack( - const CGHeroInstance * source, - const CGHeroInstance * target, - SlotID sourceSlot) -{ - auto creature = source->getCreature(sourceSlot); - if(creature == nullptr) - return; - - SlotID targetSlot = target->getSlotFor(creature); - - if(targetSlot.validSlot()) - { - if(source->stacksCount() == 1 && source->needsLastStack()) - { - cb->splitStack( - source, - target, - sourceSlot, - targetSlot, - target->getStackCount(targetSlot) + source->getStackCount(sourceSlot) - 1); - } - else - { - cb->mergeOrSwapStacks(source, target, sourceSlot, targetSlot); - } - } -} - -void CExchangeController::moveArmy(bool leftToRight) -{ - const CGHeroInstance * source = leftToRight ? left : right; - const CGHeroInstance * target = leftToRight ? right : left; - const CGarrisonSlot * selection = this->view->getSelectedSlotID(); - SlotID slot; - - if(source->tempOwner != cb->getPlayerID()) - { - return; - } - - if(selection && selection->our() && selection->getObj() == source) - { - slot = selection->getSlot(); - } - else - { - auto weakestSlot = vstd::minElementByFun( - source->Slots(), - [](const std::pair & s) -> int - { - return s.second->getCreatureID().toCreature()->getAIValue(); - }); - - slot = weakestSlot->first; - } - - cb->bulkMoveArmy(source->id, target->id, slot); -} - -void CExchangeController::moveArtifacts(bool leftToRight) -{ - const CGHeroInstance * source = leftToRight ? left : right; - const CGHeroInstance * target = leftToRight ? right : left; - - if(source->tempOwner != cb->getPlayerID()) - return; - - if(GH.isKeyboardCtrlDown()) - cb->bulkMoveArtifacts(source->id, target->id, false, true, false); - else if(GH.isKeyboardShiftDown()) - cb->bulkMoveArtifacts(source->id, target->id, false, false, true); - else - cb->bulkMoveArtifacts(source->id, target->id, false); -} - -void CExchangeController::moveArtifact( - const CGHeroInstance * source, - const CGHeroInstance * target, - ArtifactPosition srcPosition) -{ - auto srcLocation = ArtifactLocation(source, srcPosition); - auto dstLocation = ArtifactLocation(target, - ArtifactUtils::getArtAnyPosition(target, source->getArt(srcPosition)->getTypeId())); - - cb->swapArtifacts(srcLocation, dstLocation); -} - CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID) : CStatusbarWindow(PLAYER_COLORED | BORDERED, ImagePath::builtin(isQuickExchangeLayoutAvailable() ? QUICK_EXCHANGE_BG : "TRADE2")), - controller(this, hero1, hero2), + controller(hero1, hero2), moveStackLeftButtons(), moveStackRightButtons() { @@ -990,12 +754,38 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, if(qeLayout) { - moveAllGarrButtonLeft = std::make_shared(Point(325, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/armRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), controller.onMoveArmyToRight()); - echangeGarrButton = std::make_shared(Point(377, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[2]), controller.onSwapArmy()); - moveAllGarrButtonRight = std::make_shared(Point(425, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/armLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), controller.onMoveArmyToLeft()); - moveArtifactsButtonLeft = std::make_shared(Point(325, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/artRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]), controller.onMoveArtifactsToRight()); - echangeArtifactsButton = std::make_shared(Point(377, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[4]), controller.onSwapArtifacts()); - moveArtifactsButtonRight = std::make_shared(Point(425, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/artLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]), controller.onMoveArtifactsToLeft()); + auto moveArtifacts = [this](std::function moveRoutine) -> void + { + bool moveEquipped = true; + bool moveBackpack = true; + + if(GH.isKeyboardCtrlDown()) + moveBackpack = false; + else if(GH.isKeyboardShiftDown()) + moveEquipped = false; + moveRoutine(moveEquipped, moveBackpack); + }; + + auto moveArmy = [this](bool leftToRight) -> void + { + std::optional slotId = std::nullopt; + if(auto slot = getSelectedSlotID()) + slotId = slot->getSlot(); + controller.moveArmy(leftToRight, slotId); + }; + + moveAllGarrButtonLeft = std::make_shared(Point(325, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/armRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), + std::bind(moveArmy, true)); + echangeGarrButton = std::make_shared(Point(377, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[2]), + std::bind(&CExchangeController::swapArmy, &controller)); + moveAllGarrButtonRight = std::make_shared(Point(425, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/armLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), + std::bind(moveArmy, false)); + moveArtifactsButtonLeft = std::make_shared(Point(325, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/artRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]), + std::bind(moveArtifacts, [this](bool equipped, bool baclpack) -> void {controller.moveArtifacts(true, equipped, baclpack);})); + echangeArtifactsButton = std::make_shared(Point(377, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[4]), + std::bind(moveArtifacts, [this](bool equipped, bool baclpack) -> void {controller.swapArtifacts(equipped, baclpack);})); + moveArtifactsButtonRight = std::make_shared(Point(425, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/artLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]), + std::bind(moveArtifacts, [this](bool equipped, bool baclpack) -> void {controller.moveArtifacts(false, equipped, baclpack);})); for(int i = 0; i < GameConstants::ARMY_SIZE; i++) { @@ -1004,14 +794,14 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, Point(484 + 35 * i, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/unitLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), - controller.onMoveStackToLeft(SlotID(i)))); + std::bind(&CExchangeController::moveStack, &controller, false, SlotID(i)))); moveStackRightButtons.push_back( std::make_shared( Point(66 + 35 * i, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/unitRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), - controller.onMoveStackToRight(SlotID(i)))); + std::bind(&CExchangeController::moveStack, &controller, true, SlotID(i)))); } } diff --git a/client/windows/GUIClasses.h b/client/windows/GUIClasses.h index fa1484d10..a94dd3b43 100644 --- a/client/windows/GUIClasses.h +++ b/client/windows/GUIClasses.h @@ -9,10 +9,8 @@ */ #pragma once -#include "CWindowObject.h" -#include "../lib/GameConstants.h" #include "../lib/ResourceSet.h" -#include "../lib/int3.h" +#include "../widgets/CExchangeController.h" #include "../widgets/CWindowWithArtifacts.h" #include "../widgets/Images.h" @@ -28,16 +26,13 @@ class CreatureCostBox; class CCreaturePic; class MoraleLuckBox; class CHeroArea; -class CMinorResDataBar; class CSlider; class CComponentBox; class CTextInput; class CListBox; class CLabelGroup; -class CToggleButton; class CGStatusBar; class CTextBox; -class CResDataBar; class CGarrisonInt; class CGarrisonSlot; @@ -246,35 +241,6 @@ public: void show(Canvas & to) override; }; -class CCallback; -class CExchangeWindow; - -class CExchangeController -{ -private: - const CGHeroInstance * left; - const CGHeroInstance * right; - std::shared_ptr cb; - CExchangeWindow * view; - -public: - CExchangeController(CExchangeWindow * view, ObjectInstanceID hero1, ObjectInstanceID hero2); - std::function onMoveArmyToRight(); - std::function onSwapArmy(); - std::function onMoveArmyToLeft(); - std::function onSwapArtifacts(); - std::function onMoveArtifactsToLeft(); - std::function onMoveArtifactsToRight(); - std::function onMoveStackToLeft(SlotID slotID); - std::function onMoveStackToRight(SlotID slotID); - -private: - void moveArmy(bool leftToRight); - void moveArtifacts(bool leftToRight); - void moveArtifact(const CGHeroInstance * source, const CGHeroInstance * target, ArtifactPosition srcPosition); - void moveStack(const CGHeroInstance * source, const CGHeroInstance * target, SlotID sourceSlot); -}; - class CExchangeWindow : public CStatusbarWindow, public IGarrisonHolder, public CWindowWithArtifacts { std::array, 2> titles; diff --git a/lib/ArtifactUtils.cpp b/lib/ArtifactUtils.cpp index eeb94c2c6..ba8c7823a 100644 --- a/lib/ArtifactUtils.cpp +++ b/lib/ArtifactUtils.cpp @@ -171,7 +171,6 @@ DLL_LINKAGE CArtifactInstance * ArtifactUtils::createNewArtifactInstance(CArtifa auto * artInst = new CArtifactInstance(art); if(art->isCombined()) { - assert(art->isCombined()); for(const auto & part : art->getConstituents()) artInst->addPart(ArtifactUtils::createNewArtifactInstance(part), ArtifactPosition::PRE_FIRST); } diff --git a/lib/CArtifactInstance.cpp b/lib/CArtifactInstance.cpp index 2c99d90b8..13ca20d64 100644 --- a/lib/CArtifactInstance.cpp +++ b/lib/CArtifactInstance.cpp @@ -44,12 +44,6 @@ bool CCombinedArtifactInstance::isPart(const CArtifactInstance * supposedPart) c return false; } -std::vector & CCombinedArtifactInstance::getPartsInfo() -{ - // TODO romove this func. encapsulation violation - return partsInfo; -} - const std::vector & CCombinedArtifactInstance::getPartsInfo() const { return partsInfo; diff --git a/lib/CArtifactInstance.h b/lib/CArtifactInstance.h index 30ef2865b..2c87adf08 100644 --- a/lib/CArtifactInstance.h +++ b/lib/CArtifactInstance.h @@ -38,7 +38,6 @@ public: void addPart(CArtifactInstance * art, const ArtifactPosition & slot); // Checks if supposed part inst is part of this combined art inst bool isPart(const CArtifactInstance * supposedPart) const; - std::vector & getPartsInfo(); const std::vector & getPartsInfo() const; void addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap); diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index 2d1de817f..811a52e02 100644 --- a/lib/mapping/CMap.cpp +++ b/lib/mapping/CMap.cpp @@ -492,7 +492,7 @@ void CMap::checkForObjectives() } } -void CMap::addNewArtifactInstance(CArtifactInstance * art) +void CMap::addNewArtifactInstance(ConstTransitivePtr art) { art->setId(static_cast(artInstances.size())); artInstances.emplace_back(art); diff --git a/lib/mapping/CMap.h b/lib/mapping/CMap.h index 4e3402eb5..c3cd0bfdb 100644 --- a/lib/mapping/CMap.h +++ b/lib/mapping/CMap.h @@ -94,7 +94,7 @@ public: void removeBlockVisTiles(CGObjectInstance * obj, bool total = false); void calculateGuardingGreaturePositions(); - void addNewArtifactInstance(CArtifactInstance * art); + void addNewArtifactInstance(ConstTransitivePtr art); void eraseArtifactInstance(CArtifactInstance * art); void addNewQuestInstance(CQuest * quest); From 9cc623c981aa87ca1c7d83c2096af2c60d468282 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Mon, 18 Sep 2023 22:58:08 +0300 Subject: [PATCH 3/4] Fixed move checks. Backpack buttons. --- client/widgets/CWindowWithArtifacts.cpp | 7 ++++- client/widgets/CWindowWithArtifacts.h | 3 +- client/windows/CHeroBackpackWindow.cpp | 2 +- client/windows/CHeroWindow.cpp | 2 +- client/windows/CKingdomInterface.cpp | 2 +- client/windows/CTradeWindow.cpp | 4 +-- client/windows/GUIClasses.cpp | 39 +++++++++++++++++++++---- client/windows/GUIClasses.h | 6 ++-- server/NetPacksServer.cpp | 4 ++- 9 files changed, 53 insertions(+), 16 deletions(-) diff --git a/client/widgets/CWindowWithArtifacts.cpp b/client/widgets/CWindowWithArtifacts.cpp index e37815019..0b42a1ca2 100644 --- a/client/widgets/CWindowWithArtifacts.cpp +++ b/client/widgets/CWindowWithArtifacts.cpp @@ -27,13 +27,18 @@ #include "../../lib/mapObjects/CGHeroInstance.h" void CWindowWithArtifacts::addSet(CArtifactsOfHeroPtr artSet) +{ + artSets.emplace_back(artSet); +} + +void CWindowWithArtifacts::addSetAndCallbacks(CArtifactsOfHeroPtr artSet) { CArtifactsOfHeroBase::PutBackPickedArtCallback artPutBackHandler = []() -> void { CCS->curh->dragAndDropCursor(nullptr); }; - artSets.emplace_back(artSet); + addSet(artSet); std::visit([this, artPutBackHandler](auto artSetWeak) { auto artSet = artSetWeak.lock(); diff --git a/client/widgets/CWindowWithArtifacts.h b/client/widgets/CWindowWithArtifacts.h index 85067e244..f603ad7f5 100644 --- a/client/widgets/CWindowWithArtifacts.h +++ b/client/widgets/CWindowWithArtifacts.h @@ -28,6 +28,7 @@ public: using CloseCallback = std::function; void addSet(CArtifactsOfHeroPtr artSet); + void addSetAndCallbacks(CArtifactsOfHeroPtr artSet); void addCloseCallback(CloseCallback callback); const CGHeroInstance * getHeroPickedArtifact(); const CArtifactInstance * getPickedArtifact(); @@ -39,7 +40,7 @@ public: void artifactDisassembled(const ArtifactLocation & artLoc) override; void artifactAssembled(const ArtifactLocation & artLoc) override; -private: +protected: std::vector artSets; CloseCallback closeCallback; diff --git a/client/windows/CHeroBackpackWindow.cpp b/client/windows/CHeroBackpackWindow.cpp index 6f4203970..a4ff6d1c8 100644 --- a/client/windows/CHeroBackpackWindow.cpp +++ b/client/windows/CHeroBackpackWindow.cpp @@ -28,7 +28,7 @@ CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero) arts = std::make_shared(Point(windowMargin, windowMargin)); arts->setHero(hero); - addSet(arts); + addSetAndCallbacks(arts); addCloseCallback(std::bind(&CHeroBackpackWindow::close, this)); diff --git a/client/windows/CHeroWindow.cpp b/client/windows/CHeroWindow.cpp index 588785b58..5e80706e8 100644 --- a/client/windows/CHeroWindow.cpp +++ b/client/windows/CHeroWindow.cpp @@ -219,7 +219,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded) { arts = std::make_shared(Point(-65, -8)); arts->setHero(curHero); - addSet(arts); + addSetAndCallbacks(arts); } int serial = LOCPLINT->cb->getHeroSerial(curHero, false); diff --git a/client/windows/CKingdomInterface.cpp b/client/windows/CKingdomInterface.cpp index 4bcae8c91..a844b9ace 100644 --- a/client/windows/CKingdomInterface.cpp +++ b/client/windows/CKingdomInterface.cpp @@ -706,7 +706,7 @@ std::shared_ptr CKingdHeroList::createHeroItem(size_t index) if(index < heroesList.size()) { auto hero = std::make_shared(heroesList[index]); - addSet(hero->heroArts); + addSetAndCallbacks(hero->heroArts); return hero; } else diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index 74a24ced9..f377b1eb8 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -680,7 +680,7 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInsta arts = std::make_shared(Point(-361, 46)); arts->selectArtCallback = std::bind(&CTradeWindow::artifactSelected, this, _1); arts->setHero(hero); - addSet(arts); + addSetAndCallbacks(arts); } initItems(false); initItems(true); @@ -1115,7 +1115,7 @@ CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero, arts = std::make_shared(Point(-365, -12)); arts->setHero(hero); - addSet(arts); + addSetAndCallbacks(arts); initItems(true); initItems(false); diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 071663af0..76a9d8a2c 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -12,6 +12,7 @@ #include "CCastleInterface.h" #include "CCreatureWindow.h" +#include "CHeroBackpackWindow.h" #include "CHeroWindow.h" #include "InfoWindows.h" @@ -662,8 +663,8 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, artifs[1] = std::make_shared(Point(98, 150)); artifs[1]->setHero(heroInst[1]); - addSet(artifs[0]); - addSet(artifs[1]); + addSetAndCallbacks(artifs[0]); + addSetAndCallbacks(artifs[1]); for(int g=0; g<4; ++g) { @@ -754,7 +755,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, if(qeLayout) { - auto moveArtifacts = [this](std::function moveRoutine) -> void + auto moveArtifacts = [this](const std::function moveRoutine) -> void { bool moveEquipped = true; bool moveBackpack = true; @@ -766,7 +767,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, moveRoutine(moveEquipped, moveBackpack); }; - auto moveArmy = [this](bool leftToRight) -> void + auto moveArmy = [this](const bool leftToRight) -> void { std::optional slotId = std::nullopt; if(auto slot = getSelectedSlotID()) @@ -774,18 +775,42 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, controller.moveArmy(leftToRight, slotId); }; + auto openBackpack = [this](const CGHeroInstance * hero) -> void + { + GH.windows().createAndPushWindow(hero); + for(auto artSet : artSets) + GH.windows().topWindow()->addSet(artSet); + }; + moveAllGarrButtonLeft = std::make_shared(Point(325, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/armRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), std::bind(moveArmy, true)); - echangeGarrButton = std::make_shared(Point(377, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[2]), + exchangeGarrButton = std::make_shared(Point(377, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[2]), std::bind(&CExchangeController::swapArmy, &controller)); moveAllGarrButtonRight = std::make_shared(Point(425, 118), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/armLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), std::bind(moveArmy, false)); moveArtifactsButtonLeft = std::make_shared(Point(325, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/artRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]), std::bind(moveArtifacts, [this](bool equipped, bool baclpack) -> void {controller.moveArtifacts(true, equipped, baclpack);})); - echangeArtifactsButton = std::make_shared(Point(377, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[4]), + exchangeArtifactsButton = std::make_shared(Point(377, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/swapAll.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[4]), std::bind(moveArtifacts, [this](bool equipped, bool baclpack) -> void {controller.swapArtifacts(equipped, baclpack);})); moveArtifactsButtonRight = std::make_shared(Point(425, 154), AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/artLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[3]), std::bind(moveArtifacts, [this](bool equipped, bool baclpack) -> void {controller.moveArtifacts(false, equipped, baclpack);})); + backpackButtonLeft = std::make_shared(Point(325, 518), AnimationPath::builtin("buttons/backpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"), + std::bind(openBackpack, heroInst[0])); + backpackButtonLeft->addOverlay(std::make_shared(ImagePath::builtin("buttons/backpackButtonIcon"))); + backpackButtonRight = std::make_shared(Point(419, 518), AnimationPath::builtin("buttons/backpack"), CButton::tooltipLocalized("vcmi.heroWindow.openBackpack"), + std::bind(openBackpack, heroInst[1])); + backpackButtonRight->addOverlay(std::make_shared(ImagePath::builtin("buttons/backpackButtonIcon"))); + + auto leftHeroBlock = heroInst[0]->tempOwner != LOCPLINT->cb->getPlayerID(); + auto rightHeroBlock = heroInst[1]->tempOwner != LOCPLINT->cb->getPlayerID(); + moveAllGarrButtonLeft->block(leftHeroBlock); + exchangeGarrButton->block(leftHeroBlock || rightHeroBlock); + moveAllGarrButtonRight->block(rightHeroBlock); + moveArtifactsButtonLeft->block(leftHeroBlock); + exchangeArtifactsButton->block(leftHeroBlock || rightHeroBlock); + moveArtifactsButtonRight->block(rightHeroBlock); + backpackButtonLeft->block(leftHeroBlock); + backpackButtonRight->block(rightHeroBlock); for(int i = 0; i < GameConstants::ARMY_SIZE; i++) { @@ -795,6 +820,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/unitLeft.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), std::bind(&CExchangeController::moveStack, &controller, false, SlotID(i)))); + moveStackLeftButtons.back()->block(leftHeroBlock); moveStackRightButtons.push_back( std::make_shared( @@ -802,6 +828,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, AnimationPath::builtin(QUICK_EXCHANGE_MOD_PREFIX + "/unitRight.DEF"), CButton::tooltip(CGI->generaltexth->qeModCommands[1]), std::bind(&CExchangeController::moveStack, &controller, true, SlotID(i)))); + moveStackLeftButtons.back()->block(rightHeroBlock); } } diff --git a/client/windows/GUIClasses.h b/client/windows/GUIClasses.h index a94dd3b43..a73669570 100644 --- a/client/windows/GUIClasses.h +++ b/client/windows/GUIClasses.h @@ -269,13 +269,15 @@ class CExchangeWindow : public CStatusbarWindow, public IGarrisonHolder, public std::shared_ptr garr; std::shared_ptr moveAllGarrButtonLeft; - std::shared_ptr echangeGarrButton; + std::shared_ptr exchangeGarrButton; std::shared_ptr moveAllGarrButtonRight; std::shared_ptr moveArtifactsButtonLeft; - std::shared_ptr echangeArtifactsButton; + std::shared_ptr exchangeArtifactsButton; std::shared_ptr moveArtifactsButtonRight; std::vector> moveStackLeftButtons; std::vector> moveStackRightButtons; + std::shared_ptr backpackButtonLeft; + std::shared_ptr backpackButtonRight; CExchangeController controller; public: diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index 286935383..0035da264 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -68,7 +68,7 @@ void ApplyGhNetPackVisitor::visitArrangeStacks(ArrangeStacks & pack) void ApplyGhNetPackVisitor::visitBulkMoveArmy(BulkMoveArmy & pack) { - gh.throwIfWrongPlayer(&pack); + gh.throwIfWrongOwner(&pack, pack.srcArmy); result = gh.bulkMoveArmy(pack.srcArmy, pack.destArmy, pack.srcSlot); } @@ -132,6 +132,8 @@ void ApplyGhNetPackVisitor::visitExchangeArtifacts(ExchangeArtifacts & pack) void ApplyGhNetPackVisitor::visitBulkExchangeArtifacts(BulkExchangeArtifacts & pack) { gh.throwIfWrongOwner(&pack, pack.srcHero); + if(pack.swap) + gh.throwIfWrongOwner(&pack, pack.dstHero); result = gh.bulkMoveArtifacts(pack.srcHero, pack.dstHero, pack.swap, pack.equipped, pack.backpack); } From 6280e778dccb51c7109adbd940e78202088a2d6f Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Tue, 19 Sep 2023 14:10:25 +0300 Subject: [PATCH 4/4] fix build --- client/widgets/CExchangeController.cpp | 2 +- client/windows/GUIClasses.cpp | 2 +- lib/CArtifactInstance.cpp | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client/widgets/CExchangeController.cpp b/client/widgets/CExchangeController.cpp index 10888ea5b..23c9019d8 100644 --- a/client/widgets/CExchangeController.cpp +++ b/client/widgets/CExchangeController.cpp @@ -7,7 +7,7 @@ * Full text of license available in license.txt file, in main folder * */ - +#include "StdInc.h" #include "CExchangeController.h" #include "../CPlayerInterface.h" diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 76a9d8a2c..419dea97f 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -755,7 +755,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, if(qeLayout) { - auto moveArtifacts = [this](const std::function moveRoutine) -> void + auto moveArtifacts = [](const std::function moveRoutine) -> void { bool moveEquipped = true; bool moveBackpack = true; diff --git a/lib/CArtifactInstance.cpp b/lib/CArtifactInstance.cpp index 13ca20d64..8c178eda0 100644 --- a/lib/CArtifactInstance.cpp +++ b/lib/CArtifactInstance.cpp @@ -52,7 +52,7 @@ const std::vector & CCombinedArtifactInstan void CCombinedArtifactInstance::addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap) { if(!placementMap.empty()) - for(auto& part : partsInfo) + for(auto & part : partsInfo) { assert(placementMap.find(part.art) != placementMap.end()); part.slot = placementMap.at(part.art); @@ -167,7 +167,8 @@ bool CArtifactInstance::isCombined() const void CArtifactInstance::putAt(const ArtifactLocation & al) { - addPlacementMap(al.getHolderArtSet()->putArtifact(al.slot, this)); + auto placementMap = al.getHolderArtSet()->putArtifact(al.slot, this); + addPlacementMap(placementMap); } void CArtifactInstance::removeFrom(const ArtifactLocation & al)