OF_MONS.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  1. /*
  2. * Seven Kingdoms: Ancient Adversaries
  3. *
  4. * Copyright 1997,1998 Enlight Software Ltd.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. //Filename : OF_MONS.CPP
  21. //Description : Firm Airport
  22. #include <OINFO.h>
  23. #include <OVGA.h>
  24. #include <ODATE.h>
  25. #include <OSTR.h>
  26. #include <OSYS.h>
  27. #include <OSITE.h>
  28. #include <OFONT.h>
  29. #include <OBUTTON.h>
  30. #include <OPOWER.h>
  31. #include <OTOWN.h>
  32. #include <OU_MONS.h>
  33. #include <OGAME.h>
  34. #include <ONATION.h>
  35. #include <OMONSRES.h>
  36. #include <OF_MONS.h>
  37. //----------- Define constant ------------//
  38. #define MONSTER_SOLDIER_COMBAT_LEVEL_DIVIDER 2
  39. static char current_monster_action_mode;
  40. //--------- Begin of function FirmMonster::init_derived ---------//
  41. //
  42. void FirmMonster::init_derived()
  43. {
  44. monster_general_count = 0;
  45. // ##### patch begin Gilbert 21/1 #######//
  46. // monster_king.monster_id = 0;
  47. memset( &monster_king, 0, sizeof(monster_king) );
  48. // ##### patch end Gilbert 21/1 #######//
  49. memset( monster_general_array, 0, sizeof(monster_general_array) );
  50. waiting_soldier_count = 0;
  51. defending_king_count = 0;
  52. defending_general_count = 0;
  53. defending_soldier_count = 0;
  54. monster_nation_relation = 0;
  55. //----------------------------------------//
  56. // Set monster agressiveness. It affects:
  57. //
  58. // -the number of defenders will be called out at one time.
  59. //----------------------------------------//
  60. defend_target_recno = 0;
  61. patrol_unit_count = 0;
  62. //-- these vars must be initialized here instead of in FirmMonster::FirmMonster() for random seed sync during load game --//
  63. monster_aggressiveness = 20 + m.random(50); // 20 to 70
  64. }
  65. //----------- End of function FirmMonster::init_derived -----------//
  66. //--------- Begin of function FirmMonster::~FirmMonster ---------//
  67. //
  68. FirmMonster::~FirmMonster()
  69. {
  70. if( sys.signal_exit_flag )
  71. return;
  72. int goldAmount = 800 * (monster_res[monster_id]->level*30 + m.random(50)) / 100;
  73. site_array.add_site( center_x, center_y, SITE_GOLD_COIN, goldAmount );
  74. site_array.ai_get_site_object(); // ask AI units to get the gold coins
  75. }
  76. //----------- End of function FirmMonster::~FirmMonster -----------//
  77. //--------- Begin of function FirmMonster::deinit_derived ---------//
  78. //
  79. void FirmMonster::deinit_derived()
  80. {
  81. if( sys.signal_exit_flag )
  82. return;
  83. //-------- mobilize all monsters in the firm --------//
  84. int loopCount=0;
  85. if( monster_king.monster_id )
  86. mobilize_king();
  87. while( monster_general_count > 0 )
  88. {
  89. if(!mobilize_general(1))
  90. break;
  91. err_when( loopCount++ > 100 );
  92. }
  93. clear_defense_mode();
  94. }
  95. //----------- End of function FirmMonster::deinit_derived -----------//
  96. //------- Begin of function FirmMonster::firm_name -----------//
  97. //
  98. char* FirmMonster::firm_name()
  99. {
  100. static String str;
  101. #if(defined(SPANISH))
  102. str = "Guarida ";
  103. str += monster_res[monster_id]->name;
  104. #elif(defined(FRENCH))
  105. str = "Antre des ";
  106. str += monster_res[monster_id]->name;
  107. #else
  108. // GERMAN, US
  109. str = monster_res[monster_id]->name;
  110. str += translate.process(" Lair");
  111. #endif
  112. return str;
  113. }
  114. //--------- End of function FirmMonster::firm_name -----------//
  115. //--------- Begin of function FirmMonster::put_info ---------//
  116. //
  117. void FirmMonster::put_info(int refreshFlag)
  118. {
  119. disp_basic_info(INFO_Y1, refreshFlag);
  120. if( !config.show_ai_info && nation_recno!=nation_array.player_recno )
  121. return;
  122. disp_monster_info(INFO_Y1+54, refreshFlag);
  123. }
  124. //----------- End of function FirmMonster::put_info -----------//
  125. //--------- Begin of function FirmMonster::detect_info ---------//
  126. //
  127. void FirmMonster::detect_info()
  128. {
  129. if( detect_basic_info() )
  130. return;
  131. if( !config.show_ai_info && nation_recno!=nation_array.player_recno )
  132. return;
  133. }
  134. //----------- End of function FirmMonster::detect_info -----------//
  135. //--------- Begin of function FirmMonster::disp_monster_info ---------//
  136. //
  137. void FirmMonster::disp_monster_info(int dispY1, int refreshFlag)
  138. {
  139. return;
  140. //---------------- paint the panel --------------//
  141. if( refreshFlag == INFO_REPAINT )
  142. vga.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+22 );
  143. int x=INFO_X1+4, y=dispY1+3;
  144. }
  145. //----------- End of function FirmMonster::disp_monster_info -----------//
  146. //--------- Begin of function FirmMonster::next_day ---------//
  147. //
  148. void FirmMonster::next_day()
  149. {
  150. //-------- validate patrol unit --------//
  151. validate_patrol_unit();
  152. //---- the monster boss recruit new monsters ----//
  153. if( info.game_date%10 == firm_recno%10 )
  154. recruit_soldier();
  155. //----- monsters recover hit points -------//
  156. if( info.game_date%15 == firm_recno%15 ) // once a week
  157. recover_hit_points();
  158. //------ monster thinks about expansion -------//
  159. if( config.monster_type == OPTION_MONSTER_OFFENSIVE )
  160. {
  161. if( info.game_date%30 == firm_recno%30 && m.random(3)==0 )
  162. recruit_general();
  163. /*
  164. if( info.game_date%90 == firm_recno%90 )
  165. think_attack_neighbor();
  166. */
  167. //------ attack human towns and firms randomly -----//
  168. if( info.game_date > info.game_start_date + 1000 && // only start attacking 3 years after the game starts so the human can build up things
  169. info.game_date%30 == firm_recno%30 &&
  170. m.random( firm_res[FIRM_MONSTER]->total_firm_count*6 )==0 ) // it will expand slower when there are already a lot of the monster structures on the map
  171. {
  172. think_attack_human();
  173. }
  174. //--------- think expansion ---------//
  175. if( info.game_date%180 == firm_recno%180 &&
  176. m.random( firm_res[FIRM_MONSTER]->total_firm_count*10 )==0 ) // it will expand slower when there are already a lot of the monster structures on the map
  177. {
  178. think_expansion();
  179. }
  180. }
  181. }
  182. //----------- End of function FirmMonster::next_day -----------//
  183. //------- Begin of function FirmMonster::recover_hit_points -------//
  184. //
  185. void FirmMonster::recover_hit_points()
  186. {
  187. //------ recover the king's hit points -------//
  188. if( monster_king.hit_points < monster_king.max_hit_points )
  189. monster_king.hit_points++;
  190. //------ recover the generals' hit points -------//
  191. for( int i=0 ; i<monster_general_count ; i++ )
  192. {
  193. if( monster_general_array[i].hit_points < monster_general_array[i].max_hit_points )
  194. monster_general_array[i].hit_points++;
  195. }
  196. }
  197. //--------- End of function FirmMonster::recover_hit_points -------//
  198. //--------- Begin of function FirmMonster::assign_unit ---------//
  199. //
  200. // Mobilized defender units are assigned back to the firm.
  201. //
  202. void FirmMonster::assign_unit(int unitRecno)
  203. {
  204. Unit* unitPtr = unit_array[unitRecno];
  205. UnitInfo* unitInfo = unit_res[unitPtr->unit_id];
  206. err_when( !unitInfo->is_monster );
  207. switch( unitPtr->rank_id )
  208. {
  209. case RANK_KING:
  210. set_king(unitPtr->get_monster_id(), unitPtr->skill.combat_level);
  211. break;
  212. case RANK_GENERAL:
  213. add_general(unitRecno);
  214. break;
  215. case RANK_SOLDIER:
  216. add_soldier(unitPtr->leader_unit_recno);
  217. break;
  218. }
  219. //--------- the unit disappear in firm -----//
  220. unit_array.disappear_in_firm(unitRecno);
  221. }
  222. //----------- End of function FirmMonster::assign_unit -----------//
  223. //--------- Begin of function FirmMonster::set_king ---------//
  224. //
  225. // Set the monster king of this firm.
  226. //
  227. void FirmMonster::set_king(int monsterId, int combatLevel)
  228. {
  229. monster_king.monster_id = monsterId;
  230. monster_king.set_combat_level(combatLevel);
  231. monster_king.hit_points = monster_king.max_hit_points;
  232. }
  233. //----------- End of function FirmMonster::set_king -----------//
  234. //--------- Begin of function FirmMonster::add_general ---------//
  235. //
  236. // Add a general to the firm, this function is called when a
  237. // mobilized monster general is assigned back to the firm.
  238. //
  239. void FirmMonster::add_general(int generalUnitRecno)
  240. {
  241. if(monster_general_count>=MAX_MONSTER_GENERAL_IN_FIRM)
  242. return;
  243. Unit* unitPtr = unit_array[generalUnitRecno];
  244. UnitInfo* unitInfo = unit_res[unitPtr->unit_id];
  245. MonsterInFirm* monsterInFirm = monster_general_array+monster_general_count;
  246. monsterInFirm->monster_id = unitPtr->get_monster_id(); // contribution is used for storing the monster id. temporary
  247. monsterInFirm->set_combat_level(unitPtr->skill.combat_level);
  248. monsterInFirm->hit_points = (int) unitPtr->hit_points;
  249. if( monsterInFirm->hit_points == 0 ) // 0.? will become 0 in (float) to (int) conversion
  250. monsterInFirm->hit_points = 1;
  251. monsterInFirm->soldier_monster_id = unitPtr->get_monster_soldier_id(); // skill id is used for storing the soldier monster id temporarily
  252. monsterInFirm->soldier_count = 0;
  253. monsterInFirm->mobile_unit_recno = generalUnitRecno; // unit recno of this monster when it is a mobile unit
  254. // this is only used as a reference for soldiers to find their leaders
  255. monster_general_count++;
  256. //----- check if there are any soldiers waiting for this general ----//
  257. //
  258. // These are soldiers who follow the general to go out to defend
  259. // against the attack but then went back to the firm sooner
  260. // than the general does.
  261. //
  262. //-------------------------------------------------------------------//
  263. for( int i=0 ; i<waiting_soldier_count ; i++ )
  264. {
  265. //--- if this waiting soldier was led by this general ---//
  266. if( waiting_soldier_array[i] == generalUnitRecno )
  267. {
  268. monsterInFirm->soldier_count++;
  269. err_when( waiting_soldier_count > MAX_WAITING_SOLDIER );
  270. m.del_array_rec(waiting_soldier_array, waiting_soldier_count, sizeof(waiting_soldier_array[0]), i+1);
  271. waiting_soldier_count--;
  272. }
  273. }
  274. }
  275. //----------- End of function FirmMonster::add_general -----------//
  276. //--------- Begin of function FirmMonster::add_soldier ---------//
  277. //
  278. // <int> generalUnitRecno - the unit recno of the general leading
  279. // this soldier.
  280. //
  281. void FirmMonster::add_soldier(int generalUnitRecno)
  282. {
  283. //----- check if the soldier's leading general is here ----//
  284. for( int i=0 ; i<monster_general_count ; i++ )
  285. {
  286. if( monster_general_array[i].mobile_unit_recno == generalUnitRecno )
  287. {
  288. if(monster_general_array[i].soldier_count>=MAX_SOLDIER_PER_GENERAL)
  289. return;
  290. monster_general_array[i].soldier_count++;
  291. return;
  292. }
  293. }
  294. //---- if not, put the soldier into the waiting list ----//
  295. if( waiting_soldier_count < MAX_WAITING_SOLDIER ) // if the list is full, the unit disappear in air
  296. {
  297. waiting_soldier_array[waiting_soldier_count++] = generalUnitRecno; // the soldier is waiting for this general.
  298. }
  299. }
  300. //----------- End of function FirmMonster::add_soldier -----------//
  301. //--------- Begin of function FirmMonster::recruit_general ---------//
  302. //
  303. // Recruit general monsters.
  304. //
  305. // [int] soldierCount - the no. of soldiers to be created with this general.
  306. // (default: randomly from 1 to MAX_MONSTER_PER_GENERAL)
  307. //
  308. int FirmMonster::recruit_general(int soldierCount)
  309. {
  310. err_when( monster_general_count < 0 || monster_general_count > MAX_MONSTER_GENERAL_IN_FIRM );
  311. if( monster_general_count >= MAX_MONSTER_GENERAL_IN_FIRM * monster_aggressiveness / 100 )
  312. return 0;
  313. if( !monster_king.monster_id )
  314. return 0;
  315. //---------- recruit the general now ----------//
  316. MonsterInFirm* monsterInFirm = monster_general_array+monster_general_count;
  317. int combatLevel = 40 + m.random(30); // 40 to 70
  318. monsterInFirm->monster_id = monster_king.monster_id;
  319. monsterInFirm->set_combat_level(combatLevel);
  320. monsterInFirm->hit_points = monsterInFirm->max_hit_points;
  321. monsterInFirm->soldier_monster_id = monster_king.monster_id;
  322. if( soldierCount >= 0 )
  323. monsterInFirm->soldier_count = soldierCount;
  324. else
  325. monsterInFirm->soldier_count = m.random(MAX_SOLDIER_PER_GENERAL/2)+1;
  326. monster_general_count++;
  327. return 1;
  328. }
  329. //----------- End of function FirmMonster::recruit_general -----------//
  330. //--------- Begin of function FirmMonster::recruit_soldier ---------//
  331. //
  332. // Recruit soldier monsters.
  333. //
  334. void FirmMonster::recruit_soldier()
  335. {
  336. MonsterInFirm* monsterInFirm = monster_general_array;
  337. for( int i=0 ; i<monster_general_count ; i++, monsterInFirm++ )
  338. {
  339. if( monsterInFirm->soldier_count < MAX_SOLDIER_PER_GENERAL &&
  340. m.random(3) > 0 ) // 2/3 chance of recruiting a soldier
  341. {
  342. monsterInFirm->soldier_count++;
  343. }
  344. }
  345. }
  346. //----------- End of function FirmMonster::recruit_soldier -----------//
  347. //--------- Begin of function FirmMonster::mobilize_king ---------//
  348. //
  349. // The king himself does not lead any soldiers.
  350. //
  351. int FirmMonster::mobilize_king()
  352. {
  353. if( !mobilize_monster( monster_king.monster_id, RANK_KING, monster_king.combat_level, monster_king.hit_points ) )
  354. return 0;
  355. monster_king.monster_id = 0;
  356. return 1;
  357. }
  358. //----------- End of function FirmMonster::mobilize_king ---------//
  359. //--------- Begin of function FirmMonster::mobilize_general ---------//
  360. //
  361. // Mobilize monster generals. Soldiers need by the general is also mobilized.
  362. //
  363. // <int> generalId - id. of the general.
  364. // [int] mobilizeSoldier - whether also mobilize soldiers this general
  365. // commands. (default: 1)
  366. //
  367. // Return: <int> the no. of monsters have been mobilized.
  368. //
  369. int FirmMonster::mobilize_general(int generalId, int mobilizeSoldier)
  370. {
  371. err_when( generalId < 1 || generalId > monster_general_count );
  372. MonsterInFirm* monsterInFirm = monster_general_array + generalId - 1;
  373. //------ mobilize the monster general ------//
  374. int generalUnitRecno = mobilize_monster( monsterInFirm->monster_id, RANK_GENERAL, monsterInFirm->combat_level, monsterInFirm->hit_points );
  375. if( !generalUnitRecno )
  376. return 0;
  377. unit_array[generalUnitRecno]->set_monster_soldier_id(monsterInFirm->soldier_monster_id);
  378. int mobilizedCount = 1;
  379. patrol_unit_array[0] = generalUnitRecno;
  380. patrol_unit_count = 1;
  381. //------ mobilize soldiers commanded by the monster general ------//
  382. if( mobilizeSoldier )
  383. {
  384. for( int i=0 ; i<monsterInFirm->soldier_count ; i++ )
  385. {
  386. //--- the combat level of its soldiers ranges from 25% to 50% of the combat level of the general ---//
  387. int soldierCombatLevel = monsterInFirm->combat_level/MONSTER_SOLDIER_COMBAT_LEVEL_DIVIDER + m.random(monsterInFirm->combat_level/MONSTER_SOLDIER_COMBAT_LEVEL_DIVIDER);
  388. int unitRecno = mobilize_monster( monsterInFirm->soldier_monster_id, RANK_SOLDIER, soldierCombatLevel );
  389. if( unitRecno )
  390. {
  391. unit_array[unitRecno]->leader_unit_recno = generalUnitRecno;
  392. mobilizedCount++;
  393. patrol_unit_array[patrol_unit_count++] = unitRecno;
  394. if(patrol_unit_count==MAX_SOLDIER_PER_GENERAL+1)
  395. break;
  396. }
  397. else
  398. break; // no space for init_sprite
  399. }
  400. }
  401. //---- delete the monster general record from the array ----//
  402. err_when( monster_general_count > MAX_MONSTER_GENERAL_IN_FIRM );
  403. m.del_array_rec(monster_general_array, monster_general_count, sizeof(MonsterInFirm), generalId);
  404. monster_general_count--;
  405. return mobilizedCount;
  406. }
  407. //----------- End of function FirmMonster::mobilize_general ---------//
  408. //--------- Begin of function FirmMonster::mobilize_monster ---------//
  409. //
  410. // <int> monsterId = id. of the monster to be mobilized
  411. // <int> rankId = rank id. of the monster.
  412. // <int> combatLevel = the combat level of the monster
  413. // [int] hitPoints = set the hit points of the monster to this
  414. // (default: hit points of the monster is set to the max hit points when it is first created.)
  415. //
  416. // return: <int> the unit recno of the mobile unit created.
  417. //
  418. int FirmMonster::mobilize_monster(int monsterId, int rankId, int combatLevel, int hitPoints)
  419. {
  420. MonsterInfo* monsterInfo = monster_res[monsterId];
  421. UnitInfo* unitInfo = unit_res[monsterInfo->unit_id];
  422. //------- locate a space first --------//
  423. int xLoc=center_x, yLoc=center_y;
  424. SpriteInfo* spriteInfo = sprite_res[unitInfo->sprite_id];
  425. if( !world.locate_space( xLoc, yLoc, xLoc, yLoc, spriteInfo->loc_width, spriteInfo->loc_height, unitInfo->mobile_type ) )
  426. return 0;
  427. //---------- add the unit now -----------//
  428. int unitRecno = unit_array.add_unit( unitInfo->unit_id, 0,
  429. rankId, 0, xLoc, yLoc );
  430. UnitMonster* monsterPtr = (UnitMonster*) unit_array[unitRecno];
  431. monsterPtr->set_mode(UNIT_MODE_MONSTER, firm_recno);
  432. monsterPtr->set_combat_level(combatLevel);
  433. monsterPtr->set_monster_id(monsterId);
  434. monsterPtr->set_monster_action_mode(current_monster_action_mode);
  435. if( hitPoints )
  436. {
  437. monsterPtr->hit_points = (float) hitPoints;
  438. err_when( hitPoints > monsterPtr->max_hit_points );
  439. }
  440. else
  441. monsterPtr->hit_points = monsterPtr->max_hit_points;
  442. //-----------------------------------------------------//
  443. // enable unit defend mode
  444. //-----------------------------------------------------//
  445. if(firm_recno) // 0 when firm is ready to be deleted
  446. {
  447. monsterPtr->stop2();
  448. monsterPtr->action_mode2 = ACTION_MONSTER_DEFEND_DETECT_TARGET;
  449. monsterPtr->action_para2 = MONSTER_DEFEND_DETECT_COUNT;
  450. monsterPtr->action_misc = ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO;
  451. monsterPtr->action_misc_para = firm_recno;
  452. }
  453. return unitRecno;
  454. }
  455. //----------- End of function FirmMonster::mobilize_monster -----------//
  456. //--------- Begin of function FirmMonster::being_attacked ---------//
  457. //
  458. // This function is called by Unit::hit_firm()
  459. //
  460. // <int> attackerUnitRecno - recno of the unit attacking this firm.
  461. //
  462. void FirmMonster::being_attacked(int attackerUnitRecno)
  463. {
  464. int attackerNationRecno = unit_array[attackerUnitRecno]->nation_recno;
  465. //--- increase reputation of the nation that attacks monsters ---//
  466. if( attackerNationRecno )
  467. {
  468. nation_array[attackerNationRecno]->change_reputation(REPUTATION_INCREASE_PER_ATTACK_MONSTER);
  469. set_hostile_nation(attackerNationRecno); // also set hostile with the nation
  470. }
  471. //------ max no. of defender it should call out -----//
  472. int maxDefender = MAX_MONSTER_IN_FIRM * monster_aggressiveness / 200;
  473. if( total_defender() >= maxDefender ) // only mobilize new ones when the max defender no. has been reached yet
  474. return;
  475. current_monster_action_mode = MONSTER_ACTION_DEFENSE;
  476. //---- mobilize monster general to defend against the attack ----//
  477. if( monster_general_count > 0 )
  478. {
  479. int mobilizedCount = mobilize_general( m.random(monster_general_count)+1 );
  480. if(mobilizedCount)
  481. {
  482. defending_general_count++;
  483. defending_soldier_count += mobilizedCount-1;
  484. }
  485. }
  486. else if( monster_king.monster_id )
  487. {
  488. if( mobilize_king() )
  489. defending_king_count++;
  490. }
  491. defend_target_recno = attackerUnitRecno;
  492. }
  493. //----------- End of function FirmMonster::being_attacked -----------//
  494. //-------- Begin of function FirmMonster::clear_defense_mode -------//
  495. //
  496. // This function is called when the firm monster is destroyed.
  497. //
  498. void FirmMonster::clear_defense_mode()
  499. {
  500. //------------------------------------------------------------------//
  501. // change defense unit's to non-defense mode
  502. //------------------------------------------------------------------//
  503. Unit *unitPtr;
  504. for(int i=unit_array.size(); i>=1; --i)
  505. {
  506. if(unit_array.is_deleted(i))
  507. continue;
  508. unitPtr = unit_array[i];
  509. //------ reset the monster's defense mode -----//
  510. if(unitPtr->in_monster_defend_mode() && unitPtr->action_misc==ACTION_MISC_MONSTER_DEFEND_FIRM_RECNO &&
  511. unitPtr->action_misc_para==firm_recno)
  512. {
  513. unitPtr->clear_monster_defend_mode();
  514. ((UnitMonster*)unitPtr)->set_monster_action_mode(MONSTER_ACTION_STOP);
  515. }
  516. //--- if this unit belongs to this firm, reset its association with this firm ---//
  517. if( unitPtr->unit_mode == UNIT_MODE_MONSTER &&
  518. unitPtr->unit_mode_para == firm_recno )
  519. {
  520. unitPtr->unit_mode_para = 0;
  521. }
  522. }
  523. }
  524. //----------- End of function FirmMonster::clear_defense_mode -----------//
  525. //-------- Begin of function FirmMonster::reduce_defender_count -------//
  526. //
  527. // A defender unit moves back into the firm, reducing the defender count.
  528. //
  529. // <int> rankId - rank id. of the defender unit
  530. //
  531. void FirmMonster::reduce_defender_count(int rankId)
  532. {
  533. switch(rankId)
  534. {
  535. case RANK_KING:
  536. defending_king_count--;
  537. if( defending_king_count < 0 ) //**BUGHERE
  538. defending_king_count = 0;
  539. err_when( defending_king_count < 0 );
  540. break;
  541. case RANK_GENERAL:
  542. defending_general_count--;
  543. if( defending_general_count < 0 ) //**BUGHERE
  544. defending_general_count = 0;
  545. err_when( defending_general_count < 0 );
  546. break;
  547. case RANK_SOLDIER:
  548. defending_soldier_count--;
  549. if( defending_soldier_count < 0 ) //**BUGHERE
  550. defending_soldier_count = 0;
  551. err_when( defending_soldier_count < 0 );
  552. break;
  553. }
  554. if( total_defender()==0 )
  555. monster_nation_relation = 0;
  556. }
  557. //------ End of function FirmMonster::reduce_defender_count ---------//
  558. //-------- Begin of function MonsterInFirm::set_combat_level -------//
  559. void MonsterInFirm::set_combat_level(int combatLevel)
  560. {
  561. UnitInfo* unitInfo = unit_res[monster_res[monster_id]->unit_id];
  562. combat_level = combatLevel;
  563. max_hit_points = (int) unitInfo->hit_points * combatLevel / 100;
  564. }
  565. //--------- End of function MonsterInFirm::set_combat_level --------//
  566. //-------- Begin of function FirmMonster::total_combat_level -------//
  567. //
  568. int FirmMonster::total_combat_level()
  569. {
  570. MonsterInFirm* monsterInFirm = monster_general_array;
  571. int totalCombatLevel=50; // for the structure
  572. for( int i=0 ; i<monster_general_count ; i++, monsterInFirm++ )
  573. {
  574. totalCombatLevel += monsterInFirm->hit_points +
  575. (monsterInFirm->combat_level * 2 / MONSTER_SOLDIER_COMBAT_LEVEL_DIVIDER) // *2 because total_combat_level() actually takes hit_points instead of combat_level
  576. * 3 / 2 * monsterInFirm->soldier_count; // *3/2 because the function use 100% + random(100%) for the combat level, so we take 150% as the average
  577. }
  578. return totalCombatLevel;
  579. }
  580. //------ End of function FirmMonster::total_combat_level ---------//
  581. //-------- Begin of function FirmMonster::can_assign_monster -------//
  582. //
  583. // Return whether the given monster can be assigned to this firm.
  584. //
  585. // It checks if the type of the monster and the type of the monster
  586. // structure are compatible.
  587. //
  588. int FirmMonster::can_assign_monster(int unitRecno)
  589. {
  590. Unit* unitPtr = unit_array[unitRecno];
  591. int monsterId = unitPtr->get_monster_id();
  592. return strcmp( firm_res.get_build(firm_build_id)->build_code, // can assign if the build code are the same
  593. monster_res[monsterId]->firm_build_code ) == 0;
  594. }
  595. //------ End of function FirmMonster::can_assign_monster ---------//
  596. //-------- Begin of function FirmMonster::set_hostile_nation -------//
  597. void FirmMonster::set_hostile_nation(int nationRecno)
  598. {
  599. if(nationRecno==0)
  600. return;
  601. err_when(nationRecno>7); // only 8 bits
  602. monster_nation_relation |= (0x1 << nationRecno);
  603. }
  604. //------ End of function FirmMonster::set_hostile_nation ---------//
  605. //-------- Begin of function FirmMonster::reset_hostile_nation -------//
  606. void FirmMonster::reset_hostile_nation(int nationRecno)
  607. {
  608. if(nationRecno==0)
  609. return;
  610. err_when(nationRecno>7); // only 8 bits
  611. monster_nation_relation &= ~(0x1 << nationRecno);
  612. }
  613. //------ End of function FirmMonster::reset_hostile_nation ---------//
  614. //-------- Begin of function FirmMonster::is_hostile_nation -------//
  615. // return 1 for hostile nation
  616. // return 0 otherwise
  617. //
  618. int FirmMonster::is_hostile_nation(int nationRecno)
  619. {
  620. if(nationRecno==0)
  621. return 0;
  622. err_when(nationRecno>7); // only 8 bits
  623. return (monster_nation_relation & (0x1 << nationRecno));
  624. }
  625. //------ End of function FirmMonster::is_hostile_nation ---------//
  626. //------- Begin of function FirmMonster::validate_patrol_unit ---------//
  627. //
  628. void FirmMonster::validate_patrol_unit()
  629. {
  630. if(patrol_unit_count<=0)
  631. return;
  632. int unitRecno;
  633. Unit* unitPtr;
  634. for( int i=patrol_unit_count ; i>0 ; i-- )
  635. {
  636. unitRecno = patrol_unit_array[i-1];
  637. if( unit_array.is_deleted(unitRecno) ||
  638. (unitPtr=unit_array[unitRecno])->is_visible()==0 )
  639. {
  640. err_when( patrol_unit_count > MAX_SOLDIER_PER_GENERAL+1 );
  641. m.del_array_rec( patrol_unit_array, patrol_unit_count, sizeof(patrol_unit_array[0]), i );
  642. err_when( patrol_unit_count==0 ); // it's already 0
  643. patrol_unit_count--;
  644. }
  645. }
  646. err_when(patrol_unit_count<0);
  647. if(patrol_unit_count==0 && total_defender()==0)
  648. monster_nation_relation = 0;
  649. else if(patrol_unit_count<0)
  650. patrol_unit_count = 0;
  651. }
  652. //-------- End of function FirmMonster::validate_patrol_unit ---------//
  653. //------- Begin of function FirmMonster::think_attack_neighbor -------//
  654. //
  655. int FirmMonster::think_attack_neighbor()
  656. {
  657. //-- don't attack new target if some mobile monsters are already attacking somebody --//
  658. if( patrol_unit_count > 0 )
  659. return 0;
  660. //-------- only attack if we have enough generals ---------//
  661. int generalCount=0;
  662. MonsterInFirm* monsterInFirm = monster_general_array;
  663. int totalCombatLevel=0;
  664. //--- count the number of generals commanding at least 5 soldiers ---//
  665. int i;
  666. for( i=0 ; i<monster_general_count ; i++, monsterInFirm++ )
  667. {
  668. if( monsterInFirm->soldier_count >= 5 )
  669. generalCount++;
  670. }
  671. if( generalCount<=1 ) // don't attack if there is only one general in the firm
  672. return 0;
  673. //------ look for neighbors to attack ------//
  674. int xOffset, yOffset;
  675. int xLoc, yLoc;
  676. int attackFlag=0;
  677. FirmInfo* firmInfo = firm_res[firm_id];
  678. Location* locPtr;
  679. int scanLocWidth = MONSTER_ATTACK_NEIGHBOR_RANGE*2;
  680. int scanLocHeight = MONSTER_ATTACK_NEIGHBOR_RANGE*2;
  681. int scanLimit = scanLocWidth * scanLocHeight;
  682. short targetNation;
  683. for(i=firmInfo->loc_width*firmInfo->loc_height+1; i<=scanLimit; i++)
  684. {
  685. m.cal_move_around_a_point(i, scanLocWidth, scanLocHeight, xOffset, yOffset);
  686. xLoc = center_x + xOffset;
  687. yLoc = center_y + yOffset;
  688. xLoc = max(0, xLoc);
  689. xLoc = min(MAX_WORLD_X_LOC-1, xLoc);
  690. yLoc = max(0, yLoc);
  691. yLoc = min(MAX_WORLD_Y_LOC-1, yLoc);
  692. locPtr = world.get_loc(xLoc, yLoc);
  693. if(locPtr->is_firm())
  694. {
  695. Firm *firmPtr = firm_array[locPtr->firm_recno()];
  696. if(firmPtr->nation_recno)
  697. {
  698. targetNation = firmPtr->nation_recno;
  699. attackFlag = 1;
  700. xLoc = firmPtr->loc_x1;
  701. yLoc = firmPtr->loc_y1;
  702. break;
  703. }
  704. }
  705. else if(locPtr->is_town())
  706. {
  707. Town *townPtr = town_array[locPtr->town_recno()];
  708. if(townPtr->nation_recno)
  709. {
  710. targetNation = townPtr->nation_recno;
  711. attackFlag = 1;
  712. xLoc = townPtr->loc_x1;
  713. yLoc = townPtr->loc_y1;
  714. break;
  715. }
  716. }
  717. }
  718. if( !attackFlag )
  719. return 0;
  720. //------- attack the civilian now --------//
  721. current_monster_action_mode = MONSTER_ACTION_ATTACK;
  722. mobilize_general( m.random(monster_general_count)+1 );
  723. if( patrol_unit_count > 0 )
  724. {
  725. //### begin alex 16/9 ###//
  726. set_hostile_nation(targetNation);
  727. //#### end alex 16/9 ####//
  728. // ##### patch begin Gilbert 5/8 #######//
  729. unit_array.attack(xLoc, yLoc, 0, patrol_unit_array, patrol_unit_count, COMMAND_AI, 0);
  730. // ##### patch end Gilbert 5/8 #######//
  731. return 1;
  732. }
  733. else
  734. return 0;
  735. }
  736. //-------- End of function FirmMonster::think_attack_neighbor -------//
  737. //-------- Begin of function FirmMonster::think_expansion -------//
  738. //
  739. int FirmMonster::think_expansion()
  740. {
  741. #define MIN_GENERAL_EXPAND_NUM 3
  742. if(patrol_unit_count>0)
  743. return 0;
  744. if(!monster_king.monster_id || monster_general_count<MIN_GENERAL_EXPAND_NUM)
  745. return 0;
  746. //--- count the number of generals commanding 8 soldiers ----//
  747. int generalCount=0;
  748. MonsterInFirm* monsterInFirm = monster_general_array;
  749. for( int i=0 ; i<monster_general_count ; i++, monsterInFirm++ )
  750. {
  751. if( monsterInFirm->soldier_count == MAX_SOLDIER_PER_GENERAL )
  752. generalCount++;
  753. }
  754. if( generalCount < MIN_GENERAL_EXPAND_NUM ) // don't expand if the no. of generals is less than 3
  755. return 0;
  756. //------------- locate space to build monster firm randomly -------------//
  757. #define EXPAND_FIRM_DISTANCE 30
  758. #define FREE_SPACE_DISTANCE 3
  759. MonsterInfo* monsterInfo = monster_res[monster_king.monster_id];
  760. FirmInfo* firmInfo = firm_res[FIRM_MONSTER];
  761. char teraMask = UnitRes::mobile_type_to_mask(UNIT_LAND);
  762. int xLoc1 = max(0, loc_x1-EXPAND_FIRM_DISTANCE);
  763. int yLoc1 = max(0, loc_y1-EXPAND_FIRM_DISTANCE);
  764. int xLoc2 = min(MAX_WORLD_X_LOC-1, loc_x2+EXPAND_FIRM_DISTANCE);
  765. int yLoc2 = min(MAX_WORLD_Y_LOC-1, loc_y2+EXPAND_FIRM_DISTANCE);
  766. if( !world.locate_space_random(xLoc1, yLoc1, xLoc2, yLoc2,
  767. firmInfo->loc_width+FREE_SPACE_DISTANCE*2,
  768. firmInfo->loc_height+FREE_SPACE_DISTANCE*2, // leave at least 3 location space around the building
  769. (xLoc2-xLoc1+1)*(yLoc2-yLoc1+1), 0, 1, teraMask) )
  770. {
  771. return 0;
  772. }
  773. monster_general_count--;
  774. //monsterInFirm = monster_general_array + monster_general_count;
  775. //unit_array.disappear_in_firm(monsterInFirm->mobile_unit_recno);
  776. return monsterInfo->build_firm_monster(xLoc1+FREE_SPACE_DISTANCE, yLoc1+FREE_SPACE_DISTANCE, 1); //1-full hit points
  777. }
  778. //------ End of function FirmMonster::think_expansion ---------//
  779. //------- Begin of function FirmMonster::think_attack_human -------//
  780. //
  781. int FirmMonster::think_attack_human()
  782. {
  783. //-- don't attack new target if some mobile monsters are already attacking somebody --//
  784. if( patrol_unit_count > 0 )
  785. return 0;
  786. //-------- only attack if we have enough generals ---------//
  787. int generalCount=0;
  788. MonsterInFirm* monsterInFirm = monster_general_array;
  789. int totalCombatLevel=0;
  790. //--- count the number of generals commanding at least 5 soldiers ---//
  791. int i;
  792. for( i=0 ; i<monster_general_count ; i++, monsterInFirm++ )
  793. {
  794. if( monsterInFirm->soldier_count >= 5 )
  795. generalCount++;
  796. }
  797. if( generalCount<=1 ) // don't attack if there is only one general in the firm
  798. return 0;
  799. //------ look for neighbors to attack ------//
  800. int firmRecno, townRecno;
  801. int targetXLoc= -1, targetYLoc, targetNationRecno=0;
  802. Firm* firmPtr;
  803. Town* townPtr;
  804. for(i=1 ; i<100 ; i++ )
  805. {
  806. //----- randomly pick a firm ------//
  807. firmRecno = m.random(firm_array.size()) + 1;
  808. if( firm_array.is_deleted(firmRecno) )
  809. continue;
  810. firmPtr = firm_array[firmRecno];
  811. if( firmPtr->region_id == region_id )
  812. {
  813. targetXLoc = firmPtr->loc_x1;
  814. targetYLoc = firmPtr->loc_y1;
  815. targetNationRecno = firmPtr->nation_recno;
  816. break;
  817. }
  818. //----- randomly pick a town ------//
  819. townRecno = m.random(town_array.size()) + 1;
  820. if( town_array.is_deleted(townRecno) )
  821. continue;
  822. townPtr = town_array[townRecno];
  823. if( townPtr->nation_recno && townPtr->region_id == region_id )
  824. {
  825. targetXLoc = townPtr->loc_x1;
  826. targetYLoc = townPtr->loc_y1;
  827. targetNationRecno = townPtr->nation_recno;
  828. break;
  829. }
  830. }
  831. if( targetXLoc == -1 ) // no target selected
  832. return 0;
  833. //------- attack the civilian now --------//
  834. current_monster_action_mode = MONSTER_ACTION_ATTACK;
  835. mobilize_general( m.random(monster_general_count)+1 );
  836. if( patrol_unit_count > 0 )
  837. {
  838. set_hostile_nation(targetNationRecno);
  839. // ##### patch begin Gilbert 5/8 #######//
  840. unit_array.attack(targetXLoc, targetYLoc, 0, patrol_unit_array, patrol_unit_count, COMMAND_AI, 0);
  841. // ##### patch end Gilbert 5/8 #######//
  842. return 1;
  843. }
  844. else
  845. return 0;
  846. }
  847. //-------- End of function FirmMonster::think_attack_human -------//