mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Vlc obstacles [part 1] (#888)
* obstacles content handler, entity service and VLC integration
This commit is contained in:
		| @@ -38,6 +38,7 @@ void CGameInfo::setFromLib() | ||||
| 	skillh = VLC->skillh; | ||||
| 	objtypeh = VLC->objtypeh; | ||||
| 	battleFieldHandler = VLC->battlefieldsHandler; | ||||
| 	obstacleHandler = VLC->obstacleHandler; | ||||
| } | ||||
|  | ||||
| const ArtifactService * CGameInfo::artifacts() const | ||||
| @@ -85,6 +86,11 @@ const SkillService * CGameInfo::skills() const | ||||
| 	return globalServices->skills(); | ||||
| } | ||||
|  | ||||
| const ObstacleService * CGameInfo::obstacles() const | ||||
| { | ||||
| 	return globalServices->obstacles(); | ||||
| } | ||||
|  | ||||
| void CGameInfo::updateEntity(Metatype metatype, int32_t index, const JsonNode & data) | ||||
| { | ||||
| 	logGlobal->error("CGameInfo::updateEntity call is not expected."); | ||||
|   | ||||
| @@ -32,6 +32,7 @@ class CGameState; | ||||
| class IMainVideoPlayer; | ||||
| class CServerHandler; | ||||
| class BattleFieldHandler; | ||||
| class ObstacleHandler; | ||||
|  | ||||
| class CMap; | ||||
|  | ||||
| @@ -62,6 +63,7 @@ public: | ||||
| 	const spells::Service * spells() const override; | ||||
| 	const SkillService * skills() const override; | ||||
| 	const BattleFieldService * battlefields() const override; | ||||
| 	const ObstacleService * obstacles() const override; | ||||
|  | ||||
| 	void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override; | ||||
|  | ||||
| @@ -77,6 +79,7 @@ public: | ||||
| 	ConstTransitivePtr<CSkillHandler> skillh; | ||||
| 	ConstTransitivePtr<CObjectHandler> objh; | ||||
| 	ConstTransitivePtr<CObjectClassesHandler> objtypeh; | ||||
| 	ConstTransitivePtr<ObstacleHandler> obstacleHandler; | ||||
| 	CGeneralTextHandler * generaltexth; | ||||
| 	CMapHandler * mh; | ||||
| 	CTownHandler * townh; | ||||
|   | ||||
| @@ -42,6 +42,7 @@ | ||||
| #include "../../lib/spells/Problem.h" | ||||
| #include "../../lib/CTownHandler.h" | ||||
| #include "../../lib/BattleFieldHandler.h" | ||||
| #include "../../lib/ObstacleHandler.h" | ||||
| #include "../../lib/CGameState.h" | ||||
| #include "../../lib/mapping/CMap.h" | ||||
| #include "../../lib/NetPacks.h" | ||||
| @@ -361,7 +362,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet | ||||
| 	{ | ||||
| 		if(elem->obstacleType == CObstacleInstance::USUAL) | ||||
| 		{ | ||||
| 			std::string animationName = elem->getInfo().defName; | ||||
| 			std::string animationName = elem->getInfo().animation; | ||||
|  | ||||
| 			auto cached = animationsCache.find(animationName); | ||||
|  | ||||
| @@ -379,7 +380,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet | ||||
| 		} | ||||
| 		else if (elem->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE) | ||||
| 		{ | ||||
| 			std::string animationName = elem->getInfo().defName; | ||||
| 			std::string animationName = elem->getInfo().animation; | ||||
|  | ||||
| 			auto cached = animationsCache.find(animationName); | ||||
|  | ||||
|   | ||||
| @@ -88,5 +88,9 @@ | ||||
| 	"battlefields": | ||||
| 	[ | ||||
| 		"config/battlefields.json" | ||||
| 	], | ||||
| 	"obstacles": | ||||
| 	[ | ||||
| 		"config/obstacles.json" | ||||
| 	] | ||||
| } | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -2,7 +2,7 @@ | ||||
| 	"type":"object", | ||||
| 	"$schema": "http://json-schema.org/draft-04/schema", | ||||
| 	"title" : "VCMI battlefield format", | ||||
| 	"description" : "Format used to define new artifacts in VCMI", | ||||
| 	"description" : "Format used to define new battlefields in VCMI", | ||||
| 	"required" : [ "graphics" ], | ||||
|  | ||||
| 	"additionalProperties" : false, | ||||
|   | ||||
							
								
								
									
										46
									
								
								config/schemas/obstacle.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								config/schemas/obstacle.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| { | ||||
| 	"type":"object", | ||||
| 	"$schema": "http://json-schema.org/draft-04/schema", | ||||
| 	"title" : "VCMI obstacle format", | ||||
| 	"description" : "Format used to define new obstacles in VCMI", | ||||
| 	"required" : [ "animation" ], | ||||
|  | ||||
| 	"additionalProperties" : false, | ||||
| 	"properties":{ | ||||
| 		"allowedTerrains": { | ||||
| 			"type": "array", | ||||
| 			"description": "Obstacles can be place on specified terrains only", | ||||
| 			"items": { "type" : "string" } | ||||
| 		}, | ||||
| 		"specialBattlefields": { | ||||
| 			"type": "array", | ||||
| 			"description": "Obstacles can be placed on specified specified battlefields", | ||||
| 			"items": { "$ref" : "battlefield.json" } | ||||
| 		}, | ||||
| 		"width": { | ||||
| 			"type": "number", | ||||
| 			"description": "Width ob obstacle" | ||||
| 		}, | ||||
| 		"height": { | ||||
| 			"type": "number", | ||||
| 			"description": "height if obstacle" | ||||
| 		}, | ||||
| 		"blockedTiles": { | ||||
| 			"type": "array", | ||||
| 			"description": "Blocked hexes - absolute or relative hex id", | ||||
| 			"items": { "type" : "number" } | ||||
| 		}, | ||||
| 		"animation": { | ||||
| 			"type": "string", | ||||
| 			"description": "Image resource" | ||||
| 		}, | ||||
| 		"unknown": { | ||||
| 			"type": "number", | ||||
| 			"description": "Unknown field" | ||||
| 		}, | ||||
| 		"absolute": { | ||||
| 			"type": "boolean", | ||||
| 			"description": "Should be used absolute or relative coordinates for obstacle. There is possible only one absolute obstacle" | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -20,6 +20,7 @@ class HeroTypeService; | ||||
| class SkillService; | ||||
| class JsonNode; | ||||
| class BattleFieldService; | ||||
| class ObstacleService; | ||||
|  | ||||
| namespace spells | ||||
| { | ||||
| @@ -50,6 +51,7 @@ public: | ||||
| 	virtual const spells::Service * spells() const = 0; | ||||
| 	virtual const SkillService * skills() const = 0; | ||||
| 	virtual const BattleFieldService * battlefields() const = 0; | ||||
| 	virtual const ObstacleService * obstacles() const = 0; | ||||
|  | ||||
| 	virtual void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) = 0; | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * BattleFieldHandler.h, part of VCMI engine | ||||
|  * BattleFieldHandler.cpp, part of VCMI engine | ||||
|  * | ||||
|  * Authors: listed in file AUTHORS in main folder | ||||
|  * | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <vcmi/EntityService.h> | ||||
| #include <vcmi/Entity.h> | ||||
| #include "HeroBonus.h" | ||||
| #include "GameConstants.h" | ||||
| #include "IHandlerBase.h" | ||||
|   | ||||
| @@ -153,41 +153,6 @@ CHeroClass::CHeroClass() | ||||
| { | ||||
| } | ||||
|  | ||||
| std::vector<BattleHex> CObstacleInfo::getBlocked(BattleHex hex) const | ||||
| { | ||||
| 	std::vector<BattleHex> ret; | ||||
| 	if(isAbsoluteObstacle) | ||||
| 	{ | ||||
| 		assert(!hex.isValid()); | ||||
| 		range::copy(blockedTiles, std::back_inserter(ret)); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	for(int offset : blockedTiles) | ||||
| 	{ | ||||
| 		BattleHex toBlock = hex + offset; | ||||
| 		if((hex.getY() & 1) && !(toBlock.getY() & 1)) | ||||
| 			toBlock += BattleHex::LEFT; | ||||
|  | ||||
| 		if(!toBlock.isValid()) | ||||
| 			logGlobal->error("Misplaced obstacle!"); | ||||
| 		else | ||||
| 			ret.push_back(toBlock); | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| bool CObstacleInfo::isAppropriate(const Terrain & terrainType, const BattleField & battlefield) const | ||||
| { | ||||
| 	auto bgInfo = battlefield.getInfo(); | ||||
|  | ||||
| 	if(bgInfo->isSpecial) | ||||
| 		return vstd::contains(allowedSpecialBfields, bgInfo->identifier); | ||||
|  | ||||
| 	return vstd::contains(allowedTerrains, terrainType); | ||||
| } | ||||
|  | ||||
| void CHeroClassHandler::fillPrimarySkillData(const JsonNode & node, CHeroClass * heroClass, PrimarySkill::PrimarySkill pSkill) | ||||
| { | ||||
| 	const auto & skillName = PrimarySkill::names[pSkill]; | ||||
| @@ -378,7 +343,6 @@ CHeroHandler::~CHeroHandler() = default; | ||||
|  | ||||
| CHeroHandler::CHeroHandler() | ||||
| { | ||||
| 	loadObstacles(); | ||||
| 	loadTerrains(); | ||||
| 	for(int i = 0; i < Terrain::Manager::terrains().size(); ++i) | ||||
| 	{ | ||||
| @@ -818,51 +782,6 @@ void CHeroHandler::loadExperience() | ||||
| 	expPerLevel.pop_back();//last value is broken | ||||
| } | ||||
|  | ||||
| void CHeroHandler::loadObstacles() | ||||
| { | ||||
| 	auto loadObstacles = [](const JsonNode & node, bool absolute, std::vector<CObstacleInfo> & out) | ||||
| 	{ | ||||
| 		for(const JsonNode &obs : node.Vector()) | ||||
| 		{ | ||||
| 			out.emplace_back(); | ||||
| 			CObstacleInfo & obi = out.back(); | ||||
| 			obi.defName = obs["defname"].String(); | ||||
| 			obi.width =  static_cast<si32>(obs["width"].Float()); | ||||
| 			obi.height = static_cast<si32>(obs["height"].Float()); | ||||
| 			for(auto & t : obs["allowedTerrain"].Vector()) | ||||
| 				obi.allowedTerrains.emplace_back(t.String()); | ||||
| 			for(auto & t : obs["specialBattlefields"].Vector()) | ||||
| 				obi.allowedSpecialBfields.emplace_back(t.String()); | ||||
| 			obi.blockedTiles = obs["blockedTiles"].convertTo<std::vector<si16> >(); | ||||
| 			obi.isAbsoluteObstacle = absolute; | ||||
| 		} | ||||
| 	}; | ||||
| 	 | ||||
| 	auto allConfigs = VLC->modh->getActiveMods(); | ||||
| 	allConfigs.insert(allConfigs.begin(), "core"); | ||||
| 	for(auto & mod : allConfigs) | ||||
| 	{ | ||||
| 		ISimpleResourceLoader * modResourceLoader; | ||||
| 		try | ||||
| 		{ | ||||
| 			modResourceLoader = CResourceHandler::get(mod); | ||||
| 		} | ||||
| 		catch(const std::out_of_range &) | ||||
| 		{ | ||||
| 			logMod->warn("Mod '%1%' doesn't exist! Its obstacles won't be loaded!", mod); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		const ResourceID obstaclesResource{"config/obstacles.json"}; | ||||
| 		if(!modResourceLoader->existsResource(obstaclesResource)) | ||||
| 			continue; | ||||
| 		 | ||||
| 		const JsonNode config(mod, obstaclesResource); | ||||
| 		loadObstacles(config["obstacles"], false, obstacles); | ||||
| 		loadObstacles(config["absoluteObstacles"], true, absoluteObstacles); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /// convert h3-style ID (e.g. Gobin Wolf Rider) to vcmi (e.g. goblinWolfRider) | ||||
| static std::string genRefName(std::string input) | ||||
| { | ||||
|   | ||||
| @@ -223,32 +223,6 @@ public: | ||||
| 	EAlignment::EAlignment getAlignment() const; | ||||
| }; | ||||
|  | ||||
| struct DLL_LINKAGE CObstacleInfo | ||||
| { | ||||
| 	std::string defName; | ||||
| 	std::vector<Terrain> allowedTerrains; | ||||
| 	std::vector<std::string> allowedSpecialBfields; | ||||
|  | ||||
| 	ui8 isAbsoluteObstacle; //there may only one such obstacle in battle and its position is always the same | ||||
| 	si32 width, height; //how much space to the right and up is needed to place obstacle (affects only placement algorithm) | ||||
| 	std::vector<si16> blockedTiles; //offsets relative to obstacle position (that is its left bottom corner) | ||||
|  | ||||
| 	std::vector<BattleHex> getBlocked(BattleHex hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex' | ||||
|  | ||||
| 	bool isAppropriate(const Terrain & terrainType, const BattleField & specialBattlefield) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & defName; | ||||
| 		h & allowedTerrains; | ||||
| 		h & allowedSpecialBfields; | ||||
| 		h & isAbsoluteObstacle; | ||||
| 		h & width; | ||||
| 		h & height; | ||||
| 		h & blockedTiles; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CHeroClassHandler : public CHandlerBase<HeroClassID, HeroClass, CHeroClass, HeroClassService> | ||||
| { | ||||
| 	void fillPrimarySkillData(const JsonNode & node, CHeroClass * heroClass, PrimarySkill::PrimarySkill pSkill); | ||||
| @@ -286,7 +260,6 @@ class DLL_LINKAGE CHeroHandler : public CHandlerBase<HeroTypeID, HeroType, CHero | ||||
| 	void loadExperience(); | ||||
| 	void loadBallistics(); | ||||
| 	void loadTerrains(); | ||||
| 	void loadObstacles(); | ||||
|  | ||||
| public: | ||||
| 	CHeroClassHandler classes; | ||||
| @@ -315,9 +288,6 @@ public: | ||||
| 	}; | ||||
| 	std::vector<SBallisticsLevelInfo> ballistics; //info about ballistics ability per level; [0] - none; [1] - basic; [2] - adv; [3] - expert | ||||
|  | ||||
| 	std::vector<CObstacleInfo> obstacles; //info about obstacles that may be placed on battlefield | ||||
| 	std::vector<CObstacleInfo> absoluteObstacles; //info about obstacles that may be placed on battlefield | ||||
|  | ||||
| 	ui32 level(ui64 experience) const; //calculates level corresponding to given experience amount | ||||
| 	ui64 reqExp(ui32 level) const; //calculates experience required for given level | ||||
|  | ||||
| @@ -340,8 +310,6 @@ public: | ||||
| 		h & expPerLevel; | ||||
| 		h & ballistics; | ||||
| 		h & terrCosts; | ||||
| 		h & obstacles; | ||||
| 		h & absoluteObstacles; | ||||
| 	} | ||||
|  | ||||
| protected: | ||||
|   | ||||
| @@ -179,6 +179,7 @@ set(lib_SRCS | ||||
| 		JsonNode.cpp | ||||
| 		LogicalExpression.cpp | ||||
| 		NetPacksLib.cpp | ||||
| 		ObstacleHandler.cpp | ||||
| 		StartInfo.cpp | ||||
| 		ResourceSet.cpp | ||||
| 		ScriptHandler.cpp | ||||
| @@ -418,6 +419,7 @@ set(lib_HEADERS | ||||
| 		NetPacksBase.h | ||||
| 		NetPacks.h | ||||
| 		NetPacksLobby.h | ||||
| 		ObstacleHandler.h | ||||
| 		PathfinderUtil.h | ||||
| 		ResourceSet.h | ||||
| 		ScriptHandler.h | ||||
|   | ||||
| @@ -26,6 +26,7 @@ | ||||
| #include "CSkillHandler.h" | ||||
| #include "ScriptHandler.h" | ||||
| #include "BattleFieldHandler.h" | ||||
| #include "ObstacleHandler.h" | ||||
|  | ||||
| #include <vstd/StringUtils.h> | ||||
|  | ||||
| @@ -435,6 +436,7 @@ void CContentHandler::init() | ||||
| 	handlers.insert(std::make_pair("templates", ContentTypeHandler((IHandlerBase *)VLC->tplh, "template"))); | ||||
| 	handlers.insert(std::make_pair("scripts", ContentTypeHandler(VLC->scriptHandler, "script"))); | ||||
| 	handlers.insert(std::make_pair("battlefields", ContentTypeHandler(VLC->battlefieldsHandler, "battlefield"))); | ||||
| 	handlers.insert(std::make_pair("obstacles", ContentTypeHandler(VLC->obstacleHandler, "obstacle"))); | ||||
| 	//TODO: any other types of moddables? | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -35,6 +35,7 @@ | ||||
| #include "CGeneralTextHandler.h" | ||||
| #include "CModHandler.h"//todo: remove | ||||
| #include "BattleFieldHandler.h" | ||||
| #include "ObstacleHandler.h" | ||||
|  | ||||
| const SlotID SlotID::COMMANDER_SLOT_PLACEHOLDER = SlotID(-2); | ||||
| const SlotID SlotID::SUMMONED_SLOT_PLACEHOLDER = SlotID(-3); | ||||
| @@ -292,4 +293,24 @@ BattleField BattleField::fromString(std::string identifier) | ||||
| 		return BattleField(rawId.get()); | ||||
| 	else | ||||
| 		return BattleField::NONE; | ||||
| } | ||||
| } | ||||
| 		 | ||||
| const ObstacleInfo * Obstacle::getInfo() const | ||||
| { | ||||
| 	return VLC->obstacles()->getById(*this); | ||||
| } | ||||
|  | ||||
| Obstacle::operator std::string() const | ||||
| { | ||||
| 	return getInfo()->identifier; | ||||
| } | ||||
|  | ||||
| Obstacle Obstacle::fromString(std::string identifier) | ||||
| { | ||||
| 	auto rawId = VLC->modh->identifiers.getIdentifier("core", "obstacle", identifier); | ||||
|  | ||||
| 	if(rawId) | ||||
| 		return Obstacle(rawId.get()); | ||||
| 	else | ||||
| 		return Obstacle(-1); | ||||
| } | ||||
|   | ||||
| @@ -1125,6 +1125,16 @@ class BattleField : public BaseForID<BattleField, si32> | ||||
|  | ||||
| 	DLL_LINKAGE static BattleField fromString(std::string identifier); | ||||
| }; | ||||
| 	 | ||||
| class ObstacleInfo; | ||||
| class Obstacle : public BaseForID<Obstacle, si32> | ||||
| { | ||||
| 	INSTID_LIKE_CLASS_COMMON(Obstacle, si32) | ||||
| 	 | ||||
| 	DLL_LINKAGE const ObstacleInfo * getInfo() const; | ||||
| 	DLL_LINKAGE operator std::string() const; | ||||
| 	DLL_LINKAGE static Obstacle fromString(std::string identifier); | ||||
| }; | ||||
|  | ||||
| enum class ESpellSchool: ui8 | ||||
| { | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
| #include "CBonusTypeHandler.h" | ||||
| #include "CModHandler.h" | ||||
| #include "BattleFieldHandler.h" | ||||
| #include "ObstacleHandler.h" | ||||
|  | ||||
| #include "serializer/CSerializer.h" // for SAVEGAME_MAGIC | ||||
| #include "serializer/BinaryDeserializer.h" | ||||
|   | ||||
							
								
								
									
										112
									
								
								lib/ObstacleHandler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								lib/ObstacleHandler.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| /* | ||||
|  * ObstacleHandler.cpp, part of VCMI engine | ||||
|  * | ||||
|  * 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 "ObstacleHandler.h" | ||||
| #include "BattleFieldHandler.h" | ||||
|  | ||||
| int32_t ObstacleInfo::getIndex() const | ||||
| { | ||||
| 	return obstacle.getNum(); | ||||
| } | ||||
|  | ||||
| int32_t ObstacleInfo::getIconIndex() const | ||||
| { | ||||
| 	return iconIndex; | ||||
| } | ||||
|  | ||||
| const std::string & ObstacleInfo::getName() const | ||||
| { | ||||
| 	return identifier; | ||||
| } | ||||
|  | ||||
| const std::string & ObstacleInfo::getJsonKey() const | ||||
| { | ||||
| 	return identifier; | ||||
| } | ||||
|  | ||||
| void ObstacleInfo::registerIcons(const IconRegistar & cb) const | ||||
| { | ||||
| } | ||||
|  | ||||
| Obstacle ObstacleInfo::getId() const | ||||
| { | ||||
| 	return obstacle; | ||||
| } | ||||
|  | ||||
|  | ||||
| std::vector<BattleHex> ObstacleInfo::getBlocked(BattleHex hex) const | ||||
| { | ||||
| 	std::vector<BattleHex> ret; | ||||
| 	if(isAbsoluteObstacle) | ||||
| 	{ | ||||
| 		assert(!hex.isValid()); | ||||
| 		range::copy(blockedTiles, std::back_inserter(ret)); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	 | ||||
| 	for(int offset : blockedTiles) | ||||
| 	{ | ||||
| 		BattleHex toBlock = hex + offset; | ||||
| 		if((hex.getY() & 1) && !(toBlock.getY() & 1)) | ||||
| 			toBlock += BattleHex::LEFT; | ||||
| 		 | ||||
| 		if(!toBlock.isValid()) | ||||
| 			logGlobal->error("Misplaced obstacle!"); | ||||
| 		else | ||||
| 			ret.push_back(toBlock); | ||||
| 	} | ||||
| 	 | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| bool ObstacleInfo::isAppropriate(const Terrain & terrainType, const BattleField & battlefield) const | ||||
| { | ||||
| 	auto bgInfo = battlefield.getInfo(); | ||||
| 	 | ||||
| 	if(bgInfo->isSpecial) | ||||
| 		return vstd::contains(allowedSpecialBfields, bgInfo->identifier); | ||||
| 	 | ||||
| 	return vstd::contains(allowedTerrains, terrainType); | ||||
| } | ||||
|  | ||||
| ObstacleInfo * ObstacleHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index) | ||||
| { | ||||
| 	auto * info = new ObstacleInfo(Obstacle(index), identifier); | ||||
| 	 | ||||
| 	info->animation = json["animation"].String(); | ||||
| 	info->width = json["width"].Integer(); | ||||
| 	info->height = json["height"].Integer(); | ||||
| 	for(auto & t : json["allowedTerrain"].Vector()) | ||||
| 		info->allowedTerrains.emplace_back(t.String()); | ||||
| 	for(auto & t : json["specialBattlefields"].Vector()) | ||||
| 		info->allowedSpecialBfields.emplace_back(t.String()); | ||||
| 	info->blockedTiles = json["blockedTiles"].convertTo<std::vector<si16>>(); | ||||
| 	info->isAbsoluteObstacle = json["absolute"].Bool(); | ||||
| 	 | ||||
| 	objects.push_back(info); | ||||
| 	 | ||||
| 	return info; | ||||
| } | ||||
|  | ||||
| std::vector<JsonNode> ObstacleHandler::loadLegacyData(size_t dataSize) | ||||
| { | ||||
| 	return {}; | ||||
| } | ||||
|  | ||||
| std::vector<bool> ObstacleHandler::getDefaultAllowed() const | ||||
| { | ||||
| 	return {}; | ||||
| } | ||||
|  | ||||
| const std::vector<std::string> & ObstacleHandler::getTypeNames() const | ||||
| { | ||||
| 	static const std::vector<std::string> types = { "obstacle" }; | ||||
| 	return types; | ||||
| } | ||||
							
								
								
									
										94
									
								
								lib/ObstacleHandler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								lib/ObstacleHandler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| /* | ||||
|  * ObstacleHandler.h, part of VCMI engine | ||||
|  * | ||||
|  * 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 | ||||
|  * | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #include <vcmi/EntityService.h> | ||||
| #include <vcmi/Entity.h> | ||||
| #include "GameConstants.h" | ||||
| #include "IHandlerBase.h" | ||||
| #include "Terrain.h" | ||||
| #include "battle/BattleHex.h" | ||||
|  | ||||
| class DLL_LINKAGE ObstacleInfo : public EntityT<Obstacle> | ||||
| { | ||||
| public: | ||||
| 	ObstacleInfo(): obstacle(-1), width(0), height(0), isAbsoluteObstacle(false), iconIndex(0) | ||||
| 	{} | ||||
| 	 | ||||
| 	ObstacleInfo(Obstacle obstacle, std::string identifier) | ||||
| 	: obstacle(obstacle), identifier(identifier), iconIndex(obstacle.getNum()), width(0), height(0), isAbsoluteObstacle(false) | ||||
| 	{ | ||||
| 	} | ||||
| 	 | ||||
| 	Obstacle obstacle; | ||||
| 	si32 iconIndex; | ||||
| 	std::string identifier; | ||||
| 	std::string appearAnimation, animation, dissapearAnimation; | ||||
| 	std::vector<Terrain> allowedTerrains; | ||||
| 	std::vector<std::string> allowedSpecialBfields; | ||||
| 	 | ||||
| 	//TODO: here is extra field to implement it's logic in the future but save backward compatibility | ||||
| 	int obstacleType = -1; | ||||
| 	 | ||||
| 	ui8 isAbsoluteObstacle; //there may only one such obstacle in battle and its position is always the same | ||||
| 	si32 width, height; //how much space to the right and up is needed to place obstacle (affects only placement algorithm) | ||||
| 	std::vector<si16> blockedTiles; //offsets relative to obstacle position (that is its left bottom corner) | ||||
| 	 | ||||
| 	int32_t getIndex() const override; | ||||
| 	int32_t getIconIndex() const override; | ||||
| 	const std::string & getJsonKey() const override; | ||||
| 	const std::string & getName() const override; | ||||
| 	void registerIcons(const IconRegistar & cb) const override; | ||||
| 	Obstacle getId() const override; | ||||
| 	 | ||||
| 	std::vector<BattleHex> getBlocked(BattleHex hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex' | ||||
| 	 | ||||
| 	bool isAppropriate(const Terrain & terrainType, const BattleField & specialBattlefield) const; | ||||
| 	 | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & obstacle; | ||||
| 		h & obstacleType; | ||||
| 		h & iconIndex; | ||||
| 		h & identifier; | ||||
| 		h & animation; | ||||
| 		h & appearAnimation; | ||||
| 		h & dissapearAnimation; | ||||
| 		h & allowedTerrains; | ||||
| 		h & allowedSpecialBfields; | ||||
| 		h & isAbsoluteObstacle; | ||||
| 		h & width; | ||||
| 		h & height; | ||||
| 		h & blockedTiles; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE ObstacleService : public EntityServiceT<Obstacle, ObstacleInfo> | ||||
| { | ||||
| public: | ||||
| }; | ||||
|  | ||||
| class ObstacleHandler: public CHandlerBase<Obstacle, ObstacleInfo, ObstacleInfo, ObstacleService> | ||||
| { | ||||
| public:	 | ||||
| 	ObstacleInfo * loadFromJson(const std::string & scope, | ||||
| 										const JsonNode & json, | ||||
| 										const std::string & identifier, | ||||
| 										size_t index) override; | ||||
| 	 | ||||
| 	const std::vector<std::string> & getTypeNames() const override; | ||||
| 	std::vector<JsonNode> loadLegacyData(size_t dataSize) override; | ||||
| 	std::vector<bool> getDefaultAllowed() const override; | ||||
| 	 | ||||
| 	template <typename Handler> void serialize(Handler & h, const int version) | ||||
| 	{ | ||||
| 		h & objects; | ||||
| 	} | ||||
| }; | ||||
| @@ -33,6 +33,7 @@ | ||||
| #include "mapping/CMapEditManager.h" | ||||
| #include "ScriptHandler.h" | ||||
| #include "BattleFieldHandler.h" | ||||
| #include "ObstacleHandler.h" | ||||
|  | ||||
| LibClasses * VLC = nullptr; | ||||
|  | ||||
| @@ -116,6 +117,11 @@ const BattleFieldService * LibClasses::battlefields() const | ||||
| 	return battlefieldsHandler; | ||||
| } | ||||
|  | ||||
| const ObstacleService * LibClasses::obstacles() const | ||||
| { | ||||
| 	return obstacleHandler; | ||||
| } | ||||
|  | ||||
| void LibClasses::updateEntity(Metatype metatype, int32_t index, const JsonNode & data) | ||||
| { | ||||
| 	switch(metatype) | ||||
| @@ -212,6 +218,8 @@ void LibClasses::init(bool onlyEssential) | ||||
| 	createHandler(scriptHandler, "Script", pomtime); | ||||
|  | ||||
| 	createHandler(battlefieldsHandler, "Battlefields", pomtime); | ||||
| 	 | ||||
| 	createHandler(obstacleHandler, "Obstacles", pomtime); | ||||
|  | ||||
| 	logGlobal->info("\tInitializing handlers: %d ms", totalTime.getDiff()); | ||||
|  | ||||
|   | ||||
| @@ -27,6 +27,7 @@ class CContentHandler; | ||||
| class BattleFieldHandler; | ||||
| class IBonusTypeHandler; | ||||
| class CBonusTypeHandler; | ||||
| class ObstacleHandler; | ||||
| class CTerrainViewPatternConfig; | ||||
| class CRmgTemplateStorage; | ||||
| class IHandlerBase; | ||||
| @@ -58,6 +59,7 @@ public: | ||||
| 	const spells::Service * spells() const override; | ||||
| 	const SkillService * skills() const override; | ||||
| 	const BattleFieldService * battlefields() const override; | ||||
| 	const ObstacleService * obstacles() const override; | ||||
|  | ||||
| 	void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override; | ||||
|  | ||||
| @@ -79,6 +81,7 @@ public: | ||||
| 	CTerrainViewPatternConfig * terviewh; | ||||
| 	CRmgTemplateStorage * tplh; | ||||
| 	BattleFieldHandler * battlefieldsHandler; | ||||
| 	ObstacleHandler * obstacleHandler; | ||||
| 	scripting::ScriptHandler * scriptHandler; | ||||
|  | ||||
| 	LibClasses(); //c-tor, loads .lods and NULLs handlers | ||||
| @@ -108,6 +111,7 @@ public: | ||||
| 		h & spellh; | ||||
| 		h & skillh; | ||||
| 		h & battlefieldsHandler; | ||||
| 		h & obstacleHandler; | ||||
|  | ||||
| 		if(!h.saving) | ||||
| 		{ | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
| #include "../CGeneralTextHandler.h" | ||||
| #include "../Terrain.h" | ||||
| #include "../BattleFieldHandler.h" | ||||
| #include "../ObstacleHandler.h" | ||||
|  | ||||
| //TODO: remove | ||||
| #include "../IGameCallback.h" | ||||
| @@ -240,9 +241,6 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, const Terrain & terrain, | ||||
| 	//randomize obstacles | ||||
|  	if (town == nullptr && !creatureBank) //do it only when it's not siege and not creature bank | ||||
|  	{ | ||||
| 		const int ABSOLUTE_OBSTACLES_COUNT = VLC->heroh->absoluteObstacles.size(); | ||||
| 		const int USUAL_OBSTACLES_COUNT = VLC->heroh->obstacles.size(); //shouldn't be changes if we want H3-like obstacle placement | ||||
|  | ||||
| 		RandGen r; | ||||
| 		auto ourRand = [&](){ return r.rand(); }; | ||||
| 		r.srand(tile); | ||||
| @@ -253,17 +251,19 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, const Terrain & terrain, | ||||
|  | ||||
| 		auto appropriateAbsoluteObstacle = [&](int id) | ||||
| 		{ | ||||
| 			return VLC->heroh->absoluteObstacles[id].isAppropriate(curB->terrainType, battlefieldType); | ||||
| 			auto * info = Obstacle(id).getInfo(); | ||||
| 			return info && info->isAbsoluteObstacle && info->isAppropriate(curB->terrainType, battlefieldType); | ||||
| 		}; | ||||
| 		auto appropriateUsualObstacle = [&](int id) -> bool | ||||
| 		auto appropriateUsualObstacle = [&](int id) | ||||
| 		{ | ||||
| 			return VLC->heroh->obstacles[id].isAppropriate(curB->terrainType, battlefieldType); | ||||
| 			auto * info = Obstacle(id).getInfo(); | ||||
| 			return info && !info->isAbsoluteObstacle && info->isAppropriate(curB->terrainType, battlefieldType); | ||||
| 		}; | ||||
|  | ||||
| 		RangeGenerator obidgen(0, VLC->obstacleHandler->objects.size() - 1, ourRand); | ||||
| 		 | ||||
| 		if(r.rand(1,100) <= 40) //put cliff-like obstacle | ||||
| 		{ | ||||
| 			RangeGenerator obidgen(0, ABSOLUTE_OBSTACLES_COUNT-1, ourRand); | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| 				auto obstPtr = std::make_shared<CObstacleInstance>(); | ||||
| @@ -274,7 +274,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, const Terrain & terrain, | ||||
|  | ||||
| 				for(BattleHex blocked : obstPtr->getBlockedTiles()) | ||||
| 					blockedTiles.push_back(blocked); | ||||
| 				tilesToBlock -= (int)VLC->heroh->absoluteObstacles[obstPtr->ID].blockedTiles.size() / 2; | ||||
| 				tilesToBlock -= Obstacle(obstPtr->ID).getInfo()->blockedTiles.size() / 2; | ||||
| 			} | ||||
| 			catch(RangeGenerator::ExhaustedPossibilities &) | ||||
| 			{ | ||||
| @@ -283,14 +283,13 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, const Terrain & terrain, | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		RangeGenerator obidgen(0, USUAL_OBSTACLES_COUNT-1, ourRand); | ||||
| 		try | ||||
| 		{ | ||||
| 			while(tilesToBlock > 0) | ||||
| 			{ | ||||
| 				auto tileAccessibility = curB->getAccesibility(); | ||||
| 				const int obid = obidgen.getSuchNumber(appropriateUsualObstacle); | ||||
| 				const CObstacleInfo &obi = VLC->heroh->obstacles[obid]; | ||||
| 				const ObstacleInfo &obi = *Obstacle(obid).getInfo(); | ||||
|  | ||||
| 				auto validPosition = [&](BattleHex pos) -> bool | ||||
| 				{ | ||||
|   | ||||
| @@ -11,6 +11,7 @@ | ||||
| #include "CObstacleInstance.h" | ||||
| #include "../CHeroHandler.h" | ||||
| #include "../CTownHandler.h" | ||||
| #include "../ObstacleHandler.h" | ||||
| #include "../VCMI_Lib.h" | ||||
| #include "../NetPacksBase.h" | ||||
|  | ||||
| @@ -29,17 +30,9 @@ CObstacleInstance::~CObstacleInstance() | ||||
|  | ||||
| } | ||||
|  | ||||
| const CObstacleInfo & CObstacleInstance::getInfo() const | ||||
| const ObstacleInfo & CObstacleInstance::getInfo() const | ||||
| { | ||||
| 	switch(obstacleType) | ||||
| 	{ | ||||
| 	case ABSOLUTE_OBSTACLE: | ||||
| 		return VLC->heroh->absoluteObstacles[ID]; | ||||
| 	case USUAL: | ||||
| 		return VLC->heroh->obstacles[ID]; | ||||
| 	default: | ||||
| 		throw std::runtime_error("Unknown obstacle type in CObstacleInstance::getInfo()"); | ||||
| 	} | ||||
| 	return *Obstacle(ID).getInfo(); | ||||
| } | ||||
|  | ||||
| std::vector<BattleHex> CObstacleInstance::getBlockedTiles() const | ||||
|   | ||||
| @@ -10,7 +10,7 @@ | ||||
| #pragma once | ||||
| #include "BattleHex.h" | ||||
|  | ||||
| struct CObstacleInfo; | ||||
| class ObstacleInfo; | ||||
| class ObstacleChanges; | ||||
| class JsonSerializeFormat; | ||||
|  | ||||
| @@ -30,7 +30,7 @@ struct DLL_LINKAGE CObstacleInstance | ||||
| 	CObstacleInstance(); | ||||
| 	virtual ~CObstacleInstance(); | ||||
|  | ||||
| 	const CObstacleInfo &getInfo() const; //allowed only when not generated by spell (usual or absolute) | ||||
| 	const ObstacleInfo &getInfo() const; //allowed only when not generated by spell (usual or absolute) | ||||
|  | ||||
| 	std::vector<BattleHex> getBlockedTiles() const; | ||||
| 	std::vector<BattleHex> getStoppingTile() const; //hexes that will stop stack move | ||||
|   | ||||
| @@ -25,6 +25,7 @@ public: | ||||
| 	MOCK_CONST_METHOD0(spells, const spells::Service *()); | ||||
| 	MOCK_CONST_METHOD0(skills, const SkillService * ()); | ||||
| 	MOCK_CONST_METHOD0(battlefields, const BattleFieldService *()); | ||||
| 	MOCK_CONST_METHOD0(obstacles, const ObstacleService *()); | ||||
|  | ||||
| 	MOCK_METHOD3(updateEntity, void(Metatype, int32_t, const JsonNode &)); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user