1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

Fix 1723 quest crash on combined arts

This commit is contained in:
Vadim Markovtsev 2016-01-22 12:53:01 +03:00
parent b02bd61c83
commit 11bce2908d
5 changed files with 99 additions and 20 deletions

View File

@ -1152,9 +1152,42 @@ const CArtifactInstance * CArtifactSet::getArtByInstanceId( ArtifactInstanceID a
return nullptr;
}
bool CArtifactSet::hasArt(ui32 aid, bool onlyWorn /*= false*/) const
bool CArtifactSet::hasArt(ui32 aid, bool onlyWorn /*= false*/,
bool searchBackpackAssemblies /*= false*/) const
{
return getArtPos(aid, onlyWorn) != ArtifactPosition::PRE_FIRST;
return getArtPos(aid, onlyWorn) != ArtifactPosition::PRE_FIRST ||
(searchBackpackAssemblies && getHiddenArt(aid));
}
std::pair<const CCombinedArtifactInstance *, const CArtifactInstance *>
CArtifactSet::searchForConstituent(int aid) const
{
for(auto & slot : artifactsInBackpack)
{
auto art = slot.artifact;
if(art->canBeDisassembled())
{
auto ass = static_cast<CCombinedArtifactInstance *>(art.get());
for(auto& ci : ass->constituentsInfo)
{
if(ci.art->artType->id == aid)
{
return {ass, ci.art};
}
}
}
}
return {nullptr, nullptr};
}
const CArtifactInstance *CArtifactSet::getHiddenArt(int aid) const
{
return searchForConstituent(aid).second;
}
const CCombinedArtifactInstance *CArtifactSet::getAssemblyByConstituent(int aid) const
{
return searchForConstituent(aid).first;
}
const ArtSlotInfo * CArtifactSet::getSlot(ArtifactPosition pos) const

View File

@ -128,7 +128,9 @@ public:
virtual bool canBeDisassembled() const;
virtual void putAt(ArtifactLocation al);
virtual void removeFrom(ArtifactLocation al);
virtual bool isPart(const CArtifactInstance *supposedPart) const; //checks if this a part of this artifact: artifact instance is a part of itself, additionally truth is returned for consituents of combined arts
/// Checks if this a part of this artifact: artifact instance is a part
/// of itself, additionally truth is returned for constituents of combined arts
virtual bool isPart(const CArtifactInstance *supposedPart) const;
std::vector<const CArtifact *> assemblyPossibilities(const CArtifactSet *h) const;
void move(ArtifactLocation src, ArtifactLocation dst);
@ -172,7 +174,7 @@ public:
void createConstituents();
void addAsConstituent(CArtifactInstance *art, ArtifactPosition slot);
CArtifactInstance *figureMainConstituent(const ArtifactLocation al); //main constituent is replcaed with us (combined art), not lock
CArtifactInstance *figureMainConstituent(const ArtifactLocation al); //main constituent is replaced with us (combined art), not lock
CCombinedArtifactInstance();
@ -265,10 +267,8 @@ struct DLL_LINKAGE ArtSlotInfo
ConstTransitivePtr<CArtifactInstance> artifact;
ui8 locked; //if locked, then artifact points to the combined artifact
ArtSlotInfo()
{
locked = false;
}
ArtSlotInfo() : locked(false) {}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & artifact & locked;
@ -288,10 +288,16 @@ public:
const ArtSlotInfo *getSlot(ArtifactPosition pos) const;
const CArtifactInstance* getArt(ArtifactPosition pos, bool excludeLocked = true) const; //nullptr - no artifact
CArtifactInstance* getArt(ArtifactPosition pos, bool excludeLocked = true); //nullptr - no artifact
ArtifactPosition getArtPos(int aid, bool onlyWorn = true) const; //looks for equipped artifact with given ID and returns its slot ID or -1 if none(if more than one such artifact lower ID is returned)
/// Looks for equipped artifact with given ID and returns its slot ID or -1 if none
/// (if more than one such artifact lower ID is returned)
ArtifactPosition getArtPos(int aid, bool onlyWorn = true) const;
ArtifactPosition getArtPos(const CArtifactInstance *art) const;
const CArtifactInstance *getArtByInstanceId(ArtifactInstanceID artInstId) const;
bool hasArt(ui32 aid, bool onlyWorn = false) const; //checks if hero possess artifact of given id (either in backack or worn)
/// Search for constituents of assemblies in backpack which do not have an ArtifactPosition
const CArtifactInstance *getHiddenArt(int aid) const;
const CCombinedArtifactInstance *getAssemblyByConstituent(int aid) const;
/// Checks if hero possess artifact of given id (either in backack or worn)
bool hasArt(ui32 aid, bool onlyWorn = false, bool searchBackpackAssemblies = false) const;
bool isPositionFree(ArtifactPosition pos, bool onlyLockCheck = false) const;
si32 getArtTypeId(ArtifactPosition pos) const;
@ -304,4 +310,7 @@ public:
}
void artDeserializationFix(CBonusSystemNode *node);
protected:
std::pair<const CCombinedArtifactInstance *, const CArtifactInstance *> searchForConstituent(int aid) const;
};

View File

@ -754,7 +754,7 @@ DLL_LINKAGE const CArtifactInstance *ArtifactLocation::getArt() const
return s->artifact;
else
{
logNetwork->warnStream() << "ArtifactLocation::getArt: That location is locked!";
logNetwork->warnStream() << "ArtifactLocation::getArt: This location is locked!";
return nullptr;
}
}
@ -914,6 +914,32 @@ DLL_LINKAGE void PutArtifact::applyGs( CGameState *gs )
DLL_LINKAGE void EraseArtifact::applyGs( CGameState *gs )
{
auto slot = al.getSlot();
if(slot->locked)
{
logGlobal->debugStream() << "Erasing locked artifact: " << slot->artifact->artType->Name();
DisassembledArtifact dis;
dis.al.artHolder = al.artHolder;
auto aset = al.getHolderArtSet();
bool found = false;
for(auto& p : aset->artifactsWorn)
{
auto art = p.second.artifact;
if(art->canBeDisassembled() && art->isPart(slot->artifact))
{
dis.al.slot = aset->getArtPos(art);
found = true;
break;
}
}
assert(found && "Failed to determine the assembly this locked artifact belongs to");
logGlobal->debugStream() << "Found the corresponding assembly: " << dis.al.getSlot()->artifact->artType->Name();
dis.applyGs(gs);
}
else
{
logGlobal->debugStream() << "Erasing artifact " << slot->artifact->artType->Name();
}
al.removeArtifact();
}

View File

@ -70,7 +70,7 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const
case MISSION_ART:
for (auto & elem : m5arts)
{
if (h->hasArt(elem))
if (h->hasArt(elem, false, true))
continue;
return false; //if the artifact was not found
}
@ -630,6 +630,18 @@ void CGSeerHut::finishQuest(const CGHeroInstance * h, ui32 accept) const
case CQuest::MISSION_ART:
for (auto & elem : quest->m5arts)
{
if(!h->hasArt(elem))
{
// first we need to disassemble this backpack artifact
auto assembly = h->getAssemblyByConstituent(elem);
assert(assembly);
for(auto & ci : assembly->constituentsInfo)
{
cb->giveHeroNewArtifact(h, ci.art->artType, ArtifactPosition::PRE_FIRST);
}
// remove the assembly
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(assembly)));
}
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(elem, false)));
}
break;

View File

@ -2113,7 +2113,6 @@ void CGameHandler::stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroI
void CGameHandler::removeArtifact(const ArtifactLocation &al)
{
assert(al.getArt());
EraseArtifact ea;
ea.al = al;
sendAndApply(&ea);