2017-07-13 10:26:03 +02:00
/*
* CTownHandler . cpp , 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
*
*/
2011-12-14 00:23:17 +03:00
# include "StdInc.h"
2007-07-26 15:00:18 +03:00
# include "CTownHandler.h"
2011-12-14 00:23:17 +03:00
2012-08-02 14:03:26 +03:00
# include "VCMI_Lib.h"
2008-12-22 19:48:41 +02:00
# include "CGeneralTextHandler.h"
2012-08-02 14:03:26 +03:00
# include "JsonNode.h"
2023-08-19 23:22:31 +02:00
# include "constants/StringConstants.h"
2013-12-13 21:27:54 +03:00
# include "CCreatureHandler.h"
2012-12-17 15:55:29 +03:00
# include "CHeroHandler.h"
2012-12-15 11:47:02 +03:00
# include "CArtHandler.h"
2023-03-15 21:34:29 +02:00
# include "GameSettings.h"
2023-05-15 21:22:42 +02:00
# include "TerrainHandler.h"
2015-02-02 10:25:26 +02:00
# include "spells/CSpellHandler.h"
2013-07-28 17:49:50 +03:00
# include "filesystem/Filesystem.h"
2023-05-01 19:29:53 +02:00
# include "bonuses/Bonus.h"
2023-04-30 16:35:15 +02:00
# include "bonuses/Propagators.h"
2023-04-05 02:26:29 +02:00
# include "ResourceSet.h"
2023-06-02 20:47:37 +02:00
# include "mapObjectConstructors/AObjectTypeHandler.h"
# include "mapObjectConstructors/CObjectClassesHandler.h"
2023-07-30 19:12:25 +02:00
# include "modding/IdentifierStorage.h"
# include "modding/ModScope.h"
2009-04-15 17:03:31 +03:00
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_BEGIN
2013-03-02 19:55:51 +03:00
const int NAMES_PER_TOWN = 16 ; // number of town names per faction in H3 files. Json can define any number
2020-10-07 14:12:32 +02:00
const std : : map < std : : string , CBuilding : : EBuildMode > CBuilding : : MODES =
2016-11-27 21:07:01 +02:00
{
2020-10-07 14:12:32 +02:00
{ " normal " , CBuilding : : BUILD_NORMAL } ,
{ " auto " , CBuilding : : BUILD_AUTO } ,
{ " special " , CBuilding : : BUILD_SPECIAL } ,
{ " grail " , CBuilding : : BUILD_GRAIL }
} ;
2016-11-27 21:07:01 +02:00
2020-10-07 14:12:32 +02:00
const std : : map < std : : string , CBuilding : : ETowerHeight > CBuilding : : TOWER_TYPES =
{
{ " low " , CBuilding : : HEIGHT_LOW } ,
{ " average " , CBuilding : : HEIGHT_AVERAGE } ,
{ " high " , CBuilding : : HEIGHT_HIGH } ,
{ " skyship " , CBuilding : : HEIGHT_SKYSHIP }
} ;
2016-11-27 21:07:01 +02:00
2023-01-04 15:17:50 +02:00
std : : string CBuilding : : getJsonKey ( ) const
2012-09-02 13:33:41 +03:00
{
2023-01-18 23:56:01 +02:00
return modScope + ' : ' + identifier ; ;
2023-01-04 15:17:50 +02:00
}
std : : string CBuilding : : getNameTranslated ( ) const
{
return VLC - > generaltexth - > translate ( getNameTextID ( ) ) ;
}
std : : string CBuilding : : getDescriptionTranslated ( ) const
{
return VLC - > generaltexth - > translate ( getDescriptionTextID ( ) ) ;
}
2023-07-19 21:25:52 +02:00
std : : string CBuilding : : getBaseTextID ( ) const
{
return TextIdentifier ( " building " , modScope , town - > faction - > identifier , identifier ) . get ( ) ;
}
2023-01-04 15:17:50 +02:00
std : : string CBuilding : : getNameTextID ( ) const
{
2023-07-19 21:25:52 +02:00
return TextIdentifier ( getBaseTextID ( ) , " name " ) . get ( ) ;
2012-09-02 13:33:41 +03:00
}
2023-01-04 15:17:50 +02:00
std : : string CBuilding : : getDescriptionTextID ( ) const
2012-09-02 13:33:41 +03:00
{
2023-07-19 21:25:52 +02:00
return TextIdentifier ( getBaseTextID ( ) , " description " ) . get ( ) ;
2012-09-05 15:49:23 +03:00
}
2013-02-11 22:11:34 +03:00
BuildingID CBuilding : : getBase ( ) const
2012-09-05 15:49:23 +03:00
{
const CBuilding * build = this ;
2023-08-19 23:22:31 +02:00
while ( build - > upgrade ! = BuildingID : : NONE )
2013-12-07 15:23:43 +03:00
{
2013-09-07 00:57:16 +03:00
build = build - > town - > buildings . at ( build - > upgrade ) ;
2013-12-07 15:23:43 +03:00
}
2012-09-05 15:49:23 +03:00
return build - > bid ;
}
2023-03-13 23:26:44 +02:00
si32 CBuilding : : getDistance ( const BuildingID & buildID ) const
2012-09-05 15:49:23 +03:00
{
2013-09-07 00:57:16 +03:00
const CBuilding * build = town - > buildings . at ( buildID ) ;
2012-09-05 15:49:23 +03:00
int distance = 0 ;
2023-08-19 23:22:31 +02:00
while ( build - > upgrade ! = BuildingID : : NONE & & build ! = this )
2012-09-05 15:49:23 +03:00
{
2013-09-07 00:57:16 +03:00
build = build - > town - > buildings . at ( build - > upgrade ) ;
2012-09-05 15:49:23 +03:00
distance + + ;
}
if ( build = = this )
return distance ;
return - 1 ;
2012-09-02 13:33:41 +03:00
}
2023-03-13 23:26:44 +02:00
void CBuilding : : addNewBonus ( const std : : shared_ptr < Bonus > & b , BonusList & bonusList ) const
2020-10-07 14:12:32 +02:00
{
2021-01-14 00:02:13 +02:00
bonusList . push_back ( b ) ;
}
2020-10-07 14:12:32 +02:00
2013-04-21 17:08:46 +03:00
CFaction : : ~ CFaction ( )
{
2023-08-02 17:19:23 +02:00
if ( town )
{
delete town ;
town = nullptr ;
}
2013-04-21 17:08:46 +03:00
}
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
int32_t CFaction : : getIndex ( ) const
{
return index ;
}
int32_t CFaction : : getIconIndex ( ) const
{
return index ; //???
}
2023-01-18 23:56:01 +02:00
std : : string CFaction : : getJsonKey ( ) const
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
{
2023-01-18 23:56:01 +02:00
return modScope + ' : ' + identifier ; ;
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
}
void CFaction : : registerIcons ( const IconRegistar & cb ) const
{
if ( town )
{
auto & info = town - > clientInfo ;
2022-11-29 14:47:51 +02:00
cb ( info . icons [ 0 ] [ 0 ] , 0 , " ITPT " , info . iconLarge [ 0 ] [ 0 ] ) ;
cb ( info . icons [ 0 ] [ 1 ] , 0 , " ITPT " , info . iconLarge [ 0 ] [ 1 ] ) ;
cb ( info . icons [ 1 ] [ 0 ] , 0 , " ITPT " , info . iconLarge [ 1 ] [ 0 ] ) ;
cb ( info . icons [ 1 ] [ 1 ] , 0 , " ITPT " , info . iconLarge [ 1 ] [ 1 ] ) ;
cb ( info . icons [ 0 ] [ 0 ] + 2 , 0 , " ITPA " , info . iconSmall [ 0 ] [ 0 ] ) ;
cb ( info . icons [ 0 ] [ 1 ] + 2 , 0 , " ITPA " , info . iconSmall [ 0 ] [ 1 ] ) ;
cb ( info . icons [ 1 ] [ 0 ] + 2 , 0 , " ITPA " , info . iconSmall [ 1 ] [ 0 ] ) ;
cb ( info . icons [ 1 ] [ 1 ] + 2 , 0 , " ITPA " , info . iconSmall [ 1 ] [ 1 ] ) ;
cb ( index , 1 , " CPRSMALL " , info . towerIconSmall ) ;
cb ( index , 1 , " TWCRPORT " , info . towerIconLarge ) ;
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
}
}
2023-01-04 15:17:50 +02:00
std : : string CFaction : : getNameTranslated ( ) const
{
return VLC - > generaltexth - > translate ( getNameTextID ( ) ) ;
}
std : : string CFaction : : getNameTextID ( ) const
{
return TextIdentifier ( " faction " , modScope , identifier , " name " ) . get ( ) ;
}
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
FactionID CFaction : : getId ( ) const
{
return FactionID ( index ) ;
}
2023-04-05 02:50:29 +02:00
FactionID CFaction : : getFaction ( ) const
{
return FactionID ( index ) ;
}
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
bool CFaction : : hasTown ( ) const
{
return town ! = nullptr ;
}
2023-04-04 12:36:42 +02:00
EAlignment CFaction : : getAlignment ( ) const
{
return alignment ;
}
2023-08-18 12:38:19 +02:00
BoatId CFaction : : getBoatType ( ) const
2023-06-19 21:01:18 +02:00
{
2023-08-20 17:16:00 +02:00
return boatType ;
2023-06-19 21:01:18 +02:00
}
2023-04-02 02:07:39 +02:00
TerrainId CFaction : : getNativeTerrain ( ) const
{
return nativeTerrain ;
}
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
void CFaction : : updateFrom ( const JsonNode & data )
{
}
void CFaction : : serializeJson ( JsonSerializeFormat & handler )
{
}
2013-04-21 17:08:46 +03:00
CTown : : CTown ( )
2023-03-20 13:02:09 +02:00
: faction ( nullptr ) , mageLevel ( 0 ) , primaryRes ( 0 ) , moatAbility ( SpellID : : NONE ) , defaultTavernChance ( 0 )
2013-04-21 17:08:46 +03:00
{
}
CTown : : ~ CTown ( )
{
2013-06-29 16:05:48 +03:00
for ( auto & build : buildings )
2013-04-21 17:08:46 +03:00
build . second . dellNull ( ) ;
2013-06-29 16:05:48 +03:00
for ( auto & str : clientInfo . structures )
2013-04-21 19:38:31 +03:00
str . dellNull ( ) ;
2013-04-21 17:08:46 +03:00
}
2023-01-04 15:17:50 +02:00
std : : string CTown : : getRandomNameTranslated ( size_t index ) const
2016-11-13 12:38:42 +02:00
{
2023-01-04 15:17:50 +02:00
return VLC - > generaltexth - > translate ( getRandomNameTextID ( index ) ) ;
}
std : : string CTown : : getRandomNameTextID ( size_t index ) const
{
2023-01-18 23:56:01 +02:00
return TextIdentifier ( " faction " , faction - > modScope , faction - > identifier , " randomName " , index ) . get ( ) ;
2023-01-04 15:17:50 +02:00
}
size_t CTown : : getRandomNamesCount ( ) const
{
return namesCount ;
2016-11-13 12:38:42 +02:00
}
std : : string CTown : : getBuildingScope ( ) const
{
if ( faction = = nullptr )
//no faction == random faction
return " building " ;
else
2023-01-04 15:17:50 +02:00
return " building. " + faction - > getJsonKey ( ) ;
2016-11-13 12:38:42 +02:00
}
std : : set < si32 > CTown : : getAllBuildings ( ) const
{
std : : set < si32 > res ;
for ( const auto & b : buildings )
{
res . insert ( b . first . num ) ;
}
2019-01-19 12:52:02 +02:00
return res ;
2016-11-13 12:38:42 +02:00
}
2020-10-15 14:03:01 +02:00
const CBuilding * CTown : : getSpecialBuilding ( BuildingSubID : : EBuildingSubID subID ) const
{
for ( const auto & kvp : buildings )
{
if ( kvp . second - > subId = = subID )
return buildings . at ( kvp . first ) ;
}
return nullptr ;
}
2023-08-19 23:22:31 +02:00
BuildingID CTown : : getBuildingType ( BuildingSubID : : EBuildingSubID subID ) const
2020-10-15 14:03:01 +02:00
{
2023-03-13 23:26:44 +02:00
const auto * building = getSpecialBuilding ( subID ) ;
2020-10-15 14:03:01 +02:00
return building = = nullptr ? BuildingID : : NONE : building - > bid . num ;
}
2016-11-13 12:38:42 +02:00
2023-03-13 23:26:44 +02:00
std : : string CTown : : getGreeting ( BuildingSubID : : EBuildingSubID subID ) const
2020-10-25 00:04:34 +02:00
{
2023-03-13 23:26:44 +02:00
return CTownHandler : : getMappedValue < const std : : string , BuildingSubID : : EBuildingSubID > ( subID , std : : string ( ) , specialMessages , false ) ;
2020-10-25 00:04:34 +02:00
}
2023-03-13 23:26:44 +02:00
void CTown : : setGreeting ( BuildingSubID : : EBuildingSubID subID , const std : : string & message ) const
2020-10-25 00:04:34 +02:00
{
specialMessages . insert ( std : : pair < BuildingSubID : : EBuildingSubID , const std : : string > ( subID , message ) ) ;
}
2023-03-13 23:26:44 +02:00
CTownHandler : : CTownHandler ( ) :
randomTown ( new CTown ( ) ) ,
randomFaction ( new CFaction ( ) )
2008-06-30 03:06:41 +03:00
{
2023-01-04 15:17:50 +02:00
randomFaction - > town = randomTown ;
randomTown - > faction = randomFaction ;
randomFaction - > identifier = " random " ;
randomFaction - > modScope = " core " ;
2008-06-30 03:06:41 +03:00
}
2012-09-02 13:33:41 +03:00
2013-04-21 19:38:31 +03:00
CTownHandler : : ~ CTownHandler ( )
{
2016-11-13 12:38:42 +02:00
delete randomTown ;
2013-04-21 19:38:31 +03:00
}
2012-09-02 13:33:41 +03:00
JsonNode readBuilding ( CLegacyConfigParser & parser )
2008-12-22 19:48:41 +02:00
{
2012-09-02 13:33:41 +03:00
JsonNode ret ;
JsonNode & cost = ret [ " cost " ] ;
2012-09-05 15:49:23 +03:00
//note: this code will try to parse mithril as well but wil always return 0 for it
2013-06-29 16:05:48 +03:00
for ( const std : : string & resID : GameConstants : : RESOURCE_NAMES )
2012-09-02 13:33:41 +03:00
cost [ resID ] . Float ( ) = parser . readNumber ( ) ;
2013-04-11 22:24:14 +03:00
cost . Struct ( ) . erase ( " mithril " ) ; // erase mithril to avoid confusing validator
2012-09-02 13:33:41 +03:00
parser . endLine ( ) ;
2014-04-26 17:23:35 +03:00
2012-09-02 13:33:41 +03:00
return ret ;
2008-12-22 19:48:41 +02:00
}
2012-09-02 13:33:41 +03:00
2021-02-05 00:56:21 +02:00
TPropagatorPtr & CTownHandler : : emptyPropagator ( )
{
static TPropagatorPtr emptyProp ( nullptr ) ;
return emptyProp ;
}
2021-01-14 00:02:13 +02:00
2023-03-15 21:34:29 +02:00
std : : vector < JsonNode > CTownHandler : : loadLegacyData ( )
2007-07-26 15:00:18 +03:00
{
2023-03-15 21:34:29 +02:00
size_t dataSize = VLC - > settings ( ) - > getInteger ( EGameSettings : : TEXTS_FACTION ) ;
2013-04-21 15:49:26 +03:00
std : : vector < JsonNode > dest ( dataSize ) ;
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
objects . resize ( dataSize ) ;
2013-04-21 15:49:26 +03:00
auto getBuild = [ & ] ( size_t town , size_t building ) - > JsonNode &
{
return dest [ town ] [ " town " ] [ " buildings " ] [ EBuildingType : : names [ building ] ] ;
} ;
2023-09-01 23:26:14 +02:00
CLegacyConfigParser parser ( TextPath : : builtin ( " DATA/BUILDING.TXT " ) ) ;
2012-09-02 13:33:41 +03:00
parser . endLine ( ) ; // header
parser . endLine ( ) ;
2011-08-26 06:10:56 +03:00
2012-09-02 13:33:41 +03:00
//Unique buildings
2013-04-21 15:49:26 +03:00
for ( size_t town = 0 ; town < dataSize ; town + + )
2007-07-26 15:00:18 +03:00
{
2012-09-02 13:33:41 +03:00
parser . endLine ( ) ; //header
parser . endLine ( ) ;
int buildID = 17 ;
do
{
2013-04-21 15:49:26 +03:00
getBuild ( town , buildID ) = readBuilding ( parser ) ;
2012-09-02 13:33:41 +03:00
buildID + + ;
2011-08-20 07:48:23 +03:00
}
2012-09-02 13:33:41 +03:00
while ( ! parser . isNextEntryEmpty ( ) ) ;
}
// Common buildings
parser . endLine ( ) ; // header
parser . endLine ( ) ;
parser . endLine ( ) ;
int buildID = 0 ;
do
{
JsonNode building = readBuilding ( parser ) ;
2011-08-20 09:08:48 +03:00
2013-04-21 15:49:26 +03:00
for ( size_t town = 0 ; town < dataSize ; town + + )
getBuild ( town , buildID ) = building ;
2012-09-02 13:33:41 +03:00
buildID + + ;
}
while ( ! parser . isNextEntryEmpty ( ) ) ;
parser . endLine ( ) ; //header
parser . endLine ( ) ;
//Dwellings
2013-04-21 15:49:26 +03:00
for ( size_t town = 0 ; town < dataSize ; town + + )
2012-09-02 13:33:41 +03:00
{
parser . endLine ( ) ; //header
parser . endLine ( ) ;
2013-04-21 15:49:26 +03:00
for ( size_t i = 0 ; i < 14 ; i + + )
2012-09-02 13:33:41 +03:00
{
2013-04-21 15:49:26 +03:00
getBuild ( town , 30 + i ) = readBuilding ( parser ) ;
2008-01-19 13:55:04 +02:00
}
2012-09-02 13:33:41 +03:00
}
2012-10-05 16:11:26 +03:00
{
2023-09-01 23:26:14 +02:00
CLegacyConfigParser parser ( TextPath : : builtin ( " DATA/BLDGNEUT.TXT " ) ) ;
2012-10-05 16:11:26 +03:00
for ( int building = 0 ; building < 15 ; building + + )
{
std : : string name = parser . readString ( ) ;
std : : string descr = parser . readString ( ) ;
parser . endLine ( ) ;
2013-04-21 15:49:26 +03:00
for ( int j = 0 ; j < dataSize ; j + + )
2012-10-05 16:11:26 +03:00
{
2013-04-21 15:49:26 +03:00
getBuild ( j , building ) [ " name " ] . String ( ) = name ;
getBuild ( j , building ) [ " description " ] . String ( ) = descr ;
2012-10-05 16:11:26 +03:00
}
}
parser . endLine ( ) ; // silo
parser . endLine ( ) ; // blacksmith //unused entries
parser . endLine ( ) ; // moat
//shipyard with the ship
std : : string name = parser . readString ( ) ;
std : : string descr = parser . readString ( ) ;
parser . endLine ( ) ;
2013-04-21 15:49:26 +03:00
for ( int town = 0 ; town < dataSize ; town + + )
2012-10-05 16:11:26 +03:00
{
2013-04-21 15:49:26 +03:00
getBuild ( town , 20 ) [ " name " ] . String ( ) = name ;
getBuild ( town , 20 ) [ " description " ] . String ( ) = descr ;
2012-10-05 16:11:26 +03:00
}
//blacksmith
2013-04-21 15:49:26 +03:00
for ( int town = 0 ; town < dataSize ; town + + )
2012-10-05 16:11:26 +03:00
{
2013-04-21 15:49:26 +03:00
getBuild ( town , 16 ) [ " name " ] . String ( ) = parser . readString ( ) ;
getBuild ( town , 16 ) [ " description " ] . String ( ) = parser . readString ( ) ;
2012-10-05 16:11:26 +03:00
parser . endLine ( ) ;
}
}
{
2023-09-01 23:26:14 +02:00
CLegacyConfigParser parser ( TextPath : : builtin ( " DATA/BLDGSPEC.TXT " ) ) ;
2012-10-05 16:11:26 +03:00
2013-04-21 15:49:26 +03:00
for ( int town = 0 ; town < dataSize ; town + + )
2012-10-05 16:11:26 +03:00
{
for ( int build = 0 ; build < 9 ; build + + )
{
2013-04-21 15:49:26 +03:00
getBuild ( town , 17 + build ) [ " name " ] . String ( ) = parser . readString ( ) ;
getBuild ( town , 17 + build ) [ " description " ] . String ( ) = parser . readString ( ) ;
2012-10-05 16:11:26 +03:00
parser . endLine ( ) ;
}
2013-04-21 15:49:26 +03:00
getBuild ( town , 26 ) [ " name " ] . String ( ) = parser . readString ( ) ; // Grail
getBuild ( town , 26 ) [ " description " ] . String ( ) = parser . readString ( ) ;
2012-10-05 16:11:26 +03:00
parser . endLine ( ) ;
2013-04-21 15:49:26 +03:00
getBuild ( town , 15 ) [ " name " ] . String ( ) = parser . readString ( ) ; // Resource silo
getBuild ( town , 15 ) [ " description " ] . String ( ) = parser . readString ( ) ;
2012-10-05 16:11:26 +03:00
parser . endLine ( ) ;
}
}
{
2023-09-01 23:26:14 +02:00
CLegacyConfigParser parser ( TextPath : : builtin ( " DATA/DWELLING.TXT " ) ) ;
2012-10-05 16:11:26 +03:00
2013-04-21 15:49:26 +03:00
for ( int town = 0 ; town < dataSize ; town + + )
2012-10-05 16:11:26 +03:00
{
for ( int build = 0 ; build < 14 ; build + + )
{
2013-04-21 15:49:26 +03:00
getBuild ( town , 30 + build ) [ " name " ] . String ( ) = parser . readString ( ) ;
getBuild ( town , 30 + build ) [ " description " ] . String ( ) = parser . readString ( ) ;
2012-10-05 16:11:26 +03:00
parser . endLine ( ) ;
}
}
}
{
2023-09-01 23:26:14 +02:00
CLegacyConfigParser typeParser ( TextPath : : builtin ( " DATA/TOWNTYPE.TXT " ) ) ;
CLegacyConfigParser nameParser ( TextPath : : builtin ( " DATA/TOWNNAME.TXT " ) ) ;
2012-10-05 16:11:26 +03:00
size_t townID = 0 ;
do
{
2013-04-21 15:49:26 +03:00
dest [ townID ] [ " name " ] . String ( ) = typeParser . readString ( ) ;
2012-10-05 16:11:26 +03:00
2013-03-02 19:55:51 +03:00
for ( int i = 0 ; i < NAMES_PER_TOWN ; i + + )
2012-10-05 16:11:26 +03:00
{
JsonNode name ;
name . String ( ) = nameParser . readString ( ) ;
2013-04-21 15:49:26 +03:00
dest [ townID ] [ " town " ] [ " names " ] . Vector ( ) . push_back ( name ) ;
2012-10-05 16:11:26 +03:00
nameParser . endLine ( ) ;
}
townID + + ;
}
while ( typeParser . endLine ( ) ) ;
}
2013-04-21 15:49:26 +03:00
return dest ;
2012-09-02 13:33:41 +03:00
}
2023-03-13 23:26:44 +02:00
void CTownHandler : : loadBuildingRequirements ( CBuilding * building , const JsonNode & source , std : : vector < BuildingRequirementsHelper > & bidsToLoad ) const
2013-12-02 14:58:02 +03:00
{
if ( source . isNull ( ) )
return ;
2014-06-23 20:10:08 +03:00
BuildingRequirementsHelper hlp ;
2016-11-13 12:38:42 +02:00
hlp . building = building ;
hlp . town = building - > town ;
2014-06-23 20:10:08 +03:00
hlp . json = source ;
2021-01-14 00:02:13 +02:00
bidsToLoad . push_back ( hlp ) ;
2013-12-02 14:58:02 +03:00
}
2020-10-07 14:12:32 +02:00
template < typename R , typename K >
R CTownHandler : : getMappedValue ( const K key , const R defval , const std : : map < K , R > & map , bool required )
2020-10-02 23:55:46 +02:00
{
auto it = map . find ( key ) ;
if ( it ! = map . end ( ) )
return it - > second ;
if ( required )
logMod - > warn ( " Warning: Property: '%s' is unknown. Correct the typo or update VCMI. " , key ) ;
return defval ;
}
template < typename R >
2020-10-07 14:12:32 +02:00
R CTownHandler : : getMappedValue ( const JsonNode & node , const R defval , const std : : map < std : : string , R > & map , bool required )
2021-02-20 03:57:50 +02:00
{
2020-10-02 23:55:46 +02:00
if ( ! node . isNull ( ) & & node . getType ( ) = = JsonNode : : JsonType : : DATA_STRING )
2020-10-07 14:12:32 +02:00
return getMappedValue < R , std : : string > ( node . String ( ) , defval , map , required ) ;
2020-10-02 23:55:46 +02:00
return defval ;
}
2023-03-13 23:26:44 +02:00
void CTownHandler : : addBonusesForVanilaBuilding ( CBuilding * building ) const
2021-02-20 03:57:50 +02:00
{
2021-01-14 00:02:13 +02:00
std : : shared_ptr < Bonus > b ;
static TPropagatorPtr playerPropagator = std : : make_shared < CPropagatorNodeType > ( CBonusSystemNode : : ENodeTypes : : PLAYER ) ;
2023-04-29 13:46:51 +02:00
if ( building - > bid = = BuildingID : : TAVERN )
2021-02-20 03:57:50 +02:00
{
2023-05-04 20:23:44 +02:00
b = createBonus ( building , BonusType : : MORALE , + 1 ) ;
2021-01-14 00:02:13 +02:00
}
2023-04-29 13:46:51 +02:00
switch ( building - > subId )
2021-01-14 00:02:13 +02:00
{
2023-04-29 13:46:51 +02:00
case BuildingSubID : : BROTHERHOOD_OF_SWORD :
2023-05-04 20:23:44 +02:00
b = createBonus ( building , BonusType : : MORALE , + 2 ) ;
2023-04-29 13:46:51 +02:00
building - > overrideBids . insert ( BuildingID : : TAVERN ) ;
break ;
case BuildingSubID : : FOUNTAIN_OF_FORTUNE :
2023-05-04 20:23:44 +02:00
b = createBonus ( building , BonusType : : LUCK , + 2 ) ;
2023-04-29 13:46:51 +02:00
break ;
case BuildingSubID : : SPELL_POWER_GARRISON_BONUS :
2023-08-19 20:43:50 +02:00
b = createBonus ( building , BonusType : : PRIMARY_SKILL , + 2 , static_cast < int > ( PrimarySkill : : SPELL_POWER ) ) ;
2023-04-29 13:46:51 +02:00
break ;
case BuildingSubID : : ATTACK_GARRISON_BONUS :
2023-08-19 20:43:50 +02:00
b = createBonus ( building , BonusType : : PRIMARY_SKILL , + 2 , static_cast < int > ( PrimarySkill : : ATTACK ) ) ;
2023-04-29 13:46:51 +02:00
break ;
case BuildingSubID : : DEFENSE_GARRISON_BONUS :
2023-08-19 20:43:50 +02:00
b = createBonus ( building , BonusType : : PRIMARY_SKILL , + 2 , static_cast < int > ( PrimarySkill : : DEFENSE ) ) ;
2023-04-29 13:46:51 +02:00
break ;
case BuildingSubID : : LIGHTHOUSE :
2023-05-04 20:23:44 +02:00
b = createBonus ( building , BonusType : : MOVEMENT , + 500 , playerPropagator , 0 ) ;
2023-04-29 13:46:51 +02:00
break ;
2021-01-14 00:02:13 +02:00
}
2023-04-29 13:46:51 +02:00
2021-01-14 00:02:13 +02:00
if ( b )
building - > addNewBonus ( b , building - > buildingBonuses ) ;
}
2023-05-01 00:20:01 +02:00
std : : shared_ptr < Bonus > CTownHandler : : createBonus ( CBuilding * build , BonusType type , int val , int subtype ) const
2021-01-14 00:02:13 +02:00
{
2021-02-05 00:56:21 +02:00
return createBonus ( build , type , val , emptyPropagator ( ) , subtype ) ;
2021-01-14 00:02:13 +02:00
}
2023-05-01 00:20:01 +02:00
std : : shared_ptr < Bonus > CTownHandler : : createBonus ( CBuilding * build , BonusType type , int val , TPropagatorPtr & prop , int subtype ) const
2021-01-14 00:02:13 +02:00
{
std : : ostringstream descr ;
2023-01-04 15:17:50 +02:00
descr < < build - > getNameTranslated ( ) ;
2021-01-14 00:02:13 +02:00
return createBonusImpl ( build - > bid , type , val , prop , descr . str ( ) , subtype ) ;
}
2023-03-13 23:26:44 +02:00
std : : shared_ptr < Bonus > CTownHandler : : createBonusImpl ( const BuildingID & building ,
2023-05-01 00:20:01 +02:00
BonusType type ,
2023-03-13 23:26:44 +02:00
int val ,
TPropagatorPtr & prop ,
const std : : string & description ,
int subtype ) const
2021-01-14 00:02:13 +02:00
{
2023-05-01 00:20:01 +02:00
auto b = std : : make_shared < Bonus > ( BonusDuration : : PERMANENT , type , BonusSource : : TOWN_STRUCTURE , val , building , description , subtype ) ;
2021-01-14 00:02:13 +02:00
if ( prop )
b - > addPropagator ( prop ) ;
return b ;
}
void CTownHandler : : loadSpecialBuildingBonuses ( const JsonNode & source , BonusList & bonusList , CBuilding * building )
{
2023-03-13 23:26:44 +02:00
for ( const auto & b : source . Vector ( ) )
2021-01-14 00:02:13 +02:00
{
2023-01-04 15:17:50 +02:00
auto bonus = JsonUtils : : parseBuildingBonus ( b , building - > bid , building - > getNameTranslated ( ) ) ;
2021-01-14 00:02:13 +02:00
if ( bonus = = nullptr )
continue ;
2023-04-09 17:26:32 +02:00
bonus - > sid = Bonus : : getSid32 ( building - > town - > faction - > getIndex ( ) , building - > bid ) ;
2021-01-14 00:02:13 +02:00
//JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty.
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
if ( bonus - > propagator ! = nullptr
2021-01-14 00:02:13 +02:00
& & bonus - > propagator - > getPropagatorType ( ) = = CBonusSystemNode : : ENodeTypes : : UNKNOWN )
2021-02-05 00:56:21 +02:00
bonus - > addPropagator ( emptyPropagator ( ) ) ;
2021-01-14 00:02:13 +02:00
building - > addNewBonus ( bonus , bonusList ) ;
}
}
2016-11-13 12:38:42 +02:00
void CTownHandler : : loadBuilding ( CTown * town , const std : : string & stringID , const JsonNode & source )
2012-09-02 13:33:41 +03:00
{
2023-01-18 23:56:01 +02:00
assert ( stringID . find ( ' : ' ) = = std : : string : : npos ) ;
assert ( ! source . meta . empty ( ) ) ;
2023-03-13 23:26:44 +02:00
auto * ret = new CBuilding ( ) ;
2020-10-07 14:12:32 +02:00
ret - > bid = getMappedValue < BuildingID , std : : string > ( stringID , BuildingID : : NONE , MappedKeys : : BUILDING_NAMES_TO_TYPES , false ) ;
2023-05-02 02:44:09 +02:00
ret - > subId = BuildingSubID : : NONE ;
2020-10-02 23:55:46 +02:00
2023-04-29 13:46:51 +02:00
if ( ret - > bid = = BuildingID : : NONE & & ! source [ " id " ] . isNull ( ) )
{
2023-07-24 22:16:34 +02:00
// FIXME: A lot of false-positives with no clear way to handle them in mods
//logMod->warn("Building %s: id field is deprecated", stringID);
2020-10-02 23:55:46 +02:00
ret - > bid = source [ " id " ] . isNull ( ) ? BuildingID ( BuildingID : : NONE ) : BuildingID ( source [ " id " ] . Float ( ) ) ;
2023-04-29 13:46:51 +02:00
}
2020-10-02 23:55:46 +02:00
if ( ret - > bid = = BuildingID : : NONE )
2023-04-29 13:46:51 +02:00
logMod - > error ( " Building '%s' isn't recognized and won't work properly. Correct the typo or update VCMI. " , stringID ) ;
2020-10-02 23:55:46 +02:00
ret - > mode = ret - > bid = = BuildingID : : GRAIL
? CBuilding : : BUILD_GRAIL
2020-10-07 14:12:32 +02:00
: getMappedValue < CBuilding : : EBuildMode > ( source [ " mode " ] , CBuilding : : BUILD_NORMAL , CBuilding : : MODES ) ;
2020-10-02 23:55:46 +02:00
2023-04-29 13:46:51 +02:00
ret - > height = getMappedValue < CBuilding : : ETowerHeight > ( source [ " height " ] , CBuilding : : HEIGHT_NO_TOWER , CBuilding : : TOWER_TYPES ) ;
2012-09-02 13:33:41 +03:00
2013-12-02 14:58:02 +03:00
ret - > identifier = stringID ;
2023-01-18 23:56:01 +02:00
ret - > modScope = source . meta ;
2016-11-13 12:38:42 +02:00
ret - > town = town ;
2023-01-04 15:17:50 +02:00
2023-02-09 15:03:49 +02:00
VLC - > generaltexth - > registerString ( source . meta , ret - > getNameTextID ( ) , source [ " name " ] . String ( ) ) ;
VLC - > generaltexth - > registerString ( source . meta , ret - > getDescriptionTextID ( ) , source [ " description " ] . String ( ) ) ;
2023-01-04 15:17:50 +02:00
2012-09-02 13:33:41 +03:00
ret - > resources = TResources ( source [ " cost " ] ) ;
2014-04-26 17:23:35 +03:00
ret - > produce = TResources ( source [ " produce " ] ) ;
2021-01-14 00:02:13 +02:00
if ( ret - > bid = = BuildingID : : TAVERN )
addBonusesForVanilaBuilding ( ret ) ;
else if ( ret - > bid . IsSpecialOrGrail ( ) )
{
loadSpecialBuildingBonuses ( source [ " bonuses " ] , ret - > buildingBonuses , ret ) ;
if ( ret - > buildingBonuses . empty ( ) )
2023-04-29 13:46:51 +02:00
{
ret - > subId = getMappedValue < BuildingSubID : : EBuildingSubID > ( source [ " type " ] , BuildingSubID : : NONE , MappedKeys : : SPECIAL_BUILDINGS ) ;
2021-01-14 00:02:13 +02:00
addBonusesForVanilaBuilding ( ret ) ;
2023-04-29 13:46:51 +02:00
}
2021-01-14 00:02:13 +02:00
loadSpecialBuildingBonuses ( source [ " onVisitBonuses " ] , ret - > onVisitBonuses , ret ) ;
if ( ! ret - > onVisitBonuses . empty ( ) )
{
if ( ret - > subId = = BuildingSubID : : NONE )
ret - > subId = BuildingSubID : : CUSTOM_VISITING_BONUS ;
for ( auto & bonus : ret - > onVisitBonuses )
2023-01-04 15:17:50 +02:00
bonus - > sid = Bonus : : getSid32 ( ret - > town - > faction - > getIndex ( ) , ret - > bid ) ;
2021-01-14 00:02:13 +02:00
}
2023-04-30 01:58:43 +02:00
2023-04-30 22:14:25 +02:00
if ( source [ " type " ] . String ( ) = = " configurable " & & ret - > subId = = BuildingSubID : : NONE )
2023-04-30 01:58:43 +02:00
{
2023-05-02 12:45:53 +02:00
ret - > subId = BuildingSubID : : CUSTOM_VISITING_REWARD ;
2023-07-19 21:25:52 +02:00
ret - > rewardableObjectInfo . init ( source , ret - > getBaseTextID ( ) ) ;
2023-04-30 01:58:43 +02:00
}
2021-01-14 00:02:13 +02:00
}
2014-06-23 19:37:26 +03:00
//MODS COMPATIBILITY FOR 0.96
2014-04-28 09:48:00 +03:00
if ( ! ret - > produce . nonZero ( ) )
{
2014-06-23 19:37:26 +03:00
switch ( ret - > bid ) {
2023-04-05 02:26:29 +02:00
break ; case BuildingID : : VILLAGE_HALL : ret - > produce [ EGameResID : : GOLD ] = 500 ;
break ; case BuildingID : : TOWN_HALL : ret - > produce [ EGameResID : : GOLD ] = 1000 ;
break ; case BuildingID : : CITY_HALL : ret - > produce [ EGameResID : : GOLD ] = 2000 ;
break ; case BuildingID : : CAPITOL : ret - > produce [ EGameResID : : GOLD ] = 4000 ;
break ; case BuildingID : : GRAIL : ret - > produce [ EGameResID : : GOLD ] = 5000 ;
2014-06-23 19:37:26 +03:00
break ; case BuildingID : : RESOURCE_SILO :
2014-04-26 17:23:35 +03:00
{
2023-04-05 02:26:29 +02:00
switch ( ret - > town - > primaryRes . toEnum ( ) )
2014-06-23 19:37:26 +03:00
{
2023-04-05 02:26:29 +02:00
case EGameResID : : GOLD :
2014-06-23 19:37:26 +03:00
ret - > produce [ ret - > town - > primaryRes ] = 500 ;
break ;
2023-04-05 02:26:29 +02:00
case EGameResID : : WOOD_AND_ORE :
ret - > produce [ EGameResID : : WOOD ] = 1 ;
ret - > produce [ EGameResID : : ORE ] = 1 ;
2014-06-23 19:37:26 +03:00
break ;
default :
ret - > produce [ ret - > town - > primaryRes ] = 1 ;
break ;
}
2014-04-26 17:23:35 +03:00
}
}
}
2021-01-14 00:02:13 +02:00
loadBuildingRequirements ( ret , source [ " requires " ] , requirementsToLoad ) ;
2012-09-02 13:33:41 +03:00
2021-01-14 00:02:13 +02:00
if ( ret - > bid . IsSpecialOrGrail ( ) )
loadBuildingRequirements ( ret , source [ " overrides " ] , overriddenBidsToLoad ) ;
2012-09-02 13:33:41 +03:00
2012-09-05 15:49:23 +03:00
if ( ! source [ " upgrades " ] . isNull ( ) )
2013-12-04 13:36:39 +03:00
{
2014-06-23 20:10:08 +03:00
// building id and upgrades can't be the same
if ( stringID = = source [ " upgrades " ] . String ( ) )
2013-12-04 13:36:39 +03:00
{
2014-06-23 20:10:08 +03:00
throw std : : runtime_error ( boost : : str ( boost : : format ( " Building with ID '%s' of town '%s' can't be an upgrade of the same building. " ) %
2023-01-04 15:17:50 +02:00
stringID % ret - > town - > faction - > getNameTranslated ( ) ) ) ;
2013-12-04 13:36:39 +03:00
}
2014-06-23 20:10:08 +03:00
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( ret - > town - > getBuildingScope ( ) , source [ " upgrades " ] , [ = ] ( si32 identifier )
2014-06-23 20:10:08 +03:00
{
ret - > upgrade = BuildingID ( identifier ) ;
} ) ;
2013-12-04 13:36:39 +03:00
}
2012-09-05 15:49:23 +03:00
else
2013-02-11 22:11:34 +03:00
ret - > upgrade = BuildingID : : NONE ;
2012-09-05 15:49:23 +03:00
2016-11-13 12:38:42 +02:00
ret - > town - > buildings [ ret - > bid ] = ret ;
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
registerObject ( source . meta , ret - > town - > getBuildingScope ( ) , ret - > identifier , ret - > bid ) ;
2012-09-02 13:33:41 +03:00
}
2016-11-13 12:38:42 +02:00
void CTownHandler : : loadBuildings ( CTown * town , const JsonNode & source )
2012-09-02 13:33:41 +03:00
{
2023-04-29 13:46:51 +02:00
if ( source . isStruct ( ) )
2012-09-02 13:33:41 +03:00
{
2023-04-29 13:46:51 +02:00
for ( const auto & node : source . Struct ( ) )
2013-04-21 15:49:26 +03:00
{
2023-04-29 13:46:51 +02:00
if ( ! node . second . isNull ( ) )
loadBuilding ( town , node . first , node . second ) ;
2013-04-21 15:49:26 +03:00
}
2012-09-02 13:33:41 +03:00
}
}
2011-08-26 06:10:56 +03:00
2023-03-13 23:26:44 +02:00
void CTownHandler : : loadStructure ( CTown & town , const std : : string & stringID , const JsonNode & source ) const
2012-09-02 13:33:41 +03:00
{
2023-03-13 23:26:44 +02:00
auto * ret = new CStructure ( ) ;
2013-12-02 14:58:02 +03:00
ret - > building = nullptr ;
ret - > buildable = nullptr ;
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > tryRequestIdentifier ( source . meta , " building. " + town . faction - > getJsonKey ( ) , stringID , [ = , & town ] ( si32 identifier ) mutable
2013-12-02 14:58:02 +03:00
{
ret - > building = town . buildings [ BuildingID ( identifier ) ] ;
} ) ;
2012-09-02 13:33:41 +03:00
2013-12-02 14:58:02 +03:00
if ( source [ " builds " ] . isNull ( ) )
2012-09-05 15:49:23 +03:00
{
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > tryRequestIdentifier ( source . meta , " building. " + town . faction - > getJsonKey ( ) , stringID , [ = , & town ] ( si32 identifier ) mutable
2013-12-02 14:58:02 +03:00
{
ret - > building = town . buildings [ BuildingID ( identifier ) ] ;
} ) ;
2012-09-05 15:49:23 +03:00
}
else
{
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( " building. " + town . faction - > getJsonKey ( ) , source [ " builds " ] , [ = , & town ] ( si32 identifier ) mutable
2013-12-02 14:58:02 +03:00
{
2014-06-23 20:10:08 +03:00
ret - > buildable = town . buildings [ BuildingID ( identifier ) ] ;
} ) ;
2012-09-05 15:49:23 +03:00
}
2013-12-02 14:58:02 +03:00
ret - > identifier = stringID ;
2020-10-01 10:38:06 +02:00
ret - > pos . x = static_cast < si32 > ( source [ " x " ] . Float ( ) ) ;
ret - > pos . y = static_cast < si32 > ( source [ " y " ] . Float ( ) ) ;
ret - > pos . z = static_cast < si32 > ( source [ " z " ] . Float ( ) ) ;
2012-09-02 13:33:41 +03:00
2012-09-05 15:49:23 +03:00
ret - > hiddenUpgrade = source [ " hidden " ] . Bool ( ) ;
2023-08-23 14:07:50 +02:00
ret - > defName = AnimationPath : : fromJson ( source [ " animation " ] ) ;
ret - > borderName = ImagePath : : fromJson ( source [ " border " ] ) ;
ret - > areaName = ImagePath : : fromJson ( source [ " area " ] ) ;
2012-09-02 13:33:41 +03:00
2023-03-13 23:26:44 +02:00
town . clientInfo . structures . emplace_back ( ret ) ;
2012-09-02 13:33:41 +03:00
}
2023-03-13 23:26:44 +02:00
void CTownHandler : : loadStructures ( CTown & town , const JsonNode & source ) const
2012-09-02 13:33:41 +03:00
{
2023-03-13 23:26:44 +02:00
for ( const auto & node : source . Struct ( ) )
2013-04-21 15:49:26 +03:00
{
2013-12-02 14:58:02 +03:00
if ( ! node . second . isNull ( ) )
loadStructure ( town , node . first , node . second ) ;
2012-09-02 13:33:41 +03:00
}
}
2011-08-26 06:43:43 +03:00
2023-03-13 23:26:44 +02:00
void CTownHandler : : loadTownHall ( CTown & town , const JsonNode & source ) const
2012-09-02 13:33:41 +03:00
{
2013-12-04 13:36:39 +03:00
auto & dstSlots = town . clientInfo . hallSlots ;
2023-03-13 23:26:44 +02:00
const auto & srcSlots = source . Vector ( ) ;
2013-12-04 13:36:39 +03:00
dstSlots . resize ( srcSlots . size ( ) ) ;
for ( size_t i = 0 ; i < dstSlots . size ( ) ; i + + )
2012-09-02 13:33:41 +03:00
{
2013-12-04 13:36:39 +03:00
auto & dstRow = dstSlots [ i ] ;
2023-03-13 23:26:44 +02:00
const auto & srcRow = srcSlots [ i ] . Vector ( ) ;
2013-12-04 13:36:39 +03:00
dstRow . resize ( srcRow . size ( ) ) ;
2012-09-02 13:33:41 +03:00
2013-12-04 13:36:39 +03:00
for ( size_t j = 0 ; j < dstRow . size ( ) ; j + + )
2012-09-02 13:33:41 +03:00
{
2013-12-04 13:36:39 +03:00
auto & dstBox = dstRow [ j ] ;
2023-03-13 23:26:44 +02:00
const auto & srcBox = srcRow [ j ] . Vector ( ) ;
2013-12-04 13:36:39 +03:00
dstBox . resize ( srcBox . size ( ) ) ;
2012-09-02 13:33:41 +03:00
2013-12-04 13:36:39 +03:00
for ( size_t k = 0 ; k < dstBox . size ( ) ; k + + )
2012-09-02 13:33:41 +03:00
{
2013-12-04 13:36:39 +03:00
auto & dst = dstBox [ k ] ;
2023-03-13 23:26:44 +02:00
const auto & src = srcBox [ k ] ;
2013-12-04 13:36:39 +03:00
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( " building. " + town . faction - > getJsonKey ( ) , src , [ & ] ( si32 identifier )
2013-12-04 13:36:39 +03:00
{
2014-06-23 20:10:08 +03:00
dst = BuildingID ( identifier ) ;
} ) ;
2012-09-02 13:33:41 +03:00
}
2011-08-26 06:58:07 +03:00
}
2012-09-02 13:33:41 +03:00
}
}
2023-01-17 22:18:34 +02:00
Point JsonToPoint ( const JsonNode & node )
2012-10-05 21:03:49 +03:00
{
2023-03-25 23:44:10 +02:00
if ( ! node . isStruct ( ) )
return Point : : makeInvalid ( ) ;
2023-01-17 22:18:34 +02:00
Point ret ;
2020-10-01 10:38:06 +02:00
ret . x = static_cast < si32 > ( node [ " x " ] . Float ( ) ) ;
ret . y = static_cast < si32 > ( node [ " y " ] . Float ( ) ) ;
2012-10-05 21:03:49 +03:00
return ret ;
}
2023-03-13 23:26:44 +02:00
void CTownHandler : : loadSiegeScreen ( CTown & town , const JsonNode & source ) const
2012-10-05 21:03:49 +03:00
{
town . clientInfo . siegePrefix = source [ " imagePrefix " ] . String ( ) ;
2022-11-29 14:47:51 +02:00
town . clientInfo . towerIconSmall = source [ " towerIconSmall " ] . String ( ) ;
town . clientInfo . towerIconLarge = source [ " towerIconLarge " ] . String ( ) ;
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( " creature " , source [ " shooter " ] , [ & town ] ( si32 creature )
2012-12-10 23:08:00 +03:00
{
2021-01-17 14:02:58 +02:00
auto crId = CreatureID ( creature ) ;
2023-03-13 23:26:44 +02:00
if ( ( * VLC - > creh ) [ crId ] - > animation . missleFrameAngles . empty ( ) )
2021-01-17 14:02:58 +02:00
logMod - > error ( " Mod '%s' error: Creature '%s' on the Archer's tower is not a shooter. Mod should be fixed. Siege will not work properly! "
2023-01-04 15:17:50 +02:00
, town . faction - > getNameTranslated ( )
2023-01-02 18:00:51 +02:00
, ( * VLC - > creh ) [ crId ] - > getNameSingularTranslated ( ) ) ;
2021-01-17 14:02:58 +02:00
town . clientInfo . siegeShooter = crId ;
2012-12-10 23:08:00 +03:00
} ) ;
2012-10-05 21:03:49 +03:00
auto & pos = town . clientInfo . siegePositions ;
pos . resize ( 21 ) ;
pos [ 8 ] = JsonToPoint ( source [ " towers " ] [ " top " ] [ " tower " ] ) ;
pos [ 17 ] = JsonToPoint ( source [ " towers " ] [ " top " ] [ " battlement " ] ) ;
pos [ 20 ] = JsonToPoint ( source [ " towers " ] [ " top " ] [ " creature " ] ) ;
pos [ 2 ] = JsonToPoint ( source [ " towers " ] [ " keep " ] [ " tower " ] ) ;
pos [ 15 ] = JsonToPoint ( source [ " towers " ] [ " keep " ] [ " battlement " ] ) ;
pos [ 18 ] = JsonToPoint ( source [ " towers " ] [ " keep " ] [ " creature " ] ) ;
pos [ 3 ] = JsonToPoint ( source [ " towers " ] [ " bottom " ] [ " tower " ] ) ;
pos [ 16 ] = JsonToPoint ( source [ " towers " ] [ " bottom " ] [ " battlement " ] ) ;
pos [ 19 ] = JsonToPoint ( source [ " towers " ] [ " bottom " ] [ " creature " ] ) ;
pos [ 9 ] = JsonToPoint ( source [ " gate " ] [ " gate " ] ) ;
pos [ 10 ] = JsonToPoint ( source [ " gate " ] [ " arch " ] ) ;
pos [ 7 ] = JsonToPoint ( source [ " walls " ] [ " upper " ] ) ;
pos [ 6 ] = JsonToPoint ( source [ " walls " ] [ " upperMid " ] ) ;
pos [ 5 ] = JsonToPoint ( source [ " walls " ] [ " bottomMid " ] ) ;
pos [ 4 ] = JsonToPoint ( source [ " walls " ] [ " bottom " ] ) ;
pos [ 13 ] = JsonToPoint ( source [ " moat " ] [ " moat " ] ) ;
pos [ 14 ] = JsonToPoint ( source [ " moat " ] [ " bank " ] ) ;
pos [ 11 ] = JsonToPoint ( source [ " static " ] [ " bottom " ] ) ;
pos [ 12 ] = JsonToPoint ( source [ " static " ] [ " top " ] ) ;
pos [ 1 ] = JsonToPoint ( source [ " static " ] [ " background " ] ) ;
}
2013-04-22 22:51:22 +03:00
static void readIcon ( JsonNode source , std : : string & small , std : : string & large )
2012-09-02 13:33:41 +03:00
{
2017-11-26 23:18:18 +02:00
if ( source . getType ( ) = = JsonNode : : JsonType : : DATA_STRUCT ) // don't crash on old format
2012-12-19 19:35:58 +03:00
{
2013-04-22 22:51:22 +03:00
small = source [ " small " ] . String ( ) ;
large = source [ " large " ] . String ( ) ;
2012-12-19 19:35:58 +03:00
}
2013-04-22 22:51:22 +03:00
}
2023-03-13 23:26:44 +02:00
void CTownHandler : : loadClientData ( CTown & town , const JsonNode & source ) const
2013-04-22 22:51:22 +03:00
{
CTown : : ClientInfo & info = town . clientInfo ;
readIcon ( source [ " icons " ] [ " village " ] [ " normal " ] , info . iconSmall [ 0 ] [ 0 ] , info . iconLarge [ 0 ] [ 0 ] ) ;
readIcon ( source [ " icons " ] [ " village " ] [ " built " ] , info . iconSmall [ 0 ] [ 1 ] , info . iconLarge [ 0 ] [ 1 ] ) ;
readIcon ( source [ " icons " ] [ " fort " ] [ " normal " ] , info . iconSmall [ 1 ] [ 0 ] , info . iconLarge [ 1 ] [ 0 ] ) ;
readIcon ( source [ " icons " ] [ " fort " ] [ " built " ] , info . iconSmall [ 1 ] [ 1 ] , info . iconLarge [ 1 ] [ 1 ] ) ;
2023-08-23 14:07:50 +02:00
info . hallBackground = ImagePath : : fromJson ( source [ " hallBackground " ] ) ;
2023-09-04 12:03:15 +02:00
info . musicTheme = AudioPath : : fromJson ( source [ " musicTheme " ] ) ;
2023-08-23 14:07:50 +02:00
info . townBackground = ImagePath : : fromJson ( source [ " townBackground " ] ) ;
info . guildWindow = ImagePath : : fromJson ( source [ " guildWindow " ] ) ;
info . buildingsIcons = AnimationPath : : fromJson ( source [ " buildingsIcons " ] ) ;
2013-04-22 22:51:22 +03:00
2023-08-23 14:07:50 +02:00
info . guildBackground = ImagePath : : fromJson ( source [ " guildBackground " ] ) ;
2023-09-01 23:57:25 +02:00
info . tavernVideo = VideoPath : : fromJson ( source [ " tavernVideo " ] ) ;
2014-04-24 22:36:10 +03:00
2012-09-05 15:49:23 +03:00
loadTownHall ( town , source [ " hallSlots " ] ) ;
loadStructures ( town , source [ " structures " ] ) ;
2012-10-05 21:03:49 +03:00
loadSiegeScreen ( town , source [ " siege " ] ) ;
2012-09-05 15:49:23 +03:00
}
2012-09-02 13:33:41 +03:00
2018-07-16 14:16:55 +02:00
void CTownHandler : : loadTown ( CTown * town , const JsonNode & source )
2012-09-05 15:49:23 +03:00
{
2023-03-13 23:26:44 +02:00
const auto * resIter = boost : : find ( GameConstants : : RESOURCE_NAMES , source [ " primaryResource " ] . String ( ) ) ;
2018-07-16 14:16:55 +02:00
if ( resIter = = std : : end ( GameConstants : : RESOURCE_NAMES ) )
2023-04-05 02:26:29 +02:00
town - > primaryRes = GameResID ( EGameResID : : WOOD_AND_ORE ) ; //Wood + Ore
2012-12-11 15:12:46 +03:00
else
2023-04-05 02:26:29 +02:00
town - > primaryRes = GameResID ( resIter - std : : begin ( GameConstants : : RESOURCE_NAMES ) ) ;
2012-12-11 15:12:46 +03:00
2018-07-16 14:16:55 +02:00
warMachinesToLoad [ town ] = source [ " warMachine " ] ;
2012-12-11 15:12:46 +03:00
2020-10-01 10:38:06 +02:00
town - > mageLevel = static_cast < ui32 > ( source [ " mageGuild " ] . Float ( ) ) ;
2023-01-04 15:17:50 +02:00
town - > namesCount = 0 ;
2023-03-13 23:26:44 +02:00
for ( const auto & name : source [ " names " ] . Vector ( ) )
2023-01-04 15:17:50 +02:00
{
2023-02-09 15:03:49 +02:00
VLC - > generaltexth - > registerString ( town - > faction - > modScope , town - > getRandomNameTextID ( town - > namesCount ) , name . String ( ) ) ;
2023-01-04 15:17:50 +02:00
town - > namesCount + = 1 ;
}
2012-09-02 13:33:41 +03:00
2023-04-03 14:15:12 +02:00
if ( ! source [ " moatAbility " ] . isNull ( ) ) // VCMI 1.2 compatibility code
2023-03-20 13:02:09 +02:00
{
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( " spell " , source [ " moatAbility " ] , [ = ] ( si32 ability )
2023-04-03 14:15:12 +02:00
{
town - > moatAbility = SpellID ( ability ) ;
} ) ;
}
2023-04-03 15:26:43 +02:00
else
{
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( source . meta , " spell " , " castleMoat " , [ = ] ( si32 ability )
2023-04-03 15:26:43 +02:00
{
town - > moatAbility = SpellID ( ability ) ;
} ) ;
}
2023-03-20 13:02:09 +02:00
2012-09-02 13:33:41 +03:00
// Horde building creature level
2013-06-29 16:05:48 +03:00
for ( const JsonNode & node : source [ " horde " ] . Vector ( ) )
2023-03-13 23:26:44 +02:00
town - > hordeLvl [ static_cast < int > ( town - > hordeLvl . size ( ) ) ] = static_cast < int > ( node . Float ( ) ) ;
2013-11-24 14:36:51 +03:00
// town needs to have exactly 2 horde entries. Validation will take care of 2+ entries
// but anything below 2 must be handled here
for ( size_t i = source [ " horde " ] . Vector ( ) . size ( ) ; i < 2 ; i + + )
2023-03-13 23:26:44 +02:00
town - > hordeLvl [ static_cast < int > ( i ) ] = - 1 ;
2008-01-20 18:24:03 +02:00
2012-12-03 19:00:17 +03:00
const JsonVector & creatures = source [ " creatures " ] . Vector ( ) ;
2018-07-16 14:16:55 +02:00
town - > creatures . resize ( creatures . size ( ) ) ;
2012-12-03 19:00:17 +03:00
for ( size_t i = 0 ; i < creatures . size ( ) ; i + + )
2012-09-02 13:33:41 +03:00
{
2012-12-03 19:00:17 +03:00
const JsonVector & level = creatures [ i ] . Vector ( ) ;
2018-07-16 14:16:55 +02:00
town - > creatures [ i ] . resize ( level . size ( ) ) ;
2012-12-03 19:00:17 +03:00
for ( size_t j = 0 ; j < level . size ( ) ; j + + )
2012-09-02 13:33:41 +03:00
{
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( " creature " , level [ j ] , [ = ] ( si32 creature )
2012-12-03 19:00:17 +03:00
{
2018-07-16 14:16:55 +02:00
town - > creatures [ i ] [ j ] = CreatureID ( creature ) ;
2012-12-03 19:00:17 +03:00
} ) ;
2008-01-27 15:18:18 +02:00
}
2012-12-17 15:55:29 +03:00
}
2020-10-01 10:38:06 +02:00
town - > defaultTavernChance = static_cast < ui32 > ( source [ " defaultTavern " ] . Float ( ) ) ;
2012-12-17 15:55:29 +03:00
/// set chance of specific hero class to appear in this town
2023-03-13 23:26:44 +02:00
for ( const auto & node : source [ " tavern " ] . Struct ( ) )
2012-12-17 15:55:29 +03:00
{
2020-10-01 10:38:06 +02:00
int chance = static_cast < int > ( node . second . Float ( ) ) ;
2012-12-03 19:00:17 +03:00
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( node . second . meta , " heroClass " , node . first , [ = ] ( si32 classID )
2012-12-17 15:55:29 +03:00
{
2023-04-09 17:26:32 +02:00
VLC - > heroh - > classes [ HeroClassID ( classID ) ] - > selectionProbability [ town - > faction - > getId ( ) ] = chance ;
2012-12-17 15:55:29 +03:00
} ) ;
2008-01-27 15:18:18 +02:00
}
2012-09-02 13:33:41 +03:00
2023-03-13 23:26:44 +02:00
for ( const auto & node : source [ " guildSpells " ] . Struct ( ) )
2012-12-18 13:32:11 +03:00
{
2020-10-01 10:38:06 +02:00
int chance = static_cast < int > ( node . second . Float ( ) ) ;
2012-12-18 13:32:11 +03:00
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( node . second . meta , " spell " , node . first , [ = ] ( si32 spellID )
2012-12-18 13:32:11 +03:00
{
2023-04-09 17:26:32 +02:00
VLC - > spellh - > objects . at ( spellID ) - > probabilities [ town - > faction - > getId ( ) ] = chance ;
2012-12-18 13:32:11 +03:00
} ) ;
}
2018-07-16 14:16:55 +02:00
for ( const JsonNode & d : source [ " adventureMap " ] [ " dwellings " ] . Vector ( ) )
2013-04-22 22:51:22 +03:00
{
2018-07-16 14:16:55 +02:00
town - > dwellings . push_back ( d [ " graphics " ] . String ( ) ) ;
town - > dwellingNames . push_back ( d [ " name " ] . String ( ) ) ;
2013-04-22 22:51:22 +03:00
}
2018-07-16 14:16:55 +02:00
loadBuildings ( town , source [ " buildings " ] ) ;
loadClientData ( * town , source ) ;
2008-08-02 18:08:03 +03:00
}
2011-08-26 05:39:58 +03:00
2023-03-13 23:26:44 +02:00
void CTownHandler : : loadPuzzle ( CFaction & faction , const JsonNode & source ) const
2012-09-21 00:28:18 +03:00
{
faction . puzzleMap . reserve ( GameConstants : : PUZZLE_MAP_PIECES ) ;
std : : string prefix = source [ " prefix " ] . String ( ) ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & piece : source [ " pieces " ] . Vector ( ) )
2012-09-21 00:28:18 +03:00
{
size_t index = faction . puzzleMap . size ( ) ;
SPuzzleInfo spi ;
2020-10-01 10:38:06 +02:00
spi . x = static_cast < si16 > ( piece [ " x " ] . Float ( ) ) ;
spi . y = static_cast < si16 > ( piece [ " y " ] . Float ( ) ) ;
spi . whenUncovered = static_cast < ui16 > ( piece [ " index " ] . Float ( ) ) ;
spi . number = static_cast < ui16 > ( index ) ;
2012-09-21 00:28:18 +03:00
// filename calculation
std : : ostringstream suffix ;
suffix < < std : : setfill ( ' 0 ' ) < < std : : setw ( 2 ) < < index ;
2023-08-23 14:07:50 +02:00
spi . filename = ImagePath : : builtinTODO ( prefix + suffix . str ( ) ) ;
2012-09-21 00:28:18 +03:00
faction . puzzleMap . push_back ( spi ) ;
}
assert ( faction . puzzleMap . size ( ) = = GameConstants : : PUZZLE_MAP_PIECES ) ;
}
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
CFaction * CTownHandler : : loadFromJson ( const std : : string & scope , const JsonNode & source , const std : : string & identifier , size_t index )
2008-12-22 19:48:41 +02:00
{
2023-01-18 23:56:01 +02:00
assert ( identifier . find ( ' : ' ) = = std : : string : : npos ) ;
2023-03-13 23:26:44 +02:00
auto * faction = new CFaction ( ) ;
2012-12-16 16:47:53 +03:00
2023-04-09 17:26:32 +02:00
faction - > index = static_cast < FactionID > ( index ) ;
2023-01-04 15:17:50 +02:00
faction - > modScope = scope ;
2013-12-02 14:58:02 +03:00
faction - > identifier = identifier ;
2012-09-05 15:49:23 +03:00
2023-02-09 15:03:49 +02:00
VLC - > generaltexth - > registerString ( scope , faction - > getNameTextID ( ) , source [ " name " ] . String ( ) ) ;
2023-01-04 15:17:50 +02:00
2023-08-23 14:07:50 +02:00
faction - > creatureBg120 = ImagePath : : fromJson ( source [ " creatureBackground " ] [ " 120px " ] ) ;
faction - > creatureBg130 = ImagePath : : fromJson ( source [ " creatureBackground " ] [ " 130px " ] ) ;
2012-09-05 15:49:23 +03:00
2023-08-18 12:38:19 +02:00
faction - > boatType = BoatId : : CASTLE ; //Do not crash
2023-06-19 21:01:18 +02:00
if ( ! source [ " boat " ] . isNull ( ) )
{
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( " core:boat " , source [ " boat " ] , [ = ] ( int32_t boatTypeID )
2023-06-19 21:01:18 +02:00
{
faction - > boatType = BoatId ( boatTypeID ) ;
} ) ;
}
2023-04-04 12:36:42 +02:00
int alignment = vstd : : find_pos ( GameConstants : : ALIGNMENT_NAMES , source [ " alignment " ] . String ( ) ) ;
2013-03-02 19:55:51 +03:00
if ( alignment = = - 1 )
2013-04-21 15:49:26 +03:00
faction - > alignment = EAlignment : : NEUTRAL ;
2013-03-02 19:55:51 +03:00
else
2023-04-04 12:36:42 +02:00
faction - > alignment = static_cast < EAlignment > ( alignment ) ;
2022-05-28 15:03:50 +02:00
auto preferUndergound = source [ " preferUndergroundPlacement " ] ;
faction - > preferUndergroundPlacement = preferUndergound . isNull ( ) ? false : preferUndergound . Bool ( ) ;
2020-09-24 09:10:32 +02:00
2023-01-17 22:59:14 +02:00
// NOTE: semi-workaround - normally, towns are supposed to have native terrains.
// Towns without one are exceptions. So, vcmi requires nativeTerrain to be defined
// But allows it to be defined with explicit value of "none" if town should not have native terrain
// This is better than allowing such terrain-less towns silently, leading to issues with RMG
2023-01-10 20:08:07 +02:00
faction - > nativeTerrain = ETerrainId : : NONE ;
2023-01-17 22:59:14 +02:00
if ( ! source [ " nativeTerrain " ] . isNull ( ) & & source [ " nativeTerrain " ] . String ( ) ! = " none " )
2022-12-20 18:35:40 +02:00
{
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( " terrain " , source [ " nativeTerrain " ] , [ = ] ( int32_t index ) {
2022-12-20 18:35:40 +02:00
faction - > nativeTerrain = TerrainId ( index ) ;
2023-05-15 21:22:42 +02:00
auto const & terrain = VLC - > terrainTypeHandler - > getById ( faction - > nativeTerrain ) ;
if ( ! terrain - > isSurface ( ) & & ! terrain - > isUnderground ( ) )
logMod - > warn ( " Faction %s has terrain %s as native, but terrain is not suitable for either surface or subterranean layers! " , faction - > getJsonKey ( ) , terrain - > getJsonKey ( ) ) ;
2022-12-20 18:35:40 +02:00
} ) ;
}
2020-09-24 09:10:32 +02:00
2013-03-02 19:55:51 +03:00
if ( ! source [ " town " ] . isNull ( ) )
{
2017-07-16 11:58:05 +02:00
faction - > town = new CTown ( ) ;
2013-04-21 15:49:26 +03:00
faction - > town - > faction = faction ;
2018-07-16 14:16:55 +02:00
loadTown ( faction - > town , source [ " town " ] ) ;
2012-09-05 15:49:23 +03:00
}
2013-04-21 17:08:46 +03:00
else
faction - > town = nullptr ;
2013-03-02 19:55:51 +03:00
if ( ! source [ " puzzleMap " ] . isNull ( ) )
2013-04-21 15:49:26 +03:00
loadPuzzle ( * faction , source [ " puzzleMap " ] ) ;
2013-03-02 19:55:51 +03:00
2013-04-21 15:49:26 +03:00
return faction ;
2008-12-22 19:48:41 +02:00
}
2013-04-21 15:49:26 +03:00
void CTownHandler : : loadObject ( std : : string scope , std : : string name , const JsonNode & data )
2008-12-22 19:48:41 +02:00
{
2023-03-13 23:26:44 +02:00
auto * object = loadFromJson ( scope , data , name , objects . size ( ) ) ;
2014-04-26 17:23:35 +03:00
2023-03-13 23:26:44 +02:00
objects . emplace_back ( object ) ;
2014-06-15 19:43:01 +03:00
2013-04-22 22:51:22 +03:00
if ( object - > town )
{
auto & info = object - > town - > clientInfo ;
info . icons [ 0 ] [ 0 ] = 8 + object - > index * 4 + 0 ;
info . icons [ 0 ] [ 1 ] = 8 + object - > index * 4 + 1 ;
info . icons [ 1 ] [ 0 ] = 8 + object - > index * 4 + 2 ;
info . icons [ 1 ] [ 1 ] = 8 + object - > index * 4 + 3 ;
2012-09-02 13:33:41 +03:00
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( scope , " object " , " town " , [ = ] ( si32 index )
2014-06-15 19:43:01 +03:00
{
// register town once objects are loaded
JsonNode config = data [ " town " ] [ " mapObject " ] ;
2016-02-21 19:58:09 +02:00
config [ " faction " ] . String ( ) = name ;
2014-06-15 19:43:01 +03:00
config [ " faction " ] . meta = scope ;
2014-06-27 00:07:09 +03:00
if ( config . meta . empty ( ) ) // MODS COMPATIBILITY FOR 0.96
config . meta = scope ;
2014-06-15 19:43:01 +03:00
VLC - > objtypeh - > loadSubObject ( object - > identifier , config , index , object - > index ) ;
2014-06-27 00:07:09 +03:00
// MODS COMPATIBILITY FOR 0.96
2023-03-13 23:26:44 +02:00
const auto & advMap = data [ " town " ] [ " adventureMap " ] ;
2014-06-27 00:07:09 +03:00
if ( ! advMap . isNull ( ) )
{
2017-08-30 23:23:19 +02:00
logMod - > warn ( " Outdated town mod. Will try to generate valid templates out of fort " ) ;
2014-06-27 00:07:09 +03:00
JsonNode config ;
config [ " animation " ] = advMap [ " castle " ] ;
VLC - > objtypeh - > getHandlerFor ( index , object - > index ) - > addTemplate ( config ) ;
}
2014-06-15 19:43:01 +03:00
} ) ;
}
2012-09-02 13:33:41 +03:00
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
registerObject ( scope , " faction " , name , object - > index ) ;
2013-04-21 15:49:26 +03:00
}
2012-10-05 16:11:26 +03:00
2013-04-21 15:49:26 +03:00
void CTownHandler : : loadObject ( std : : string scope , std : : string name , const JsonNode & data , size_t index )
{
2023-03-13 23:26:44 +02:00
auto * object = loadFromJson ( scope , data , name , index ) ;
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
if ( objects . size ( ) > index )
assert ( objects [ index ] = = nullptr ) ; // ensure that this id was not loaded before
2017-08-25 07:17:14 +02:00
else
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
objects . resize ( index + 1 ) ;
objects [ index ] = object ;
2014-06-15 19:43:01 +03:00
2013-04-22 22:51:22 +03:00
if ( object - > town )
{
auto & info = object - > town - > clientInfo ;
info . icons [ 0 ] [ 0 ] = ( GameConstants : : F_NUMBER + object - > index ) * 2 + 0 ;
info . icons [ 0 ] [ 1 ] = ( GameConstants : : F_NUMBER + object - > index ) * 2 + 1 ;
info . icons [ 1 ] [ 0 ] = object - > index * 2 + 0 ;
info . icons [ 1 ] [ 1 ] = object - > index * 2 + 1 ;
2012-10-05 16:11:26 +03:00
2023-07-30 19:12:25 +02:00
VLC - > identifiers ( ) - > requestIdentifier ( scope , " object " , " town " , [ = ] ( si32 index )
2014-06-15 19:43:01 +03:00
{
// register town once objects are loaded
JsonNode config = data [ " town " ] [ " mapObject " ] ;
2016-02-21 19:58:09 +02:00
config [ " faction " ] . String ( ) = name ;
2014-06-15 19:43:01 +03:00
config [ " faction " ] . meta = scope ;
VLC - > objtypeh - > loadSubObject ( object - > identifier , config , index , object - > index ) ;
} ) ;
}
2012-09-02 13:33:41 +03:00
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
registerObject ( scope , " faction " , name , object - > index ) ;
2009-10-04 05:02:45 +03:00
}
2012-11-20 20:53:45 +03:00
2016-11-13 12:38:42 +02:00
void CTownHandler : : loadRandomFaction ( )
{
2023-09-01 23:26:14 +02:00
JsonNode randomFactionJson ( JsonPath : : builtin ( " config/factions/random.json " ) ) ;
2023-07-30 19:12:25 +02:00
randomFactionJson . setMeta ( ModScope : : scopeBuiltin ( ) , true ) ;
2016-11-13 12:38:42 +02:00
loadBuildings ( randomTown , randomFactionJson [ " random " ] [ " town " ] [ " buildings " ] ) ;
}
void CTownHandler : : loadCustom ( )
{
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
loadRandomFaction ( ) ;
2016-11-13 12:38:42 +02:00
}
2013-12-02 14:58:02 +03:00
void CTownHandler : : afterLoadFinalization ( )
{
initializeRequirements ( ) ;
2021-01-14 00:02:13 +02:00
initializeOverridden ( ) ;
2018-07-16 14:16:55 +02:00
initializeWarMachines ( ) ;
2013-12-02 14:58:02 +03:00
}
void CTownHandler : : initializeRequirements ( )
{
// must be done separately after all ID's are known
for ( auto & requirement : requirementsToLoad )
{
2014-08-04 14:47:42 +03:00
requirement . building - > requirements = CBuilding : : TRequired ( requirement . json , [ & ] ( const JsonNode & node ) - > BuildingID
2013-12-02 14:58:02 +03:00
{
2014-08-04 14:47:42 +03:00
if ( node . Vector ( ) . size ( ) > 1 )
{
2023-08-06 12:30:20 +02:00
logMod - > error ( " Unexpected length of town buildings requirements: %d " , node . Vector ( ) . size ( ) ) ;
logMod - > error ( " Entry contains: " ) ;
logMod - > error ( node . toJson ( ) ) ;
2014-08-04 14:47:42 +03:00
}
2023-08-06 12:30:20 +02:00
2023-08-12 16:28:47 +02:00
auto index = VLC - > identifiers ( ) - > getIdentifier ( requirement . town - > getBuildingScope ( ) , node [ 0 ] ) ;
2023-08-06 12:30:20 +02:00
if ( ! index . has_value ( ) )
{
logMod - > error ( " Unknown building in town buildings: %s " , node [ 0 ] . String ( ) ) ;
return BuildingID : : NONE ;
}
return BuildingID ( index . value ( ) ) ;
2013-12-02 14:58:02 +03:00
} ) ;
}
requirementsToLoad . clear ( ) ;
}
2021-01-14 00:02:13 +02:00
void CTownHandler : : initializeOverridden ( )
{
for ( auto & bidHelper : overriddenBidsToLoad )
{
auto jsonNode = bidHelper . json ;
auto scope = bidHelper . town - > getBuildingScope ( ) ;
2023-03-13 23:26:44 +02:00
for ( const auto & b : jsonNode . Vector ( ) )
2021-01-14 00:02:13 +02:00
{
2023-07-30 19:12:25 +02:00
auto bid = BuildingID ( VLC - > identifiers ( ) - > getIdentifier ( scope , b ) . value ( ) ) ;
2021-01-14 00:02:13 +02:00
bidHelper . building - > overrideBids . insert ( bid ) ;
}
}
overriddenBidsToLoad . clear ( ) ;
}
2018-07-16 14:16:55 +02:00
void CTownHandler : : initializeWarMachines ( )
{
// must be done separately after all objects are loaded
for ( auto & p : warMachinesToLoad )
{
CTown * t = p . first ;
JsonNode creatureKey = p . second ;
2023-07-30 19:12:25 +02:00
auto ret = VLC - > identifiers ( ) - > getIdentifier ( " creature " , creatureKey , false ) ;
2018-07-16 14:16:55 +02:00
if ( ret )
{
const CCreature * creature = CreatureID ( * ret ) . toCreature ( ) ;
t - > warMachine = creature - > warMachine ;
}
}
warMachinesToLoad . clear ( ) ;
}
2013-04-21 15:49:26 +03:00
std : : vector < bool > CTownHandler : : getDefaultAllowed ( ) const
2012-11-20 20:53:45 +03:00
{
2013-04-21 15:49:26 +03:00
std : : vector < bool > allowedFactions ;
2023-03-13 23:26:44 +02:00
allowedFactions . reserve ( objects . size ( ) ) ;
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
for ( auto town : objects )
2012-11-20 20:53:45 +03:00
{
2013-04-21 15:49:26 +03:00
allowedFactions . push_back ( town - > town ! = nullptr ) ;
2012-11-20 20:53:45 +03:00
}
return allowedFactions ;
}
2016-11-13 12:38:42 +02:00
2023-04-09 17:26:32 +02:00
std : : set < FactionID > CTownHandler : : getAllowedFactions ( bool withTown ) const
2014-05-23 18:12:31 +03:00
{
2023-04-09 17:26:32 +02:00
std : : set < FactionID > allowedFactions ;
2014-10-30 14:03:53 +02:00
std : : vector < bool > allowed ;
if ( withTown )
allowed = getDefaultAllowed ( ) ;
else
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
allowed . resize ( objects . size ( ) , true ) ;
2015-12-02 20:59:38 +02:00
2014-05-23 18:12:31 +03:00
for ( size_t i = 0 ; i < allowed . size ( ) ; i + + )
if ( allowed [ i ] )
2023-04-09 17:26:32 +02:00
allowedFactions . insert ( static_cast < FactionID > ( i ) ) ;
2014-05-23 18:12:31 +03:00
return allowedFactions ;
2014-06-04 11:25:13 +03:00
}
2016-02-14 13:22:46 +02:00
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
const std : : vector < std : : string > & CTownHandler : : getTypeNames ( ) const
2016-02-14 13:22:46 +02:00
{
Entities redesign and a few ERM features
* Made most Handlers derived from CHandlerBase and moved service API there.
* Declared existing Entity APIs.
* Added basic script context caching
* Started Lua script module
* Started Lua spell effect API
* Started script state persistence
* Started battle info callback binding
* CommitPackage removed
* Extracted spells::Caster to own header; Expanded Spell API.
* implemented !!MC:S, !!FU:E, !!FU:P, !!MA, !!VR:H, !!VR:C
* !!BU:C, !!BU:E, !!BU:G, !!BU:M implemented
* Allow use of "MC:S@varName@" to declare normal variable (technically v-variable with string key)
* Re-enabled VERM macros.
* !?GM0 added
* !?TM implemented
* Added !!MF:N
* Started !?OB, !!BM, !!HE, !!OW, !!UN
* Added basic support of w-variables
* Added support for ERM indirect variables
* Made !?FU regular trigger
* !!re (ERA loop receiver) implemented
* Fixed ERM receivers with zero args.
2018-03-17 16:58:30 +02:00
static const std : : vector < std : : string > typeNames = { " faction " , " town " } ;
return typeNames ;
2016-02-14 13:22:46 +02:00
}
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_END