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)