2009-04-15 17:03:31 +03: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
*
2009-04-16 14:14:13 +03:00
*/
2017-07-13 10:26:03 +02:00
# pragma once
# include "ConstTransitivePtr.h"
# include "ResourceSet.h"
# include "int3.h"
# include "GameConstants.h"
# include "IHandlerBase.h"
# include "LogicalExpression.h"
# include "battle/BattleHex.h"
2009-04-16 14:14:13 +03:00
2012-09-02 13:33:41 +03:00
class CLegacyConfigParser ;
class JsonNode ;
2013-04-21 15:49:26 +03:00
class CTown ;
2013-04-22 16:23:53 +03:00
class CFaction ;
2016-01-06 11:53:40 +02:00
struct BattleHex ;
2009-04-16 14:14:13 +03:00
2012-09-02 13:33:41 +03:00
/// a typical building encountered in every castle ;]
/// this is structure available to both client and server
/// contains all mechanics-related data about town structures
2014-04-26 17:23:35 +03:00
2012-09-02 13:33:41 +03:00
class DLL_LINKAGE CBuilding
{
2012-09-05 15:49:23 +03:00
2012-09-02 13:33:41 +03:00
std : : string name ;
std : : string description ;
2009-04-16 14:14:13 +03:00
2012-09-02 13:33:41 +03:00
public :
2013-12-02 14:58:02 +03:00
typedef LogicalExpression < BuildingID > TRequired ;
2013-04-21 15:49:26 +03:00
CTown * town ; // town this building belongs to
2012-09-02 13:33:41 +03:00
TResources resources ;
2014-04-26 17:23:35 +03:00
TResources produce ;
2013-12-02 14:58:02 +03:00
TRequired requirements ;
std : : string identifier ;
2012-09-05 15:49:23 +03:00
2013-12-02 14:58:02 +03:00
BuildingID bid ; //structure ID
2013-02-11 22:11:34 +03:00
BuildingID upgrade ; /// indicates that building "upgrade" can be improved by this, -1 = empty
2020-10-02 23:55:46 +02:00
BuildingSubID : : EBuildingSubID subId ; /// subtype for special buildings, -1 = the building is not special
2012-09-05 15:49:23 +03:00
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
2013-02-11 22:11:34 +03:00
} mode ;
2009-04-16 14:14:13 +03:00
2020-10-02 23:55:46 +02:00
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 ;
2020-10-07 14:12:32 +02:00
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 ) { } ;
2016-11-27 21:07:01 +02:00
2012-09-02 13:33:41 +03:00
const std : : string & Name ( ) const ;
const std : : string & Description ( ) const ;
2009-04-16 14:14:13 +03:00
2012-09-05 15:49:23 +03:00
//return base of upgrade(s) or this
2013-02-11 22:11:34 +03:00
BuildingID getBase ( ) const ;
2012-09-05 15:49:23 +03:00
// returns how many times build has to be upgraded to become build
2013-02-11 22:11:34 +03:00
si32 getDistance ( BuildingID build ) const ;
2020-10-15 14:03:01 +02:00
STRONG_INLINE
bool IsTradeBuilding ( ) const
{
return bid = = BuildingID : : MARKETPLACE | | subId = = BuildingSubID : : ARTIFACT_MERCHANT | | subId = = BuildingSubID : : FREELANCERS_GUILD ;
}
2020-10-19 21:38:06 +02:00
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 ;
}
2020-10-07 14:12:32 +02:00
/// input: faction, bid; output: subId, height;
void update792 ( const BuildingID & bid , BuildingSubID : : EBuildingSubID & subId , ETowerHeight & height ) ;
2012-09-05 15:49:23 +03:00
2009-04-16 14:14:13 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2017-07-31 15:35:42 +02:00
h & identifier ;
h & town ;
h & bid ;
h & resources ;
h & produce ;
h & name ;
h & description ;
h & requirements ;
h & upgrade ;
h & mode ;
2020-10-02 23:55:46 +02:00
if ( version > = 792 )
{
h & subId ;
h & height ;
}
2020-10-25 00:04:34 +02:00
if ( ! h . saving & & version < 793 )
2020-10-02 23:55:46 +02:00
{
2020-10-07 14:12:32 +02:00
update792 ( bid , subId , height ) ;
2020-10-02 23:55:46 +02:00
}
2017-10-28 01:25:44 +02:00
if ( ! h . saving )
deserializeFix ( ) ;
2009-04-16 14:14:13 +03:00
}
2012-09-02 13:33:41 +03:00
friend class CTownHandler ;
2017-10-28 01:25:44 +02:00
private :
void deserializeFix ( ) ;
2009-04-16 14:14:13 +03:00
} ;
2012-09-02 13:33:41 +03:00
/// This is structure used only by client
/// Consists of all gui-related data about town structures
2012-09-05 15:49:23 +03:00
/// Should be moved from lib to client
2012-09-02 13:33:41 +03:00
struct DLL_LINKAGE CStructure
2009-04-16 14:14:13 +03:00
{
2012-09-05 15:49:23 +03:00
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"
2009-04-16 14:14:13 +03:00
int3 pos ;
2013-12-02 14:58:02 +03:00
std : : string defName , borderName , areaName , identifier ;
2012-09-02 13:33:41 +03:00
2013-12-02 14:58:02 +03:00
bool hiddenUpgrade ; // used only if "building" is upgrade, if true - structure on town screen will behave exactly like parent (mouse clicks, hover texts, etc)
2012-09-02 13:33:41 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2017-07-31 15:35:42 +02:00
h & pos ;
h & defName ;
h & borderName ;
h & areaName ;
h & identifier ;
h & building ;
h & buildable ;
h & hiddenUpgrade ;
2012-09-02 13:33:41 +03:00
}
} ;
2013-04-21 15:49:26 +03:00
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)
std : : string filename ; //file with graphic of this puzzle
template < typename Handler > void serialize ( Handler & h , const int version )
{
2017-07-31 15:35:42 +02:00
h & number ;
h & x ;
h & y ;
h & whenUncovered ;
h & filename ;
2013-04-21 15:49:26 +03:00
}
} ;
2013-04-21 20:06:24 +03:00
class DLL_LINKAGE CFaction
2013-04-21 15:49:26 +03:00
{
public :
2013-04-21 17:08:46 +03:00
CFaction ( ) ;
~ CFaction ( ) ;
2013-04-21 15:49:26 +03:00
std : : string name ; //town name, by default - from TownName.txt
2013-12-02 14:58:02 +03:00
std : : string identifier ;
2013-04-21 15:49:26 +03:00
TFaction index ;
ETerrainType nativeTerrain ;
EAlignment : : EAlignment alignment ;
CTown * town ; //NOTE: can be null
std : : string creatureBg120 ;
std : : string creatureBg130 ;
2016-02-14 13:22:46 +02:00
2013-04-21 15:49:26 +03:00
std : : vector < SPuzzleInfo > puzzleMap ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
2017-07-31 15:35:42 +02:00
h & name ;
h & identifier ;
h & index ;
h & nativeTerrain ;
h & alignment ;
h & town ;
h & creatureBg120 ;
h & creatureBg130 ;
h & puzzleMap ;
2013-04-21 15:49:26 +03:00
}
} ;
2012-09-02 13:33:41 +03:00
class DLL_LINKAGE CTown
{
2012-10-05 16:11:26 +03:00
public :
2013-04-21 17:08:46 +03:00
CTown ( ) ;
~ CTown ( ) ;
2016-01-28 00:35:01 +02:00
// TODO: remove once save and mod compatability not needed
static std : : vector < BattleHex > defaultMoatHexes ( ) ;
2013-04-21 17:08:46 +03:00
2016-11-13 12:38:42 +02:00
std : : string getFactionName ( ) const ;
std : : string getBuildingScope ( ) const ;
std : : set < si32 > getAllBuildings ( ) const ;
2020-10-15 14:03:01 +02:00
const CBuilding * getSpecialBuilding ( BuildingSubID : : EBuildingSubID subID ) const ;
2020-10-25 00:04:34 +02:00
const std : : string getGreeting ( BuildingSubID : : EBuildingSubID subID ) const ;
void setGreeting ( BuildingSubID : : EBuildingSubID subID , const std : : string message ) const ; //may affect only mutable field
2020-10-15 14:03:01 +02:00
BuildingID : : EBuildingID getBuildingType ( BuildingSubID : : EBuildingSubID subID ) const ;
2016-11-13 12:38:42 +02:00
2013-04-21 15:49:26 +03:00
CFaction * faction ;
2016-02-14 13:22:46 +02:00
2012-09-02 13:33:41 +03:00
std : : vector < std : : string > names ; //names of the town instances
/// level -> list of creatures on this tier
2013-12-02 14:58:02 +03:00
// 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
ui16 primaryRes ;
ArtifactID warMachine ;
2013-02-09 00:17:39 +03:00
si32 moatDamage ;
2016-01-06 11:53:40 +02:00
std : : vector < BattleHex > moatHexes ;
2013-11-03 15:07:23 +03:00
// 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 ;
2012-09-02 13:33:41 +03:00
// Client-only data. Should be moved away from lib
struct ClientInfo
{
2012-12-13 16:07:56 +03:00
struct Point
{
si32 x ;
si32 y ;
template < typename Handler > void serialize ( Handler & h , const int version )
2017-07-31 15:35:42 +02:00
{
h & x ;
h & y ;
}
2012-12-13 16:07:56 +03:00
} ;
2012-10-05 21:03:49 +03:00
2012-09-22 18:10:15 +03:00
//icons [fort is present?][build limit reached?] -> index of icon in def files
int icons [ 2 ] [ 2 ] ;
2013-04-22 22:51:22 +03:00
std : : string iconSmall [ 2 ] [ 2 ] ; /// icon names used during loading
std : : string iconLarge [ 2 ] [ 2 ] ;
2014-04-24 22:36:10 +03:00
std : : string tavernVideo ;
2012-09-05 15:49:23 +03:00
std : : string musicTheme ;
std : : string townBackground ;
2014-04-24 22:36:10 +03:00
std : : string guildBackground ;
2012-09-05 15:49:23 +03:00
std : : string guildWindow ;
std : : string buildingsIcons ;
2012-09-02 13:33:41 +03:00
std : : string hallBackground ;
2012-09-05 15:49:23 +03:00
/// vector[row][column] = list of buildings in this slot
2013-02-11 22:11:34 +03:00
std : : vector < std : : vector < std : : vector < BuildingID > > > hallSlots ;
2012-09-05 15:49:23 +03:00
/// 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 ;
2012-09-02 13:33:41 +03:00
2012-10-05 21:03:49 +03:00
std : : string siegePrefix ;
std : : vector < Point > siegePositions ;
2013-02-11 02:24:57 +03:00
CreatureID siegeShooter ; // shooter creature ID
2012-10-05 21:03:49 +03:00
2012-09-02 13:33:41 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2017-07-31 15:35:42 +02:00
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 ;
2012-09-02 13:33:41 +03:00
}
} clientInfo ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
2017-07-31 15:35:42 +02:00
h & names ;
h & faction ;
h & creatures ;
h & dwellings ;
h & dwellingNames ;
h & buildings ;
h & hordeLvl ;
h & mageLevel ;
h & primaryRes ;
h & warMachine ;
h & clientInfo ;
h & moatDamage ;
2016-01-28 00:35:01 +02:00
if ( version > = 758 )
{
h & moatHexes ;
}
else if ( ! h . saving )
{
moatHexes = defaultMoatHexes ( ) ;
}
h & defaultTavernChance ;
2012-09-02 13:33:41 +03:00
}
2020-10-25 00:04:34 +02:00
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
2009-04-16 14:14:13 +03:00
} ;
2013-04-21 15:49:26 +03:00
class DLL_LINKAGE CTownHandler : public IHandlerBase
2009-04-16 14:14:13 +03:00
{
2013-12-02 14:58:02 +03:00
struct BuildingRequirementsHelper
{
JsonNode json ;
CBuilding * building ;
2016-11-13 12:38:42 +02:00
CTown * town ;
2013-12-02 14:58:02 +03:00
} ;
2018-07-16 14:16:55 +02:00
std : : map < CTown * , JsonNode > warMachinesToLoad ;
2013-12-02 14:58:02 +03:00
std : : vector < BuildingRequirementsHelper > requirementsToLoad ;
2020-09-24 09:10:32 +02:00
const static ETerrainType : : EETerrainType defaultGoodTerrain = ETerrainType : : EETerrainType : : GRASS ;
const static ETerrainType : : EETerrainType defaultEvilTerrain = ETerrainType : : EETerrainType : : LAVA ;
const static ETerrainType : : EETerrainType defaultNeutralTerrain = ETerrainType : : EETerrainType : : ROUGH ;
2013-12-02 14:58:02 +03:00
void initializeRequirements ( ) ;
2018-07-16 14:16:55 +02:00
void initializeWarMachines ( ) ;
2013-12-02 14:58:02 +03:00
2012-09-02 13:33:41 +03:00
/// loads CBuilding's into town
2016-11-13 12:38:42 +02:00
void loadBuildingRequirements ( CBuilding * building , const JsonNode & source ) ;
void loadBuilding ( CTown * town , const std : : string & stringID , const JsonNode & source ) ;
void loadBuildings ( CTown * town , const JsonNode & source ) ;
2012-09-02 13:33:41 +03:00
/// loads CStructure's into town
2013-12-02 14:58:02 +03:00
void loadStructure ( CTown & town , const std : : string & stringID , const JsonNode & source ) ;
2012-09-02 13:33:41 +03:00
void loadStructures ( CTown & town , const JsonNode & source ) ;
/// loads town hall vector (hallSlots)
void loadTownHall ( CTown & town , const JsonNode & source ) ;
2012-10-05 21:03:49 +03:00
void loadSiegeScreen ( CTown & town , const JsonNode & source ) ;
2012-09-02 13:33:41 +03:00
2012-09-05 15:49:23 +03:00
void loadClientData ( CTown & town , const JsonNode & source ) ;
2018-07-16 14:16:55 +02:00
void loadTown ( CTown * town , const JsonNode & source ) ;
2012-09-02 13:33:41 +03:00
2012-09-21 00:28:18 +03:00
void loadPuzzle ( CFaction & faction , const JsonNode & source ) ;
2020-09-24 09:10:32 +02:00
ETerrainType : : EETerrainType getDefaultTerrainForAlignment ( EAlignment : : EAlignment aligment ) const ;
2015-08-24 10:55:45 +02:00
CFaction * loadFromJson ( const JsonNode & data , const std : : string & identifier ) ;
2012-09-05 15:49:23 +03:00
2016-11-13 12:38:42 +02:00
void loadRandomFaction ( ) ;
2020-10-02 23:55:46 +02:00
2020-10-07 14:12:32 +02:00
public :
template < typename R , typename K >
static R getMappedValue ( const K key , const R defval , const std : : map < K , R > & map , bool required = true ) ;
2020-10-02 23:55:46 +02:00
template < typename R >
2020-10-07 14:12:32 +02:00
static R getMappedValue ( const JsonNode & node , const R defval , const std : : map < std : : string , R > & map , bool required = true ) ;
2020-10-02 23:55:46 +02:00
2013-04-21 15:49:26 +03:00
std : : vector < ConstTransitivePtr < CFaction > > factions ;
2009-04-16 14:14:13 +03:00
2016-11-13 12:38:42 +02:00
CTown * randomTown ;
2012-09-02 13:33:41 +03:00
CTownHandler ( ) ; //c-tor, set pointer in VLC to this
2013-04-21 19:38:31 +03:00
~ CTownHandler ( ) ;
2012-09-02 13:33:41 +03:00
2013-04-21 15:49:26 +03:00
std : : vector < JsonNode > loadLegacyData ( size_t dataSize ) 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 ;
2016-11-13 12:38:42 +02:00
void loadCustom ( ) override ;
2013-12-02 14:58:02 +03:00
void afterLoadFinalization ( ) override ;
2013-04-21 15:49:26 +03:00
std : : vector < bool > getDefaultAllowed ( ) const override ;
2014-10-30 14:03:53 +02:00
std : : set < TFaction > getAllowedFactions ( bool withTown = true ) const ;
2012-11-20 20:53:45 +03:00
2016-02-14 13:22:46 +02:00
//json serialization helper
static si32 decodeFaction ( const std : : string & identifier ) ;
//json serialization helper
static std : : string encodeFaction ( const si32 index ) ;
2009-04-16 14:14:13 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2013-04-21 15:49:26 +03:00
h & factions ;
2016-11-13 12:38:42 +02:00
if ( version > = 770 )
{
h & randomTown ;
}
else if ( ! h . saving )
{
loadRandomFaction ( ) ;
}
2009-04-16 14:14:13 +03:00
}
} ;