mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Implement markets
This commit is contained in:
		| @@ -585,6 +585,16 @@ namespace BuildingSubID | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| namespace EMarketMode | ||||
| { | ||||
| 	enum EMarketMode | ||||
| 	{ | ||||
| 		RESOURCE_RESOURCE, RESOURCE_PLAYER, CREATURE_RESOURCE, RESOURCE_ARTIFACT, | ||||
| 		ARTIFACT_RESOURCE, ARTIFACT_EXP, CREATURE_EXP, CREATURE_UNDEAD, RESOURCE_SKILL, | ||||
| 		MARTKET_AFTER_LAST_PLACEHOLDER | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| namespace MappedKeys | ||||
| { | ||||
|  | ||||
| @@ -634,6 +644,19 @@ namespace MappedKeys | ||||
| 		{ "lighthouse", BuildingSubID::LIGHTHOUSE }, | ||||
| 		{ "treasury", BuildingSubID::TREASURY } | ||||
| 	}; | ||||
|  | ||||
| 	static const std::map<std::string, EMarketMode::EMarketMode> MARKET_NAMES_TO_TYPES = | ||||
| 	{ | ||||
| 		{ "resource-resource", EMarketMode::RESOURCE_RESOURCE }, | ||||
| 		{ "resource-player", EMarketMode::RESOURCE_PLAYER }, | ||||
| 		{ "creature-resource", EMarketMode::CREATURE_RESOURCE }, | ||||
| 		{ "resource-artifact", EMarketMode::RESOURCE_ARTIFACT }, | ||||
| 		{ "artifact-resource", EMarketMode::ARTIFACT_RESOURCE }, | ||||
| 		{ "artifact-experience", EMarketMode::ARTIFACT_EXP }, | ||||
| 		{ "creature-experience", EMarketMode::CREATURE_EXP }, | ||||
| 		{ "creature-undead", EMarketMode::CREATURE_UNDEAD }, | ||||
| 		{ "resource-skill", EMarketMode::RESOURCE_SKILL }, | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| namespace EAiTactic | ||||
| @@ -670,16 +693,6 @@ namespace ESpellCastProblem | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| namespace EMarketMode | ||||
| { | ||||
| 	enum EMarketMode | ||||
| 	{ | ||||
| 		RESOURCE_RESOURCE, RESOURCE_PLAYER, CREATURE_RESOURCE, RESOURCE_ARTIFACT, | ||||
| 		ARTIFACT_RESOURCE, ARTIFACT_EXP, CREATURE_EXP, CREATURE_UNDEAD, RESOURCE_SKILL, | ||||
| 		MARTKET_AFTER_LAST_PLACEHOLDER | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| namespace ECommander | ||||
| { | ||||
| 	enum SecondarySkills {ATTACK, DEFENSE, HEALTH, DAMAGE, SPEED, SPELL_POWER, CASTS, RESISTANCE}; | ||||
|   | ||||
| @@ -19,6 +19,7 @@ | ||||
| #include "CGTownInstance.h" | ||||
| #include "../GameSettings.h" | ||||
| #include "../CSkillHandler.h" | ||||
| #include "CObjectClassesHandler.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| @@ -158,23 +159,10 @@ std::vector<int> IMarket::availableItemsIds(EMarketMode::EMarketMode mode) const | ||||
|  | ||||
| const IMarket * IMarket::castFrom(const CGObjectInstance *obj, bool verbose) | ||||
| { | ||||
| 	switch(obj->ID) | ||||
| 	{ | ||||
| 	case Obj::TOWN: | ||||
| 		return dynamic_cast<const CGTownInstance *>(obj); | ||||
| 	case Obj::ALTAR_OF_SACRIFICE: | ||||
| 	case Obj::BLACK_MARKET: | ||||
| 	case Obj::TRADING_POST: | ||||
| 	case Obj::TRADING_POST_SNOW: | ||||
| 	case Obj::FREELANCERS_GUILD: | ||||
| 		return dynamic_cast<const CGMarket *>(obj); | ||||
| 	case Obj::UNIVERSITY: | ||||
| 		return dynamic_cast<const CGUniversity *>(obj); | ||||
| 	default: | ||||
| 		if(verbose) | ||||
| 			logGlobal->error("Cannot cast to IMarket object with ID %d", obj->ID); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	auto * imarket = dynamic_cast<const IMarket *>(obj); | ||||
| 	if(verbose && !imarket) | ||||
| 		logGlobal->error("Cannot cast to IMarket object type %s", obj->typeName); | ||||
| 	return imarket; | ||||
| } | ||||
|  | ||||
| IMarket::IMarket() | ||||
| @@ -191,43 +179,24 @@ std::vector<EMarketMode::EMarketMode> IMarket::availableModes() const | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| void CGMarket::initObj(CRandomGenerator & rand) | ||||
| { | ||||
| 	VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand); | ||||
| } | ||||
|  | ||||
| void CGMarket::onHeroVisit(const CGHeroInstance * h) const | ||||
| { | ||||
| 	openWindow(EOpenWindowMode::MARKET_WINDOW,id.getNum(),h->id.getNum()); | ||||
| 	openWindow(EOpenWindowMode::MARKET_WINDOW, id.getNum(), h->id.getNum()); | ||||
| } | ||||
|  | ||||
| int CGMarket::getMarketEfficiency() const | ||||
| { | ||||
| 	return 5; | ||||
| 	return marketEfficacy; | ||||
| } | ||||
|  | ||||
| bool CGMarket::allowsTrade(EMarketMode::EMarketMode mode) const | ||||
| { | ||||
| 	switch(mode) | ||||
| 	{ | ||||
| 	case EMarketMode::RESOURCE_RESOURCE: | ||||
| 	case EMarketMode::RESOURCE_PLAYER: | ||||
| 		switch(ID) | ||||
| 		{ | ||||
| 		case Obj::TRADING_POST: | ||||
| 		case Obj::TRADING_POST_SNOW: | ||||
| 			return true; | ||||
| 		default: | ||||
| 			return false; | ||||
| 		} | ||||
| 	case EMarketMode::CREATURE_RESOURCE: | ||||
| 		return ID == Obj::FREELANCERS_GUILD; | ||||
| 	//case ARTIFACT_RESOURCE: | ||||
| 	case EMarketMode::RESOURCE_ARTIFACT: | ||||
| 		return ID == Obj::BLACK_MARKET; | ||||
| 	case EMarketMode::ARTIFACT_EXP: | ||||
| 	case EMarketMode::CREATURE_EXP: | ||||
| 		return ID == Obj::ALTAR_OF_SACRIFICE; //TODO? check here for alignment of visiting hero? - would not be coherent with other checks here | ||||
| 	case EMarketMode::RESOURCE_SKILL: | ||||
| 		return ID == Obj::UNIVERSITY; | ||||
| 	default: | ||||
| 		return false; | ||||
| 	} | ||||
| 	return marketModes.count(mode); | ||||
| } | ||||
|  | ||||
| int CGMarket::availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const | ||||
| @@ -237,14 +206,9 @@ int CGMarket::availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial | ||||
|  | ||||
| std::vector<int> CGMarket::availableItemsIds(EMarketMode::EMarketMode mode) const | ||||
| { | ||||
| 	switch(mode) | ||||
| 	{ | ||||
| 	case EMarketMode::RESOURCE_RESOURCE: | ||||
| 	case EMarketMode::RESOURCE_PLAYER: | ||||
| 	if(allowsTrade(mode)) | ||||
| 		return IMarket::availableItemsIds(mode); | ||||
| 	default: | ||||
| 		return std::vector<int>(); | ||||
| 	} | ||||
| 	return std::vector<int>(); | ||||
| } | ||||
|  | ||||
| CGMarket::CGMarket() | ||||
| @@ -290,22 +254,26 @@ void CGBlackMarket::newTurn(CRandomGenerator & rand) const | ||||
|  | ||||
| void CGUniversity::initObj(CRandomGenerator & rand) | ||||
| { | ||||
| 	CGMarket::initObj(rand); | ||||
| 	 | ||||
| 	std::vector<int> toChoose; | ||||
| 	int skillsNeeded = skillsTotal - skills.size(); | ||||
| 	for(int i = 0; i < VLC->skillh->size(); ++i) | ||||
| 	{ | ||||
| 		if(cb->isAllowed(2, i)) | ||||
| 		if(!vstd::contains(skills, i) && cb->isAllowed(2, i)) | ||||
| 		{ | ||||
| 			toChoose.push_back(i); | ||||
| 		} | ||||
| 	} | ||||
| 	if(toChoose.size() < 4) | ||||
| 	if(toChoose.size() < skillsNeeded) | ||||
| 	{ | ||||
| 		logGlobal->warn("Warning: less then 4 available skills was found by University initializer!"); | ||||
| 		logGlobal->warn("Warning: less then %d available skills was found by University initializer!", skillsTotal); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// get 4 skills | ||||
| 	for(int i = 0; i < 4; ++i) | ||||
| 	// get 4 skills, excluding predefined | ||||
| 	 | ||||
| 	for(int i = 0; i < skillsNeeded; ++i) | ||||
| 	{ | ||||
| 		// move randomly one skill to selected and remove from list | ||||
| 		auto it = RandomGeneratorUtil::nextItem(toChoose, rand); | ||||
| @@ -322,7 +290,7 @@ std::vector<int> CGUniversity::availableItemsIds(EMarketMode::EMarketMode mode) | ||||
| 			return skills; | ||||
|  | ||||
| 		default: | ||||
| 			return std::vector <int> (); | ||||
| 			return std::vector<int>(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -33,9 +33,14 @@ public: | ||||
| class DLL_LINKAGE CGMarket : public CGObjectInstance, public IMarket | ||||
| { | ||||
| public: | ||||
| 	 | ||||
| 	std::set<EMarketMode::EMarketMode> marketModes; | ||||
| 	int marketEfficacy = 5; | ||||
| 	 | ||||
| 	CGMarket(); | ||||
| 	///IObjectIntercae | ||||
| 	///IObjectInterface | ||||
| 	void onHeroVisit(const CGHeroInstance * h) const override; //open trading window | ||||
| 	void initObj(CRandomGenerator & rand) override;//set skills for trade | ||||
|  | ||||
| 	///IMarket | ||||
| 	int getMarketEfficiency() const override; | ||||
| @@ -46,6 +51,8 @@ public: | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<CGObjectInstance&>(*this); | ||||
| 		h & marketModes; | ||||
| 		h & marketEfficacy; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -67,7 +74,12 @@ public: | ||||
| class DLL_LINKAGE CGUniversity : public CGMarket | ||||
| { | ||||
| public: | ||||
| 	int skillsTotal = 4; | ||||
| 	std::vector<int> skills; //available skills | ||||
| 	 | ||||
| 	//window variables | ||||
| 	std::string title; | ||||
| 	std::string speech; | ||||
|  | ||||
| 	std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override; | ||||
| 	void initObj(CRandomGenerator & rand) override;//set skills for trade | ||||
| @@ -77,6 +89,8 @@ public: | ||||
| 	{ | ||||
| 		h & static_cast<CGMarket&>(*this); | ||||
| 		h & skills; | ||||
| 		h & title; | ||||
| 		h & speech; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -40,6 +40,7 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| 	SET_HANDLER_CLASS("town", CTownInstanceConstructor); | ||||
| 	SET_HANDLER_CLASS("bank", CBankInstanceConstructor); | ||||
| 	SET_HANDLER_CLASS("boat", BoatInstanceConstructor); | ||||
| 	SET_HANDLER_CLASS("market", MarketInstanceConstructor); | ||||
|  | ||||
| 	SET_HANDLER_CLASS("static", CObstacleConstructor); | ||||
| 	SET_HANDLER_CLASS("", CObstacleConstructor); | ||||
| @@ -54,7 +55,6 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| 	SET_HANDLER("generic", CGObjectInstance); | ||||
| 	SET_HANDLER("cartographer", CCartographer); | ||||
| 	SET_HANDLER("artifact", CGArtifact); | ||||
| 	SET_HANDLER("blackMarket", CGBlackMarket); | ||||
| 	SET_HANDLER("borderGate", CGBorderGate); | ||||
| 	SET_HANDLER("borderGuard", CGBorderGuard); | ||||
| 	SET_HANDLER("monster", CGCreature); | ||||
| @@ -65,7 +65,6 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| 	SET_HANDLER("keymaster", CGKeymasterTent); | ||||
| 	SET_HANDLER("lighthouse", CGLighthouse); | ||||
| 	SET_HANDLER("magi", CGMagi); | ||||
| 	SET_HANDLER("market", CGMarket); | ||||
| 	SET_HANDLER("mine", CGMine); | ||||
| 	SET_HANDLER("obelisk", CGObelisk); | ||||
| 	SET_HANDLER("observatory", CGObservatory); | ||||
| @@ -82,7 +81,6 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| 	SET_HANDLER("monolith", CGMonolith); | ||||
| 	SET_HANDLER("subterraneanGate", CGSubterraneanGate); | ||||
| 	SET_HANDLER("whirlpool", CGWhirlpool); | ||||
| 	SET_HANDLER("university", CGUniversity); | ||||
| 	SET_HANDLER("witch", CGWitchHut); | ||||
| 	SET_HANDLER("terrain", CGTerrainPatch); | ||||
|  | ||||
|   | ||||
| @@ -291,6 +291,66 @@ void BoatInstanceConstructor::configureObject(CGObjectInstance * object, CRandom | ||||
|  | ||||
| } | ||||
|  | ||||
| void MarketInstanceConstructor::initTypeData(const JsonNode & input) | ||||
| { | ||||
| 	for(auto & element : input["modes"].Vector()) | ||||
| 	{ | ||||
| 		if(MappedKeys::MARKET_NAMES_TO_TYPES.count(element.String())) | ||||
| 			marketModes.insert(MappedKeys::MARKET_NAMES_TO_TYPES.at(element.String())); | ||||
| 	} | ||||
| 	 | ||||
| 	marketEfficacy = input["efficacy"].isNull() ? -1 : input["efficacy"].Integer(); | ||||
| 	predefinedOffer = input["offer"]; | ||||
| 	 | ||||
| 	title = input["title"].String(); | ||||
| 	speech = input["speech"].String(); | ||||
| } | ||||
|  | ||||
| CGObjectInstance * MarketInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	CGMarket * market = nullptr; | ||||
| 	if(marketModes.size() == 1) | ||||
| 	{ | ||||
| 		switch(*marketModes.begin()) | ||||
| 		{ | ||||
| 			case EMarketMode::ARTIFACT_RESOURCE: | ||||
| 			case EMarketMode::RESOURCE_ARTIFACT: | ||||
| 				market = new CGBlackMarket; | ||||
| 				break; | ||||
| 				 | ||||
| 			case EMarketMode::RESOURCE_SKILL: | ||||
| 				market = new CGUniversity; | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	if(!market) | ||||
| 		market = new CGMarket; | ||||
| 	 | ||||
| 	preInitObject(market); | ||||
|  | ||||
| 	if(tmpl) | ||||
| 		market->appearance = tmpl; | ||||
| 	market->marketModes = marketModes; | ||||
| 	if(marketEfficacy >= 0) | ||||
| 		market->marketEfficacy = marketEfficacy; | ||||
| 	 | ||||
| 	return market; | ||||
| } | ||||
|  | ||||
| void MarketInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const | ||||
| { | ||||
| 	if(auto * university = dynamic_cast<CGUniversity *>(object)) | ||||
| 	{ | ||||
| 		for(auto skill : JsonRandom::loadSecondary(predefinedOffer, rng)) | ||||
| 			university->skills.push_back(skill.first.getNum()); | ||||
| 		 | ||||
| 		university->title = VLC->generaltexth->translate(title); | ||||
| 		university->speech = VLC->generaltexth->translate(speech); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| bool CBankInstanceConstructor::hasNameTextID() const | ||||
| { | ||||
| 	return true; | ||||
|   | ||||
| @@ -255,4 +255,27 @@ public: | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class MarketInstanceConstructor : public CDefaultObjectTypeHandler<CGMarket> | ||||
| { | ||||
| protected: | ||||
| 	void initTypeData(const JsonNode & config) override; | ||||
| 	 | ||||
| 	std::set<EMarketMode::EMarketMode> marketModes; | ||||
| 	JsonNode predefinedOffer; | ||||
| 	int marketEfficacy; | ||||
| 	 | ||||
| 	std::string title, speech; | ||||
| 	 | ||||
| public: | ||||
| 	CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override; | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<CDefaultObjectTypeHandler<CGMarket>&>(*this); | ||||
| 		h & marketModes; | ||||
| 		h & marketEfficacy; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
|   | ||||
| @@ -89,12 +89,12 @@ void registerTypesMapObjectTypes(Serializer &s) | ||||
| 	s.template registerType<AObjectTypeHandler, CDwellingInstanceConstructor>(); | ||||
| 	s.template registerType<AObjectTypeHandler, CBankInstanceConstructor>(); | ||||
| 	s.template registerType<AObjectTypeHandler, BoatInstanceConstructor>(); | ||||
| 	s.template registerType<AObjectTypeHandler, MarketInstanceConstructor>(); | ||||
| 	s.template registerType<AObjectTypeHandler, CObstacleConstructor>(); | ||||
|  | ||||
| #define REGISTER_GENERIC_HANDLER(TYPENAME) s.template registerType<AObjectTypeHandler, CDefaultObjectTypeHandler<TYPENAME> >() | ||||
|  | ||||
| 	REGISTER_GENERIC_HANDLER(CGObjectInstance); | ||||
| 	REGISTER_GENERIC_HANDLER(CGMarket); | ||||
| 	REGISTER_GENERIC_HANDLER(CCartographer); | ||||
| 	REGISTER_GENERIC_HANDLER(CGArtifact); | ||||
| 	REGISTER_GENERIC_HANDLER(CGBlackMarket); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user