2012-08-10 16:07:53 +03:00
# include "StdInc.h"
# include "CModHandler.h"
2012-08-11 12:06:23 +03:00
# include "JsonNode.h"
2012-09-20 19:14:23 +03:00
# include "Filesystem/CResourceLoader.h"
# include "Filesystem/ISimpleResourceLoader.h"
2012-08-10 16:07:53 +03:00
/*
* CModHandler . 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
*
*/
class CArtHandler ;
class CHeroHandler ;
class CCreatureHandler ;
class CSpellHandler ;
class CBuildingHandler ;
class CObjectHandler ;
class CDefObjInfoHandler ;
class CTownHandler ;
class CGeneralTextHandler ;
2012-09-19 19:10:45 +03:00
class ResourceLocator ;
2012-08-10 16:07:53 +03:00
CModHandler : : CModHandler ( )
{
VLC - > modh = this ;
2012-08-11 12:06:23 +03:00
loadConfigFromFile ( " defaultMods " ) ;
2012-08-10 16:07:53 +03:00
//CResourceHandler::loadModsFilesystems(); //scan for all mods
//TODO: mod filesystem is already initialized at LibClasses launch
//TODO: load default (last?) config
}
artID CModHandler : : addNewArtifact ( CArtifact * art )
{
int id = artifacts . size ( ) ;
artifacts . push_back ( art ) ;
return id ;
}
creID CModHandler : : addNewCreature ( CCreature * cre )
{
int id = creatures . size ( ) ;
creatures . push_back ( cre ) ;
return id ;
}
void CModHandler : : loadConfigFromFile ( std : : string name )
2012-08-11 12:06:23 +03:00
{
const JsonNode config ( ResourceID ( " config/ " + name + " .json " ) ) ;
auto hardcodedFeatures = config [ " hardcodedFeatures " ] ;
settings . CREEP_SIZE = hardcodedFeatures [ " CREEP_SIZE " ] . Float ( ) ;
settings . WEEKLY_GROWTH = hardcodedFeatures [ " WEEKLY_GROWTH_PERCENT " ] . Float ( ) ;
settings . NEUTRAL_STACK_EXP = hardcodedFeatures [ " NEUTRAL_STACK_EXP_DAILY " ] . Float ( ) ;
2012-09-05 15:49:23 +03:00
settings . MAX_BUILDING_PER_TURN = hardcodedFeatures [ " MAX_BUILDING_PER_TURN " ] . Float ( ) ;
2012-08-11 12:06:23 +03:00
settings . DWELLINGS_ACCUMULATE_CREATURES = hardcodedFeatures [ " DWELLINGS_ACCUMULATE_CREATURES " ] . Bool ( ) ;
settings . ALL_CREATURES_GET_DOUBLE_MONTHS = hardcodedFeatures [ " ALL_CREATURES_GET_DOUBLE_MONTHS " ] . Bool ( ) ;
2012-08-24 12:37:52 +03:00
auto gameModules = config [ " modules " ] ;
modules . STACK_EXP = gameModules [ " STACK_EXPERIENCE " ] . Bool ( ) ;
modules . STACK_ARTIFACT = gameModules [ " STACK_ARTIFACTS " ] . Bool ( ) ;
modules . COMMANDERS = gameModules [ " COMMANDERS " ] . Bool ( ) ;
modules . MITHRIL = gameModules [ " MITHRIL " ] . Bool ( ) ;
2012-09-18 10:36:07 +03:00
2012-09-19 19:10:45 +03:00
//TODO: load only mods from the list
2012-09-18 10:36:07 +03:00
2012-09-19 19:10:45 +03:00
//TODO: read mods from Mods/ folder
2012-09-18 10:36:07 +03:00
2012-09-20 19:14:23 +03:00
auto & configList = CResourceHandler : : get ( ) - > getResourcesWithName ( ResourceID ( " CONFIG/MODS/HOTA/MOD " , EResType : : TEXT ) ) ;
2012-09-18 10:36:07 +03:00
2012-09-20 19:14:23 +03:00
BOOST_FOREACH ( auto & entry , configList )
{
auto stream = entry . getLoader ( ) - > load ( entry . getResourceName ( ) ) ;
std : : unique_ptr < ui8 [ ] > textData ( new ui8 [ stream - > getSize ( ) ] ) ;
stream - > read ( textData . get ( ) , stream - > getSize ( ) ) ;
2012-09-18 10:36:07 +03:00
2012-09-19 19:10:45 +03:00
tlog3 < < " \t \t Found mod file: " < < entry . getResourceName ( ) < < " \n " ;
const JsonNode config ( ( char * ) textData . get ( ) , stream - > getSize ( ) ) ;
2012-09-18 10:36:07 +03:00
const JsonNode * value = & config [ " creatures " ] ;
if ( ! value - > isNull ( ) )
{
BOOST_FOREACH ( auto creature , value - > Vector ( ) )
{
2012-09-19 19:10:45 +03:00
auto cre = loadCreature ( creature ) ; //create and push back creature
2012-09-18 10:36:07 +03:00
}
}
}
2012-09-19 19:10:45 +03:00
2012-08-11 12:06:23 +03:00
}
2012-08-10 16:07:53 +03:00
void CModHandler : : saveConfigToFile ( std : : string name )
2012-08-11 12:06:23 +03:00
{
//JsonNode savedConf = config;
//JsonNode schema(ResourceID("config/defaultSettings.json"));
//savedConf.Struct().erase("session");
//savedConf.minimize(schema);
CResourceHandler : : get ( ) - > createResource ( " config/ " + name + " .json " ) ;
std : : ofstream file ( CResourceHandler : : get ( ) - > getResourceName ( ResourceID ( " config/ " + name + " .json " ) ) , std : : ofstream : : trunc ) ;
//file << savedConf;
}
2012-08-30 17:57:24 +03:00
CCreature * CModHandler : : loadCreature ( const JsonNode & node )
{
CCreature * cre = new CCreature ( ) ;
cre - > idNumber = creatures . size ( ) ;
const JsonNode * value ; //optional value
2012-09-19 19:10:45 +03:00
//TODO: ref name?
2012-08-30 17:57:24 +03:00
auto name = node [ " name " ] ;
cre - > nameSing = name [ " singular " ] . String ( ) ;
cre - > namePl = name [ " plural " ] . String ( ) ;
2012-09-19 19:10:45 +03:00
cre - > nameRef = cre - > nameSing ;
2012-08-30 17:57:24 +03:00
2012-09-19 19:10:45 +03:00
//TODO: export resource set to separate function?
2012-08-30 17:57:24 +03:00
auto cost = node [ " cost " ] ;
if ( cost . getType ( ) = = JsonNode : : DATA_FLOAT ) //gold
{
cre - > cost [ Res : : GOLD ] = cost . Float ( ) ;
}
2012-09-19 19:10:45 +03:00
else if ( cost . getType ( ) = = JsonNode : : DATA_VECTOR )
2012-08-30 17:57:24 +03:00
{
int i = 0 ;
BOOST_FOREACH ( auto val , cost . Vector ( ) )
{
cre - > cost [ i + + ] = val . Float ( ) ;
}
}
2012-09-19 19:10:45 +03:00
else //damn you...
{
value = & cost [ " gold " ] ;
if ( ! value - > isNull ( ) )
cre - > cost [ Res : : GOLD ] = value - > Float ( ) ;
value = & cost [ " gems " ] ;
if ( ! value - > isNull ( ) )
cre - > cost [ Res : : GEMS ] = value - > Float ( ) ;
value = & cost [ " crystal " ] ;
if ( ! value - > isNull ( ) )
cre - > cost [ Res : : CRYSTAL ] = value - > Float ( ) ;
value = & cost [ " mercury " ] ;
if ( ! value - > isNull ( ) )
cre - > cost [ Res : : MERCURY ] = value - > Float ( ) ;
value = & cost [ " sulfur " ] ;
if ( ! value - > isNull ( ) )
cre - > cost [ Res : : SULFUR ] = value - > Float ( ) ;
value = & cost [ " ore " ] ;
if ( ! value - > isNull ( ) )
cre - > cost [ Res : : ORE ] = value - > Float ( ) ;
value = & cost [ " wood " ] ;
if ( ! value - > isNull ( ) )
cre - > cost [ Res : : WOOD ] = value - > Float ( ) ;
value = & cost [ " mithril " ] ;
if ( ! value - > isNull ( ) )
cre - > cost [ Res : : MITHRIL ] = value - > Float ( ) ;
}
2012-08-30 17:57:24 +03:00
cre - > level = node [ " level " ] . Float ( ) ;
cre - > faction = - 1 ; //TODO: node["faction"].String() to id or just node["faction"].Float();
cre - > fightValue = node [ " fightValue " ] . Float ( ) ;
cre - > AIValue = node [ " aiValue " ] . Float ( ) ;
cre - > growth = node [ " growth " ] . Float ( ) ;
cre - > addBonus ( node [ " hitPoints " ] . Float ( ) , Bonus : : STACK_HEALTH ) ;
cre - > addBonus ( node [ " speed " ] . Float ( ) , Bonus : : STACKS_SPEED ) ;
cre - > addBonus ( node [ " attack " ] . Float ( ) , Bonus : : PRIMARY_SKILL , PrimarySkill : : ATTACK ) ;
cre - > addBonus ( node [ " defense " ] . Float ( ) , Bonus : : PRIMARY_SKILL , PrimarySkill : : DEFENSE ) ;
2012-09-19 19:10:45 +03:00
auto vec = node [ " damage " ] ;
cre - > addBonus ( vec [ " min " ] . Float ( ) , Bonus : : CREATURE_DAMAGE , 1 ) ;
cre - > addBonus ( vec [ " max " ] . Float ( ) , Bonus : : CREATURE_DAMAGE , 2 ) ;
2012-08-30 17:57:24 +03:00
//optional
2012-09-19 19:10:45 +03:00
value = & node [ " upgrades " ] ;
if ( ! value - > isNull ( ) )
{
BOOST_FOREACH ( auto str , value - > Vector ( ) )
{
cre - > upgradeNames . insert ( str . String ( ) ) ;
}
}
2012-08-30 17:57:24 +03:00
value = & node [ " shots " ] ;
if ( ! value - > isNull ( ) )
cre - > addBonus ( value - > Float ( ) , Bonus : : SHOTS ) ;
value = & node [ " spellPoints " ] ;
if ( ! value - > isNull ( ) )
cre - > addBonus ( value - > Float ( ) , Bonus : : CASTS ) ;
2012-09-19 19:10:45 +03:00
value = & node [ " doubleWide " ] ;
if ( ! value - > isNull ( ) )
cre - > doubleWide = value - > Bool ( ) ;
else
cre - > doubleWide = false ;
2012-08-30 17:57:24 +03:00
value = & node [ " abilities " ] ;
if ( ! value - > isNull ( ) )
{
BOOST_FOREACH ( const JsonNode & bonus , value - > Vector ( ) )
{
cre - > addNewBonus ( ParseBonus ( bonus ) ) ;
}
}
//graphics
auto graphics = node [ " graphics " ] ;
cre - > animDefName = graphics [ " animation " ] . String ( ) ;
cre - > timeBetweenFidgets = graphics [ " timeBetweenFidgets " ] . Float ( ) ;
cre - > troopCountLocationOffset = graphics [ " troopCountLocationOffset " ] . Float ( ) ;
cre - > attackClimaxFrame = graphics [ " attackClimaxFrame " ] . Float ( ) ;
auto animationTime = graphics [ " animationTime " ] ;
cre - > walkAnimationTime = animationTime [ " walk " ] . Float ( ) ;
cre - > attackAnimationTime = animationTime [ " attack " ] . Float ( ) ;
cre - > flightAnimationDistance = animationTime [ " flight " ] . Float ( ) ; //?
//TODO: background?
auto missle = graphics [ " missle " ] ;
auto offsets = missle [ " offset " ] ;
cre - > upperRightMissleOffsetX = offsets [ " upperX " ] . Float ( ) ;
cre - > upperRightMissleOffsetY = offsets [ " upperY " ] . Float ( ) ;
cre - > rightMissleOffsetX = offsets [ " middleX " ] . Float ( ) ;
cre - > rightMissleOffsetY = offsets [ " middleY " ] . Float ( ) ;
cre - > lowerRightMissleOffsetX = offsets [ " lowerX " ] . Float ( ) ;
cre - > lowerRightMissleOffsetY = offsets [ " lowerY " ] . Float ( ) ;
int i = 0 ;
BOOST_FOREACH ( auto angle , missle [ " frameAngles " ] . Vector ( ) )
{
cre - > missleFrameAngles [ i + + ] = angle . Float ( ) ;
}
2012-09-19 19:10:45 +03:00
//TODO: we need to know creature id to add it
//FIXME: creature handler is not yet initialized
//VLC->creh->idToProjectile[cre->idNumber] = "PLCBOWX.DEF";
cre - > projectile = " PLCBOWX.DEF " ;
2012-08-30 17:57:24 +03:00
auto sounds = node [ " sound " ] ;
2012-09-17 22:00:26 +03:00
# define GET_SOUND_VALUE(value_name) do { value = &node[#value_name]; if (!value->isNull()) cre->sounds.value_name = sounds[#value_name].String(); } while(0)
GET_SOUND_VALUE ( attack ) ;
GET_SOUND_VALUE ( defend ) ;
GET_SOUND_VALUE ( killed ) ;
GET_SOUND_VALUE ( move ) ;
GET_SOUND_VALUE ( shoot ) ;
GET_SOUND_VALUE ( wince ) ;
GET_SOUND_VALUE ( ext1 ) ;
GET_SOUND_VALUE ( ext2 ) ;
GET_SOUND_VALUE ( startMoving ) ;
GET_SOUND_VALUE ( endMoving ) ;
# undef GET_SOUND_VALUE
2012-08-30 17:57:24 +03:00
creatures . push_back ( cre ) ;
return cre ;
}
2012-08-10 16:07:53 +03:00
void CModHandler : : recreateHandlers ( )
{
//TODO: consider some template magic to unify all handlers?
2012-09-18 10:36:07 +03:00
//VLC->arth->artifacts.clear();
//VLC->creh->creatures.clear(); //TODO: what about items from original game?
BOOST_FOREACH ( auto creature , creatures )
{
VLC - > creh - > creatures . push_back ( creature ) ;
2012-09-19 19:10:45 +03:00
//TODO: use refName?
//if (creature->nameRef.size())
// VLC->creh->nameToID[creature->nameRef] = creature->idNumber;
VLC - > creh - > nameToID [ creature - > nameSing ] = creature - > idNumber ;
}
BOOST_FOREACH ( auto creature , VLC - > creh - > creatures ) //populate upgrades described with string
{
BOOST_FOREACH ( auto upgradeName , creature - > upgradeNames )
{
auto it = VLC - > creh - > nameToID . find ( upgradeName ) ;
if ( it ! = VLC - > creh - > nameToID . end ( ) )
{
creature - > upgrades . insert ( it - > second ) ;
}
}
2012-09-18 10:36:07 +03:00
}
2012-08-10 16:07:53 +03:00
2012-09-19 19:10:45 +03:00
VLC - > creh - > buildBonusTreeForTiers ( ) ; //do that after all new creatures are loaded
2012-09-18 10:36:07 +03:00
BOOST_FOREACH ( auto mod , activeMods ) //inactive part
2012-08-10 16:07:53 +03:00
{
BOOST_FOREACH ( auto art , allMods [ mod ] . artifacts )
{
VLC - > arth - > artifacts . push_back ( artifacts [ art ] ) ;
2012-08-24 12:37:52 +03:00
//TODO: recreate types / limiters based on string id
2012-08-10 16:07:53 +03:00
}
BOOST_FOREACH ( auto creature , allMods [ mod ] . creatures )
{
VLC - > creh - > creatures . push_back ( creatures [ creature ] ) ;
2012-09-18 10:36:07 +03:00
//TODO VLC->creh->notUsedMonster.push_back (creatures[creature]);
2012-08-24 12:37:52 +03:00
//TODO: recreate upgrades and other properties based on string id
2012-08-10 16:07:53 +03:00
}
}
}
CModHandler : : ~ CModHandler ( )
{
2012-09-05 15:49:23 +03:00
}