mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Something that compiles, but crashes when launching RMG map.
This commit is contained in:
		| @@ -840,8 +840,8 @@ void CGameState::initNewGame() | ||||
| 		CStopWatch sw; | ||||
|  | ||||
| 		// Gen map | ||||
| 		CMapGenerator mapGenerator; | ||||
| 		map = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed).release(); | ||||
| 		CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, std::time(nullptr)); | ||||
| 		map = mapGenerator.generate(); | ||||
|  | ||||
| 		// Update starting options | ||||
| 		for(int i = 0; i < map->players.size(); ++i) | ||||
|   | ||||
| @@ -194,17 +194,17 @@ void CMapGenOptions::finalize(CRandomGenerator & rand) | ||||
| 		auto possiblePlayers = mapTemplate->getPlayers().getNumbers(); | ||||
| 		possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers())); | ||||
| 		assert(!possiblePlayers.empty()); | ||||
| 		playerCount = *RandomGeneratorUtil::nextItem(possiblePlayers, rand); | ||||
| 		playerCount = *std::next(possiblePlayers.begin(), rand.nextInt(8)); | ||||
| 		updatePlayers(); | ||||
| 	} | ||||
| 	if(teamCount == RANDOM_SIZE) | ||||
| 	{ | ||||
| 		teamCount = rand.nextInt(playerCount - 1); | ||||
| 		teamCount = rand.nextInt(8); | ||||
| 	} | ||||
| 	if(compOnlyPlayerCount == RANDOM_SIZE) | ||||
| 	{ | ||||
| 		auto possiblePlayers = mapTemplate->getCpuPlayers().getNumbers(); | ||||
| 		compOnlyPlayerCount = *RandomGeneratorUtil::nextItem(possiblePlayers, rand); | ||||
| 		compOnlyPlayerCount = *std::next(possiblePlayers.begin(), rand.nextInt(8)); | ||||
| 		updateCompOnlyPlayers(); | ||||
| 	} | ||||
| 	if(compOnlyTeamCount == RANDOM_SIZE) | ||||
| @@ -220,11 +220,11 @@ void CMapGenOptions::finalize(CRandomGenerator & rand) | ||||
|  | ||||
| 	if(waterContent == EWaterContent::RANDOM) | ||||
| 	{ | ||||
| 		waterContent = static_cast<EWaterContent::EWaterContent>(rand.nextInt(2)); | ||||
| 		waterContent = static_cast<EWaterContent::EWaterContent>(rand.nextInt(EWaterContent::TOTAL_COUNT)); | ||||
| 	} | ||||
| 	if(monsterStrength == EMonsterStrength::RANDOM) | ||||
| 	{ | ||||
| 		monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(rand.nextInt(2)); | ||||
| 		monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(rand.nextInt(EMonsterStrength::TOTAL_COUNT)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -18,34 +18,36 @@ class CRmgTemplate; | ||||
|  | ||||
| namespace EWaterContent | ||||
| { | ||||
| enum EWaterContent | ||||
| { | ||||
| 	RANDOM = -1, | ||||
| 	NONE, | ||||
| 	NORMAL, | ||||
| 	ISLANDS | ||||
| }; | ||||
| 	enum EWaterContent | ||||
| 	{ | ||||
| 		RANDOM = -1, | ||||
| 		NONE, | ||||
| 		NORMAL, | ||||
| 		ISLANDS, | ||||
| 		TOTAL_COUNT | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| namespace EMonsterStrength | ||||
| { | ||||
| enum EMonsterStrength | ||||
| { | ||||
| 	RANDOM = -1, | ||||
| 	WEAK, | ||||
| 	NORMAL, | ||||
| 	STRONG | ||||
| }; | ||||
| 	enum EMonsterStrength | ||||
| 	{ | ||||
| 		RANDOM = -1, | ||||
| 		WEAK, | ||||
| 		NORMAL, | ||||
| 		STRONG, | ||||
| 		TOTAL_COUNT | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| namespace EPlayerType | ||||
| { | ||||
| enum EPlayerType | ||||
| { | ||||
| 	HUMAN, | ||||
| 	AI, | ||||
| 	COMP_ONLY | ||||
| }; | ||||
| 	enum EPlayerType | ||||
| 	{ | ||||
| 		HUMAN, | ||||
| 		AI, | ||||
| 		COMP_ONLY | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| /// The map gen options class holds values about general map generation settings | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -13,369 +13,22 @@ | ||||
|  | ||||
| #include "../GameConstants.h" | ||||
| #include "../CRandomGenerator.h" | ||||
| #include "CMapGenOptions.h" | ||||
| #include "../CObjectHandler.h" | ||||
| #include "../int3.h" | ||||
|  | ||||
| class CMap; | ||||
| class CRmgTemplate; | ||||
| class CRmgTemplateZone; | ||||
| class CMapGenOptions; | ||||
| class CTerrainViewPatternConfig; | ||||
| class CMapEditManager; | ||||
| class JsonNode; | ||||
|  | ||||
| typedef std::vector<JsonNode> JsonVector; | ||||
|  | ||||
| namespace ETemplateZoneType | ||||
| { | ||||
| enum ETemplateZoneType | ||||
| { | ||||
| 	PLAYER_START, | ||||
| 	CPU_START, | ||||
| 	TREASURE, | ||||
| 	JUNCTION | ||||
| }; | ||||
| } | ||||
|  | ||||
| typedef int TRmgTemplateZoneId; | ||||
|  | ||||
| class CMapGenerator; | ||||
|  | ||||
| /// The CRmgTemplateZone describes a zone in a template. | ||||
| class DLL_LINKAGE CRmgTemplateZone | ||||
| { | ||||
| public: | ||||
| 	class DLL_LINKAGE CTownInfo | ||||
| 	{ | ||||
| 	public: | ||||
| 		CTownInfo(); | ||||
|  | ||||
| 		int getTownCount() const; /// Default: 0 | ||||
| 		void setTownCount(int value); | ||||
| 		int getCastleCount() const; /// Default: 0 | ||||
| 		void setCastleCount(int value); | ||||
| 		int getTownDensity() const; /// Default: 0 | ||||
| 		void setTownDensity(int value); | ||||
| 		int getCastleDensity() const; /// Default: 0 | ||||
| 		void setCastleDensity(int value); | ||||
|  | ||||
| 	private: | ||||
| 		int townCount, castleCount, townDensity, castleDensity; | ||||
| 	}; | ||||
| 	 | ||||
| 	class DLL_LINKAGE CTileInfo | ||||
| 	{ | ||||
| 	public: | ||||
| 		CTileInfo(); | ||||
|  | ||||
| 		int getNearestObjectDistance() const; | ||||
| 		void setNearestObjectDistance(int value); | ||||
| 		bool isObstacle() const; | ||||
| 		void setObstacle(bool value); | ||||
| 		bool isOccupied() const; | ||||
| 		void setOccupied(bool value); | ||||
| 		ETerrainType getTerrainType() const; | ||||
| 		void setTerrainType(ETerrainType value); | ||||
|  | ||||
| 	private: | ||||
| 		int nearestObjectDistance; | ||||
| 		bool obstacle; | ||||
| 		bool occupied; | ||||
| 		ETerrainType terrain; | ||||
| 	}; | ||||
|  | ||||
| 	CRmgTemplateZone(); | ||||
|  | ||||
| 	TRmgTemplateZoneId getId() const; /// Default: 0 | ||||
| 	void setId(TRmgTemplateZoneId value); | ||||
| 	ETemplateZoneType::ETemplateZoneType getType() const; /// Default: ETemplateZoneType::PLAYER_START | ||||
| 	void setType(ETemplateZoneType::ETemplateZoneType value); | ||||
| 	int getSize() const; /// Default: 1 | ||||
| 	void setSize(int value); | ||||
| 	boost::optional<int> getOwner() const; | ||||
| 	void setOwner(boost::optional<int> value); | ||||
| 	const CTownInfo & getPlayerTowns() const; | ||||
| 	void setPlayerTowns(const CTownInfo & value); | ||||
| 	const CTownInfo & getNeutralTowns() const; | ||||
| 	void setNeutralTowns(const CTownInfo & value); | ||||
| 	bool getTownsAreSameType() const; /// Default: false | ||||
| 	void setTownsAreSameType(bool value); | ||||
| 	const std::set<TFaction> & getTownTypes() const; /// Default: all | ||||
| 	void setTownTypes(const std::set<TFaction> & value); | ||||
| 	std::set<TFaction> getDefaultTownTypes() const; | ||||
| 	bool getMatchTerrainToTown() const; /// Default: true | ||||
| 	void setMatchTerrainToTown(bool value); | ||||
| 	const std::set<ETerrainType> & getTerrainTypes() const; /// Default: all | ||||
| 	void setTerrainTypes(const std::set<ETerrainType> & value); | ||||
| 	std::set<ETerrainType> getDefaultTerrainTypes() const; | ||||
| 	boost::optional<TRmgTemplateZoneId> getTerrainTypeLikeZone() const; | ||||
| 	void setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value); | ||||
| 	boost::optional<TRmgTemplateZoneId> getTownTypeLikeZone() const; | ||||
| 	void setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value); | ||||
| 	void setShape(std::vector<int3> shape); | ||||
| 	bool fill(CMapGenerator* gen); | ||||
|  | ||||
| private: | ||||
| 	TRmgTemplateZoneId id; | ||||
| 	ETemplateZoneType::ETemplateZoneType type; | ||||
| 	int size; | ||||
| 	boost::optional<int> owner; | ||||
| 	CTownInfo playerTowns, neutralTowns; | ||||
| 	bool townsAreSameType; | ||||
| 	std::set<TFaction> townTypes; | ||||
| 	bool matchTerrainToTown; | ||||
| 	std::set<ETerrainType> terrainTypes; | ||||
| 	boost::optional<TRmgTemplateZoneId> terrainTypeLikeZone, townTypeLikeZone; | ||||
|  | ||||
| 	std::vector<int3> shape; | ||||
| 	std::map<int3, CTileInfo> tileinfo; | ||||
| 	std::vector<CGObjectInstance*> objects; | ||||
|  | ||||
| 	int3 getCenter(); | ||||
| 	bool pointIsIn(int x, int y); | ||||
| 	bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos); | ||||
| 	void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos); | ||||
| 	bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str); | ||||
| }; | ||||
|  | ||||
| /// The CRmgTemplateZoneConnection describes the connection between two zones. | ||||
| class DLL_LINKAGE CRmgTemplateZoneConnection | ||||
| { | ||||
| public: | ||||
| 	CRmgTemplateZoneConnection(); | ||||
|  | ||||
| 	TRmgTemplateZoneId getZoneA() const; /// Default: 0 | ||||
| 	void setZoneA(TRmgTemplateZoneId value); | ||||
| 	TRmgTemplateZoneId getZoneB() const; /// Default: 0 | ||||
| 	void setZoneB(TRmgTemplateZoneId value); | ||||
| 	int getGuardStrength() const; /// Default: 0 | ||||
| 	void setGuardStrength(int value); | ||||
|  | ||||
| private: | ||||
| 	TRmgTemplateZoneId zoneA, zoneB; | ||||
| 	int guardStrength; | ||||
| }; | ||||
|  | ||||
| /// The CRmgTemplate describes a random map template. | ||||
| class DLL_LINKAGE CRmgTemplate | ||||
| { | ||||
| public: | ||||
| 	class CSize | ||||
| 	{ | ||||
| 	public: | ||||
| 		CSize(); | ||||
| 		CSize(int width, int height, bool under); | ||||
|  | ||||
| 		int getWidth() const; /// Default: CMapHeader::MAP_SIZE_MIDDLE | ||||
| 		void setWidth(int value); | ||||
| 		int getHeight() const; /// Default: CMapHeader::MAP_SIZE_MIDDLE | ||||
| 		void setHeight(int value); | ||||
| 		bool getUnder() const; /// Default: true | ||||
| 		void setUnder(bool value); | ||||
| 		bool operator<=(const CSize & value) const; | ||||
| 		bool operator>=(const CSize & value) const; | ||||
|  | ||||
| 	private: | ||||
| 		int width, height; | ||||
| 		bool under; | ||||
| 	}; | ||||
|  | ||||
| 	class CPlayerCountRange | ||||
| 	{ | ||||
| 	public: | ||||
| 		void addRange(int lower, int upper); | ||||
| 		void addNumber(int value); | ||||
| 		bool isInRange(int count) const; | ||||
| 		std::set<int> getNumbers() const; | ||||
|  | ||||
| 	private: | ||||
| 		std::list<std::pair<int, int> > range; | ||||
| 	}; | ||||
|  | ||||
| 	CRmgTemplate(); | ||||
|  | ||||
| 	const std::string & getName() const; | ||||
| 	void setName(const std::string & value); | ||||
| 	const CSize & getMinSize() const; | ||||
| 	void setMinSize(const CSize & value); | ||||
| 	const CSize & getMaxSize() const; | ||||
| 	void setMaxSize(const CSize & value); | ||||
| 	const CPlayerCountRange & getPlayers() const; | ||||
| 	void setPlayers(const CPlayerCountRange & value); | ||||
| 	const CPlayerCountRange & getCpuPlayers() const; | ||||
| 	void setCpuPlayers(const CPlayerCountRange & value); | ||||
| 	const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & getZones() const; | ||||
| 	void setZones(const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & value); | ||||
| 	const std::list<CRmgTemplateZoneConnection> & getConnections() const; | ||||
| 	void setConnections(const std::list<CRmgTemplateZoneConnection> & value); | ||||
|  | ||||
| 	void validate() const; /// Tests template on validity and throws exception on failure | ||||
|  | ||||
| private: | ||||
| 	std::string name; | ||||
| 	CSize minSize, maxSize; | ||||
| 	CPlayerCountRange players, cpuPlayers; | ||||
| 	std::map<TRmgTemplateZoneId, CRmgTemplateZone> zones; | ||||
| 	std::list<CRmgTemplateZoneConnection> connections; | ||||
| }; | ||||
|  | ||||
| namespace EWaterContent | ||||
| { | ||||
| enum EWaterContent | ||||
| { | ||||
| 	RANDOM = -1, | ||||
| 	NONE, | ||||
| 	NORMAL, | ||||
| 	ISLANDS | ||||
| }; | ||||
| } | ||||
|  | ||||
| namespace EMonsterStrength | ||||
| { | ||||
| enum EMonsterStrength | ||||
| { | ||||
| 	RANDOM = -1, | ||||
| 	WEAK, | ||||
| 	NORMAL, | ||||
| 	STRONG | ||||
| }; | ||||
| } | ||||
|  | ||||
| namespace EPlayerType | ||||
| { | ||||
| enum EPlayerType | ||||
| { | ||||
| 	HUMAN, | ||||
| 	AI, | ||||
| 	COMP_ONLY | ||||
| }; | ||||
| } | ||||
|  | ||||
| /// The map gen options class holds values about general map generation settings | ||||
| /// e.g. the size of the map, the count of players,... | ||||
| class DLL_LINKAGE CMapGenOptions | ||||
| { | ||||
| public: | ||||
| 	/// The player settings class maps the player color, starting town and human player flag. | ||||
| 	class DLL_LINKAGE CPlayerSettings | ||||
| 	{ | ||||
| 	public: | ||||
| 		CPlayerSettings(); | ||||
|  | ||||
| 		/// The color of the player ranging from 0 to PlayerColor::PLAYER_LIMIT - 1. | ||||
| 		/// The default value is 0. | ||||
| 		PlayerColor getColor() const; | ||||
| 		void setColor(PlayerColor value); | ||||
|  | ||||
| 		/// The starting town of the player ranging from 0 to town max count or RANDOM_TOWN. | ||||
| 		/// The default value is RANDOM_TOWN. | ||||
| 		si32 getStartingTown() const; | ||||
| 		void setStartingTown(si32 value); | ||||
|  | ||||
| 		/// The default value is EPlayerType::AI. | ||||
| 		EPlayerType::EPlayerType getPlayerType() const; | ||||
| 		void setPlayerType(EPlayerType::EPlayerType value); | ||||
|  | ||||
| 		/// Constant for a random town selection. | ||||
| 		static const si32 RANDOM_TOWN = -1; | ||||
|  | ||||
| 	private: | ||||
| 		PlayerColor color; | ||||
| 		si32 startingTown; | ||||
| 		EPlayerType::EPlayerType playerType; | ||||
|  | ||||
| 	public: | ||||
| 		template <typename Handler> | ||||
| 		void serialize(Handler & h, const int version) | ||||
| 		{ | ||||
| 			h & color & startingTown & playerType; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	CMapGenOptions(); | ||||
|  | ||||
| 	si32 getWidth() const; | ||||
| 	void setWidth(si32 value); | ||||
|  | ||||
| 	si32 getHeight() const; | ||||
| 	void setHeight(si32 value); | ||||
|  | ||||
| 	bool getHasTwoLevels() const; | ||||
| 	void setHasTwoLevels(bool value); | ||||
|  | ||||
| 	/// The count of the players ranging from 1 to PlayerColor::PLAYER_LIMIT or RANDOM_SIZE for random. If you call | ||||
| 	/// this method, all player settings are reset to default settings. | ||||
| 	si8 getPlayerCount() const; | ||||
| 	void setPlayerCount(si8 value); | ||||
|  | ||||
| 	/// The count of the teams ranging from 0 to <players count - 1> or RANDOM_SIZE for random. | ||||
| 	si8 getTeamCount() const; | ||||
| 	void setTeamCount(si8 value); | ||||
|  | ||||
| 	/// The count of the computer only players ranging from 0 to <PlayerColor::PLAYER_LIMIT - players count> or RANDOM_SIZE for random. | ||||
| 	/// If you call this method, all player settings are reset to default settings. | ||||
| 	si8 getCompOnlyPlayerCount() const; | ||||
| 	void setCompOnlyPlayerCount(si8 value); | ||||
|  | ||||
| 	/// The count of the computer only teams ranging from 0 to <comp only players - 1> or RANDOM_SIZE for random. | ||||
| 	si8 getCompOnlyTeamCount() const; | ||||
| 	void setCompOnlyTeamCount(si8 value); | ||||
|  | ||||
| 	EWaterContent::EWaterContent getWaterContent() const; | ||||
| 	void setWaterContent(EWaterContent::EWaterContent value); | ||||
|  | ||||
| 	EMonsterStrength::EMonsterStrength getMonsterStrength() const; | ||||
| 	void setMonsterStrength(EMonsterStrength::EMonsterStrength value); | ||||
|  | ||||
| 	/// The first player colors belong to standard players and the last player colors belong to comp only players. | ||||
| 	/// All standard players are by default of type EPlayerType::AI. | ||||
| 	const std::map<PlayerColor, CPlayerSettings> & getPlayersSettings() const; | ||||
| 	void setStartingTownForPlayer(PlayerColor color, si32 town); | ||||
| 	/// Sets a player type for a standard player. A standard player is the opposite of a computer only player. The | ||||
| 	/// values which can be chosen for the player type are EPlayerType::AI or EPlayerType::HUMAN. | ||||
| 	void setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType); | ||||
|  | ||||
| 	/// The random map template to generate the map with or empty/not set if the template should be chosen randomly. | ||||
| 	/// Default: Not set/random. | ||||
| 	const CRmgTemplate * getMapTemplate() const; | ||||
| 	void setMapTemplate(const CRmgTemplate * value); | ||||
|  | ||||
| 	const std::map<std::string, CRmgTemplate> & getAvailableTemplates() const; | ||||
|  | ||||
| 	/// Finalizes the options. All random sizes for various properties will be overwritten by numbers from | ||||
| 	/// a random number generator by keeping the options in a valid state. Check options should return true, otherwise | ||||
| 	/// this function fails. | ||||
| 	void finalize(); | ||||
| 	void finalize(CRandomGenerator & gen); | ||||
|  | ||||
| 	/// Returns false if there is no template available which fits to the currently selected options. | ||||
| 	bool checkOptions() const; | ||||
|  | ||||
| 	static const si8 RANDOM_SIZE = -1; | ||||
|  | ||||
| private: | ||||
| 	void resetPlayersMap(); | ||||
| 	int countHumanPlayers() const; | ||||
| 	PlayerColor getNextPlayerColor() const; | ||||
| 	void updateCompOnlyPlayers(); | ||||
| 	void updatePlayers(); | ||||
| 	const CRmgTemplate * getPossibleTemplate(CRandomGenerator & gen) const; | ||||
|  | ||||
| 	si32 width, height; | ||||
| 	bool hasTwoLevels; | ||||
| 	si8 playerCount, teamCount, compOnlyPlayerCount, compOnlyTeamCount; | ||||
| 	EWaterContent::EWaterContent waterContent; | ||||
| 	EMonsterStrength::EMonsterStrength monsterStrength; | ||||
| 	std::map<PlayerColor, CPlayerSettings> players; | ||||
| 	const CRmgTemplate * mapTemplate; | ||||
|  | ||||
| public: | ||||
| 	template <typename Handler> | ||||
| 	void serialize(Handler & h, const int version) | ||||
| 	{ | ||||
| 		h & width & height & hasTwoLevels & playerCount & teamCount & compOnlyPlayerCount; | ||||
| 		h & compOnlyTeamCount & waterContent & monsterStrength & players; | ||||
|         //TODO add name of template to class, enables selection of a template by a user | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| /// The map generator creates a map randomly. | ||||
| class DLL_LINKAGE CMapGenerator | ||||
| { | ||||
| @@ -383,16 +36,16 @@ public: | ||||
| 	explicit CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed = std::time(nullptr)); | ||||
| 	~CMapGenerator(); // required due to unique_ptr | ||||
|  | ||||
| 	std::unique_ptr<CMap> generate(); | ||||
| 	ConstTransitivePtr<CMap> generate(); | ||||
| 	 | ||||
| 	CMapGenOptions mapGenOptions; | ||||
| 	std::unique_ptr<CMap> map; | ||||
| 	CRandomGenerator gen; | ||||
| 	ConstTransitivePtr<CMap> map; | ||||
| 	CRandomGenerator rand; | ||||
| 	int randomSeed; | ||||
| 	CMapEditManager * editManager; | ||||
|  | ||||
| private: | ||||
| 	std::map<TRmgTemplateZoneId, CRmgTemplateZone> zones; | ||||
| 	std::map<TRmgTemplateZoneId, CRmgTemplateZone*> zones; | ||||
|  | ||||
| 	/// Generation methods | ||||
| 	std::string getMapDescription() const; | ||||
| @@ -407,45 +60,3 @@ private: | ||||
| /* Implementation/Detail classes, Private API */ | ||||
| /* ---------------------------------------------------------------------------- */ | ||||
|  | ||||
| /// The CRmgTemplateLoader is a abstract base class for loading templates. | ||||
| class DLL_LINKAGE CRmgTemplateLoader | ||||
| { | ||||
| public: | ||||
| 	virtual ~CRmgTemplateLoader() { }; | ||||
| 	virtual void loadTemplates() = 0; | ||||
| 	const std::map<std::string, CRmgTemplate> & getTemplates() const; | ||||
|  | ||||
| protected: | ||||
| 	std::map<std::string, CRmgTemplate> templates; | ||||
| }; | ||||
|  | ||||
| /// The CJsonRmgTemplateLoader loads templates from a JSON file. | ||||
| class DLL_LINKAGE CJsonRmgTemplateLoader : public CRmgTemplateLoader | ||||
| { | ||||
| public: | ||||
| 	void loadTemplates() override; | ||||
|  | ||||
| private: | ||||
| 	CRmgTemplate::CSize parseMapTemplateSize(const std::string & text) const; | ||||
| 	CRmgTemplateZone::CTownInfo parseTemplateZoneTowns(const JsonNode & node) const; | ||||
| 	ETemplateZoneType::ETemplateZoneType parseZoneType(const std::string & type) const; | ||||
| 	std::set<TFaction> parseTownTypes(const JsonVector & townTypesVector, const std::set<TFaction> & defaultTownTypes) const; | ||||
| 	std::set<ETerrainType> parseTerrainTypes(const JsonVector & terTypeStrings, const std::set<ETerrainType> & defaultTerrainTypes) const; | ||||
| 	CRmgTemplate::CPlayerCountRange parsePlayers(const std::string & players) const; | ||||
| }; | ||||
|  | ||||
| /// The CRmgTemplateStorage is a singleton object where templates are stored and which can be accessed from anywhere. | ||||
| class DLL_LINKAGE CRmgTemplateStorage | ||||
| { | ||||
| public: | ||||
| 	static CRmgTemplateStorage & get(); | ||||
|  | ||||
| 	const std::map<std::string, CRmgTemplate> & getTemplates() const; | ||||
|  | ||||
| private: | ||||
| 	CRmgTemplateStorage(); | ||||
| 	~CRmgTemplateStorage(); | ||||
|  | ||||
| 	static boost::mutex smx; | ||||
| 	std::map<std::string, CRmgTemplate> templates; /// Key: Template name | ||||
| }; | ||||
|   | ||||
| @@ -229,4 +229,4 @@ CRmgTemplateStorage::CRmgTemplateStorage() | ||||
| CRmgTemplateStorage::~CRmgTemplateStorage() | ||||
| { | ||||
| 	for (auto & pair : templates) delete pair.second; | ||||
| } | ||||
| } | ||||
| @@ -11,10 +11,15 @@ | ||||
|  | ||||
| #include "StdInc.h" | ||||
| #include "CRmgTemplateZone.h" | ||||
| #include "../mapping/CMapEditManager.h" | ||||
| #include "../mapping/CMap.h" | ||||
|  | ||||
| #include "../VCMI_Lib.h" | ||||
| #include "../CTownHandler.h" | ||||
|  | ||||
| class CMap; | ||||
| class CMapEditManager; | ||||
|  | ||||
| CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0) | ||||
| { | ||||
|  | ||||
| @@ -64,6 +69,52 @@ void CRmgTemplateZone::CTownInfo::setCastleDensity(int value) | ||||
| 	castleDensity = value; | ||||
| } | ||||
|  | ||||
| CRmgTemplateZone::CTileInfo::CTileInfo():nearestObjectDistance(INT_MAX), obstacle(false), occupied(false), terrain(ETerrainType::WRONG)  | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| int CRmgTemplateZone::CTileInfo::getNearestObjectDistance() const | ||||
| { | ||||
| 	return nearestObjectDistance; | ||||
| } | ||||
|  | ||||
| void CRmgTemplateZone::CTileInfo::setNearestObjectDistance(int value) | ||||
| { | ||||
| 	if(value < 0) throw std::runtime_error("Negative value for nearest object distance not allowed."); | ||||
| 	nearestObjectDistance = value; | ||||
| } | ||||
|  | ||||
| bool CRmgTemplateZone::CTileInfo::isObstacle() const | ||||
| { | ||||
| 	return obstacle; | ||||
| } | ||||
|  | ||||
| void CRmgTemplateZone::CTileInfo::setObstacle(bool value) | ||||
| { | ||||
| 	obstacle = value; | ||||
| } | ||||
|  | ||||
| bool CRmgTemplateZone::CTileInfo::isOccupied() const | ||||
| { | ||||
| 	return occupied; | ||||
| } | ||||
|  | ||||
| void CRmgTemplateZone::CTileInfo::setOccupied(bool value) | ||||
| { | ||||
| 	occupied = value; | ||||
| } | ||||
|  | ||||
| ETerrainType CRmgTemplateZone::CTileInfo::getTerrainType() const | ||||
| { | ||||
| 	return terrain; | ||||
| } | ||||
|  | ||||
| void CRmgTemplateZone::CTileInfo::setTerrainType(ETerrainType value) | ||||
| { | ||||
| 	terrain = value; | ||||
| } | ||||
|  | ||||
| CRmgTemplateZone::CRmgTemplateZone() : id(0), type(ETemplateZoneType::PLAYER_START), size(1), | ||||
| 	townsAreSameType(false), matchTerrainToTown(true) | ||||
| { | ||||
| @@ -214,3 +265,280 @@ void CRmgTemplateZone::setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> v | ||||
| { | ||||
| 	townTypeLikeZone = value; | ||||
| } | ||||
|  | ||||
| bool CRmgTemplateZone::pointIsIn(int x, int y) | ||||
| { | ||||
| 	int i, j; | ||||
| 	bool c = false; | ||||
| 	int nvert = shape.size(); | ||||
| 	for (i = 0, j = nvert-1; i < nvert; j = i++) { | ||||
| 		if ( ((shape[i].y>y) != (shape[j].y>y)) && | ||||
| 			(x < (shape[j].x-shape[i].x) * (y-shape[i].y) / (shape[j].y-shape[i].y) + shape[i].x) ) | ||||
| 			c = !c; | ||||
| 	} | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| void CRmgTemplateZone::setShape(std::vector<int3> shape) | ||||
| { | ||||
| 	int z = -1; | ||||
| 	si32 minx = INT_MAX; | ||||
| 	si32 maxx = -1; | ||||
| 	si32 miny = INT_MAX; | ||||
| 	si32 maxy = -1; | ||||
| 	for(auto &point : shape) | ||||
| 	{ | ||||
| 		if (z == -1) | ||||
| 			z = point.z; | ||||
| 		if (point.z != z) | ||||
| 			throw std::runtime_error("Zone shape points should lie on same z."); | ||||
| 		minx = std::min(minx, point.x); | ||||
| 		maxx = std::max(maxx, point.x); | ||||
| 		miny = std::min(miny, point.y); | ||||
| 		maxy = std::max(maxy, point.y); | ||||
| 	} | ||||
| 	this->shape = shape; | ||||
| 	for(int x = minx; x <= maxx; ++x) | ||||
| 	{ | ||||
| 		for(int y = miny; y <= maxy; ++y) | ||||
| 		{ | ||||
| 			if (pointIsIn(x, y)) | ||||
| 			{ | ||||
| 				tileinfo[int3(x,y,z)] = CTileInfo(); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int3 CRmgTemplateZone::getCenter() | ||||
| { | ||||
| 	si32 cx = 0; | ||||
| 	si32 cy = 0; | ||||
| 	si32 area = 0; | ||||
| 	si32 sz = shape.size(); | ||||
| 	//include last->first too | ||||
| 	for(si32 i = 0, j = sz-1; i < sz; j = i++) { | ||||
| 		si32 sf = (shape[i].x * shape[j].y - shape[j].x * shape[i].y); | ||||
| 		cx += (shape[i].x + shape[j].x) * sf; | ||||
| 		cy += (shape[i].y + shape[j].y) * sf; | ||||
| 		area += sf; | ||||
| 	} | ||||
| 	area /= 2; | ||||
| 	return int3(std::abs(cx/area/6), std::abs(cy/area/6), shape[0].z); | ||||
| } | ||||
|  | ||||
| bool CRmgTemplateZone::fill(CMapGenerator* gen) | ||||
| { | ||||
| 	std::vector<CGObjectInstance*> required_objects; | ||||
| 	if ((type == ETemplateZoneType::CPU_START) || (type == ETemplateZoneType::PLAYER_START)) | ||||
| 	{ | ||||
| 		logGlobal->infoStream() << "Preparing playing zone"; | ||||
| 		int player_id = *owner - 1; | ||||
| 		auto & playerInfo = gen->map->players[player_id]; | ||||
| 		if (playerInfo.canAnyonePlay()) | ||||
| 		{ | ||||
| 			PlayerColor player(player_id); | ||||
| 			auto  town = new CGTownInstance(); | ||||
| 			town->ID = Obj::TOWN; | ||||
| 			int townId = gen->mapGenOptions.getPlayersSettings().find(player)->second.getStartingTown(); | ||||
|  | ||||
| 			if(townId == CMapGenOptions::CPlayerSettings::RANDOM_TOWN) | ||||
| 				townId = gen->rand.nextInt (VLC->townh->factions.size()); // all possible towns | ||||
|  | ||||
| 			town->subID = townId; | ||||
| 			town->tempOwner = player; | ||||
| 			town->builtBuildings.insert(BuildingID::FORT); | ||||
| 			town->builtBuildings.insert(BuildingID::DEFAULT); | ||||
| 			 | ||||
| 			placeObject(gen, town, getCenter()); | ||||
| 			logGlobal->infoStream() << "Placed object"; | ||||
|  | ||||
| 			logGlobal->infoStream() << "Fill player info " << player_id; | ||||
| 			auto & playerInfo = gen->map->players[player_id]; | ||||
| 			// Update player info | ||||
| 			playerInfo.allowedFactions.clear(); | ||||
| 			playerInfo.allowedFactions.insert(town->subID); | ||||
| 			playerInfo.hasMainTown = true; | ||||
| 			playerInfo.posOfMainTown = town->pos - int3(2, 0, 0); | ||||
| 			playerInfo.generateHeroAtMainTown = true; | ||||
|  | ||||
| 			//required_objects.push_back(town); | ||||
|  | ||||
| 			std::vector<Res::ERes> required_mines; | ||||
| 			required_mines.push_back(Res::ERes::WOOD); | ||||
| 			required_mines.push_back(Res::ERes::ORE); | ||||
|  | ||||
| 			for(const auto res : required_mines) | ||||
| 			{			 | ||||
| 				auto mine = new CGMine(); | ||||
| 				mine->ID = Obj::MINE; | ||||
| 				mine->subID = static_cast<si32>(res); | ||||
| 				mine->producedResource = res; | ||||
| 				mine->producedQuantity = mine->defaultResProduction(); | ||||
| 				required_objects.push_back(mine); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{			 | ||||
| 			type = ETemplateZoneType::TREASURE; | ||||
| 			logGlobal->infoStream() << "Skipping this zone cause no player"; | ||||
| 		} | ||||
| 	} | ||||
| 	logGlobal->infoStream() << "Creating required objects"; | ||||
| 	for(const auto &obj : required_objects) | ||||
| 	{ | ||||
| 		int3 pos; | ||||
| 		logGlobal->infoStream() << "Looking for place"; | ||||
| 		if ( ! findPlaceForObject(gen, obj, 3, pos))		 | ||||
| 		{ | ||||
| 			logGlobal->errorStream() << "Failed to fill zone due to lack of space"; | ||||
| 			//TODO CLEANUP! | ||||
| 			return false; | ||||
| 		} | ||||
| 		logGlobal->infoStream() << "Place found"; | ||||
|  | ||||
| 		placeObject(gen, obj, pos); | ||||
| 		logGlobal->infoStream() << "Placed object"; | ||||
| 	} | ||||
| 	std::vector<CGObjectInstance*> guarded_objects; | ||||
| 	static auto res_gen = gen->rand.getIntRange(Res::ERes::WOOD, Res::ERes::GOLD); | ||||
| 	const double res_mindist = 5; | ||||
| 	do { | ||||
| 		auto obj = new CGResource(); | ||||
| 		auto restype = static_cast<Res::ERes>(res_gen()); | ||||
| 		obj->ID = Obj::RESOURCE; | ||||
| 		obj->subID = static_cast<si32>(restype); | ||||
| 		obj->amount = 0; | ||||
| 		 | ||||
| 		int3 pos; | ||||
| 		if ( ! findPlaceForObject(gen, obj, res_mindist, pos))		 | ||||
| 		{ | ||||
| 			delete obj; | ||||
| 			break; | ||||
| 		} | ||||
| 		placeObject(gen, obj, pos);		 | ||||
| 		if ((restype != Res::ERes::WOOD) && (restype != Res::ERes::ORE)) | ||||
| 		{ | ||||
| 			guarded_objects.push_back(obj); | ||||
| 		} | ||||
| 	} while(true); | ||||
|  | ||||
| 	for(const auto &obj : guarded_objects) | ||||
| 	{ | ||||
| 		if ( ! guardObject(gen, obj, 500)) | ||||
| 		{ | ||||
| 			//TODO, DEL obj from map | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	auto sel = gen->editManager->getTerrainSelection(); | ||||
| 	sel.clearSelection(); | ||||
| 	for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) | ||||
| 	{ | ||||
| 		if (it->second.isObstacle()) | ||||
| 		{ | ||||
| 			auto obj = new CGObjectInstance(); | ||||
| 			obj->ID = static_cast<Obj>(130); | ||||
| 			obj->subID = 0; | ||||
| 			placeObject(gen, obj, it->first); | ||||
| 		} | ||||
| 	} | ||||
| 	logGlobal->infoStream() << boost::format("Filling %d with ROCK") % sel.getSelectedItems().size(); | ||||
| 	//gen->editManager->drawTerrain(ETerrainType::ROCK, &gen->gen); | ||||
| 	logGlobal->infoStream() << "Zone filled successfully"; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos) | ||||
| { | ||||
| 	//si32 min_dist = sqrt(tileinfo.size()/density); | ||||
| 	int best_distance = 0; | ||||
| 	bool result = false; | ||||
| 	si32 w = gen->map->width; | ||||
| 	si32 h = gen->map->height;  | ||||
| 	auto ow = obj->getWidth(); | ||||
| 	auto oh = obj->getHeight(); | ||||
| 	//logGlobal->infoStream() << boost::format("Min dist for density %f is %d") % density % min_dist; | ||||
| 	for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) | ||||
| 	{ | ||||
| 		auto &ti = it->second; | ||||
| 		auto p = it->first; | ||||
| 		auto dist = ti.getNearestObjectDistance(); | ||||
| 		//avoid borders | ||||
| 		if ((p.x < 3) || (w - p.x < 3) || (p.y < 3) || (h - p.y < 3)) | ||||
| 			continue; | ||||
| 		if (!ti.isOccupied() && !ti.isObstacle()  && (dist >= min_dist) && (dist > best_distance)) | ||||
| 		{ | ||||
| 			best_distance = dist; | ||||
| 			pos = p; | ||||
| 			result = true; | ||||
| 		} | ||||
| 	} | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos) | ||||
| { | ||||
| 	logGlobal->infoStream() << boost::format("Insert object at %d %d") % pos.x % pos.y; | ||||
| 	object->pos = pos; | ||||
| 	gen->editManager->insertObject(object, pos); | ||||
| 	logGlobal->infoStream() << "Inserted object"; | ||||
| 	auto points = object->getBlockedPos(); | ||||
| 	if (object->isVisitable()) | ||||
| 		points.emplace(pos + object->getVisitableOffset()); | ||||
| 	points.emplace(pos); | ||||
| 	for(auto const &p : points) | ||||
| 	{		 | ||||
| 		if (tileinfo.find(pos + p) != tileinfo.end()) | ||||
| 		{ | ||||
| 			tileinfo[pos + p].setOccupied(true); | ||||
| 		} | ||||
| 	} | ||||
| 	for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it) | ||||
| 	{		 | ||||
| 		si32 d = pos.dist2d(it->first); | ||||
| 		it->second.setNearestObjectDistance(std::min(d, it->second.getNearestObjectDistance())); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str) | ||||
| { | ||||
| 	 | ||||
| 	logGlobal->infoStream() << boost::format("Guard object at %d %d") % object->pos.x % object->pos.y; | ||||
| 	int3 visitable = object->pos + object->getVisitableOffset(); | ||||
| 	std::vector<int3> tiles; | ||||
| 	for(int i = -1; i < 2; ++i) | ||||
| 	{ | ||||
| 		for(int j = -1; j < 2; ++j) | ||||
| 		{ | ||||
| 			auto it = tileinfo.find(visitable + int3(i, j, 0)); | ||||
| 			if (it != tileinfo.end()) | ||||
| 			{ | ||||
| 				logGlobal->infoStream() << boost::format("Block at %d %d") % it->first.x % it->first.y; | ||||
| 				if ( ! it->second.isOccupied() &&  ! it->second.isObstacle()) | ||||
| 				{ | ||||
| 					tiles.push_back(it->first); | ||||
| 					it->second.setObstacle(true); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if ( ! tiles.size()) | ||||
| 	{		 | ||||
| 		logGlobal->infoStream() << "Failed"; | ||||
| 		return false; | ||||
| 	} | ||||
| 	auto guard_tile = *std::next(tiles.begin(), gen->rand.nextInt(tiles.size())); | ||||
| 	tileinfo[guard_tile].setObstacle(false); | ||||
| 	auto guard = new CGCreature(); | ||||
| 	guard->ID = Obj::RANDOM_MONSTER; | ||||
| 	guard->subID = 0; | ||||
| 	auto  hlp = new CStackInstance(); | ||||
| 	hlp->count = 10; | ||||
| 	//type will be set during initialization | ||||
| 	guard->putStack(SlotID(0), hlp); | ||||
|  | ||||
| 	guard->pos = guard_tile; | ||||
| 	gen->editManager->insertObject(guard, guard->pos); | ||||
| 	return true; | ||||
| } | ||||
|   | ||||
| @@ -12,6 +12,9 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../GameConstants.h" | ||||
| #include "CMapGenerator.h" | ||||
|  | ||||
| class CMapgenerator; | ||||
|  | ||||
| namespace ETemplateZoneType | ||||
| { | ||||
| @@ -45,6 +48,27 @@ public: | ||||
| 	private: | ||||
| 		int townCount, castleCount, townDensity, castleDensity; | ||||
| 	}; | ||||
| 	 | ||||
| 	class DLL_LINKAGE CTileInfo | ||||
| 	{ | ||||
| 	public: | ||||
| 		CTileInfo(); | ||||
|  | ||||
| 		int getNearestObjectDistance() const; | ||||
| 		void setNearestObjectDistance(int value); | ||||
| 		bool isObstacle() const; | ||||
| 		void setObstacle(bool value); | ||||
| 		bool isOccupied() const; | ||||
| 		void setOccupied(bool value); | ||||
| 		ETerrainType getTerrainType() const; | ||||
| 		void setTerrainType(ETerrainType value); | ||||
|  | ||||
| 	private: | ||||
| 		int nearestObjectDistance; | ||||
| 		bool obstacle; | ||||
| 		bool occupied; | ||||
| 		ETerrainType terrain; | ||||
| 	}; | ||||
|  | ||||
| 	CRmgTemplateZone(); | ||||
|  | ||||
| @@ -52,12 +76,10 @@ public: | ||||
| 	void setId(TRmgTemplateZoneId value); | ||||
| 	ETemplateZoneType::ETemplateZoneType getType() const; /// Default: ETemplateZoneType::PLAYER_START | ||||
| 	void setType(ETemplateZoneType::ETemplateZoneType value); | ||||
|  | ||||
| 	int getSize() const; /// Default: 1 | ||||
| 	void setSize(int value); | ||||
| 	boost::optional<int> getOwner() const; | ||||
| 	void setOwner(boost::optional<int> value); | ||||
|  | ||||
| 	const CTownInfo & getPlayerTowns() const; | ||||
| 	void setPlayerTowns(const CTownInfo & value); | ||||
| 	const CTownInfo & getNeutralTowns() const; | ||||
| @@ -69,7 +91,6 @@ public: | ||||
| 	std::set<TFaction> getDefaultTownTypes() const; | ||||
| 	bool getMatchTerrainToTown() const; /// Default: true | ||||
| 	void setMatchTerrainToTown(bool value); | ||||
|  | ||||
| 	const std::set<ETerrainType> & getTerrainTypes() const; /// Default: all | ||||
| 	void setTerrainTypes(const std::set<ETerrainType> & value); | ||||
| 	std::set<ETerrainType> getDefaultTerrainTypes() const; | ||||
| @@ -77,6 +98,8 @@ public: | ||||
| 	void setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value); | ||||
| 	boost::optional<TRmgTemplateZoneId> getTownTypeLikeZone() const; | ||||
| 	void setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value); | ||||
| 	void setShape(std::vector<int3> shape); | ||||
| 	bool fill(CMapGenerator* gen); | ||||
|  | ||||
| private: | ||||
| 	TRmgTemplateZoneId id; | ||||
| @@ -89,4 +112,14 @@ private: | ||||
| 	bool matchTerrainToTown; | ||||
| 	std::set<ETerrainType> terrainTypes; | ||||
| 	boost::optional<TRmgTemplateZoneId> terrainTypeLikeZone, townTypeLikeZone; | ||||
|  | ||||
| 	std::vector<int3> shape; | ||||
| 	std::map<int3, CTileInfo> tileinfo; | ||||
| 	std::vector<CGObjectInstance*> objects; | ||||
|  | ||||
| 	int3 getCenter(); | ||||
| 	bool pointIsIn(int x, int y); | ||||
| 	bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos); | ||||
| 	void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos); | ||||
| 	bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str); | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user