CObjectHandler.cpp 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. #define VCMI_DLL
  2. #include "../stdafx.h"
  3. #include "CObjectHandler.h"
  4. #include "CDefObjInfoHandler.h"
  5. #include "CLodHandler.h"
  6. #include "CGeneralTextHandler.h"
  7. #include "CDefObjInfoHandler.h"
  8. #include "CHeroHandler.h"
  9. #include "CSpellHandler.h"
  10. #include <boost/bind.hpp>
  11. #include <boost/algorithm/string/replace.hpp>
  12. #include <boost/random/linear_congruential.hpp>
  13. #include "CTownHandler.h"
  14. #include "CArtHandler.h"
  15. #include "../lib/VCMI_Lib.h"
  16. #include "../lib/IGameCallback.h"
  17. #include "../CGameState.h"
  18. #include "../lib/NetPacks.h"
  19. IGameCallback * IObjectInterface::cb = NULL;
  20. DLL_EXPORT void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
  21. extern CLodHandler * bitmaph;
  22. extern boost::rand48 ran;
  23. void IObjectInterface::onHeroVisit(const CGHeroInstance * h)
  24. {};
  25. void IObjectInterface::onHeroLeave(const CGHeroInstance * h)
  26. {};
  27. void IObjectInterface::newTurn ()
  28. {};
  29. IObjectInterface::~IObjectInterface()
  30. {}
  31. IObjectInterface::IObjectInterface()
  32. {}
  33. void IObjectInterface::initObj()
  34. {}
  35. void CObjectHandler::loadObjects()
  36. {
  37. VLC->objh = this;
  38. // int ID=0; //TODO use me
  39. tlog5 << "\t\tReading OBJNAMES \n";
  40. std::string buf = bitmaph->getTextFile("OBJNAMES.TXT");
  41. int it=0; //hope that -1 will not break this
  42. while (it<buf.length()-1)
  43. {
  44. std::string nobj;
  45. loadToIt(nobj, buf, it, 3);
  46. if(nobj.size() && (nobj[nobj.size()-1]==(char)10 || nobj[nobj.size()-1]==(char)13 || nobj[nobj.size()-1]==(char)9)) {
  47. nobj = nobj.substr(0, nobj.size()-1);
  48. }
  49. names.push_back(nobj);
  50. }
  51. tlog5 << "\t\tReading ADVEVENT \n";
  52. buf = bitmaph->getTextFile("ADVEVENT.TXT");
  53. it=0;
  54. std::string temp;
  55. while (it<buf.length()-1)
  56. {
  57. loadToIt(temp,buf,it,3);
  58. if (temp[0]=='\"') {
  59. temp = temp.substr(1,temp.length()-2);
  60. }
  61. boost::algorithm::replace_all(temp,"\"\"","\"");
  62. advobtxt.push_back(temp);
  63. }
  64. tlog5 << "\t\tReading XTRAINFO \n";
  65. buf = bitmaph->getTextFile("XTRAINFO.TXT");
  66. it=0;
  67. while (it<buf.length()-1)
  68. {
  69. loadToIt(temp,buf,it,3);
  70. xtrainfo.push_back(temp);
  71. }
  72. tlog5 << "\t\tReading MINENAME \n";
  73. buf = bitmaph->getTextFile("MINENAME.TXT");
  74. it=0;
  75. while (it<buf.length()-1)
  76. {
  77. loadToIt(temp,buf,it,3);
  78. mines.push_back(std::pair<std::string,std::string>(temp,""));
  79. }
  80. tlog5 << "\t\tReading MINEEVNT \n";
  81. buf = bitmaph->getTextFile("MINEEVNT.TXT");
  82. it=0;
  83. int i=0;
  84. while (it<buf.length()-1)
  85. {
  86. loadToIt(temp,buf,it,3);
  87. temp = temp.substr(1,temp.length()-2);
  88. mines[i++].second = temp;
  89. }
  90. tlog5 << "\t\tReading RESTYPES \n";
  91. buf = bitmaph->getTextFile("RESTYPES.TXT");
  92. it=0;
  93. while (it<buf.length()-1)
  94. {
  95. loadToIt(temp,buf,it,3);
  96. restypes.push_back(temp);
  97. }
  98. tlog5 << "\t\tReading cregens \n";
  99. cregens.resize(110); //TODO: hardcoded value - change
  100. for(size_t i=0; i < cregens.size(); ++i) {
  101. cregens[i]=-1;
  102. }
  103. std::ifstream ifs("config/cregens.txt");
  104. while(!ifs.eof())
  105. {
  106. int dw, cr;
  107. ifs >> dw >> cr;
  108. cregens[dw]=cr;
  109. }
  110. ifs.close();
  111. ifs.clear();
  112. tlog5 << "\t\tReading ZCRGN1 \n";
  113. buf = bitmaph->getTextFile("ZCRGN1.TXT");
  114. it=0;
  115. while (it<buf.length()-1)
  116. {
  117. loadToIt(temp,buf,it,3);
  118. creGens.push_back(temp);
  119. }
  120. tlog5 << "\t\tDone loading objects!\n";
  121. }
  122. int CGObjectInstance::getOwner() const
  123. {
  124. //if (state)
  125. // return state->owner;
  126. //else
  127. return tempOwner; //won't have owner
  128. }
  129. CGObjectInstance::CGObjectInstance(): animPhaseShift(rand()%0xff)
  130. {
  131. pos = int3(-1,-1,-1);
  132. //std::cout << "Tworze obiekt "<<this<<std::endl;
  133. //state = new CLuaObjectScript();
  134. ID = subID = id = -1;
  135. defInfo = NULL;
  136. state = NULL;
  137. info = NULL;
  138. tempOwner = 254;
  139. blockVisit = false;
  140. }
  141. CGObjectInstance::~CGObjectInstance()
  142. {
  143. //std::cout << "Usuwam obiekt "<<this<<std::endl;
  144. //if (state)
  145. // delete state;
  146. //state=NULL;
  147. }
  148. CGObjectInstance::CGObjectInstance(const CGObjectInstance & right)
  149. {
  150. pos = right.pos;
  151. ID = right.ID;
  152. subID = right.subID;
  153. id = right.id;
  154. defInfo = right.defInfo;
  155. info = right.info;
  156. blockVisit = right.blockVisit;
  157. //state = new CLuaObjectScript(right.state->);
  158. //*state = *right.state;
  159. //state = right.state;
  160. tempOwner = right.tempOwner;
  161. }
  162. CGObjectInstance& CGObjectInstance::operator=(const CGObjectInstance & right)
  163. {
  164. pos = right.pos;
  165. ID = right.ID;
  166. subID = right.subID;
  167. id = right.id;
  168. defInfo = right.defInfo;
  169. info = right.info;
  170. blockVisit = right.blockVisit;
  171. //state = new CLuaObjectScript();
  172. //*state = *right.state;
  173. tempOwner = right.tempOwner;
  174. return *this;
  175. }
  176. const std::string & CGObjectInstance::getHoverText() const
  177. {
  178. return hoverName;
  179. }
  180. void CGObjectInstance::setOwner(int ow)
  181. {
  182. //if (state)
  183. // state->owner = ow;
  184. //else
  185. tempOwner = ow;
  186. }
  187. int CGObjectInstance::getWidth() const//returns width of object graphic in tiles
  188. {
  189. return defInfo->width;
  190. }
  191. int CGObjectInstance::getHeight() const //returns height of object graphic in tiles
  192. {
  193. return defInfo->width;
  194. }
  195. bool CGObjectInstance::visitableAt(int x, int y) const //returns true if object is visitable at location (x, y) form left top tile of image (x, y in tiles)
  196. {
  197. if(x<0 || y<0 || x>=getWidth() || y>=getHeight() || defInfo==NULL)
  198. return false;
  199. if((defInfo->visitMap[y+6-getHeight()] >> (7-(8-getWidth()+x) )) & 1)
  200. return true;
  201. return false;
  202. }
  203. bool CGObjectInstance::blockingAt(int x, int y) const
  204. {
  205. if(x<0 || y<0 || x>=getWidth() || y>=getHeight() || defInfo==NULL)
  206. return false;
  207. if((defInfo->blockMap[y+6-getHeight()] >> (7-(8-getWidth()+x) )) & 1)
  208. return true;
  209. return false;
  210. }
  211. bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const //screen printing priority comparing
  212. {
  213. if(defInfo->printPriority==1 && cmp.defInfo->printPriority==0)
  214. return true;
  215. if(cmp.defInfo->printPriority==1 && defInfo->printPriority==0)
  216. return false;
  217. if(this->pos.y<cmp.pos.y)
  218. return true;
  219. if(this->pos.y>cmp.pos.y)
  220. return false;
  221. if(cmp.ID==34 && ID!=34)
  222. return true;
  223. if(cmp.ID!=34 && ID==34)
  224. return false;
  225. if(!defInfo->isVisitable() && cmp.defInfo->isVisitable())
  226. return true;
  227. if(!cmp.defInfo->isVisitable() && defInfo->isVisitable())
  228. return false;
  229. if(this->pos.x<cmp.pos.x)
  230. return true;
  231. return false;
  232. }
  233. void CGObjectInstance::initObj()
  234. {
  235. }
  236. int lowestSpeed(const CGHeroInstance * chi)
  237. {
  238. if(!chi->army.slots.size())
  239. {
  240. tlog1 << "Error! Hero " << chi->id << " ("<<chi->name<<") has no army!\n";
  241. return 20;
  242. }
  243. std::map<si32,std::pair<ui32,si32> >::const_iterator i = chi->army.slots.begin();
  244. ui32 ret = VLC->creh->creatures[(*i++).second.first].speed;
  245. for (;i!=chi->army.slots.end();i++)
  246. {
  247. ret = std::min(ret,VLC->creh->creatures[(*i).second.first].speed);
  248. }
  249. return ret;
  250. }
  251. unsigned int CGHeroInstance::getTileCost(const EterrainType & ttype, const Eroad & rdtype, const Eriver & rvtype) const
  252. {
  253. unsigned int ret = type->heroClass->terrCosts[ttype];
  254. //applying pathfinding skill
  255. switch(getSecSkillLevel(0))
  256. {
  257. case 1: //basic
  258. switch(ttype)
  259. {
  260. case rough:
  261. ret = 100;
  262. break;
  263. case sand: case snow:
  264. if(ret>125)
  265. ret = 125;
  266. break;
  267. case swamp:
  268. if(ret>150)
  269. ret = 150;
  270. break;
  271. default:
  272. //TODO do something nasty here throw maybe? or some def value asing
  273. break;
  274. }
  275. break;
  276. case 2: //advanced
  277. switch(ttype)
  278. {
  279. case rough:
  280. case sand:
  281. case snow:
  282. ret = 100;
  283. break;
  284. case swamp:
  285. if(ret>125)
  286. ret = 125;
  287. break;
  288. default:
  289. //TODO look up
  290. break;
  291. }
  292. break;
  293. case 3: //expert
  294. ret = 100;
  295. break;
  296. default:
  297. //TODO look up
  298. break;
  299. }
  300. //calculating road influence
  301. switch(rdtype)
  302. {
  303. case dirtRoad:
  304. ret*=0.75;
  305. break;
  306. case grazvelRoad:
  307. ret*=0.667;
  308. break;
  309. case cobblestoneRoad:
  310. ret*=0.5;
  311. break;
  312. default:
  313. //TODO killllll me
  314. break;
  315. }
  316. return ret;
  317. }
  318. unsigned int CGHeroInstance::getLowestCreatureSpeed() const
  319. {
  320. unsigned int sl = 100;
  321. for(size_t h=0; h < army.slots.size(); ++h)
  322. {
  323. if(VLC->creh->creatures[army.slots.find(h)->first].speed<sl)
  324. sl = VLC->creh->creatures[army.slots.find(h)->first].speed;
  325. }
  326. return sl;
  327. }
  328. int3 CGHeroInstance::convertPosition(int3 src, bool toh3m) //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
  329. {
  330. if (toh3m)
  331. {
  332. src.x+=1;
  333. return src;
  334. }
  335. else
  336. {
  337. src.x-=1;
  338. return src;
  339. }
  340. }
  341. int3 CGHeroInstance::getPosition(bool h3m) const //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
  342. {
  343. if (h3m) {
  344. return pos;
  345. }
  346. else {
  347. return convertPosition(pos,false);
  348. }
  349. }
  350. int CGHeroInstance::getSightDistance() const //returns sight distance of this hero
  351. {
  352. return 6 + getSecSkillLevel(3); //default + scouting
  353. }
  354. int CGHeroInstance::manaLimit() const
  355. {
  356. double modifier = 1.0;
  357. switch(getSecSkillLevel(24)) //intelligence level
  358. {
  359. case 1: modifier+=0.25; break;
  360. case 2: modifier+=0.5; break;
  361. case 3: modifier+=1.0; break;
  362. }
  363. return 10*getPrimSkillLevel(3)*modifier;
  364. }
  365. //void CGHeroInstance::setPosition(int3 Pos, bool h3m) //as above, but sets position
  366. //{
  367. // if (h3m)
  368. // pos = Pos;
  369. // else
  370. // pos = convertPosition(Pos,true);
  371. //}
  372. bool CGHeroInstance::canWalkOnSea() const
  373. {
  374. //TODO: write it - it should check if hero is flying, or something similiar
  375. return false;
  376. }
  377. int CGHeroInstance::getCurrentLuck() const
  378. {
  379. //TODO: write it
  380. return 0;
  381. }
  382. int CGHeroInstance::getCurrentMorale() const
  383. {
  384. //TODO: write it
  385. return 0;
  386. }
  387. int CGHeroInstance::getPrimSkillLevel(int id) const
  388. {
  389. return primSkills[id];
  390. }
  391. int CGHeroInstance::getSecSkillLevel(const int & ID) const
  392. {
  393. for(size_t i=0; i < secSkills.size(); ++i)
  394. if(secSkills[i].first==ID)
  395. return secSkills[i].second;
  396. return 0;
  397. }
  398. int CGHeroInstance::maxMovePoints(bool onLand) const
  399. {
  400. int ret = 1270+70*lowestSpeed(this);
  401. if (ret>2000)
  402. ret=2000;
  403. if(onLand)
  404. {
  405. //logistics:
  406. switch(getSecSkillLevel(2))
  407. {
  408. case 1:
  409. ret *= 1.1f;
  410. break;
  411. case 2:
  412. ret *= 1.2f;
  413. break;
  414. case 3:
  415. ret *= 1.3f;
  416. break;
  417. }
  418. }
  419. else
  420. {
  421. //navigation:
  422. switch(getSecSkillLevel(2))
  423. {
  424. case 1:
  425. ret *= 1.5f;
  426. break;
  427. case 2:
  428. ret *= 2.0f;
  429. break;
  430. case 3:
  431. ret *= 2.5f;
  432. break;
  433. }
  434. }
  435. return ret;
  436. }
  437. ui32 CGHeroInstance::getArtAtPos(ui16 pos) const
  438. {
  439. if(pos<19)
  440. if(vstd::contains(artifWorn,pos))
  441. return artifWorn.find(pos)->second;
  442. else
  443. return -1;
  444. else
  445. if(pos-19 < artifacts.size())
  446. return artifacts[pos-19];
  447. else
  448. return -1;
  449. }
  450. void CGHeroInstance::setArtAtPos(ui16 pos, int art)
  451. {
  452. if(art<0)
  453. {
  454. if(pos<19)
  455. artifWorn.erase(pos);
  456. else
  457. artifacts -= artifacts[pos-19];
  458. }
  459. else
  460. {
  461. if(pos<19)
  462. artifWorn[pos] = art;
  463. else
  464. if(pos-19 < artifacts.size())
  465. artifacts[pos-19] = art;
  466. else
  467. artifacts.push_back(art);
  468. }
  469. }
  470. const CArtifact * CGHeroInstance::getArt(int pos) const
  471. {
  472. int id = getArtAtPos(pos);
  473. if(id>=0)
  474. return &VLC->arth->artifacts[id];
  475. else
  476. return NULL;
  477. }
  478. int CGHeroInstance::getSpellSecLevel(int spell) const
  479. {
  480. int bestslvl = 0;
  481. if(VLC->spellh->spells[spell].air)
  482. if(getSecSkillLevel(15) >= bestslvl)
  483. {
  484. bestslvl = getSecSkillLevel(15);
  485. }
  486. if(VLC->spellh->spells[spell].fire)
  487. if(getSecSkillLevel(14) >= bestslvl)
  488. {
  489. bestslvl = getSecSkillLevel(14);
  490. }
  491. if(VLC->spellh->spells[spell].water)
  492. if(getSecSkillLevel(16) >= bestslvl)
  493. {
  494. bestslvl = getSecSkillLevel(16);
  495. }
  496. if(VLC->spellh->spells[spell].earth)
  497. if(getSecSkillLevel(17) >= bestslvl)
  498. {
  499. bestslvl = getSecSkillLevel(17);
  500. }
  501. return bestslvl;
  502. }
  503. CGHeroInstance::CGHeroInstance()
  504. {
  505. ID = 34;
  506. tacticFormationEnabled = inTownGarrison = false;
  507. mana = movement = portrait = level = -1;
  508. isStanding = true;
  509. moveDir = 4;
  510. exp = 0xffffffff;
  511. visitedTown = NULL;
  512. type = NULL;
  513. secSkills.push_back(std::make_pair(-1, -1));
  514. }
  515. void CGHeroInstance::initHero(int SUBID)
  516. {
  517. subID = SUBID;
  518. initHero();
  519. }
  520. void CGHeroInstance::initHero()
  521. {
  522. if(!defInfo)
  523. {
  524. defInfo = new CGDefInfo();
  525. defInfo->id = 34;
  526. defInfo->subid = subID;
  527. defInfo->printPriority = 0;
  528. defInfo->visitDir = 0xff;
  529. }
  530. if(!type)
  531. type = VLC->heroh->heroes[subID];
  532. for(int i=0;i<6;i++)
  533. {
  534. defInfo->blockMap[i]=255;
  535. defInfo->visitMap[i]=0;
  536. }
  537. defInfo->handler=NULL;
  538. defInfo->blockMap[5] = 253;
  539. defInfo->visitMap[5] = 2;
  540. artifWorn[16] = 3;
  541. if(type->heroType % 2 == 1) //it's a magical hero
  542. {
  543. artifWorn[17] = 0; //give him spellbook
  544. }
  545. if(portrait < 0 || portrait == 255)
  546. portrait = subID;
  547. if((!primSkills.size()) || (getPrimSkillLevel(0)<0))
  548. {
  549. primSkills.resize(4);
  550. primSkills[0] = type->heroClass->initialAttack;
  551. primSkills[1] = type->heroClass->initialDefence;
  552. primSkills[2] = type->heroClass->initialPower;
  553. primSkills[3] = type->heroClass->initialKnowledge;
  554. }
  555. if(secSkills.size() == 1 && secSkills[0] == std::pair<ui8,ui8>(-1, -1)) //set secondary skills to default
  556. secSkills = type->secSkillsInit;
  557. if(mana < 0)
  558. mana = manaLimit();
  559. if (!name.length())
  560. name = type->name;
  561. if (exp == 0xffffffff)
  562. {
  563. exp=40+ (ran()) % 50;
  564. level = 1;
  565. }
  566. else
  567. {
  568. level = VLC->heroh->level(exp);
  569. }
  570. if (!army.slots.size()) //standard army//initial army
  571. {
  572. int pom, pom2=0;
  573. for(int x=0;x<3;x++)
  574. {
  575. pom = (VLC->creh->nameToID[type->refTypeStack[x]]);
  576. if(pom>=145 && pom<=149) //war machine
  577. {
  578. pom2++;
  579. switch (pom)
  580. {
  581. case 145: //catapult
  582. artifWorn[16] = 3;
  583. break;
  584. default:
  585. artifWorn[9+CArtHandler::convertMachineID(pom,true)] = CArtHandler::convertMachineID(pom,true);
  586. break;
  587. }
  588. continue;
  589. }
  590. army.slots[x-pom2].first = pom;
  591. if((pom = (type->highStack[x]-type->lowStack[x])) > 0)
  592. army.slots[x-pom2].second = (ran()%pom)+type->lowStack[x];
  593. else
  594. army.slots[x-pom2].second = +type->lowStack[x];
  595. army.formation = false;
  596. }
  597. }
  598. hoverName = VLC->generaltexth->allTexts[15];
  599. boost::algorithm::replace_first(hoverName,"%s",name);
  600. boost::algorithm::replace_first(hoverName,"%s", type->heroClass->name);
  601. }
  602. CGHeroInstance::~CGHeroInstance()
  603. {
  604. }
  605. bool CGHeroInstance::needsLastStack() const
  606. {
  607. return true;
  608. }
  609. void CGHeroInstance::onHeroVisit(const CGHeroInstance * h)
  610. {
  611. //TODO: check for allies
  612. if(tempOwner == h->tempOwner) //our hero
  613. {
  614. //exchange
  615. }
  616. else
  617. {
  618. cb->startBattleI(
  619. &h->army,
  620. &army,
  621. h->pos,
  622. h,
  623. this,
  624. 0);
  625. }
  626. }
  627. const std::string & CGHeroInstance::getBiography() const
  628. {
  629. if (biography.length())
  630. return biography;
  631. else
  632. return VLC->generaltexth->hTxts[subID].biography;
  633. }
  634. void CGHeroInstance::initObj()
  635. {
  636. cb->setBlockVis(id,true);
  637. }
  638. int CGTownInstance::getSightDistance() const //returns sight distance
  639. {
  640. return 10;
  641. }
  642. int CGTownInstance::fortLevel() const //0 - none, 1 - fort, 2 - citadel, 3 - castle
  643. {
  644. if((builtBuildings.find(9))!=builtBuildings.end())
  645. return 3;
  646. if((builtBuildings.find(8))!=builtBuildings.end())
  647. return 2;
  648. if((builtBuildings.find(7))!=builtBuildings.end())
  649. return 1;
  650. return 0;
  651. }
  652. int CGTownInstance::hallLevel() const // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
  653. {
  654. if ((builtBuildings.find(13))!=builtBuildings.end())
  655. return 3;
  656. if ((builtBuildings.find(12))!=builtBuildings.end())
  657. return 2;
  658. if ((builtBuildings.find(11))!=builtBuildings.end())
  659. return 1;
  660. if ((builtBuildings.find(10))!=builtBuildings.end())
  661. return 0;
  662. return -1;
  663. }
  664. int CGTownInstance::mageGuildLevel() const
  665. {
  666. if ((builtBuildings.find(4))!=builtBuildings.end())
  667. return 5;
  668. if ((builtBuildings.find(3))!=builtBuildings.end())
  669. return 4;
  670. if ((builtBuildings.find(2))!=builtBuildings.end())
  671. return 3;
  672. if ((builtBuildings.find(1))!=builtBuildings.end())
  673. return 2;
  674. if ((builtBuildings.find(0))!=builtBuildings.end())
  675. return 1;
  676. return 0;
  677. }
  678. bool CGTownInstance::creatureDwelling(const int & level, bool upgraded) const
  679. {
  680. return builtBuildings.find(30+level+upgraded*7)!=builtBuildings.end();
  681. }
  682. int CGTownInstance::getHordeLevel(const int & HID) const//HID - 0 or 1; returns creature level or -1 if that horde structure is not present
  683. {
  684. return town->hordeLvl[HID];
  685. }
  686. int CGTownInstance::creatureGrowth(const int & level) const
  687. {
  688. int ret = VLC->creh->creatures[town->basicCreatures[level]].growth;
  689. switch(fortLevel())
  690. {
  691. case 3:
  692. ret*=2;break;
  693. case 2:
  694. ret*=(1.5); break;
  695. }
  696. if(builtBuildings.find(26)!=builtBuildings.end()) //grail
  697. ret+=VLC->creh->creatures[town->basicCreatures[level]].growth;
  698. if(getHordeLevel(0)==level)
  699. if((builtBuildings.find(18)!=builtBuildings.end()) || (builtBuildings.find(19)!=builtBuildings.end()))
  700. ret+=VLC->creh->creatures[town->basicCreatures[level]].hordeGrowth;
  701. if(getHordeLevel(1)==level)
  702. if((builtBuildings.find(24)!=builtBuildings.end()) || (builtBuildings.find(25)!=builtBuildings.end()))
  703. ret+=VLC->creh->creatures[town->basicCreatures[level]].hordeGrowth;
  704. return ret;
  705. }
  706. int CGTownInstance::dailyIncome() const
  707. {
  708. int ret = 0;
  709. if ((builtBuildings.find(26))!=builtBuildings.end())
  710. ret+=5000;
  711. if ((builtBuildings.find(13))!=builtBuildings.end())
  712. ret+=4000;
  713. else if ((builtBuildings.find(12))!=builtBuildings.end())
  714. ret+=2000;
  715. else if ((builtBuildings.find(11))!=builtBuildings.end())
  716. ret+=1000;
  717. else if ((builtBuildings.find(10))!=builtBuildings.end())
  718. ret+=500;
  719. return ret;
  720. }
  721. bool CGTownInstance::hasFort() const
  722. {
  723. return (builtBuildings.find(7))!=builtBuildings.end();
  724. }
  725. bool CGTownInstance::hasCapitol() const
  726. {
  727. return (builtBuildings.find(13))!=builtBuildings.end();
  728. }
  729. CGTownInstance::CGTownInstance()
  730. {
  731. builded=-1;
  732. destroyed=-1;
  733. garrisonHero=NULL;
  734. town=NULL;
  735. visitingHero = NULL;
  736. }
  737. CGTownInstance::~CGTownInstance()
  738. {}
  739. int CGTownInstance::spellsAtLevel(int level, bool checkGuild) const
  740. {
  741. if(checkGuild && mageGuildLevel() < level)
  742. return 0;
  743. int ret = 6 - level; //how many spells are available at this level
  744. if(subID == 2 && vstd::contains(builtBuildings,22)) //magic library in Tower
  745. ret++;
  746. return ret;
  747. }
  748. bool CGTownInstance::needsLastStack() const
  749. {
  750. if(garrisonHero)
  751. return true;
  752. else return false;
  753. }
  754. void CGTownInstance::onHeroVisit(const CGHeroInstance * h)
  755. {
  756. if(getOwner() != h->getOwner())
  757. {
  758. return;
  759. }
  760. cb->heroVisitCastle(id,h->id);
  761. }
  762. void CGTownInstance::onHeroLeave(const CGHeroInstance * h)
  763. {
  764. cb->stopHeroVisitCastle(id,h->id);
  765. }
  766. void CGTownInstance::initObj()
  767. {
  768. MetaString ms;
  769. ms << name << ", " << town->Name();
  770. cb->setHoverName(id,&ms);
  771. }
  772. //std::vector<int> CVisitableOPH::yourObjects()
  773. //{
  774. // std::vector<int> ret;
  775. // ret.push_back(51);//camp
  776. // ret.push_back(23);//tower
  777. // ret.push_back(61);//axis
  778. // ret.push_back(32);//garden
  779. // ret.push_back(100);//stone
  780. // ret.push_back(102);//tree
  781. // return ret;
  782. //}
  783. void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h )
  784. {
  785. if(visitors.find(h->id)==visitors.end())
  786. {
  787. onNAHeroVisit(h->id, false);
  788. if(ID != 102) //not tree
  789. visitors.insert(h->id);
  790. }
  791. else
  792. {
  793. onNAHeroVisit(h->id, true);
  794. }
  795. }
  796. void CGVisitableOPH::initObj()
  797. {
  798. if(ID==102)
  799. ttype = ran()%3;
  800. else
  801. ttype = -1;
  802. }
  803. void CGVisitableOPH::treeSelected( int heroID, int resType, int resVal, int expVal, ui32 result )
  804. {
  805. if(result==0) //player agreed to give res for exp
  806. {
  807. cb->giveResource(cb->getOwner(heroID),resType,-resVal); //take resource
  808. cb->changePrimSkill(heroID,4,expVal); //give exp
  809. visitors.insert(heroID); //set state to visited
  810. }
  811. }
  812. void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited)
  813. {
  814. int id=0, subid=0, ot=0, val=1;
  815. switch(ID)
  816. {
  817. case 51:
  818. subid=0;
  819. ot=80;
  820. break;
  821. case 23:
  822. subid=1;
  823. ot=39;
  824. break;
  825. case 61:
  826. subid=2;
  827. ot=100;
  828. break;
  829. case 32:
  830. subid=3;
  831. ot=59;
  832. break;
  833. case 100:
  834. id=5;
  835. ot=143;
  836. val=1000;
  837. break;
  838. case 102:
  839. id = 5;
  840. subid = 1;
  841. ot = 146;
  842. val = 1;
  843. break;
  844. }
  845. if (!alreadyVisited)
  846. {
  847. switch (ID)
  848. {
  849. case 51:
  850. case 23:
  851. case 61:
  852. case 32:
  853. {
  854. cb->changePrimSkill(heroID,subid,val);
  855. InfoWindow iw;
  856. iw.components.push_back(Component(0,subid,val,0));
  857. iw.text << std::pair<ui8,ui32>(11,ot);
  858. iw.player = cb->getOwner(heroID);
  859. cb->showInfoDialog(&iw);
  860. break;
  861. }
  862. case 100: //give exp
  863. {
  864. InfoWindow iw;
  865. iw.components.push_back(Component(id,subid,val,0));
  866. iw.player = cb->getOwner(heroID);
  867. iw.text << std::pair<ui8,ui32>(11,ot);
  868. cb->showInfoDialog(&iw);
  869. cb->changePrimSkill(heroID,4,val);
  870. break;
  871. }
  872. case 102:
  873. {
  874. const CGHeroInstance *h = cb->getHero(heroID);
  875. val = VLC->heroh->reqExp(h->level+val) - VLC->heroh->reqExp(h->level);
  876. if(!ttype)
  877. {
  878. visitors.insert(heroID);
  879. InfoWindow iw;
  880. iw.components.push_back(Component(id,subid,1,0));
  881. iw.player = cb->getOwner(heroID);
  882. iw.text << std::pair<ui8,ui32>(11,148);
  883. cb->showInfoDialog(&iw);
  884. cb->changePrimSkill(heroID,4,val);
  885. break;
  886. }
  887. else
  888. {
  889. int res, resval;
  890. if(ttype==1)
  891. {
  892. res = 6;
  893. resval = 2000;
  894. ot = 149;
  895. }
  896. else
  897. {
  898. res = 5;
  899. resval = 10;
  900. ot = 151;
  901. }
  902. if(cb->getResource(h->tempOwner,res) < resval) //not enough resources
  903. {
  904. ot++;
  905. InfoWindow iw;
  906. iw.player = h->tempOwner;
  907. iw.text << std::pair<ui8,ui32>(11,ot);
  908. cb->showInfoDialog(&iw);
  909. return;
  910. }
  911. YesNoDialog sd;
  912. sd.player = cb->getOwner(heroID);
  913. sd.text << std::pair<ui8,ui32>(11,ot);
  914. sd.components.push_back(Component(id,subid,val,0));
  915. cb->showYesNoDialog(&sd,boost::bind(&CGVisitableOPH::treeSelected,this,heroID,res,resval,val,_1));
  916. }
  917. break;
  918. }
  919. }
  920. }
  921. else
  922. {
  923. ot++;
  924. InfoWindow iw;
  925. iw.player = cb->getOwner(heroID);
  926. iw.text << std::pair<ui8,ui32>(11,ot);
  927. cb->showInfoDialog(&iw);
  928. }
  929. }
  930. const std::string & CGVisitableOPH::getHoverText() const
  931. {
  932. int pom;
  933. switch(ID)
  934. {
  935. case 51:
  936. pom = 8;
  937. break;
  938. case 23:
  939. pom = 7;
  940. break;
  941. case 61:
  942. pom = 11;
  943. break;
  944. case 32:
  945. pom = 4;
  946. break;
  947. case 100:
  948. pom = 5;
  949. break;
  950. case 102:
  951. pom = 18;
  952. break;
  953. default:
  954. throw "Wrong CGVisitableOPH object ID!\n";
  955. }
  956. hoverName = VLC->objh->names[ID] + " " + VLC->objh->xtrainfo[pom];
  957. const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
  958. if(h)
  959. {
  960. hoverName += (vstd::contains(visitors,h->id))
  961. ? (VLC->generaltexth->allTexts[353]) //not visited
  962. : ( VLC->generaltexth->allTexts[352]); //visited
  963. }
  964. return hoverName;
  965. }
  966. bool CArmedInstance::needsLastStack() const
  967. {
  968. return false;
  969. }
  970. void CGCreature::onHeroVisit( const CGHeroInstance * h )
  971. {
  972. army.slots[0].first = subID;
  973. cb->startBattleI(h->id,army,pos,boost::bind(&CGCreature::endBattle,this,_1));
  974. }
  975. void CGCreature::endBattle( BattleResult *result )
  976. {
  977. if(result->winner==0)
  978. {
  979. cb->removeObject(id);
  980. }
  981. else
  982. {
  983. int killedAmount=0;
  984. for(std::set<std::pair<ui32,si32> >::iterator i=result->casualties[1].begin(); i!=result->casualties[1].end(); i++)
  985. if(i->first == subID)
  986. killedAmount += i->second;
  987. cb->setAmount(id, army.slots[0].second - killedAmount);
  988. }
  989. }
  990. void CGCreature::initObj()
  991. {
  992. si32 &amount = army.slots[0].second;
  993. CCreature &c = VLC->creh->creatures[subID];
  994. if(!amount)
  995. if(c.ammMax == c.ammMin)
  996. amount = c.ammMax;
  997. else
  998. amount = c.ammMin + (ran() % (c.ammMax - c.ammMin));
  999. }