CObjectHandler.cpp 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456
  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. std::map<int,std::map<int, std::vector<int> > > CGTeleport::objs;
  20. IGameCallback * IObjectInterface::cb = NULL;
  21. DLL_EXPORT void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
  22. extern CLodHandler * bitmaph;
  23. extern boost::rand48 ran;
  24. void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const
  25. {};
  26. void IObjectInterface::onHeroLeave(const CGHeroInstance * h) const
  27. {};
  28. void IObjectInterface::newTurn () const
  29. {};
  30. IObjectInterface::~IObjectInterface()
  31. {}
  32. IObjectInterface::IObjectInterface()
  33. {}
  34. void IObjectInterface::initObj()
  35. {}
  36. void CObjectHandler::loadObjects()
  37. {
  38. tlog5 << "\t\tReading cregens \n";
  39. cregens.resize(110); //TODO: hardcoded value - change
  40. for(size_t i=0; i < cregens.size(); ++i)
  41. {
  42. cregens[i]=-1;
  43. }
  44. std::ifstream ifs("config/cregens.txt");
  45. while(!ifs.eof())
  46. {
  47. int dw, cr;
  48. ifs >> dw >> cr;
  49. cregens[dw]=cr;
  50. }
  51. ifs.close();
  52. ifs.clear();
  53. tlog5 << "\t\tDone loading objects!\n";
  54. }
  55. int CGObjectInstance::getOwner() const
  56. {
  57. //if (state)
  58. // return state->owner;
  59. //else
  60. return tempOwner; //won't have owner
  61. }
  62. CGObjectInstance::CGObjectInstance(): animPhaseShift(rand()%0xff)
  63. {
  64. pos = int3(-1,-1,-1);
  65. //std::cout << "Tworze obiekt "<<this<<std::endl;
  66. //state = new CLuaObjectScript();
  67. ID = subID = id = -1;
  68. defInfo = NULL;
  69. info = NULL;
  70. tempOwner = 254;
  71. blockVisit = false;
  72. }
  73. CGObjectInstance::~CGObjectInstance()
  74. {
  75. //std::cout << "Usuwam obiekt "<<this<<std::endl;
  76. //if (state)
  77. // delete state;
  78. //state=NULL;
  79. }
  80. //CGObjectInstance::CGObjectInstance(const CGObjectInstance & right)
  81. //{
  82. // pos = right.pos;
  83. // ID = right.ID;
  84. // subID = right.subID;
  85. // id = right.id;
  86. // defInfo = right.defInfo;
  87. // info = right.info;
  88. // blockVisit = right.blockVisit;
  89. // //state = new CLuaObjectScript(right.state->);
  90. // //*state = *right.state;
  91. // //state = right.state;
  92. // tempOwner = right.tempOwner;
  93. //}
  94. //CGObjectInstance& CGObjectInstance::operator=(const CGObjectInstance & right)
  95. //{
  96. // pos = right.pos;
  97. // ID = right.ID;
  98. // subID = right.subID;
  99. // id = right.id;
  100. // defInfo = right.defInfo;
  101. // info = right.info;
  102. // blockVisit = right.blockVisit;
  103. // //state = new CLuaObjectScript();
  104. // //*state = *right.state;
  105. // tempOwner = right.tempOwner;
  106. // return *this;
  107. //}
  108. const std::string & CGObjectInstance::getHoverText() const
  109. {
  110. return hoverName;
  111. }
  112. void CGObjectInstance::setOwner(int ow)
  113. {
  114. //if (state)
  115. // state->owner = ow;
  116. //else
  117. tempOwner = ow;
  118. }
  119. int CGObjectInstance::getWidth() const//returns width of object graphic in tiles
  120. {
  121. return defInfo->width;
  122. }
  123. int CGObjectInstance::getHeight() const //returns height of object graphic in tiles
  124. {
  125. return defInfo->width;
  126. }
  127. 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)
  128. {
  129. if(x<0 || y<0 || x>=getWidth() || y>=getHeight() || defInfo==NULL)
  130. return false;
  131. if((defInfo->visitMap[y+6-getHeight()] >> (7-(8-getWidth()+x) )) & 1)
  132. return true;
  133. return false;
  134. }
  135. bool CGObjectInstance::blockingAt(int x, int y) const
  136. {
  137. if(x<0 || y<0 || x>=getWidth() || y>=getHeight() || defInfo==NULL)
  138. return false;
  139. if((defInfo->blockMap[y+6-getHeight()] >> (7-(8-getWidth()+x) )) & 1)
  140. return true;
  141. return false;
  142. }
  143. bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const //screen printing priority comparing
  144. {
  145. if(defInfo->printPriority==1 && cmp.defInfo->printPriority==0)
  146. return true;
  147. if(cmp.defInfo->printPriority==1 && defInfo->printPriority==0)
  148. return false;
  149. if(this->pos.y<cmp.pos.y)
  150. return true;
  151. if(this->pos.y>cmp.pos.y)
  152. return false;
  153. if(cmp.ID==34 && ID!=34)
  154. return true;
  155. if(cmp.ID!=34 && ID==34)
  156. return false;
  157. if(!defInfo->isVisitable() && cmp.defInfo->isVisitable())
  158. return true;
  159. if(!cmp.defInfo->isVisitable() && defInfo->isVisitable())
  160. return false;
  161. if(this->pos.x<cmp.pos.x)
  162. return true;
  163. return false;
  164. }
  165. void CGObjectInstance::initObj()
  166. {
  167. }
  168. int lowestSpeed(const CGHeroInstance * chi)
  169. {
  170. if(!chi->army.slots.size())
  171. {
  172. tlog1 << "Error! Hero " << chi->id << " ("<<chi->name<<") has no army!\n";
  173. return 20;
  174. }
  175. std::map<si32,std::pair<ui32,si32> >::const_iterator i = chi->army.slots.begin();
  176. ui32 ret = VLC->creh->creatures[(*i++).second.first].speed;
  177. for (;i!=chi->army.slots.end();i++)
  178. {
  179. ret = std::min(ret,VLC->creh->creatures[(*i).second.first].speed);
  180. }
  181. return ret;
  182. }
  183. unsigned int CGHeroInstance::getTileCost(const EterrainType & ttype, const Eroad & rdtype, const Eriver & rvtype) const
  184. {
  185. unsigned int ret = type->heroClass->terrCosts[ttype];
  186. //applying pathfinding skill
  187. switch(getSecSkillLevel(0))
  188. {
  189. case 1: //basic
  190. switch(ttype)
  191. {
  192. case rough:
  193. ret = 100;
  194. break;
  195. case sand: case snow:
  196. if(ret>125)
  197. ret = 125;
  198. break;
  199. case swamp:
  200. if(ret>150)
  201. ret = 150;
  202. break;
  203. default:
  204. //TODO do something nasty here throw maybe? or some def value asing
  205. break;
  206. }
  207. break;
  208. case 2: //advanced
  209. switch(ttype)
  210. {
  211. case rough:
  212. case sand:
  213. case snow:
  214. ret = 100;
  215. break;
  216. case swamp:
  217. if(ret>125)
  218. ret = 125;
  219. break;
  220. default:
  221. //TODO look up
  222. break;
  223. }
  224. break;
  225. case 3: //expert
  226. ret = 100;
  227. break;
  228. default:
  229. //TODO look up
  230. break;
  231. }
  232. //calculating road influence
  233. switch(rdtype)
  234. {
  235. case dirtRoad:
  236. ret*=0.75;
  237. break;
  238. case grazvelRoad:
  239. ret*=0.667;
  240. break;
  241. case cobblestoneRoad:
  242. ret*=0.5;
  243. break;
  244. default:
  245. //TODO killllll me
  246. break;
  247. }
  248. return ret;
  249. }
  250. unsigned int CGHeroInstance::getLowestCreatureSpeed() const
  251. {
  252. unsigned int sl = 100;
  253. for(size_t h=0; h < army.slots.size(); ++h)
  254. {
  255. if(VLC->creh->creatures[army.slots.find(h)->first].speed<sl)
  256. sl = VLC->creh->creatures[army.slots.find(h)->first].speed;
  257. }
  258. return sl;
  259. }
  260. int3 CGHeroInstance::convertPosition(int3 src, bool toh3m) //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
  261. {
  262. if (toh3m)
  263. {
  264. src.x+=1;
  265. return src;
  266. }
  267. else
  268. {
  269. src.x-=1;
  270. return src;
  271. }
  272. }
  273. int3 CGHeroInstance::getPosition(bool h3m) const //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
  274. {
  275. if (h3m)
  276. {
  277. return pos;
  278. }
  279. else
  280. {
  281. return convertPosition(pos,false);
  282. }
  283. }
  284. int CGHeroInstance::getSightDistance() const //returns sight distance of this hero
  285. {
  286. return 6 + getSecSkillLevel(3); //default + scouting
  287. }
  288. si32 CGHeroInstance::manaLimit() const
  289. {
  290. double modifier = 1.0;
  291. switch(getSecSkillLevel(24)) //intelligence level
  292. {
  293. case 1: modifier+=0.25; break;
  294. case 2: modifier+=0.5; break;
  295. case 3: modifier+=1.0; break;
  296. }
  297. return 10*getPrimSkillLevel(3)*modifier;
  298. }
  299. //void CGHeroInstance::setPosition(int3 Pos, bool h3m) //as above, but sets position
  300. //{
  301. // if (h3m)
  302. // pos = Pos;
  303. // else
  304. // pos = convertPosition(Pos,true);
  305. //}
  306. bool CGHeroInstance::canWalkOnSea() const
  307. {
  308. //TODO: write it - it should check if hero is flying, or something similiar
  309. return false;
  310. }
  311. int CGHeroInstance::getCurrentLuck() const
  312. {
  313. //TODO: write it
  314. return 0;
  315. }
  316. int CGHeroInstance::getCurrentMorale() const
  317. {
  318. //TODO: write it
  319. return 0;
  320. }
  321. int CGHeroInstance::getPrimSkillLevel(int id) const
  322. {
  323. return primSkills[id];
  324. }
  325. ui8 CGHeroInstance::getSecSkillLevel(const int & ID) const
  326. {
  327. for(size_t i=0; i < secSkills.size(); ++i)
  328. if(secSkills[i].first==ID)
  329. return secSkills[i].second;
  330. return 0;
  331. }
  332. int CGHeroInstance::maxMovePoints(bool onLand) const
  333. {
  334. int ret = 1270+70*lowestSpeed(this);
  335. if (ret>2000)
  336. ret=2000;
  337. if(onLand)
  338. {
  339. //logistics:
  340. switch(getSecSkillLevel(2))
  341. {
  342. case 1:
  343. ret *= 1.1f;
  344. break;
  345. case 2:
  346. ret *= 1.2f;
  347. break;
  348. case 3:
  349. ret *= 1.3f;
  350. break;
  351. }
  352. }
  353. else
  354. {
  355. //navigation:
  356. switch(getSecSkillLevel(2))
  357. {
  358. case 1:
  359. ret *= 1.5f;
  360. break;
  361. case 2:
  362. ret *= 2.0f;
  363. break;
  364. case 3:
  365. ret *= 2.5f;
  366. break;
  367. }
  368. }
  369. return ret;
  370. }
  371. ui32 CGHeroInstance::getArtAtPos(ui16 pos) const
  372. {
  373. if(pos<19)
  374. if(vstd::contains(artifWorn,pos))
  375. return artifWorn.find(pos)->second;
  376. else
  377. return -1;
  378. else
  379. if(pos-19 < artifacts.size())
  380. return artifacts[pos-19];
  381. else
  382. return -1;
  383. }
  384. void CGHeroInstance::setArtAtPos(ui16 pos, int art)
  385. {
  386. if(art<0)
  387. {
  388. if(pos<19)
  389. artifWorn.erase(pos);
  390. else
  391. artifacts -= artifacts[pos-19];
  392. }
  393. else
  394. {
  395. if(pos<19)
  396. artifWorn[pos] = art;
  397. else
  398. if(pos-19 < artifacts.size())
  399. artifacts[pos-19] = art;
  400. else
  401. artifacts.push_back(art);
  402. }
  403. }
  404. const CArtifact * CGHeroInstance::getArt(int pos) const
  405. {
  406. int id = getArtAtPos(pos);
  407. if(id>=0)
  408. return &VLC->arth->artifacts[id];
  409. else
  410. return NULL;
  411. }
  412. int CGHeroInstance::getSpellSecLevel(int spell) const
  413. {
  414. int bestslvl = 0;
  415. if(VLC->spellh->spells[spell].air)
  416. if(getSecSkillLevel(15) >= bestslvl)
  417. {
  418. bestslvl = getSecSkillLevel(15);
  419. }
  420. if(VLC->spellh->spells[spell].fire)
  421. if(getSecSkillLevel(14) >= bestslvl)
  422. {
  423. bestslvl = getSecSkillLevel(14);
  424. }
  425. if(VLC->spellh->spells[spell].water)
  426. if(getSecSkillLevel(16) >= bestslvl)
  427. {
  428. bestslvl = getSecSkillLevel(16);
  429. }
  430. if(VLC->spellh->spells[spell].earth)
  431. if(getSecSkillLevel(17) >= bestslvl)
  432. {
  433. bestslvl = getSecSkillLevel(17);
  434. }
  435. return bestslvl;
  436. }
  437. CGHeroInstance::CGHeroInstance()
  438. {
  439. ID = 34;
  440. tacticFormationEnabled = inTownGarrison = false;
  441. mana = movement = portrait = level = -1;
  442. isStanding = true;
  443. moveDir = 4;
  444. exp = 0xffffffff;
  445. visitedTown = NULL;
  446. type = NULL;
  447. secSkills.push_back(std::make_pair(-1, -1));
  448. }
  449. void CGHeroInstance::initHero(int SUBID)
  450. {
  451. subID = SUBID;
  452. initHero();
  453. }
  454. void CGHeroInstance::initHero()
  455. {
  456. initHeroDefInfo();
  457. if(!type)
  458. type = VLC->heroh->heroes[subID];
  459. artifWorn[16] = 3;
  460. if(type->heroType % 2 == 1) //it's a magical hero
  461. {
  462. artifWorn[17] = 0; //give him spellbook
  463. }
  464. if(portrait < 0 || portrait == 255)
  465. portrait = subID;
  466. if((!primSkills.size()) || (getPrimSkillLevel(0)<0))
  467. {
  468. primSkills.resize(4);
  469. primSkills[0] = type->heroClass->initialAttack;
  470. primSkills[1] = type->heroClass->initialDefence;
  471. primSkills[2] = type->heroClass->initialPower;
  472. primSkills[3] = type->heroClass->initialKnowledge;
  473. }
  474. if(secSkills.size() == 1 && secSkills[0] == std::pair<ui8,ui8>(-1, -1)) //set secondary skills to default
  475. secSkills = type->secSkillsInit;
  476. if(mana < 0)
  477. mana = manaLimit();
  478. if (!name.length())
  479. name = type->name;
  480. if (exp == 0xffffffff)
  481. {
  482. exp=40+ (ran()) % 50;
  483. level = 1;
  484. }
  485. else
  486. {
  487. level = VLC->heroh->level(exp);
  488. }
  489. if (!army.slots.size()) //standard army//initial army
  490. {
  491. int pom, pom2=0;
  492. for(int x=0;x<3;x++)
  493. {
  494. pom = (VLC->creh->nameToID[type->refTypeStack[x]]);
  495. if(pom>=145 && pom<=149) //war machine
  496. {
  497. pom2++;
  498. switch (pom)
  499. {
  500. case 145: //catapult
  501. artifWorn[16] = 3;
  502. break;
  503. default:
  504. artifWorn[9+CArtHandler::convertMachineID(pom,true)] = CArtHandler::convertMachineID(pom,true);
  505. break;
  506. }
  507. continue;
  508. }
  509. army.slots[x-pom2].first = pom;
  510. if((pom = (type->highStack[x]-type->lowStack[x])) > 0)
  511. army.slots[x-pom2].second = (ran()%pom)+type->lowStack[x];
  512. else
  513. army.slots[x-pom2].second = +type->lowStack[x];
  514. army.formation = false;
  515. }
  516. }
  517. hoverName = VLC->generaltexth->allTexts[15];
  518. boost::algorithm::replace_first(hoverName,"%s",name);
  519. boost::algorithm::replace_first(hoverName,"%s", type->heroClass->name);
  520. }
  521. void CGHeroInstance::initHeroDefInfo()
  522. {
  523. if(!defInfo)
  524. {
  525. defInfo = new CGDefInfo();
  526. defInfo->id = 34;
  527. defInfo->subid = subID;
  528. defInfo->printPriority = 0;
  529. defInfo->visitDir = 0xff;
  530. }
  531. for(int i=0;i<6;i++)
  532. {
  533. defInfo->blockMap[i]=255;
  534. defInfo->visitMap[i]=0;
  535. }
  536. defInfo->handler=NULL;
  537. defInfo->blockMap[5] = 253;
  538. defInfo->visitMap[5] = 2;
  539. }
  540. CGHeroInstance::~CGHeroInstance()
  541. {
  542. }
  543. bool CGHeroInstance::needsLastStack() const
  544. {
  545. return true;
  546. }
  547. void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
  548. {
  549. //TODO: check for allies
  550. if(tempOwner == h->tempOwner) //our hero
  551. {
  552. //exchange
  553. }
  554. else
  555. {
  556. cb->startBattleI(
  557. &h->army,
  558. &army,
  559. h->pos,
  560. h,
  561. this,
  562. 0);
  563. }
  564. }
  565. const std::string & CGHeroInstance::getBiography() const
  566. {
  567. if (biography.length())
  568. return biography;
  569. else
  570. return VLC->generaltexth->hTxts[subID].biography;
  571. }
  572. void CGHeroInstance::initObj()
  573. {
  574. blockVisit = true;
  575. }
  576. int CGTownInstance::getSightDistance() const //returns sight distance
  577. {
  578. return 10;
  579. }
  580. int CGTownInstance::fortLevel() const //0 - none, 1 - fort, 2 - citadel, 3 - castle
  581. {
  582. if((builtBuildings.find(9))!=builtBuildings.end())
  583. return 3;
  584. if((builtBuildings.find(8))!=builtBuildings.end())
  585. return 2;
  586. if((builtBuildings.find(7))!=builtBuildings.end())
  587. return 1;
  588. return 0;
  589. }
  590. int CGTownInstance::hallLevel() const // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
  591. {
  592. if ((builtBuildings.find(13))!=builtBuildings.end())
  593. return 3;
  594. if ((builtBuildings.find(12))!=builtBuildings.end())
  595. return 2;
  596. if ((builtBuildings.find(11))!=builtBuildings.end())
  597. return 1;
  598. if ((builtBuildings.find(10))!=builtBuildings.end())
  599. return 0;
  600. return -1;
  601. }
  602. int CGTownInstance::mageGuildLevel() const
  603. {
  604. if ((builtBuildings.find(4))!=builtBuildings.end())
  605. return 5;
  606. if ((builtBuildings.find(3))!=builtBuildings.end())
  607. return 4;
  608. if ((builtBuildings.find(2))!=builtBuildings.end())
  609. return 3;
  610. if ((builtBuildings.find(1))!=builtBuildings.end())
  611. return 2;
  612. if ((builtBuildings.find(0))!=builtBuildings.end())
  613. return 1;
  614. return 0;
  615. }
  616. bool CGTownInstance::creatureDwelling(const int & level, bool upgraded) const
  617. {
  618. return builtBuildings.find(30+level+upgraded*7)!=builtBuildings.end();
  619. }
  620. int CGTownInstance::getHordeLevel(const int & HID) const//HID - 0 or 1; returns creature level or -1 if that horde structure is not present
  621. {
  622. return town->hordeLvl[HID];
  623. }
  624. int CGTownInstance::creatureGrowth(const int & level) const
  625. {
  626. int ret = VLC->creh->creatures[town->basicCreatures[level]].growth;
  627. switch(fortLevel())
  628. {
  629. case 3:
  630. ret*=2;break;
  631. case 2:
  632. ret*=(1.5); break;
  633. }
  634. if(builtBuildings.find(26)!=builtBuildings.end()) //grail
  635. ret+=VLC->creh->creatures[town->basicCreatures[level]].growth;
  636. if(getHordeLevel(0)==level)
  637. if((builtBuildings.find(18)!=builtBuildings.end()) || (builtBuildings.find(19)!=builtBuildings.end()))
  638. ret+=VLC->creh->creatures[town->basicCreatures[level]].hordeGrowth;
  639. if(getHordeLevel(1)==level)
  640. if((builtBuildings.find(24)!=builtBuildings.end()) || (builtBuildings.find(25)!=builtBuildings.end()))
  641. ret+=VLC->creh->creatures[town->basicCreatures[level]].hordeGrowth;
  642. return ret;
  643. }
  644. int CGTownInstance::dailyIncome() const
  645. {
  646. int ret = 0;
  647. if ((builtBuildings.find(26))!=builtBuildings.end())
  648. ret+=5000;
  649. if ((builtBuildings.find(13))!=builtBuildings.end())
  650. ret+=4000;
  651. else if ((builtBuildings.find(12))!=builtBuildings.end())
  652. ret+=2000;
  653. else if ((builtBuildings.find(11))!=builtBuildings.end())
  654. ret+=1000;
  655. else if ((builtBuildings.find(10))!=builtBuildings.end())
  656. ret+=500;
  657. return ret;
  658. }
  659. bool CGTownInstance::hasFort() const
  660. {
  661. return (builtBuildings.find(7))!=builtBuildings.end();
  662. }
  663. bool CGTownInstance::hasCapitol() const
  664. {
  665. return (builtBuildings.find(13))!=builtBuildings.end();
  666. }
  667. CGTownInstance::CGTownInstance()
  668. {
  669. builded=-1;
  670. destroyed=-1;
  671. garrisonHero=NULL;
  672. town=NULL;
  673. visitingHero = NULL;
  674. }
  675. CGTownInstance::~CGTownInstance()
  676. {}
  677. int CGTownInstance::spellsAtLevel(int level, bool checkGuild) const
  678. {
  679. if(checkGuild && mageGuildLevel() < level)
  680. return 0;
  681. int ret = 6 - level; //how many spells are available at this level
  682. if(subID == 2 && vstd::contains(builtBuildings,22)) //magic library in Tower
  683. ret++;
  684. return ret;
  685. }
  686. bool CGTownInstance::needsLastStack() const
  687. {
  688. if(garrisonHero)
  689. return true;
  690. else return false;
  691. }
  692. void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
  693. {
  694. if(getOwner() != h->getOwner())
  695. {
  696. return;
  697. }
  698. cb->heroVisitCastle(id,h->id);
  699. }
  700. void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
  701. {
  702. cb->stopHeroVisitCastle(id,h->id);
  703. }
  704. void CGTownInstance::initObj()
  705. {
  706. MetaString ms;
  707. ms << name << ", " << town->Name();
  708. hoverName = toString(ms);
  709. }
  710. void CGVisitableOPH::onHeroVisit( const CGHeroInstance * h ) const
  711. {
  712. if(visitors.find(h->id)==visitors.end())
  713. {
  714. onNAHeroVisit(h->id, false);
  715. if(ID != 102 && ID!=4 && ID!=41) //not tree nor arena nor library of enlightenment
  716. cb->setObjProperty(id,4,h->id); //add to the visitors
  717. }
  718. else
  719. {
  720. onNAHeroVisit(h->id, true);
  721. }
  722. }
  723. void CGVisitableOPH::initObj()
  724. {
  725. if(ID==102)
  726. ttype = ran()%3;
  727. else
  728. ttype = -1;
  729. }
  730. void CGVisitableOPH::treeSelected( int heroID, int resType, int resVal, int expVal, ui32 result ) const
  731. {
  732. if(result==0) //player agreed to give res for exp
  733. {
  734. cb->giveResource(cb->getOwner(heroID),resType,-resVal); //take resource
  735. cb->changePrimSkill(heroID,4,expVal); //give exp
  736. cb->setObjProperty(id,4,heroID); //add to the visitors
  737. }
  738. }
  739. void CGVisitableOPH::onNAHeroVisit(int heroID, bool alreadyVisited) const
  740. {
  741. int id=0, subid=0, ot=0, val=1;
  742. switch(ID)
  743. {
  744. case 4:
  745. ot = 0;
  746. break;
  747. case 51:
  748. subid=0;
  749. ot=80;
  750. break;
  751. case 23:
  752. subid=1;
  753. ot=39;
  754. break;
  755. case 61:
  756. subid=2;
  757. ot=100;
  758. break;
  759. case 32:
  760. subid=3;
  761. ot=59;
  762. break;
  763. case 100:
  764. id=5;
  765. ot=143;
  766. val=1000;
  767. break;
  768. case 102:
  769. id = 5;
  770. subid = 1;
  771. ot = 146;
  772. val = 1;
  773. break;
  774. case 41:
  775. ot = 66;
  776. break;
  777. }
  778. if (!alreadyVisited)
  779. {
  780. switch (ID)
  781. {
  782. case 4: //arena
  783. {
  784. SelectionDialog sd;
  785. sd.text << std::pair<ui8,ui32>(11,ot);
  786. sd.components.push_back(Component(0,0,2,0));
  787. sd.components.push_back(Component(0,1,2,0));
  788. sd.player = cb->getOwner(heroID);
  789. cb->showSelectionDialog(&sd,boost::bind(&CGVisitableOPH::arenaSelected,this,heroID,_1));
  790. return;
  791. }
  792. case 51:
  793. case 23:
  794. case 61:
  795. case 32:
  796. {
  797. cb->changePrimSkill(heroID,subid,val);
  798. InfoWindow iw;
  799. iw.components.push_back(Component(0,subid,val,0));
  800. iw.text << std::pair<ui8,ui32>(11,ot);
  801. iw.player = cb->getOwner(heroID);
  802. cb->showInfoDialog(&iw);
  803. break;
  804. }
  805. case 100: //give exp
  806. {
  807. InfoWindow iw;
  808. iw.components.push_back(Component(id,subid,val,0));
  809. iw.player = cb->getOwner(heroID);
  810. iw.text << std::pair<ui8,ui32>(11,ot);
  811. cb->showInfoDialog(&iw);
  812. cb->changePrimSkill(heroID,4,val);
  813. break;
  814. }
  815. case 102:
  816. {
  817. const CGHeroInstance *h = cb->getHero(heroID);
  818. val = VLC->heroh->reqExp(h->level+val) - VLC->heroh->reqExp(h->level);
  819. if(!ttype)
  820. {
  821. cb->setObjProperty(this->id,4,heroID); //add to the visitors
  822. InfoWindow iw;
  823. iw.components.push_back(Component(id,subid,1,0));
  824. iw.player = cb->getOwner(heroID);
  825. iw.text << std::pair<ui8,ui32>(11,148);
  826. cb->showInfoDialog(&iw);
  827. cb->changePrimSkill(heroID,4,val);
  828. break;
  829. }
  830. else
  831. {
  832. int res, resval;
  833. if(ttype==1)
  834. {
  835. res = 6;
  836. resval = 2000;
  837. ot = 149;
  838. }
  839. else
  840. {
  841. res = 5;
  842. resval = 10;
  843. ot = 151;
  844. }
  845. if(cb->getResource(h->tempOwner,res) < resval) //not enough resources
  846. {
  847. ot++;
  848. InfoWindow iw;
  849. iw.player = h->tempOwner;
  850. iw.text << std::pair<ui8,ui32>(11,ot);
  851. cb->showInfoDialog(&iw);
  852. return;
  853. }
  854. YesNoDialog sd;
  855. sd.player = cb->getOwner(heroID);
  856. sd.text << std::pair<ui8,ui32>(11,ot);
  857. sd.components.push_back(Component(id,subid,val,0));
  858. cb->showYesNoDialog(&sd,boost::bind(&CGVisitableOPH::treeSelected,this,heroID,res,resval,val,_1));
  859. }
  860. break;
  861. }
  862. case 41:
  863. {
  864. const CGHeroInstance *h = cb->getHero(heroID);
  865. if(h->level < 10 - 2*h->getSecSkillLevel(4)) //not enough level
  866. {
  867. InfoWindow iw;
  868. iw.player = cb->getOwner(heroID);
  869. iw.text << std::pair<ui8,ui32>(11,68);
  870. cb->showInfoDialog(&iw);
  871. }
  872. else
  873. {
  874. cb->setObjProperty(this->id,4,heroID); //add to the visitors
  875. cb->changePrimSkill(heroID,0,2);
  876. cb->changePrimSkill(heroID,1,2);
  877. cb->changePrimSkill(heroID,2,2);
  878. cb->changePrimSkill(heroID,3,2);
  879. InfoWindow iw;
  880. iw.player = cb->getOwner(heroID);
  881. iw.text << std::pair<ui8,ui32>(11,66);
  882. cb->showInfoDialog(&iw);
  883. }
  884. break;
  885. }
  886. }
  887. }
  888. else
  889. {
  890. ot++;
  891. InfoWindow iw;
  892. iw.player = cb->getOwner(heroID);
  893. iw.text << std::pair<ui8,ui32>(11,ot);
  894. cb->showInfoDialog(&iw);
  895. }
  896. }
  897. const std::string & CGVisitableOPH::getHoverText() const
  898. {
  899. int pom = -1;
  900. switch(ID)
  901. {
  902. case 4:
  903. pom = -1;
  904. break;
  905. case 51:
  906. pom = 8;
  907. break;
  908. case 23:
  909. pom = 7;
  910. break;
  911. case 61:
  912. pom = 11;
  913. break;
  914. case 32:
  915. pom = 4;
  916. break;
  917. case 100:
  918. pom = 5;
  919. break;
  920. case 102:
  921. pom = 18;
  922. break;
  923. case 41:
  924. break;
  925. default:
  926. throw std::string("Wrong CGVisitableOPH object ID!\n");
  927. }
  928. hoverName = VLC->generaltexth->names[ID];
  929. if(pom >= 0)
  930. hoverName += (" " + VLC->generaltexth->xtrainfo[pom]);
  931. const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
  932. if(h)
  933. {
  934. hoverName += ' ';
  935. hoverName += (vstd::contains(visitors,h->id))
  936. ? (VLC->generaltexth->allTexts[352]) //visited
  937. : ( VLC->generaltexth->allTexts[353]); //not visited
  938. }
  939. return hoverName;
  940. }
  941. void CGVisitableOPH::arenaSelected( int heroID, int primSkill ) const
  942. {
  943. cb->setObjProperty(id,4,heroID); //add to the visitors
  944. cb->changePrimSkill(heroID,primSkill,2);
  945. }
  946. bool CArmedInstance::needsLastStack() const
  947. {
  948. return false;
  949. }
  950. void CGCreature::onHeroVisit( const CGHeroInstance * h ) const
  951. {
  952. cb->startBattleI(h->id,army,pos,boost::bind(&CGCreature::endBattle,this,_1));
  953. }
  954. void CGCreature::endBattle( BattleResult *result ) const
  955. {
  956. if(result->winner==0)
  957. {
  958. cb->removeObject(id);
  959. }
  960. else
  961. {
  962. int killedAmount=0;
  963. for(std::set<std::pair<ui32,si32> >::iterator i=result->casualties[1].begin(); i!=result->casualties[1].end(); i++)
  964. if(i->first == subID)
  965. killedAmount += i->second;
  966. cb->setAmount(id, army.slots.find(0)->second.second - killedAmount);
  967. MetaString ms;
  968. int pom = CCreature::getQuantityID(army.slots.find(0)->second.second);
  969. pom = 174 + 3*pom + 1;
  970. ms << std::pair<ui8,ui32>(6,pom) << " " << std::pair<ui8,ui32>(7,subID);
  971. cb->setHoverName(id,&ms);
  972. }
  973. }
  974. void CGCreature::initObj()
  975. {
  976. army.slots[0].first = subID;
  977. si32 &amount = army.slots[0].second;
  978. CCreature &c = VLC->creh->creatures[subID];
  979. if(!amount)
  980. if(c.ammMax == c.ammMin)
  981. amount = c.ammMax;
  982. else
  983. amount = c.ammMin + (ran() % (c.ammMax - c.ammMin));
  984. MetaString ms;
  985. int pom = CCreature::getQuantityID(army.slots.find(0)->second.second);
  986. pom = 174 + 3*pom + 1;
  987. ms << std::pair<ui8,ui32>(6,pom) << " " << std::pair<ui8,ui32>(7,subID);
  988. hoverName = toString(ms);
  989. }
  990. void CGMine::onHeroVisit( const CGHeroInstance * h ) const
  991. {
  992. if(subID == 7) //TODO: support for abandoned mine
  993. return;
  994. if(h->tempOwner == tempOwner) //we're visiting our mine
  995. return; //TODO: leaving garrison
  996. //TODO: check if mine is guarded
  997. cb->setOwner(id,h->tempOwner); //not ours? flag it!
  998. MetaString ms;
  999. ms << std::pair<ui8,ui32>(9,subID) << " (" << std::pair<ui8,ui32>(6,23+h->tempOwner) << ")";
  1000. cb->setHoverName(id,&ms);
  1001. int vv=1; //amount of resource per turn
  1002. if (subID==0 || subID==2)
  1003. vv++;
  1004. else if (subID==6)
  1005. vv = 1000;
  1006. InfoWindow iw;
  1007. iw.text << std::pair<ui8,ui32>(10,subID);
  1008. iw.player = h->tempOwner;
  1009. iw.components.push_back(Component(2,subID,vv,-1));
  1010. cb->showInfoDialog(&iw);
  1011. }
  1012. void CGMine::newTurn() const
  1013. {
  1014. if (tempOwner == NEUTRAL_PLAYER)
  1015. return;
  1016. int vv = 1;
  1017. if (subID==0 || subID==2)
  1018. vv++;
  1019. else if (subID==6)
  1020. vv = 1000;
  1021. cb->giveResource(tempOwner,subID,vv);
  1022. }
  1023. void CGMine::initObj()
  1024. {
  1025. MetaString ms;
  1026. ms << std::pair<ui8,ui32>(9,subID);
  1027. if(tempOwner >= PLAYER_LIMIT)
  1028. tempOwner = NEUTRAL_PLAYER;
  1029. else
  1030. ms << " (" << std::pair<ui8,ui32>(6,23+tempOwner) << ")";
  1031. hoverName = toString(ms);
  1032. }
  1033. void CGResource::initObj()
  1034. {
  1035. blockVisit = true;
  1036. hoverName = VLC->generaltexth->restypes[subID];
  1037. if(!amount)
  1038. {
  1039. switch(subID)
  1040. {
  1041. case 6:
  1042. amount = 500 + (rand()%6)*100;
  1043. break;
  1044. case 0: case 2:
  1045. amount = 6 + (rand()%5);
  1046. break;
  1047. default:
  1048. amount = 3 + (rand()%3);
  1049. break;
  1050. }
  1051. }
  1052. }
  1053. void CGResource::onHeroVisit( const CGHeroInstance * h ) const
  1054. {
  1055. if(army.slots.size())
  1056. {
  1057. if(message.size())
  1058. {
  1059. YesNoDialog ynd;
  1060. ynd.player = h->getOwner();
  1061. ynd.text << message;
  1062. cb->showYesNoDialog(&ynd,boost::bind(&CGResource::fightForRes,this,_1,h));
  1063. }
  1064. else
  1065. {
  1066. fightForRes(0,h);
  1067. }
  1068. }
  1069. else
  1070. {
  1071. if(message.length())
  1072. {
  1073. InfoWindow iw;
  1074. iw.player = h->tempOwner;
  1075. iw.text << message;
  1076. cb->showInfoDialog(&iw);
  1077. }
  1078. collectRes(h->getOwner());
  1079. }
  1080. }
  1081. void CGResource::collectRes( int player ) const
  1082. {
  1083. cb->giveResource(player,subID,amount);
  1084. ShowInInfobox sii;
  1085. sii.player = player;
  1086. sii.c = Component(2,subID,amount,0);
  1087. sii.text << std::pair<ui8,ui32>(11,113);
  1088. sii.text.replacements.push_back(VLC->generaltexth->restypes[subID]);
  1089. cb->showCompInfo(&sii);
  1090. cb->removeObject(id);
  1091. }
  1092. void CGResource::fightForRes(ui32 refusedFight, const CGHeroInstance *h) const
  1093. {
  1094. if(refusedFight)
  1095. return;
  1096. cb->startBattleI(h->id,army,pos,boost::bind(&CGResource::endBattle,this,_1,h));
  1097. }
  1098. void CGResource::endBattle( BattleResult *result, const CGHeroInstance *h ) const
  1099. {
  1100. if(result->winner == 0) //attacker won
  1101. collectRes(h->getOwner());
  1102. }
  1103. void CGVisitableOPW::newTurn() const
  1104. {
  1105. if (cb->getDate(1)==1) //first day of week
  1106. {
  1107. cb->setObjProperty(id,5,false);
  1108. MetaString ms; //set text to "not visited"
  1109. ms << std::pair<ui8,ui32>(3,ID) << " " << std::pair<ui8,ui32>(1,353);
  1110. cb->setHoverName(id,&ms);
  1111. }
  1112. }
  1113. void CGVisitableOPW::onHeroVisit( const CGHeroInstance * h ) const
  1114. {
  1115. int mid;
  1116. switch (ID)
  1117. {
  1118. case 55:
  1119. mid = 92;
  1120. break;
  1121. case 112:
  1122. mid = 170;
  1123. break;
  1124. case 109:
  1125. mid = 164;
  1126. break;
  1127. }
  1128. if (visited)
  1129. {
  1130. if (ID!=112)
  1131. mid++;
  1132. else
  1133. mid--;
  1134. InfoWindow iw;
  1135. iw.player = h->tempOwner;
  1136. iw.text << std::pair<ui8,ui32>(11,mid);
  1137. cb->showInfoDialog(&iw);
  1138. }
  1139. else
  1140. {
  1141. int type, sub, val;
  1142. type = 2;
  1143. switch (ID)
  1144. {
  1145. case 55:
  1146. if (rand()%2)
  1147. {
  1148. sub = 5;
  1149. val = 5;
  1150. }
  1151. else
  1152. {
  1153. sub = 6;
  1154. val = 500;
  1155. }
  1156. break;
  1157. case 112:
  1158. mid = 170;
  1159. sub = (rand() % 5) + 1;
  1160. val = (rand() % 4) + 3;
  1161. break;
  1162. case 109:
  1163. mid = 164;
  1164. sub = 6;
  1165. if(cb->getDate(2)<2)
  1166. val = 500;
  1167. else
  1168. val = 1000;
  1169. }
  1170. cb->giveResource(h->tempOwner,sub,val);
  1171. InfoWindow iw;
  1172. iw.player = h->tempOwner;
  1173. iw.components.push_back(Component(type,sub,val,0));
  1174. iw.text << std::pair<ui8,ui32>(11,mid);
  1175. cb->showInfoDialog(&iw);
  1176. cb->setObjProperty(id,5,true);
  1177. MetaString ms; //set text to "visited"
  1178. ms << std::pair<ui8,ui32>(3,ID) << " " << std::pair<ui8,ui32>(1,352);
  1179. cb->setHoverName(id,&ms);
  1180. }
  1181. }
  1182. void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
  1183. {
  1184. int destinationid=-1;
  1185. switch(ID)
  1186. {
  1187. case 43: //one way - find correspong exit monolith
  1188. if(vstd::contains(objs,44) && vstd::contains(objs[44],subID) && objs[44][subID].size())
  1189. destinationid = objs[44][subID][rand()%objs[44][subID].size()];
  1190. else
  1191. tlog2 << "Cannot find corresponding exit monolith for "<< id << std::endl;
  1192. break;
  1193. case 45: //two way monolith - pick any other one
  1194. if(vstd::contains(objs,45) && vstd::contains(objs[45],subID) && objs[45][subID].size()>1)
  1195. while ((destinationid = objs[45][subID][rand()%objs[45][subID].size()])==id);
  1196. else
  1197. tlog2 << "Cannot find corresponding exit monolith for "<< id << std::endl;
  1198. break;
  1199. case 103: //find nearest subterranean gate on the other level
  1200. {
  1201. std::pair<int,double> best(-1,150000); //pair<id,dist>
  1202. for(int i=0; i<objs[103][0].size(); i++)
  1203. {
  1204. if(cb->getObj(objs[103][0][i])->pos.z == pos.z) continue; //gates on our level are not interesting
  1205. double hlp = cb->getObj(objs[103][0][i])->pos.dist2d(pos);
  1206. if(hlp<best.second)
  1207. {
  1208. best.first = objs[103][0][i];
  1209. best.second = hlp;
  1210. }
  1211. }
  1212. if(best.first<0)
  1213. return;
  1214. else
  1215. destinationid = best.first;
  1216. break;
  1217. }
  1218. }
  1219. if(destinationid < 0)
  1220. {
  1221. tlog2 << "Cannot find exit... :( \n";
  1222. return;
  1223. }
  1224. cb->moveHero(h->id,
  1225. (ID!=103)
  1226. ? (CGHeroInstance::convertPosition(cb->getObj(destinationid)->pos,true))
  1227. : (cb->getObj(destinationid)->pos),
  1228. true);
  1229. }
  1230. void CGTeleport::initObj()
  1231. {
  1232. objs[ID][subID].push_back(id);
  1233. }
  1234. void CGArtifact::initObj()
  1235. {
  1236. blockVisit = true;
  1237. if(ID == 5)
  1238. hoverName = VLC->arth->artifacts[subID].Name();
  1239. }
  1240. void CGArtifact::onHeroVisit( const CGHeroInstance * h ) const
  1241. {
  1242. cb->giveHeroArtifact(subID,h->id,-2);
  1243. cb->removeObject(id);
  1244. InfoWindow iw;
  1245. iw.player = h->tempOwner;
  1246. iw.components.push_back(Component(4,subID,0,0));
  1247. iw.text << std::pair<ui8,ui32>(12,subID);
  1248. cb->showInfoDialog(&iw);
  1249. }
  1250. void CGPickable::initObj()
  1251. {
  1252. blockVisit = true;
  1253. switch(ID)
  1254. {
  1255. case 12: //campfire
  1256. val2 = (ran()%3) + 4; //4 - 6
  1257. val1 = val2 * 100;
  1258. type = ran()%6; //given resource
  1259. break;
  1260. case 101: //treasure chest
  1261. {
  1262. int hlp = ran()%100;
  1263. if(hlp >= 95)
  1264. {
  1265. type = 1;
  1266. val1 = VLC->arth->treasures[ran()%VLC->arth->treasures.size()]->id;
  1267. return;
  1268. }
  1269. else if (hlp >= 65)
  1270. {
  1271. val1 = 2000;
  1272. }
  1273. else if(hlp >= 33)
  1274. {
  1275. val1 = 1500;
  1276. }
  1277. else
  1278. {
  1279. val1 = 1000;
  1280. }
  1281. val2 = val1 - 500;
  1282. type = 0;
  1283. break;
  1284. }
  1285. }
  1286. }
  1287. void CGPickable::onHeroVisit( const CGHeroInstance * h ) const
  1288. {
  1289. switch(ID)
  1290. {
  1291. case 12: //campfire
  1292. {
  1293. cb->giveResource(h->tempOwner,type,val2); //non-gold resource
  1294. cb->giveResource(h->tempOwner,6,val1);//gold
  1295. InfoWindow iw;
  1296. iw.player = h->tempOwner;
  1297. iw.components.push_back(Component(2,6,val1,0));
  1298. iw.components.push_back(Component(2,type,val2,0));
  1299. iw.text << std::pair<ui8,ui32>(11,23);
  1300. cb->showInfoDialog(&iw);
  1301. break;
  1302. }
  1303. case 101: //treasure chest
  1304. {
  1305. if (subID) //not OH3 treasure chest
  1306. {
  1307. tlog2 << "Not supported WoG treasure chest!\n";
  1308. return;
  1309. }
  1310. if(type) //there is an artifact
  1311. {
  1312. cb->giveHeroArtifact(val1,h->id,-2);
  1313. InfoWindow iw;
  1314. iw.player = h->tempOwner;
  1315. iw.components.push_back(Component(4,val1,1,0));
  1316. iw.text << std::pair<ui8,ui32>(11,145);
  1317. iw.text.replacements.push_back(VLC->arth->artifacts[val1].Name());
  1318. cb->showInfoDialog(&iw);
  1319. break;
  1320. }
  1321. else
  1322. {
  1323. SelectionDialog sd;
  1324. sd.player = h->tempOwner;
  1325. sd.text << std::pair<ui8,ui32>(11,146);
  1326. sd.components.push_back(Component(2,6,val1,0));
  1327. sd.components.push_back(Component(5,0,val2,0));
  1328. boost::function<void(ui32)> fun = boost::bind(&CGPickable::chosen,this,_1,h->id);
  1329. cb->showSelectionDialog(&sd,fun);
  1330. return;
  1331. }
  1332. }
  1333. }
  1334. cb->removeObject(id);
  1335. }
  1336. void CGPickable::chosen( int which, int heroID ) const
  1337. {
  1338. switch(which)
  1339. {
  1340. case 0: //player pick gold
  1341. cb->giveResource(cb->getOwner(heroID),6,val1);
  1342. break;
  1343. case 1: //player pick exp
  1344. cb->changePrimSkill(heroID, 4, val2);
  1345. break;
  1346. default:
  1347. throw std::string("Unhandled treasure choice");
  1348. }
  1349. cb->removeObject(id);
  1350. }
  1351. void CGWitchHut::initObj()
  1352. {
  1353. ability = allowedAbilities[ran()%allowedAbilities.size()];
  1354. }
  1355. void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
  1356. {
  1357. InfoWindow iw;
  1358. iw.player = h->getOwner();
  1359. if(h->getSecSkillLevel(ability)) //you alredy know this skill
  1360. {
  1361. iw.text << std::pair<ui8,ui32>(11,172);
  1362. iw.text.replacements.push_back(VLC->generaltexth->skillName[ability]);
  1363. }
  1364. else if(h->secSkills.size() >= SKILL_PER_HERO) //already all skills slots used
  1365. {
  1366. iw.text << std::pair<ui8,ui32>(11,173);
  1367. iw.text.replacements.push_back(VLC->generaltexth->skillName[ability]);
  1368. }
  1369. else //give sec skill
  1370. {
  1371. iw.components.push_back(Component(1, ability, 1, 0));
  1372. iw.text << std::pair<ui8,ui32>(11,171);
  1373. iw.text.replacements.push_back(VLC->generaltexth->skillName[ability]);
  1374. cb->changeSecSkill(h->id,ability,1,true);
  1375. }
  1376. cb->showInfoDialog(&iw);
  1377. }