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

check amount of artifacts on hero when checking requirements of a quest that requires artifact(s)

fixes case when 2 or more identical artifacts are required
This commit is contained in:
Andrey Filipenkov 2022-10-01 09:28:32 +03:00
parent 86708841f8
commit aa217236b3
6 changed files with 52 additions and 16 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

@ -21,6 +21,8 @@ class CGCreature;
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?
@ -60,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
{

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;