mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			359 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			359 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * CTownHandler.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/Faction.h>
 | |
| #include <vcmi/FactionService.h>
 | |
| 
 | |
| #include "ConstTransitivePtr.h"
 | |
| #include "ResourceSet.h"
 | |
| #include "int3.h"
 | |
| #include "GameConstants.h"
 | |
| #include "IHandlerBase.h"
 | |
| #include "LogicalExpression.h"
 | |
| #include "battle/BattleHex.h"
 | |
| #include "bonuses/Bonus.h"
 | |
| #include "bonuses/BonusList.h"
 | |
| #include "Point.h"
 | |
| #include "rewardable/Info.h"
 | |
| #include "filesystem/ResourcePath.h"
 | |
| 
 | |
| VCMI_LIB_NAMESPACE_BEGIN
 | |
| 
 | |
| class CLegacyConfigParser;
 | |
| class JsonNode;
 | |
| class CTown;
 | |
| class CFaction;
 | |
| struct BattleHex;
 | |
| class JsonSerializeFormat;
 | |
| 
 | |
| /// a typical building encountered in every castle ;]
 | |
| /// this is structure available to both client and server
 | |
| /// contains all mechanics-related data about town structures
 | |
| class DLL_LINKAGE CBuilding
 | |
| {
 | |
| 	std::string modScope;
 | |
| 	std::string identifier;
 | |
| 
 | |
| public:
 | |
| 	using TRequired = LogicalExpression<BuildingID>;
 | |
| 
 | |
| 	CTown * town; // town this building belongs to
 | |
| 	TResources resources;
 | |
| 	TResources produce;
 | |
| 	TRequired requirements;
 | |
| 
 | |
| 	BuildingID bid; //structure ID
 | |
| 	BuildingID upgrade; /// indicates that building "upgrade" can be improved by this, -1 = empty
 | |
| 	BuildingSubID::EBuildingSubID subId; /// subtype for special buildings, -1 = the building is not special
 | |
| 	std::set<BuildingID> overrideBids; /// the building which bonuses should be overridden with bonuses of the current building
 | |
| 	BonusList buildingBonuses;
 | |
| 	BonusList onVisitBonuses;
 | |
| 	
 | |
| 	Rewardable::Info rewardableObjectInfo; ///configurable rewards for special buildings
 | |
| 
 | |
| 	enum EBuildMode
 | |
| 	{
 | |
| 		BUILD_NORMAL,  // 0 - normal, default
 | |
| 		BUILD_AUTO,    // 1 - auto - building appears when all requirements are built
 | |
| 		BUILD_SPECIAL, // 2 - special - building can not be built normally
 | |
| 		BUILD_GRAIL    // 3 - grail - building requires grail to be built
 | |
| 	} mode;
 | |
| 
 | |
| 	enum ETowerHeight // for lookup towers and some grails
 | |
| 	{
 | |
| 		HEIGHT_NO_TOWER = 5, // building has not 'lookout tower' ability
 | |
| 		HEIGHT_LOW = 10,     // low lookout tower, but castle without lookout tower gives radius 5
 | |
| 		HEIGHT_AVERAGE = 15,
 | |
| 		HEIGHT_HIGH = 20,    // such tower is in the Tower town
 | |
| 		HEIGHT_SKYSHIP = std::numeric_limits<int>::max()  // grail, open entire map
 | |
| 	} height;
 | |
| 
 | |
| 	static const std::map<std::string, CBuilding::EBuildMode> MODES;
 | |
| 	static const std::map<std::string, CBuilding::ETowerHeight> TOWER_TYPES;
 | |
| 
 | |
| 	CBuilding() : town(nullptr), mode(BUILD_NORMAL) {};
 | |
| 
 | |
| 	const BuildingTypeUniqueID getUniqueTypeID() const;
 | |
| 
 | |
| 	std::string getJsonKey() const;
 | |
| 
 | |
| 	std::string getNameTranslated() const;
 | |
| 	std::string getDescriptionTranslated() const;
 | |
| 
 | |
| 	std::string getBaseTextID() const;
 | |
| 	std::string getNameTextID() const;
 | |
| 	std::string getDescriptionTextID() const;
 | |
| 
 | |
| 	//return base of upgrade(s) or this
 | |
| 	BuildingID getBase() const;
 | |
| 
 | |
| 	// returns how many times build has to be upgraded to become build
 | |
| 	si32 getDistance(const BuildingID & build) const;
 | |
| 
 | |
| 	STRONG_INLINE
 | |
| 	bool IsTradeBuilding() const
 | |
| 	{
 | |
| 		return bid == BuildingID::MARKETPLACE || subId == BuildingSubID::ARTIFACT_MERCHANT || subId == BuildingSubID::FREELANCERS_GUILD;
 | |
| 	}
 | |
| 
 | |
| 	STRONG_INLINE
 | |
| 	bool IsWeekBonus() const
 | |
| 	{
 | |
| 		return subId == BuildingSubID::STABLES || subId == BuildingSubID::MANA_VORTEX;
 | |
| 	}
 | |
| 
 | |
| 	STRONG_INLINE
 | |
| 	bool IsVisitingBonus() const
 | |
| 	{
 | |
| 		return subId == BuildingSubID::ATTACK_VISITING_BONUS ||
 | |
| 			subId == BuildingSubID::DEFENSE_VISITING_BONUS ||
 | |
| 			subId == BuildingSubID::SPELL_POWER_VISITING_BONUS ||
 | |
| 			subId == BuildingSubID::KNOWLEDGE_VISITING_BONUS ||
 | |
| 			subId == BuildingSubID::EXPERIENCE_VISITING_BONUS ||
 | |
| 			subId == BuildingSubID::CUSTOM_VISITING_BONUS;
 | |
| 	}
 | |
| 
 | |
| 	void addNewBonus(const std::shared_ptr<Bonus> & b, BonusList & bonusList) const;
 | |
| 
 | |
| 	friend class CTownHandler;
 | |
| };
 | |
| 
 | |
| /// This is structure used only by client
 | |
| /// Consists of all gui-related data about town structures
 | |
| /// Should be moved from lib to client
 | |
| struct DLL_LINKAGE CStructure
 | |
| {
 | |
| 	CBuilding * building;  // base building. If null - this structure will be always present on screen
 | |
| 	CBuilding * buildable; // building that will be used to determine built building and visible cost. Usually same as "building"
 | |
| 
 | |
| 	int3 pos;
 | |
| 	AnimationPath defName;
 | |
| 	ImagePath borderName;
 | |
| 	ImagePath areaName;
 | |
| 	std::string identifier;
 | |
| 
 | |
| 	bool hiddenUpgrade; // used only if "building" is upgrade, if true - structure on town screen will behave exactly like parent (mouse clicks, hover texts, etc)
 | |
| };
 | |
| 
 | |
| struct DLL_LINKAGE SPuzzleInfo
 | |
| {
 | |
| 	ui16 number; //type of puzzle
 | |
| 	si16 x, y; //position
 | |
| 	ui16 whenUncovered; //determines the sequence of discovering (the lesser it is the sooner puzzle will be discovered)
 | |
| 	ImagePath filename; //file with graphic of this puzzle
 | |
| };
 | |
| 
 | |
| class DLL_LINKAGE CFaction : public Faction
 | |
| {
 | |
| 	friend class CTownHandler;
 | |
| 	friend class CBuilding;
 | |
| 	friend class CTown;
 | |
| 
 | |
| 	std::string modScope;
 | |
| 	std::string identifier;
 | |
| 
 | |
| 	FactionID index = FactionID::NEUTRAL;
 | |
| 
 | |
| 	FactionID getFaction() const override; //This function should not be used
 | |
| 
 | |
| public:
 | |
| 	TerrainId nativeTerrain;
 | |
| 	EAlignment alignment = EAlignment::NEUTRAL;
 | |
| 	bool preferUndergroundPlacement = false;
 | |
| 	bool special = false;
 | |
| 
 | |
| 	/// Boat that will be used by town shipyard (if any)
 | |
| 	/// and for placing heroes directly on boat (in map editor, water prisons & taverns)
 | |
| 	BoatId boatType = BoatId::CASTLE;
 | |
| 
 | |
| 	CTown * town = nullptr; //NOTE: can be null
 | |
| 
 | |
| 	ImagePath creatureBg120;
 | |
| 	ImagePath creatureBg130;
 | |
| 
 | |
| 	std::vector<SPuzzleInfo> puzzleMap;
 | |
| 
 | |
| 	CFaction() = default;
 | |
| 	~CFaction();
 | |
| 
 | |
| 	int32_t getIndex() const override;
 | |
| 	int32_t getIconIndex() const override;
 | |
| 	std::string getJsonKey() const override;
 | |
| 	void registerIcons(const IconRegistar & cb) const override;
 | |
| 	FactionID getId() const override;
 | |
| 
 | |
| 	std::string getNameTranslated() const override;
 | |
| 	std::string getNameTextID() const override;
 | |
| 	std::string getDescriptionTranslated() const;
 | |
| 	std::string getDescriptionTextID() const;
 | |
| 
 | |
| 	bool hasTown() const override;
 | |
| 	TerrainId getNativeTerrain() const override;
 | |
| 	EAlignment getAlignment() const override;
 | |
| 	BoatId getBoatType() const override;
 | |
| 
 | |
| 	void updateFrom(const JsonNode & data);
 | |
| 	void serializeJson(JsonSerializeFormat & handler);
 | |
| };
 | |
| 
 | |
| class DLL_LINKAGE CTown
 | |
| {
 | |
| 	friend class CTownHandler;
 | |
| 	size_t namesCount = 0;
 | |
| 
 | |
| public:
 | |
| 	CTown();
 | |
| 	~CTown();
 | |
| 
 | |
| 	std::string getBuildingScope() const;
 | |
| 	std::set<si32> getAllBuildings() const;
 | |
| 	const CBuilding * getSpecialBuilding(BuildingSubID::EBuildingSubID subID) const;
 | |
| 	std::string getGreeting(BuildingSubID::EBuildingSubID subID) const;
 | |
| 	void setGreeting(BuildingSubID::EBuildingSubID subID, const std::string & message) const; //may affect only mutable field
 | |
| 	BuildingID getBuildingType(BuildingSubID::EBuildingSubID subID) const;
 | |
| 
 | |
| 	std::string getRandomNameTextID(size_t index) const;
 | |
| 	size_t getRandomNamesCount() const;
 | |
| 
 | |
| 	CFaction * faction;
 | |
| 
 | |
| 	/// level -> list of creatures on this tier
 | |
| 	// TODO: replace with pointers to CCreature
 | |
| 	std::vector<std::vector<CreatureID> > creatures;
 | |
| 
 | |
| 	std::map<BuildingID, ConstTransitivePtr<CBuilding> > buildings;
 | |
| 
 | |
| 	std::vector<std::string> dwellings; //defs for adventure map dwellings for new towns, [0] means tier 1 creatures etc.
 | |
| 	std::vector<std::string> dwellingNames;
 | |
| 
 | |
| 	// should be removed at least from configs in favor of auto-detection
 | |
| 	std::map<int,int> hordeLvl; //[0] - first horde building creature level; [1] - second horde building (-1 if not present)
 | |
| 	ui32 mageLevel; //max available mage guild level
 | |
| 	GameResID primaryRes;
 | |
| 	ArtifactID warMachine;
 | |
| 	SpellID moatAbility;
 | |
| 
 | |
| 	// default chance for hero of specific class to appear in tavern, if field "tavern" was not set
 | |
| 	// resulting chance = sqrt(town.chance * heroClass.chance)
 | |
| 	ui32 defaultTavernChance;
 | |
| 
 | |
| 	// Client-only data. Should be moved away from lib
 | |
| 	struct ClientInfo
 | |
| 	{
 | |
| 		//icons [fort is present?][build limit reached?] -> index of icon in def files
 | |
| 		int icons[2][2];
 | |
| 		std::string iconSmall[2][2]; /// icon names used during loading
 | |
| 		std::string iconLarge[2][2];
 | |
| 		VideoPath tavernVideo;
 | |
| 		std::vector<AudioPath> musicTheme;
 | |
| 		ImagePath townBackground;
 | |
| 		ImagePath guildBackground;
 | |
| 		ImagePath guildWindow;
 | |
| 		AnimationPath buildingsIcons;
 | |
| 		ImagePath hallBackground;
 | |
| 		/// vector[row][column] = list of buildings in this slot
 | |
| 		std::vector< std::vector< std::vector<BuildingID> > > hallSlots;
 | |
| 
 | |
| 		/// list of town screen structures.
 | |
| 		/// NOTE: index in vector is meaningless. Vector used instead of list for a bit faster access
 | |
| 		std::vector<ConstTransitivePtr<CStructure> > structures;
 | |
| 
 | |
| 		std::string siegePrefix;
 | |
| 		std::vector<Point> siegePositions;
 | |
| 		CreatureID siegeShooter; // shooter creature ID
 | |
| 		std::string towerIconSmall;
 | |
| 		std::string towerIconLarge;
 | |
| 
 | |
| 	} clientInfo;
 | |
| 	
 | |
| private:
 | |
| 	///generated bonusing buildings messages for all towns of this type.
 | |
| 	mutable std::map<BuildingSubID::EBuildingSubID, const std::string> specialMessages; //may be changed by CGTownBuilding::getVisitingBonusGreeting() const
 | |
| };
 | |
| 
 | |
| class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFaction, FactionService>
 | |
| {
 | |
| 	struct BuildingRequirementsHelper
 | |
| 	{
 | |
| 		JsonNode json;
 | |
| 		CBuilding * building;
 | |
| 		CTown * town;
 | |
| 	};
 | |
| 
 | |
| 	std::map<CTown *, JsonNode> warMachinesToLoad;
 | |
| 	std::vector<BuildingRequirementsHelper> requirementsToLoad;
 | |
| 	std::vector<BuildingRequirementsHelper> overriddenBidsToLoad; //list of buildings, which bonuses should be overridden.
 | |
| 
 | |
| 	static const TPropagatorPtr & emptyPropagator();
 | |
| 
 | |
| 	void initializeRequirements();
 | |
| 	void initializeOverridden();
 | |
| 	void initializeWarMachines();
 | |
| 
 | |
| 	/// loads CBuilding's into town
 | |
| 	void loadBuildingRequirements(CBuilding * building, const JsonNode & source, std::vector<BuildingRequirementsHelper> & bidsToLoad) const;
 | |
| 	void loadBuilding(CTown * town, const std::string & stringID, const JsonNode & source);
 | |
| 	void loadBuildings(CTown * town, const JsonNode & source);
 | |
| 
 | |
| 	std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val) const;
 | |
| 	std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype) const;
 | |
| 	std::shared_ptr<Bonus> createBonus(CBuilding * build, BonusType type, int val, BonusSubtypeID subtype, const TPropagatorPtr & prop) const;
 | |
| 
 | |
| 	/// loads CStructure's into town
 | |
| 	void loadStructure(CTown & town, const std::string & stringID, const JsonNode & source) const;
 | |
| 	void loadStructures(CTown & town, const JsonNode & source) const;
 | |
| 
 | |
| 	/// loads town hall vector (hallSlots)
 | |
| 	void loadTownHall(CTown & town, const JsonNode & source) const;
 | |
| 	void loadSiegeScreen(CTown & town, const JsonNode & source) const;
 | |
| 
 | |
| 	void loadClientData(CTown & town, const JsonNode & source) const;
 | |
| 
 | |
| 	void loadTown(CTown * town, const JsonNode & source);
 | |
| 
 | |
| 	void loadPuzzle(CFaction & faction, const JsonNode & source) const;
 | |
| 
 | |
| 	void loadRandomFaction();
 | |
| 
 | |
| 
 | |
| public:
 | |
| 	template<typename R, typename K>
 | |
| 	static R getMappedValue(const K key, const R defval, const std::map<K, R> & map, bool required = true);
 | |
| 	template<typename R>
 | |
| 	static R getMappedValue(const JsonNode & node, const R defval, const std::map<std::string, R> & map, bool required = true);
 | |
| 
 | |
| 	CTown * randomTown;
 | |
| 	CFaction * randomFaction;
 | |
| 
 | |
| 	CTownHandler();
 | |
| 	~CTownHandler();
 | |
| 
 | |
| 	std::vector<JsonNode> loadLegacyData() override;
 | |
| 
 | |
| 	void loadObject(std::string scope, std::string name, const JsonNode & data) override;
 | |
| 	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
 | |
| 	void addBonusesForVanilaBuilding(CBuilding * building) const;
 | |
| 
 | |
| 	void loadCustom() override;
 | |
| 	void afterLoadFinalization() override;
 | |
| 
 | |
| 	std::set<FactionID> getDefaultAllowed() const;
 | |
| 	std::set<FactionID> getAllowedFactions(bool withTown = true) const;
 | |
| 
 | |
| 	static void loadSpecialBuildingBonuses(const JsonNode & source, BonusList & bonusList, CBuilding * building);
 | |
| 
 | |
| protected:
 | |
| 	const std::vector<std::string> & getTypeNames() const override;
 | |
| 	std::shared_ptr<CFaction> loadFromJson(const std::string & scope, const JsonNode & data, const std::string & identifier, size_t index) override;
 | |
| };
 | |
| 
 | |
| VCMI_LIB_NAMESPACE_END
 |