diff --git a/AI/VCAI/MapObjectsEvaluator.cpp b/AI/VCAI/MapObjectsEvaluator.cpp index 83595b8b4..f07597242 100644 --- a/AI/VCAI/MapObjectsEvaluator.cpp +++ b/AI/VCAI/MapObjectsEvaluator.cpp @@ -101,7 +101,7 @@ boost::optional MapObjectsEvaluator::getObjectValue(const CGObjectInstance else if(obj->ID == Obj::SPELL_SCROLL) { auto scrollObject = dynamic_cast(obj); - auto spell = scrollObject->storedArtifact->getGivenSpellID().toSpell(); + auto spell = scrollObject->storedArtifact->getScrollSpellID().toSpell(); if(spell) { switch(spell->getLevel()) @@ -116,7 +116,7 @@ boost::optional MapObjectsEvaluator::getObjectValue(const CGObjectInstance } } else - logAi->warn("AI found spell scroll with invalid spell ID: %s", scrollObject->storedArtifact->getGivenSpellID()); + logAi->warn("AI found spell scroll with invalid spell ID: %s", scrollObject->storedArtifact->getScrollSpellID()); } return getObjectValue(obj->ID, obj->subID); diff --git a/client/widgets/CArtifactHolder.cpp b/client/widgets/CArtifactHolder.cpp index 713cd6137..0f881e54d 100644 --- a/client/widgets/CArtifactHolder.cpp +++ b/client/widgets/CArtifactHolder.cpp @@ -200,7 +200,7 @@ bool CHeroArtPlace::askToAssemble(const CGHeroInstance * hero, ArtifactPosition assert(hero); const auto art = hero->getArt(slot); assert(art); - auto assemblyPossibilities = art->assemblyPossibilities(hero, ArtifactUtils::isSlotEquipment(slot)); + auto assemblyPossibilities = ArtifactUtils::assemblyPossibilities(hero, art->getTypeId(), ArtifactUtils::isSlotEquipment(slot)); // If the artifact can be assembled, display dialog. for(const auto * combination : assemblyPossibilities) @@ -359,11 +359,32 @@ void CHeroArtPlace::setArtifact(const CArtifactInstance *art) image->enable(); image->setFrame(locked ? ArtifactID::ART_LOCK : art->artType->getIconIndex()); - text = art->getEffectiveDescription(ourOwner->curHero); + text = art->getDescription(); + + // Display info about set + if(ourOwner && ourOwner->curHero && !art->canBeDisassembled()) + { + for(const auto combinedArt : art->artType->constituentOf) + { + std::string artList; + text += "\n\n"; + text += "{" + combinedArt->getNameTranslated() + "}"; + int wornArtifacts = 0; + for(const auto part : *combinedArt->constituents) + { + if(art->artType->constituentOf.size() <= 1) + artList += "\n" + part->getNameTranslated(); + if(ourOwner->curHero->hasArt(part->getId(), true)) + wornArtifacts++; + } + text += " (" + boost::str(boost::format("%d") % wornArtifacts) + " / " + + boost::str(boost::format("%d") % combinedArt->constituents->size()) + ")" + artList; + } + } if(art->artType->getId() == ArtifactID::SPELL_SCROLL) { - int spellID = art->getGivenSpellID(); + int spellID = art->getScrollSpellID(); if(spellID >= 0) { //add spell component info (used to provide a pic in r-click popup) @@ -1039,11 +1060,11 @@ void CCommanderArtPlace::setArtifact(const CArtifactInstance * art) image->enable(); image->setFrame(art->artType->getIconIndex()); - text = art->getEffectiveDescription(); + text = art->getDescription(); if (art->artType->getId() == ArtifactID::SPELL_SCROLL) { - int spellID = art->getGivenSpellID(); + int spellID = art->getScrollSpellID(); if (spellID >= 0) { //add spell component info (used to provide a pic in r-click popup) diff --git a/client/widgets/CComponent.cpp b/client/widgets/CComponent.cpp index 3cd07d8d1..b88ffaf9c 100644 --- a/client/widgets/CComponent.cpp +++ b/client/widgets/CComponent.cpp @@ -176,7 +176,7 @@ std::string CComponent::getDescription() { art.reset(CArtifactInstance::createScroll(SpellID(val))); } - return art->getEffectiveDescription(); + return art->getDescription(); } case experience: return CGI->generaltexth->allTexts[241]; case spell: return (*CGI->spellh)[subtype]->getDescriptionTranslated(val); diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index 2b6da96a7..107395a68 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -837,7 +837,7 @@ void CArtifactInstance::init() setNodeType(ARTIFACT_INSTANCE); } -std::string CArtifactInstance::getEffectiveDescription(const CGHeroInstance * hero) const +std::string CArtifactInstance::getDescription() const { std::string text = artType->getDescriptionTranslated(); if (!vstd::contains(text, '{')) @@ -848,7 +848,7 @@ std::string CArtifactInstance::getEffectiveDescription(const CGHeroInstance * he // we expect scroll description to be like this: This scroll contains the [spell name] spell which is added into your spell book for as long as you carry the scroll. // so we want to replace text in [...] with a spell name // however other language versions don't have name placeholder at all, so we have to be careful - SpellID spellID = getGivenSpellID(); + SpellID spellID = getScrollSpellID(); size_t nameStart = text.find_first_of('['); size_t nameEnd = text.find_first_of(']', nameStart); if(spellID.getNum() >= 0) @@ -857,24 +857,6 @@ std::string CArtifactInstance::getEffectiveDescription(const CGHeroInstance * he text = text.replace(nameStart, nameEnd - nameStart + 1, spellID.toSpell(VLC->spells())->getNameTranslated()); } } - else if(hero && !artType->constituentOf.empty()) //display info about set - { - std::string artList; - auto * combinedArt = artType->constituentOf[0]; - text += "\n\n"; - text += "{" + combinedArt->getNameTranslated() + "}"; - int wornArtifacts = 0; - for(auto * a : *combinedArt->constituents) //TODO: can the artifact be a part of more than one set? - { - artList += "\n" + a->getNameTranslated(); - if (hero->hasArt(a->getId(), true)) - wornArtifacts++; - } - text += " (" + boost::str(boost::format("%d") % wornArtifacts) + " / " + - boost::str(boost::format("%d") % combinedArt->constituents->size()) + ")" + artList; - //TODO: fancy colors and fonts for this text - } - return text; } @@ -910,46 +892,6 @@ bool CArtifactInstance::canBeDisassembled() const return artType->canBeDisassembled(); } -std::vector CArtifactInstance::assemblyPossibilities(const CArtifactSet * h, bool equipped) const -{ - std::vector ret; - if(artType->constituents) //combined artifact already: no combining of combined artifacts... for now. - return ret; - - for(const auto * artifact : artType->constituentOf) - { - assert(artifact->constituents); - bool possible = true; - - for(const auto * constituent : *artifact->constituents) //check if all constituents are available - { - if(equipped) - { - // Search for equipped arts - if (!h->hasArt(constituent->getId(), true, false, false)) - { - possible = false; - break; - } - } - else - { - // Search in backpack - if(!h->hasArtBackpack(constituent->getId())) - { - possible = false; - break; - } - } - } - - if(possible) - ret.push_back(artifact); - } - - return ret; -} - void CArtifactInstance::move(const ArtifactLocation & src, const ArtifactLocation & dst) { removeFrom(src); @@ -1022,7 +964,7 @@ void CArtifactInstance::deserializationFix() setType(artType); } -SpellID CArtifactInstance::getGivenSpellID() const +SpellID CArtifactInstance::getScrollSpellID() const { const auto b = getBonusLocalFirst(Selector::type()(Bonus::SPELL)); if(!b) @@ -1654,4 +1596,44 @@ DLL_LINKAGE bool ArtifactUtils::isBackpackFreeSlots(const CArtifactSet * target, return target->artifactsInBackpack.size() + reqSlots <= backpackCap; } +DLL_LINKAGE std::vector ArtifactUtils::assemblyPossibilities( + const CArtifactSet * artSet, const ArtifactID & aid, bool equipped) +{ + std::vector arts; + const auto * art = aid.toArtifact(); + if(art->canBeDisassembled()) + return arts; + + for(const auto artifact : art->constituentOf) + { + assert(artifact->constituents); + bool possible = true; + + for(const auto constituent : *artifact->constituents) //check if all constituents are available + { + if(equipped) + { + // Search for equipped arts + if(!artSet->hasArt(constituent->getId(), true, false, false)) + { + possible = false; + break; + } + } + else + { + // Search in backpack + if(!artSet->hasArtBackpack(constituent->getId())) + { + possible = false; + break; + } + } + } + if(possible) + arts.push_back(artifact); + } + return arts; +} + VCMI_LIB_NAMESPACE_END diff --git a/lib/CArtHandler.h b/lib/CArtHandler.h index 8f669c32c..ab5ecd409 100644 --- a/lib/CArtHandler.h +++ b/lib/CArtHandler.h @@ -153,8 +153,8 @@ public: void deserializationFix(); void setType(CArtifact *Art); - std::string getEffectiveDescription(const CGHeroInstance *hero = nullptr) const; - SpellID getGivenSpellID() const; //to be used with scrolls (and similar arts), -1 if none + std::string getDescription() const; + SpellID getScrollSpellID() const; //to be used with scrolls (and similar arts), -1 if none ArtifactID getTypeId() const; bool canBePutAt(const ArtifactLocation & al, bool assumeDestRemoved = false) const; //forwards to the above one @@ -165,7 +165,6 @@ public: /// of itself, additionally truth is returned for constituents of combined arts virtual bool isPart(const CArtifactInstance *supposedPart) const; - std::vector assemblyPossibilities(const CArtifactSet * h, bool equipped) const; void move(const ArtifactLocation & src,const ArtifactLocation & dst); template void serialize(Handler &h, const int version) @@ -390,6 +389,7 @@ namespace ArtifactUtils DLL_LINKAGE bool isSlotBackpack(const ArtifactPosition & slot); DLL_LINKAGE bool isSlotEquipment(const ArtifactPosition & slot); DLL_LINKAGE bool isBackpackFreeSlots(const CArtifactSet * target, const size_t reqSlots = 1); + DLL_LINKAGE std::vector assemblyPossibilities(const CArtifactSet * artSet, const ArtifactID & aid, bool equipped); } VCMI_LIB_NAMESPACE_END diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 743d872fa..196d53984 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -1316,7 +1316,7 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const break; case Obj::SPELL_SCROLL: { - int spellID = storedArtifact->getGivenSpellID(); + int spellID = storedArtifact->getScrollSpellID(); iw.components.emplace_back(Component::EComponentType::SPELL, spellID, 0, 0); if(message.length()) iw.text << message; diff --git a/mapeditor/inspector/inspector.cpp b/mapeditor/inspector/inspector.cpp index edf87e94c..02acd0898 100644 --- a/mapeditor/inspector/inspector.cpp +++ b/mapeditor/inspector/inspector.cpp @@ -280,7 +280,7 @@ void Inspector::updateProperties(CGArtifact * o) CArtifactInstance * instance = o->storedArtifact; if(instance) { - SpellID spellId = instance->getGivenSpellID(); + SpellID spellId = instance->getScrollSpellID(); if(spellId != -1) { auto * delegate = new InspectorDelegate; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 134b1e8a1..98779ea16 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -730,7 +730,7 @@ void CGameHandler::endBattleConfirm(const BattleInfo * battleInfo) { iw.components.emplace_back( Component::EComponentType::ARTIFACT, art->artType->getId(), - art->artType->getId() == ArtifactID::SPELL_SCROLL? art->getGivenSpellID() : 0, 0); + art->artType->getId() == ArtifactID::SPELL_SCROLL? art->getScrollSpellID() : 0, 0); if (iw.components.size() >= 14) { sendAndApply(&iw); @@ -4057,8 +4057,11 @@ bool CGameHandler::assembleArtifacts (ObjectInstanceID heroID, ArtifactPosition CArtifact * combinedArt = VLC->arth->objects[assembleTo]; if(!combinedArt->constituents) COMPLAIN_RET("assembleArtifacts: Artifact being attempted to assemble is not a combined artifacts!"); - if(!vstd::contains(destArtifact->assemblyPossibilities(hero, ArtifactUtils::isSlotEquipment(artifactSlot)), combinedArt)) + if (!vstd::contains(ArtifactUtils::assemblyPossibilities(hero, destArtifact->getTypeId(), + ArtifactUtils::isSlotEquipment(artifactSlot)), combinedArt)) + { COMPLAIN_RET("assembleArtifacts: It's impossible to assemble requested artifact!"); + } if(ArtifactUtils::checkSpellbookIsNeeded(hero, assembleTo, artifactSlot))