1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-04 23:17:41 +02:00

Remove pointers from artifacts

This commit is contained in:
Ivan Savenko 2025-03-30 23:09:43 +03:00
parent 4ed13409c2
commit d34b47bb20
29 changed files with 211 additions and 146 deletions

View File

@ -1050,22 +1050,22 @@ void AIGateway::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance
{
for(auto p : h->artifactsWorn)
{
if(p.second.artifact)
if(p.second.getArt())
allArtifacts.push_back(ArtifactLocation(h->id, p.first));
}
}
for(auto slot : h->artifactsInBackpack)
allArtifacts.push_back(ArtifactLocation(h->id, h->getArtPos(slot.artifact)));
allArtifacts.push_back(ArtifactLocation(h->id, h->getArtPos(slot.getArt())));
if(otherh)
{
for(auto p : otherh->artifactsWorn)
{
if(p.second.artifact)
if(p.second.getArt())
allArtifacts.push_back(ArtifactLocation(otherh->id, p.first));
}
for(auto slot : otherh->artifactsInBackpack)
allArtifacts.push_back(ArtifactLocation(otherh->id, otherh->getArtPos(slot.artifact)));
allArtifacts.push_back(ArtifactLocation(otherh->id, otherh->getArtPos(slot.getArt())));
}
//we give stuff to one hero or another, depending on giveStuffToFirstHero
@ -1087,7 +1087,7 @@ void AIGateway::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance
auto s = artHolder->getSlot(location.slot);
if(!s || s->locked) //we can't move locks
continue;
auto artifact = s->artifact;
auto artifact = s->getArt();
if(!artifact)
continue;
//FIXME: why are the above possible to be null?
@ -1111,10 +1111,10 @@ void AIGateway::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance
for(auto slot : artifact->getType()->getPossibleSlots().at(target->bearerType()))
{
auto otherSlot = target->getSlot(slot);
if(otherSlot && otherSlot->artifact) //we need to exchange artifact for better one
if(otherSlot && otherSlot->getArt()) //we need to exchange artifact for better one
{
int64_t otherArtifactScore = getArtifactScoreForHero(target, otherSlot->artifact);
logAi->trace( "Comparing artifacts of %s: %s vs %s. Score: %d vs %d", target->getHeroTypeName(), artifact->getType()->getJsonKey(), otherSlot->artifact->getType()->getJsonKey(), artifactScore, otherArtifactScore);
int64_t otherArtifactScore = getArtifactScoreForHero(target, otherSlot->getArt());
logAi->trace( "Comparing artifacts of %s: %s vs %s. Score: %d vs %d", target->getHeroTypeName(), artifact->getType()->getJsonKey(), otherSlot->getArt()->getType()->getJsonKey(), artifactScore, otherArtifactScore);
//if that artifact is better than what we have, pick it
//combined artifacts are not always allowed to move
@ -1132,9 +1132,9 @@ void AIGateway::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance
logAi->trace(
"Exchange artifacts %s <-> %s",
artifact->getType()->getJsonKey(),
otherSlot->artifact->getType()->getJsonKey());
otherSlot->getArt()->getType()->getJsonKey());
if(!otherSlot->artifact->canBePutAt(artHolder, location.slot, true))
if(!otherSlot->getArt()->canBePutAt(artHolder, location.slot, true))
{
ArtifactLocation destLocation(target->id, slot);
ArtifactLocation backpack(artHolder->id, ArtifactPosition::BACKPACK_START);
@ -1144,7 +1144,7 @@ void AIGateway::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance
}
else
{
cb->swapArtifacts(location, ArtifactLocation(target->id, target->getArtPos(otherSlot->artifact)));
cb->swapArtifacts(location, ArtifactLocation(target->id, target->getArtPos(otherSlot->getArt())));
}
changeMade = true;

View File

@ -1177,22 +1177,22 @@ void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * ot
{
for(auto p : h->artifactsWorn)
{
if(p.second.artifact)
if(p.second.getArt())
allArtifacts.push_back(ArtifactLocation(h->id, p.first));
}
}
for(auto slot : h->artifactsInBackpack)
allArtifacts.push_back(ArtifactLocation(h->id, h->getArtPos(slot.artifact)));
allArtifacts.push_back(ArtifactLocation(h->id, h->getArtPos(slot.getArt())));
if(otherh)
{
for(auto p : otherh->artifactsWorn)
{
if(p.second.artifact)
if(p.second.getArt())
allArtifacts.push_back(ArtifactLocation(otherh->id, p.first));
}
for(auto slot : otherh->artifactsInBackpack)
allArtifacts.push_back(ArtifactLocation(otherh->id, otherh->getArtPos(slot.artifact)));
allArtifacts.push_back(ArtifactLocation(otherh->id, otherh->getArtPos(slot.getArt())));
}
//we give stuff to one hero or another, depending on giveStuffToFirstHero
@ -1213,7 +1213,7 @@ void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * ot
auto s = cb->getHero(location.artHolder)->getSlot(location.slot);
if(!s || s->locked) //we can't move locks
continue;
auto artifact = s->artifact;
auto artifact = s->getArt();
if(!artifact)
continue;
//FIXME: why are the above possible to be null?
@ -1235,13 +1235,13 @@ void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * ot
for(auto slot : artifact->getType()->getPossibleSlots().at(target->bearerType()))
{
auto otherSlot = target->getSlot(slot);
if(otherSlot && otherSlot->artifact) //we need to exchange artifact for better one
if(otherSlot && otherSlot->getArt()) //we need to exchange artifact for better one
{
//if that artifact is better than what we have, pick it
if(compareArtifacts(artifact, otherSlot->artifact) && artifact->canBePutAt(target, slot, true)) //combined artifacts are not always allowed to move
if(compareArtifacts(artifact, otherSlot->getArt()) && artifact->canBePutAt(target, slot, true)) //combined artifacts are not always allowed to move
{
ArtifactLocation destLocation(target->id, slot);
cb->swapArtifacts(location, ArtifactLocation(target->id, target->getArtPos(otherSlot->artifact)));
cb->swapArtifacts(location, ArtifactLocation(target->id, target->getArtPos(otherSlot->getArt())));
changeMade = true;
break;
}

View File

@ -152,10 +152,10 @@ void CArtifactsOfHeroQuickBackpack::setHero(const CGHeroInstance * hero)
std::map<const ArtifactID, const CArtifactInstance*> filteredArts;
for(auto & slotInfo : curHero->artifactsInBackpack)
if(slotInfo.artifact->getTypeId() != artInSlotId && !slotInfo.artifact->isScroll() &&
slotInfo.artifact->getType()->canBePutAt(curHero, filterBySlot, true))
if(slotInfo.getArt()->getTypeId() != artInSlotId && !slotInfo.getArt()->isScroll() &&
slotInfo.getArt()->getType()->canBePutAt(curHero, filterBySlot, true))
{
filteredArts.insert(std::pair(slotInfo.artifact->getTypeId(), slotInfo.artifact));
filteredArts.insert(std::pair(slotInfo.getArt()->getTypeId(), slotInfo.getArt()));
}
std::map<const SpellID, const CArtifactInstance*> filteredScrolls;
@ -164,8 +164,8 @@ void CArtifactsOfHeroQuickBackpack::setHero(const CGHeroInstance * hero)
{
for(auto & slotInfo : curHero->artifactsInBackpack)
{
if(slotInfo.artifact->isScroll() && slotInfo.artifact->getScrollSpellID() != scrollInSlotSpellId)
filteredScrolls.insert(std::pair(slotInfo.artifact->getScrollSpellID(), slotInfo.artifact));
if(slotInfo.getArt()->isScroll() && slotInfo.getArt()->getScrollSpellID() != scrollInSlotSpellId)
filteredScrolls.insert(std::pair(slotInfo.getArt()->getScrollSpellID(), slotInfo.getArt()));
}
}

View File

@ -268,13 +268,13 @@ void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosit
if(auto slotInfo = curHero->getSlot(slot))
{
artPlace->lockSlot(slotInfo->locked);
artPlace->setArtifact(slotInfo->artifact->getTypeId(), slotInfo->artifact->getScrollSpellID());
if(slotInfo->locked || slotInfo->artifact->isCombined())
artPlace->setArtifact(slotInfo->getArt()->getTypeId(), slotInfo->getArt()->getScrollSpellID());
if(slotInfo->locked || slotInfo->getArt()->isCombined())
return;
// If the artifact is part of at least one combined artifact, add additional information
std::map<const ArtifactID, std::vector<ArtifactID>> arts;
for(const auto combinedArt : slotInfo->artifact->getType()->getPartOf())
for(const auto combinedArt : slotInfo->getArt()->getType()->getPartOf())
{
assert(combinedArt->isCombined());
arts.try_emplace(combinedArt->getId());

View File

@ -156,7 +156,7 @@ void CAltarArtifacts::updateAltarSlots()
{
newArtsFromBulkMove.erase(std::remove_if(newArtsFromBulkMove.begin(), newArtsFromBulkMove.end(), [artForRemove = art](auto & slotInfo)
{
return slotInfo.artifact == artForRemove;
return slotInfo.artifactID == artForRemove->getId();
}));
}
for(const auto & slotInfo : newArtsFromBulkMove)
@ -164,9 +164,9 @@ void CAltarArtifacts::updateAltarSlots()
for(const auto & altarSlot : offerTradePanel->slots)
if(altarSlot->id == -1)
{
altarSlot->setID(slotInfo.artifact->getTypeId().num);
altarSlot->subtitle->setText(std::to_string(calcExpCost(slotInfo.artifact->getTypeId())));
tradeSlotsMap.try_emplace(altarSlot, slotInfo.artifact);
altarSlot->setID(slotInfo.getArt()->getTypeId().num);
altarSlot->subtitle->setText(std::to_string(calcExpCost(slotInfo.getArt()->getTypeId())));
tradeSlotsMap.try_emplace(altarSlot, slotInfo.getArt());
break;
}
}

View File

@ -489,7 +489,7 @@ CStackWindow::CommanderMainSection::CommanderMainSection(CStackWindow * owner, i
for(auto equippedArtifact : parent->info->commander->artifactsWorn)
{
Point artPos = getArtifactPos(equippedArtifact.first);
const auto commanderArt = equippedArtifact.second.artifact;
const auto commanderArt = equippedArtifact.second.getArt();
assert(commanderArt);
auto artPlace = std::make_shared<CCommanderArtPlace>(artPos, parent->info->owner, equippedArtifact.first, commanderArt->getTypeId());
artifacts.push_back(artPlace);

View File

@ -151,7 +151,7 @@ DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::commanderSlots(
DLL_LINKAGE bool ArtifactUtils::isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot)
{
return slot.second.artifact
return slot.second.getArt()
&& !slot.second.locked
&& !vstd::contains(unmovableSlots(), slot.first);
}

View File

@ -225,7 +225,7 @@ bool CArtifact::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, b
if(ArtifactUtils::isSlotBackpack(slot))
return true;
CArtifactFittingSet fittingSet(artSet->bearerType());
CArtifactFittingSet fittingSet(artSet->getCallback(), artSet->bearerType());
fittingSet.artifactsWorn = artSet->artifactsWorn;
if(assumeDestRemoved)
fittingSet.removeArtifact(slot);
@ -712,8 +712,8 @@ const CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, boo
{
if(const ArtSlotInfo * si = getSlot(pos))
{
if(si->artifact && (!excludeLocked || !si->locked))
return si->artifact;
if(si->getArt() && (!excludeLocked || !si->locked))
return si->getArt();
}
return nullptr;
}
@ -722,8 +722,8 @@ ArtifactInstanceID CArtifactSet::getArtID(const ArtifactPosition & pos, bool exc
{
if(const ArtSlotInfo * si = getSlot(pos))
{
if(si->artifact && (!excludeLocked || !si->locked))
return si->artifact->getId();
if(si->getArt() && (!excludeLocked || !si->locked))
return si->getArt()->getId();
}
return {};
}
@ -732,7 +732,7 @@ ArtifactPosition CArtifactSet::getArtPos(const ArtifactID & aid, bool onlyWorn,
{
for(const auto & [slot, slotInfo] : artifactsWorn)
{
if(slotInfo.artifact->getTypeId() == aid && (allowLocked || !slotInfo.locked))
if(slotInfo.getArt()->getTypeId() == aid && (allowLocked || !slotInfo.locked))
return slot;
}
if(!onlyWorn)
@ -752,12 +752,12 @@ ArtifactPosition CArtifactSet::getArtPos(const ArtifactID & aid, bool onlyWorn,
const CArtifactInstance * CArtifactSet::getArtByInstanceId(const ArtifactInstanceID & artInstId) const
{
for(const auto & i : artifactsWorn)
if(i.second.artifact->getId() == artInstId)
return i.second.artifact;
if(i.second.getArt()->getId() == artInstId)
return i.second.getArt();
for(const auto & i : artifactsInBackpack)
if(i.artifact->getId() == artInstId)
return i.artifact;
if(i.getArt()->getId() == artInstId)
return i.getArt();
return nullptr;
}
@ -795,22 +795,21 @@ CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition &
ArtPlacementMap resArtPlacement;
const auto putToSlot = [this](const ArtifactPosition & targetSlot, const CArtifactInstance * targetArt, bool locked)
{
ArtSlotInfo * slotInfo;
ArtSlotInfo newSlot(targetArt, locked);
if(targetSlot == ArtifactPosition::TRANSITION_POS)
{
slotInfo = &artifactsTransitionPos;
artifactsTransitionPos = newSlot;
}
else if(ArtifactUtils::isSlotEquipment(targetSlot))
{
slotInfo = &artifactsWorn[targetSlot];
artifactsWorn.insert_or_assign(targetSlot, newSlot);
}
else
{
auto position = artifactsInBackpack.begin() + targetSlot - ArtifactPosition::BACKPACK_START;
slotInfo = &(*artifactsInBackpack.emplace(position));
artifactsInBackpack.insert(position, newSlot);
}
slotInfo->artifact = targetArt;
slotInfo->locked = locked;
};
putToSlot(slot, art, false);
@ -818,41 +817,45 @@ CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition &
{
const CArtifactInstance * mainPart = nullptr;
for(const auto & part : art->getPartsInfo())
if(vstd::contains(part.art->getType()->getPossibleSlots().at(bearerType()), slot)
if(vstd::contains(part.getArtifact()->getType()->getPossibleSlots().at(bearerType()), slot)
&& (part.slot == ArtifactPosition::PRE_FIRST))
{
mainPart = part.art;
mainPart = part.getArtifact();
break;
}
for(const auto & part : art->getPartsInfo())
{
if(part.art != mainPart)
if(part.getArtifact() != mainPart)
{
auto partSlot = part.slot;
if(!part.art->getType()->canBePutAt(this, partSlot))
partSlot = ArtifactUtils::getArtAnyPosition(this, part.art->getTypeId());
if(!part.getArtifact()->getType()->canBePutAt(this, partSlot))
partSlot = ArtifactUtils::getArtAnyPosition(this, part.getArtifact()->getTypeId());
assert(ArtifactUtils::isSlotEquipment(partSlot));
putToSlot(partSlot, part.art, true);
resArtPlacement.emplace(part.art, partSlot);
putToSlot(partSlot, part.getArtifact(), true);
resArtPlacement.emplace(part.getArtifact(), partSlot);
}
else
{
resArtPlacement.emplace(part.art, part.slot);
resArtPlacement.emplace(part.getArtifact(), part.slot);
}
}
}
return resArtPlacement;
}
CArtifactSet::CArtifactSet(IGameCallback * cb)
:artifactsTransitionPos(cb)
{}
void CArtifactSet::removeArtifact(const ArtifactPosition & slot)
{
const auto eraseArtSlot = [this](const ArtifactPosition & slotForErase)
{
if(slotForErase == ArtifactPosition::TRANSITION_POS)
{
artifactsTransitionPos.artifact = nullptr;
artifactsTransitionPos.artifactID = {};
}
else if(ArtifactUtils::isSlotBackpack(slotForErase))
{
@ -876,7 +879,7 @@ void CArtifactSet::removeArtifact(const ArtifactPosition & slot)
if(part.slot != ArtifactPosition::PRE_FIRST)
{
assert(getArt(part.slot, false));
assert(getArt(part.slot, false) == part.art);
assert(getArt(part.slot, false) == part.getArtifact());
}
eraseArtSlot(part.slot);
}
@ -889,12 +892,12 @@ const CArtifactInstance * CArtifactSet::getCombinedArtWithPart(const ArtifactID
{
for(const auto & slot : artifactsInBackpack)
{
auto art = slot.artifact;
auto art = slot.getArt();
if(art->isCombined())
{
for(auto & ci : art->getPartsInfo())
{
if(ci.art->getTypeId() == partId)
if(ci.getArtifact()->getTypeId() == partId)
return art;
}
}
@ -925,7 +928,7 @@ void CArtifactSet::lockSlot(const ArtifactPosition & pos)
if(pos == ArtifactPosition::TRANSITION_POS)
artifactsTransitionPos.locked = true;
else if(ArtifactUtils::isSlotEquipment(pos))
artifactsWorn[pos].locked = true;
artifactsWorn.at(pos).locked = true;
else
{
assert(artifactsInBackpack.size() > pos - ArtifactPosition::BACKPACK_START);
@ -939,7 +942,7 @@ bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockChe
return artifactsInBackpack.size() < GameConstants::ALTAR_ARTIFACTS_SLOTS;
if(const ArtSlotInfo *s = getSlot(pos))
return (onlyLockCheck || !s->artifact) && !s->locked;
return (onlyLockCheck || !s->getArt()) && !s->locked;
return true; //no slot means not used
}
@ -947,8 +950,8 @@ bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockChe
void CArtifactSet::artDeserializationFix(CBonusSystemNode *node)
{
for(auto & elem : artifactsWorn)
if(elem.second.artifact && !elem.second.locked)
node->attachToSource(*elem.second.artifact);
if(elem.second.getArt() && !elem.second.locked)
node->attachToSource(*elem.second.getArt());
}
void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName, CMap * map)
@ -995,7 +998,7 @@ void CArtifactSet::serializeJsonHero(JsonSerializeFormat & handler, CMap * map)
{
backpackTemp.reserve(artifactsInBackpack.size());
for(const ArtSlotInfo & info : artifactsInBackpack)
backpackTemp.push_back(info.artifact->getTypeId());
backpackTemp.push_back(info.getArt()->getTypeId());
}
handler.serializeIdArray(NArtifactPosition::backpack, backpackTemp);
if(!handler.saving)
@ -1033,7 +1036,7 @@ void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const Artifa
if(info != nullptr && !info->locked)
{
artifactID = info->artifact->getTypeId();
artifactID = info->getArt()->getTypeId();
handler.serializeId(NArtifactPosition::namesHero[slot.num], artifactID, ArtifactID::NONE);
}
}
@ -1058,13 +1061,15 @@ void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const Artifa
}
}
CArtifactFittingSet::CArtifactFittingSet(ArtBearer::ArtBearer bearer)
: bearer(bearer)
CArtifactFittingSet::CArtifactFittingSet(IGameCallback *cb, ArtBearer::ArtBearer bearer)
: GameCallbackHolder(cb)
, CArtifactSet(cb)
, bearer(bearer)
{
}
CArtifactFittingSet::CArtifactFittingSet(const CArtifactSet & artSet)
: CArtifactFittingSet(artSet.bearerType())
: CArtifactFittingSet(artSet.getCallback(), artSet.bearerType())
{
artifactsWorn = artSet.artifactsWorn;
artifactsInBackpack = artSet.artifactsInBackpack;

View File

@ -15,6 +15,7 @@
#include "bonuses/Bonus.h"
#include "bonuses/CBonusSystemNode.h"
#include "GameConstants.h"
#include "GameCallbackHolder.h"
#include "IHandlerBase.h"
#include "serializer/Serializeable.h"
@ -178,24 +179,27 @@ private:
void loadComponents(CArtifact * art, const JsonNode & node);
};
struct DLL_LINKAGE ArtSlotInfo
struct DLL_LINKAGE ArtSlotInfo : public GameCallbackHolder
{
const CArtifactInstance * artifact;
bool locked; //if locked, then artifact points to the combined artifact
ArtifactInstanceID artifactID;
bool locked = false; //if locked, then artifact points to the combined artifact
explicit ArtSlotInfo(IGameCallback * cb);
ArtSlotInfo(const CArtifactInstance * artifact, bool locked);
ArtSlotInfo() : artifact(nullptr), locked(false) {}
const CArtifactInstance * getArt() const;
ArtifactInstanceID getID() const;
template <typename Handler> void serialize(Handler & h)
{
h & artifact;
h & artifactID;
h & locked;
}
};
class DLL_LINKAGE CArtifactSet : public virtual Serializeable
{
public:
using ArtPlacementMap = std::map<const CArtifactInstance*, ArtifactPosition>;
@ -214,9 +218,11 @@ public:
bool hasArt(const ArtifactID & aid, bool onlyWorn = false, bool searchCombinedParts = false) const;
bool isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck = false) const;
virtual IGameCallback * getCallback() const = 0;
virtual ArtBearer::ArtBearer bearerType() const = 0;
virtual ArtPlacementMap putArtifact(const ArtifactPosition & slot, const CArtifactInstance * art);
virtual void removeArtifact(const ArtifactPosition & slot);
CArtifactSet(IGameCallback * cb);
virtual ~CArtifactSet() = default;
template <typename Handler> void serialize(Handler &h)
@ -239,10 +245,11 @@ private:
};
// Used to try on artifacts before the claimed changes have been applied
class DLL_LINKAGE CArtifactFittingSet : public CArtifactSet
class DLL_LINKAGE CArtifactFittingSet : public CArtifactSet, public GameCallbackHolder
{
IGameCallback * getCallback() const final { return cb; }
public:
CArtifactFittingSet(ArtBearer::ArtBearer Bearer);
CArtifactFittingSet(IGameCallback *cb, ArtBearer::ArtBearer Bearer);
explicit CArtifactFittingSet(const CArtifactSet & artSet);
ArtBearer::ArtBearer bearerType() const override;

View File

@ -13,10 +13,29 @@
#include "ArtifactUtils.h"
#include "CArtHandler.h"
#include "IGameCallback.h"
#include "networkPacks/ArtifactLocation.h"
VCMI_LIB_NAMESPACE_BEGIN
CCombinedArtifactInstance::PartInfo::PartInfo(IGameCallback * cb)
:GameCallbackHolder(cb)
{}
CCombinedArtifactInstance::PartInfo::PartInfo(const CArtifactInstance * artifact, ArtifactPosition slot)
: GameCallbackHolder(artifact->cb)
, artifactID(artifact->getId())
, slot(slot)
{
}
const CArtifactInstance * CCombinedArtifactInstance::PartInfo::getArtifact() const
{
if (artifactID.hasValue())
return cb->getArtInstance(artifactID);
return nullptr;
}
void CCombinedArtifactInstance::addPart(const CArtifactInstance * art, const ArtifactPosition & slot)
{
auto artInst = static_cast<CArtifactInstance*>(this);
@ -37,7 +56,7 @@ bool CCombinedArtifactInstance::isPart(const CArtifactInstance * supposedPart) c
for(const PartInfo & constituent : partsInfo)
{
if(constituent.art == supposedPart)
if(constituent.artifactID == supposedPart->getId())
return true;
}
@ -59,8 +78,8 @@ void CCombinedArtifactInstance::addPlacementMap(const CArtifactSet::ArtPlacement
if(!placementMap.empty())
for(auto & part : partsInfo)
{
if(placementMap.find(part.art) != placementMap.end())
part.slot = placementMap.at(part.art);
if(placementMap.find(part.getArtifact()) != placementMap.end())
part.slot = placementMap.at(part.getArtifact());
}
}
@ -105,22 +124,16 @@ void CGrowingArtifactInstance::growingUp()
}
}
void CArtifactInstance::init()
CArtifactInstance::CArtifactInstance(IGameCallback *cb, const CArtifact * art)
:CArtifactInstance(cb)
{
// Artifact to be randomized
id = static_cast<ArtifactInstanceID>(ArtifactID::NONE);
setNodeType(ARTIFACT_INSTANCE);
}
CArtifactInstance::CArtifactInstance(const CArtifact * art)
{
init();
setType(art);
}
CArtifactInstance::CArtifactInstance()
CArtifactInstance::CArtifactInstance(IGameCallback *cb)
: CCombinedArtifactInstance(cb)
, CBonusSystemNode(ARTIFACT_INSTANCE)
{
init();
}
void CArtifactInstance::setType(const CArtifact * art)
@ -173,7 +186,7 @@ void CArtifactInstance::deserializationFix()
{
setType(artTypeID.toArtifact());
for(PartInfo & part : partsInfo)
attachToSource(*part.art);
attachToSource(*part.getArtifact());
}
VCMI_LIB_NAMESPACE_END

View File

@ -16,22 +16,27 @@ VCMI_LIB_NAMESPACE_BEGIN
struct ArtifactLocation;
class DLL_LINKAGE CCombinedArtifactInstance
class DLL_LINKAGE CCombinedArtifactInstance : public GameCallbackHolder
{
protected:
CCombinedArtifactInstance() = default;
using GameCallbackHolder::GameCallbackHolder;
public:
struct PartInfo
struct PartInfo : public GameCallbackHolder
{
const CArtifactInstance * art;
explicit PartInfo(IGameCallback * cb);
PartInfo(const CArtifactInstance * artifact, ArtifactPosition slot);
ArtifactInstanceID artifactID;
ArtifactPosition slot;
const CArtifactInstance * getArtifact() const;
template <typename Handler> void serialize(Handler & h)
{
h & art;
h & artifactID;
h & slot;
}
PartInfo(const CArtifactInstance * art = nullptr, const ArtifactPosition & slot = ArtifactPosition::PRE_FIRST)
: art(art), slot(slot) {};
};
void addPart(const CArtifactInstance * art, const ArtifactPosition & slot);
// Checks if supposed part inst is part of this combined art inst
@ -68,14 +73,12 @@ class DLL_LINKAGE CArtifactInstance final
: public CBonusSystemNode, public CCombinedArtifactInstance, public CScrollArtifactInstance, public CGrowingArtifactInstance
{
protected:
void init();
ArtifactInstanceID id;
ArtifactID artTypeID;
public:
CArtifactInstance(const CArtifact * art);
CArtifactInstance();
public:
CArtifactInstance(IGameCallback *cb, const CArtifact * art);
CArtifactInstance(IGameCallback *cb);
void setType(const CArtifact * art);
std::string nodeName() const override;
ArtifactID getTypeId() const;

View File

@ -678,6 +678,7 @@ void CCreatureSet::serializeJson(JsonSerializeFormat & handler, const std::strin
CStackInstance::CStackInstance(IGameCallback *cb, bool isHypothetic)
: CBonusSystemNode(isHypothetic)
, GameCallbackHolder(cb)
, CArtifactSet(cb)
, nativeTerrain(this, Selector::type()(BonusType::TERRAIN_NATIVE))
, initiative(this, Selector::type()(BonusType::STACKS_SPEED))
{

View File

@ -77,6 +77,7 @@ class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDe
ObjectInstanceID armyInstanceID; //stack must be part of some army, army must be part of some object
IGameCallback * getCallback() const final { return cb; }
public:
struct RandomStackInfo
{

View File

@ -353,7 +353,7 @@ bool CStack::unitHasAmmoCart(const battle::Unit * unit) const
const auto * ownerHero = battle->battleGetOwnerHero(unit);
if(ownerHero && ownerHero->artifactsWorn.find(ArtifactPosition::MACH2) != ownerHero->artifactsWorn.end())
{
if(battle->battleGetOwnerHero(unit)->artifactsWorn.at(ArtifactPosition::MACH2).artifact->getTypeId() == ArtifactID::AMMO_CART)
if(battle->battleGetOwnerHero(unit)->artifactsWorn.at(ArtifactPosition::MACH2).getArt()->getTypeId() == ArtifactID::AMMO_CART)
{
return true;
}

View File

@ -137,7 +137,7 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr
return false;
// TODO: why would there be nullptr artifacts?
const CArtifactInstance *art = info->artifact;
const CArtifactInstance *art = info->getArt();
if(!art)
return false;

View File

@ -254,6 +254,7 @@ int CGHeroInstance::movementPointsLimitCached(bool onLand, const TurnInfo * ti)
CGHeroInstance::CGHeroInstance(IGameCallback * cb)
: CArmedInstance(cb),
CArtifactSet(cb),
tacticFormationEnabled(false),
inTownGarrison(false),
moveDir(4),

View File

@ -74,6 +74,8 @@ private:
ui32 movement; //remaining movement points
bool inTownGarrison; // if hero is in town garrison
IGameCallback * getCallback() const final { return cb; }
public:
//////////////////////////////////////////////////////////////////////////
//format: 123

View File

@ -77,8 +77,9 @@ std::set<EMarketMode> CGMarket::availableModes() const
return getMarketHandler()->availableModes();
}
CGMarket::CGMarket(IGameCallback *cb):
CGObjectInstance(cb)
CGMarket::CGMarket(IGameCallback *cb)
: IMarket(cb)
, CGObjectInstance(cb)
{}
std::vector<TradeItemBuy> CGBlackMarket::availableItemsIds(EMarketMode mode) const

View File

@ -264,6 +264,7 @@ TownFortifications CGTownInstance::fortificationsLevel() const
}
CGTownInstance::CGTownInstance(IGameCallback *cb):
IMarket(cb),
CGDwelling(cb),
built(0),
destroyed(0),

View File

@ -164,8 +164,8 @@ void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const
// Disassemble this backpack artifact
for(const auto & ci : parts)
{
if(ci.art->getTypeId() != elem)
cb->giveHeroNewArtifact(h, ci.art->getTypeId(), ArtifactPosition::BACKPACK_START);
if(ci.getArtifact()->getTypeId() != elem)
cb->giveHeroNewArtifact(h, ci.getArtifact()->getTypeId(), ArtifactPosition::BACKPACK_START);
}
continue;

View File

@ -140,8 +140,8 @@ int IMarket::availableUnits(const EMarketMode mode, const int marketItemSerial)
}
}
IMarket::IMarket()
:altarArtifactsStorage(std::make_unique<CArtifactSetAltar>())
IMarket::IMarket(IGameCallback *cb)
:altarArtifactsStorage(std::make_unique<CArtifactSetAltar>(cb))
{
}

View File

@ -18,12 +18,19 @@ VCMI_LIB_NAMESPACE_BEGIN
class DLL_LINKAGE IMarket : public virtual Serializeable, boost::noncopyable
{
public:
IMarket();
explicit IMarket(IGameCallback *cb);
~IMarket();
class CArtifactSetAltar : public CArtifactSet
{
IGameCallback *cb;
public:
CArtifactSetAltar(IGameCallback *cb)
: CArtifactSet(cb)
, cb(cb)
{}
IGameCallback * getCallback() const override {return cb;};
ArtBearer::ArtBearer bearerType() const override {return ArtBearer::ALTAR;};
};

View File

@ -488,7 +488,7 @@ void CMap::removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & s
for(auto & part : artifact->getPartsInfo())
{
if(part.slot != ArtifactPosition::PRE_FIRST)
partsMap.try_emplace(part.art, ArtifactPosition::PRE_FIRST);
partsMap.try_emplace(part.getArtifact(), ArtifactPosition::PRE_FIRST);
}
artifact->addPlacementMap(partsMap);
}
@ -766,17 +766,17 @@ CArtifactInstance * CMap::createScroll(const SpellID & spellId)
CArtifactInstance * CMap::createSingleArtifact(const ArtifactID & artId, const SpellID & spellId)
{
return new CArtifactInstance();
return new CArtifactInstance(cb);
}
CArtifactInstance * CMap::createArtifact(const ArtifactID & artID, const SpellID & spellId)
{
if(!artID.hasValue())
return new CArtifactInstance(); // random, empty //TODO: make this illegal & remove?
return new CArtifactInstance(cb); // random, empty //TODO: make this illegal & remove?
auto art = artID.toArtifact();
auto artInst = new CArtifactInstance(art);
auto artInst = new CArtifactInstance(cb, art);
if(art->isCombined() && !art->isFused())
{
for(const auto & part : art->getConstituents())

View File

@ -1209,7 +1209,7 @@ void RemoveObject::applyGs(CGameState *gs)
beatenHero->tempOwner = PlayerColor::NEUTRAL; //no one owns beaten hero
vstd::erase_if(beatenHero->artifactsInBackpack, [](const ArtSlotInfo& asi)
{
return asi.artifact->getTypeId() == ArtifactID::GRAIL;
return asi.getArt()->getTypeId() == ArtifactID::GRAIL;
});
if(beatenHero->getVisitedTown())
@ -1715,14 +1715,14 @@ void BulkEraseArtifacts::applyGs(CGameState *gs)
const auto slotInfo = artSet->getSlot(slot);
if(slotInfo->locked)
{
logGlobal->debug("Erasing locked artifact: %s", slotInfo->artifact->getType()->getNameTranslated());
logGlobal->debug("Erasing locked artifact: %s", slotInfo->getArt()->getType()->getNameTranslated());
DisassembledArtifact dis;
dis.al.artHolder = artHolder;
for(auto & slotInfoWorn : artSet->artifactsWorn)
{
auto art = slotInfoWorn.second.artifact;
if(art->isCombined() && art->isPart(slotInfo->artifact))
auto art = slotInfoWorn.second.getArt();
if(art->isCombined() && art->isPart(slotInfo->getArt()))
{
dis.al.slot = artSet->getArtPos(art);
break;
@ -1734,7 +1734,7 @@ void BulkEraseArtifacts::applyGs(CGameState *gs)
}
else
{
logGlobal->debug("Erasing artifact %s", slotInfo->artifact->getType()->getNameTranslated());
logGlobal->debug("Erasing artifact %s", slotInfo->getArt()->getType()->getNameTranslated());
}
gs->getMap().removeArtifactInstance(*artSet, slot);
}
@ -1863,8 +1863,8 @@ void DisassembledArtifact::applyGs(CGameState *gs)
{
// 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->detachFromSource(*part.art);
gs->getMap().putArtifactInstance(*hero, part.art->getId(), slot);
disassembledArt->detachFromSource(*part.getArtifact());
gs->getMap().putArtifactInstance(*hero, part.getArtifact()->getId(), slot);
}
gs->getMap().eraseArtifactInstance(disassembledArt->getId());
}
@ -2460,18 +2460,30 @@ void SetRewardableConfiguration::applyGs(CGameState *gs)
}
}
ArtSlotInfo::ArtSlotInfo(IGameCallback * cb)
: GameCallbackHolder(cb)
{
}
ArtSlotInfo::ArtSlotInfo(const CArtifactInstance * artifact, bool locked)
: GameCallbackHolder(artifact->cb)
, artifactID(artifact->getId())
, locked(locked)
{
}
const CArtifactInstance * ArtSlotInfo::getArt() const
{
if(locked)
return nullptr;
return artifact;
return cb->getArtInstance(artifactID);
}
ArtifactInstanceID ArtSlotInfo::getID() const
{
if(locked || artifact == nullptr)
if(locked)
return {};
return artifact->getId();
return artifactID;
}
VCMI_LIB_NAMESPACE_END

View File

@ -144,18 +144,18 @@ bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const
// check required amount of artifacts
size_t artCnt = 0;
for(const auto & [slot, slotInfo] : hero->artifactsWorn)
if(slotInfo.artifact->getTypeId() == elem.first)
if(slotInfo.getArt()->getTypeId() == elem.first)
artCnt++;
for(auto & slotInfo : hero->artifactsInBackpack)
if(slotInfo.artifact->getTypeId() == elem.first)
if(slotInfo.getArt()->getTypeId() == elem.first)
{
artCnt++;
}
else if(slotInfo.artifact->isCombined())
else if(slotInfo.getArt()->isCombined())
{
for(const auto & partInfo : slotInfo.artifact->getPartsInfo())
if(partInfo.art->getTypeId() == elem.first)
for(const auto & partInfo : slotInfo.getArt()->getPartsInfo())
if(partInfo.getArtifact()->getTypeId() == elem.first)
artCnt++;
}

View File

@ -168,7 +168,11 @@ public:
void load(std::vector<T> &data)
{
uint32_t length = readAndCheckLength();
data.resize(length);
if constexpr (std::is_base_of_v<GameCallbackHolder, T>)
data.resize(length, T(cb));
else
data.resize(length);
for(uint32_t i=0;i<length;i++)
load( data[i]);
}
@ -373,7 +377,14 @@ public:
for(uint32_t i=0;i<length;i++)
{
load(key);
load(data[key]);
if constexpr (std::is_base_of_v<GameCallbackHolder, T2>)
{
data.try_emplace(key, cb);
load(data.at(key));
}
else
load(data[key]);
}
}
void load(std::string &data)

View File

@ -83,11 +83,11 @@ void HeroArtifactsWidget::obtainData()
std::vector<const CArtifact *> combinedArtifactsParts;
for (const auto & [artPosition, artSlotInfo] : fittingSet.artifactsWorn)
{
addArtifactToTable(LIBRARY->arth->getById(artSlotInfo.artifact->getTypeId())->getIndex(), artPosition);
addArtifactToTable(LIBRARY->arth->getById(artSlotInfo.getArt()->getTypeId())->getIndex(), artPosition);
}
for (const auto & art : hero.artifactsInBackpack)
{
addArtifactToTable(LIBRARY->arth->getById(art.artifact->getTypeId())->getIndex(), ArtifactPosition::BACKPACK_START);
addArtifactToTable(LIBRARY->arth->getById(art.getArt()->getTypeId())->getIndex(), ArtifactPosition::BACKPACK_START);
}
}
@ -105,12 +105,12 @@ void HeroArtifactsWidget::commitChanges()
for(const auto & [artPosition, artSlotInfo] : fittingSet.artifactsWorn)
{
hero.putArtifact(artPosition, artSlotInfo.artifact);
hero.putArtifact(artPosition, artSlotInfo.getArt());
}
for(const auto & art : fittingSet.artifactsInBackpack)
{
hero.putArtifact(ArtifactPosition::BACKPACK_START + static_cast<int>(hero.artifactsInBackpack.size()), art.artifact);
hero.putArtifact(ArtifactPosition::BACKPACK_START + static_cast<int>(hero.artifactsInBackpack.size()), art.getArt());
}
}
@ -157,12 +157,12 @@ void HeroArtifactsDelegate::updateModelData(QAbstractItemModel * model, const QM
for(const auto & [artPosition, artSlotInfo] : hero.artifactsWorn)
{
auto slotText = NArtifactPosition::namesHero[artPosition.num];
textList += QString("%1: %2").arg(QString::fromStdString(slotText)).arg(QString::fromStdString(artSlotInfo.artifact->getType()->getNameTranslated()));
textList += QString("%1: %2").arg(QString::fromStdString(slotText)).arg(QString::fromStdString(artSlotInfo.getArt()->getType()->getNameTranslated()));
}
textList += QString("%1:").arg(QString::fromStdString(NArtifactPosition::backpack));
for(const auto & art : hero.artifactsInBackpack)
{
textList += QString::fromStdString(art.artifact->getType()->getNameTranslated());
textList += QString::fromStdString(art.getArt()->getType()->getNameTranslated());
}
setModelTextData(model, index, textList);
}

View File

@ -642,12 +642,12 @@ ModCompatibilityInfo MapController::modAssessmentMap(const CMap & map)
for(const auto & [_, slotInfo] : hero->artifactsWorn)
{
extractEntityMod(slotInfo.artifact->getTypeId().toEntity(LIBRARY));
extractEntityMod(slotInfo.getArt()->getTypeId().toEntity(LIBRARY));
}
for(const auto & art : hero->artifactsInBackpack)
{
extractEntityMod(art.artifact->getTypeId().toEntity(LIBRARY));
extractEntityMod(art.getArt()->getTypeId().toEntity(LIBRARY));
}
}
}

View File

@ -2678,7 +2678,7 @@ bool CGameHandler::bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceI
auto & slotsDstSrc = ma.artsPack1;
// Temporary fitting set for artifacts. Used to select available slots before sending data.
CArtifactFittingSet artFittingSet(pdstSet->bearerType());
CArtifactFittingSet artFittingSet(gameState()->callback, pdstSet->bearerType());
auto moveArtifact = [this, &artFittingSet, dstId](const CArtifactInstance * artifact,
ArtifactPosition srcSlot, std::vector<MoveArtifactInfo> & slots) -> void
@ -2714,7 +2714,7 @@ bool CGameHandler::bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceI
{
for(auto & slotInfo : artSet->artifactsInBackpack)
{
auto slot = artSet->getArtPos(slotInfo.artifact);
auto slot = artSet->getArtPos(slotInfo.getArt());
slots.emplace_back(slot, slot);
}
};
@ -2754,8 +2754,8 @@ bool CGameHandler::bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceI
// Move over artifacts that are in backpack
for(auto & slotInfo : psrcSet->artifactsInBackpack)
{
moveArtifact(psrcSet->getArt(psrcSet->getArtPos(slotInfo.artifact)),
psrcSet->getArtPos(slotInfo.artifact), slotsSrcDst);
moveArtifact(psrcSet->getArt(psrcSet->getArtPos(slotInfo.getArt())),
psrcSet->getArtPos(slotInfo.getArt()), slotsSrcDst);
}
}
}