2023-10-19 16:19:09 +02:00
/*
* 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 reqires 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 ) { } ;
2023-10-22 17:36:41 +02:00
const BuildingTypeUniqueID getUniqueTypeID ( ) const ;
2023-10-19 16:19:09 +02:00
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 ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & modScope ;
h & identifier ;
h & town ;
h & bid ;
h & resources ;
h & produce ;
h & requirements ;
h & upgrade ;
h & mode ;
h & subId ;
h & height ;
h & overrideBids ;
h & buildingBonuses ;
h & onVisitBonuses ;
h & rewardableObjectInfo ;
}
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)
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & pos ;
h & defName ;
h & borderName ;
h & areaName ;
h & identifier ;
h & building ;
h & buildable ;
h & hiddenUpgrade ;
}
} ;
struct DLL_LINKAGE SPuzzleInfo
{
ui16 number ; //type of puzzle
si16 x , y ; //position
ui16 whenUncovered ; //determines the sequnce of discovering (the lesser it is the sooner puzzle will be discovered)
ImagePath filename ; //file with graphic of this puzzle
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & number ;
h & x ;
h & y ;
h & whenUncovered ;
h & filename ;
}
} ;
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 ;
/// 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 ;
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 ) ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & modScope ;
h & identifier ;
h & index ;
h & nativeTerrain ;
h & boatType ;
h & alignment ;
h & town ;
h & creatureBg120 ;
h & creatureBg130 ;
h & puzzleMap ;
}
} ;
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 getRandomNameTranslated ( size_t index ) 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 ;
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 ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & icons ;
h & iconSmall ;
h & iconLarge ;
h & tavernVideo ;
h & musicTheme ;
h & townBackground ;
h & guildBackground ;
h & guildWindow ;
h & buildingsIcons ;
h & hallBackground ;
h & hallSlots ;
h & structures ;
h & siegePrefix ;
h & siegePositions ;
h & siegeShooter ;
h & towerIconSmall ;
h & towerIconLarge ;
}
} clientInfo ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & namesCount ;
h & faction ;
h & creatures ;
h & dwellings ;
h & dwellingNames ;
h & buildings ;
h & hordeLvl ;
h & mageLevel ;
h & primaryRes ;
h & warMachine ;
h & clientInfo ;
h & moatAbility ;
h & defaultTavernChance ;
}
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 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 ) ;
2023-10-22 17:36:41 +02:00
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 , TPropagatorPtr & prop ) const ;
2023-10-19 16:19:09 +02:00
std : : shared_ptr < Bonus > createBonusImpl ( const BuildingID & building ,
2023-10-22 17:36:41 +02:00
const FactionID & faction ,
2023-10-19 16:19:09 +02:00
BonusType type ,
int val ,
TPropagatorPtr & prop ,
const std : : string & description ,
2023-10-22 17:36:41 +02:00
BonusSubtypeID subtype ) const ;
2023-10-19 16:19:09 +02:00
/// 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 : : vector < bool > getDefaultAllowed ( ) const override ;
std : : set < FactionID > getAllowedFactions ( bool withTown = true ) const ;
static void loadSpecialBuildingBonuses ( const JsonNode & source , BonusList & bonusList , CBuilding * building ) ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & objects ;
h & randomTown ;
}
protected :
const std : : vector < std : : string > & getTypeNames ( ) const override ;
CFaction * loadFromJson ( const std : : string & scope , const JsonNode & data , const std : : string & identifier , size_t index ) override ;
} ;
VCMI_LIB_NAMESPACE_END