CCreatureHandler.cpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. #include "StdInc.h"
  2. #include "CCreatureHandler.h"
  3. #include "CGeneralTextHandler.h"
  4. #include "Filesystem/CResourceLoader.h"
  5. #include "VCMI_Lib.h"
  6. #include "CGameState.h"
  7. #include "CTownHandler.h"
  8. #include "CModHandler.h"
  9. using namespace boost::assign;
  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. return VLC->townh->factions[0].nativeTerrain == terrain; //FIXME: handle neutral faction properly
  131. }
  132. int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
  133. {
  134. befi=i;
  135. for(; i<andame; ++i)
  136. {
  137. if(buf[i]=='\t')
  138. break;
  139. }
  140. std::string tmp = buf.substr(befi, i-befi);
  141. int ret = atoi(buf.substr(befi, i-befi).c_str());
  142. ++i;
  143. return ret;
  144. }
  145. /**
  146. * Determines if a faction is good.
  147. * @param ID of the faction.
  148. * @return true if the faction is good, false otherwise.
  149. */
  150. bool CCreatureHandler::isGood (si8 faction) const
  151. {
  152. return faction != -1 && factionAlignments[faction] == 1;
  153. }
  154. /**
  155. * Determines if a faction is evil.
  156. * @param ID of the faction.
  157. * @return true if the faction is evil, false otherwise.
  158. */
  159. bool CCreatureHandler::isEvil (si8 faction) const
  160. {
  161. return faction != -1 && factionAlignments[faction] == -1;
  162. }
  163. static void AddAbility(CCreature *cre, const JsonVector &ability_vec)
  164. {
  165. Bonus *nsf = new Bonus();
  166. std::string type = ability_vec[0].String();
  167. std::map<std::string, int>::const_iterator it = bonusNameMap.find(type);
  168. if (it == bonusNameMap.end()) {
  169. if (type == "DOUBLE_WIDE")
  170. cre->doubleWide = true;
  171. else if (type == "ENEMY_MORALE_DECREASING") {
  172. cre->addBonus(-1, Bonus::MORALE);
  173. cre->getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
  174. }
  175. else if (type == "ENEMY_LUCK_DECREASING") {
  176. cre->addBonus(-1, Bonus::LUCK);
  177. cre->getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
  178. } else
  179. tlog1 << "Error: invalid ability type " << type << " in creatures.txt" << std::endl;
  180. return;
  181. }
  182. nsf->type = it->second;
  183. nsf->val = ability_vec[1].Float();
  184. nsf->subtype = ability_vec[2].Float();
  185. nsf->additionalInfo = ability_vec[3].Float();
  186. nsf->source = Bonus::CREATURE_ABILITY;
  187. nsf->sid = cre->idNumber;
  188. //nsf->duration = Bonus::ONE_BATTLE; //what the?
  189. nsf->duration = Bonus::PERMANENT;
  190. nsf->turnsRemain = 0;
  191. cre->addNewBonus(nsf);
  192. }
  193. static void RemoveAbility(CCreature *cre, const JsonNode &ability)
  194. {
  195. std::string type = ability.String();
  196. std::map<std::string, int>::const_iterator it = bonusNameMap.find(type);
  197. if (it == bonusNameMap.end()) {
  198. if (type == "DOUBLE_WIDE")
  199. cre->doubleWide = false;
  200. else
  201. tlog1 << "Error: invalid ability type " << type << " in creatures.json" << std::endl;
  202. return;
  203. }
  204. int typeNo = it->second;
  205. Bonus::BonusType ecf = static_cast<Bonus::BonusType>(typeNo);
  206. Bonus *b = cre->getBonusLocalFirst(Selector::type(ecf));
  207. cre->removeBonus(b);
  208. }
  209. void CCreatureHandler::loadCreatures()
  210. {
  211. tlog5 << "\t\tReading config/cr_abils.json and ZCRTRAIT.TXT" << std::endl;
  212. ////////////reading ZCRTRAIT.TXT ///////////////////
  213. CLegacyConfigParser parser("DATA/ZCRTRAIT.TXT");
  214. parser.endLine(); // header
  215. parser.endLine();
  216. do
  217. {
  218. //loop till non-empty line
  219. while (parser.isNextEntryEmpty())
  220. parser.endLine();
  221. CCreature &ncre = *new CCreature;
  222. ncre.idNumber = creatures.size();
  223. ncre.cost.resize(GameConstants::RESOURCE_QUANTITY);
  224. ncre.level=0;
  225. ncre.iconIndex = ncre.idNumber + 2; // +2 for empty\selection images
  226. ncre.nameSing = parser.readString();
  227. ncre.namePl = parser.readString();
  228. for(int v=0; v<7; ++v)
  229. {
  230. ncre.cost[v] = parser.readNumber();
  231. }
  232. ncre.fightValue = parser.readNumber();
  233. ncre.AIValue = parser.readNumber();
  234. ncre.growth = parser.readNumber();
  235. ncre.hordeGrowth = parser.readNumber();
  236. ncre.addBonus(parser.readNumber(), Bonus::STACK_HEALTH);
  237. ncre.addBonus(parser.readNumber(), Bonus::STACKS_SPEED);
  238. ncre.addBonus(parser.readNumber(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
  239. ncre.addBonus(parser.readNumber(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
  240. ncre.addBonus(parser.readNumber(), Bonus::CREATURE_DAMAGE, 1);
  241. ncre.addBonus(parser.readNumber(), Bonus::CREATURE_DAMAGE, 2);
  242. ncre.addBonus(parser.readNumber(), Bonus::SHOTS);
  243. //spells - not used?
  244. parser.readNumber();
  245. ncre.ammMin = parser.readNumber();
  246. ncre.ammMax = parser.readNumber();
  247. ncre.abilityText = parser.readString();
  248. ncre.abilityRefs = parser.readString();
  249. { //adding abilities from ZCRTRAIT.TXT
  250. if(boost::algorithm::find_first(ncre.abilityRefs, "DOUBLE_WIDE"))
  251. ncre.doubleWide = true;
  252. if(boost::algorithm::find_first(ncre.abilityRefs, "FLYING_ARMY"))
  253. ncre.addBonus(0, Bonus::FLYING);
  254. if(boost::algorithm::find_first(ncre.abilityRefs, "SHOOTING_ARMY"))
  255. ncre.addBonus(0, Bonus::SHOOTER);
  256. if(boost::algorithm::find_first(ncre.abilityRefs, "SIEGE_WEAPON"))
  257. ncre.addBonus(0, Bonus::SIEGE_WEAPON);
  258. if(boost::algorithm::find_first(ncre.abilityRefs, "const_two_attacks"))
  259. ncre.addBonus(1, Bonus::ADDITIONAL_ATTACK);
  260. if(boost::algorithm::find_first(ncre.abilityRefs, "const_free_attack"))
  261. ncre.addBonus(0, Bonus::BLOCKS_RETALIATION);
  262. if(boost::algorithm::find_first(ncre.abilityRefs, "IS_UNDEAD"))
  263. ncre.addBonus(0, Bonus::UNDEAD);
  264. if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_melee_penalty"))
  265. ncre.addBonus(0, Bonus::NO_MELEE_PENALTY);
  266. if(boost::algorithm::find_first(ncre.abilityRefs, "const_jousting"))
  267. ncre.addBonus(0, Bonus::JOUSTING);
  268. if(boost::algorithm::find_first(ncre.abilityRefs, "const_raises_morale"))
  269. {
  270. ncre.addBonus(+1, Bonus::MORALE);;
  271. ncre.getBonusList().back()->addPropagator(make_shared<CPropagatorNodeType>(CBonusSystemNode::HERO));
  272. }
  273. if(boost::algorithm::find_first(ncre.abilityRefs, "const_lowers_morale"))
  274. {
  275. ncre.addBonus(-1, Bonus::MORALE);;
  276. ncre.getBonusList().back()->effectRange = Bonus::ONLY_ENEMY_ARMY;
  277. }
  278. if(boost::algorithm::find_first(ncre.abilityRefs, "KING_1"))
  279. ncre.addBonus(0, Bonus::KING1);
  280. if(boost::algorithm::find_first(ncre.abilityRefs, "KING_2"))
  281. ncre.addBonus(0, Bonus::KING2);
  282. if(boost::algorithm::find_first(ncre.abilityRefs, "KING_3"))
  283. ncre.addBonus(0, Bonus::KING3);
  284. if(boost::algorithm::find_first(ncre.abilityRefs, "const_no_wall_penalty"))
  285. ncre.addBonus(0, Bonus::NO_WALL_PENALTY);
  286. if(boost::algorithm::find_first(ncre.abilityRefs, "CATAPULT"))
  287. ncre.addBonus(0, Bonus::CATAPULT);
  288. if(boost::algorithm::find_first(ncre.abilityRefs, "MULTI_HEADED"))
  289. ncre.addBonus(0, Bonus::ATTACKS_ALL_ADJACENT);
  290. if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_MIND_SPELLS"))
  291. ncre.addBonus(0, Bonus::MIND_IMMUNITY); //giants are immune to mind spells
  292. if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_FIRE_SPELLS"))
  293. ncre.addBonus(0, Bonus::FIRE_IMMUNITY);
  294. if(boost::algorithm::find_first(ncre.abilityRefs, "HAS_EXTENDED_ATTACK"))
  295. ncre.addBonus(0, Bonus::TWO_HEX_ATTACK_BREATH);;
  296. }
  297. creatures.push_back(&ncre);
  298. }
  299. while (parser.endLine());
  300. // loading creatures properties
  301. tlog5 << "\t\tReading config/creatures.json" << std::endl;
  302. const JsonNode config(ResourceID("config/creatures.json"));
  303. BOOST_FOREACH(const JsonNode &creature, config["creatures"].Vector())
  304. {
  305. int creatureID = creature["id"].Float();
  306. const JsonNode *value;
  307. /* A creature can have several names. */
  308. BOOST_FOREACH(const JsonNode &name, creature["name"].Vector())
  309. {
  310. boost::assign::insert(nameToID)(name.String(), creatureID);
  311. }
  312. // Set various creature properties
  313. CCreature *c = creatures[creatureID];
  314. c->level = creature["level"].Float();
  315. c->faction = creature["faction"].Float();
  316. c->animDefName = creature["defname"].String();
  317. BOOST_FOREACH(const JsonNode &value, creature["upgrades"].Vector())
  318. {
  319. c->upgrades.insert(value.Float());
  320. }
  321. value = &creature["projectile_defname"];
  322. if (!value->isNull())
  323. {
  324. c->projectile = value->String();
  325. value = &creature["projectile_spin"];
  326. c->projectileSpin = value->Bool();
  327. }
  328. value = &creature["turret_shooter"];
  329. if (!value->isNull() && value->Bool())
  330. factionToTurretCreature[c->faction] = creatureID;
  331. value = &creature["ability_remove"];//remove first - arch devil
  332. if (!value->isNull())
  333. {
  334. BOOST_FOREACH(const JsonNode &ability, value->Vector())
  335. {
  336. RemoveAbility(c, ability);
  337. }
  338. }
  339. value = &creature["ability_add"];
  340. if (!value->isNull()) {
  341. BOOST_FOREACH(const JsonNode &ability, value->Vector())
  342. {
  343. AddAbility(c, ability.Vector());
  344. }
  345. }
  346. }
  347. BOOST_FOREACH(const JsonNode &creature, config["unused_creatures"].Vector())
  348. {
  349. notUsedMonsters += creature.Float();
  350. }
  351. loadAnimationInfo();
  352. loadSoundsInfo();
  353. //reading creature ability names
  354. const JsonNode config2(ResourceID("config/bonusnames.json"));
  355. BOOST_FOREACH(const JsonNode &bonus, config2["bonuses"].Vector())
  356. {
  357. std::map<std::string,int>::const_iterator it_map;
  358. std::string bonusID = bonus["id"].String();
  359. it_map = bonusNameMap.find(bonusID);
  360. if (it_map != bonusNameMap.end())
  361. stackBonuses[it_map->second] = std::pair<std::string, std::string>(bonus["name"].String(), bonus["description"].String());
  362. else
  363. tlog2 << "Bonus " << bonusID << " not recognized, ignoring\n";
  364. }
  365. //handle magic resistance secondary skill premy, potentialy may be buggy
  366. //std::map<TBonusType, std::pair<std::string, std::string> >::iterator it = stackBonuses.find(Bonus::MAGIC_RESISTANCE);
  367. //stackBonuses[Bonus::SECONDARY_SKILL_PREMY] = std::pair<std::string, std::string>(it->second.first, it->second.second);
  368. if (VLC->modh->modules.STACK_EXP) //reading default stack experience bonuses
  369. {
  370. CLegacyConfigParser parser("DATA/CREXPBON.TXT");
  371. Bonus b; //prototype with some default properties
  372. b.source = Bonus::STACK_EXPERIENCE;
  373. b.duration = Bonus::PERMANENT;
  374. b.valType = Bonus::ADDITIVE_VALUE;
  375. b.effectRange = Bonus::NO_LIMIT;
  376. b.additionalInfo = 0;
  377. b.turnsRemain = 0;
  378. BonusList bl;
  379. parser.endLine();
  380. parser.readString(); //ignore index
  381. loadStackExp(b, bl, parser);
  382. BOOST_FOREACH(Bonus * b, bl)
  383. addBonusForAllCreatures(b); //health bonus is common for all
  384. parser.endLine();
  385. for (int i = 1; i < 7; ++i)
  386. {
  387. for (int j = 0; j < 4; ++j) //four modifiers common for tiers
  388. {
  389. parser.readString(); //ignore index
  390. bl.clear();
  391. loadStackExp(b, bl, parser);
  392. BOOST_FOREACH(Bonus * b, bl)
  393. addBonusForTier(i, b);
  394. parser.endLine();
  395. }
  396. }
  397. for (int j = 0; j < 4; ++j) //tier 7
  398. {
  399. parser.readString(); //ignore index
  400. bl.clear();
  401. loadStackExp(b, bl, parser);
  402. BOOST_FOREACH(Bonus * b, bl)
  403. {
  404. addBonusForTier(7, b);
  405. creaturesOfLevel[0].addNewBonus(b); //bonuses from level 7 are given to high-level creatures
  406. }
  407. parser.endLine();
  408. }
  409. do //parse everything that's left
  410. {
  411. b.sid = parser.readNumber(); //id = this particular creature ID
  412. loadStackExp(b, creatures[b.sid]->getBonusList(), parser); //add directly to CCreature Node
  413. }
  414. while (parser.endLine());
  415. //Calculate rank exp values, formula appears complicated bu no parsing needed
  416. expRanks.resize(8);
  417. int dif = 0;
  418. int it = 8000; //ignore name of this variable
  419. expRanks[0].push_back(it);
  420. for (int j = 1; j < 10; ++j) //used for tiers 8-10, and all other probably
  421. {
  422. expRanks[0].push_back(expRanks[0][j-1] + it + dif);
  423. dif += it/5;
  424. }
  425. for (int i = 1; i < 8; ++i)
  426. {
  427. dif = 0;
  428. it = 1000 * i;
  429. expRanks[i].push_back(it);
  430. for (int j = 1; j < 10; ++j)
  431. {
  432. expRanks[i].push_back(expRanks[i][j-1] + it + dif);
  433. dif += it/5;
  434. }
  435. }
  436. CLegacyConfigParser expBonParser("DATA/CREXPMOD.TXT");
  437. expBonParser.endLine(); //header
  438. maxExpPerBattle.resize(8);
  439. for (int i = 1; i < 8; ++i)
  440. {
  441. expBonParser.readString(); //index
  442. expBonParser.readString(); //float multiplier -> hardcoded
  443. expBonParser.readString(); //ignore upgrade mod? ->hardcoded
  444. expBonParser.readString(); //already calculated
  445. maxExpPerBattle[i] = expBonParser.readNumber();
  446. expRanks[i].push_back(expRanks[i].back() + expBonParser.readNumber());
  447. expBonParser.endLine();
  448. }
  449. //skeleton gets exp penalty
  450. creatures[56].get()->addBonus(-50, Bonus::EXP_MULTIPLIER, -1);
  451. creatures[57].get()->addBonus(-50, Bonus::EXP_MULTIPLIER, -1);
  452. //exp for tier >7, rank 11
  453. expRanks[0].push_back(147000);
  454. expAfterUpgrade = 75; //percent
  455. maxExpPerBattle[0] = maxExpPerBattle[7];
  456. }//end of Stack Experience
  457. tlog5 << "\t\tReading config/commanders.json" << std::endl;
  458. const JsonNode config3(ResourceID("config/commanders.json"));
  459. BOOST_FOREACH (auto creature, config3["factionCreatures"].Vector())
  460. {
  461. factionCommanders[creature["faction"].Float()] = creature["id"].Float();
  462. }
  463. BOOST_FOREACH (auto bonus, config3["bonusPerLevel"].Vector())
  464. {
  465. commanderLevelPremy.push_back(ParseBonus (bonus.Vector()));
  466. }
  467. int i = 0;
  468. BOOST_FOREACH (auto skill, config3["skillLevels"].Vector())
  469. {
  470. skillLevels.push_back (std::vector<ui8>());
  471. BOOST_FOREACH (auto skillLevel, skill["levels"].Vector())
  472. {
  473. skillLevels[i].push_back (skillLevel.Float());
  474. }
  475. ++i;
  476. }
  477. BOOST_FOREACH (auto ability, config3["abilityRequirements"].Vector())
  478. {
  479. std::pair <Bonus, std::pair <ui8, ui8> > a;
  480. a.first = *ParseBonus (ability["ability"].Vector());
  481. a.second.first = ability["skills"].Vector()[0].Float();
  482. a.second.second = ability["skills"].Vector()[1].Float();
  483. skillRequirements.push_back (a);
  484. }
  485. }
  486. void CCreatureHandler::loadAnimationInfo()
  487. {
  488. CLegacyConfigParser parser("DATA/CRANIM.TXT");
  489. parser.endLine(); // header
  490. parser.endLine();
  491. for(int dd=0; dd<creatures.size(); ++dd)
  492. {
  493. while (parser.isNextEntryEmpty() && parser.endLine()) // skip empty lines
  494. ;
  495. loadUnitAnimInfo(*creatures[dd], parser);
  496. }
  497. }
  498. void CCreatureHandler::loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser & parser)
  499. {
  500. unit.timeBetweenFidgets = parser.readNumber();
  501. unit.walkAnimationTime = parser.readNumber();
  502. unit.attackAnimationTime = parser.readNumber();
  503. unit.flightAnimationDistance = parser.readNumber();
  504. ///////////////////////
  505. unit.upperRightMissleOffsetX = parser.readNumber();
  506. unit.upperRightMissleOffsetY = parser.readNumber();
  507. unit.rightMissleOffsetX = parser.readNumber();
  508. unit.rightMissleOffsetY = parser.readNumber();
  509. unit.lowerRightMissleOffsetX = parser.readNumber();
  510. unit.lowerRightMissleOffsetY = parser.readNumber();
  511. ///////////////////////
  512. for(int jjj=0; jjj<12; ++jjj)
  513. {
  514. unit.missleFrameAngles[jjj] = parser.readNumber();
  515. }
  516. unit.troopCountLocationOffset= parser.readNumber();
  517. unit.attackClimaxFrame = parser.readNumber();
  518. parser.endLine();
  519. }
  520. void CCreatureHandler::loadSoundsInfo()
  521. {
  522. tlog5 << "\t\tReading config/cr_sounds.json" << std::endl;
  523. const JsonNode config(ResourceID("config/cr_sounds.json"));
  524. if (!config["creature_sounds"].isNull())
  525. {
  526. BOOST_FOREACH(const JsonNode &node, config["creature_sounds"].Vector())
  527. {
  528. const JsonNode *value;
  529. int id;
  530. value = &node["name"];
  531. bmap<std::string,int>::const_iterator i = nameToID.find(value->String());
  532. if (i != nameToID.end())
  533. id = i->second;
  534. else
  535. {
  536. tlog1 << "Sound info for an unknown creature: " << value->String() << std::endl;
  537. continue;
  538. }
  539. /* This is a bit ugly. Maybe we should use an array for
  540. * sound ids instead of separate variables and define
  541. * attack/defend/killed/... as indexes. */
  542. #define GET_SOUND_VALUE(value_name) do { value = &node[#value_name]; if (!value->isNull()) creatures[id]->sounds.value_name = value->String(); } while(0)
  543. GET_SOUND_VALUE(attack);
  544. GET_SOUND_VALUE(defend);
  545. GET_SOUND_VALUE(killed);
  546. GET_SOUND_VALUE(move);
  547. GET_SOUND_VALUE(shoot);
  548. GET_SOUND_VALUE(wince);
  549. GET_SOUND_VALUE(ext1);
  550. GET_SOUND_VALUE(ext2);
  551. GET_SOUND_VALUE(startMoving);
  552. GET_SOUND_VALUE(endMoving);
  553. #undef GET_SOUND_VALUE
  554. }
  555. }
  556. }
  557. void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser & parser) //help function for parsing CREXPBON.txt
  558. {
  559. bool enable = false; //some bonuses are activated with values 2 or 1
  560. std::string buf = parser.readString();
  561. std::string mod = parser.readString();
  562. switch (buf[0])
  563. {
  564. case 'H':
  565. b.type = Bonus::STACK_HEALTH;
  566. b.valType = Bonus::PERCENT_TO_BASE;
  567. break;
  568. case 'A':
  569. b.type = Bonus::PRIMARY_SKILL;
  570. b.subtype = PrimarySkill::ATTACK;
  571. break;
  572. case 'D':
  573. b.type = Bonus::PRIMARY_SKILL;
  574. b.subtype = PrimarySkill::DEFENSE;
  575. break;
  576. case 'M': //Max damage
  577. b.type = Bonus::CREATURE_DAMAGE;
  578. b.subtype = 2;
  579. break;
  580. case 'm': //Min damage
  581. b.type = Bonus::CREATURE_DAMAGE;
  582. b.subtype = 1;
  583. break;
  584. case 'S':
  585. b.type = Bonus::STACKS_SPEED; break;
  586. case 'O':
  587. b.type = Bonus::SHOTS; break;
  588. case 'b':
  589. b.type = Bonus::ENEMY_DEFENCE_REDUCTION; break;
  590. case 'C':
  591. b.type = Bonus::CHANGES_SPELL_COST_FOR_ALLY; break;
  592. case 'd':
  593. b.type = Bonus::DEFENSIVE_STANCE; break;
  594. case 'e':
  595. b.type = Bonus::DOUBLE_DAMAGE_CHANCE;
  596. b.subtype = 0;
  597. break;
  598. case 'E':
  599. b.type = Bonus::DEATH_STARE;
  600. b.subtype = 0; //Gorgon
  601. break;
  602. case 'g':
  603. b.type = Bonus::SPELL_DAMAGE_REDUCTION;
  604. b.subtype = -1; //all magic schools
  605. break;
  606. case 'P':
  607. b.type = Bonus::CASTS; break;
  608. case 'R':
  609. b.type = Bonus::ADDITIONAL_RETALIATION; break;
  610. case 'W':
  611. b.type = Bonus::MAGIC_RESISTANCE;
  612. b.subtype = 0; //otherwise creature window goes crazy
  613. break;
  614. case 'f': //on-off skill
  615. enable = true; //sometimes format is: 2 -> 0, 1 -> 1
  616. switch (mod[0])
  617. {
  618. case 'A':
  619. b.type = Bonus::ATTACKS_ALL_ADJACENT; break;
  620. case 'b':
  621. b.type = Bonus::RETURN_AFTER_STRIKE; break;
  622. case 'B':
  623. b.type = Bonus::TWO_HEX_ATTACK_BREATH; break;
  624. case 'c':
  625. b.type = Bonus::JOUSTING; break;
  626. case 'D':
  627. b.type = Bonus::ADDITIONAL_ATTACK; break;
  628. case 'f':
  629. b.type = Bonus::FEARLESS; break;
  630. case 'F':
  631. b.type = Bonus::FLYING; break;
  632. case 'm':
  633. b.type = Bonus::SELF_MORALE; break;
  634. case 'M':
  635. b.type = Bonus::NO_MORALE; break;
  636. case 'p': //Mind spells
  637. case 'P':
  638. b.type = Bonus::MIND_IMMUNITY; break;
  639. case 'r':
  640. b.type = Bonus::REBIRTH; //on/off? makes sense?
  641. b.subtype = 0;
  642. b.val = 20; //arbitrary value
  643. break;
  644. case 'R':
  645. b.type = Bonus::BLOCKS_RETALIATION; break;
  646. case 's':
  647. b.type = Bonus::FREE_SHOOTING; break;
  648. case 'u':
  649. b.type = Bonus::SPELL_RESISTANCE_AURA; break;
  650. case 'U':
  651. b.type = Bonus::UNDEAD; break;
  652. default:
  653. tlog5 << "Not parsed bonus " << buf << mod << "\n";
  654. return;
  655. break;
  656. }
  657. break;
  658. case 'w': //specific spell immunities, enabled/disabled
  659. enable = true;
  660. switch (mod[0])
  661. {
  662. case 'B': //Blind
  663. b.type = Bonus::SPELL_IMMUNITY;
  664. b.subtype = 74;
  665. break;
  666. case 'H': //Hypnotize
  667. b.type = Bonus::SPELL_IMMUNITY;
  668. b.subtype = 60;
  669. break;
  670. case 'I': //Implosion
  671. b.type = Bonus::SPELL_IMMUNITY;
  672. b.subtype = 18;
  673. break;
  674. case 'K': //Berserk
  675. b.type = Bonus::SPELL_IMMUNITY;
  676. b.subtype = 59;
  677. break;
  678. case 'M': //Meteor Shower
  679. b.type = Bonus::SPELL_IMMUNITY;
  680. b.subtype = 23;
  681. break;
  682. case 'N': //dispell beneficial spells
  683. b.type = Bonus::SPELL_IMMUNITY;
  684. b.subtype = 78;
  685. break;
  686. case 'R': //Armageddon
  687. b.type = Bonus::SPELL_IMMUNITY;
  688. b.subtype = 26;
  689. break;
  690. case 'S': //Slow
  691. b.type = Bonus::SPELL_IMMUNITY;
  692. b.subtype = 54;
  693. break;
  694. case '6':
  695. case '7':
  696. case '8':
  697. case '9':
  698. b.type = Bonus::LEVEL_SPELL_IMMUNITY;
  699. b.val = std::atoi(mod.c_str()) - 5;
  700. break;
  701. case ':':
  702. b.type = Bonus::LEVEL_SPELL_IMMUNITY;
  703. b.val = GameConstants::SPELL_LEVELS; //in case someone adds higher level spells?
  704. break;
  705. case 'F':
  706. b.type = Bonus::FIRE_IMMUNITY;
  707. b.subtype = 1; //not positive
  708. break;
  709. case 'O':
  710. b.type = Bonus::FIRE_IMMUNITY;
  711. b.subtype = 2; //only direct damage
  712. break;
  713. case 'f':
  714. b.type = Bonus::FIRE_IMMUNITY;
  715. b.subtype = 0; //all
  716. break;
  717. case 'C':
  718. b.type = Bonus::WATER_IMMUNITY;
  719. b.subtype = 1; //not positive
  720. break;
  721. case 'W':
  722. b.type = Bonus::WATER_IMMUNITY;
  723. b.subtype = 2; //only direct damage
  724. break;
  725. case 'w':
  726. b.type = Bonus::WATER_IMMUNITY;
  727. b.subtype = 0; //all
  728. break;
  729. case 'E':
  730. b.type = Bonus::EARTH_IMMUNITY;
  731. b.subtype = 2; //only direct damage
  732. break;
  733. case 'e':
  734. b.type = Bonus::EARTH_IMMUNITY;
  735. b.subtype = 0; //all
  736. break;
  737. case 'A':
  738. b.type = Bonus::AIR_IMMUNITY;
  739. b.subtype = 2; //only direct damage
  740. break;
  741. case 'a':
  742. b.type = Bonus::AIR_IMMUNITY;
  743. b.subtype = 0; //all
  744. break;
  745. case 'D':
  746. b.type = Bonus::DIRECT_DAMAGE_IMMUNITY;
  747. break;
  748. case '0':
  749. b.type = Bonus::RECEPTIVE;
  750. break;
  751. default:
  752. tlog5 << "Not parsed bonus " << buf << mod << "\n";
  753. return;
  754. }
  755. break;
  756. case 'i':
  757. enable = true;
  758. b.type = Bonus::NO_DISTANCE_PENALTY;
  759. break;
  760. case 'o':
  761. enable = true;
  762. b.type = Bonus::NO_WALL_PENALTY;
  763. break;
  764. case 'a':
  765. case 'c': //some special abilities are threated as spells, work in progress
  766. b.type = Bonus::SPELL_AFTER_ATTACK;
  767. b.subtype = stringToNumber(mod);
  768. break;
  769. case 'h':
  770. b.type= Bonus::HATE;
  771. b.subtype = stringToNumber(mod);
  772. break;
  773. case 'p':
  774. b.type = Bonus::SPELL_BEFORE_ATTACK;
  775. b.subtype = stringToNumber(mod);
  776. b.additionalInfo = 3; //always expert?
  777. break;
  778. default:
  779. tlog5 << "Not parsed bonus " << buf << mod << "\n";
  780. return;
  781. break;
  782. }
  783. switch (mod[0])
  784. {
  785. case '+':
  786. case '=': //should we allow percent values to stack or pick highest?
  787. b.valType = Bonus::ADDITIVE_VALUE;
  788. break;
  789. }
  790. //limiters, range
  791. si32 lastVal, curVal, lastLev = 0;
  792. if (enable) //0 and 2 means non-active, 1 - active
  793. {
  794. if (b.type != Bonus::REBIRTH)
  795. b.val = 0; //on-off ability, no value specified
  796. curVal = parser.readNumber();// 0 level is never active
  797. for (int i = 1; i < 11; ++i)
  798. {
  799. curVal = parser.readNumber();
  800. if (curVal == 1)
  801. {
  802. b.limiter.reset (new RankRangeLimiter(i));
  803. bl.push_back(new Bonus(b));
  804. break; //never turned off it seems
  805. }
  806. }
  807. }
  808. else
  809. {
  810. lastVal = parser.readNumber(); //basic value, not particularly useful but existent
  811. for (int i = 1; i < 11; ++i)
  812. {
  813. curVal = parser.readNumber();
  814. if (b.type == Bonus::HATE)
  815. curVal *= 10; //odd fix
  816. if (curVal > lastVal) //threshold, add new bonus
  817. {
  818. b.val = curVal - lastVal;
  819. lastVal = curVal;
  820. b.limiter.reset (new RankRangeLimiter(i));
  821. bl.push_back(new Bonus(b));
  822. lastLev = i; //start new range from here, i = previous rank
  823. }
  824. else if (curVal < lastVal)
  825. {
  826. b.val = lastVal;
  827. b.limiter.reset (new RankRangeLimiter(lastLev, i));
  828. }
  829. }
  830. }
  831. }
  832. int CCreatureHandler::stringToNumber(std::string & s)
  833. {
  834. boost::algorithm::replace_first(s,"#",""); //drop hash character
  835. return std::atoi(s.c_str());
  836. }
  837. CCreatureHandler::~CCreatureHandler()
  838. {
  839. }
  840. static int retreiveRandNum(const boost::function<int()> &randGen)
  841. {
  842. if(randGen)
  843. return randGen();
  844. else
  845. return rand();
  846. }
  847. template <typename T> const T & pickRandomElementOf(const std::vector<T> &v, const boost::function<int()> &randGen)
  848. {
  849. return v[retreiveRandNum(randGen) % v.size()];
  850. }
  851. int CCreatureHandler::pickRandomMonster(const boost::function<int()> &randGen, int tier) const
  852. {
  853. int r = 0;
  854. if(tier == -1) //pick any allowed creature
  855. {
  856. do
  857. {
  858. r = pickRandomElementOf(creatures, randGen)->idNumber;
  859. } while (vstd::contains(VLC->creh->notUsedMonsters,r));
  860. }
  861. else
  862. {
  863. assert(vstd::iswithin(tier, 1, 7));
  864. std::vector<int> allowed;
  865. BOOST_FOREACH(const CBonusSystemNode *b, creaturesOfLevel[tier].getChildrenNodes())
  866. {
  867. assert(b->getNodeType() == CBonusSystemNode::CREATURE);
  868. int creid = static_cast<const CCreature*>(b)->idNumber;
  869. if(!vstd::contains(notUsedMonsters, creid))
  870. allowed.push_back(creid);
  871. }
  872. if(!allowed.size())
  873. {
  874. tlog2 << "Cannot pick a random creature of tier " << tier << "!\n";
  875. return 0;
  876. }
  877. return pickRandomElementOf(allowed, randGen);
  878. }
  879. return r;
  880. }
  881. void CCreatureHandler::addBonusForTier(int tier, Bonus *b)
  882. {
  883. assert(vstd::iswithin(tier, 1, 7));
  884. creaturesOfLevel[tier].addNewBonus(b);
  885. }
  886. void CCreatureHandler::addBonusForAllCreatures(Bonus *b)
  887. {
  888. allCreatures.addNewBonus(b);
  889. }
  890. void CCreatureHandler::buildBonusTreeForTiers()
  891. {
  892. BOOST_FOREACH(CCreature *c, creatures)
  893. {
  894. if(vstd::isbetween(c->level, 0, ARRAY_COUNT(creaturesOfLevel)))
  895. c->attachTo(&creaturesOfLevel[c->level]);
  896. else
  897. c->attachTo(&creaturesOfLevel[0]);
  898. }
  899. BOOST_FOREACH(CBonusSystemNode &b, creaturesOfLevel)
  900. b.attachTo(&allCreatures);
  901. }
  902. void CCreatureHandler::deserializationFix()
  903. {
  904. buildBonusTreeForTiers();
  905. }