1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-26 03:52:01 +02:00

Merge pull request #4643 from SoundSSGood/CArtHandler-refactoring

CArtifactSet  tidy up
This commit is contained in:
Ivan Savenko 2024-10-01 16:26:32 +03:00 committed by GitHub
commit cef7466c71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 194 additions and 237 deletions

View File

@ -188,7 +188,7 @@ public:
bool swapGarrisonOnSiege(ObjectInstanceID tid) override {return false;}; bool swapGarrisonOnSiege(ObjectInstanceID tid) override {return false;};
bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) 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 giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override {return false;};
bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble) override {return false;}; bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble) override {return false;};
void removeArtifact(const ArtifactLocation & al) override {}; void removeArtifact(const ArtifactLocation & al) override {};
bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;}; bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;};

View File

@ -743,7 +743,7 @@ void BattleWindow::bSpellf()
const auto artID = blockingBonus->sid.as<ArtifactID>(); const auto artID = blockingBonus->sid.as<ArtifactID>();
//If we have artifact, put name of our hero. Otherwise assume it's the enemy. //If we have artifact, put name of our hero. Otherwise assume it's the enemy.
//TODO check who *really* is source of bonus //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. //%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]) LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[683])

View File

@ -137,9 +137,9 @@ void CArtifactsOfHeroBase::scrollBackpack(bool left)
LOCPLINT->cb->scrollBackpackArtifacts(curHero->id, 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)); artPlace.second->selectSlot(art->canBePutAt(curHero, artPlace.second->slot, assumeDestRemoved));
} }
@ -271,7 +271,7 @@ void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosit
arts.try_emplace(combinedArt->getId(), std::vector<ArtifactID>{}); arts.try_emplace(combinedArt->getId(), std::vector<ArtifactID>{});
for(const auto part : combinedArt->getConstituents()) 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()); arts.at(combinedArt->getId()).emplace_back(part->getId());
} }
} }

View File

@ -39,7 +39,7 @@ public:
virtual void setHero(const CGHeroInstance * hero); virtual void setHero(const CGHeroInstance * hero);
virtual const CGHeroInstance * getHero() const; virtual const CGHeroInstance * getHero() const;
virtual void scrollBackpack(bool left); 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 void unmarkSlots();
virtual ArtPlacePtr getArtPlace(const ArtifactPosition & slot); virtual ArtPlacePtr getArtPlace(const ArtifactPosition & slot);
virtual ArtPlacePtr getArtPlace(const Point & cursorPosition); virtual ArtPlacePtr getArtPlace(const Point & cursorPosition);

View File

@ -62,15 +62,12 @@ const CGHeroInstance * CWindowWithArtifacts::getHeroPickedArtifact() const
const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact() const const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact() const
{ {
const CArtifactInstance * art = nullptr;
for(const auto & artSet : artSets) for(const auto & artSet : artSets)
if(const auto pickedArt = artSet->getHero()->getArt(ArtifactPosition::TRANSITION_POS)) if(const auto pickedArt = artSet->getHero()->getArt(ArtifactPosition::TRANSITION_POS))
{ {
art = pickedArt; return pickedArt;
break;
} }
return art; return nullptr;
} }
void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance * hero, const ArtifactPosition & slot, void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance * hero, const ArtifactPosition & slot,
@ -207,7 +204,7 @@ void CWindowWithArtifacts::markPossibleSlots() const
continue; continue;
if(getHeroPickedArtifact() == hero || !std::dynamic_pointer_cast<CArtifactsOfHeroKingdom>(artSet)) if(getHeroPickedArtifact() == hero || !std::dynamic_pointer_cast<CArtifactsOfHeroKingdom>(artSet))
artSet->markPossibleSlots(pickedArtInst, hero->tempOwner == LOCPLINT->playerID); artSet->markPossibleSlots(pickedArtInst->artType, hero->tempOwner == LOCPLINT->playerID);
} }
} }
} }

View File

@ -209,7 +209,7 @@ DLL_LINKAGE std::vector<const CArtifact*> ArtifactUtils::assemblyPossibilities(
for(const auto constituent : artifact->getConstituents()) //check if all constituents are available 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; possible = false;
break; break;

View File

@ -220,7 +220,7 @@ bool CArtifact::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, b
auto possibleSlot = ArtifactUtils::getArtAnyPosition(&fittingSet, art->getId()); auto possibleSlot = ArtifactUtils::getArtAnyPosition(&fittingSet, art->getId());
if(ArtifactUtils::isSlotEquipment(possibleSlot)) if(ArtifactUtils::isSlotEquipment(possibleSlot))
{ {
fittingSet.setNewArtSlot(possibleSlot, nullptr, true); fittingSet.lockSlot(possibleSlot);
} }
else else
{ {
@ -691,9 +691,7 @@ void CArtHandler::afterLoadFinalization()
CBonusSystemNode::treeHasChanged(); CBonusSystemNode::treeHasChanged();
} }
CArtifactSet::~CArtifactSet() = default; CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const
const CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const
{ {
if(const ArtSlotInfo * si = getSlot(pos)) if(const ArtSlotInfo * si = getSlot(pos))
{ {
@ -704,56 +702,34 @@ const CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, boo
return nullptr; return nullptr;
} }
CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked)
{
return const_cast<CArtifactInstance*>((const_cast<const CArtifactSet*>(this))->getArt(pos, excludeLocked));
}
ArtifactPosition CArtifactSet::getArtPos(const ArtifactID & aid, bool onlyWorn, bool allowLocked) const ArtifactPosition CArtifactSet::getArtPos(const ArtifactID & aid, bool onlyWorn, bool allowLocked) const
{ {
const auto result = getAllArtPositions(aid, onlyWorn, allowLocked, false); for(const auto & [slot, slotInfo] : artifactsWorn)
return result.empty() ? ArtifactPosition{ArtifactPosition::PRE_FIRST} : result[0];
}
std::vector<ArtifactPosition> CArtifactSet::getAllArtPositions(const ArtifactID & aid, bool onlyWorn, bool allowLocked, bool getAll) const
{
std::vector<ArtifactPosition> 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<ArtifactPosition> CArtifactSet::getBackpackArtPositions(const ArtifactID & aid) const
{
std::vector<ArtifactPosition> result;
si32 backpackPosition = ArtifactPosition::BACKPACK_START;
for(const auto & artInfo : artifactsInBackpack)
{ {
const auto * art = artInfo.getArt(); if(slotInfo.artifact->getTypeId() == aid && (allowLocked || !slotInfo.locked))
if(art && art->artType->getId() == aid) return slot;
result.emplace_back(backpackPosition);
backpackPosition++;
} }
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 const CArtifactInstance * CArtifactSet::getArtByInstanceId(const ArtifactInstanceID & artInstId) const
{ {
for(auto i : artifactsWorn) for(const auto & i : artifactsWorn)
if(i.second.artifact->getId() == artInstId) if(i.second.artifact->getId() == artInstId)
return i.second.artifact; return i.second.artifact;
for(auto i : artifactsInBackpack) for(const auto & i : artifactsInBackpack)
if(i.artifact->getId() == artInstId) if(i.artifact->getId() == artInstId)
return i.artifact; return i.artifact;
@ -779,29 +755,16 @@ ArtifactPosition CArtifactSet::getArtPos(const CArtifactInstance * artInst) cons
return ArtifactPosition::PRE_FIRST; 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 CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, CArtifactInstance * art)
{
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)
{ {
ArtPlacementMap resArtPlacement; ArtPlacementMap resArtPlacement;
@ -827,19 +790,38 @@ CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(ArtifactPosition slot, C
assert(ArtifactUtils::isSlotEquipment(partSlot)); assert(ArtifactUtils::isSlotEquipment(partSlot));
setNewArtSlot(partSlot, part.art, true); setNewArtSlot(partSlot, part.art, true);
resArtPlacement.emplace(std::make_pair(part.art, partSlot)); resArtPlacement.emplace(part.art, partSlot);
} }
else else
{ {
resArtPlacement.emplace(std::make_pair(part.art, part.slot)); resArtPlacement.emplace(part.art, part.slot);
} }
} }
} }
return resArtPlacement; 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(const auto art = getArt(slot, false))
{ {
if(art->isCombined()) if(art->isCombined())
@ -858,7 +840,7 @@ void CArtifactSet::removeArtifact(ArtifactPosition slot)
} }
} }
std::pair<const CArtifactInstance *, const CArtifactInstance *> CArtifactSet::searchForConstituent(const ArtifactID & aid) const const CArtifactInstance * CArtifactSet::getCombinedArtWithPart(const ArtifactID & partId) const
{ {
for(const auto & slot : artifactsInBackpack) for(const auto & slot : artifactsInBackpack)
{ {
@ -867,24 +849,12 @@ std::pair<const CArtifactInstance *, const CArtifactInstance *> CArtifactSet::se
{ {
for(auto & ci : art->getPartsInfo()) for(auto & ci : art->getPartsInfo())
{ {
if(ci.art->getTypeId() == aid) if(ci.art->getTypeId() == partId)
{ return art;
return {art, ci.art};
}
} }
} }
} }
return {nullptr, nullptr}; return 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;
} }
const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const
@ -905,6 +875,11 @@ const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const
return nullptr; return nullptr;
} }
void CArtifactSet::lockSlot(const ArtifactPosition & pos)
{
setNewArtSlot(pos, nullptr, true);
}
bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck) const bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck) const
{ {
if(bearerType() == ArtBearer::ALTAR) if(bearerType() == ArtBearer::ALTAR)
@ -916,7 +891,7 @@ bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockChe
return true; //no slot means not used return true; //no slot means not used
} }
void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, ConstTransitivePtr<CArtifactInstance> art, bool locked) void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked)
{ {
assert(!vstd::contains(artifactsWorn, slot)); assert(!vstd::contains(artifactsWorn, slot));
@ -932,31 +907,12 @@ void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, ConstTransitiveP
else else
{ {
auto position = artifactsInBackpack.begin() + slot - ArtifactPosition::BACKPACK_START; auto position = artifactsInBackpack.begin() + slot - ArtifactPosition::BACKPACK_START;
slotInfo = &(*artifactsInBackpack.emplace(position, ArtSlotInfo())); slotInfo = &(*artifactsInBackpack.emplace(position));
} }
slotInfo->artifact = art; slotInfo->artifact = art;
slotInfo->locked = locked; 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) void CArtifactSet::artDeserializationFix(CBonusSystemNode *node)
{ {
for(auto & elem : artifactsWorn) for(auto & elem : artifactsWorn)

View File

@ -175,10 +175,10 @@ private:
struct DLL_LINKAGE ArtSlotInfo struct DLL_LINKAGE ArtSlotInfo
{ {
ConstTransitivePtr<CArtifactInstance> artifact; CArtifactInstance * artifact;
ui8 locked; //if locked, then artifact points to the combined artifact bool locked; //if locked, then artifact points to the combined artifact
ArtSlotInfo() : locked(false) {} ArtSlotInfo() : artifact(nullptr), locked(false) {}
const CArtifactInstance * getArt() const; const CArtifactInstance * getArt() const;
template <typename Handler> void serialize(Handler & h) template <typename Handler> void serialize(Handler & h)
@ -197,32 +197,20 @@ public:
std::map<ArtifactPosition, ArtSlotInfo> artifactsWorn; //map<position,artifact_id>; 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::map<ArtifactPosition, ArtSlotInfo> artifactsWorn; //map<position,artifact_id>; 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 ArtSlotInfo artifactsTransitionPos; // Used as transition position for dragAndDrop artifact exchange
void setNewArtSlot(const ArtifactPosition & slot, ConstTransitivePtr<CArtifactInstance> art, bool locked);
void eraseArtSlot(const ArtifactPosition & slot);
const ArtSlotInfo * getSlot(const ArtifactPosition & pos) const; const ArtSlotInfo * getSlot(const ArtifactPosition & pos) const;
const CArtifactInstance * getArt(const ArtifactPosition & pos, bool excludeLocked = true) const; //nullptr - no artifact void lockSlot(const ArtifactPosition & pos);
CArtifactInstance * getArt(const ArtifactPosition & pos, bool excludeLocked = true); //nullptr - no artifact CArtifactInstance * getArt(const ArtifactPosition & pos, bool excludeLocked = true) const;
/// Looks for equipped artifact with given ID and returns its slot ID or -1 if none /// Looks for first artifact with given ID
/// (if more than one such artifact lower ID is returned)
ArtifactPosition getArtPos(const ArtifactID & aid, bool onlyWorn = true, bool allowLocked = true) const; ArtifactPosition getArtPos(const ArtifactID & aid, bool onlyWorn = true, bool allowLocked = true) const;
ArtifactPosition getArtPos(const CArtifactInstance * art) const; ArtifactPosition getArtPos(const CArtifactInstance * art) const;
std::vector<ArtifactPosition> getAllArtPositions(const ArtifactID & aid, bool onlyWorn, bool allowLocked, bool getAll) const;
std::vector<ArtifactPosition> getBackpackArtPositions(const ArtifactID & aid) const;
const CArtifactInstance * getArtByInstanceId(const ArtifactInstanceID & artInstId) const; const CArtifactInstance * getArtByInstanceId(const ArtifactInstanceID & artInstId) const;
/// Search for constituents of assemblies in backpack which do not have an ArtifactPosition bool hasArt(const ArtifactID & aid, bool onlyWorn = false, bool searchCombinedParts = false) const;
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 isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck = 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 ArtBearer::ArtBearer bearerType() const = 0;
virtual ArtPlacementMap putArtifact(ArtifactPosition slot, CArtifactInstance * art); virtual ArtPlacementMap putArtifact(const ArtifactPosition & slot, CArtifactInstance * art);
virtual void removeArtifact(ArtifactPosition slot); virtual void removeArtifact(const ArtifactPosition & slot);
virtual ~CArtifactSet(); virtual ~CArtifactSet() = default;
template <typename Handler> void serialize(Handler &h) template <typename Handler> void serialize(Handler &h)
{ {
@ -233,10 +221,11 @@ public:
void artDeserializationFix(CBonusSystemNode *node); void artDeserializationFix(CBonusSystemNode *node);
void serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName); void serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName);
protected: const CArtifactInstance * getCombinedArtWithPart(const ArtifactID & partId) const;
std::pair<const CArtifactInstance *, const CArtifactInstance *> searchForConstituent(const ArtifactID & aid) const;
private: private:
void setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked);
void serializeJsonHero(JsonSerializeFormat & handler); void serializeJsonHero(JsonSerializeFormat & handler);
void serializeJsonCreature(JsonSerializeFormat & handler); void serializeJsonCreature(JsonSerializeFormat & handler);
void serializeJsonCommander(JsonSerializeFormat & handler); void serializeJsonCommander(JsonSerializeFormat & handler);

View File

@ -49,13 +49,13 @@ const std::vector<CCombinedArtifactInstance::PartInfo> & CCombinedArtifactInstan
return partsInfo; return partsInfo;
} }
void CCombinedArtifactInstance::addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap) void CCombinedArtifactInstance::addPlacementMap(const CArtifactSet::ArtPlacementMap & placementMap)
{ {
if(!placementMap.empty()) if(!placementMap.empty())
for(auto & part : partsInfo) for(auto & part : partsInfo)
{ {
assert(placementMap.find(part.art) != placementMap.end()); if(placementMap.find(part.art) != placementMap.end())
part.slot = placementMap.at(part.art); part.slot = placementMap.at(part.art);
} }
} }
@ -167,28 +167,6 @@ bool CArtifactInstance::isScroll() const
return artType->isScroll(); 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() void CArtifactInstance::deserializationFix()
{ {
setType(artType); setType(artType);

View File

@ -25,7 +25,7 @@ protected:
public: public:
struct PartInfo struct PartInfo
{ {
ConstTransitivePtr<CArtifactInstance> art; CArtifactInstance * art;
ArtifactPosition slot; ArtifactPosition slot;
template <typename Handler> void serialize(Handler & h) template <typename Handler> void serialize(Handler & h)
{ {
@ -39,7 +39,7 @@ public:
// Checks if supposed part inst is part of this combined art inst // Checks if supposed part inst is part of this combined art inst
bool isPart(const CArtifactInstance * supposedPart) const; bool isPart(const CArtifactInstance * supposedPart) const;
const std::vector<PartInfo> & getPartsInfo() const; const std::vector<PartInfo> & getPartsInfo() const;
void addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap); void addPlacementMap(const CArtifactSet::ArtPlacementMap & placementMap);
template <typename Handler> void serialize(Handler & h) template <typename Handler> void serialize(Handler & h)
{ {
@ -88,9 +88,6 @@ public:
bool assumeDestRemoved = false) const; bool assumeDestRemoved = false) const;
bool isCombined() const; bool isCombined() const;
bool isScroll() 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(); void deserializationFix();
template <typename Handler> void serialize(Handler & h) template <typename Handler> void serialize(Handler & h)

View File

@ -863,7 +863,7 @@ ArtBearer::ArtBearer CStackInstance::bearerType() const
return ArtBearer::CREATURE; return ArtBearer::CREATURE;
} }
CStackInstance::ArtPlacementMap CStackInstance::putArtifact(ArtifactPosition pos, CArtifactInstance * art) CStackInstance::ArtPlacementMap CStackInstance::putArtifact(const ArtifactPosition & pos, CArtifactInstance * art)
{ {
assert(!getArt(pos)); assert(!getArt(pos));
assert(art->canBePutAt(this, pos)); assert(art->canBePutAt(this, pos));
@ -872,7 +872,7 @@ CStackInstance::ArtPlacementMap CStackInstance::putArtifact(ArtifactPosition pos
return CArtifactSet::putArtifact(pos, art); return CArtifactSet::putArtifact(pos, art);
} }
void CStackInstance::removeArtifact(ArtifactPosition pos) void CStackInstance::removeArtifact(const ArtifactPosition & pos)
{ {
assert(getArt(pos)); assert(getArt(pos));

View File

@ -126,8 +126,8 @@ public:
void setArmyObj(const CArmedInstance *ArmyObj); void setArmyObj(const CArmedInstance *ArmyObj);
virtual void giveStackExp(TExpType exp); virtual void giveStackExp(TExpType exp);
bool valid(bool allowUnrandomized) const; bool valid(bool allowUnrandomized) const;
ArtPlacementMap putArtifact(ArtifactPosition pos, CArtifactInstance * art) override;//from CArtifactSet ArtPlacementMap putArtifact(const ArtifactPosition & pos, CArtifactInstance * art) override;//from CArtifactSet
void removeArtifact(ArtifactPosition pos) override; void removeArtifact(const ArtifactPosition & pos) override;
ArtBearer::ArtBearer bearerType() const override; //from CArtifactSet ArtBearer::ArtBearer bearerType() const override; //from CArtifactSet
std::string nodeName() const override; //from CBonusSystemnode std::string nodeName() const override; //from CBonusSystemnode
void deserializationFix(); void deserializationFix();

View File

@ -122,7 +122,7 @@ public:
virtual bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) = 0; 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 giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) = 0;
virtual bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble = std::nullopt) = 0; virtual bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble = std::nullopt) = 0;
virtual void removeArtifact(const ArtifactLocation& al) = 0; virtual void removeArtifact(const ArtifactLocation& al) = 0;
virtual bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) = 0; virtual bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) = 0;

View File

@ -1640,7 +1640,7 @@ bool CGameState::giveHeroArtifact(CGHeroInstance * h, const ArtifactID & aid)
auto slot = ArtifactUtils::getArtAnyPosition(h, aid); auto slot = ArtifactUtils::getArtAnyPosition(h, aid);
if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot)) if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
{ {
ai->putAt(*h, slot); map->putArtifactInstance(*h, ai, slot);
return true; return true;
} }
else else

View File

@ -147,7 +147,7 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr
if (!locked && !takeable) if (!locked && !takeable)
{ {
logGlobal->debug("Removing artifact %s from slot %d of hero %s", art->artType->getJsonKey(), al.slot.getNum(), hero.hero->getHeroTypeName()); 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 true;
} }
return false; return false;
@ -327,7 +327,7 @@ void CGameStateCampaign::giveCampaignBonusToHero(CGHeroInstance * hero)
CArtifactInstance * scroll = ArtifactUtils::createScroll(SpellID(curBonus->info2)); CArtifactInstance * scroll = ArtifactUtils::createScroll(SpellID(curBonus->info2));
const auto slot = ArtifactUtils::getArtAnyPosition(hero, scroll->getTypeId()); const auto slot = ArtifactUtils::getArtAnyPosition(hero, scroll->getTypeId());
if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot)) if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
scroll->putAt(*hero, slot); gameState->map->putArtifactInstance(*hero, scroll, slot);
else else
logGlobal->error("Cannot give starting scroll - no free slots!"); logGlobal->error("Cannot give starting scroll - no free slots!");
break; break;
@ -423,7 +423,7 @@ void CGameStateCampaign::transferMissingArtifacts(const CampaignTravel & travelO
auto * artifact = donorHero->getArt(artLocation); 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()); 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) if (receiver)
{ {
@ -431,7 +431,7 @@ void CGameStateCampaign::transferMissingArtifacts(const CampaignTravel & travelO
const auto slot = ArtifactUtils::getArtAnyPosition(receiver, artifact->getTypeId()); const auto slot = ArtifactUtils::getArtAnyPosition(receiver, artifact->getTypeId());
if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot)) if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
artifact->putAt(*receiver, slot); gameState->map->putArtifactInstance(*receiver, artifact, slot);
else else
logGlobal->error("Cannot transfer artifact - no free slots!"); logGlobal->error("Cannot transfer artifact - no free slots!");
} }

View File

@ -1156,7 +1156,7 @@ std::string CGHeroInstance::getBiographyTextID() const
return ""; //for random hero 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)); assert(art->canBePutAt(this, pos));
@ -1165,7 +1165,7 @@ CGHeroInstance::ArtPlacementMap CGHeroInstance::putArtifact(ArtifactPosition pos
return CArtifactSet::putArtifact(pos, art); return CArtifactSet::putArtifact(pos, art);
} }
void CGHeroInstance::removeArtifact(ArtifactPosition pos) void CGHeroInstance::removeArtifact(const ArtifactPosition & pos)
{ {
auto art = getArt(pos); auto art = getArt(pos);
assert(art); assert(art);
@ -1201,7 +1201,7 @@ void CGHeroInstance::removeSpellbook()
if(hasSpellbook()) if(hasSpellbook())
{ {
getArt(ArtifactPosition::SPELLBOOK)->removeFrom(*this, ArtifactPosition::SPELLBOOK); cb->removeArtifact(ArtifactLocation(this->id, ArtifactPosition::SPELLBOOK));
} }
} }

View File

@ -241,8 +241,8 @@ public:
void initHero(vstd::RNG & rand); void initHero(vstd::RNG & rand);
void initHero(vstd::RNG & rand, const HeroTypeID & SUBID); void initHero(vstd::RNG & rand, const HeroTypeID & SUBID);
ArtPlacementMap putArtifact(ArtifactPosition pos, CArtifactInstance * art) override; ArtPlacementMap putArtifact(const ArtifactPosition & pos, CArtifactInstance * art) override;
void removeArtifact(ArtifactPosition pos) override; void removeArtifact(const ArtifactPosition & pos) override;
void initExp(vstd::RNG & rand); void initExp(vstd::RNG & rand);
void initArmy(vstd::RNG & rand, IArmyDescriptor *dst = nullptr); void initArmy(vstd::RNG & rand, IArmyDescriptor *dst = nullptr);
void pushPrimSkill(PrimarySkill which, int val); void pushPrimSkill(PrimarySkill which, int val);

View File

@ -152,7 +152,7 @@ void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const
} }
else else
{ {
const auto * assembly = h->getAssemblyByConstituent(elem); const auto * assembly = h->getCombinedArtWithPart(elem);
assert(assembly); assert(assembly);
auto parts = assembly->getPartsInfo(); auto parts = assembly->getPartsInfo();

View File

@ -772,9 +772,8 @@ void CGArtifact::initObj(vstd::RNG & rand)
{ {
if (!storedArtifact) if (!storedArtifact)
{ {
auto * a = new CArtifactInstance(); storedArtifact = ArtifactUtils::createArtifact(ArtifactID());
cb->gameState()->map->addNewArtifactInstance(a); cb->gameState()->map->addNewArtifactInstance(storedArtifact);
storedArtifact = a;
} }
if(!storedArtifact->artType) if(!storedArtifact->artType)
storedArtifact->setType(getArtifact().toArtifact()); storedArtifact->setType(getArtifact().toArtifact());
@ -901,7 +900,7 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
void CGArtifact::pick(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()); cb->removeObject(this, h->getOwner());
} }

View File

@ -552,6 +552,34 @@ void CMap::eraseArtifactInstance(CArtifactInstance * art)
artInstances[art->getId().getNum()].dellNull(); 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) void CMap::addNewQuestInstance(CQuest* quest)
{ {
quest->qid = static_cast<si32>(quests.size()); quest->qid = static_cast<si32>(quests.size());

View File

@ -110,6 +110,9 @@ public:
void addNewArtifactInstance(CArtifactSet & artSet); void addNewArtifactInstance(CArtifactSet & artSet);
void addNewArtifactInstance(ConstTransitivePtr<CArtifactInstance> art); void addNewArtifactInstance(ConstTransitivePtr<CArtifactInstance> art);
void eraseArtifactInstance(CArtifactInstance * 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 addNewQuestInstance(CQuest * quest);
void removeQuestInstance(CQuest * quest); void removeQuestInstance(CQuest * quest);

View File

@ -917,7 +917,7 @@ void CMapLoaderH3M::loadArtifactsOfHero(CGHeroInstance * hero)
hero->artifactsInBackpack.clear(); hero->artifactsInBackpack.clear();
while(!hero->artifactsWorn.empty()) while(!hero->artifactsWorn.empty())
hero->eraseArtSlot(hero->artifactsWorn.begin()->first); hero->removeArtifact(hero->artifactsWorn.begin()->first);
} }
for(int i = 0; i < features.artifactSlotsCount; i++) for(int i = 0; i < features.artifactSlotsCount; i++)
@ -959,7 +959,7 @@ bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot)
if(ArtifactID(artifactID).toArtifact()->canBePutAt(hero, ArtifactPosition(slot))) if(ArtifactID(artifactID).toArtifact()->canBePutAt(hero, ArtifactPosition(slot)))
{ {
auto * artifact = ArtifactUtils::createArtifact(artifactID); auto * artifact = ArtifactUtils::createArtifact(artifactID);
artifact->putAt(*hero, ArtifactPosition(slot)); map->putArtifactInstance(*hero, artifact, slot);
map->addNewArtifactInstance(artifact); map->addNewArtifactInstance(artifact);
} }
else else

View File

@ -1471,8 +1471,7 @@ void NewArtifact::applyGs(CGameState *gs)
{ {
auto art = ArtifactUtils::createArtifact(artId, spellId); auto art = ArtifactUtils::createArtifact(artId, spellId);
gs->map->addNewArtifactInstance(art); gs->map->addNewArtifactInstance(art);
PutArtifact pa(ArtifactLocation(artHolder, pos), false); PutArtifact pa(art->getId(), ArtifactLocation(artHolder, pos), false);
pa.art = art;
pa.applyGs(gs); pa.applyGs(gs);
} }
@ -1591,14 +1590,14 @@ void RebalanceStacks::applyGs(CGameState *gs)
const auto dstHero = dynamic_cast<CGHeroInstance*>(dst.army.get()); const auto dstHero = dynamic_cast<CGHeroInstance*>(dst.army.get());
auto srcStack = const_cast<CStackInstance*>(src.getStack()); auto srcStack = const_cast<CStackInstance*>(src.getStack());
auto dstStack = const_cast<CStackInstance*>(dst.getStack()); auto dstStack = const_cast<CStackInstance*>(dst.getStack());
if(auto srcArt = srcStack->getArt(ArtifactPosition::CREATURE_SLOT)) if(srcStack->getArt(ArtifactPosition::CREATURE_SLOT))
{ {
if(auto dstArt = dstStack->getArt(ArtifactPosition::CREATURE_SLOT)) if(auto dstArt = dstStack->getArt(ArtifactPosition::CREATURE_SLOT))
{ {
auto dstSlot = ArtifactUtils::getArtBackpackPosition(srcHero, dstArt->getTypeId()); auto dstSlot = ArtifactUtils::getArtBackpackPosition(srcHero, dstArt->getTypeId());
if(srcHero && dstSlot != ArtifactPosition::PRE_FIRST) 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 - artifact can be lost :/
else else
@ -1610,12 +1609,12 @@ void RebalanceStacks::applyGs(CGameState *gs)
ea.applyGs(gs); ea.applyGs(gs);
logNetwork->warn("Cannot move artifact! No free slots"); 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 //TODO: choose from dialog
} }
else //just move to the other slot before stack gets erased 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) if (stackExp)
@ -1685,14 +1684,13 @@ void BulkSmartRebalanceStacks::applyGs(CGameState *gs)
void PutArtifact::applyGs(CGameState *gs) void PutArtifact::applyGs(CGameState *gs)
{ {
// Ensure that artifact has been correctly added via NewArtifact pack auto art = gs->getArtInstance(id);
assert(vstd::contains(gs->map->artInstances, art));
assert(!art->getParentNodes().empty()); assert(!art->getParentNodes().empty());
auto hero = gs->getHero(al.artHolder); auto hero = gs->getHero(al.artHolder);
assert(hero); assert(hero);
assert(art && art->canBePutAt(hero, al.slot)); assert(art && art->canBePutAt(hero, al.slot));
assert(ArtifactUtils::checkIfSlotValid(*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) void BulkEraseArtifacts::applyGs(CGameState *gs)
@ -1731,15 +1729,13 @@ void BulkEraseArtifacts::applyGs(CGameState *gs)
{ {
logGlobal->debug("Erasing artifact %s", slotInfo->artifact->artType->getNameTranslated()); logGlobal->debug("Erasing artifact %s", slotInfo->artifact->artType->getNameTranslated());
} }
auto art = artSet->getArt(slot); gs->map->removeArtifactInstance(*artSet, slot);
assert(art);
art->removeFrom(*artSet, slot);
} }
} }
void BulkMoveArtifacts::applyGs(CGameState *gs) void BulkMoveArtifacts::applyGs(CGameState *gs)
{ {
const auto bulkArtsRemove = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & artSet) const auto bulkArtsRemove = [gs](std::vector<LinkedSlots> & artsPack, CArtifactSet & artSet)
{ {
std::vector<ArtifactPosition> packToRemove; std::vector<ArtifactPosition> packToRemove;
for(const auto & slotsPair : artsPack) for(const auto & slotsPair : artsPack)
@ -1750,20 +1746,16 @@ void BulkMoveArtifacts::applyGs(CGameState *gs)
}); });
for(const auto & slot : packToRemove) for(const auto & slot : packToRemove)
{ gs->map->removeArtifactInstance(artSet, slot);
auto * art = artSet.getArt(slot);
assert(art);
art->removeFrom(artSet, slot);
}
}; };
const auto bulkArtsPut = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & initArtSet, CArtifactSet & dstArtSet) const auto bulkArtsPut = [gs](std::vector<LinkedSlots> & artsPack, CArtifactSet & initArtSet, CArtifactSet & dstArtSet)
{ {
for(const auto & slotsPair : artsPack) for(const auto & slotsPair : artsPack)
{ {
auto * art = initArtSet.getArt(slotsPair.srcPos); auto * art = initArtSet.getArt(slotsPair.srcPos);
assert(art); 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) for(const auto slot : slotsInvolved)
{ {
const auto constituentInstance = hero->getArt(slot); const auto constituentInstance = hero->getArt(slot);
constituentInstance->removeFrom(*hero, slot); gs->map->removeArtifactInstance(*hero, slot);
if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot) if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot)
combinedArt->addPart(constituentInstance, slot); combinedArt->addPart(constituentInstance, slot);
@ -1849,7 +1841,7 @@ void AssembledArtifact::applyGs(CGameState *gs)
} }
// Put new combined artifacts // Put new combined artifacts
combinedArt->putAt(*hero, al.slot); gs->map->putArtifactInstance(*hero, combinedArt, al.slot);
} }
void DisassembledArtifact::applyGs(CGameState *gs) void DisassembledArtifact::applyGs(CGameState *gs)
@ -1859,14 +1851,14 @@ void DisassembledArtifact::applyGs(CGameState *gs)
auto disassembledArt = hero->getArt(al.slot); auto disassembledArt = hero->getArt(al.slot);
assert(disassembledArt); assert(disassembledArt);
auto parts = disassembledArt->getPartsInfo(); const auto parts = disassembledArt->getPartsInfo();
disassembledArt->removeFrom(*hero, al.slot); gs->map->removeArtifactInstance(*hero, al.slot);
for(auto & part : parts) for(auto & part : parts)
{ {
// ArtifactPosition::PRE_FIRST is value of main part slot -> it'll replace combined artifact in its pos // 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); auto slot = (ArtifactUtils::isSlotEquipment(part.slot) ? part.slot : al.slot);
disassembledArt->detachFrom(*part.art); disassembledArt->detachFrom(*part.art);
part.art->putAt(*hero, slot); gs->map->putArtifactInstance(*hero, part.art, slot);
} }
gs->map->eraseArtifactInstance(disassembledArt); gs->map->eraseArtifactInstance(disassembledArt);
} }

View File

@ -965,14 +965,14 @@ struct DLL_LINKAGE CArtifactOperationPack : CPackForClient
struct DLL_LINKAGE PutArtifact : CArtifactOperationPack struct DLL_LINKAGE PutArtifact : CArtifactOperationPack
{ {
PutArtifact() = default; PutArtifact() = default;
explicit PutArtifact(const ArtifactLocation & dst, bool askAssemble = true) explicit PutArtifact(const ArtifactInstanceID & id, const ArtifactLocation & dst, bool askAssemble = true)
: al(dst), askAssemble(askAssemble) : al(dst), askAssemble(askAssemble), id(id)
{ {
} }
ArtifactLocation al; ArtifactLocation al;
bool askAssemble; bool askAssemble;
ConstTransitivePtr<CArtifactInstance> art; ArtifactInstanceID id;
void applyGs(CGameState * gs) override; void applyGs(CGameState * gs) override;
void visitTyped(ICPackVisitor & visitor) override; void visitTyped(ICPackVisitor & visitor) override;
@ -981,7 +981,7 @@ struct DLL_LINKAGE PutArtifact : CArtifactOperationPack
{ {
h & al; h & al;
h & askAssemble; h & askAssemble;
h & art; h & id;
} }
}; };

View File

@ -143,10 +143,28 @@ bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const
for(const auto & elem : artifactsRequirements) for(const auto & elem : artifactsRequirements)
{ {
// check required amount of artifacts // 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; return false;
if(!hero->hasArt(elem.first)) // Check if art has no own slot. (As part of combined in backpack)
reqSlots += hero->getAssemblyByConstituent(elem.first)->getPartsInfo().size() - 2; if(hero->getArtPos(elem.first, false) == ArtifactPosition::PRE_FIRST)
reqSlots += hero->getCombinedArtWithPart(elem.first)->getPartsInfo().size() - 2;
} }
if(!ArtifactUtils::isBackpackFreeSlots(hero, reqSlots)) if(!ArtifactUtils::isBackpackFreeSlots(hero, reqSlots))
return false; return false;

View File

@ -2718,15 +2718,15 @@ bool CGameHandler::switchArtifactsCostume(const PlayerColor & player, const Obje
// Second, find the necessary artifacts for the costume // Second, find the necessary artifacts for the costume
for(const auto & artPos : costumeArtMap) 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 bma.artsPack0.emplace_back(BulkMoveArtifacts::LinkedSlots
{ {
artSet->getArtPos(artFittingSet.getArt(availableArts.front())), artSet->getArtPos(artFittingSet.getArt(slot)),
artPos.first artPos.first
}); });
artFittingSet.removeArtifact(availableArts.front()); artFittingSet.removeArtifact(slot);
if(ArtifactUtils::isSlotBackpack(availableArts.front())) if(ArtifactUtils::isSlotBackpack(slot))
estimateBackpackSize--; estimateBackpackSize--;
} }
} }
@ -3757,9 +3757,10 @@ bool CGameHandler::swapStacks(const StackLocation & sl1, const StackLocation & s
} }
} }
bool CGameHandler::putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble) bool CGameHandler::putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble)
{ {
assert(art && art->artType); const auto artInst = getArtInstance(id);
assert(artInst && artInst->artType);
ArtifactLocation dst(al.artHolder, ArtifactPosition::PRE_FIRST); ArtifactLocation dst(al.artHolder, ArtifactPosition::PRE_FIRST);
dst.creature = al.creature; dst.creature = al.creature;
auto putTo = getArtSet(al); auto putTo = getArtSet(al);
@ -3767,11 +3768,11 @@ bool CGameHandler::putArtifact(const ArtifactLocation & al, const CArtifactInsta
if(al.slot == ArtifactPosition::FIRST_AVAILABLE) 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()) 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 else
{ {
@ -3786,10 +3787,9 @@ bool CGameHandler::putArtifact(const ArtifactLocation & al, const CArtifactInsta
askAssemble = false; askAssemble = false;
} }
if(art->canBePutAt(putTo, dst.slot)) if(artInst->canBePutAt(putTo, dst.slot))
{ {
PutArtifact pa(dst, askAssemble.value()); PutArtifact pa(id, dst, askAssemble.value());
pa.art = art;
sendAndApply(&pa); sendAndApply(&pa);
return true; return true;
} }

View File

@ -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 CArtifact * artType, const SpellID & spellId, const ArtifactPosition & pos);
bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) override; 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 giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override;
bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble) override; bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble) override;
void removeArtifact(const ArtifactLocation &al) override; void removeArtifact(const ArtifactLocation &al) override;
void removeArtifact(const ObjectInstanceID & srcId, const std::vector<ArtifactPosition> & slotsPack); void removeArtifact(const ObjectInstanceID & srcId, const std::vector<ArtifactPosition> & slotsPack);
bool moveArtifact(const PlayerColor & player, const ArtifactLocation & src, const ArtifactLocation & dst) override; bool moveArtifact(const PlayerColor & player, const ArtifactLocation & src, const ArtifactLocation & dst) override;

View File

@ -72,7 +72,7 @@ public:
bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) 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 giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override {return false;}
bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble) override {return false;} bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble) override {return false;}
void removeArtifact(const ArtifactLocation &al) override {} void removeArtifact(const ArtifactLocation &al) override {}
bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;} bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;}