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

@ -280,16 +280,16 @@ ArtifactPosition CArtHandler::stringToSlot(std::string slotName)
void CArtHandler::addSlot(CArtifact * art, const std::string & slotID)
{
static const std::vector<ArtifactPosition> miscSlots =
static const std::vector<ArtifactPosition> miscSlots =
{
ArtifactPosition::MISC1, ArtifactPosition::MISC2, ArtifactPosition::MISC3, ArtifactPosition::MISC4, ArtifactPosition::MISC5
};
static const std::vector<ArtifactPosition> ringSlots =
{
ArtifactPosition::LEFT_RING, ArtifactPosition::RIGHT_RING
};
if (slotID == "MISC")
{
vstd::concatenate(art->possibleSlots[ArtBearer::HERO], miscSlots);
@ -323,7 +323,7 @@ void CArtHandler::loadSlots(CArtifact * art, const JsonNode & node)
CArtifact::EartClass CArtHandler::stringToClass(std::string className)
{
static const std::map<std::string, CArtifact::EartClass> artifactClassMap =
{
{
{"TREASURE", CArtifact::ART_TREASURE},
{"MINOR", CArtifact::ART_MINOR},
{"MAJOR", CArtifact::ART_MAJOR},
@ -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

@ -340,7 +340,7 @@ DLL_LINKAGE void RemoveBonus::applyGs( CGameState *gs )
if(b->source == source && b->sid == id)
{
bonus = *b; //backup bonus (to show to interfaces later)
node->removeBonus(b);
node->removeBonus(b);
break;
}
}
@ -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();
}
@ -1262,7 +1288,7 @@ DLL_LINKAGE void BattleStackAttacked::applyGs( CGameState *gs )
{
//"hide" killed creatures instead so we keep info about it
at->state.insert(EBattleStackState::DEAD_CLONE);
for(CStack * s : gs->curB->stacks)
{
if(s->cloneID == at->ID)
@ -1375,7 +1401,7 @@ void actualizeEffect(CStack * s, const Bonus & ef)
stackBonus->turnsRemain = std::max(stackBonus->turnsRemain, ef.turnsRemain);
}
}
CBonusSystemNode::treeHasChanged();
CBonusSystemNode::treeHasChanged();
}
void actualizeEffect(CStack * s, const std::vector<Bonus> & ef)

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);