mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +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:
		| @@ -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 *> | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 | ||||
| 	{ | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
| 				 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user