1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Merge pull request #3069 from SoundSSGood/artifact-location-id

ArtifactLocation now use ID for artHolder identification
This commit is contained in:
Ivan Savenko
2023-11-01 14:41:36 +02:00
committed by GitHub
39 changed files with 339 additions and 390 deletions

View File

@@ -74,6 +74,49 @@ DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::constituentWorn
return positions;
}
DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::allWornSlots()
{
static const std::vector<ArtifactPosition> positions =
{
ArtifactPosition::HEAD,
ArtifactPosition::SHOULDERS,
ArtifactPosition::NECK,
ArtifactPosition::RIGHT_HAND,
ArtifactPosition::LEFT_HAND,
ArtifactPosition::TORSO,
ArtifactPosition::RIGHT_RING,
ArtifactPosition::LEFT_RING,
ArtifactPosition::FEET,
ArtifactPosition::MISC1,
ArtifactPosition::MISC2,
ArtifactPosition::MISC3,
ArtifactPosition::MISC4,
ArtifactPosition::MISC5,
ArtifactPosition::MACH1,
ArtifactPosition::MACH2,
ArtifactPosition::MACH3,
ArtifactPosition::MACH4,
ArtifactPosition::SPELLBOOK
};
return positions;
}
DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::commanderSlots()
{
static const std::vector<ArtifactPosition> positions =
{
ArtifactPosition::COMMANDER1,
ArtifactPosition::COMMANDER2,
ArtifactPosition::COMMANDER3,
ArtifactPosition::COMMANDER4,
ArtifactPosition::COMMANDER5,
ArtifactPosition::COMMANDER6
};
return positions;
}
DLL_LINKAGE bool ArtifactUtils::isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot)
{
return slot.second.artifact

View File

@@ -31,6 +31,8 @@ namespace ArtifactUtils
// TODO: Make this constexpr when the toolset is upgraded
DLL_LINKAGE const std::vector<ArtifactPosition> & unmovableSlots();
DLL_LINKAGE const std::vector<ArtifactPosition> & constituentWornSlots();
DLL_LINKAGE const std::vector<ArtifactPosition> & allWornSlots();
DLL_LINKAGE const std::vector<ArtifactPosition> & commanderSlots();
DLL_LINKAGE bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot);
DLL_LINKAGE bool checkSpellbookIsNeeded(const CGHeroInstance * heroPtr, const ArtifactID & artID, const ArtifactPosition & slot);
DLL_LINKAGE bool isSlotBackpack(const ArtifactPosition & slot);

View File

@@ -693,8 +693,8 @@ void CArtHandler::makeItCommanderArt(CArtifact * a, bool onlyCommander)
a->possibleSlots[ArtBearer::HERO].clear();
a->possibleSlots[ArtBearer::CREATURE].clear();
}
for (int i = ArtifactPosition::COMMANDER1; i <= ArtifactPosition::COMMANDER6; ++i)
a->possibleSlots[ArtBearer::COMMANDER].push_back(ArtifactPosition(i));
for(const auto & slot : ArtifactUtils::commanderSlots())
a->possibleSlots[ArtBearer::COMMANDER].push_back(ArtifactPosition(slot));
}
bool CArtHandler::legalArtifact(const ArtifactID & id)
@@ -975,9 +975,9 @@ const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const
}
if(vstd::contains(artifactsWorn, pos))
return &artifactsWorn.at(pos);
if(pos >= ArtifactPosition::AFTER_LAST )
if(ArtifactUtils::isSlotBackpack(pos))
{
int backpackPos = (int)pos - ArtifactPosition::BACKPACK_START;
auto backpackPos = pos - ArtifactPosition::BACKPACK_START;
if(backpackPos < 0 || backpackPos >= artifactsInBackpack.size())
return nullptr;
else
@@ -1080,9 +1080,9 @@ void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const s
void CArtifactSet::serializeJsonHero(JsonSerializeFormat & handler, CMap * map)
{
for(ArtifactPosition ap = ArtifactPosition::HEAD; ap < ArtifactPosition::AFTER_LAST; ap.advance(1))
for(const auto & slot : ArtifactUtils::allWornSlots())
{
serializeJsonSlot(handler, ap, map);
serializeJsonSlot(handler, slot, map);
}
std::vector<ArtifactID> backpackTemp;

View File

@@ -155,9 +155,9 @@ void CArtifactInstance::setId(ArtifactInstanceID id)
this->id = id;
}
bool CArtifactInstance::canBePutAt(const ArtifactLocation & al, bool assumeDestRemoved) const
bool CArtifactInstance::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, bool assumeDestRemoved) const
{
return artType->canBePutAt(al.getHolderArtSet(), al.slot, assumeDestRemoved);
return artType->canBePutAt(artSet, slot, assumeDestRemoved);
}
bool CArtifactInstance::isCombined() const
@@ -165,15 +165,15 @@ bool CArtifactInstance::isCombined() const
return artType->isCombined();
}
void CArtifactInstance::putAt(const ArtifactLocation & al)
void CArtifactInstance::putAt(CArtifactSet & set, const ArtifactPosition slot)
{
auto placementMap = al.getHolderArtSet()->putArtifact(al.slot, this);
auto placementMap = set.putArtifact(slot, this);
addPlacementMap(placementMap);
}
void CArtifactInstance::removeFrom(const ArtifactLocation & al)
void CArtifactInstance::removeFrom(CArtifactSet & set, const ArtifactPosition slot)
{
al.getHolderArtSet()->removeArtifact(al.slot);
set.removeArtifact(slot);
for(auto & part : partsInfo)
{
if(part.slot != ArtifactPosition::PRE_FIRST)
@@ -181,10 +181,10 @@ void CArtifactInstance::removeFrom(const ArtifactLocation & al)
}
}
void CArtifactInstance::move(const ArtifactLocation & src, const ArtifactLocation & dst)
void CArtifactInstance::move(CArtifactSet & srcSet, const ArtifactPosition srcSlot, CArtifactSet & dstSet, const ArtifactPosition dstSlot)
{
removeFrom(src);
putAt(dst);
removeFrom(srcSet, srcSlot);
putAt(dstSet, dstSlot);
}
void CArtifactInstance::deserializationFix()

View File

@@ -84,11 +84,12 @@ public:
ArtifactInstanceID getId() const;
void setId(ArtifactInstanceID id);
bool canBePutAt(const ArtifactLocation & al, bool assumeDestRemoved = false) const;
bool canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot = ArtifactPosition::FIRST_AVAILABLE,
bool assumeDestRemoved = false) const;
bool isCombined() const;
void putAt(const ArtifactLocation & al);
void removeFrom(const ArtifactLocation & al);
void move(const ArtifactLocation & src, const ArtifactLocation & dst);
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();
template <typename Handler> void serialize(Handler & h, const int version)

View File

@@ -458,7 +458,7 @@ const CStackInstance & CCreatureSet::getStack(const SlotID & slot) const
return *getStackPtr(slot);
}
const CStackInstance * CCreatureSet::getStackPtr(const SlotID & slot) const
CStackInstance * CCreatureSet::getStackPtr(const SlotID & slot) const
{
if(hasStackAtSlot(slot))
return stacks.find(slot)->second;
@@ -870,7 +870,7 @@ ArtBearer::ArtBearer CStackInstance::bearerType() const
CStackInstance::ArtPlacementMap CStackInstance::putArtifact(ArtifactPosition pos, CArtifactInstance * art)
{
assert(!getArt(pos));
assert(art->artType->canBePutAt(this, pos));
assert(art->canBePutAt(this, pos));
attachTo(*art);
return CArtifactSet::putArtifact(pos, art);

View File

@@ -253,7 +253,7 @@ public:
void setToArmy(CSimpleArmy &src); //erases all our army and moves stacks from src to us; src MUST NOT be an armed object! WARNING: use it wisely. Or better do not use at all.
const CStackInstance & getStack(const SlotID & slot) const; //stack must exist
const CStackInstance * getStackPtr(const SlotID & slot) const; //if stack doesn't exist, returns nullptr
CStackInstance * getStackPtr(const SlotID & slot) const; //if stack doesn't exist, returns nullptr
const CCreature * getCreature(const SlotID & slot) const; //workaround of map issue;
int getStackCount(const SlotID & slot) const;
TExpType getStackExperience(const SlotID & slot) const;

View File

@@ -16,6 +16,7 @@
#include "gameState/TavernHeroesPool.h"
#include "gameState/QuestInfo.h"
#include "mapObjects/CGHeroInstance.h"
#include "networkPacks/ArtifactLocation.h"
#include "CGeneralTextHandler.h"
#include "StartInfo.h" // for StartInfo
#include "battle/BattleInfo.h" // for BattleInfo
@@ -966,6 +967,22 @@ const CGObjectInstance * CGameInfoCallback::getObjInstance( ObjectInstanceID oid
return gs->map->objects[oid.num];
}
CArtifactSet * CGameInfoCallback::getArtSet(const ArtifactLocation & loc) const
{
auto hero = const_cast<CGHeroInstance*>(getHero(loc.artHolder));
if(loc.creature.has_value())
{
if(loc.creature.value() == SlotID::COMMANDER_SLOT_PLACEHOLDER)
return hero->commander;
else
return hero->getStackPtr(loc.creature.value());
}
else
{
return hero;
}
}
std::vector<ObjectInstanceID> CGameInfoCallback::getVisibleTeleportObjects(std::vector<ObjectInstanceID> ids, PlayerColor player) const
{
vstd::erase_if(ids, [&](const ObjectInstanceID & id) -> bool

View File

@@ -40,6 +40,8 @@ class CGameState;
class PathfinderConfig;
struct TurnTimerInfo;
struct ArtifactLocation;
class CArtifactSet;
class CArmedInstance;
class CGObjectInstance;
class CGHeroInstance;
@@ -174,6 +176,7 @@ public:
virtual int64_t estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const; //estimates damage of given spell; returns 0 if spell causes no dmg
virtual const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const;
virtual const CGObjectInstance * getObjInstance(ObjectInstanceID oid) const;
virtual CArtifactSet * getArtSet(const ArtifactLocation & loc) const;
//virtual const CGObjectInstance * getArmyInstance(ObjectInstanceID oid) const;
//objects

View File

@@ -607,20 +607,23 @@ public:
TRANSITION_POS = -3,
FIRST_AVAILABLE = -2,
PRE_FIRST = -1, //sometimes used as error, sometimes as first free in backpack
// Hero
HEAD, SHOULDERS, NECK, RIGHT_HAND, LEFT_HAND, TORSO, //5
RIGHT_RING, LEFT_RING, FEET, //8
MISC1, MISC2, MISC3, MISC4, //12
MACH1, MACH2, MACH3, MACH4, //16
SPELLBOOK, MISC5, //18
AFTER_LAST,
//cres
BACKPACK_START = 19,
// Creatures
CREATURE_SLOT = 0,
COMMANDER1 = 0, COMMANDER2, COMMANDER3, COMMANDER4, COMMANDER5, COMMANDER6, COMMANDER_AFTER_LAST,
BACKPACK_START = 19
// Commander
COMMANDER1 = 0, COMMANDER2, COMMANDER3, COMMANDER4, COMMANDER5, COMMANDER6
};
static_assert (AFTER_LAST == BACKPACK_START, "incorrect number of artifact slots");
static_assert(MISC5 < BACKPACK_START, "incorrect number of artifact slots");
DLL_LINKAGE static si32 decode(const std::string & identifier);
DLL_LINKAGE static std::string encode(const si32 index);

View File

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

View File

@@ -134,9 +134,9 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(std::vector<CampaignHeroR
bool takeable = travelOptions.artifactsKeptByHero.count(art->artType->getId());
ArtifactLocation al(hero, artifactPosition);
if(!takeable && !al.getSlot()->locked) //don't try removing locked artifacts -> it crashes #1719
al.removeArtifact();
ArtifactLocation al(hero->id, artifactPosition);
if(!takeable && !hero->getSlot(al.slot)->locked) //don't try removing locked artifacts -> it crashes #1719
hero->getArt(al.slot)->removeFrom(*hero, al.slot);
};
// process on copy - removal of artifact will invalidate container
@@ -300,7 +300,7 @@ void CGameStateCampaign::giveCampaignBonusToHero(CGHeroInstance * hero)
CArtifactInstance * scroll = ArtifactUtils::createScroll(SpellID(curBonus->info2));
const auto slot = ArtifactUtils::getArtAnyPosition(hero, scroll->getTypeId());
if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
scroll->putAt(ArtifactLocation(hero, slot));
scroll->putAt(*hero, slot);
else
logGlobal->error("Cannot give starting scroll - no free slots!");
break;

View File

@@ -1092,7 +1092,7 @@ std::string CGHeroInstance::getBiographyTextID() const
CGHeroInstance::ArtPlacementMap CGHeroInstance::putArtifact(ArtifactPosition pos, CArtifactInstance * art)
{
assert(art->artType->canBePutAt(this, pos));
assert(art->canBePutAt(this, pos));
if(ArtifactUtils::isSlotEquipment(pos))
attachTo(*art);
@@ -1135,7 +1135,7 @@ void CGHeroInstance::removeSpellbook()
if(hasSpellbook())
{
ArtifactLocation(this, ArtifactPosition(ArtifactPosition::SPELLBOOK)).removeArtifact();
getArt(ArtifactPosition::SPELLBOOK)->removeFrom(*this, ArtifactPosition::SPELLBOOK);
}
}

View File

@@ -144,7 +144,7 @@ void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const
{
if(h->hasArt(elem))
{
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(elem, false)));
cb->removeArtifact(ArtifactLocation(h->id, h->getArtPos(elem, false)));
}
else
{
@@ -153,7 +153,7 @@ void CQuest::completeQuest(IGameCallback * cb, const CGHeroInstance *h) const
auto parts = assembly->getPartsInfo();
// Remove the assembly
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(assembly)));
cb->removeArtifact(ArtifactLocation(h->id, h->getArtPos(assembly)));
// Disassemble this backpack artifact
for(const auto & ci : parts)

View File

@@ -944,10 +944,9 @@ bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot)
// He has Shackles of War (normally - MISC slot artifact) in LEFT_HAND slot set in editor
// Artifact seems to be missing in game, so skip artifacts that don't fit target slot
auto * artifact = ArtifactUtils::createArtifact(map, artifactID);
auto dstLoc = ArtifactLocation(hero, ArtifactPosition(slot));
if(artifact->canBePutAt(dstLoc))
if(artifact->canBePutAt(hero, ArtifactPosition(slot)))
{
artifact->putAt(dstLoc);
artifact->putAt(*hero, ArtifactPosition(slot));
}
else
{

View File

@@ -9,67 +9,34 @@
*/
#pragma once
#include "../ConstTransitivePtr.h"
#include "../constants/EntityIdentifiers.h"
VCMI_LIB_NAMESPACE_BEGIN
class CGHeroInstance;
class CStackInstance;
class CArmedInstance;
class CArtifactSet;
class CBonusSystemNode;
struct ArtSlotInfo;
using TArtHolder = std::variant<ConstTransitivePtr<CGHeroInstance>, ConstTransitivePtr<CStackInstance>>;
struct ArtifactLocation
{
TArtHolder artHolder;//TODO: identify holder by id
ArtifactPosition slot = ArtifactPosition::PRE_FIRST;
ObjectInstanceID artHolder;
ArtifactPosition slot;
std::optional<SlotID> creature;
ArtifactLocation()
: artHolder(ConstTransitivePtr<CGHeroInstance>())
: artHolder(ObjectInstanceID::NONE)
, slot(ArtifactPosition::PRE_FIRST)
, creature(std::nullopt)
{
}
template<typename T>
ArtifactLocation(const T * ArtHolder, ArtifactPosition Slot)
: artHolder(const_cast<T *>(ArtHolder)) //we are allowed here to const cast -> change will go through one of our packages... do not abuse!
, slot(Slot)
{
}
ArtifactLocation(TArtHolder ArtHolder, const ArtifactPosition & Slot)
: artHolder(std::move(std::move(ArtHolder)))
, slot(Slot)
ArtifactLocation(const ObjectInstanceID id, const ArtifactPosition & slot = ArtifactPosition::PRE_FIRST)
: artHolder(id)
, slot(slot)
, creature(std::nullopt)
{
}
template <typename T>
bool isHolder(const T *t) const
{
if(auto ptrToT = std::get<ConstTransitivePtr<T>>(artHolder))
{
return ptrToT == t;
}
return false;
}
DLL_LINKAGE void removeArtifact(); // BE CAREFUL, this operation modifies holder (gs)
DLL_LINKAGE const CArmedInstance *relatedObj() const; //hero or the stack owner
DLL_LINKAGE PlayerColor owningPlayer() const;
DLL_LINKAGE CArtifactSet *getHolderArtSet();
DLL_LINKAGE CBonusSystemNode *getHolderNode();
DLL_LINKAGE CArtifactSet *getHolderArtSet() const;
DLL_LINKAGE const CBonusSystemNode *getHolderNode() const;
DLL_LINKAGE const CArtifactInstance *getArt() const;
DLL_LINKAGE CArtifactInstance *getArt();
DLL_LINKAGE const ArtSlotInfo *getSlot() const;
template <typename Handler> void serialize(Handler &h, const int version)
template <typename Handler> void serialize(Handler & h, const int version)
{
h & artHolder;
h & slot;
h & creature;
}
};

View File

@@ -1574,67 +1574,6 @@ struct GetBase
}
};
void ArtifactLocation::removeArtifact()
{
CArtifactInstance *a = getArt();
assert(a);
a->removeFrom(*this);
}
const CArmedInstance * ArtifactLocation::relatedObj() const
{
return std::visit(ObjectRetriever(), artHolder);
}
PlayerColor ArtifactLocation::owningPlayer() const
{
const auto * obj = relatedObj();
return obj ? obj->tempOwner : PlayerColor::NEUTRAL;
}
CArtifactSet *ArtifactLocation::getHolderArtSet()
{
return std::visit(GetBase<CArtifactSet>(), artHolder);
}
CBonusSystemNode *ArtifactLocation::getHolderNode()
{
return std::visit(GetBase<CBonusSystemNode>(), artHolder);
}
const CArtifactInstance *ArtifactLocation::getArt() const
{
const auto * s = getSlot();
if(s)
return s->getArt();
else
return nullptr;
}
CArtifactSet * ArtifactLocation::getHolderArtSet() const
{
auto * t = const_cast<ArtifactLocation *>(this);
return t->getHolderArtSet();
}
const CBonusSystemNode * ArtifactLocation::getHolderNode() const
{
auto * t = const_cast<ArtifactLocation *>(this);
return t->getHolderNode();
}
CArtifactInstance *ArtifactLocation::getArt()
{
const ArtifactLocation *t = this;
return const_cast<CArtifactInstance*>(t->getArt());
}
const ArtSlotInfo *ArtifactLocation::getSlot() const
{
return getHolderArtSet()->getSlot(slot);
}
void ChangeStackCount::applyGs(CGameState * gs)
{
auto * srcObj = gs->getArmyInstance(army);
@@ -1709,39 +1648,40 @@ void RebalanceStacks::applyGs(CGameState * gs)
if(srcCount == count) //moving whole stack
{
[[maybe_unused]] const CCreature *c = dst.army->getCreature(dst.slot);
const auto c = dst.army->getCreature(dst.slot);
if(c) //stack at dest -> merge
{
assert(c == srcType);
auto alHere = ArtifactLocation (src.getStack(), ArtifactPosition::CREATURE_SLOT);
auto alDest = ArtifactLocation (dst.getStack(), ArtifactPosition::CREATURE_SLOT);
auto * artHere = alHere.getArt();
auto * artDest = alDest.getArt();
if (artHere)
const auto srcHero = dynamic_cast<CGHeroInstance*>(src.army.get());
const auto dstHero = dynamic_cast<CGHeroInstance*>(dst.army.get());
auto srcStack = const_cast<CStackInstance*>(src.getStack());
auto dstStack = const_cast<CStackInstance*>(dst.getStack());
if(auto srcArt = srcStack->getArt(ArtifactPosition::CREATURE_SLOT))
{
if (alDest.getArt())
if(auto dstArt = dstStack->getArt(ArtifactPosition::CREATURE_SLOT))
{
auto * hero = dynamic_cast<CGHeroInstance *>(src.army.get());
auto dstSlot = ArtifactUtils::getArtBackpackPosition(hero, alDest.getArt()->getTypeId());
if(hero && dstSlot != ArtifactPosition::PRE_FIRST)
auto dstSlot = ArtifactUtils::getArtBackpackPosition(srcHero, dstArt->getTypeId());
if(srcHero && dstSlot != ArtifactPosition::PRE_FIRST)
{
artDest->move (alDest, ArtifactLocation (hero, dstSlot));
dstArt->move(*dstStack, ArtifactPosition::CREATURE_SLOT, *srcHero, dstSlot);
}
//else - artifact cna be lost :/
else
{
EraseArtifact ea;
ea.al = alDest;
ea.al = ArtifactLocation(dstHero->id, ArtifactPosition::CREATURE_SLOT);
ea.al.creature = dst.slot;
ea.applyGs(gs);
logNetwork->warn("Cannot move artifact! No free slots");
}
artHere->move (alHere, alDest);
srcArt->move(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT);
//TODO: choose from dialog
}
else //just move to the other slot before stack gets erased
{
artHere->move (alHere, alDest);
srcArt->move(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT);
}
}
if (stackExp)
@@ -1811,53 +1751,57 @@ void BulkSmartRebalanceStacks::applyGs(CGameState * gs)
void PutArtifact::applyGs(CGameState *gs)
{
assert(art->canBePutAt(al));
// Ensure that artifact has been correctly added via NewArtifact pack
assert(vstd::contains(gs->map->artInstances, art));
assert(!art->getParentNodes().empty());
art->putAt(al);
auto hero = gs->getHero(al.artHolder);
assert(hero);
assert(art && art->canBePutAt(hero, al.slot));
art->putAt(*hero, al.slot);
}
void EraseArtifact::applyGs(CGameState *gs)
{
const auto * slot = al.getSlot();
const auto hero = gs->getHero(al.artHolder);
assert(hero);
const auto slot = hero->getSlot(al.slot);
if(slot->locked)
{
logGlobal->debug("Erasing locked artifact: %s", slot->artifact->artType->getNameTranslated());
DisassembledArtifact dis;
dis.al.artHolder = al.artHolder;
auto * aset = al.getHolderArtSet();
#ifndef NDEBUG
bool found = false;
#endif
for(auto& p : aset->artifactsWorn)
for(auto & slotInfo : hero->artifactsWorn)
{
auto art = p.second.artifact;
auto art = slotInfo.second.artifact;
if(art->isCombined() && art->isPart(slot->artifact))
{
dis.al.slot = aset->getArtPos(art);
#ifndef NDEBUG
found = true;
#endif
dis.al.slot = hero->getArtPos(art);
break;
}
}
assert(found && "Failed to determine the assembly this locked artifact belongs to");
logGlobal->debug("Found the corresponding assembly: %s", dis.al.getSlot()->artifact->artType->getNameTranslated());
assert((dis.al.slot != ArtifactPosition::PRE_FIRST) && "Failed to determine the assembly this locked artifact belongs to");
logGlobal->debug("Found the corresponding assembly: %s", hero->getArt(dis.al.slot)->artType->getNameTranslated());
dis.applyGs(gs);
}
else
{
logGlobal->debug("Erasing artifact %s", slot->artifact->artType->getNameTranslated());
}
al.removeArtifact();
auto art = hero->getArt(al.slot);
assert(art);
art->removeFrom(*hero, al.slot);
}
void MoveArtifact::applyGs(CGameState * gs)
{
CArtifactInstance * art = src.getArt();
assert(!ArtifactUtils::isSlotEquipment(dst.slot) || !dst.getArt());
art->move(src, dst);
auto srcHero = gs->getArtSet(src);
auto dstHero = gs->getArtSet(dst);
assert(srcHero);
assert(dstHero);
auto art = srcHero->getArt(src.slot);
assert(art && art->canBePutAt(dstHero, dst.slot));
art->move(*srcHero, src.slot, *dstHero, dst.slot);
}
void BulkMoveArtifacts::applyGs(CGameState * gs)
@@ -1869,8 +1813,8 @@ void BulkMoveArtifacts::applyGs(CGameState * gs)
BULK_PUT
};
auto bulkArtsOperation = [this](std::vector<LinkedSlots> & artsPack,
CArtifactSet * artSet, EBulkArtsOp operation) -> void
auto bulkArtsOperation = [this, gs](std::vector<LinkedSlots> & artsPack,
CArtifactSet & artSet, EBulkArtsOp operation) -> void
{
int numBackpackArtifactsMoved = 0;
for(auto & slot : artsPack)
@@ -1883,21 +1827,18 @@ void BulkMoveArtifacts::applyGs(CGameState * gs)
{
srcPos = ArtifactPosition(srcPos.num - numBackpackArtifactsMoved);
}
const auto * slotInfo = artSet->getSlot(srcPos);
assert(slotInfo);
auto * art = const_cast<CArtifactInstance *>(slotInfo->getArt());
auto * art = artSet.getArt(srcPos);
assert(art);
switch(operation)
{
case EBulkArtsOp::BULK_MOVE:
const_cast<CArtifactInstance*>(art)->move(
ArtifactLocation(srcArtHolder, srcPos), ArtifactLocation(dstArtHolder, slot.dstPos));
art->move(artSet, srcPos, *gs->getHero(dstArtHolder), slot.dstPos);
break;
case EBulkArtsOp::BULK_REMOVE:
art->removeFrom(ArtifactLocation(dstArtHolder, srcPos));
art->removeFrom(artSet, srcPos);
break;
case EBulkArtsOp::BULK_PUT:
art->putAt(ArtifactLocation(srcArtHolder, slot.dstPos));
art->putAt(*gs->getHero(srcArtHolder), slot.dstPos);
break;
default:
break;
@@ -1910,37 +1851,38 @@ void BulkMoveArtifacts::applyGs(CGameState * gs)
}
};
auto * leftSet = gs->getArtSet(ArtifactLocation(srcArtHolder));
if(swap)
{
// Swap
auto * leftSet = getSrcHolderArtSet();
auto * rightSet = getDstHolderArtSet();
auto * rightSet = gs->getArtSet(ArtifactLocation(dstArtHolder));
CArtifactFittingSet artFittingSet(leftSet->bearerType());
artFittingSet.artifactsWorn = rightSet->artifactsWorn;
artFittingSet.artifactsInBackpack = rightSet->artifactsInBackpack;
bulkArtsOperation(artsPack1, rightSet, EBulkArtsOp::BULK_REMOVE);
bulkArtsOperation(artsPack0, leftSet, EBulkArtsOp::BULK_MOVE);
bulkArtsOperation(artsPack1, &artFittingSet, EBulkArtsOp::BULK_PUT);
bulkArtsOperation(artsPack1, *rightSet, EBulkArtsOp::BULK_REMOVE);
bulkArtsOperation(artsPack0, *leftSet, EBulkArtsOp::BULK_MOVE);
bulkArtsOperation(artsPack1, artFittingSet, EBulkArtsOp::BULK_PUT);
}
else
{
bulkArtsOperation(artsPack0, getSrcHolderArtSet(), EBulkArtsOp::BULK_MOVE);
bulkArtsOperation(artsPack0, *leftSet, EBulkArtsOp::BULK_MOVE);
}
}
void AssembledArtifact::applyGs(CGameState *gs)
{
CArtifactSet * artSet = al.getHolderArtSet();
const CArtifactInstance * transformedArt = al.getArt();
auto hero = gs->getHero(al.artHolder);
assert(hero);
const auto transformedArt = hero->getArt(al.slot);
assert(transformedArt);
assert(vstd::contains_if(ArtifactUtils::assemblyPossibilities(artSet, transformedArt->getTypeId()), [=](const CArtifact * art)->bool
assert(vstd::contains_if(ArtifactUtils::assemblyPossibilities(hero, transformedArt->getTypeId()), [=](const CArtifact * art)->bool
{
return art->getId() == builtArt->getId();
}));
const auto transformedArtSlot = artSet->getSlotByInstance(transformedArt);
const auto transformedArtSlot = hero->getSlotByInstance(transformedArt);
auto * combinedArt = new CArtifactInstance(builtArt);
gs->map->addNewArtifactInstance(combinedArt);
@@ -1952,7 +1894,7 @@ void AssembledArtifact::applyGs(CGameState *gs)
if(transformedArt->getTypeId() == constituent->getId())
slot = transformedArtSlot;
else
slot = artSet->getArtPos(constituent->getId(), false, false);
slot = hero->getArtPos(constituent->getId(), false, false);
assert(slot != ArtifactPosition::PRE_FIRST);
slotsInvolved.emplace_back(slot);
@@ -1972,8 +1914,8 @@ void AssembledArtifact::applyGs(CGameState *gs)
break;
}
if(!vstd::contains(combinedArt->artType->getPossibleSlots().at(artSet->bearerType()), al.slot)
&& vstd::contains(combinedArt->artType->getPossibleSlots().at(artSet->bearerType()), slot))
if(!vstd::contains(combinedArt->artType->getPossibleSlots().at(hero->bearerType()), al.slot)
&& vstd::contains(combinedArt->artType->getPossibleSlots().at(hero->bearerType()), slot))
al.slot = slot;
}
else
@@ -1986,8 +1928,8 @@ void AssembledArtifact::applyGs(CGameState *gs)
// Delete parts from hero
for(const auto slot : slotsInvolved)
{
const auto constituentInstance = artSet->getArt(slot);
constituentInstance->removeFrom(ArtifactLocation(al.artHolder, slot));
const auto constituentInstance = hero->getArt(slot);
constituentInstance->removeFrom(*hero, slot);
if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot)
combinedArt->addPart(constituentInstance, slot);
@@ -1996,25 +1938,26 @@ void AssembledArtifact::applyGs(CGameState *gs)
}
// Put new combined artifacts
combinedArt->putAt(al);
combinedArt->putAt(*hero, al.slot);
}
void DisassembledArtifact::applyGs(CGameState *gs)
{
auto * disassembled = al.getArt();
assert(disassembled);
auto hero = gs->getHero(al.artHolder);
assert(hero);
auto disassembledArt = hero->getArt(al.slot);
assert(disassembledArt);
auto parts = disassembled->getPartsInfo();
disassembled->removeFrom(al);
auto parts = disassembledArt->getPartsInfo();
disassembledArt->removeFrom(*hero, al.slot);
for(auto & part : parts)
{
ArtifactLocation partLoc = al;
// ArtifactPosition::PRE_FIRST is value of main part slot -> it'll replace combined artifact in its pos
partLoc.slot = (ArtifactUtils::isSlotEquipment(part.slot) ? part.slot : al.slot);
disassembled->detachFrom(*part.art);
part.art->putAt(partLoc);
auto slot = (ArtifactUtils::isSlotEquipment(part.slot) ? part.slot : al.slot);
disassembledArt->detachFrom(*part.art);
part.art->putAt(*hero, slot);
}
gs->map->eraseArtifactInstance(disassembled);
gs->map->eraseArtifactInstance(disassembledArt);
}
void HeroVisit::applyGs(CGameState *gs)
@@ -2603,14 +2546,4 @@ const CArtifactInstance * ArtSlotInfo::getArt() const
return artifact;
}
CArtifactSet * BulkMoveArtifacts::getSrcHolderArtSet()
{
return std::visit(GetBase<CArtifactSet>(), srcArtHolder);
}
CArtifactSet * BulkMoveArtifacts::getDstHolderArtSet()
{
return std::visit(GetBase<CArtifactSet>(), dstArtHolder);
}
VCMI_LIB_NAMESPACE_END

View File

@@ -1060,14 +1060,16 @@ struct DLL_LINKAGE BulkMoveArtifacts : CArtifactOperationPack
}
};
TArtHolder srcArtHolder;
TArtHolder dstArtHolder;
ObjectInstanceID srcArtHolder;
ObjectInstanceID dstArtHolder;
BulkMoveArtifacts()
: swap(false)
: srcArtHolder(ObjectInstanceID::NONE)
, dstArtHolder(ObjectInstanceID::NONE)
, swap(false)
{
}
BulkMoveArtifacts(TArtHolder srcArtHolder, TArtHolder dstArtHolder, bool swap)
BulkMoveArtifacts(const ObjectInstanceID srcArtHolder, const ObjectInstanceID dstArtHolder, bool swap)
: srcArtHolder(std::move(srcArtHolder))
, dstArtHolder(std::move(dstArtHolder))
, swap(swap)
@@ -1079,8 +1081,6 @@ struct DLL_LINKAGE BulkMoveArtifacts : CArtifactOperationPack
std::vector<LinkedSlots> artsPack0;
std::vector<LinkedSlots> artsPack1;
bool swap;
CArtifactSet * getSrcHolderArtSet();
CArtifactSet * getDstHolderArtSet();
void visitTyped(ICPackVisitor & visitor) override;