diff --git a/client/widgets/CArtifactHolder.cpp b/client/widgets/CArtifactHolder.cpp index b2c6a63f7..f2aaf7ee1 100644 --- a/client/widgets/CArtifactHolder.cpp +++ b/client/widgets/CArtifactHolder.cpp @@ -290,7 +290,7 @@ bool ArtifactUtilsClient::askToDisassemble(const CGHeroInstance * hero, const Ar const auto art = hero->getArt(slot); assert(art); - if(art->canBeDisassembled()) + if(art->isCombined()) { if(ArtifactUtils::isSlotBackpack(slot) && !ArtifactUtils::isBackpackFreeSlots(hero, art->artType->constituents->size() - 1)) return false; diff --git a/client/widgets/CArtifactsOfHeroBase.cpp b/client/widgets/CArtifactsOfHeroBase.cpp index be3b94d61..9afe6a20e 100644 --- a/client/widgets/CArtifactsOfHeroBase.cpp +++ b/client/widgets/CArtifactsOfHeroBase.cpp @@ -257,11 +257,11 @@ void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosit { artPlace->lockSlot(slotInfo->locked); artPlace->setArtifact(slotInfo->artifact); - if(!slotInfo->artifact->canBeDisassembled()) + if(!slotInfo->artifact->isCombined()) { // If the artifact is part of at least one combined artifact, add additional information std::map arts; - for(const auto combinedArt : slotInfo->artifact->artType->constituentOf) + for(const auto combinedArt : slotInfo->artifact->artType->partOf) { arts.insert(std::pair(combinedArt, 0)); for(const auto part : *combinedArt->constituents) diff --git a/lib/ArtifactUtils.cpp b/lib/ArtifactUtils.cpp index 1c356e0f0..32d1b2cf0 100644 --- a/lib/ArtifactUtils.cpp +++ b/lib/ArtifactUtils.cpp @@ -120,10 +120,10 @@ DLL_LINKAGE std::vector ArtifactUtils::assemblyPossibilities( { std::vector arts; const auto * art = aid.toArtifact(); - if(art->canBeDisassembled()) + if(art->isCombined()) return arts; - for(const auto artifact : art->constituentOf) + for(const auto artifact : art->partOf) { assert(artifact->constituents); bool possible = true; @@ -169,13 +169,13 @@ DLL_LINKAGE CArtifactInstance * ArtifactUtils::createNewArtifactInstance(CArtifa assert(art); auto * artInst = new CArtifactInstance(art); - if(art->canBeDisassembled()) + if(art->isCombined()) { assert(art->constituents); for(const auto & part : *art->constituents) artInst->addArtInstAsPart(ArtifactUtils::createNewArtifactInstance(part), ArtifactPosition::PRE_FIRST); } - if(dynamic_cast(art)) + if(art->isGrowing()) { auto bonus = std::make_shared(); bonus->type = BonusType::LEVEL_COUNTER; @@ -209,7 +209,7 @@ DLL_LINKAGE CArtifactInstance * ArtifactUtils::createArtifact(CMap * map, const art = new CArtifactInstance(); // random, empty } map->addNewArtifactInstance(art); - if(art->artType && art->canBeDisassembled()) + if(art->artType && art->isCombined()) { for(auto & part : art->partsInfo) { diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index e76b7c0d4..b98b7453e 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -46,6 +46,21 @@ VCMI_LIB_NAMESPACE_BEGIN +bool CCombinedArtifact::isCombined() const +{ + return !(constituents == nullptr); +} + +bool CScrollArtifact::isScroll() const +{ + return static_cast(this)->getId() == ArtifactID::SPELL_SCROLL; +} + +bool CGrowingArtifact::isGrowing() const +{ + return !bonusesPerLevel.empty() || !thresholdBonuses.empty(); +} + int32_t CArtifact::getIndex() const { return id.toEnum(); @@ -134,11 +149,6 @@ bool CArtifact::isTradable() const } } -bool CArtifact::canBeDisassembled() const -{ - return !(constituents == nullptr); -} - bool CArtifact::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, bool assumeDestRemoved) const { auto simpleArtCanBePutAt = [this](const CArtifactSet * artSet, ArtifactPosition slot, bool assumeDestRemoved) -> bool @@ -158,7 +168,7 @@ bool CArtifact::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, b auto artCanBePutAt = [this, simpleArtCanBePutAt](const CArtifactSet * artSet, ArtifactPosition slot, bool assumeDestRemoved) -> bool { - if(canBeDisassembled()) + if(isCombined()) { if(!simpleArtCanBePutAt(artSet, slot, assumeDestRemoved)) return false; @@ -350,17 +360,19 @@ CArtifact * CArtHandler::loadFromJson(const std::string & scope, const JsonNode assert(identifier.find(':') == std::string::npos); assert(!scope.empty()); - CArtifact * art = nullptr; - - if(!VLC->settings()->getBoolean(EGameSettings::MODULE_COMMANDERS) || node["growing"].isNull()) + CArtifact * art = new CArtifact(); + if(!node["growing"].isNull()) { - art = new CArtifact(); - } - else - { - auto * growing = new CGrowingArtifact(); - loadGrowingArt(growing, node); - art = growing; + for(auto bonus : node["growing"]["bonusesPerLevel"].Vector()) + { + art->bonusesPerLevel.emplace_back(static_cast(bonus["level"].Float()), Bonus()); + JsonUtils::parseBonus(bonus["bonus"], &art->bonusesPerLevel.back().second); + } + for(auto bonus : node["growing"]["thresholdBonuses"].Vector()) + { + art->thresholdBonuses.emplace_back(static_cast(bonus["level"].Float()), Bonus()); + JsonUtils::parseBonus(bonus["bonus"], &art->thresholdBonuses.back().second); + } } art->id = ArtifactID(index); art->identifier = identifier; @@ -553,26 +565,12 @@ void CArtHandler::loadComponents(CArtifact * art, const JsonNode & node) // when this code is called both combinational art as well as component are loaded // so it is safe to access any of them art->constituents->push_back(objects[id]); - objects[id]->constituentOf.push_back(art); + objects[id]->partOf.push_back(art); }); } } } -void CArtHandler::loadGrowingArt(CGrowingArtifact * art, const JsonNode & node) const -{ - for (auto b : node["growing"]["bonusesPerLevel"].Vector()) - { - art->bonusesPerLevel.emplace_back(static_cast(b["level"].Float()), Bonus()); - JsonUtils::parseBonus(b["bonus"], &art->bonusesPerLevel.back().second); - } - for (auto b : node["growing"]["thresholdBonuses"].Vector()) - { - art->thresholdBonuses.emplace_back(static_cast(b["level"].Float()), Bonus()); - JsonUtils::parseBonus(b["bonus"], &art->thresholdBonuses.back().second); - } -} - ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags, std::function accepts) { auto getAllowedArts = [&](std::vector > &out, std::vector *arts, CArtifact::EartClass flag) @@ -893,7 +891,7 @@ unsigned CArtifactSet::getArtPosCount(const ArtifactID & aid, bool onlyWorn, boo void CArtifactSet::putArtifact(ArtifactPosition slot, CArtifactInstance * art) { setNewArtSlot(slot, art, false); - if(art->artType->canBeDisassembled() && ArtifactUtils::isSlotEquipment(slot)) + if(art->artType->isCombined() && ArtifactUtils::isSlotEquipment(slot)) { const CArtifactInstance * mainPart = nullptr; for(const auto & part : art->partsInfo) @@ -923,7 +921,7 @@ void CArtifactSet::removeArtifact(ArtifactPosition slot) auto art = getArt(slot, false); if(art) { - if(art->canBeDisassembled()) + if(art->isCombined()) { for(auto & part : art->partsInfo) { @@ -940,7 +938,7 @@ std::pair CArtifactSet::se for(const auto & slot : artifactsInBackpack) { auto art = slot.artifact; - if(art->canBeDisassembled()) + if(art->isCombined()) { for(auto& ci : art->partsInfo) { diff --git a/lib/CArtHandler.h b/lib/CArtHandler.h index bb2e02516..8254e9f6e 100644 --- a/lib/CArtHandler.h +++ b/lib/CArtHandler.h @@ -42,7 +42,51 @@ namespace ArtBearer }; } -class DLL_LINKAGE CArtifact : public Artifact, public CBonusSystemNode //container for artifacts +class DLL_LINKAGE CCombinedArtifact +{ +protected: + CCombinedArtifact() = default; +public: + std::unique_ptr> constituents; // Artifacts IDs a combined artifact consists of, or nullptr. + std::vector partOf; // Reverse map of constituents - combined arts that include this art + + bool isCombined() const; + + template void serialize(Handler & h, const int version) + { + h & constituents; + h & partOf; + } +}; + +class DLL_LINKAGE CScrollArtifact +{ +protected: + CScrollArtifact() = default; +public: + bool isScroll() const; +}; + +class DLL_LINKAGE CGrowingArtifact +{ +protected: + CGrowingArtifact() = default; +public: + std::vector > bonusesPerLevel; // Bonus given each n levels + std::vector > thresholdBonuses; // After certain level they will be added once + + bool isGrowing() const; + + template void serialize(Handler & h, const int version) + { + h & bonusesPerLevel; + h & thresholdBonuses; + } +}; + +// Container for artifacts. Not for instances. +class DLL_LINKAGE CArtifact + : public Artifact, public CBonusSystemNode, public CCombinedArtifact, public CScrollArtifact, public CGrowingArtifact { ArtifactID id; @@ -58,8 +102,6 @@ public: si32 iconIndex = ArtifactID::NONE; ui32 price = 0; std::map > possibleSlots; //Bearer Type => ids of slots where artifact can be placed - std::unique_ptr > constituents; // Artifacts IDs a combined artifact consists of, or nullptr. - std::vector constituentOf; // Reverse map of constituents - combined arts that include this art EartClass aClass = ART_SPECIAL; CreatureID warMachine; @@ -87,23 +129,22 @@ public: std::string nodeName() const override; void addNewBonus(const std::shared_ptr& b) override; - virtual bool canBeDisassembled() const; virtual bool canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot = ArtifactPosition::FIRST_AVAILABLE, bool assumeDestRemoved = false) const; void updateFrom(const JsonNode & data); void serializeJson(JsonSerializeFormat & handler); - template void serialize(Handler &h, const int version) + template void serialize(Handler & h, const int version) { h & static_cast(*this); + h & static_cast(*this); + h & static_cast(*this); h & image; h & large; h & advMapDef; h & iconIndex; h & price; h & possibleSlots; - h & constituents; - h & constituentOf; h & aClass; h & id; h & modScope; @@ -117,20 +158,6 @@ public: friend class CArtHandler; }; -class DLL_LINKAGE CGrowingArtifact : public CArtifact //for example commander artifacts getting bonuses after battle -{ -public: - std::vector > bonusesPerLevel; //bonus given each n levels - std::vector > thresholdBonuses; //after certain level they will be added once - - template void serialize(Handler &h, const int version) - { - h & static_cast(*this); - h & bonusesPerLevel; - h & thresholdBonuses; - } -}; - class DLL_LINKAGE CArtHandler : public CHandlerBase { public: @@ -186,7 +213,6 @@ private: void loadClass(CArtifact * art, const JsonNode & node) const; void loadType(CArtifact * art, const JsonNode & node) const; void loadComponents(CArtifact * art, const JsonNode & node); - void loadGrowingArt(CGrowingArtifact * art, const JsonNode & node) const; void erasePickedArt(const ArtifactID & id); }; diff --git a/lib/CArtifactInstance.cpp b/lib/CArtifactInstance.cpp index c8dcede34..92bcf590d 100644 --- a/lib/CArtifactInstance.cpp +++ b/lib/CArtifactInstance.cpp @@ -58,15 +58,16 @@ void CGrowingArtifactInstance::growingUp() { auto artInst = static_cast(this); - if(auto growingArtType = dynamic_cast(static_cast(artInst->artType))) + if(artInst->artType->isGrowing()) { + auto bonus = std::make_shared(); bonus->type = BonusType::LEVEL_COUNTER; bonus->val = 1; bonus->duration = BonusDuration::COMMANDER_KILLED; artInst->accumulateBonus(bonus); - for(const auto & bonus : growingArtType->bonusesPerLevel) + for(const auto & bonus : artInst->artType->bonusesPerLevel) { // Every n levels if(artInst->valOfBonuses(BonusType::LEVEL_COUNTER) % bonus.first == 0) @@ -74,7 +75,7 @@ void CGrowingArtifactInstance::growingUp() artInst->accumulateBonus(std::make_shared(bonus.second)); } } - for(const auto & bonus : growingArtType->thresholdBonuses) + for(const auto & bonus : artInst->artType->thresholdBonuses) { // At n level if(artInst->valOfBonuses(BonusType::LEVEL_COUNTER) == bonus.first) @@ -117,7 +118,7 @@ std::string CArtifactInstance::nodeName() const std::string CArtifactInstance::getDescription() const { std::string text = artType->getDescriptionTranslated(); - if(artType->getId() == ArtifactID::SPELL_SCROLL) + if(artType->isScroll()) ArtifactUtils::insertScrrollSpellName(text, getScrollSpellID()); return text; } @@ -132,9 +133,9 @@ bool CArtifactInstance::canBePutAt(const ArtifactLocation & al, bool assumeDestR return artType->canBePutAt(al.getHolderArtSet(), al.slot, assumeDestRemoved); } -bool CArtifactInstance::canBeDisassembled() const +bool CArtifactInstance::isCombined() const { - return artType->canBeDisassembled(); + return artType->isCombined(); } void CArtifactInstance::putAt(const ArtifactLocation & al) diff --git a/lib/CArtifactInstance.h b/lib/CArtifactInstance.h index aad5bf1d5..aab15d4b2 100644 --- a/lib/CArtifactInstance.h +++ b/lib/CArtifactInstance.h @@ -37,6 +37,11 @@ public: void addArtInstAsPart(CArtifactInstance * art, const ArtifactPosition & slot); // Checks if supposed part inst is part of this combined art inst bool isPart(const CArtifactInstance * supposedPart) const; + + template void serialize(Handler & h, const int version) + { + h & partsInfo; + } }; class DLL_LINKAGE CScrollArtifactInstance @@ -72,7 +77,7 @@ public: ArtifactID getTypeId() const; bool canBePutAt(const ArtifactLocation & al, bool assumeDestRemoved = false) const; - bool canBeDisassembled() const; + bool isCombined() const; void putAt(const ArtifactLocation & al); void removeFrom(const ArtifactLocation & al); void move(const ArtifactLocation & src, const ArtifactLocation & dst); @@ -81,9 +86,9 @@ public: template void serialize(Handler & h, const int version) { h & static_cast(*this); + h & static_cast(*this); h & artType; h & id; - h & partsInfo; BONUS_TREE_DESERIALIZATION_FIX } }; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 8324cab8e..1aa32afda 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -1528,7 +1528,7 @@ void NewArtifact::applyGs(CGameState *gs) assert(art->artType); art->setType(art->artType); - if(art->canBeDisassembled()) + if(art->isCombined()) { assert(art->artType->constituents); for(const auto & part : *art->artType->constituents) @@ -1827,7 +1827,7 @@ void EraseArtifact::applyGs(CGameState *gs) for(auto& p : aset->artifactsWorn) { auto art = p.second.artifact; - if(art->canBeDisassembled() && art->isPart(slot->artifact)) + if(art->isCombined() && art->isPart(slot->artifact)) { dis.al.slot = aset->getArtPos(art); #ifndef NDEBUG @@ -2226,6 +2226,10 @@ void BattleResultAccepted::applyGs(CGameState * gs) const art.second.artifact->growingUp(); } } + for(auto & art : h->artifactsWorn) + { + art.second.artifact->growingUp(); + } } } diff --git a/lib/registerTypes/RegisterTypes.h b/lib/registerTypes/RegisterTypes.h index 405c9bbab..c23a60074 100644 --- a/lib/registerTypes/RegisterTypes.h +++ b/lib/registerTypes/RegisterTypes.h @@ -206,7 +206,6 @@ void registerTypesMapObjects2(Serializer &s) // s.template registerType(); s.template registerType(); - s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index b1de0801e..57e44b768 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -118,7 +118,7 @@ void CMapGenerator::initQuestArtsRemaining() for (auto art : VLC->arth->objects) { //Don't use parts of combined artifacts - if (art->aClass == CArtifact::ART_TREASURE && VLC->arth->legalArtifact(art->getId()) && art->constituentOf.empty()) + if (art->aClass == CArtifact::ART_TREASURE && VLC->arth->legalArtifact(art->getId()) && art->partOf.empty()) questArtifacts.push_back(art->getId()); } } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 1093c2e65..f8ad8a809 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -4102,7 +4102,7 @@ bool CGameHandler::assembleArtifacts (ObjectInstanceID heroID, ArtifactPosition } else { - if(!destArtifact->canBeDisassembled()) + if(!destArtifact->isCombined()) COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble is not a combined artifact!"); if(ArtifactUtils::isSlotBackpack(artifactSlot)