1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Merge pull request #1027 from kambala-decapitator/fix-quest-multiple-artifacts

Fix quest check that requires identical artifacts
This commit is contained in:
Andrii Danylchenko 2022-10-01 13:03:46 +03:00 committed by GitHub
commit 1aefbd14a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 56 additions and 21 deletions

View File

@ -1191,18 +1191,27 @@ CArtifactInstance* CArtifactSet::getArt(ArtifactPosition pos, bool excludeLocked
ArtifactPosition CArtifactSet::getArtPos(int aid, bool onlyWorn, bool allowLocked) const
{
const auto result = getAllArtPositions(aid, onlyWorn, allowLocked, false);
return result.empty() ? ArtifactPosition{ArtifactPosition::PRE_FIRST} : result[0];
}
std::vector<ArtifactPosition> CArtifactSet::getAllArtPositions(int aid, bool onlyWorn, bool allowLocked, bool getAll) const
{
std::vector<ArtifactPosition> result;
for(auto i = artifactsWorn.cbegin(); i != artifactsWorn.cend(); i++)
if(i->second.artifact->artType->id == aid && (allowLocked || !i->second.locked))
return i->first;
result.push_back(i->first);
if(onlyWorn)
return ArtifactPosition::PRE_FIRST;
return result;
if(!getAll && !result.empty())
return result;
for(int i = 0; i < artifactsInBackpack.size(); i++)
if(artifactsInBackpack[i].artifact->artType->id == aid)
return ArtifactPosition(GameConstants::BACKPACK_START + i);
result.push_back(ArtifactPosition(GameConstants::BACKPACK_START + i));
return ArtifactPosition::PRE_FIRST;
return result;
}
ArtifactPosition CArtifactSet::getArtPos(const CArtifactInstance *art) const
@ -1237,8 +1246,19 @@ bool CArtifactSet::hasArt(
bool searchBackpackAssemblies,
bool allowLocked) const
{
return getArtPos(aid, onlyWorn, allowLocked) != ArtifactPosition::PRE_FIRST ||
(searchBackpackAssemblies && getHiddenArt(aid));
return getArtPosCount(aid, onlyWorn, searchBackpackAssemblies, allowLocked) > 0;
}
unsigned CArtifactSet::getArtPosCount(int 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;
}
std::pair<const CCombinedArtifactInstance *, const CArtifactInstance *>

View File

@ -328,6 +328,7 @@ public:
/// (if more than one such artifact lower ID is returned)
ArtifactPosition getArtPos(int aid, bool onlyWorn = true, bool allowLocked = true) const;
ArtifactPosition getArtPos(const CArtifactInstance *art) const;
std::vector<ArtifactPosition> getAllArtPositions(int aid, bool onlyWorn, bool allowLocked, bool getAll) const;
const CArtifactInstance *getArtByInstanceId(ArtifactInstanceID artInstId) const;
/// Search for constituents of assemblies in backpack which do not have an ArtifactPosition
const CArtifactInstance *getHiddenArt(int aid) const;
@ -335,6 +336,7 @@ public:
/// Checks if hero possess artifact of given id (either in backack or worn)
bool hasArt(ui32 aid, bool onlyWorn = false, bool searchBackpackAssemblies = false, bool allowLocked = true) const;
bool isPositionFree(ArtifactPosition pos, bool onlyLockCheck = false) const;
unsigned getArtPosCount(int aid, bool onlyWorn = true, bool searchBackpackAssemblies = true, bool allowLocked = true) const;
virtual ArtBearer::ArtBearer bearerType() const = 0;
virtual void putArtifact(ArtifactPosition pos, CArtifactInstance * art) = 0;

View File

@ -112,11 +112,16 @@ bool CQuest::checkQuest(const CGHeroInstance * h) const
return true;
return false;
case MISSION_ART:
for(auto & elem : m5arts)
// if the object was deserialized
if(artifactsRequirements.empty())
for(auto id : m5arts)
++artifactsRequirements[id];
for(const auto & elem : artifactsRequirements)
{
if(h->hasArt(elem, false, true))
continue;
return false; //if the artifact was not found
// check required amount of artifacts
if(h->getArtPosCount(elem.first, false, true, true) < elem.second)
return false;
}
return true;
case MISSION_ARMY:
@ -417,6 +422,12 @@ void CQuest::getCompletionText(MetaString &iwText, std::vector<Component> &compo
}
}
void CQuest::addArtifactID(ui16 id)
{
m5arts.push_back(id);
++artifactsRequirements[id];
}
void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName)
{
auto q = handler.enterStruct(fieldName);

View File

@ -19,8 +19,10 @@ VCMI_LIB_NAMESPACE_BEGIN
class CGCreature;
class DLL_LINKAGE CQuest
class DLL_LINKAGE CQuest final
{
mutable std::unordered_map<ui16, unsigned> artifactsRequirements; // artifact ID -> required count
public:
enum Emission {MISSION_NONE = 0, MISSION_LEVEL = 1, MISSION_PRIMARY_STAT = 2, MISSION_KILL_HERO = 3, MISSION_KILL_CREATURE = 4,
MISSION_ART = 5, MISSION_ARMY = 6, MISSION_RESOURCES = 7, MISSION_HERO = 8, MISSION_PLAYER = 9, MISSION_KEYMASTER = 10};
@ -34,7 +36,7 @@ public:
ui32 m13489val;
std::vector<ui32> m2stats;
std::vector<ui16> m5arts; //artifacts id
std::vector<ui16> m5arts; // artifact IDs. Add IDs through addArtifactID(), not directly to the field.
std::vector<CStackBasicDescriptor> m6creatures; //pair[cre id, cre count], CreatureSet info irrelevant
std::vector<ui32> m7resources; //TODO: use resourceset?
@ -52,7 +54,6 @@ public:
bool isCustomFirst, isCustomNext, isCustomComplete;
CQuest();
virtual ~CQuest(){};
static bool checkMissionArmy(const CQuest * q, const CCreatureSet * army);
virtual bool checkQuest (const CGHeroInstance * h) const; //determines whether the quest is complete or not
@ -61,6 +62,7 @@ public:
virtual void getRolloverText (MetaString &text, bool onHover) const; //hover or quest log entry
virtual void completeQuest (const CGHeroInstance * h) const {};
virtual void addReplacements(MetaString &out, const std::string &base) const;
void addArtifactID(ui16 id);
bool operator== (const CQuest & quest) const
{
@ -161,7 +163,7 @@ protected:
class DLL_LINKAGE CGQuestGuard : public CGSeerHut
{
public:
CGQuestGuard() : CGSeerHut(){};
CGQuestGuard() = default;
void init(CRandomGenerator & rand) override;
void completeQuest (const CGHeroInstance * h) const override;
@ -209,7 +211,7 @@ public:
class DLL_LINKAGE CGBorderGuard : public CGKeys, public IQuestObject
{
public:
CGBorderGuard() : IQuestObject(){};
CGBorderGuard() = default;
void initObj(CRandomGenerator & rand) override;
void onHeroVisit(const CGHeroInstance * h) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
@ -231,7 +233,7 @@ public:
class DLL_LINKAGE CGBorderGate : public CGBorderGuard
{
public:
CGBorderGate() : CGBorderGuard(){};
CGBorderGate() = default;
void onHeroVisit(const CGHeroInstance * h) const override;
bool passableFor(PlayerColor color) const override;

View File

@ -1758,7 +1758,7 @@ CGSeerHut * CMapLoaderH3M::readSeerHut()
if (artID != 255)
{
//not none quest
hut->quest->m5arts.push_back (artID);
hut->quest->addArtifactID(artID);
hut->quest->missionType = CQuest::MISSION_ART;
}
else
@ -1887,7 +1887,7 @@ void CMapLoaderH3M::readQuest(IQuestObject * guard)
for(int yy = 0; yy < artNumber; ++yy)
{
int artid = reader.readUInt16();
guard->quest->m5arts.push_back(artid);
guard->quest->addArtifactID(artid);
map->allowedArtifact[artid] = false; //these are unavailable for random generation
}
break;

View File

@ -430,7 +430,7 @@ void TreasurePlacer::addAllPossibleObjects()
obj->quest->missionType = CQuest::MISSION_ART;
ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
obj->quest->m5arts.push_back(artid);
obj->quest->addArtifactID(artid);
obj->quest->lastDay = -1;
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
@ -467,7 +467,7 @@ void TreasurePlacer::addAllPossibleObjects()
obj->quest->missionType = CQuest::MISSION_ART;
ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
obj->quest->m5arts.push_back(artid);
obj->quest->addArtifactID(artid);
obj->quest->lastDay = -1;
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
@ -490,7 +490,7 @@ void TreasurePlacer::addAllPossibleObjects()
obj->quest->missionType = CQuest::MISSION_ART;
ArtifactID artid = *RandomGeneratorUtil::nextItem(generator.getQuestArtsRemaning(), generator.rand);
obj->quest->m5arts.push_back(artid);
obj->quest->addArtifactID(artid);
obj->quest->lastDay = -1;
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;