CCreatureHandler.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092
  1. #include "StdInc.h"
  2. #include "CCreatureHandler.h"
  3. #include "CLodHandler.h"
  4. #include "../lib/VCMI_Lib.h"
  5. #include "../lib/CGameState.h"
  6. #include "../lib/JsonNode.h"
  7. #include "CHeroHandler.h"
  8. using namespace boost::assign;
  9. extern CLodHandler * bitmaph;
  10. /*
  11. * CCreatureHandler.cpp, part of VCMI engine
  12. *
  13. * Authors: listed in file AUTHORS in main folder
  14. *
  15. * License: GNU General Public License v2.0 or later
  16. * Full text of license available in license.txt file, in main folder
  17. *
  18. */
  19. CCreatureHandler::CCreatureHandler()
  20. {
  21. VLC->creh = this;
  22. // Set the faction alignments to the defaults:
  23. // Good: Castle, Rampart, Tower
  24. // Evil: Inferno, Necropolis, Dungeon
  25. // Neutral: Stronghold, Fortess, Conflux
  26. factionAlignments += 1, 1, 1, -1, -1, -1, 0, 0, 0;
  27. doubledCreatures += 4, 14, 20, 28, 44, 60, 70, 72, 85, 86, 100, 104; //according to Strategija
  28. allCreatures.setDescription("All creatures");
  29. creaturesOfLevel[0].setDescription("Creatures of unnormalized tier");
  30. for(int i = 1; i < ARRAY_COUNT(creaturesOfLevel); i++)
  31. creaturesOfLevel[i].setDescription("Creatures of tier " + boost::lexical_cast<std::string>(i));
  32. }
  33. int CCreature::getQuantityID(const int & quantity)
  34. {
  35. if (quantity<5)
  36. return 1;
  37. if (quantity<10)
  38. return 2;
  39. if (quantity<20)
  40. return 3;
  41. if (quantity<50)
  42. return 4;
  43. if (quantity<100)
  44. return 5;
  45. if (quantity<250)
  46. return 6;
  47. if (quantity<500)
  48. return 7;
  49. if (quantity<1000)
  50. return 8;
  51. return 9;
  52. }
  53. int CCreature::estimateCreatureCount(ui32 countID)
  54. {
  55. static const int creature_count[] = { 0, 3, 8, 15, 35, 75, 175, 375, 750, 2500 };
  56. if (countID > 9)
  57. assert("Wrong countID!");
  58. return creature_count[countID];
  59. }
  60. bool CCreature::isDoubleWide() const
  61. {
  62. return doubleWide;
  63. }
  64. bool CCreature::isFlying() const
  65. {
  66. return hasBonusOfType(Bonus::FLYING);
  67. }
  68. bool CCreature::isShooting() const
  69. {
  70. return hasBonusOfType(Bonus::SHOOTER);
  71. }
  72. bool CCreature::isUndead() const
  73. {
  74. return hasBonusOfType(Bonus::UNDEAD);
  75. }
  76. /**
  77. * Determines if the creature is of a good alignment.
  78. * @return true if the creture is good, false otherwise.
  79. */
  80. bool CCreature::isGood () const
  81. {
  82. return VLC->creh->isGood(faction);
  83. }
  84. /**
  85. * Determines if the creature is of an evil alignment.
  86. * @return true if the creature is evil, false otherwise.
  87. */
  88. bool CCreature::isEvil () const
  89. {
  90. return VLC->creh->isEvil(faction);
  91. }
  92. si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatures can be bought
  93. {
  94. int ret = 2147483645;
  95. int resAmnt = std::min(res.size(),cost.size());
  96. for(int i=0;i<resAmnt;i++)
  97. if(cost[i])
  98. ret = std::min(ret,(int)(res[i]/cost[i]));
  99. return ret;
  100. }
  101. CCreature::CCreature()
  102. {
  103. doubleWide = false;
  104. setNodeType(CBonusSystemNode::CREATURE);
  105. }
  106. void CCreature::addBonus(int val, int type, int subtype /*= -1*/)
  107. {
  108. Bonus *added = new Bonus(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, idNumber, subtype, Bonus::BASE_NUMBER);
  109. addNewBonus(added);
  110. }
  111. // void CCreature::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const
  112. // {
  113. // out.insert (VLC->creh->globalEffects);
  114. // }
  115. bool CCreature::isMyUpgrade(const CCreature *anotherCre) const
  116. {
  117. //TODO upgrade of upgrade?
  118. return vstd::contains(upgrades, anotherCre->idNumber);
  119. }
  120. bool CCreature::valid() const
  121. {
  122. return this == VLC->creh->creatures[idNumber];
  123. }
  124. std::string CCreature::nodeName() const
  125. {
  126. return "\"" + namePl + "\"";
  127. }
  128. bool CCreature::isItNativeTerrain(int terrain) const
  129. {
  130. if(!vstd::iswithin(faction, 0, 9))
  131. return false;
  132. //not good handler dependency
  133. return VLC->heroh->nativeTerrains[faction] == terrain;
  134. }
  135. int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
  136. {
  137. befi=i;
  138. for(; i<andame; ++i)
  139. {
  140. if(buf[i]=='\t')
  141. break;
  142. }
  143. std::string tmp = buf.substr(befi, i-befi);
  144. int ret = atoi(buf.substr(befi, i-befi).c_str());
  145. ++i;
  146. return ret;
  147. }
  148. double readFloat(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadUnitAnimInfo()
  149. {
  150. befi=i;
  151. for(; i<andame; ++i)
  152. {
  153. if(buf[i]=='\t')
  154. break;
  155. }
  156. std::string tmp = buf.substr(befi, i-befi);
  157. double ret = atof(buf.substr(befi, i-befi).c_str());
  158. ++i;
  159. return ret;
  160. }
  161. /**
  162. * Determines if a faction is good.
  163. * @param ID of the faction.
  164. * @return true if the faction is good, false otherwise.
  165. */
  166. bool CCreatureHandler::isGood (si8 faction) const
  167. {
  168. return faction != -1 && factionAlignments[faction] == 1;
  169. }
  170. /**
  171. * Determines if a faction is evil.
  172. * @param ID of the faction.
  173. * @return true if the faction is evil, false otherwise.
  174. */
  175. bool CCreatureHandler::isEvil (si8 faction) const
  176. {
  177. return faction != -1 && factionAlignments[faction] == -1;
  178. }
  179. static Bonus * ParseBonus (const JsonVector &ability_vec) //TODO: merge with AddAbility, create universal parser for all bonus properties
  180. {
  181. Bonus * b = new Bonus();
  182. std::string type = ability_vec[0].String();
  183. auto it = bonusNameMap.find(type);
  184. if (it == bonusNameMap.end())
  185. {
  186. tlog1 << "Error: invalid ability type " << type << " in creatures.txt" << std::endl;
  187. return b;
  188. }
  189. b->type = it->second;
  190. b->val = ability_vec[1].Float();
  191. b->subtype = ability_vec[2].Float();
  192. b->additionalInfo = ability_vec[3].Float();
  193. b->duration = Bonus::PERMANENT;
  194. b->turnsRemain = 0;
  195. return b;
  196. }
  197. static void AddAbility(CCreature *cre, const JsonVector &ability_vec)
  198. {
  199. Bonus *nsf = new Bonus();
  200. std::string type = ability_vec[0].String();
  201. std::map<std::string, int>::const_iterator it = bonusNameMap.find(type);
  202. if (it == bonusNameMap.end()) {
  203. if (type == "DOUBLE_WIDE")
  204. cre->doubleWide = true;
  205. else if (type == "ENEMY_MORALE_DECREASING") {
  206. cre->addBonus(-1, Bonus::MORALE);
  207. cre->getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
  208. }
  209. else if (type == "ENEMY_LUCK_DECREASING") {
  210. cre->addBonus(-1, Bonus::LUCK);
  211. cre->getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
  212. } else
  213. tlog1 << "Error: invalid ability type " << type << " in creatures.txt" << std::endl;
  214. return;
  215. }
  216. nsf->type = it->second;
  217. nsf->val = ability_vec[1].Float();
  218. nsf->subtype = ability_vec[2].Float();
  219. nsf->additionalInfo = ability_vec[3].Float();
  220. nsf->source = Bonus::CREATURE_ABILITY;
  221. nsf->sid = cre->idNumber;
  222. //nsf->duration = Bonus::ONE_BATTLE; //what the?
  223. nsf->duration = Bonus::PERMANENT;
  224. nsf->turnsRemain = 0;
  225. cre->addNewBonus(nsf);
  226. }
  227. static void RemoveAbility(CCreature *cre, const JsonNode &ability)
  228. {
  229. std::string type = ability.String();
  230. std::map<std::string, int>::const_iterator it = bonusNameMap.find(type);
  231. if (it == bonusNameMap.end()) {
  232. if (type == "DOUBLE_WIDE")
  233. cre->doubleWide = false;
  234. else
  235. tlog1 << "Error: invalid ability type " << type << " in creatures.json" << std::endl;
  236. return;
  237. }
  238. int typeNo = it->second;
  239. Bonus::BonusType ecf = static_cast<Bonus::BonusType>(typeNo);
  240. Bonus *b = cre->getBonus(Selector::type(ecf));
  241. cre->removeBonus(b);
  242. }
  243. void CCreatureHandler::loadCreatures()
  244. {
  245. tlog5 << "\t\tReading config/cr_abils.json and ZCRTRAIT.TXT" << std::endl;
  246. ////////////reading ZCRTRAIT.TXT ///////////////////
  247. std::string buf = bitmaph->getTextFile("ZCRTRAIT.TXT");
  248. int andame = buf.size();
  249. int i=0; //buf iterator
  250. int hmcr=0;
  251. for(; i<andame; ++i)
  252. {
  253. if(buf[i]=='\r')
  254. ++hmcr;
  255. if(hmcr==2)
  256. break;
  257. }
  258. i+=2;
  259. while(i<buf.size())
  260. {
  261. CCreature &ncre = *new CCreature;
  262. ncre.idNumber = creatures.size();
  263. ncre.cost.resize(GameConstants::RESOURCE_QUANTITY);
  264. ncre.level=0;
  265. int befi=i;
  266. for(; i<andame; ++i)
  267. {
  268. if(buf[i]=='\t')
  269. break;
  270. }
  271. ncre.nameSing = buf.substr(befi, i-befi);
  272. ++i;
  273. befi=i;
  274. for(; i<andame; ++i)
  275. {
  276. if(buf[i]=='\t')
  277. break;
  278. }
  279. ncre.namePl = buf.substr(befi, i-befi);
  280. ++i;
  281. for(int v=0; v<7; ++v)
  282. {
  283. ncre.cost[v] = readNumber(befi, i, andame, buf);
  284. }
  285. ncre.fightValue = readNumber(befi, i, andame, buf);
  286. ncre.AIValue = readNumber(befi, i, andame, buf);
  287. ncre.growth = readNumber(befi, i, andame, buf);
  288. ncre.hordeGrowth = readNumber(befi, i, andame, buf);
  289. ncre.hitPoints = readNumber(befi, i, andame, buf);
  290. ncre.addBonus(ncre.hitPoints, Bonus::STACK_HEALTH);
  291. ncre.speed = readNumber(befi, i, andame, buf);
  292. ncre.addBonus(ncre.speed, Bonus::STACKS_SPEED);
  293. ncre.attack = readNumber(befi, i, andame, buf);
  294. ncre.addBonus(ncre.attack, Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
  295. ncre.defence = readNumber(befi, i, andame, buf);
  296. ncre.addBonus(ncre.defence, Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
  297. ncre.damageMin = readNumber(befi, i, andame, buf); //not used anymore?
  298. ncre.addBonus(ncre.damageMin, Bonus::CREATURE_DAMAGE, 1);
  299. ncre.damageMax = readNumber(befi, i, andame, buf);
  300. ncre.addBonus(ncre.damageMax, Bonus::CREATURE_DAMAGE, 2);
  301. ncre.shots = readNumber(befi, i, andame, buf);
  302. ncre.addBonus(ncre.shots, Bonus::SHOTS);
  303. ncre.spells = readNumber(befi, i, andame, buf);
  304. ncre.ammMin = readNumber(befi, i, andame, buf);
  305. ncre.ammMax = readNumber(befi, i, andame, buf);
  306. befi=i;
  307. for(; i<andame; ++i)
  308. {
  309. if(buf[i]=='\t')
  310. break;
  311. }
  312. ncre.abilityText = buf.substr(befi, i-befi);
  313. ++i;
  314. befi=i;
  315. for(; i<andame; ++i)
  316. {
  317. if(buf[i]=='\r')
  318. break;
  319. }
  320. ncre.abilityRefs = buf.substr(befi, i-befi);
  321. i+=2;
  322. if(true)
  323. { //adding abilities from ZCRTRAIT.TXT
  324. if(boost::algorithm::find_first(ncre.abilityRefs, "DOUBLE_WIDE"))
  325. ncre.doubleWide = true;
  326. if(boost::algorithm::find_first(ncre.abilityRefs, "FLYING_ARMY"))
  327. ncre.addBonus(0, Bonus::FLYING);
  328. if(boost::algorithm::find_first(ncre.abilityRefs, "SHOOTING_ARMY"))
  329. ncre.addBonus(0, Bonus::SHOOTER);
  330. if(boost::algorithm::find_first(ncre.abilityRefs, "SIEGE_WEAPON"))
  331. ncre.addBonus(0, Bonus::SIEGE_WEAPON);
  332. if(boost::algorithm::find_first(ncre.abilityRefs, "const_two_attacks"))
  333. ncre.addBonus(1, Bonus::ADDITIONAL_ATTACK);
  334. if(boost::algorithm::find_first(ncre.abilityRefs, "const_free_attack"))
  335. ncre.addBonus(0, Bonus::BLOCKS_RETALIATION);
  336. if(boost::algorithm::find_first(ncre.abilityRefs, "IS_UNDEAD"))
  337. ncre.addBonus(0, Bonus::UNDEAD);
  338. if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_melee_penalty"))
  339. ncre.addBonus(0, Bonus::NO_MELEE_PENALTY);
  340. if(boost::algorithm::find_first(ncre.abilityRefs, "const_jousting"))
  341. ncre.addBonus(0, Bonus::JOUSTING);
  342. if(boost::algorithm::find_first(ncre.abilityRefs, "const_raises_morale"))
  343. {
  344. ncre.addBonus(+1, Bonus::MORALE);;
  345. ncre.getBonusList().back()->addPropagator(make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO));
  346. }
  347. if(boost::algorithm::find_first(ncre.abilityRefs, "const_lowers_morale"))
  348. {
  349. ncre.addBonus(-1, Bonus::MORALE);;
  350. ncre.getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
  351. }
  352. if(boost::algorithm::find_first(ncre.abilityRefs, "KING_1"))
  353. ncre.addBonus(0, Bonus::KING1);
  354. if(boost::algorithm::find_first(ncre.abilityRefs, "KING_2"))
  355. ncre.addBonus(0, Bonus::KING2);
  356. if(boost::algorithm::find_first(ncre.abilityRefs, "KING_3"))
  357. ncre.addBonus(0, Bonus::KING3);
  358. if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_wall_penalty"))
  359. ncre.addBonus(0, Bonus::NO_WALL_PENALTY);
  360. if(boost::algorithm::find_first(ncre.abilityRefs, "CATAPULT"))
  361. ncre.addBonus(0, Bonus::CATAPULT);
  362. if(boost::algorithm::find_first(ncre.abilityRefs, "MULTI_HEADED"))
  363. ncre.addBonus(0, Bonus::ATTACKS_ALL_ADJACENT);
  364. if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_MIND_SPELLS"))
  365. ncre.addBonus(0, Bonus::MIND_IMMUNITY); //giants are immune to mind spells
  366. if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_FIRE_SPELLS"))
  367. ncre.addBonus(0, Bonus::FIRE_IMMUNITY);
  368. if(boost::algorithm::find_first(ncre.abilityRefs, "HAS_EXTENDED_ATTACK"))
  369. ncre.addBonus(0, Bonus::TWO_HEX_ATTACK_BREATH);;
  370. }
  371. if(ncre.nameSing!=std::string("") && ncre.namePl!=std::string(""))
  372. {
  373. ncre.idNumber = creatures.size();
  374. creatures.push_back(&ncre);
  375. }
  376. }
  377. // loading creatures properties
  378. tlog5 << "\t\tReading config/creatures.json" << std::endl;
  379. const JsonNode config(GameConstants::DATA_DIR + "/config/creatures.json");
  380. BOOST_FOREACH(const JsonNode &creature, config["creatures"].Vector())
  381. {
  382. int creatureID = creature["id"].Float();
  383. const JsonNode *value;
  384. /* A creature can have several names. */
  385. BOOST_FOREACH(const JsonNode &name, creature["name"].Vector())
  386. {
  387. boost::assign::insert(nameToID)(name.String(), creatureID);
  388. }
  389. // Set various creature properties
  390. CCreature *c = creatures[creatureID];
  391. c->level = creature["level"].Float();
  392. c->faction = creature["faction"].Float();
  393. c->animDefName = creature["defname"].String();
  394. BOOST_FOREACH(const JsonNode &value, creature["upgrades"].Vector())
  395. {
  396. c->upgrades.insert(value.Float());
  397. }
  398. value = &creature["projectile_defname"];
  399. if (!value->isNull())
  400. {
  401. idToProjectile[creatureID] = value->String();
  402. value = &creature["projectile_spin"];
  403. idToProjectileSpin[creatureID] = value->Bool();
  404. }
  405. value = &creature["turret_shooter"];
  406. if (!value->isNull() && value->Bool())
  407. factionToTurretCreature[c->faction] = creatureID;
  408. value = &creature["ability_add"];
  409. if (!value->isNull()) {
  410. BOOST_FOREACH(const JsonNode &ability, value->Vector())
  411. {
  412. AddAbility(c, ability.Vector());
  413. }
  414. }
  415. value = &creature["ability_remove"];
  416. if (!value->isNull())
  417. {
  418. BOOST_FOREACH(const JsonNode &ability, value->Vector())
  419. {
  420. RemoveAbility(c, ability);
  421. }
  422. }
  423. }
  424. BOOST_FOREACH(const JsonNode &creature, config["unused_creatures"].Vector())
  425. {
  426. notUsedMonsters += creature.Float();
  427. }
  428. buildBonusTreeForTiers();
  429. loadAnimationInfo();
  430. //reading creature ability names
  431. const JsonNode config2(GameConstants::DATA_DIR + "/config/bonusnames.json");
  432. BOOST_FOREACH(const JsonNode &bonus, config2["bonuses"].Vector())
  433. {
  434. std::map<std::string,int>::const_iterator it_map;
  435. std::string bonusID = bonus["id"].String();
  436. it_map = bonusNameMap.find(bonusID);
  437. if (it_map != bonusNameMap.end())
  438. stackBonuses[it_map->second] = std::pair<std::string, std::string>(bonus["name"].String(), bonus["description"].String());
  439. else
  440. tlog2 << "Bonus " << bonusID << " not recognized, ignoring\n";
  441. }
  442. //handle magic resistance secondary skill premy, potentialy may be buggy
  443. //std::map<TBonusType, std::pair<std::string, std::string> >::iterator it = stackBonuses.find(Bonus::MAGIC_RESISTANCE);
  444. //stackBonuses[Bonus::SECONDARY_SKILL_PREMY] = std::pair<std::string, std::string>(it->second.first, it->second.second);
  445. if (GameConstants::STACK_EXP) //reading default stack experience bonuses
  446. {
  447. buf = bitmaph->getTextFile("CREXPBON.TXT");
  448. int it = 0;
  449. si32 creid = -1;
  450. Bonus b; //prototype with some default properties
  451. b.source = Bonus::STACK_EXPERIENCE;
  452. b.duration = Bonus::PERMANENT;
  453. b.valType = Bonus::ADDITIVE_VALUE;
  454. b.effectRange = Bonus::NO_LIMIT;
  455. b.additionalInfo = 0;
  456. b.turnsRemain = 0;
  457. BonusList bl;
  458. std::string dump2;
  459. loadToIt (dump2, buf, it, 3); //ignore first line
  460. loadToIt (dump2, buf, it, 4); //ignore index
  461. loadStackExp(b, bl, buf, it);
  462. BOOST_FOREACH(Bonus * b, bl)
  463. addBonusForAllCreatures(b); //health bonus is common for all
  464. loadToIt (dump2, buf, it, 3); //crop comment
  465. for (i = 1; i < 7; ++i)
  466. {
  467. for (int j = 0; j < 4; ++j) //four modifiers common for tiers
  468. {
  469. loadToIt (dump2, buf, it, 4); //ignore index
  470. bl.clear();
  471. loadStackExp(b, bl, buf, it);
  472. BOOST_FOREACH(Bonus * b, bl)
  473. addBonusForTier(i, b);
  474. loadToIt (dump2, buf, it, 3); //crop comment
  475. }
  476. }
  477. for (int j = 0; j < 4; ++j) //tier 7
  478. {
  479. loadToIt (dump2, buf, it, 4); //ignore index
  480. bl.clear();
  481. loadStackExp(b, bl, buf, it);
  482. BOOST_FOREACH(Bonus * b, bl)
  483. {
  484. addBonusForTier(7, b);
  485. creaturesOfLevel[0].addNewBonus(b); //bonuses from level 7 are given to high-level creatures
  486. }
  487. loadToIt (dump2, buf, it, 3); //crop comment
  488. }
  489. do //parse everything that's left
  490. {
  491. loadToIt(creid, buf, it, 4); //get index
  492. b.sid = creid; //id = this particular creature ID
  493. loadStackExp(b, creatures[creid]->getBonusList(), buf, it); //add directly to CCreature Node
  494. loadToIt (dump2, buf, it, 3); //crop comment
  495. } while (it < buf.size());
  496. //Calculate rank exp values, formula appears complicated bu no parsing needed
  497. expRanks.resize(8);
  498. int dif = 0;
  499. it = 8000; //ignore name of this variable
  500. expRanks[0].push_back(it);
  501. for (int j = 1; j < 10; ++j) //used for tiers 8-10, and all other probably
  502. {
  503. expRanks[0].push_back(expRanks[0][j-1] + it + dif);
  504. dif += it/5;
  505. }
  506. for (i = 1; i < 8; ++i)
  507. {
  508. dif = 0;
  509. it = 1000 * i;
  510. expRanks[i].push_back(it);
  511. for (int j = 1; j < 10; ++j)
  512. {
  513. expRanks[i].push_back(expRanks[i][j-1] + it + dif);
  514. dif += it/5;
  515. }
  516. }
  517. buf = bitmaph->getTextFile("CREXPMOD.TXT"); //could be hardcoded though, lots of useless info
  518. it = 0;
  519. loadToIt (dump2, buf, it, 3); //ignore first line
  520. maxExpPerBattle.resize(8);
  521. si32 val;
  522. for (i = 1; i < 8; ++i)
  523. {
  524. loadToIt (dump2, buf, it, 4); //index
  525. loadToIt (dump2, buf, it, 4); //float multiplier -> hardcoded
  526. loadToIt (dump2, buf, it, 4); //ignore upgrade mod? ->hardcoded
  527. loadToIt (dump2, buf, it, 4); //already calculated
  528. loadToIt (val, buf, it, 4);
  529. maxExpPerBattle[i] = (ui32)val;
  530. loadToIt (val, buf, it, 4); //11th level
  531. val += (si32)expRanks[i].back();
  532. expRanks[i].push_back((ui32)val);
  533. loadToIt (dump2, buf, it, 3); //crop comment
  534. }
  535. //skeleton gets exp penalty
  536. creatures[56].get()->addBonus(-50, Bonus::EXP_MULTIPLIER, -1);
  537. creatures[57].get()->addBonus(-50, Bonus::EXP_MULTIPLIER, -1);
  538. //exp for tier >7, rank 11
  539. expRanks[0].push_back(147000);
  540. expAfterUpgrade = 75; //percent
  541. maxExpPerBattle[0] = maxExpPerBattle[7];
  542. }//end of Stack Experience
  543. //experiment - add 100 to attack for creatures of tier 1
  544. // Bonus *b = new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::OTHER, +100, 0, 0);
  545. // addBonusForTier(1, b);
  546. tlog5 << "\t\tReading config/commanders.json" << std::endl;
  547. const JsonNode config3(GameConstants::DATA_DIR + "/config/commanders.json");
  548. BOOST_FOREACH (auto creature, config3["factionCreatures"].Vector())
  549. {
  550. factionCommanders[creature["faction"].Float()] = creature["id"].Float();
  551. }
  552. BOOST_FOREACH (auto bonus, config3["bonusPerLevel"].Vector())
  553. {
  554. commanderLevelPremy.push_back(ParseBonus (bonus.Vector()));
  555. }
  556. i = 0;
  557. BOOST_FOREACH (auto skill, config3["skillLevels"].Vector())
  558. {
  559. skillLevels.push_back (std::vector<ui8>());
  560. BOOST_FOREACH (auto skillLevel, skill["levels"].Vector())
  561. {
  562. skillLevels[i].push_back (skillLevel.Float());
  563. }
  564. ++i;
  565. }
  566. BOOST_FOREACH (auto ability, config3["abilityRequirements"].Vector())
  567. {
  568. std::pair <Bonus, std::pair <ui8, ui8> > a;
  569. a.first = *ParseBonus (ability["ability"].Vector());
  570. a.second.first = ability["skills"].Vector()[0].Float();
  571. a.second.second = ability["skills"].Vector()[1].Float();
  572. skillRequirements.push_back (a);
  573. }
  574. }
  575. void CCreatureHandler::loadAnimationInfo()
  576. {
  577. std::string buf = bitmaph->getTextFile("CRANIM.TXT");
  578. int andame = buf.size();
  579. int i=0; //buf iterator
  580. int hmcr=0;
  581. for(; i<andame; ++i)
  582. {
  583. if(buf[i]=='\r')
  584. ++hmcr;
  585. if(hmcr==2)
  586. break;
  587. }
  588. i+=2;
  589. for(int dd=0; dd<creatures.size(); ++dd)
  590. {
  591. //tlog5 << "\t\t\tReading animation info for creature " << dd << std::endl;
  592. loadUnitAnimInfo(*creatures[dd], buf, i);
  593. }
  594. return;
  595. }
  596. void CCreatureHandler::loadUnitAnimInfo(CCreature & unit, std::string & src, int & i)
  597. {
  598. int befi=i;
  599. unit.timeBetweenFidgets = readFloat(befi, i, src.size(), src);
  600. while(unit.timeBetweenFidgets == 0.0)
  601. {
  602. for(; i<src.size(); ++i)
  603. {
  604. if(src[i]=='\r')
  605. break;
  606. }
  607. i+=2;
  608. unit.timeBetweenFidgets = readFloat(befi, i, src.size(), src);
  609. }
  610. unit.walkAnimationTime = readFloat(befi, i, src.size(), src);
  611. unit.attackAnimationTime = readFloat(befi, i, src.size(), src);
  612. unit.flightAnimationDistance = readFloat(befi, i, src.size(), src);
  613. ///////////////////////
  614. unit.upperRightMissleOffsetX = readNumber(befi, i, src.size(), src);
  615. unit.upperRightMissleOffsetY = readNumber(befi, i, src.size(), src);
  616. unit.rightMissleOffsetX = readNumber(befi, i, src.size(), src);
  617. unit.rightMissleOffsetY = readNumber(befi, i, src.size(), src);
  618. unit.lowerRightMissleOffsetX = readNumber(befi, i, src.size(), src);
  619. unit.lowerRightMissleOffsetY = readNumber(befi, i, src.size(), src);
  620. ///////////////////////
  621. for(int jjj=0; jjj<12; ++jjj)
  622. {
  623. unit.missleFrameAngles[jjj] = readFloat(befi, i, src.size(), src);
  624. }
  625. unit.troopCountLocationOffset= readNumber(befi, i, src.size(), src);
  626. unit.attackClimaxFrame = readNumber(befi, i, src.size(), src);
  627. for(; i<src.size(); ++i)
  628. {
  629. if(src[i]=='\r')
  630. break;
  631. }
  632. i+=2;
  633. }
  634. void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, std::string & src, int & it) //help function for parsing CREXPBON.txt
  635. {
  636. std::string buf, mod;
  637. bool enable = false; //some bonuses are activated with values 2 or 1
  638. loadToIt(buf, src, it, 4);
  639. loadToIt(mod, src, it, 4);
  640. switch (buf[0])
  641. {
  642. case 'H':
  643. b.type = Bonus::STACK_HEALTH;
  644. b.valType = Bonus::PERCENT_TO_BASE;
  645. break;
  646. case 'A':
  647. b.type = Bonus::PRIMARY_SKILL;
  648. b.subtype = PrimarySkill::ATTACK;
  649. break;
  650. case 'D':
  651. b.type = Bonus::PRIMARY_SKILL;
  652. b.subtype = PrimarySkill::DEFENSE;
  653. break;
  654. case 'M': //Max damage
  655. b.type = Bonus::CREATURE_DAMAGE;
  656. b.subtype = 2;
  657. break;
  658. case 'm': //Min damage
  659. b.type = Bonus::CREATURE_DAMAGE;
  660. b.subtype = 1;
  661. break;
  662. case 'S':
  663. b.type = Bonus::STACKS_SPEED; break;
  664. case 'O':
  665. b.type = Bonus::SHOTS; break;
  666. case 'b':
  667. b.type = Bonus::ENEMY_DEFENCE_REDUCTION; break;
  668. case 'C':
  669. b.type = Bonus::CHANGES_SPELL_COST_FOR_ALLY; break;
  670. case 'd':
  671. b.type = Bonus::DEFENSIVE_STANCE; break;
  672. case 'e':
  673. b.type = Bonus::DOUBLE_DAMAGE_CHANCE; break;
  674. case 'E':
  675. b.type = Bonus::DEATH_STARE;
  676. b.subtype = 0; //Gorgon
  677. break;
  678. case 'g':
  679. b.type = Bonus::SPELL_DAMAGE_REDUCTION;
  680. b.subtype = -1; //all magic schools
  681. break;
  682. case 'P':
  683. b.type = Bonus::CASTS; break;
  684. case 'R':
  685. b.type = Bonus::ADDITIONAL_RETALIATION; break;
  686. case 'W':
  687. b.type = Bonus::MAGIC_RESISTANCE;
  688. b.subtype = 0; //otherwise creature window goes crazy
  689. break;
  690. case 'f': //on-off skill
  691. enable = true; //sometimes format is: 2 -> 0, 1 -> 1
  692. switch (mod[0])
  693. {
  694. case 'A':
  695. b.type = Bonus::ATTACKS_ALL_ADJACENT; break;
  696. case 'b':
  697. b.type = Bonus::RETURN_AFTER_STRIKE; break;
  698. case 'B':
  699. b.type = Bonus::TWO_HEX_ATTACK_BREATH; break;
  700. case 'c':
  701. b.type = Bonus::JOUSTING; break;
  702. case 'D':
  703. b.type = Bonus::ADDITIONAL_ATTACK; break;
  704. case 'f':
  705. b.type = Bonus::FEARLESS; break;
  706. case 'F':
  707. b.type = Bonus::FLYING; break;
  708. case 'm':
  709. b.type = Bonus::SELF_MORALE; break;
  710. case 'M':
  711. b.type = Bonus::NO_MORALE; break;
  712. case 'p': //Mind spells
  713. case 'P':
  714. b.type = Bonus::MIND_IMMUNITY; break;
  715. case 'r':
  716. b.type = Bonus::REBIRTH; //on/off? makes sense?
  717. b.subtype = 0;
  718. b.val = 20; //arbitrary value
  719. break;
  720. case 'R':
  721. b.type = Bonus::BLOCKS_RETALIATION; break;
  722. case 's':
  723. b.type = Bonus::FREE_SHOOTING; break;
  724. case 'u':
  725. b.type = Bonus::SPELL_RESISTANCE_AURA; break;
  726. case 'U':
  727. b.type = Bonus::UNDEAD; break;
  728. default:
  729. tlog5 << "Not parsed bonus " << buf << mod << "\n";
  730. return;
  731. break;
  732. }
  733. break;
  734. case 'w': //specific spell immunities, enabled/disabled
  735. enable = true;
  736. switch (mod[0])
  737. {
  738. case 'B': //Blind
  739. b.type = Bonus::SPELL_IMMUNITY;
  740. b.subtype = 74;
  741. break;
  742. case 'H': //Hypnotize
  743. b.type = Bonus::SPELL_IMMUNITY;
  744. b.subtype = 60;
  745. break;
  746. case 'I': //Implosion
  747. b.type = Bonus::SPELL_IMMUNITY;
  748. b.subtype = 18;
  749. break;
  750. case 'K': //Berserk
  751. b.type = Bonus::SPELL_IMMUNITY;
  752. b.subtype = 59;
  753. break;
  754. case 'M': //Meteor Shower
  755. b.type = Bonus::SPELL_IMMUNITY;
  756. b.subtype = 23;
  757. break;
  758. case 'N': //dispell beneficial spells
  759. b.type = Bonus::SPELL_IMMUNITY;
  760. b.subtype = 78;
  761. break;
  762. case 'R': //Armageddon
  763. b.type = Bonus::SPELL_IMMUNITY;
  764. b.subtype = 26;
  765. break;
  766. case 'S': //Slow
  767. b.type = Bonus::SPELL_IMMUNITY;
  768. b.subtype = 54;
  769. break;
  770. case '6':
  771. case '7':
  772. case '8':
  773. case '9':
  774. b.type = Bonus::LEVEL_SPELL_IMMUNITY;
  775. b.val = std::atoi(mod.c_str()) - 5;
  776. break;
  777. case ':':
  778. b.type = Bonus::LEVEL_SPELL_IMMUNITY;
  779. b.val = GameConstants::SPELL_LEVELS; //in case someone adds higher level spells?
  780. break;
  781. case 'F':
  782. b.type = Bonus::FIRE_IMMUNITY;
  783. b.subtype = 1; //not positive
  784. break;
  785. case 'O':
  786. b.type = Bonus::FIRE_IMMUNITY;
  787. b.subtype = 2; //only direct damage
  788. break;
  789. case 'f':
  790. b.type = Bonus::FIRE_IMMUNITY;
  791. b.subtype = 0; //all
  792. break;
  793. case 'C':
  794. b.type = Bonus::WATER_IMMUNITY;
  795. b.subtype = 1; //not positive
  796. break;
  797. case 'W':
  798. b.type = Bonus::WATER_IMMUNITY;
  799. b.subtype = 2; //only direct damage
  800. break;
  801. case 'w':
  802. b.type = Bonus::WATER_IMMUNITY;
  803. b.subtype = 0; //all
  804. break;
  805. case 'E':
  806. b.type = Bonus::EARTH_IMMUNITY;
  807. b.subtype = 2; //only direct damage
  808. break;
  809. case 'e':
  810. b.type = Bonus::EARTH_IMMUNITY;
  811. b.subtype = 0; //all
  812. break;
  813. case 'A':
  814. b.type = Bonus::AIR_IMMUNITY;
  815. b.subtype = 2; //only direct damage
  816. break;
  817. case 'a':
  818. b.type = Bonus::AIR_IMMUNITY;
  819. b.subtype = 0; //all
  820. break;
  821. case 'D':
  822. b.type = Bonus::DIRECT_DAMAGE_IMMUNITY;
  823. break;
  824. case '0':
  825. b.type = Bonus::RECEPTIVE;
  826. break;
  827. default:
  828. tlog5 << "Not parsed bonus " << buf << mod << "\n";
  829. return;
  830. }
  831. break;
  832. case 'i':
  833. enable = true;
  834. b.type = Bonus::NO_DISTANCE_PENALTY;
  835. break;
  836. case 'o':
  837. enable = true;
  838. b.type = Bonus::NO_WALL_PENALTY;
  839. break;
  840. case 'a':
  841. case 'c': //some special abilities are threated as spells, work in progress
  842. b.type = Bonus::SPELL_AFTER_ATTACK;
  843. b.subtype = stringToNumber(mod);
  844. break;
  845. case 'h':
  846. b.type= Bonus::HATE;
  847. b.subtype = stringToNumber(mod);
  848. break;
  849. case 'p':
  850. b.type = Bonus::SPELL_BEFORE_ATTACK;
  851. b.subtype = stringToNumber(mod);
  852. b.additionalInfo = 3; //always expert?
  853. break;
  854. default:
  855. tlog5 << "Not parsed bonus " << buf << mod << "\n";
  856. return;
  857. break;
  858. }
  859. switch (mod[0])
  860. {
  861. case '+':
  862. case '=': //should we allow percent values to stack or pick highest?
  863. b.valType = Bonus::ADDITIVE_VALUE;
  864. break;
  865. }
  866. //limiters, range
  867. si32 lastVal, curVal, lastLev = 0;
  868. if (enable) //0 and 2 means non-active, 1 - active
  869. {
  870. if (b.type != Bonus::REBIRTH)
  871. b.val = 0; //on-off ability, no value specified
  872. loadToIt (curVal, src, it, 4); // 0 level is never active
  873. for (int i = 1; i < 11; ++i)
  874. {
  875. loadToIt (curVal, src, it, 4);
  876. if (curVal == 1)
  877. {
  878. b.limiter.reset (new RankRangeLimiter(i));
  879. bl.push_back(new Bonus(b));
  880. break; //never turned off it seems
  881. }
  882. }
  883. }
  884. else
  885. {
  886. loadToIt (lastVal, src, it, 4); //basic value, not particularly useful but existent
  887. for (int i = 1; i < 11; ++i)
  888. {
  889. loadToIt (curVal, src, it, 4);
  890. if (b.type == Bonus::HATE)
  891. curVal *= 10; //odd fix
  892. if (curVal > lastVal) //threshold, add new bonus
  893. {
  894. b.val = curVal - lastVal;
  895. lastVal = curVal;
  896. b.limiter.reset (new RankRangeLimiter(i));
  897. bl.push_back(new Bonus(b));
  898. lastLev = i; //start new range from here, i = previous rank
  899. }
  900. else if (curVal < lastVal)
  901. {
  902. b.val = lastVal;
  903. b.limiter.reset (new RankRangeLimiter(lastLev, i));
  904. }
  905. }
  906. }
  907. }
  908. int CCreatureHandler::stringToNumber(std::string & s)
  909. {
  910. boost::algorithm::replace_first(s,"#",""); //drop hash character
  911. return std::atoi(s.c_str());
  912. }
  913. CCreatureHandler::~CCreatureHandler()
  914. {
  915. }
  916. static int retreiveRandNum(const boost::function<int()> &randGen)
  917. {
  918. if(randGen)
  919. return randGen();
  920. else
  921. return rand();
  922. }
  923. template <typename T> const T & pickRandomElementOf(const std::vector<T> &v, const boost::function<int()> &randGen)
  924. {
  925. return v[retreiveRandNum(randGen) % v.size()];
  926. }
  927. int CCreatureHandler::pickRandomMonster(const boost::function<int()> &randGen, int tier) const
  928. {
  929. int r = 0;
  930. if(tier == -1) //pick any allowed creature
  931. {
  932. do
  933. {
  934. r = pickRandomElementOf(creatures, randGen)->idNumber;
  935. } while (vstd::contains(VLC->creh->notUsedMonsters,r));
  936. }
  937. else
  938. {
  939. assert(vstd::iswithin(tier, 1, 7));
  940. std::vector<int> allowed;
  941. BOOST_FOREACH(const CBonusSystemNode *b, creaturesOfLevel[tier].getChildrenNodes())
  942. {
  943. assert(b->getNodeType() == CBonusSystemNode::CREATURE);
  944. int creid = static_cast<const CCreature*>(b)->idNumber;
  945. if(!vstd::contains(notUsedMonsters, creid))
  946. allowed.push_back(creid);
  947. }
  948. if(!allowed.size())
  949. {
  950. tlog2 << "Cannot pick a random creature of tier " << tier << "!\n";
  951. return 0;
  952. }
  953. return pickRandomElementOf(allowed, randGen);
  954. }
  955. return r;
  956. }
  957. void CCreatureHandler::addBonusForTier(int tier, Bonus *b)
  958. {
  959. assert(vstd::iswithin(tier, 1, 7));
  960. creaturesOfLevel[tier].addNewBonus(b);
  961. }
  962. void CCreatureHandler::addBonusForAllCreatures(Bonus *b)
  963. {
  964. allCreatures.addNewBonus(b);
  965. }
  966. void CCreatureHandler::buildBonusTreeForTiers()
  967. {
  968. BOOST_FOREACH(CCreature *c, creatures)
  969. {
  970. if(vstd::isbetween(c->level, 0, ARRAY_COUNT(creaturesOfLevel)))
  971. c->attachTo(&creaturesOfLevel[c->level]);
  972. else
  973. c->attachTo(&creaturesOfLevel[0]);
  974. }
  975. BOOST_FOREACH(CBonusSystemNode &b, creaturesOfLevel)
  976. b.attachTo(&allCreatures);
  977. }
  978. void CCreatureHandler::deserializationFix()
  979. {
  980. buildBonusTreeForTiers();
  981. }