From b9ae7f11380892b73b5360165bb01abc384285cf Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:59:40 +0300 Subject: [PATCH 1/2] CMap put move and remove artifact method --- client/Client.h | 2 +- client/widgets/CArtifactsOfHeroBase.cpp | 4 +-- client/widgets/CArtifactsOfHeroBase.h | 2 +- client/windows/CWindowWithArtifacts.cpp | 9 ++---- lib/CArtifactInstance.cpp | 28 ++--------------- lib/CArtifactInstance.h | 7 ++--- lib/IGameCallback.h | 2 +- lib/gameState/CGameState.cpp | 2 +- lib/gameState/CGameStateCampaign.cpp | 8 ++--- lib/mapObjects/CGHeroInstance.cpp | 2 +- lib/mapObjects/MiscObjects.cpp | 7 ++--- lib/mapping/CMap.cpp | 28 +++++++++++++++++ lib/mapping/CMap.h | 3 ++ lib/mapping/MapFormatH3M.cpp | 2 +- lib/networkPacks/NetPacksLib.cpp | 42 ++++++++++--------------- lib/networkPacks/PacksForClient.h | 8 ++--- server/CGameHandler.cpp | 14 ++++----- server/CGameHandler.h | 2 +- test/mock/mock_IGameCallback.h | 2 +- 19 files changed, 84 insertions(+), 90 deletions(-) diff --git a/client/Client.h b/client/Client.h index d63f70578..6c34809b4 100644 --- a/client/Client.h +++ b/client/Client.h @@ -188,7 +188,7 @@ public: bool swapGarrisonOnSiege(ObjectInstanceID tid) override {return false;}; bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) override {return false;}; bool giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override {return false;}; - bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional askAssemble) override {return false;}; + bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional askAssemble) override {return false;}; void removeArtifact(const ArtifactLocation & al) override {}; bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;}; diff --git a/client/widgets/CArtifactsOfHeroBase.cpp b/client/widgets/CArtifactsOfHeroBase.cpp index c44e3d01f..70f277b8e 100644 --- a/client/widgets/CArtifactsOfHeroBase.cpp +++ b/client/widgets/CArtifactsOfHeroBase.cpp @@ -137,9 +137,9 @@ void CArtifactsOfHeroBase::scrollBackpack(bool left) LOCPLINT->cb->scrollBackpackArtifacts(curHero->id, left); } -void CArtifactsOfHeroBase::markPossibleSlots(const CArtifactInstance * art, bool assumeDestRemoved) +void CArtifactsOfHeroBase::markPossibleSlots(const CArtifact * art, bool assumeDestRemoved) { - for(auto artPlace : artWorn) + for(const auto & artPlace : artWorn) artPlace.second->selectSlot(art->canBePutAt(curHero, artPlace.second->slot, assumeDestRemoved)); } diff --git a/client/widgets/CArtifactsOfHeroBase.h b/client/widgets/CArtifactsOfHeroBase.h index c4cb83e33..7aaaf5ce3 100644 --- a/client/widgets/CArtifactsOfHeroBase.h +++ b/client/widgets/CArtifactsOfHeroBase.h @@ -39,7 +39,7 @@ public: virtual void setHero(const CGHeroInstance * hero); virtual const CGHeroInstance * getHero() const; virtual void scrollBackpack(bool left); - virtual void markPossibleSlots(const CArtifactInstance * art, bool assumeDestRemoved = true); + virtual void markPossibleSlots(const CArtifact * art, bool assumeDestRemoved = true); virtual void unmarkSlots(); virtual ArtPlacePtr getArtPlace(const ArtifactPosition & slot); virtual ArtPlacePtr getArtPlace(const Point & cursorPosition); diff --git a/client/windows/CWindowWithArtifacts.cpp b/client/windows/CWindowWithArtifacts.cpp index 24daa3d1c..6561f23d2 100644 --- a/client/windows/CWindowWithArtifacts.cpp +++ b/client/windows/CWindowWithArtifacts.cpp @@ -62,15 +62,12 @@ const CGHeroInstance * CWindowWithArtifacts::getHeroPickedArtifact() const const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact() const { - const CArtifactInstance * art = nullptr; - for(const auto & artSet : artSets) if(const auto pickedArt = artSet->getHero()->getArt(ArtifactPosition::TRANSITION_POS)) { - art = pickedArt; - break; + return pickedArt; } - return art; + return nullptr; } void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance * hero, const ArtifactPosition & slot, @@ -202,7 +199,7 @@ void CWindowWithArtifacts::markPossibleSlots() const continue; if(getHeroPickedArtifact() == hero || !std::dynamic_pointer_cast(artSet)) - artSet->markPossibleSlots(pickedArtInst, hero->tempOwner == LOCPLINT->playerID); + artSet->markPossibleSlots(pickedArtInst->artType, hero->tempOwner == LOCPLINT->playerID); } } } diff --git a/lib/CArtifactInstance.cpp b/lib/CArtifactInstance.cpp index 0451e2d2f..6f191e46b 100644 --- a/lib/CArtifactInstance.cpp +++ b/lib/CArtifactInstance.cpp @@ -49,13 +49,13 @@ const std::vector & CCombinedArtifactInstan return partsInfo; } -void CCombinedArtifactInstance::addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap) +void CCombinedArtifactInstance::addPlacementMap(const CArtifactSet::ArtPlacementMap & placementMap) { if(!placementMap.empty()) for(auto & part : partsInfo) { - assert(placementMap.find(part.art) != placementMap.end()); - part.slot = placementMap.at(part.art); + if(placementMap.find(part.art) != placementMap.end()) + part.slot = placementMap.at(part.art); } } @@ -167,28 +167,6 @@ bool CArtifactInstance::isScroll() const return artType->isScroll(); } -void CArtifactInstance::putAt(CArtifactSet & set, const ArtifactPosition slot) -{ - auto placementMap = set.putArtifact(slot, this); - addPlacementMap(placementMap); -} - -void CArtifactInstance::removeFrom(CArtifactSet & set, const ArtifactPosition slot) -{ - set.removeArtifact(slot); - for(auto & part : partsInfo) - { - if(part.slot != ArtifactPosition::PRE_FIRST) - part.slot = ArtifactPosition::PRE_FIRST; - } -} - -void CArtifactInstance::move(CArtifactSet & srcSet, const ArtifactPosition srcSlot, CArtifactSet & dstSet, const ArtifactPosition dstSlot) -{ - removeFrom(srcSet, srcSlot); - putAt(dstSet, dstSlot); -} - void CArtifactInstance::deserializationFix() { setType(artType); diff --git a/lib/CArtifactInstance.h b/lib/CArtifactInstance.h index 7c100a91f..f679f8b44 100644 --- a/lib/CArtifactInstance.h +++ b/lib/CArtifactInstance.h @@ -25,7 +25,7 @@ protected: public: struct PartInfo { - ConstTransitivePtr art; + CArtifactInstance * art; ArtifactPosition slot; template void serialize(Handler & h) { @@ -39,7 +39,7 @@ public: // Checks if supposed part inst is part of this combined art inst bool isPart(const CArtifactInstance * supposedPart) const; const std::vector & getPartsInfo() const; - void addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap); + void addPlacementMap(const CArtifactSet::ArtPlacementMap & placementMap); template void serialize(Handler & h) { @@ -88,9 +88,6 @@ public: bool assumeDestRemoved = false) const; bool isCombined() const; bool isScroll() const; - void putAt(CArtifactSet & set, const ArtifactPosition slot); - void removeFrom(CArtifactSet & set, const ArtifactPosition slot); - void move(CArtifactSet & srcSet, const ArtifactPosition srcSlot, CArtifactSet & dstSet, const ArtifactPosition dstSlot); void deserializationFix(); template void serialize(Handler & h) diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index a9cc7b655..c2ff9e26c 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -122,7 +122,7 @@ public: virtual bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) = 0; virtual bool giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) = 0; - virtual bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional askAssemble = std::nullopt) = 0; + virtual bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional askAssemble = std::nullopt) = 0; virtual void removeArtifact(const ArtifactLocation& al) = 0; virtual bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) = 0; diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 31bd4e2de..13d361289 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -1638,7 +1638,7 @@ bool CGameState::giveHeroArtifact(CGHeroInstance * h, const ArtifactID & aid) auto slot = ArtifactUtils::getArtAnyPosition(h, aid); if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot)) { - ai->putAt(*h, slot); + map->putArtifactInstance(*h, ai, slot); return true; } else diff --git a/lib/gameState/CGameStateCampaign.cpp b/lib/gameState/CGameStateCampaign.cpp index 8705d2d6f..703f97667 100644 --- a/lib/gameState/CGameStateCampaign.cpp +++ b/lib/gameState/CGameStateCampaign.cpp @@ -147,7 +147,7 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr if (!locked && !takeable) { logGlobal->debug("Removing artifact %s from slot %d of hero %s", art->artType->getJsonKey(), al.slot.getNum(), hero.hero->getHeroTypeName()); - hero.hero->getArt(al.slot)->removeFrom(*hero.hero, al.slot); + gameState->map->removeArtifactInstance(*hero.hero, al.slot); return true; } return false; @@ -327,7 +327,7 @@ void CGameStateCampaign::giveCampaignBonusToHero(CGHeroInstance * hero) CArtifactInstance * scroll = ArtifactUtils::createScroll(SpellID(curBonus->info2)); const auto slot = ArtifactUtils::getArtAnyPosition(hero, scroll->getTypeId()); if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot)) - scroll->putAt(*hero, slot); + gameState->map->putArtifactInstance(*hero, scroll, slot); else logGlobal->error("Cannot give starting scroll - no free slots!"); break; @@ -423,7 +423,7 @@ void CGameStateCampaign::transferMissingArtifacts(const CampaignTravel & travelO auto * artifact = donorHero->getArt(artLocation); logGlobal->debug("Removing artifact %s from slot %d of hero %s for transfer", artifact->artType->getJsonKey(), artLocation.getNum(), donorHero->getHeroTypeName()); - artifact->removeFrom(*donorHero, artLocation); + gameState->map->removeArtifactInstance(*donorHero, artLocation); if (receiver) { @@ -431,7 +431,7 @@ void CGameStateCampaign::transferMissingArtifacts(const CampaignTravel & travelO const auto slot = ArtifactUtils::getArtAnyPosition(receiver, artifact->getTypeId()); if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot)) - artifact->putAt(*receiver, slot); + gameState->map->putArtifactInstance(*receiver, artifact, slot); else logGlobal->error("Cannot transfer artifact - no free slots!"); } diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 8cf3871b0..0a7b84596 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -1201,7 +1201,7 @@ void CGHeroInstance::removeSpellbook() if(hasSpellbook()) { - getArt(ArtifactPosition::SPELLBOOK)->removeFrom(*this, ArtifactPosition::SPELLBOOK); + //VLC->arth->removeArtifactFrom(*this, ArtifactPosition::SPELLBOOK); } } diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index ab5fc3d50..9c01e64aa 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -772,9 +772,8 @@ void CGArtifact::initObj(vstd::RNG & rand) { if (!storedArtifact) { - auto * a = new CArtifactInstance(); - cb->gameState()->map->addNewArtifactInstance(a); - storedArtifact = a; + storedArtifact = ArtifactUtils::createArtifact(ArtifactID()); + cb->gameState()->map->addNewArtifactInstance(storedArtifact); } if(!storedArtifact->artType) storedArtifact->setType(getArtifact().toArtifact()); @@ -901,7 +900,7 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const void CGArtifact::pick(const CGHeroInstance * h) const { - if(cb->putArtifact(ArtifactLocation(h->id, ArtifactPosition::FIRST_AVAILABLE), storedArtifact)) + if(cb->putArtifact(ArtifactLocation(h->id, ArtifactPosition::FIRST_AVAILABLE), storedArtifact->getId())) cb->removeObject(this, h->getOwner()); } diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index ee0948ee5..77af471b0 100644 --- a/lib/mapping/CMap.cpp +++ b/lib/mapping/CMap.cpp @@ -552,6 +552,34 @@ void CMap::eraseArtifactInstance(CArtifactInstance * art) artInstances[art->getId().getNum()].dellNull(); } +void CMap::moveArtifactInstance( + CArtifactSet & srcSet, const ArtifactPosition & srcSlot, + CArtifactSet & dstSet, const ArtifactPosition & dstSlot) +{ + auto art = srcSet.getArt(srcSlot); + removeArtifactInstance(srcSet, srcSlot); + putArtifactInstance(dstSet, art, dstSlot); +} + +void CMap::putArtifactInstance(CArtifactSet & set, CArtifactInstance * art, const ArtifactPosition & slot) +{ + art->addPlacementMap(set.putArtifact(slot, art)); +} + +void CMap::removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & slot) +{ + auto art = set.getArt(slot); + assert(art); + set.removeArtifact(slot); + CArtifactSet::ArtPlacementMap partsMap; + for(auto & part : art->getPartsInfo()) + { + if(part.slot != ArtifactPosition::PRE_FIRST) + partsMap.try_emplace(part.art, ArtifactPosition::PRE_FIRST); + } + art->addPlacementMap(partsMap); +} + void CMap::addNewQuestInstance(CQuest* quest) { quest->qid = static_cast(quests.size()); diff --git a/lib/mapping/CMap.h b/lib/mapping/CMap.h index 46a4fa1e0..847f81b06 100644 --- a/lib/mapping/CMap.h +++ b/lib/mapping/CMap.h @@ -110,6 +110,9 @@ public: void addNewArtifactInstance(CArtifactSet & artSet); void addNewArtifactInstance(ConstTransitivePtr art); void eraseArtifactInstance(CArtifactInstance * art); + void moveArtifactInstance(CArtifactSet & srcSet, const ArtifactPosition & srcSlot, CArtifactSet & dstSet, const ArtifactPosition & dstSlot); + void putArtifactInstance(CArtifactSet & set, CArtifactInstance * art, const ArtifactPosition & slot); + void removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & slot); void addNewQuestInstance(CQuest * quest); void removeQuestInstance(CQuest * quest); diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 32e0057ac..09eeda739 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -959,7 +959,7 @@ bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot) if(ArtifactID(artifactID).toArtifact()->canBePutAt(hero, ArtifactPosition(slot))) { auto * artifact = ArtifactUtils::createArtifact(artifactID); - artifact->putAt(*hero, ArtifactPosition(slot)); + map->putArtifactInstance(*hero, artifact, slot); map->addNewArtifactInstance(artifact); } else diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 43309a8c5..ae31fdec8 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/lib/networkPacks/NetPacksLib.cpp @@ -1471,8 +1471,7 @@ void NewArtifact::applyGs(CGameState *gs) { auto art = ArtifactUtils::createArtifact(artId, spellId); gs->map->addNewArtifactInstance(art); - PutArtifact pa(ArtifactLocation(artHolder, pos), false); - pa.art = art; + PutArtifact pa(art->getId(), ArtifactLocation(artHolder, pos), false); pa.applyGs(gs); } @@ -1591,14 +1590,14 @@ void RebalanceStacks::applyGs(CGameState *gs) const auto dstHero = dynamic_cast(dst.army.get()); auto srcStack = const_cast(src.getStack()); auto dstStack = const_cast(dst.getStack()); - if(auto srcArt = srcStack->getArt(ArtifactPosition::CREATURE_SLOT)) + if(srcStack->getArt(ArtifactPosition::CREATURE_SLOT)) { if(auto dstArt = dstStack->getArt(ArtifactPosition::CREATURE_SLOT)) { auto dstSlot = ArtifactUtils::getArtBackpackPosition(srcHero, dstArt->getTypeId()); if(srcHero && dstSlot != ArtifactPosition::PRE_FIRST) { - dstArt->move(*dstStack, ArtifactPosition::CREATURE_SLOT, *srcHero, dstSlot); + gs->map->moveArtifactInstance(*dstStack, ArtifactPosition::CREATURE_SLOT, *srcHero, dstSlot); } //else - artifact can be lost :/ else @@ -1610,12 +1609,12 @@ void RebalanceStacks::applyGs(CGameState *gs) ea.applyGs(gs); logNetwork->warn("Cannot move artifact! No free slots"); } - srcArt->move(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT); + gs->map->moveArtifactInstance(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT); //TODO: choose from dialog } else //just move to the other slot before stack gets erased { - srcArt->move(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT); + gs->map->moveArtifactInstance(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT); } } if (stackExp) @@ -1685,14 +1684,13 @@ void BulkSmartRebalanceStacks::applyGs(CGameState *gs) void PutArtifact::applyGs(CGameState *gs) { - // Ensure that artifact has been correctly added via NewArtifact pack - assert(vstd::contains(gs->map->artInstances, art)); + auto art = gs->getArtInstance(id); assert(!art->getParentNodes().empty()); auto hero = gs->getHero(al.artHolder); assert(hero); assert(art && art->canBePutAt(hero, al.slot)); assert(ArtifactUtils::checkIfSlotValid(*hero, al.slot)); - art->putAt(*hero, al.slot); + gs->map->putArtifactInstance(*hero, art, al.slot); } void BulkEraseArtifacts::applyGs(CGameState *gs) @@ -1731,15 +1729,13 @@ void BulkEraseArtifacts::applyGs(CGameState *gs) { logGlobal->debug("Erasing artifact %s", slotInfo->artifact->artType->getNameTranslated()); } - auto art = artSet->getArt(slot); - assert(art); - art->removeFrom(*artSet, slot); + gs->map->removeArtifactInstance(*artSet, slot); } } void BulkMoveArtifacts::applyGs(CGameState *gs) { - const auto bulkArtsRemove = [](std::vector & artsPack, CArtifactSet & artSet) + const auto bulkArtsRemove = [gs](std::vector & artsPack, CArtifactSet & artSet) { std::vector packToRemove; for(const auto & slotsPair : artsPack) @@ -1750,20 +1746,16 @@ void BulkMoveArtifacts::applyGs(CGameState *gs) }); for(const auto & slot : packToRemove) - { - auto * art = artSet.getArt(slot); - assert(art); - art->removeFrom(artSet, slot); - } + gs->map->removeArtifactInstance(artSet, slot); }; - const auto bulkArtsPut = [](std::vector & artsPack, CArtifactSet & initArtSet, CArtifactSet & dstArtSet) + const auto bulkArtsPut = [gs](std::vector & artsPack, CArtifactSet & initArtSet, CArtifactSet & dstArtSet) { for(const auto & slotsPair : artsPack) { auto * art = initArtSet.getArt(slotsPair.srcPos); assert(art); - art->putAt(dstArtSet, slotsPair.dstPos); + gs->map->putArtifactInstance(dstArtSet, art, slotsPair.dstPos); } }; @@ -1840,7 +1832,7 @@ void AssembledArtifact::applyGs(CGameState *gs) for(const auto slot : slotsInvolved) { const auto constituentInstance = hero->getArt(slot); - constituentInstance->removeFrom(*hero, slot); + gs->map->removeArtifactInstance(*hero, slot); if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot) combinedArt->addPart(constituentInstance, slot); @@ -1849,7 +1841,7 @@ void AssembledArtifact::applyGs(CGameState *gs) } // Put new combined artifacts - combinedArt->putAt(*hero, al.slot); + gs->map->putArtifactInstance(*hero, combinedArt, al.slot); } void DisassembledArtifact::applyGs(CGameState *gs) @@ -1859,14 +1851,14 @@ void DisassembledArtifact::applyGs(CGameState *gs) auto disassembledArt = hero->getArt(al.slot); assert(disassembledArt); - auto parts = disassembledArt->getPartsInfo(); - disassembledArt->removeFrom(*hero, al.slot); + const auto parts = disassembledArt->getPartsInfo(); + gs->map->removeArtifactInstance(*hero, al.slot); for(auto & part : parts) { // ArtifactPosition::PRE_FIRST is value of main part slot -> it'll replace combined artifact in its pos auto slot = (ArtifactUtils::isSlotEquipment(part.slot) ? part.slot : al.slot); disassembledArt->detachFrom(*part.art); - part.art->putAt(*hero, slot); + gs->map->putArtifactInstance(*hero, part.art, slot); } gs->map->eraseArtifactInstance(disassembledArt); } diff --git a/lib/networkPacks/PacksForClient.h b/lib/networkPacks/PacksForClient.h index 5a81ec806..fabc5a36a 100644 --- a/lib/networkPacks/PacksForClient.h +++ b/lib/networkPacks/PacksForClient.h @@ -965,14 +965,14 @@ struct DLL_LINKAGE CArtifactOperationPack : CPackForClient struct DLL_LINKAGE PutArtifact : CArtifactOperationPack { PutArtifact() = default; - explicit PutArtifact(const ArtifactLocation & dst, bool askAssemble = true) - : al(dst), askAssemble(askAssemble) + explicit PutArtifact(const ArtifactInstanceID & id, const ArtifactLocation & dst, bool askAssemble = true) + : id(id), al(dst), askAssemble(askAssemble) { } ArtifactLocation al; bool askAssemble; - ConstTransitivePtr art; + ArtifactInstanceID id; void applyGs(CGameState * gs) override; void visitTyped(ICPackVisitor & visitor) override; @@ -981,7 +981,7 @@ struct DLL_LINKAGE PutArtifact : CArtifactOperationPack { h & al; h & askAssemble; - h & art; + h & id; } }; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 35dde1615..8579260b3 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -3757,9 +3757,10 @@ bool CGameHandler::swapStacks(const StackLocation & sl1, const StackLocation & s } } -bool CGameHandler::putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional askAssemble) +bool CGameHandler::putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional askAssemble) { - assert(art && art->artType); + const auto artInst = getArtInstance(id); + assert(artInst && artInst->artType); ArtifactLocation dst(al.artHolder, ArtifactPosition::PRE_FIRST); dst.creature = al.creature; auto putTo = getArtSet(al); @@ -3767,11 +3768,11 @@ bool CGameHandler::putArtifact(const ArtifactLocation & al, const CArtifactInsta if(al.slot == ArtifactPosition::FIRST_AVAILABLE) { - dst.slot = ArtifactUtils::getArtAnyPosition(putTo, art->getTypeId()); + dst.slot = ArtifactUtils::getArtAnyPosition(putTo, artInst->getTypeId()); } else if(ArtifactUtils::isSlotBackpack(al.slot) && !al.creature.has_value()) { - dst.slot = ArtifactUtils::getArtBackpackPosition(putTo, art->getTypeId()); + dst.slot = ArtifactUtils::getArtBackpackPosition(putTo, artInst->getTypeId()); } else { @@ -3786,10 +3787,9 @@ bool CGameHandler::putArtifact(const ArtifactLocation & al, const CArtifactInsta askAssemble = false; } - if(art->canBePutAt(putTo, dst.slot)) + if(artInst->canBePutAt(putTo, dst.slot)) { - PutArtifact pa(dst, askAssemble.value()); - pa.art = art; + PutArtifact pa(id, dst, askAssemble.value()); sendAndApply(&pa); return true; } diff --git a/server/CGameHandler.h b/server/CGameHandler.h index cdb194377..e2aa8c4f6 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -136,7 +136,7 @@ public: bool giveHeroNewArtifact(const CGHeroInstance * h, const CArtifact * artType, const SpellID & spellId, const ArtifactPosition & pos); bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) override; bool giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override; - bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional askAssemble) override; + bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional askAssemble) override; void removeArtifact(const ArtifactLocation &al) override; void removeArtifact(const ObjectInstanceID & srcId, const std::vector & slotsPack); bool moveArtifact(const PlayerColor & player, const ArtifactLocation & src, const ArtifactLocation & dst) override; diff --git a/test/mock/mock_IGameCallback.h b/test/mock/mock_IGameCallback.h index 1f2456a2f..c91118739 100644 --- a/test/mock/mock_IGameCallback.h +++ b/test/mock/mock_IGameCallback.h @@ -72,7 +72,7 @@ public: bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) override {return false;} bool giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override {return false;} - bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional askAssemble) override {return false;} + bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional askAssemble) override {return false;} void removeArtifact(const ArtifactLocation &al) override {} bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;} From 586a32a6162d15ada7afc273c087aba8ef1a9c90 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:51:59 +0300 Subject: [PATCH 2/2] CArtifactSet cleanup --- client/battle/BattleWindow.cpp | 2 +- client/widgets/CArtifactsOfHeroBase.cpp | 2 +- lib/ArtifactUtils.cpp | 2 +- lib/CArtHandler.cpp | 162 +++++++++--------------- lib/CArtHandler.h | 37 ++---- lib/CCreatureSet.cpp | 4 +- lib/CCreatureSet.h | 4 +- lib/mapObjects/CGHeroInstance.cpp | 6 +- lib/mapObjects/CGHeroInstance.h | 4 +- lib/mapObjects/CQuest.cpp | 2 +- lib/mapping/MapFormatH3M.cpp | 2 +- lib/networkPacks/PacksForClient.h | 2 +- lib/rewardable/Limiter.cpp | 24 +++- server/CGameHandler.cpp | 8 +- 14 files changed, 112 insertions(+), 149 deletions(-) diff --git a/client/battle/BattleWindow.cpp b/client/battle/BattleWindow.cpp index d6e162486..25b1b2eb3 100644 --- a/client/battle/BattleWindow.cpp +++ b/client/battle/BattleWindow.cpp @@ -743,7 +743,7 @@ void BattleWindow::bSpellf() const auto artID = blockingBonus->sid.as(); //If we have artifact, put name of our hero. Otherwise assume it's the enemy. //TODO check who *really* is source of bonus - std::string heroName = myHero->hasArt(artID) ? myHero->getNameTranslated() : owner.enemyHero().name; + std::string heroName = myHero->hasArt(artID, true) ? myHero->getNameTranslated() : owner.enemyHero().name; //%s wields the %s, an ancient artifact which creates a p dead to all magic. LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[683]) diff --git a/client/widgets/CArtifactsOfHeroBase.cpp b/client/widgets/CArtifactsOfHeroBase.cpp index 70f277b8e..8318fdf89 100644 --- a/client/widgets/CArtifactsOfHeroBase.cpp +++ b/client/widgets/CArtifactsOfHeroBase.cpp @@ -271,7 +271,7 @@ void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosit arts.try_emplace(combinedArt->getId(), std::vector{}); for(const auto part : combinedArt->getConstituents()) { - if(curHero->hasArt(part->getId(), false, false, false)) + if(curHero->hasArt(part->getId(), false, false)) arts.at(combinedArt->getId()).emplace_back(part->getId()); } } diff --git a/lib/ArtifactUtils.cpp b/lib/ArtifactUtils.cpp index dfc9fca20..7c95e435a 100644 --- a/lib/ArtifactUtils.cpp +++ b/lib/ArtifactUtils.cpp @@ -209,7 +209,7 @@ DLL_LINKAGE std::vector ArtifactUtils::assemblyPossibilities( for(const auto constituent : artifact->getConstituents()) //check if all constituents are available { - if(!artSet->hasArt(constituent->getId(), onlyEquiped, false, false)) + if(!artSet->hasArt(constituent->getId(), onlyEquiped, false)) { possible = false; break; diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index 4f944eb70..5b3f82a0d 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -220,7 +220,7 @@ bool CArtifact::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, b auto possibleSlot = ArtifactUtils::getArtAnyPosition(&fittingSet, art->getId()); if(ArtifactUtils::isSlotEquipment(possibleSlot)) { - fittingSet.setNewArtSlot(possibleSlot, nullptr, true); + fittingSet.lockSlot(possibleSlot); } else { @@ -691,9 +691,7 @@ void CArtHandler::afterLoadFinalization() CBonusSystemNode::treeHasChanged(); } -CArtifactSet::~CArtifactSet() = default; - -const CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const +CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const { if(const ArtSlotInfo * si = getSlot(pos)) { @@ -704,56 +702,34 @@ const CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, boo return nullptr; } -CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) -{ - return const_cast((const_cast(this))->getArt(pos, excludeLocked)); -} - ArtifactPosition CArtifactSet::getArtPos(const ArtifactID & aid, bool onlyWorn, bool allowLocked) const { - const auto result = getAllArtPositions(aid, onlyWorn, allowLocked, false); - return result.empty() ? ArtifactPosition{ArtifactPosition::PRE_FIRST} : result[0]; -} - -std::vector CArtifactSet::getAllArtPositions(const ArtifactID & aid, bool onlyWorn, bool allowLocked, bool getAll) const -{ - std::vector result; - for(const auto & slotInfo : artifactsWorn) - if(slotInfo.second.artifact->getTypeId() == aid && (allowLocked || !slotInfo.second.locked)) - result.push_back(slotInfo.first); - - if(onlyWorn) - return result; - if(!getAll && !result.empty()) - return result; - - auto backpackPositions = getBackpackArtPositions(aid); - result.insert(result.end(), backpackPositions.begin(), backpackPositions.end()); - return result; -} - -std::vector CArtifactSet::getBackpackArtPositions(const ArtifactID & aid) const -{ - std::vector result; - - si32 backpackPosition = ArtifactPosition::BACKPACK_START; - for(const auto & artInfo : artifactsInBackpack) + for(const auto & [slot, slotInfo] : artifactsWorn) { - const auto * art = artInfo.getArt(); - if(art && art->artType->getId() == aid) - result.emplace_back(backpackPosition); - backpackPosition++; + if(slotInfo.artifact->getTypeId() == aid && (allowLocked || !slotInfo.locked)) + return slot; } - return result; + if(!onlyWorn) + { + size_t backpackPositionIdx = ArtifactPosition::BACKPACK_START; + for(const auto & artInfo : artifactsInBackpack) + { + const auto art = artInfo.getArt(); + if(art && art->artType->getId() == aid) + return ArtifactPosition(backpackPositionIdx); + backpackPositionIdx++; + } + } + return ArtifactPosition::PRE_FIRST; } const CArtifactInstance * CArtifactSet::getArtByInstanceId(const ArtifactInstanceID & artInstId) const { - for(auto i : artifactsWorn) + for(const auto & i : artifactsWorn) if(i.second.artifact->getId() == artInstId) return i.second.artifact; - for(auto i : artifactsInBackpack) + for(const auto & i : artifactsInBackpack) if(i.artifact->getId() == artInstId) return i.artifact; @@ -779,29 +755,16 @@ ArtifactPosition CArtifactSet::getArtPos(const CArtifactInstance * artInst) cons return ArtifactPosition::PRE_FIRST; } -bool CArtifactSet::hasArt(const ArtifactID & aid, bool onlyWorn, bool searchBackpackAssemblies, bool allowLocked) const +bool CArtifactSet::hasArt(const ArtifactID & aid, bool onlyWorn, bool searchCombinedParts) const { - return getArtPosCount(aid, onlyWorn, searchBackpackAssemblies, allowLocked) > 0; + if(searchCombinedParts && getCombinedArtWithPart(aid)) + return true; + if(getArtPos(aid, onlyWorn, searchCombinedParts) != ArtifactPosition::PRE_FIRST) + return true; + return false; } -bool CArtifactSet::hasArtBackpack(const ArtifactID & aid) const -{ - return !getBackpackArtPositions(aid).empty(); -} - -unsigned CArtifactSet::getArtPosCount(const ArtifactID & aid, bool onlyWorn, bool searchBackpackAssemblies, bool allowLocked) const -{ - const auto allPositions = getAllArtPositions(aid, onlyWorn, allowLocked, true); - if(!allPositions.empty()) - return allPositions.size(); - - if(searchBackpackAssemblies && getHiddenArt(aid)) - return 1; - - return 0; -} - -CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(ArtifactPosition slot, CArtifactInstance * art) +CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, CArtifactInstance * art) { ArtPlacementMap resArtPlacement; @@ -827,19 +790,38 @@ CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(ArtifactPosition slot, C assert(ArtifactUtils::isSlotEquipment(partSlot)); setNewArtSlot(partSlot, part.art, true); - resArtPlacement.emplace(std::make_pair(part.art, partSlot)); + resArtPlacement.emplace(part.art, partSlot); } else { - resArtPlacement.emplace(std::make_pair(part.art, part.slot)); + resArtPlacement.emplace(part.art, part.slot); } } } return resArtPlacement; } -void CArtifactSet::removeArtifact(ArtifactPosition slot) +void CArtifactSet::removeArtifact(const ArtifactPosition & slot) { + const auto eraseArtSlot = [this](const ArtifactPosition & slotForErase) + { + if(slotForErase == ArtifactPosition::TRANSITION_POS) + { + artifactsTransitionPos.artifact = nullptr; + } + else if(ArtifactUtils::isSlotBackpack(slotForErase)) + { + auto backpackSlot = ArtifactPosition(slotForErase - ArtifactPosition::BACKPACK_START); + + assert(artifactsInBackpack.begin() + backpackSlot < artifactsInBackpack.end()); + artifactsInBackpack.erase(artifactsInBackpack.begin() + backpackSlot); + } + else + { + artifactsWorn.erase(slotForErase); + } + }; + if(const auto art = getArt(slot, false)) { if(art->isCombined()) @@ -858,7 +840,7 @@ void CArtifactSet::removeArtifact(ArtifactPosition slot) } } -std::pair CArtifactSet::searchForConstituent(const ArtifactID & aid) const +const CArtifactInstance * CArtifactSet::getCombinedArtWithPart(const ArtifactID & partId) const { for(const auto & slot : artifactsInBackpack) { @@ -867,24 +849,12 @@ std::pair CArtifactSet::se { for(auto & ci : art->getPartsInfo()) { - if(ci.art->getTypeId() == aid) - { - return {art, ci.art}; - } + if(ci.art->getTypeId() == partId) + return art; } } } - return {nullptr, nullptr}; -} - -const CArtifactInstance * CArtifactSet::getHiddenArt(const ArtifactID & aid) const -{ - return searchForConstituent(aid).second; -} - -const CArtifactInstance * CArtifactSet::getAssemblyByConstituent(const ArtifactID & aid) const -{ - return searchForConstituent(aid).first; + return nullptr; } const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const @@ -905,6 +875,11 @@ const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const return nullptr; } +void CArtifactSet::lockSlot(const ArtifactPosition & pos) +{ + setNewArtSlot(pos, nullptr, true); +} + bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck) const { if(bearerType() == ArtBearer::ALTAR) @@ -916,7 +891,7 @@ bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockChe return true; //no slot means not used } -void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, ConstTransitivePtr art, bool locked) +void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked) { assert(!vstd::contains(artifactsWorn, slot)); @@ -932,31 +907,12 @@ void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, ConstTransitiveP else { auto position = artifactsInBackpack.begin() + slot - ArtifactPosition::BACKPACK_START; - slotInfo = &(*artifactsInBackpack.emplace(position, ArtSlotInfo())); + slotInfo = &(*artifactsInBackpack.emplace(position)); } slotInfo->artifact = art; slotInfo->locked = locked; } -void CArtifactSet::eraseArtSlot(const ArtifactPosition & slot) -{ - if(slot == ArtifactPosition::TRANSITION_POS) - { - artifactsTransitionPos.artifact = nullptr; - } - else if(ArtifactUtils::isSlotBackpack(slot)) - { - auto backpackSlot = ArtifactPosition(slot - ArtifactPosition::BACKPACK_START); - - assert(artifactsInBackpack.begin() + backpackSlot < artifactsInBackpack.end()); - artifactsInBackpack.erase(artifactsInBackpack.begin() + backpackSlot); - } - else - { - artifactsWorn.erase(slot); - } -} - void CArtifactSet::artDeserializationFix(CBonusSystemNode *node) { for(auto & elem : artifactsWorn) diff --git a/lib/CArtHandler.h b/lib/CArtHandler.h index 77b7d1d1f..e82f43147 100644 --- a/lib/CArtHandler.h +++ b/lib/CArtHandler.h @@ -175,10 +175,10 @@ private: struct DLL_LINKAGE ArtSlotInfo { - ConstTransitivePtr artifact; - ui8 locked; //if locked, then artifact points to the combined artifact + CArtifactInstance * artifact; + bool locked; //if locked, then artifact points to the combined artifact - ArtSlotInfo() : locked(false) {} + ArtSlotInfo() : artifact(nullptr), locked(false) {} const CArtifactInstance * getArt() const; template void serialize(Handler & h) @@ -197,32 +197,20 @@ public: 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 ArtSlotInfo artifactsTransitionPos; // Used as transition position for dragAndDrop artifact exchange - void setNewArtSlot(const ArtifactPosition & slot, ConstTransitivePtr art, bool locked); - void eraseArtSlot(const ArtifactPosition & slot); - const ArtSlotInfo * getSlot(const ArtifactPosition & pos) const; - const CArtifactInstance * getArt(const ArtifactPosition & pos, bool excludeLocked = true) const; //nullptr - no artifact - CArtifactInstance * getArt(const ArtifactPosition & pos, bool excludeLocked = true); //nullptr - no artifact - /// Looks for equipped artifact with given ID and returns its slot ID or -1 if none - /// (if more than one such artifact lower ID is returned) + void lockSlot(const ArtifactPosition & pos); + CArtifactInstance * getArt(const ArtifactPosition & pos, bool excludeLocked = true) const; + /// Looks for first artifact with given ID ArtifactPosition getArtPos(const ArtifactID & aid, bool onlyWorn = true, bool allowLocked = true) const; ArtifactPosition getArtPos(const CArtifactInstance * art) const; - std::vector getAllArtPositions(const ArtifactID & aid, bool onlyWorn, bool allowLocked, bool getAll) const; - std::vector getBackpackArtPositions(const ArtifactID & aid) const; const CArtifactInstance * getArtByInstanceId(const ArtifactInstanceID & artInstId) const; - /// Search for constituents of assemblies in backpack which do not have an ArtifactPosition - const CArtifactInstance * getHiddenArt(const ArtifactID & aid) const; - const CArtifactInstance * getAssemblyByConstituent(const ArtifactID & aid) const; - /// Checks if hero possess artifact of given id (either in backack or worn) - bool hasArt(const ArtifactID & aid, bool onlyWorn = false, bool searchBackpackAssemblies = false, bool allowLocked = true) const; - bool hasArtBackpack(const ArtifactID & aid) const; + bool hasArt(const ArtifactID & aid, bool onlyWorn = false, bool searchCombinedParts = false) const; bool isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck = false) const; - unsigned getArtPosCount(const ArtifactID & aid, bool onlyWorn = true, bool searchBackpackAssemblies = true, bool allowLocked = true) const; virtual ArtBearer::ArtBearer bearerType() const = 0; - virtual ArtPlacementMap putArtifact(ArtifactPosition slot, CArtifactInstance * art); - virtual void removeArtifact(ArtifactPosition slot); - virtual ~CArtifactSet(); + virtual ArtPlacementMap putArtifact(const ArtifactPosition & slot, CArtifactInstance * art); + virtual void removeArtifact(const ArtifactPosition & slot); + virtual ~CArtifactSet() = default; template void serialize(Handler &h) { @@ -233,10 +221,11 @@ public: void artDeserializationFix(CBonusSystemNode *node); void serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName); -protected: - std::pair searchForConstituent(const ArtifactID & aid) const; + const CArtifactInstance * getCombinedArtWithPart(const ArtifactID & partId) const; private: + void setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked); + void serializeJsonHero(JsonSerializeFormat & handler); void serializeJsonCreature(JsonSerializeFormat & handler); void serializeJsonCommander(JsonSerializeFormat & handler); diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index 9f74f35e5..fd1bfdc01 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -863,7 +863,7 @@ ArtBearer::ArtBearer CStackInstance::bearerType() const return ArtBearer::CREATURE; } -CStackInstance::ArtPlacementMap CStackInstance::putArtifact(ArtifactPosition pos, CArtifactInstance * art) +CStackInstance::ArtPlacementMap CStackInstance::putArtifact(const ArtifactPosition & pos, CArtifactInstance * art) { assert(!getArt(pos)); assert(art->canBePutAt(this, pos)); @@ -872,7 +872,7 @@ CStackInstance::ArtPlacementMap CStackInstance::putArtifact(ArtifactPosition pos return CArtifactSet::putArtifact(pos, art); } -void CStackInstance::removeArtifact(ArtifactPosition pos) +void CStackInstance::removeArtifact(const ArtifactPosition & pos) { assert(getArt(pos)); diff --git a/lib/CCreatureSet.h b/lib/CCreatureSet.h index df7ab8dd4..d20fee553 100644 --- a/lib/CCreatureSet.h +++ b/lib/CCreatureSet.h @@ -126,8 +126,8 @@ public: void setArmyObj(const CArmedInstance *ArmyObj); virtual void giveStackExp(TExpType exp); bool valid(bool allowUnrandomized) const; - ArtPlacementMap putArtifact(ArtifactPosition pos, CArtifactInstance * art) override;//from CArtifactSet - void removeArtifact(ArtifactPosition pos) override; + ArtPlacementMap putArtifact(const ArtifactPosition & pos, CArtifactInstance * art) override;//from CArtifactSet + void removeArtifact(const ArtifactPosition & pos) override; ArtBearer::ArtBearer bearerType() const override; //from CArtifactSet std::string nodeName() const override; //from CBonusSystemnode void deserializationFix(); diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 0a7b84596..ce5653743 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -1156,7 +1156,7 @@ std::string CGHeroInstance::getBiographyTextID() const return ""; //for random hero } -CGHeroInstance::ArtPlacementMap CGHeroInstance::putArtifact(ArtifactPosition pos, CArtifactInstance * art) +CGHeroInstance::ArtPlacementMap CGHeroInstance::putArtifact(const ArtifactPosition & pos, CArtifactInstance * art) { assert(art->canBePutAt(this, pos)); @@ -1165,7 +1165,7 @@ CGHeroInstance::ArtPlacementMap CGHeroInstance::putArtifact(ArtifactPosition pos return CArtifactSet::putArtifact(pos, art); } -void CGHeroInstance::removeArtifact(ArtifactPosition pos) +void CGHeroInstance::removeArtifact(const ArtifactPosition & pos) { auto art = getArt(pos); assert(art); @@ -1201,7 +1201,7 @@ void CGHeroInstance::removeSpellbook() if(hasSpellbook()) { - //VLC->arth->removeArtifactFrom(*this, ArtifactPosition::SPELLBOOK); + cb->removeArtifact(ArtifactLocation(this->id, ArtifactPosition::SPELLBOOK)); } } diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index a4dffa8af..d07885e70 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -241,8 +241,8 @@ public: void initHero(vstd::RNG & rand); void initHero(vstd::RNG & rand, const HeroTypeID & SUBID); - ArtPlacementMap putArtifact(ArtifactPosition pos, CArtifactInstance * art) override; - void removeArtifact(ArtifactPosition pos) override; + ArtPlacementMap putArtifact(const ArtifactPosition & pos, CArtifactInstance * art) override; + void removeArtifact(const ArtifactPosition & pos) override; void initExp(vstd::RNG & rand); void initArmy(vstd::RNG & rand, IArmyDescriptor *dst = nullptr); void pushPrimSkill(PrimarySkill which, int val); diff --git a/lib/mapObjects/CQuest.cpp b/lib/mapObjects/CQuest.cpp index 15a9153e8..1cdfa40e3 100644 --- a/lib/mapObjects/CQuest.cpp +++ b/lib/mapObjects/CQuest.cpp @@ -152,7 +152,7 @@ void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const } else { - const auto * assembly = h->getAssemblyByConstituent(elem); + const auto * assembly = h->getCombinedArtWithPart(elem); assert(assembly); auto parts = assembly->getPartsInfo(); diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 09eeda739..14575a5a1 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -917,7 +917,7 @@ void CMapLoaderH3M::loadArtifactsOfHero(CGHeroInstance * hero) hero->artifactsInBackpack.clear(); while(!hero->artifactsWorn.empty()) - hero->eraseArtSlot(hero->artifactsWorn.begin()->first); + hero->removeArtifact(hero->artifactsWorn.begin()->first); } for(int i = 0; i < features.artifactSlotsCount; i++) diff --git a/lib/networkPacks/PacksForClient.h b/lib/networkPacks/PacksForClient.h index fabc5a36a..280778d3d 100644 --- a/lib/networkPacks/PacksForClient.h +++ b/lib/networkPacks/PacksForClient.h @@ -966,7 +966,7 @@ struct DLL_LINKAGE PutArtifact : CArtifactOperationPack { PutArtifact() = default; explicit PutArtifact(const ArtifactInstanceID & id, const ArtifactLocation & dst, bool askAssemble = true) - : id(id), al(dst), askAssemble(askAssemble) + : al(dst), askAssemble(askAssemble), id(id) { } diff --git a/lib/rewardable/Limiter.cpp b/lib/rewardable/Limiter.cpp index a5b522e4b..563db49e1 100644 --- a/lib/rewardable/Limiter.cpp +++ b/lib/rewardable/Limiter.cpp @@ -143,10 +143,28 @@ bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const for(const auto & elem : artifactsRequirements) { // check required amount of artifacts - if(hero->getArtPosCount(elem.first, false, true, true) < elem.second) + size_t artCnt = 0; + for(const auto & [slot, slotInfo] : hero->artifactsWorn) + if(slotInfo.artifact->getTypeId() == elem.first) + artCnt++; + + for(auto & slotInfo : hero->artifactsInBackpack) + if(slotInfo.artifact->getTypeId() == elem.first) + { + artCnt++; + } + else if(slotInfo.artifact->isCombined()) + { + for(const auto & partInfo : slotInfo.artifact->getPartsInfo()) + if(partInfo.art->getTypeId() == elem.first) + artCnt++; + } + + if(artCnt < elem.second) return false; - if(!hero->hasArt(elem.first)) - reqSlots += hero->getAssemblyByConstituent(elem.first)->getPartsInfo().size() - 2; + // Check if art has no own slot. (As part of combined in backpack) + if(hero->getArtPos(elem.first, false) == ArtifactPosition::PRE_FIRST) + reqSlots += hero->getCombinedArtWithPart(elem.first)->getPartsInfo().size() - 2; } if(!ArtifactUtils::isBackpackFreeSlots(hero, reqSlots)) return false; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 8579260b3..ca0159e55 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2718,15 +2718,15 @@ bool CGameHandler::switchArtifactsCostume(const PlayerColor & player, const Obje // Second, find the necessary artifacts for the costume for(const auto & artPos : costumeArtMap) { - if(const auto availableArts = artFittingSet.getAllArtPositions(artPos.second, false, false, false); !availableArts.empty()) + if(const auto slot = artFittingSet.getArtPos(artPos.second, false, false); slot != ArtifactPosition::PRE_FIRST) { bma.artsPack0.emplace_back(BulkMoveArtifacts::LinkedSlots { - artSet->getArtPos(artFittingSet.getArt(availableArts.front())), + artSet->getArtPos(artFittingSet.getArt(slot)), artPos.first }); - artFittingSet.removeArtifact(availableArts.front()); - if(ArtifactUtils::isSlotBackpack(availableArts.front())) + artFittingSet.removeArtifact(slot); + if(ArtifactUtils::isSlotBackpack(slot)) estimateBackpackSize--; } }