2014-06-05 19:52:14 +03:00
/*
2014-06-05 20:26:50 +03:00
* CGTownInstance . h , part of VCMI engine
2014-06-05 19:52:14 +03:00
*
* 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
*
*/
2017-07-13 10:26:03 +02:00
# pragma once
2023-06-02 20:47:37 +02:00
# include "IMarket.h"
2023-04-26 20:55:56 +02:00
# include "CGDwelling.h"
# include "CGTownBuilding.h"
2017-07-13 10:26:03 +02:00
# include "../CTownHandler.h" // For CTown
2014-06-05 19:52:14 +03:00
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_BEGIN
2014-06-05 19:52:14 +03:00
class CCastleEvent ;
2023-03-23 17:49:33 +02:00
struct DamageRange ;
2014-06-05 19:52:14 +03:00
class DLL_LINKAGE CTownAndVisitingHero : public CBonusSystemNode
{
public :
CTownAndVisitingHero ( ) ;
} ;
struct DLL_LINKAGE GrowthInfo
{
struct Entry
{
int count ;
std : : string description ;
Entry ( const std : : string & format , int _count ) ;
2023-02-12 22:39:17 +02:00
Entry ( int subID , const BuildingID & building , int _count ) ;
Entry ( int _count , std : : string fullDescription ) ;
2014-06-05 19:52:14 +03:00
} ;
std : : vector < Entry > entries ;
int totalGrowth ( ) const ;
} ;
2023-06-06 18:19:30 +02:00
class DLL_LINKAGE CGTownInstance : public CGDwelling , public IShipyard , public IMarket , public INativeTerrainProvider , public ICreatureUpgrader
2014-06-05 19:52:14 +03:00
{
2023-09-27 23:57:05 +02:00
std : : string nameTextId ; // name of town
2014-06-05 19:52:14 +03:00
public :
2023-06-07 00:55:21 +02:00
using CGDwelling : : getPosition ;
2014-06-05 19:52:14 +03:00
enum EFortLevel { NONE = 0 , FORT = 1 , CITADEL = 2 , CASTLE = 3 } ;
CTownAndVisitingHero townAndVis ;
const CTown * town ;
si32 builded ; //how many buildings has been built this turn
si32 destroyed ; //how many buildings has been destroyed this turn
ConstTransitivePtr < CGHeroInstance > garrisonHero , visitingHero ;
ui32 identifier ; //special identifier from h3m (only > RoE maps)
2023-04-02 18:56:10 +02:00
PlayerColor alignmentToPlayer ; // if set to non-neutral, random town will have same faction as specified player
2021-01-14 00:02:13 +02:00
std : : set < BuildingID > forbiddenBuildings ;
std : : set < BuildingID > builtBuildings ;
std : : set < BuildingID > overriddenBuildings ; ///buildings which bonuses are overridden and should not be applied
2014-06-05 19:52:14 +03:00
std : : vector < CGTownBuilding * > bonusingBuildings ;
std : : vector < SpellID > possibleSpells , obligatorySpells ;
std : : vector < std : : vector < SpellID > > spells ; //spells[level] -> vector of spells, first will be available in guild
std : : list < CCastleEvent > events ;
std : : pair < si32 , si32 > bonusValue ; //var to store town bonuses (rampart = resources from mystic pond);
//////////////////////////////////////////////////////////////////////////
2024-01-20 20:34:51 +02:00
template < typename Handler > void serialize ( Handler & h )
2014-06-05 19:52:14 +03:00
{
h & static_cast < CGDwelling & > ( * this ) ;
2023-09-27 23:57:05 +02:00
h & nameTextId ;
2017-07-31 15:35:42 +02:00
h & builded ;
h & destroyed ;
h & identifier ;
h & garrisonHero ;
h & visitingHero ;
2023-04-02 18:56:10 +02:00
h & alignmentToPlayer ;
2017-07-31 15:35:42 +02:00
h & forbiddenBuildings ;
h & builtBuildings ;
h & bonusValue ;
h & possibleSpells ;
h & obligatorySpells ;
h & spells ;
h & events ;
h & bonusingBuildings ;
2023-05-07 02:02:52 +02:00
for ( auto * bonusingBuilding : bonusingBuildings )
bonusingBuilding - > town = this ;
2023-11-04 18:54:15 +02:00
if ( h . saving )
{
CFaction * faction = town ? town - > faction : nullptr ;
h & faction ;
}
else
{
2023-11-04 19:25:50 +02:00
CFaction * faction = nullptr ;
2023-11-04 18:54:15 +02:00
h & faction ;
town = faction ? faction - > town : nullptr ;
}
2017-07-31 15:35:42 +02:00
h & townAndVis ;
2014-06-05 19:52:14 +03:00
BONUS_TREE_DESERIALIZATION_FIX
2023-04-02 12:06:16 +02:00
if ( town )
2014-06-05 19:52:14 +03:00
{
2023-04-02 12:06:16 +02:00
vstd : : erase_if ( builtBuildings , [ this ] ( BuildingID building ) - > bool
2014-06-05 19:52:14 +03:00
{
2023-04-02 12:06:16 +02:00
if ( ! town - > buildings . count ( building ) | | ! town - > buildings . at ( building ) )
{
2023-09-27 23:57:05 +02:00
logGlobal - > error ( " #1444-like issue in CGTownInstance::serialize. From town %s at %s removing the bogus builtBuildings item %s " , nameTextId , pos . toString ( ) , building ) ;
2023-04-02 12:06:16 +02:00
return true ;
}
return false ;
} ) ;
}
2020-10-07 14:12:32 +02:00
2022-06-20 16:39:50 +02:00
h & overriddenBuildings ;
2021-09-12 13:30:54 +02:00
2021-03-23 16:47:07 +02:00
if ( ! h . saving )
this - > setNodeType ( CBonusSystemNode : : TOWN ) ;
2014-06-05 19:52:14 +03:00
}
//////////////////////////////////////////////////////////////////////////
2022-11-06 01:26:13 +02:00
CBonusSystemNode & whatShouldBeAttached ( ) override ;
2014-06-05 19:52:14 +03:00
std : : string nodeName ( ) const override ;
void updateMoraleBonusFromArmy ( ) override ;
void deserializationFix ( ) ;
void recreateBuildingsBonuses ( ) ;
void setVisitingHero ( CGHeroInstance * h ) ;
void setGarrisonedHero ( CGHeroInstance * h ) ;
const CArmedInstance * getUpperArmy ( ) const ; //garrisoned hero if present or the town itself
2023-01-04 15:17:50 +02:00
std : : string getNameTranslated ( ) const ;
2023-11-26 18:53:34 +02:00
std : : string getNameTextID ( ) const ;
2023-09-27 23:57:05 +02:00
void setNameTextId ( const std : : string & newName ) ;
2023-01-04 15:17:50 +02:00
2014-06-05 19:52:14 +03:00
//////////////////////////////////////////////////////////////////////////
2015-10-12 15:47:10 +02:00
bool passableFor ( PlayerColor color ) const override ;
2014-06-24 02:26:36 +03:00
//int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated
2016-01-31 17:01:58 +02:00
int getSightRadius ( ) const override ; //returns sight distance
2023-04-20 19:20:51 +02:00
BoatId getBoatType ( ) const override ; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
2015-10-12 15:47:10 +02:00
void getOutOffsets ( std : : vector < int3 > & offsets ) const override ; //offsets to obj pos when we boat can be placed. Parameter will be cleared
2023-06-07 00:55:21 +02:00
EGeneratorState shipyardStatus ( ) const override ;
const IObjectInterface * getObject ( ) const override ;
2014-06-05 19:52:14 +03:00
int getMarketEfficiency ( ) const override ; //=market count
2023-08-19 20:43:50 +02:00
bool allowsTrade ( EMarketMode mode ) const override ;
2023-11-08 17:49:08 +02:00
std : : vector < TradeItemBuy > availableItemsIds ( EMarketMode mode ) const override ;
2014-06-05 19:52:14 +03:00
void updateAppearance ( ) ;
//////////////////////////////////////////////////////////////////////////
2015-10-12 15:47:10 +02:00
bool needsLastStack ( ) const override ;
2014-06-05 19:52:14 +03:00
CGTownInstance : : EFortLevel fortLevel ( ) const ;
int hallLevel ( ) const ; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
int mageGuildLevel ( ) const ; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
int getHordeLevel ( const int & HID ) const ; //HID - 0 or 1; returns creature level or -1 if that horde structure is not present
int creatureGrowth ( const int & level ) const ;
GrowthInfo getGrowthInfo ( int level ) const ;
bool hasFort ( ) const ;
bool hasCapitol ( ) const ;
2023-05-02 02:44:09 +02:00
std : : vector < const CGTownBuilding * > getBonusingBuildings ( BuildingSubID : : EBuildingSubID subId ) const ;
2020-10-15 14:03:01 +02:00
bool hasBuiltSomeTradeBuilding ( ) const ;
2020-10-02 23:55:46 +02:00
//checks if special building with type buildingID is constructed
bool hasBuilt ( BuildingSubID : : EBuildingSubID buildingID ) const ;
2014-06-05 19:52:14 +03:00
//checks if building is constructed and town has same subID
2023-02-12 22:39:17 +02:00
bool hasBuilt ( const BuildingID & buildingID ) const ;
2023-11-02 17:12:58 +02:00
bool hasBuilt ( const BuildingID & buildingID , FactionID townID ) const ;
2020-10-02 23:55:46 +02:00
2023-02-12 22:39:17 +02:00
TResources getBuildingCost ( const BuildingID & buildingID ) const ;
2014-06-05 19:52:14 +03:00
TResources dailyIncome ( ) const ; //calculates daily income of this town
int spellsAtLevel ( int level , bool checkGuild ) const ; //levels are counted from 1 (1 - 5)
bool armedGarrison ( ) const ; //true if town has creatures in garrison or garrisoned hero
int getTownLevel ( ) const ;
2023-02-12 22:39:17 +02:00
CBuilding : : TRequired genBuildingRequirements ( const BuildingID & build , bool deep = false ) const ;
2014-08-07 19:40:22 +03:00
2016-02-21 21:23:47 +02:00
void mergeGarrisonOnSiege ( ) const ; // merge garrison into army of visiting hero
2023-02-12 22:39:17 +02:00
void removeCapitols ( const PlayerColor & owner ) const ;
2016-02-22 02:33:15 +02:00
void clearArmy ( ) const ;
2020-10-02 23:55:46 +02:00
void addHeroToStructureVisitors ( const CGHeroInstance * h , si64 structureInstanceID ) const ; //hero must be visiting or garrisoned in town
2023-08-19 23:22:31 +02:00
void deleteTownBonus ( BuildingID bid ) ;
2014-06-05 19:52:14 +03:00
2023-01-16 18:28:05 +02:00
/// Returns damage range for secondary towers of this town
2023-03-23 17:49:33 +02:00
DamageRange getTowerDamageRange ( ) const ;
2023-01-16 18:28:05 +02:00
/// Returns damage range for central tower(keep) of this town
2023-03-23 17:49:33 +02:00
DamageRange getKeepDamageRange ( ) const ;
2023-01-16 18:28:05 +02:00
2023-04-09 17:26:32 +02:00
const CTown * getTown ( ) const ;
/// INativeTerrainProvider
FactionID getFaction ( ) const override ;
TerrainId getNativeTerrain ( ) const override ;
2016-11-13 12:38:42 +02:00
2024-01-01 16:37:48 +02:00
CGTownInstance ( IGameCallback * cb ) ;
2014-06-05 19:52:14 +03:00
virtual ~ CGTownInstance ( ) ;
///IObjectInterface overrides
2016-09-09 19:30:36 +02:00
void newTurn ( CRandomGenerator & rand ) const override ;
2014-06-05 19:52:14 +03:00
void onHeroVisit ( const CGHeroInstance * h ) const override ;
void onHeroLeave ( const CGHeroInstance * h ) const override ;
2016-09-09 19:30:36 +02:00
void initObj ( CRandomGenerator & rand ) override ;
2023-10-25 12:50:11 +02:00
void pickRandomObject ( CRandomGenerator & rand ) override ;
2021-10-29 10:45:10 +02:00
void battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const override ;
2014-06-24 20:39:36 +03:00
std : : string getObjectName ( ) const override ;
2017-05-28 15:23:42 +02:00
2023-06-06 18:19:30 +02:00
void fillUpgradeInfo ( UpgradeInfo & info , const CStackInstance & stack ) const override ;
2017-05-28 15:23:42 +02:00
void afterAddToMap ( CMap * map ) override ;
2022-09-17 13:04:01 +02:00
void afterRemoveFromMap ( CMap * map ) override ;
2020-10-15 14:03:01 +02:00
2021-08-19 00:45:28 +02:00
inline bool isBattleOutsideTown ( const CGHeroInstance * defendingHero ) const
2021-03-23 16:47:07 +02:00
{
return defendingHero & & garrisonHero & & defendingHero ! = garrisonHero ;
}
2014-06-05 19:52:14 +03:00
protected :
2023-11-06 18:27:16 +02:00
void setPropertyDer ( ObjProperty what , ObjPropertyID identifier ) override ;
2016-02-22 01:37:19 +02:00
void serializeJsonOptions ( JsonSerializeFormat & handler ) override ;
2023-04-30 22:14:25 +02:00
void blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const override ;
2020-10-15 14:03:01 +02:00
2017-10-07 16:42:33 +02:00
private :
2023-10-25 12:50:11 +02:00
FactionID randomizeFaction ( CRandomGenerator & rand ) ;
2023-02-12 22:39:17 +02:00
void setOwner ( const PlayerColor & owner ) const ;
void onTownCaptured ( const PlayerColor & winner ) const ;
2017-10-07 16:42:33 +02:00
int getDwellingBonus ( const std : : vector < CreatureID > & creatureIds , const std : : vector < ConstTransitivePtr < CGDwelling > > & dwellings ) const ;
2020-10-15 14:03:01 +02:00
bool townEnvisagesBuilding ( BuildingSubID : : EBuildingSubID bid ) const ;
2023-08-19 23:22:31 +02:00
bool isBonusingBuildingAdded ( BuildingID bid ) const ;
2021-01-14 00:02:13 +02:00
void initOverriddenBids ( ) ;
2023-04-30 01:58:43 +02:00
void addTownBonuses ( CRandomGenerator & rand ) ;
2014-06-05 19:52:14 +03:00
} ;
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_END