| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2014-06-05 20:26:50 +03:00
										 |  |  |  * CQuest.cpp, part of VCMI engine | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Authors: listed in file AUTHORS in main folder | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * License: GNU General Public License v2.0 or later | 
					
						
							|  |  |  |  * Full text of license available in license.txt file, in main folder | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "StdInc.h"
 | 
					
						
							|  |  |  | #include "CQuest.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-15 15:03:32 +03:00
										 |  |  | #include <vcmi/spells/Spell.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-05 20:26:50 +03:00
										 |  |  | #include "../NetPacks.h"
 | 
					
						
							| 
									
										
										
										
											2014-06-05 23:51:24 +03:00
										 |  |  | #include "../CSoundBase.h"
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | #include "../CGeneralTextHandler.h"
 | 
					
						
							|  |  |  | #include "../CHeroHandler.h"
 | 
					
						
							|  |  |  | #include "CObjectClassesHandler.h"
 | 
					
						
							| 
									
										
										
										
											2015-12-02 21:05:10 +02:00
										 |  |  | #include "MiscObjects.h"
 | 
					
						
							| 
									
										
										
										
											2014-06-25 17:11:07 +03:00
										 |  |  | #include "../IGameCallback.h"
 | 
					
						
							|  |  |  | #include "../CGameState.h"
 | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | #include "../serializer/JsonSerializeFormat.h"
 | 
					
						
							|  |  |  | #include "../CModHandler.h"
 | 
					
						
							|  |  |  | #include "../GameConstants.h"
 | 
					
						
							|  |  |  | #include "../StringConstants.h"
 | 
					
						
							| 
									
										
										
										
											2018-03-31 18:56:40 +13:00
										 |  |  | #include "../CSkillHandler.h"
 | 
					
						
							| 
									
										
										
										
											2017-05-28 16:23:42 +03:00
										 |  |  | #include "../mapping/CMap.h"
 | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-26 16:07:42 +03:00
										 |  |  | VCMI_LIB_NAMESPACE_BEGIN | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | std::map <PlayerColor, std::set <ui8> > CGKeys::playerKeyMap; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | //TODO: Remove constructor
 | 
					
						
							|  |  |  | CQuest::CQuest(): | 
					
						
							|  |  |  | 	qid(-1), | 
					
						
							|  |  |  | 	missionType(MISSION_NONE), | 
					
						
							|  |  |  | 	progress(NOT_ACTIVE), | 
					
						
							|  |  |  | 	lastDay(-1), | 
					
						
							|  |  |  | 	m13489val(0), | 
					
						
							|  |  |  | 	textOption(0), | 
					
						
							|  |  |  | 	completedOption(0), | 
					
						
							|  |  |  | 	stackDirection(0), | 
					
						
							|  |  |  | 	heroPortrait(-1), | 
					
						
							|  |  |  | 	isCustomFirst(false),  | 
					
						
							|  |  |  | 	isCustomNext(false), | 
					
						
							|  |  |  | 	isCustomComplete(false) | 
					
						
							| 
									
										
										
										
											2016-08-22 20:41:37 +03:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-01 20:54:05 +02:00
										 |  |  | static std::string visitedTxt(const bool visited) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	int id = visited ? 352 : 353; | 
					
						
							|  |  |  | 	return VLC->generaltexth->allTexts[id]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | const std::string & CQuest::missionName(CQuest::Emission mission) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static const std::array<std::string, 11> names = { | 
					
						
							|  |  |  | 		"empty", | 
					
						
							|  |  |  | 		"heroLevel", | 
					
						
							|  |  |  | 		"primarySkill", | 
					
						
							|  |  |  | 		"killHero", | 
					
						
							|  |  |  | 		"killCreature", | 
					
						
							|  |  |  | 		"bringArt", | 
					
						
							|  |  |  | 		"bringCreature", | 
					
						
							|  |  |  | 		"bringResources", | 
					
						
							|  |  |  | 		"bringHero", | 
					
						
							|  |  |  | 		"bringPlayer", | 
					
						
							| 
									
										
										
										
											2022-12-28 00:47:13 +02:00
										 |  |  | 		"keymaster" | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-01 22:50:38 +02:00
										 |  |  | 	if(static_cast<size_t>(mission) < names.size()) | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | 		return names[static_cast<size_t>(mission)]; | 
					
						
							|  |  |  | 	return names[0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const std::string & CQuest::missionState(int state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static const std::array<std::string, 5> states = { | 
					
						
							|  |  |  | 		"receive", | 
					
						
							|  |  |  | 		"visit", | 
					
						
							|  |  |  | 		"complete", | 
					
						
							|  |  |  | 		"hover", | 
					
						
							|  |  |  | 		"description", | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-01 22:50:38 +02:00
										 |  |  | 	if(state < states.size()) | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | 		return states[state]; | 
					
						
							|  |  |  | 	return states[0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-23 14:28:43 +03:00
										 |  |  | bool CQuest::checkMissionArmy(const CQuest * q, const CCreatureSet * army) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	std::vector<CStackBasicDescriptor>::const_iterator cre; | 
					
						
							|  |  |  | 	TSlots::const_iterator it; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 	ui32 count = 0; | 
					
						
							| 
									
										
										
										
											2021-05-23 14:28:43 +03:00
										 |  |  | 	ui32 slotsCount = 0; | 
					
						
							|  |  |  | 	bool hasExtraCreatures = false; | 
					
						
							|  |  |  | 	for(cre = q->m6creatures.begin(); cre != q->m6creatures.end(); ++cre) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		for(count = 0, it = army->Slots().begin(); it != army->Slots().end(); ++it) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if(it->second->type == cre->type) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				count += it->second->count; | 
					
						
							|  |  |  | 				slotsCount++; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		if(static_cast<TQuantity>(count) < cre->count) //not enough creatures of this kind
 | 
					
						
							| 
									
										
										
										
											2021-05-23 14:28:43 +03:00
										 |  |  | 			return false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		hasExtraCreatures |= static_cast<TQuantity>(count) > cre->count; | 
					
						
							| 
									
										
										
										
											2021-05-23 14:28:43 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return hasExtraCreatures || slotsCount < army->Slots().size(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | bool CQuest::checkQuest(const CGHeroInstance * h) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	switch (missionType) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		case MISSION_NONE: | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		case MISSION_LEVEL: | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 			return m13489val <= h->level; | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		case MISSION_PRIMARY_STAT: | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 				if(h->getPrimSkillLevel(static_cast<PrimarySkill::PrimarySkill>(i)) < static_cast<int>(m2stats[i])) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 					return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		case MISSION_KILL_HERO: | 
					
						
							|  |  |  | 		case MISSION_KILL_CREATURE: | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 			if(!CGHeroInstance::cb->getObjByQuestIdentifier(m13489val)) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				return true; | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 		case MISSION_ART: | 
					
						
							| 
									
										
										
										
											2023-03-19 20:41:01 +02:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2022-10-01 09:28:32 +03:00
										 |  |  | 			// if the object was deserialized
 | 
					
						
							|  |  |  | 			if(artifactsRequirements.empty()) | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 				for(const auto & id : m5arts) | 
					
						
							| 
									
										
										
										
											2022-10-01 09:28:32 +03:00
										 |  |  | 					++artifactsRequirements[id]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-19 20:41:01 +02:00
										 |  |  | 			size_t reqSlots = 0; | 
					
						
							| 
									
										
										
										
											2022-10-01 09:28:32 +03:00
										 |  |  | 			for(const auto & elem : artifactsRequirements) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2022-10-01 09:28:32 +03:00
										 |  |  | 				// check required amount of artifacts
 | 
					
						
							|  |  |  | 				if(h->getArtPosCount(elem.first, false, true, true) < elem.second) | 
					
						
							|  |  |  | 					return false; | 
					
						
							| 
									
										
										
										
											2023-03-19 20:41:01 +02:00
										 |  |  | 				if(!h->hasArt(elem.first)) | 
					
						
							|  |  |  | 					reqSlots += h->getAssemblyByConstituent(elem.first)->constituentsInfo.size() - 2; | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-03-19 20:41:01 +02:00
										 |  |  | 			if(ArtifactUtils::isBackpackFreeSlots(h, reqSlots)) | 
					
						
							|  |  |  | 				return true; | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				return false; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		case MISSION_ARMY: | 
					
						
							| 
									
										
										
										
											2021-05-23 14:28:43 +03:00
										 |  |  | 			return checkMissionArmy(this, h); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		case MISSION_RESOURCES: | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			for(Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, +1)) //including Mithril ?
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			{	//Quest has no direct access to callback
 | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 				if(CGHeroInstance::cb->getResource(h->tempOwner, i) < static_cast<int>(m7resources[i])) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 					return false; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		case MISSION_HERO: | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 			return m13489val == h->type->getIndex(); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		case MISSION_PLAYER: | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 			return m13489val == h->getOwner().getNum(); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		default: | 
					
						
							|  |  |  | 			return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | void CQuest::getVisitText(MetaString &iwText, std::vector<Component> &components, bool isCustom, bool firstVisit, const CGHeroInstance * h) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	std::string text; | 
					
						
							|  |  |  | 	bool failRequirements = (h ? !checkQuest(h) : true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	if(firstVisit) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		isCustom = isCustomFirst; | 
					
						
							|  |  |  | 		iwText << (text = firstVisitText); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	else if(failRequirements) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		isCustom = isCustomNext; | 
					
						
							|  |  |  | 		iwText << (text = nextVisitText); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch (missionType) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		case MISSION_LEVEL: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 			components.emplace_back(Component::EComponentType::EXPERIENCE, 0, m13489val, 0); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			if(!isCustom) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				iwText.addReplacement(m13489val); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_PRIMARY_STAT: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			MetaString loot; | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			for(int i = 0; i < 4; ++i) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 				if(m2stats[i]) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 					components.emplace_back(Component::EComponentType::PRIM_SKILL, i, m2stats[i], 0); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 					loot << "%d %s"; | 
					
						
							|  |  |  | 					loot.addReplacement(m2stats[i]); | 
					
						
							|  |  |  | 					loot.addReplacement(VLC->generaltexth->primarySkillNames[i]); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (!isCustom) | 
					
						
							|  |  |  | 				iwText.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_KILL_HERO: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 			components.emplace_back(Component::EComponentType::HERO_PORTRAIT, heroPortrait, 0, 0); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			if(!isCustom) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				addReplacements(iwText, text); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_HERO: | 
					
						
							|  |  |  | 			//FIXME: portrait may not match hero, if custom portrait was set in map editor
 | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 			components.emplace_back(Component::EComponentType::HERO_PORTRAIT, VLC->heroh->objects[m13489val]->imageIndex, 0, 0); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			if(!isCustom) | 
					
						
							| 
									
										
										
										
											2023-02-24 13:40:06 +02:00
										 |  |  | 				iwText.addReplacement(VLC->heroh->objects[m13489val]->getNameTranslated()); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_KILL_CREATURE: | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 				components.emplace_back(stackToKill); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 				if(!isCustom) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				{ | 
					
						
							|  |  |  | 					addReplacements(iwText, text); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_ART: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			MetaString loot; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 			for(const auto & elem : m5arts) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 				components.emplace_back(Component::EComponentType::ARTIFACT, elem, 0, 0); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				loot << "%s"; | 
					
						
							|  |  |  | 				loot.addReplacement(MetaString::ART_NAMES, elem); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			if(!isCustom) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				iwText.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_ARMY: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			MetaString loot; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 			for(const auto & elem : m6creatures) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 				components.emplace_back(elem); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				loot << "%s"; | 
					
						
							|  |  |  | 				loot.addReplacement(elem); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			if(!isCustom) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				iwText.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_RESOURCES: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			MetaString loot; | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			for(int i = 0; i < 7; ++i) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 				if(m7resources[i]) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 					components.emplace_back(Component::EComponentType::RESOURCE, i, m7resources[i], 0); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 					loot << "%d %s"; | 
					
						
							|  |  |  | 					loot.addReplacement(m7resources[i]); | 
					
						
							|  |  |  | 					loot.addReplacement(MetaString::RES_NAMES, i); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			if(!isCustom) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				iwText.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_PLAYER: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 			components.emplace_back(Component::EComponentType::FLAG, m13489val, 0, 0); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			if(!isCustom) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				iwText.addReplacement(VLC->generaltexth->colors[m13489val]); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | void CQuest::getRolloverText(MetaString &ms, bool onHover) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-02-14 00:57:33 +03:00
										 |  |  | 	// Quests with MISSION_NONE type don't have a text for them
 | 
					
						
							|  |  |  | 	assert(missionType != MISSION_NONE); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	if(onHover) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		ms << "\n\n"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 	std::string questName = missionName(static_cast<Emission>(missionType - 1)); | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | 	std::string questState = missionState(onHover ? 3 : 4); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-30 19:09:19 +02:00
										 |  |  | 	ms << VLC->generaltexth->translate("core.seerhut.quest", questName, questState,textOption); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	switch(missionType) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		case MISSION_LEVEL: | 
					
						
							| 
									
										
										
										
											2017-01-26 10:52:19 +03:00
										 |  |  | 			ms.addReplacement(m13489val); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_PRIMARY_STAT: | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				MetaString loot; | 
					
						
							|  |  |  | 				for (int i = 0; i < 4; ++i) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					if (m2stats[i]) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						loot << "%d %s"; | 
					
						
							|  |  |  | 						loot.addReplacement(m2stats[i]); | 
					
						
							|  |  |  | 						loot.addReplacement(VLC->generaltexth->primarySkillNames[i]); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				ms.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_KILL_HERO: | 
					
						
							|  |  |  | 			ms.addReplacement(heroName); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_KILL_CREATURE: | 
					
						
							|  |  |  | 			ms.addReplacement(stackToKill); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_ART: | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				MetaString loot; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 				for(const auto & elem : m5arts) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				{ | 
					
						
							|  |  |  | 					loot << "%s"; | 
					
						
							|  |  |  | 					loot.addReplacement(MetaString::ART_NAMES, elem); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				ms.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_ARMY: | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				MetaString loot; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 				for(const auto & elem : m6creatures) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				{ | 
					
						
							|  |  |  | 					loot << "%s"; | 
					
						
							|  |  |  | 					loot.addReplacement(elem); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				ms.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_RESOURCES: | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				MetaString loot; | 
					
						
							|  |  |  | 				for (int i = 0; i < 7; ++i) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					if (m7resources[i]) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						loot << "%d %s"; | 
					
						
							|  |  |  | 						loot.addReplacement(m7resources[i]); | 
					
						
							|  |  |  | 						loot.addReplacement(MetaString::RES_NAMES, i); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				ms.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_HERO: | 
					
						
							| 
									
										
										
										
											2023-02-24 13:40:06 +02:00
										 |  |  | 			ms.addReplacement(VLC->heroh->objects[m13489val]->getNameTranslated()); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_PLAYER: | 
					
						
							|  |  |  | 			ms.addReplacement(VLC->generaltexth->colors[m13489val]); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | void CQuest::getCompletionText(MetaString &iwText, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	iwText << completedText; | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	switch(missionType) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		case CQuest::MISSION_LEVEL: | 
					
						
							|  |  |  | 			if (!isCustomComplete) | 
					
						
							|  |  |  | 				iwText.addReplacement(m13489val); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case CQuest::MISSION_PRIMARY_STAT: | 
					
						
							|  |  |  | 			if (vstd::contains (completedText,'%')) //there's one case when there's nothing to replace
 | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				MetaString loot; | 
					
						
							|  |  |  | 				for (int i = 0; i < 4; ++i) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					if (m2stats[i]) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						loot << "%d %s"; | 
					
						
							|  |  |  | 						loot.addReplacement(m2stats[i]); | 
					
						
							|  |  |  | 						loot.addReplacement(VLC->generaltexth->primarySkillNames[i]); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if (!isCustomComplete) | 
					
						
							|  |  |  | 					iwText.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case CQuest::MISSION_ART: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			MetaString loot; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 			for(const auto & elem : m5arts) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				loot << "%s"; | 
					
						
							|  |  |  | 				loot.addReplacement(MetaString::ART_NAMES, elem); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (!isCustomComplete) | 
					
						
							|  |  |  | 				iwText.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case CQuest::MISSION_ARMY: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			MetaString loot; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 			for(const auto & elem : m6creatures) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				loot << "%s"; | 
					
						
							|  |  |  | 				loot.addReplacement(elem); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (!isCustomComplete) | 
					
						
							|  |  |  | 				iwText.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case CQuest::MISSION_RESOURCES: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			MetaString loot; | 
					
						
							|  |  |  | 			for (int i = 0; i < 7; ++i) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if (m7resources[i]) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					loot << "%d %s"; | 
					
						
							|  |  |  | 					loot.addReplacement(m7resources[i]); | 
					
						
							|  |  |  | 					loot.addReplacement(MetaString::RES_NAMES, i); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if (!isCustomComplete) | 
					
						
							|  |  |  | 				iwText.addReplacement(loot.buildList()); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_KILL_HERO: | 
					
						
							|  |  |  | 		case MISSION_KILL_CREATURE: | 
					
						
							|  |  |  | 			if (!isCustomComplete) | 
					
						
							|  |  |  | 				addReplacements(iwText, completedText); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_HERO: | 
					
						
							|  |  |  | 			if (!isCustomComplete) | 
					
						
							| 
									
										
										
										
											2023-02-24 13:40:06 +02:00
										 |  |  | 				iwText.addReplacement(VLC->heroh->objects[m13489val]->getNameTranslated()); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case MISSION_PLAYER: | 
					
						
							|  |  |  | 			if (!isCustomComplete) | 
					
						
							|  |  |  | 				iwText.addReplacement(VLC->generaltexth->colors[m13489val]); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | void CQuest::addArtifactID(const ArtifactID & id) | 
					
						
							| 
									
										
										
										
											2022-10-01 09:28:32 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	m5arts.push_back(id); | 
					
						
							|  |  |  | 	++artifactsRequirements[id]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | void CQuest::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	auto q = handler.enterStruct(fieldName); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	handler.serializeString("firstVisitText", firstVisitText); | 
					
						
							|  |  |  | 	handler.serializeString("nextVisitText", nextVisitText); | 
					
						
							|  |  |  | 	handler.serializeString("completedText", completedText); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(!handler.saving) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		isCustomFirst = !firstVisitText.empty(); | 
					
						
							|  |  |  | 		isCustomNext = !nextVisitText.empty(); | 
					
						
							|  |  |  | 		isCustomComplete = !completedText.empty(); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static const std::vector<std::string> MISSION_TYPE_JSON = | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		"None", "Level", "PrimaryStat", "KillHero", "KillCreature", "Artifact", "Army", "Resources", "Hero", "Player" | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	handler.serializeEnum("missionType", missionType, Emission::MISSION_NONE, MISSION_TYPE_JSON); | 
					
						
							|  |  |  | 	handler.serializeInt("timeLimit", lastDay, -1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (missionType) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case MISSION_NONE: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case MISSION_LEVEL: | 
					
						
							|  |  |  | 		handler.serializeInt("heroLevel", m13489val, -1); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case MISSION_PRIMARY_STAT: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			auto primarySkills = handler.enterStruct("primarySkills"); | 
					
						
							|  |  |  | 			if(!handler.saving) | 
					
						
							|  |  |  | 				m2stats.resize(GameConstants::PRIMARY_SKILLS); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for(int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i) | 
					
						
							|  |  |  | 				handler.serializeInt(PrimarySkill::names[i], m2stats[i], 0); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case MISSION_KILL_HERO: | 
					
						
							|  |  |  | 	case MISSION_KILL_CREATURE: | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		handler.serializeInstance<ui32>("killTarget", m13489val, static_cast<ui32>(-1)); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case MISSION_ART: | 
					
						
							|  |  |  | 		//todo: ban artifacts
 | 
					
						
							| 
									
										
										
										
											2022-11-29 00:11:46 +02:00
										 |  |  | 		handler.serializeIdArray<ArtifactID>("artifacts", m5arts); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case MISSION_ARMY: | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  | 			auto a = handler.enterArray("creatures"); | 
					
						
							|  |  |  | 			a.serializeStruct(m6creatures); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case MISSION_RESOURCES: | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         	auto r = handler.enterStruct("resources"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         	if(!handler.saving) | 
					
						
							|  |  |  | 				m7resources.resize(GameConstants::RESOURCE_QUANTITY-1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for(size_t idx = 0; idx < (GameConstants::RESOURCE_QUANTITY - 1); idx++) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				handler.serializeInt(GameConstants::RESOURCE_NAMES[idx], m7resources[idx], 0); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case MISSION_HERO: | 
					
						
							| 
									
										
										
											
												Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
											
										 
											2018-03-17 17:58:30 +03:00
										 |  |  | 		handler.serializeId<ui32, ui32, HeroTypeID>("hero", m13489val, 0); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case MISSION_PLAYER: | 
					
						
							|  |  |  | 		handler.serializeEnum("player",  m13489val, PlayerColor::CANNOT_DETERMINE.getNum(), GameConstants::PLAYER_COLOR_NAMES); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		logGlobal->error("Invalid quest mission type"); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | void CGSeerHut::setObjToKill() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	if(quest->missionType == CQuest::MISSION_KILL_CREATURE) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		quest->stackToKill = getCreatureToKill(false)->getStack(SlotID(0)); //FIXME: stacks tend to disappear (desync?) on server :?
 | 
					
						
							|  |  |  | 		assert(quest->stackToKill.type); | 
					
						
							|  |  |  | 		quest->stackToKill.count = 0; //no count in info window
 | 
					
						
							|  |  |  | 		quest->stackDirection = checkDirection(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	else if(quest->missionType == CQuest::MISSION_KILL_HERO) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2023-01-02 13:27:03 +02:00
										 |  |  | 		quest->heroName = getHeroToKill(false)->getNameTranslated(); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		quest->heroPortrait = getHeroToKill(false)->portrait; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-09 20:30:36 +03:00
										 |  |  | void CGSeerHut::init(CRandomGenerator & rand) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | 	auto names = VLC->generaltexth->findStringsWithPrefix("core.seerhut.names"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	seerName = *RandomGeneratorUtil::nextItem(names, rand); | 
					
						
							| 
									
										
										
										
											2016-09-09 20:30:36 +03:00
										 |  |  | 	quest->textOption = rand.nextInt(2); | 
					
						
							|  |  |  | 	quest->completedOption = rand.nextInt(1, 3); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-09 20:30:36 +03:00
										 |  |  | void CGSeerHut::initObj(CRandomGenerator & rand) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-09-09 20:30:36 +03:00
										 |  |  | 	init(rand); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	quest->progress = CQuest::NOT_ACTIVE; | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	if(quest->missionType) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2023-01-10 16:24:59 +02:00
										 |  |  | 		std::string questName  = quest->missionName(quest->missionType); | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 		if(!quest->isCustomFirst) | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | 			quest->firstVisitText = VLC->generaltexth->translate("core.seerhut.quest." + questName + "." + quest->missionState(0), quest->textOption); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 		if(!quest->isCustomNext) | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | 			quest->nextVisitText = VLC->generaltexth->translate("core.seerhut.quest." + questName + "." + quest->missionState(1), quest->textOption); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 		if(!quest->isCustomComplete) | 
					
						
							| 
									
										
										
										
											2022-12-27 23:17:41 +02:00
										 |  |  | 			quest->completedText = VLC->generaltexth->translate("core.seerhut.quest." + questName + "." + quest->missionState(2), quest->textOption); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		quest->progress = CQuest::COMPLETE; | 
					
						
							| 
									
										
										
										
											2016-01-20 22:40:21 +03:00
										 |  |  | 		quest->firstVisitText = VLC->generaltexth->seerEmpty[quest->completedOption]; | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | void CGSeerHut::getRolloverText(MetaString &text, bool onHover) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	quest->getRolloverText (text, onHover);//TODO: simplify?
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	if(!onHover) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		text.addReplacement(seerName); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-24 20:39:36 +03:00
										 |  |  | std::string CGSeerHut::getHoverText(PlayerColor player) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-24 20:39:36 +03:00
										 |  |  | 	std::string hoverName = getObjectName(); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	if(ID == Obj::SEER_HUT && quest->progress != CQuest::NOT_ACTIVE) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-06-24 20:39:36 +03:00
										 |  |  | 		hoverName = VLC->generaltexth->allTexts[347]; | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 		boost::algorithm::replace_first(hoverName, "%s", seerName); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-24 20:39:36 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	if(quest->progress & quest->missionType) //rollover when the quest is active
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		MetaString ms; | 
					
						
							|  |  |  | 		getRolloverText (ms, true); | 
					
						
							|  |  |  | 		hoverName += ms.toString(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return hoverName; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CQuest::addReplacements(MetaString &out, const std::string &base) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch(missionType) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case MISSION_KILL_CREATURE: | 
					
						
							|  |  |  | 		out.addReplacement(stackToKill); | 
					
						
							|  |  |  | 		if (std::count(base.begin(), base.end(), '%') == 2) //say where is placed monster
 | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			out.addReplacement(VLC->generaltexth->arraytxt[147+stackDirection]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case MISSION_KILL_HERO: | 
					
						
							|  |  |  | 		out.addReplacement(heroName); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool IQuestObject::checkQuest(const CGHeroInstance* h) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return quest->checkQuest(h); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void IQuestObject::getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	quest->getVisitText (text,components, isCustom, FirstVisit, h); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | void IQuestObject::afterAddToMapCommon(CMap * map) const | 
					
						
							| 
									
										
										
										
											2017-05-28 16:23:42 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	map->addNewQuestInstance(quest); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | void CGSeerHut::getCompletionText(MetaString &text, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	quest->getCompletionText (text, components, isCustom, h); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	switch(rewardType) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 	case EXPERIENCE: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::EXPERIENCE, 0, static_cast<si32>(h->calculateXp(rVal)), 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case MANA_POINTS: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::PRIM_SKILL, 5, rVal, 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case MORALE_BONUS: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::MORALE, 0, rVal, 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case LUCK_BONUS: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::LUCK, 0, rVal, 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case RESOURCES: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::RESOURCE, rID, rVal, 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case PRIMARY_SKILL: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::PRIM_SKILL, rID, rVal, 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case SECONDARY_SKILL: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::SEC_SKILL, rID, rVal, 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case ARTIFACT: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::ARTIFACT, rID, 0, 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case SPELL: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::SPELL, rID, 0, 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case CREATURE: | 
					
						
							| 
									
										
										
										
											2023-03-10 15:54:12 +03:00
										 |  |  | 		components.emplace_back(Component::EComponentType::CREATURE, rID, rVal, 0); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CGSeerHut::setPropertyDer (ui8 what, ui32 val) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	switch(what) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		case 10: | 
					
						
							|  |  |  | 			quest->progress = static_cast<CQuest::Eprogress>(val); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-09 20:30:36 +03:00
										 |  |  | void CGSeerHut::newTurn(CRandomGenerator & rand) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	if(quest->lastDay >= 0 && quest->lastDay <= cb->getDate() - 1) //time is up
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2016-01-20 10:44:13 +03:00
										 |  |  | 		cb->setObjProperty (id, CGSeerHut::OBJPROP_VISITED, CQuest::COMPLETE); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | void CGSeerHut::onHeroVisit(const CGHeroInstance * h) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	InfoWindow iw; | 
					
						
							|  |  |  | 	iw.player = h->getOwner(); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 	if(quest->progress < CQuest::COMPLETE) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		bool firstVisit = !quest->progress; | 
					
						
							|  |  |  | 		bool failRequirements = !checkQuest(h); | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 		bool isCustom = false; | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 		if(firstVisit) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			isCustom = quest->isCustomFirst; | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			cb->setObjProperty(id, CGSeerHut::OBJPROP_VISITED, CQuest::IN_PROGRESS); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			AddQuest aq; | 
					
						
							|  |  |  | 			aq.quest = QuestInfo (quest, this, visitablePos()); | 
					
						
							|  |  |  | 			aq.player = h->tempOwner; | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 			cb->sendAndApply(&aq); //TODO: merge with setObjProperty?
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 		else if(failRequirements) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			isCustom = quest->isCustomNext; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 		if(firstVisit || failRequirements) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			getVisitText (iw.text, iw.components, isCustom, firstVisit, h); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			cb->showInfoDialog(&iw); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | 		if(!failRequirements) // propose completion, also on first visit
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			BlockingDialog bd (true, false); | 
					
						
							|  |  |  | 			bd.player = h->getOwner(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			getCompletionText (bd.text, bd.components, isCustom, h); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			cb->showBlockingDialog (&bd); | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2016-01-20 22:40:21 +03:00
										 |  |  | 		iw.text << VLC->generaltexth->seerEmpty[quest->completedOption]; | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		if (ID == Obj::SEER_HUT) | 
					
						
							|  |  |  | 			iw.text.addReplacement(seerName); | 
					
						
							|  |  |  | 		cb->showInfoDialog(&iw); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CGSeerHut::checkDirection() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int3 cord = getCreatureToKill()->pos; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 	if(static_cast<double>(cord.x) / static_cast<double>(cb->getMapSize().x) < 0.34) //north
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.34) //northwest
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			return 8; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		else if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.67) //north
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			return 1; | 
					
						
							|  |  |  | 		else //northeast
 | 
					
						
							|  |  |  | 			return 2; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 	else if(static_cast<double>(cord.x) / static_cast<double>(cb->getMapSize().x) < 0.67) //horizontal
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.34) //west
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			return 7; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		else if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.67) //central
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			return 9; | 
					
						
							|  |  |  | 		else //east
 | 
					
						
							|  |  |  | 			return 3; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else //south
 | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.34) //southwest
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			return 6; | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		else if(static_cast<double>(cord.y) / static_cast<double>(cb->getMapSize().y) < 0.67) //south
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			return 5; | 
					
						
							|  |  |  | 		else //southeast
 | 
					
						
							|  |  |  | 			return 4; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CGSeerHut::finishQuest(const CGHeroInstance * h, ui32 accept) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (accept) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		switch (quest->missionType) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			case CQuest::MISSION_ART: | 
					
						
							| 
									
										
										
										
											2023-03-19 20:41:01 +02:00
										 |  |  | 				for(auto & elem : quest->m5arts) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2023-03-19 20:41:01 +02:00
										 |  |  | 					if(h->hasArt(elem)) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						cb->removeArtifact(ArtifactLocation(h, h->getArtPos(elem, false))); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					else | 
					
						
							| 
									
										
										
										
											2016-01-22 12:53:01 +03:00
										 |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 						const auto * assembly = h->getAssemblyByConstituent(elem); | 
					
						
							| 
									
										
										
										
											2016-01-22 12:53:01 +03:00
										 |  |  | 						assert(assembly); | 
					
						
							| 
									
										
										
										
											2023-03-19 20:41:01 +02:00
										 |  |  | 						auto parts = assembly->constituentsInfo; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// Remove the assembly
 | 
					
						
							|  |  |  | 						cb->removeArtifact(ArtifactLocation(h, h->getArtPos(assembly))); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// Disassemble this backpack artifact
 | 
					
						
							|  |  |  | 						for(const auto & ci : parts) | 
					
						
							| 
									
										
										
										
											2016-01-22 12:53:01 +03:00
										 |  |  | 						{ | 
					
						
							| 
									
										
										
										
											2023-03-21 12:13:53 +02:00
										 |  |  | 							if(ci.art->getTypeId() != elem) | 
					
						
							| 
									
										
										
										
											2023-03-19 20:41:01 +02:00
										 |  |  | 								cb->giveHeroNewArtifact(h, ci.art->artType, GameConstants::BACKPACK_START); | 
					
						
							| 
									
										
										
										
											2016-01-22 12:53:01 +03:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case CQuest::MISSION_ARMY: | 
					
						
							|  |  |  | 					cb->takeCreatures(h->id, quest->m6creatures); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case CQuest::MISSION_RESOURCES: | 
					
						
							|  |  |  | 				for (int i = 0; i < 7; ++i) | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 					cb->giveResource(h->getOwner(), static_cast<Res::ERes>(i), -static_cast<int>(quest->m7resources[i])); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-20 10:44:13 +03:00
										 |  |  | 		cb->setObjProperty (id, CGSeerHut::OBJPROP_VISITED, CQuest::COMPLETE); //mission complete
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 		completeQuest(h); //make sure to remove QuestGuard at the very end
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (rewardType) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		case EXPERIENCE: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			TExpType expVal = h->calculateXp(rVal); | 
					
						
							|  |  |  | 			cb->changePrimSkill(h, PrimarySkill::EXPERIENCE, expVal, false); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		case MANA_POINTS: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			cb->setManaPoints(h->id, h->mana+rVal); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		case MORALE_BONUS: case LUCK_BONUS: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Bonus hb(Bonus::ONE_WEEK, (rewardType == 3 ? Bonus::MORALE : Bonus::LUCK), | 
					
						
							|  |  |  | 				Bonus::OBJECT, rVal, h->id.getNum(), "", -1); | 
					
						
							|  |  |  | 			GiveBonus gb; | 
					
						
							|  |  |  | 			gb.id = h->id.getNum(); | 
					
						
							|  |  |  | 			gb.bonus = hb; | 
					
						
							|  |  |  | 			cb->giveHeroBonus(&gb); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case RESOURCES: | 
					
						
							|  |  |  | 			cb->giveResource(h->getOwner(), static_cast<Res::ERes>(rID), rVal); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case PRIMARY_SKILL: | 
					
						
							|  |  |  | 			cb->changePrimSkill(h, static_cast<PrimarySkill::PrimarySkill>(rID), rVal, false); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case SECONDARY_SKILL: | 
					
						
							|  |  |  | 			cb->changeSecSkill(h, SecondarySkill(rID), rVal, false); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case ARTIFACT: | 
					
						
							| 
									
										
										
										
											2023-03-20 01:18:32 +02:00
										 |  |  | 			cb->giveHeroNewArtifact(h, VLC->arth->objects[rID],ArtifactPosition::FIRST_AVAILABLE); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case SPELL: | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			std::set<SpellID> spell; | 
					
						
							|  |  |  | 			spell.insert (SpellID(rID)); | 
					
						
							|  |  |  | 			cb->changeSpells(h, true, spell); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case CREATURE: | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				CCreatureSet creatures; | 
					
						
							|  |  |  | 				creatures.setCreature(SlotID(0), CreatureID(rID), rVal); | 
					
						
							|  |  |  | 				cb->giveCreatures(this, h, creatures, false); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->m13489val); | 
					
						
							|  |  |  | 	if(allowNull && !o) | 
					
						
							|  |  |  | 		return nullptr; | 
					
						
							|  |  |  | 	assert(o && (o->ID == Obj::HERO  ||  o->ID == Obj::PRISON)); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 	return dynamic_cast<const CGHeroInstance *>(o); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->m13489val); | 
					
						
							|  |  |  | 	if(allowNull && !o) | 
					
						
							|  |  |  | 		return nullptr; | 
					
						
							|  |  |  | 	assert(o && o->ID == Obj::MONSTER); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 	return dynamic_cast<const CGCreature *>(o); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CGSeerHut::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	finishQuest(hero, answer); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-28 16:23:42 +03:00
										 |  |  | void CGSeerHut::afterAddToMap(CMap* map) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IQuestObject::afterAddToMapCommon(map); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	static const std::map<ERewardType, std::string> REWARD_MAP = | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		{NOTHING,		""}, | 
					
						
							|  |  |  | 		{EXPERIENCE,	"experience"}, | 
					
						
							|  |  |  | 		{MANA_POINTS,	"mana"}, | 
					
						
							|  |  |  | 		{MORALE_BONUS,	"morale"}, | 
					
						
							|  |  |  | 		{LUCK_BONUS,	"luck"}, | 
					
						
							|  |  |  | 		{RESOURCES,		"resource"}, | 
					
						
							|  |  |  | 		{PRIMARY_SKILL,	"primarySkill"}, | 
					
						
							|  |  |  | 		{SECONDARY_SKILL,"secondarySkill"}, | 
					
						
							|  |  |  | 		{ARTIFACT,		"artifact"}, | 
					
						
							|  |  |  | 		{SPELL,			"spell"}, | 
					
						
							|  |  |  | 		{CREATURE,		"creature"} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	static const std::map<std::string, ERewardType> REWARD_RMAP = | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		{"experience",    EXPERIENCE}, | 
					
						
							|  |  |  | 		{"mana",          MANA_POINTS}, | 
					
						
							|  |  |  | 		{"morale",        MORALE_BONUS}, | 
					
						
							|  |  |  | 		{"luck",          LUCK_BONUS}, | 
					
						
							|  |  |  | 		{"resource",      RESOURCES}, | 
					
						
							|  |  |  | 		{"primarySkill",  PRIMARY_SKILL}, | 
					
						
							|  |  |  | 		{"secondarySkill",SECONDARY_SKILL}, | 
					
						
							|  |  |  | 		{"artifact",      ARTIFACT}, | 
					
						
							|  |  |  | 		{"spell",         SPELL}, | 
					
						
							|  |  |  | 		{"creature",      CREATURE} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//quest and reward
 | 
					
						
							|  |  |  | 	quest->serializeJson(handler, "quest"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//only one reward is supported
 | 
					
						
							|  |  |  | 	//todo: full reward format support after CRewardInfo integration
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	auto s = handler.enterStruct("reward"); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 	std::string fullIdentifier; | 
					
						
							|  |  |  | 	std::string metaTypeName; | 
					
						
							|  |  |  | 	std::string scope; | 
					
						
							|  |  |  | 	std::string identifier; | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(handler.saving) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		si32 amount = rVal; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		metaTypeName = REWARD_MAP.at(rewardType); | 
					
						
							|  |  |  | 		switch (rewardType) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		case NOTHING: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case EXPERIENCE: | 
					
						
							|  |  |  | 		case MANA_POINTS: | 
					
						
							|  |  |  | 		case MORALE_BONUS: | 
					
						
							|  |  |  | 		case LUCK_BONUS: | 
					
						
							| 
									
										
										
										
											2022-11-15 03:20:55 +03:00
										 |  |  | 			identifier.clear(); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case RESOURCES: | 
					
						
							|  |  |  | 			identifier = GameConstants::RESOURCE_NAMES[rID]; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case PRIMARY_SKILL: | 
					
						
							|  |  |  | 			identifier = PrimarySkill::names[rID]; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case SECONDARY_SKILL: | 
					
						
							| 
									
										
										
										
											2018-03-31 18:56:40 +13:00
										 |  |  | 			identifier = CSkillHandler::encodeSkill(rID); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case ARTIFACT: | 
					
						
							| 
									
										
										
											
												Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
											
										 
											2018-03-17 17:58:30 +03:00
										 |  |  | 			identifier = ArtifactID(rID).toArtifact(VLC->artifacts())->getJsonKey(); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 			amount = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case SPELL: | 
					
						
							| 
									
										
										
											
												Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
											
										 
											2018-03-17 17:58:30 +03:00
										 |  |  | 			identifier = SpellID(rID).toSpell(VLC->spells())->getJsonKey(); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 			amount = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case CREATURE: | 
					
						
							| 
									
										
										
											
												Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
											
										 
											2018-03-17 17:58:30 +03:00
										 |  |  | 			identifier = CreatureID(rID).toCreature(VLC->creatures())->getJsonKey(); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			assert(false); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(rewardType != NOTHING) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			fullIdentifier = CModHandler::makeFullIdentifier(scope, metaTypeName, identifier); | 
					
						
							|  |  |  | 			handler.serializeInt(fullIdentifier, amount); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		rewardType = NOTHING; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const JsonNode & rewardsJson = handler.getCurrent(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 03:20:55 +03:00
										 |  |  | 		fullIdentifier.clear(); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if(rewardsJson.Struct().empty()) | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			auto iter = rewardsJson.Struct().begin(); | 
					
						
							|  |  |  | 			fullIdentifier = iter->first; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		CModHandler::parseIdentifier(fullIdentifier, scope, metaTypeName, identifier); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		auto it = REWARD_RMAP.find(metaTypeName); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(it == REWARD_RMAP.end()) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2017-08-11 20:03:05 +03:00
										 |  |  | 			logGlobal->error("%s: invalid metatype in reward item %s", instanceName, fullIdentifier); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			rewardType = it->second; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bool doRequest = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (rewardType) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		case NOTHING: | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		case EXPERIENCE: | 
					
						
							|  |  |  | 		case MANA_POINTS: | 
					
						
							|  |  |  | 		case MORALE_BONUS: | 
					
						
							|  |  |  | 		case LUCK_BONUS: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case PRIMARY_SKILL: | 
					
						
							|  |  |  | 			doRequest = true; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case RESOURCES: | 
					
						
							|  |  |  | 		case SECONDARY_SKILL: | 
					
						
							|  |  |  | 		case ARTIFACT: | 
					
						
							|  |  |  | 		case SPELL: | 
					
						
							|  |  |  | 		case CREATURE: | 
					
						
							|  |  |  | 			doRequest = true; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			assert(false); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(doRequest) | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2022-12-21 19:00:36 +02:00
										 |  |  | 			auto rawId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeMap(), fullIdentifier, false); | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if(rawId) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				rID = rawId.get(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				rewardType = NOTHING;//fallback in case of error
 | 
					
						
							|  |  |  | 				return; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		handler.serializeInt(fullIdentifier, rVal); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-09 20:30:36 +03:00
										 |  |  | void CGQuestGuard::init(CRandomGenerator & rand) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	blockVisit = true; | 
					
						
							| 
									
										
										
										
											2016-09-09 20:30:36 +03:00
										 |  |  | 	quest->textOption = rand.nextInt(3, 5); | 
					
						
							|  |  |  | 	quest->completedOption = rand.nextInt(4, 5); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CGQuestGuard::completeQuest(const CGHeroInstance *h) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	cb->removeObject(this); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-13 13:38:42 +03:00
										 |  |  | void CGQuestGuard::serializeJsonOptions(JsonSerializeFormat & handler) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	//quest only, do not call base class
 | 
					
						
							|  |  |  | 	quest->serializeJson(handler, "quest"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-25 15:52:20 +03:00
										 |  |  | void CGKeys::reset() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	playerKeyMap.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | void CGKeys::setPropertyDer (ui8 what, ui32 val) //101-108 - enable key for player 1-8
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (what >= 101 && what <= (100 + PlayerColor::PLAYER_LIMIT_I)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		PlayerColor player(what-101); | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		playerKeyMap[player].insert(static_cast<ui8>(val)); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 		logGlobal->error("Unexpected properties requested to set: what=%d, val=%d", static_cast<int>(what), val); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | bool CGKeys::wasMyColorVisited(const PlayerColor & player) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-02-12 23:39:17 +03:00
										 |  |  | 	return playerKeyMap.count(player) && vstd::contains(playerKeyMap[player], subID); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-24 20:39:36 +03:00
										 |  |  | std::string CGKeys::getHoverText(PlayerColor player) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-24 20:39:36 +03:00
										 |  |  | 	return getObjectName() + "\n" + visitedTxt(wasMyColorVisited(player)); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-24 20:39:36 +03:00
										 |  |  | std::string CGKeys::getObjectName() const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-24 20:39:36 +03:00
										 |  |  | 	return VLC->generaltexth->tentColors[subID] + " " + CGObjectInstance::getObjectName(); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool CGKeymasterTent::wasVisited (PlayerColor player) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return wasMyColorVisited (player); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CGKeymasterTent::onHeroVisit( const CGHeroInstance * h ) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int txt_id; | 
					
						
							|  |  |  | 	if (!wasMyColorVisited (h->getOwner()) ) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		cb->setObjProperty(id, h->tempOwner.getNum()+101, subID); | 
					
						
							|  |  |  | 		txt_id=19; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		txt_id=20; | 
					
						
							| 
									
										
										
										
											2023-03-08 01:32:21 +03:00
										 |  |  | 	h->showInfoDialog(txt_id); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-09 20:30:36 +03:00
										 |  |  | void CGBorderGuard::initObj(CRandomGenerator & rand) | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	//ui32 m13489val = subID; //store color as quest info
 | 
					
						
							|  |  |  | 	blockVisit = true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CGBorderGuard::getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	text << std::pair<ui8,ui32>(11,18); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CGBorderGuard::getRolloverText (MetaString &text, bool onHover) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!onHover) | 
					
						
							| 
									
										
										
										
											2022-12-31 15:01:19 +02:00
										 |  |  | 		text << VLC->generaltexth->tentColors[subID] << " " << VLC->objtypeh->getObjectName(Obj::KEYMASTER, subID); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | bool CGBorderGuard::checkQuest(const CGHeroInstance * h) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	return wasMyColorVisited (h->tempOwner); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | void CGBorderGuard::onHeroVisit(const CGHeroInstance * h) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (wasMyColorVisited (h->getOwner()) ) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		BlockingDialog bd (true, false); | 
					
						
							|  |  |  | 		bd.player = h->getOwner(); | 
					
						
							|  |  |  | 		bd.text.addTxt (MetaString::ADVOB_TXT, 17); | 
					
						
							|  |  |  | 		cb->showBlockingDialog (&bd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2023-03-08 01:32:21 +03:00
										 |  |  | 		h->showInfoDialog(18); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		AddQuest aq; | 
					
						
							|  |  |  | 		aq.quest = QuestInfo (quest, this, visitablePos()); | 
					
						
							|  |  |  | 		aq.player = h->tempOwner; | 
					
						
							|  |  |  | 		cb->sendAndApply (&aq); | 
					
						
							|  |  |  | 		//TODO: add this quest only once OR check for multiple instances later
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CGBorderGuard::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (answer) | 
					
						
							|  |  |  | 		cb->removeObject(this); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-28 16:23:42 +03:00
										 |  |  | void CGBorderGuard::afterAddToMap(CMap * map) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	IQuestObject::afterAddToMapCommon(map); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 09:28:37 +03:00
										 |  |  | void CGBorderGate::onHeroVisit(const CGHeroInstance * h) const //TODO: passability
 | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (!wasMyColorVisited (h->getOwner()) ) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2023-03-08 01:32:21 +03:00
										 |  |  | 		h->showInfoDialog(18); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		AddQuest aq; | 
					
						
							|  |  |  | 		aq.quest = QuestInfo (quest, this, visitablePos()); | 
					
						
							|  |  |  | 		aq.player = h->tempOwner; | 
					
						
							|  |  |  | 		cb->sendAndApply (&aq); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-24 02:26:36 +03:00
										 |  |  | bool CGBorderGate::passableFor(PlayerColor color) const | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-24 02:26:36 +03:00
										 |  |  | 	return wasMyColorVisited(color); | 
					
						
							| 
									
										
										
										
											2014-06-05 19:52:14 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-26 16:07:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | VCMI_LIB_NAMESPACE_END |