CModHandler.cpp 11 KB

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