1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-21 17:17:06 +02:00

Fused identical artifacts

This commit is contained in:
SoundSSGood 2024-10-12 21:20:29 +03:00
parent d4d3ddf685
commit 86d5c05ffa
9 changed files with 72 additions and 53 deletions

View File

@ -356,6 +356,7 @@
"vcmi.heroWindow.sortBackpackBySlot.help" : "Sort artifacts in backpack by equipped slot.",
"vcmi.heroWindow.sortBackpackByClass.hover" : "Sort by class",
"vcmi.heroWindow.sortBackpackByClass.help" : "Sort artifacts in backpack by artifact class. Treasure, Minor, Major, Relic",
"vcmi.heroWindow.fusingArtifact.fusing" : "You possess all of the components needed for the fusion of the %s. Do you wish to perform the fusion? {All components will be consumed upon fusion.}",
"vcmi.tavernWindow.inviteHero" : "Invite hero",

View File

@ -74,7 +74,10 @@ bool ArtifactsUIController::askToAssemble(const CGHeroInstance * hero, const Art
MetaString message = MetaString::createFromTextID(art->artType->getDescriptionTextID());
message.appendEOL();
message.appendEOL();
message.appendRawString(CGI->generaltexth->allTexts[732]); // You possess all of the components needed to assemble the
if(combinedArt->isFused())
message.appendRawString(CGI->generaltexth->translate("vcmi.heroWindow.fusingArtifact.fusing"));
else
message.appendRawString(CGI->generaltexth->allTexts[732]); // You possess all of the components needed to assemble the
message.replaceName(ArtifactID(combinedArt->getId()));
LOCPLINT->showYesNoDialog(message.toString(), [&assembleConfirmed, hero, slot, combinedArt]()
{

View File

@ -217,9 +217,9 @@ void CArtPlace::setGestureCallback(const ClickFunctor & callback)
void CArtPlace::addCombinedArtInfo(const std::map<const ArtifactID, std::vector<ArtifactID>> & arts)
{
for(const auto & availableArts : arts)
for(auto [combinedId, availableArts] : arts)
{
const auto combinedArt = availableArts.first.toArtifact();
const auto combinedArt = combinedId.toArtifact();
MetaString info;
info.appendEOL();
info.appendEOL();
@ -227,14 +227,20 @@ void CArtPlace::addCombinedArtInfo(const std::map<const ArtifactID, std::vector<
info.appendName(combinedArt->getId());
info.appendRawString("}");
info.appendRawString(" (%d/%d)");
info.replaceNumber(availableArts.second.size());
info.replaceNumber(availableArts.size());
info.replaceNumber(combinedArt->getConstituents().size());
for(const auto part : combinedArt->getConstituents())
{
const auto found = std::find_if(availableArts.begin(), availableArts.end(), [part](const auto & availablePart) -> bool
{
return availablePart == part->getId() ? true : false;
});
info.appendEOL();
if(vstd::contains(availableArts.second, part->getId()))
if(found < availableArts.end())
{
info.appendName(part->getId());
availableArts.erase(found);
}
else
{

View File

@ -268,11 +268,17 @@ void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosit
std::map<const ArtifactID, std::vector<ArtifactID>> arts;
for(const auto combinedArt : slotInfo->artifact->artType->getPartOf())
{
arts.try_emplace(combinedArt->getId(), std::vector<ArtifactID>{});
assert(combinedArt->isCombined());
arts.try_emplace(combinedArt->getId());
CArtifactFittingSet fittingSet(*curHero);
for(const auto part : combinedArt->getConstituents())
{
if(curHero->hasArt(part->getId(), false, false))
const auto partSlot = fittingSet.getArtPos(part->getId(), false, false);
if(partSlot != ArtifactPosition::PRE_FIRST)
{
arts.at(combinedArt->getId()).emplace_back(part->getId());
fittingSet.lockSlot(partSlot);
}
}
}
artPlace->addCombinedArtInfo(arts);

View File

@ -61,6 +61,10 @@
"description" : "Optional, list of components for combinational artifacts",
"items" : { "type" : "string" }
},
"fusedComponents" : {
"type" : "boolean",
"description" : "Used together with components fild. Marks the artifact as fused. Cannot be disassembled."
},
"bonuses" : {
"type" : "array",
"description" : "Bonuses provided by this artifact using bonus system",

View File

@ -202,21 +202,23 @@ DLL_LINKAGE std::vector<const CArtifact*> ArtifactUtils::assemblyPossibilities(
if(art->isCombined())
return arts;
for(const auto artifact : art->getPartOf())
for(const auto combinedArt : art->getPartOf())
{
assert(artifact->isCombined());
assert(combinedArt->isCombined());
bool possible = true;
for(const auto constituent : artifact->getConstituents()) //check if all constituents are available
CArtifactFittingSet fittingSet(*artSet);
for(const auto part : combinedArt->getConstituents()) // check if all constituents are available
{
if(!artSet->hasArt(constituent->getId(), onlyEquiped, false))
const auto slot = fittingSet.getArtPos(part->getId(), onlyEquiped, false);
if(slot == ArtifactPosition::PRE_FIRST)
{
possible = false;
break;
}
fittingSet.lockSlot(slot);
}
if(possible)
arts.push_back(artifact);
arts.push_back(combinedArt);
}
return arts;
}

View File

@ -56,7 +56,7 @@ const std::vector<const CArtifact*> & CCombinedArtifact::getConstituents() const
return constituents;
}
const std::vector<const CArtifact*> & CCombinedArtifact::getPartOf() const
const std::set<const CArtifact*> & CCombinedArtifact::getPartOf() const
{
return partOf;
}
@ -630,7 +630,7 @@ 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(ArtifactID(id).toArtifact());
objects[id]->partOf.push_back(art);
objects[id]->partOf.insert(art);
});
}
}
@ -784,8 +784,27 @@ bool CArtifactSet::hasArt(const ArtifactID & aid, bool onlyWorn, bool searchComb
CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, CArtifactInstance * art)
{
ArtPlacementMap resArtPlacement;
const auto putToSlot = [this](const ArtifactPosition & targetSlot, CArtifactInstance * targetArt, bool locked)
{
ArtSlotInfo * slotInfo;
if(targetSlot == ArtifactPosition::TRANSITION_POS)
{
slotInfo = &artifactsTransitionPos;
}
else if(ArtifactUtils::isSlotEquipment(targetSlot))
{
slotInfo = &artifactsWorn[targetSlot];
}
else
{
auto position = artifactsInBackpack.begin() + targetSlot - ArtifactPosition::BACKPACK_START;
slotInfo = &(*artifactsInBackpack.emplace(position));
}
slotInfo->artifact = targetArt;
slotInfo->locked = locked;
};
setNewArtSlot(slot, art, false);
putToSlot(slot, art, false);
if(art->artType->isCombined() && ArtifactUtils::isSlotEquipment(slot))
{
const CArtifactInstance * mainPart = nullptr;
@ -806,7 +825,7 @@ CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition &
partSlot = ArtifactUtils::getArtAnyPosition(this, part.art->getTypeId());
assert(ArtifactUtils::isSlotEquipment(partSlot));
setNewArtSlot(partSlot, part.art, true);
putToSlot(partSlot, part.art, true);
resArtPlacement.emplace(part.art, partSlot);
}
else
@ -894,7 +913,15 @@ const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const
void CArtifactSet::lockSlot(const ArtifactPosition & pos)
{
setNewArtSlot(pos, nullptr, true);
if(pos == ArtifactPosition::TRANSITION_POS)
artifactsTransitionPos.locked = true;
else if(ArtifactUtils::isSlotEquipment(pos))
artifactsWorn[pos].locked = true;
else
{
assert(artifactsInBackpack.size() > pos - ArtifactPosition::BACKPACK_START);
(artifactsInBackpack.begin() + pos - ArtifactPosition::BACKPACK_START)->locked = true;
}
}
bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck) const
@ -908,28 +935,6 @@ 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)
{
assert(!vstd::contains(artifactsWorn, slot));
ArtSlotInfo * slotInfo;
if(slot == ArtifactPosition::TRANSITION_POS)
{
slotInfo = &artifactsTransitionPos;
}
else if(ArtifactUtils::isSlotEquipment(slot))
{
slotInfo = &artifactsWorn[slot];
}
else
{
auto position = artifactsInBackpack.begin() + slot - ArtifactPosition::BACKPACK_START;
slotInfo = &(*artifactsInBackpack.emplace(position));
}
slotInfo->artifact = art;
slotInfo->locked = locked;
}
void CArtifactSet::artDeserializationFix(CBonusSystemNode *node)
{
for(auto & elem : artifactsWorn)

View File

@ -49,13 +49,13 @@ protected:
CCombinedArtifact() : fused(false) {};
std::vector<const CArtifact*> constituents; // Artifacts IDs a combined artifact consists of, or nullptr.
std::vector<const CArtifact*> partOf; // Reverse map of constituents - combined arts that include this art
std::set<const CArtifact*> partOf; // Reverse map of constituents - combined arts that include this art
bool fused;
public:
bool isCombined() const;
const std::vector<const CArtifact*> & getConstituents() const;
const std::vector<const CArtifact*> & getPartOf() const;
const std::set<const CArtifact*> & getPartOf() const;
void setFused(bool isFused);
bool isFused() const;
bool hasParts() const;
@ -229,8 +229,6 @@ public:
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);

View File

@ -1818,14 +1818,11 @@ void AssembledArtifact::applyGs(CGameState *gs)
// Find slots for all involved artifacts
std::vector<ArtifactPosition> slotsInvolved;
CArtifactFittingSet artSet(*hero);
for(const auto constituent : builtArt->getConstituents())
{
ArtifactPosition slot;
if(transformedArt->getTypeId() == constituent->getId())
slot = transformedArtSlot;
else
slot = hero->getArtPos(constituent->getId(), false, false);
const auto slot = artSet.getArtPos(constituent->getId(), false, false);
artSet.lockSlot(slot);
assert(slot != ArtifactPosition::PRE_FIRST);
slotsInvolved.emplace_back(slot);
}
@ -2487,10 +2484,7 @@ void SetBankConfiguration::applyGs(CGameState *gs)
const CArtifactInstance * ArtSlotInfo::getArt() const
{
if(locked)
{
logNetwork->warn("ArtifactLocation::getArt: This location is locked!");
return nullptr;
}
return artifact;
}