CModHandler.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #include "StdInc.h"
  2. #include "CModHandler.h"
  3. #include "JsonNode.h"
  4. #include "Filesystem/CResourceLoader.h"
  5. #include "Filesystem/ISimpleResourceLoader.h"
  6. /*
  7. * CModHandler.h, part of VCMI engine
  8. *
  9. * Authors: listed in file AUTHORS in main folder
  10. *
  11. * License: GNU General Public License v2.0 or later
  12. * Full text of license available in license.txt file, in main folder
  13. *
  14. */
  15. class CArtHandler;
  16. class CHeroHandler;
  17. class CCreatureHandler;
  18. class CSpellHandler;
  19. class CBuildingHandler;
  20. class CObjectHandler;
  21. class CDefObjInfoHandler;
  22. class CTownHandler;
  23. class CGeneralTextHandler;
  24. class ResourceLocator;
  25. CModHandler::CModHandler()
  26. {
  27. VLC->modh = this;
  28. loadConfigFromFile ("defaultMods");
  29. //CResourceHandler::loadModsFilesystems(); //scan for all mods
  30. //TODO: mod filesystem is already initialized at LibClasses launch
  31. //TODO: load default (last?) config
  32. }
  33. artID CModHandler::addNewArtifact (CArtifact * art)
  34. {
  35. int id = artifacts.size();
  36. artifacts.push_back (art);
  37. return id;
  38. }
  39. creID CModHandler::addNewCreature (CCreature * cre)
  40. {
  41. int id = creatures.size();
  42. creatures.push_back (cre);
  43. return id;
  44. }
  45. void CModHandler::loadConfigFromFile (std::string name)
  46. {
  47. const JsonNode config(ResourceID("config/" + name + ".json"));
  48. auto hardcodedFeatures = config["hardcodedFeatures"];
  49. settings.CREEP_SIZE = hardcodedFeatures["CREEP_SIZE"].Float();
  50. settings.WEEKLY_GROWTH = hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Float();
  51. settings.NEUTRAL_STACK_EXP = hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Float();
  52. settings.MAX_BUILDING_PER_TURN = hardcodedFeatures["MAX_BUILDING_PER_TURN"].Float();
  53. settings.DWELLINGS_ACCUMULATE_CREATURES = hardcodedFeatures["DWELLINGS_ACCUMULATE_CREATURES"].Bool();
  54. settings.ALL_CREATURES_GET_DOUBLE_MONTHS = hardcodedFeatures["ALL_CREATURES_GET_DOUBLE_MONTHS"].Bool();
  55. auto gameModules = config["modules"];
  56. modules.STACK_EXP = gameModules["STACK_EXPERIENCE"].Bool();
  57. modules.STACK_ARTIFACT = gameModules["STACK_ARTIFACTS"].Bool();
  58. modules.COMMANDERS = gameModules["COMMANDERS"].Bool();
  59. modules.MITHRIL = gameModules["MITHRIL"].Bool();
  60. //TODO: load only mods from the list
  61. //TODO: read mods from Mods/ folder
  62. auto & configList = CResourceHandler::get()->getResourcesWithName (ResourceID("CONFIG/MODS/HOTA/MOD", EResType::TEXT));
  63. BOOST_FOREACH(auto & entry, configList)
  64. {
  65. auto stream = entry.getLoader()->load (entry.getResourceName());
  66. std::unique_ptr<ui8[]> textData (new ui8[stream->getSize()]);
  67. stream->read (textData.get(), stream->getSize());
  68. tlog3 << "\t\tFound mod file: " << entry.getResourceName() << "\n";
  69. const JsonNode config ((char*)textData.get(), stream->getSize());
  70. const JsonNode *value = &config["creatures"];
  71. if (!value->isNull())
  72. {
  73. BOOST_FOREACH (auto creature, value->Vector())
  74. {
  75. auto cre = loadCreature (creature); //create and push back creature
  76. }
  77. }
  78. }
  79. }
  80. void CModHandler::saveConfigToFile (std::string name)
  81. {
  82. //JsonNode savedConf = config;
  83. //JsonNode schema(ResourceID("config/defaultSettings.json"));
  84. //savedConf.Struct().erase("session");
  85. //savedConf.minimize(schema);
  86. CResourceHandler::get()->createResource("config/" + name +".json");
  87. std::ofstream file(CResourceHandler::get()->getResourceName(ResourceID("config/" + name +".json")), std::ofstream::trunc);
  88. //file << savedConf;
  89. }
  90. CCreature * CModHandler::loadCreature (const JsonNode &node)
  91. {
  92. CCreature * cre = new CCreature();
  93. cre->idNumber = creatures.size();
  94. const JsonNode *value; //optional value
  95. //TODO: ref name?
  96. auto name = node["name"];
  97. cre->nameSing = name["singular"].String();
  98. cre->namePl = name["plural"].String();
  99. cre->nameRef = cre->nameSing;
  100. //TODO: export resource set to separate function?
  101. auto cost = node["cost"];
  102. if (cost.getType() == JsonNode::DATA_FLOAT) //gold
  103. {
  104. cre->cost[Res::GOLD] = cost.Float();
  105. }
  106. else if (cost.getType() == JsonNode::DATA_VECTOR)
  107. {
  108. int i = 0;
  109. BOOST_FOREACH (auto val, cost.Vector())
  110. {
  111. cre->cost[i++] = val.Float();
  112. }
  113. }
  114. else //damn you...
  115. {
  116. value = &cost["gold"];
  117. if (!value->isNull())
  118. cre->cost[Res::GOLD] = value->Float();
  119. value = &cost["gems"];
  120. if (!value->isNull())
  121. cre->cost[Res::GEMS] = value->Float();
  122. value = &cost["crystal"];
  123. if (!value->isNull())
  124. cre->cost[Res::CRYSTAL] = value->Float();
  125. value = &cost["mercury"];
  126. if (!value->isNull())
  127. cre->cost[Res::MERCURY] = value->Float();
  128. value = &cost["sulfur"];
  129. if (!value->isNull())
  130. cre->cost[Res::SULFUR] = value->Float();
  131. value = &cost["ore"];
  132. if (!value->isNull())
  133. cre->cost[Res::ORE] = value->Float();
  134. value = &cost["wood"];
  135. if (!value->isNull())
  136. cre->cost[Res::WOOD] = value->Float();
  137. value = &cost["mithril"];
  138. if (!value->isNull())
  139. cre->cost[Res::MITHRIL] = value->Float();
  140. }
  141. cre->level = node["level"].Float();
  142. cre->faction = -1; //TODO: node["faction"].String() to id or just node["faction"].Float();
  143. cre->fightValue = node["fightValue"].Float();
  144. cre->AIValue = node["aiValue"].Float();
  145. cre->growth = node["growth"].Float();
  146. cre->addBonus(node["hitPoints"].Float(), Bonus::STACK_HEALTH);
  147. cre->addBonus(node["speed"].Float(), Bonus::STACKS_SPEED);
  148. cre->addBonus(node["attack"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
  149. cre->addBonus(node["defense"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
  150. auto vec = node["damage"];
  151. cre->addBonus(vec["min"].Float(), Bonus::CREATURE_DAMAGE, 1);
  152. cre->addBonus(vec["max"].Float(), Bonus::CREATURE_DAMAGE, 2);
  153. //optional
  154. value = &node["upgrades"];
  155. if (!value->isNull())
  156. {
  157. BOOST_FOREACH (auto str, value->Vector())
  158. {
  159. cre->upgradeNames.insert (str.String());
  160. }
  161. }
  162. value = &node["shots"];
  163. if (!value->isNull())
  164. cre->addBonus(value->Float(), Bonus::SHOTS);
  165. value = &node["spellPoints"];
  166. if (!value->isNull())
  167. cre->addBonus(value->Float(), Bonus::CASTS);
  168. value = &node["doubleWide"];
  169. if (!value->isNull())
  170. cre->doubleWide = value->Bool();
  171. else
  172. cre->doubleWide = false;
  173. value = &node["abilities"];
  174. if (!value->isNull())
  175. {
  176. BOOST_FOREACH (const JsonNode &bonus, value->Vector())
  177. {
  178. cre->addNewBonus(ParseBonus(bonus));
  179. }
  180. }
  181. //graphics
  182. auto graphics = node["graphics"];
  183. cre->animDefName = graphics["animation"].String();
  184. cre->timeBetweenFidgets = graphics["timeBetweenFidgets"].Float();
  185. cre->troopCountLocationOffset = graphics["troopCountLocationOffset"].Float();
  186. cre->attackClimaxFrame = graphics["attackClimaxFrame"].Float();
  187. auto animationTime = graphics["animationTime"];
  188. cre->walkAnimationTime = animationTime["walk"].Float();
  189. cre->attackAnimationTime = animationTime["attack"].Float();
  190. cre->flightAnimationDistance = animationTime["flight"].Float(); //?
  191. //TODO: background?
  192. auto missle = graphics["missle"];
  193. auto offsets = missle["offset"];
  194. cre->upperRightMissleOffsetX = offsets["upperX"].Float();
  195. cre->upperRightMissleOffsetY = offsets["upperY"].Float();
  196. cre->rightMissleOffsetX = offsets["middleX"].Float();
  197. cre->rightMissleOffsetY = offsets["middleY"].Float();
  198. cre->lowerRightMissleOffsetX = offsets["lowerX"].Float();
  199. cre->lowerRightMissleOffsetY = offsets["lowerY"].Float();
  200. int i = 0;
  201. BOOST_FOREACH (auto angle, missle["frameAngles"].Vector())
  202. {
  203. cre->missleFrameAngles[i++] = angle.Float();
  204. }
  205. //TODO: we need to know creature id to add it
  206. //FIXME: creature handler is not yet initialized
  207. //VLC->creh->idToProjectile[cre->idNumber] = "PLCBOWX.DEF";
  208. cre->projectile = "PLCBOWX.DEF";
  209. auto sounds = node["sound"];
  210. #define GET_SOUND_VALUE(value_name) do { value = &node[#value_name]; if (!value->isNull()) cre->sounds.value_name = sounds[#value_name].String(); } while(0)
  211. GET_SOUND_VALUE(attack);
  212. GET_SOUND_VALUE(defend);
  213. GET_SOUND_VALUE(killed);
  214. GET_SOUND_VALUE(move);
  215. GET_SOUND_VALUE(shoot);
  216. GET_SOUND_VALUE(wince);
  217. GET_SOUND_VALUE(ext1);
  218. GET_SOUND_VALUE(ext2);
  219. GET_SOUND_VALUE(startMoving);
  220. GET_SOUND_VALUE(endMoving);
  221. #undef GET_SOUND_VALUE
  222. creatures.push_back(cre);
  223. return cre;
  224. }
  225. void CModHandler::recreateHandlers()
  226. {
  227. //TODO: consider some template magic to unify all handlers?
  228. //VLC->arth->artifacts.clear();
  229. //VLC->creh->creatures.clear(); //TODO: what about items from original game?
  230. BOOST_FOREACH (auto creature, creatures)
  231. {
  232. VLC->creh->creatures.push_back (creature);
  233. //TODO: use refName?
  234. //if (creature->nameRef.size())
  235. // VLC->creh->nameToID[creature->nameRef] = creature->idNumber;
  236. VLC->creh->nameToID[creature->nameSing] = creature->idNumber;
  237. }
  238. BOOST_FOREACH (auto creature, VLC->creh->creatures) //populate upgrades described with string
  239. {
  240. BOOST_FOREACH (auto upgradeName, creature->upgradeNames)
  241. {
  242. auto it = VLC->creh->nameToID.find(upgradeName);
  243. if (it != VLC->creh->nameToID.end())
  244. {
  245. creature->upgrades.insert (it->second);
  246. }
  247. }
  248. }
  249. VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded
  250. BOOST_FOREACH (auto mod, activeMods) //inactive part
  251. {
  252. BOOST_FOREACH (auto art, allMods[mod].artifacts)
  253. {
  254. VLC->arth->artifacts.push_back (artifacts[art]);
  255. //TODO: recreate types / limiters based on string id
  256. }
  257. BOOST_FOREACH (auto creature, allMods[mod].creatures)
  258. {
  259. VLC->creh->creatures.push_back (creatures[creature]);
  260. //TODO VLC->creh->notUsedMonster.push_back (creatures[creature]);
  261. //TODO: recreate upgrades and other properties based on string id
  262. }
  263. }
  264. }
  265. CModHandler::~CModHandler()
  266. {
  267. }