OUNITAT.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428
  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 : OUNITAT.CPP
  21. //Description : Object Unit attack supporting functions
  22. //Owner : Alex
  23. #include <ALL.h>
  24. #include <ONEWS.h>
  25. #include <OWORLD.h>
  26. #include <ONATION.h>
  27. #include <OU_MARI.h>
  28. #include <OSPY.h>
  29. #include <OGAME.h>
  30. #include <OTOWN.h>
  31. #include <OF_CAMP.h>
  32. #include <OF_MONS.h>
  33. #include <OEFFECT.h>
  34. #include <OMONSRES.h>
  35. #include <OREBEL.h>
  36. #include <OSERES.h>
  37. #include <OSYS.h>
  38. #include <OWARPT.h>
  39. #ifdef NO_DEBUG_UNIT
  40. #undef err_when
  41. #undef err_here
  42. #undef err_if
  43. #undef err_else
  44. #undef err_now
  45. #define err_when(cond)
  46. #define err_here()
  47. #define err_if(cond)
  48. #define err_else
  49. #define err_now(msg)
  50. #undef DEBUG
  51. #endif
  52. //----------------- Begin of function Unit::update_attack_path_dist -----------------//
  53. // return 1 if it is time to update result path
  54. // return 0 otherwise
  55. //
  56. int Unit::update_attack_path_dist()
  57. {
  58. if(result_path_dist<=6) //1-6
  59. {
  60. return 1;
  61. }
  62. else if(result_path_dist<=10) // 8, 10
  63. {
  64. return !((result_path_dist-6)%2);
  65. }
  66. else if(result_path_dist<=20) // 15, 20
  67. {
  68. return !((result_path_dist-10)%5);
  69. }
  70. else if(result_path_dist<=60) // 28, 36, 44, 52, 60
  71. {
  72. return !((result_path_dist-20)%8);
  73. }
  74. else if(result_path_dist<=90) // 75, 90
  75. {
  76. return !((result_path_dist-60)%15);
  77. }
  78. else // 110, 130, 150, etc
  79. {
  80. return !((result_path_dist-90)%20);
  81. }
  82. err_here();
  83. return 0;
  84. }
  85. //---------- End of function Unit::update_attack_path_dist ----------//
  86. //##### begin trevor 15/8 #######//
  87. //----------------- Begin of function Unit::hit_target -----------------//
  88. // The function can be called in by class Bullet since parent and target
  89. // are specified.
  90. //
  91. // [Unit*] parentUnit is the unit attacking
  92. // [Unit*] taregtUnit is the unit being attacked
  93. // <int> attackDamage is the damage done to the target Unit
  94. //
  95. // ****************************** Warning ***********************************
  96. // don't use any member variables of this unit. This unit may not be involved
  97. // in the attack event
  98. // **************************************************************************
  99. //
  100. void Unit::hit_target(Unit* parentUnit, Unit* targetUnit, float attackDamage)
  101. {
  102. short parentNationRecno = (parentUnit) ? parentUnit->nation_recno : 0;
  103. short targetNationRecno = targetUnit->nation_recno;
  104. //------------------------------------------------------------//
  105. // if the attacked unit is in defense mode, order other available
  106. // unit in the same camp to help this unit
  107. // Note : checking for nation_recno since one unit can attack units
  108. // in same nation by bullet accidentally
  109. //------------------------------------------------------------//
  110. if(parentUnit && parentUnit->cur_action!=SPRITE_DIE && parentUnit->is_visible() &&
  111. parentNationRecno!=targetNationRecno && parentUnit->nation_can_attack(targetNationRecno) &&
  112. targetUnit->in_auto_defense_mode())
  113. {
  114. err_when(targetUnit->action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO || !targetUnit->action_misc_para);
  115. if(!firm_array.is_deleted(targetUnit->action_misc_para))
  116. {
  117. Firm *firmPtr = firm_array[targetUnit->action_misc_para];
  118. if(firmPtr->firm_id==FIRM_CAMP)
  119. {
  120. err_when(firmPtr->firm_id!=FIRM_CAMP);
  121. FirmCamp *campPtr = firmPtr->cast_to_FirmCamp();
  122. campPtr->defense(parentUnit->sprite_recno);
  123. }
  124. }
  125. else
  126. targetUnit->clear_unit_defense_mode();
  127. }
  128. // ---------- add indicator on the map ----------//
  129. if( nation_array.player_recno && targetUnit->is_own() )
  130. war_point_array.add_point(targetUnit->next_x_loc(),targetUnit->next_y_loc());
  131. //-----------------------------------------------------------------------//
  132. // decrease the hit points of the target Unit
  133. //-----------------------------------------------------------------------//
  134. #define DEFAULT_ARMOR 4
  135. #define DEFAULT_ARMOR_OVER_ATTACK_SLOW_DOWN (float) DEFAULT_ARMOR / ATTACK_SLOW_DOWN
  136. #define ONE_OVER_ATTACK_SLOW_DOWN (float) 1/ATTACK_SLOW_DOWN
  137. #define COMPARE_POINT DEFAULT_ARMOR_OVER_ATTACK_SLOW_DOWN + ONE_OVER_ATTACK_SLOW_DOWN
  138. //-*********** simulate aat ************-//
  139. #ifdef DEBUG
  140. if(!debug_sim_game_type)
  141. {
  142. #endif
  143. if( attackDamage >= COMPARE_POINT )
  144. targetUnit->hit_points -= attackDamage - DEFAULT_ARMOR_OVER_ATTACK_SLOW_DOWN;
  145. else
  146. targetUnit->hit_points -= min(attackDamage,ONE_OVER_ATTACK_SLOW_DOWN); // in case attackDamage = 0, no hit_point is reduced
  147. #ifdef DEBUG
  148. }
  149. #endif
  150. //-*********** simulate aat ************-//
  151. Nation *parentNationPtr = parentNationRecno ? nation_array[parentNationRecno] : NULL;
  152. Nation *targetNationPtr = targetNationRecno ? nation_array[targetNationRecno] : NULL;
  153. char targetUnitClass = unit_res[targetUnit->unit_id]->unit_class;
  154. if( targetUnit->hit_points <= 0 )
  155. {
  156. targetUnit->hit_points = (float) 0;
  157. //---- if the unit killed is a human unit -----//
  158. if( targetUnit->race_id )
  159. {
  160. //---- if the unit killed is a civilian unit -----//
  161. if( targetUnit->is_civilian() )
  162. {
  163. if( targetNationRecno )
  164. {
  165. targetNationPtr->civilian_killed(targetUnit->race_id, 0);
  166. targetNationPtr->own_civilian_killed++;
  167. }
  168. if(parentUnit && parentNationRecno )
  169. {
  170. parentNationPtr->civilian_killed(targetUnit->race_id, 1);
  171. parentNationPtr->enemy_civilian_killed++;
  172. }
  173. }
  174. else //---- if the unit killed is a soldier -----//
  175. {
  176. if( targetNationRecno )
  177. targetNationPtr->own_soldier_killed++;
  178. if(parentUnit && parentNationRecno )
  179. parentNationPtr->enemy_soldier_killed++;
  180. }
  181. }
  182. //--------- if it's a non-human unit ---------//
  183. else
  184. {
  185. switch( unit_res[targetUnit->unit_id]->unit_class )
  186. {
  187. case UNIT_CLASS_WEAPON:
  188. if(parentUnit && parentNationRecno )
  189. parentNationPtr->enemy_weapon_destroyed++;
  190. if( targetNationRecno )
  191. targetNationPtr->own_weapon_destroyed++;
  192. break;
  193. case UNIT_CLASS_SHIP:
  194. if(parentUnit && parentNationRecno )
  195. parentNationPtr->enemy_ship_destroyed++;
  196. if( targetNationRecno )
  197. targetNationPtr->own_ship_destroyed++;
  198. break;
  199. }
  200. //---- if the unit destroyed is a trader or caravan -----//
  201. if( targetUnit->unit_id == UNIT_CARAVAN || // whoever kills a caravan decrease, who will be resented by all races
  202. targetUnit->unit_id == UNIT_VESSEL )
  203. {
  204. if( targetNationRecno )
  205. targetNationPtr->civilian_killed(0, 0); // 0-for all races
  206. if(parentUnit && parentNationRecno )
  207. parentNationPtr->civilian_killed(0, 1); // 1-is the nation is the attacking one
  208. }
  209. }
  210. return;
  211. }
  212. if(parentUnit!=NULL && parentNationRecno!=targetNationRecno)
  213. parentUnit->gain_experience(); // gain experience to increase combat level
  214. //-----------------------------------------------------------------------//
  215. // action of the target to take
  216. //-----------------------------------------------------------------------//
  217. if( !parentUnit ) // do nothing if parent is dead
  218. return;
  219. if( parentUnit->cur_action==SPRITE_DIE ) // skip for explosive cart
  220. {
  221. err_when(parentUnit->unit_id!=UNIT_EXPLOSIVE_CART);
  222. return;
  223. }
  224. if( targetNationRecno == parentNationRecno ) // the target and the attacker's nations are different (it's possible that when a unit who has just changed nation has its bullet hitting its own nation)
  225. return;
  226. //------- two nations at war ---------//
  227. if( parentNationRecno && targetNationRecno )
  228. {
  229. parentNationPtr->set_at_war_today();
  230. targetNationPtr->set_at_war_today(parentUnit->sprite_recno);
  231. }
  232. //-------- increase battling fryhtan score --------//
  233. if( targetUnitClass==UNIT_CLASS_MONSTER && parentNationRecno )
  234. {
  235. parentNationPtr->kill_monster_score += (float) 0.1;
  236. }
  237. //------ call target unit being attack functions -------//
  238. if( targetNationRecno )
  239. {
  240. targetNationPtr->being_attacked(parentNationRecno);
  241. if( targetUnit->ai_unit )
  242. {
  243. if( targetUnit->rank_id >= RANK_GENERAL )
  244. targetUnit->ai_leader_being_attacked(parentUnit->sprite_recno);
  245. if( unit_res[targetUnit->unit_id]->unit_class == UNIT_CLASS_SHIP )
  246. ((UnitMarine*)targetUnit)->ai_ship_being_attacked(parentUnit->sprite_recno);
  247. }
  248. //--- if a member in a troop is under attack, ask for other troop members to help ---//
  249. if( info.game_date%2 == sprite_recno%2 )
  250. {
  251. if( targetUnit->leader_unit_recno ||
  252. (targetUnit->team_info && targetUnit->team_info->member_count > 1) )
  253. {
  254. if( !unit_array.is_deleted(parentUnit->sprite_recno) ) // it is possible that parentUnit is dying right now
  255. {
  256. targetUnit->ask_team_help_attack(parentUnit);
  257. }
  258. }
  259. }
  260. }
  261. //--- increase reputation of the nation that attacks monsters ---//
  262. else if( targetUnitClass == UNIT_CLASS_MONSTER )
  263. {
  264. if( parentNationRecno )
  265. parentNationPtr->change_reputation(REPUTATION_INCREASE_PER_ATTACK_MONSTER);
  266. }
  267. //------------------------------------------//
  268. if(!targetUnit->can_attack()) // no action if the target unit is unable to attack
  269. return;
  270. err_when(!targetUnit->can_attack());
  271. targetUnit->unit_auto_guarding(parentUnit);
  272. }
  273. //---------- End of function Unit::hit_target ----------//
  274. //##### end trevor 15/8 #######//
  275. //----------- Begin of function Unit::unit_auto_guarding ---------------//
  276. // the unit attacks the unit attacking it
  277. //
  278. // <Unit*> attackUnit - the unit attacking this unit
  279. //
  280. void Unit::unit_auto_guarding(Unit *attackUnit)
  281. {
  282. if( force_move_flag )
  283. return;
  284. //##### begin trevor 9/10 ########//
  285. //---------------------------------------//
  286. //
  287. // If the aggressive_mode is off, then don't
  288. // fight back when the unit is moving, only
  289. // fight back when the unit is already fighting
  290. // or is idle.
  291. //
  292. //---------------------------------------//
  293. if( !aggressive_mode && cur_action != SPRITE_ATTACK &&
  294. cur_action != SPRITE_IDLE )
  295. {
  296. return;
  297. }
  298. //##### begin trevor 9/10 ########//
  299. //--------------------------------------------------------------------//
  300. // decide attack or not
  301. //--------------------------------------------------------------------//
  302. int changeToAttack=0;
  303. if(cur_action==SPRITE_ATTACK || (sprite_info->need_turning && cur_action==SPRITE_TURN &&
  304. (abs(next_x_loc()-action_x_loc)<attack_range || abs(next_y_loc()-action_y_loc)<attack_range)))
  305. {
  306. err_when(cur_x!=next_x || cur_y!=next_y);
  307. if(action_mode!=ACTION_ATTACK_UNIT)
  308. changeToAttack++; //else continue to attack the target unit
  309. else
  310. {
  311. err_when(!action_para);
  312. if(unit_array.is_deleted(action_para))
  313. changeToAttack++; // attack new target
  314. }
  315. }
  316. else if(cur_action!=SPRITE_DIE)// && abs(cur_x-next_x)<spriteInfo->speed && abs(cur_y-next_y)<spriteInfo->speed)
  317. {
  318. changeToAttack++;
  319. /*if(!ai_unit) // player unit
  320. {
  321. if(action_mode!=ACTION_ATTACK_UNIT)
  322. changeToAttack++; //else continue to attack the target unit
  323. else
  324. {
  325. err_when(!action_para);
  326. if(unit_array.is_deleted(action_para))
  327. changeToAttack++; // attack new target
  328. }
  329. }
  330. else
  331. changeToAttack++;*/
  332. }
  333. if(!changeToAttack)
  334. {
  335. if(ai_unit) // allow ai unit to select target to attack
  336. {
  337. //------------------------------------------------------------//
  338. // conditions to let the unit escape
  339. //------------------------------------------------------------//
  340. //-************* codes here ************-//
  341. //------------------------------------------------------------//
  342. // select the weaker target to attack first, if more than one
  343. // unit attack this unit
  344. //------------------------------------------------------------//
  345. int attackXLoc = attackUnit->next_x_loc();
  346. int attackYLoc = attackUnit->next_y_loc();
  347. int attackDistance = cal_distance(attackXLoc, attackYLoc, attackUnit->sprite_info->loc_width,
  348. attackUnit->sprite_info->loc_height);
  349. if(attackDistance==1) // only consider close attack
  350. {
  351. err_when(!action_para || unit_array.is_deleted(action_para));
  352. Unit *targetUnit = unit_array[action_para];
  353. if(targetUnit->hit_points > attackUnit->hit_points) // the new attacker is weaker
  354. attack_unit(attackUnit->sprite_recno);
  355. }
  356. }
  357. return;
  358. }
  359. //--------------------------------------------------------------------//
  360. // cancel AI actions
  361. //--------------------------------------------------------------------//
  362. if( ai_action_id )
  363. nation_array[nation_recno]->action_failure(ai_action_id, sprite_recno);
  364. if(in_auto_defense_mode())
  365. set_search_tries(AUTO_DEFENSE_SEARCH_TRIES);
  366. if(!attackUnit->is_visible())
  367. return;
  368. //--------------------------------------------------------------------------------//
  369. // checking for ship processing trading
  370. //--------------------------------------------------------------------------------//
  371. if(sprite_info->sprite_sub_type=='M') //**** BUGHERE, is sprite_sub_type really representing UNIT_MARINE???
  372. {
  373. UnitInfo* unitInfo = unit_res[unit_id];
  374. if(unitInfo->carry_goods_capacity)
  375. {
  376. UnitMarine *shipPtr = (UnitMarine*) this;
  377. if(shipPtr->auto_mode && shipPtr->stop_defined_num>1)
  378. {
  379. int targetXLoc = attackUnit->next_x_loc();
  380. int targetYLoc = attackUnit->next_y_loc();
  381. SpriteInfo *targetSpriteInfo = attackUnit->sprite_info;
  382. int attackDistance = cal_distance(targetXLoc, targetYLoc, targetSpriteInfo->loc_width, targetSpriteInfo->loc_height);
  383. int maxAttackRange = max_attack_range();
  384. if(maxAttackRange<attackDistance)
  385. return; // can't attack the target
  386. }
  387. }
  388. }
  389. switch(action_mode2)
  390. {
  391. case ACTION_AUTO_DEFENSE_DETECT_TARGET: case ACTION_AUTO_DEFENSE_BACK_CAMP:
  392. action_mode2 = ACTION_AUTO_DEFENSE_ATTACK_TARGET;
  393. break;
  394. case ACTION_DEFEND_TOWN_DETECT_TARGET: case ACTION_DEFEND_TOWN_BACK_TOWN:
  395. action_mode2 = ACTION_DEFEND_TOWN_ATTACK_TARGET;
  396. break;
  397. case ACTION_MONSTER_DEFEND_DETECT_TARGET: case ACTION_MONSTER_DEFEND_BACK_FIRM:
  398. action_mode2 = ACTION_MONSTER_DEFEND_ATTACK_TARGET;
  399. break;
  400. }
  401. //##### trevor 9/10 #######//
  402. save_original_action();
  403. //----------------------------------------------------------//
  404. // set the original location of the attacking target when
  405. // the attack() function is called, action_x_loc2 & action_y_loc2
  406. // will change when the unit move, but these two will not.
  407. //----------------------------------------------------------//
  408. original_target_x_loc = attackUnit->next_x_loc();
  409. original_target_y_loc = attackUnit->next_y_loc();
  410. //##### trevor 9/10 #######//
  411. if(!unit_array.is_deleted(attackUnit->sprite_recno))
  412. attack_unit(attackUnit->sprite_recno);
  413. }
  414. //---------- End of function Unit::unit_auto_guarding ----------//
  415. //----------- Begin of function Unit::hit_building ---------------//
  416. //
  417. // note: If parentUnit==NULL, the attacking unit is already dead.
  418. // In range attack, the unit calling this function may not be the
  419. // attacking unit.
  420. //
  421. // <Unit*> parentUnit - the attacking unit
  422. // <int> target?Loc - the target building location
  423. // <int> attackDamage - the actual damage made
  424. //
  425. // ****************************** Warning ***********************************
  426. // don't use any member variables of this unit. This unit may not be involved
  427. // in the attack event
  428. // **************************************************************************
  429. //
  430. void Unit::hit_building(Unit* attackUnit, int targetXLoc, int targetYLoc, float attackDamage)
  431. {
  432. Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
  433. if(locPtr->is_firm())
  434. hit_firm( attackUnit, targetXLoc, targetYLoc, attackDamage);
  435. else if( locPtr->is_town() )
  436. hit_town( attackUnit, targetXLoc, targetYLoc, attackDamage);
  437. }
  438. //---------- End of function Unit::hit_building ----------//
  439. //##### begin trevor 15/8 #######//
  440. //------------ Begin of function Unit::hit_firm --------------//
  441. //
  442. // note: If parentUnit==NULL, the attacking unit is already dead.
  443. // In range attack, the unit calling this function may not be the
  444. // attacking unit.
  445. //
  446. // <Unit*> attackUnit - the attacking unit
  447. // <int> target?Loc - the target building location
  448. // <int> attackDamage - the actual damage made
  449. //
  450. // ****************************** Warning ***********************************
  451. // don't use any member variables of this unit. This unit may not be involved
  452. // in the attack event
  453. // **************************************************************************
  454. //
  455. void Unit::hit_firm(Unit* attackUnit, int targetXLoc, int targetYLoc, float attackDamage)
  456. {
  457. Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
  458. if(!locPtr->is_firm())
  459. return; // do nothing if no firm there
  460. //----------- attack firm ------------//
  461. err_when(!locPtr->firm_recno());
  462. Firm *targetFirm = firm_array[locPtr->firm_recno()];
  463. err_when(!targetFirm);
  464. //------------------------------------------------------------------------------//
  465. // change relation to hostile
  466. // check for NULL to skip unhandled case by bullets
  467. // check for SPRITE_DIE to skip the case by EXPLOSIVE_CART
  468. //------------------------------------------------------------------------------//
  469. if( attackUnit!=NULL && attackUnit->cur_action!=SPRITE_DIE &&
  470. targetFirm->nation_recno != attackUnit->nation_recno ) // the target and the attacker's nations are different (it's possible that when a unit who has just changed nation has its bullet hitting its own nation)
  471. {
  472. if( attackUnit->nation_recno && targetFirm->nation_recno )
  473. {
  474. //### trevor 29/9 ###//
  475. nation_array[attackUnit->nation_recno]->set_at_war_today();
  476. nation_array[targetFirm->nation_recno]->set_at_war_today(attackUnit->sprite_recno);
  477. //### trevor 29/9 ###//
  478. }
  479. if( targetFirm->nation_recno )
  480. nation_array[targetFirm->nation_recno]->being_attacked(attackUnit->nation_recno);
  481. //------------ auto defense -----------------//
  482. if(attackUnit->is_visible())
  483. targetFirm->auto_defense(attackUnit->sprite_recno);
  484. if(attackUnit->nation_recno!=targetFirm->nation_recno)
  485. attackUnit->gain_experience(); // gain experience to increase combat level
  486. targetFirm->being_attacked(attackUnit->sprite_recno);
  487. //------ increase battling fryhtan score -------//
  488. if( targetFirm->firm_id == FIRM_MONSTER && attackUnit->nation_recno )
  489. nation_array[attackUnit->nation_recno]->kill_monster_score += (float) 0.01;
  490. }
  491. //---------- add indicator on the map ----------//
  492. // ###### begin Gilbert 6/10 #######//
  493. if( nation_array.player_recno && targetFirm->own_firm() )
  494. war_point_array.add_point(targetFirm->center_x, targetFirm->center_y);
  495. // ###### end Gilbert 6/10 #######//
  496. //---------- damage to the firm ------------//
  497. targetFirm->hit_points -= attackDamage/3; // /3 so that it takes longer to destroy a firm
  498. //######## begin trevor 25/8 ##########//
  499. if(targetFirm->hit_points <= 0)
  500. {
  501. targetFirm->hit_points = (float) 0;
  502. se_res.sound(targetFirm->center_x, targetFirm->center_y, 1,
  503. 'F', targetFirm->firm_id, "DIE" );
  504. if( targetFirm->nation_recno == nation_array.player_recno )
  505. news_array.firm_destroyed(targetFirm->firm_recno, attackUnit);
  506. if( targetFirm->nation_recno )
  507. {
  508. if( attackUnit->nation_recno )
  509. nation_array[attackUnit->nation_recno]->enemy_firm_destroyed++;
  510. if( targetFirm->nation_recno )
  511. nation_array[targetFirm->nation_recno]->own_firm_destroyed++;
  512. }
  513. else if( targetFirm->firm_id == FIRM_MONSTER )
  514. {
  515. news_array.monster_firm_destroyed( ((FirmMonster*)targetFirm)->monster_id, targetFirm->center_x, targetFirm->center_y );
  516. }
  517. firm_array.del_firm(targetFirm->firm_recno);
  518. }
  519. //######## end trevor 25/8 ##########//
  520. }
  521. //---------- End of function Unit::hit_firm ----------//
  522. //--------- Begin of function Unit::hit_town ---------//
  523. //
  524. // note: If attackUnit==NULL, the attacking unit is already dead.
  525. // In range attack, the unit calling this function may not be the
  526. // attacking unit.
  527. //
  528. // <Unit*> attackUnit - the attacking unit
  529. // <int> target?Loc - the target building location
  530. // <int> attackDamage - the actual damage made
  531. //
  532. // ****************************** Warning ***********************************
  533. // don't use any member variables of this unit. This unit may not be involved
  534. // in the attack event
  535. // **************************************************************************
  536. //
  537. void Unit::hit_town(Unit* attackUnit, int targetXLoc, int targetYLoc, float attackDamage)
  538. {
  539. Location *locPtr = world.get_loc(targetXLoc, targetYLoc);
  540. if(!locPtr->is_town())
  541. return; // do nothing if no town there
  542. //----------- attack town ----------//
  543. err_when(!locPtr->town_recno());
  544. Town *targetTown = town_array[locPtr->town_recno()];
  545. int targetTownRecno = targetTown->town_recno;
  546. int targetTownNameId = targetTown->town_name_id;
  547. int targetTownXLoc = targetTown->center_x;
  548. int targetTownYLoc = targetTown->center_y;
  549. // ---------- add indicator on the map ----------//
  550. // ###### begin Gilbert 6/10 #######//
  551. if( nation_array.player_recno && targetTown->nation_recno == nation_array.player_recno )
  552. war_point_array.add_point(targetTown->center_x, targetTown->center_y);
  553. // ###### end Gilbert 6/10 #######//
  554. //------------------------------------------------------------------------------//
  555. // change relation to hostile
  556. // check for NULL to skip unhandled case by bullets
  557. // check for SPRITE_DIE to skip the case by EXPLOSIVE_CART
  558. //------------------------------------------------------------------------------//
  559. if( attackUnit!=NULL && attackUnit->cur_action!=SPRITE_DIE &&
  560. targetTown->nation_recno != attackUnit->nation_recno ) // the target and the attacker's nations are different (it's possible that when a unit who has just changed nation has its bullet hitting its own nation)
  561. {
  562. int townNationRecno = targetTown->nation_recno;
  563. //------- change to hostile relation -------//
  564. if( attackUnit->nation_recno && targetTown->nation_recno )
  565. {
  566. //### trevor 29/9 ###//
  567. nation_array[attackUnit->nation_recno]->set_at_war_today();
  568. nation_array[targetTown->nation_recno]->set_at_war_today(attackUnit->sprite_recno);
  569. //### trevor 29/9 ###//
  570. }
  571. if( targetTown->nation_recno)
  572. {
  573. nation_array[targetTown->nation_recno]->being_attacked(attackUnit->nation_recno);
  574. }
  575. news_array.disable(); // don't add the town abandon news that might be called by Town::dec_pop() as the town is actually destroyed not abandoned
  576. targetTown->being_attacked(attackUnit->sprite_recno, attackDamage);
  577. news_array.enable();
  578. //------ if the town is destroyed, add a news --------//
  579. if( town_array.is_deleted(targetTownRecno) &&
  580. townNationRecno == nation_array.player_recno )
  581. {
  582. news_array.town_destroyed(targetTownNameId, targetTownXLoc, targetTownYLoc, attackUnit);
  583. }
  584. //---------- gain experience --------//
  585. if(attackUnit->nation_recno!=targetTown->nation_recno)
  586. attackUnit->gain_experience(); // gain experience to increase combat level
  587. //------------ auto defense -----------------//
  588. if( !firm_array.is_deleted(targetTownRecno) )
  589. targetTown->auto_defense(attackUnit->sprite_recno);
  590. }
  591. }
  592. //---------- End of function Unit::hit_town ----------//
  593. //##### end trevor 15/8 #######//
  594. //--------- Begin of function Unit::hit_wall -----------//
  595. //
  596. // <Unit*> attackUnit - the attacking unit
  597. // <int> target?Loc - the targeted wall location
  598. // <int> attackDamage - the actual damage made
  599. //
  600. // ****************************** Warning ***********************************
  601. // don't use any member variables of this unit. This unit may not be involved
  602. // in the attack event
  603. // **************************************************************************
  604. //
  605. void Unit::hit_wall(Unit* attackUnit, int targetXLoc, int targetYLoc, float attackDamage)
  606. {
  607. Location *locPtr = world.get_loc(targetXLoc, targetYLoc);
  608. err_when(!locPtr->is_wall());
  609. //######## begin trevor 25/6 #########//
  610. /*
  611. if(attackUnit!=NULL)
  612. attackUnit->change_relation(attackUnit->nation_recno, locPtr->wall_nation_recno(), NATION_HOSTILE);
  613. */
  614. //######## end trevor 25/6 #########//
  615. if( !locPtr->attack_wall((int)attackDamage) )
  616. world.correct_wall(targetXLoc, targetYLoc);
  617. }
  618. //---------- End of function Unit::hit_wall ----------//
  619. //--------- Begin of function Unit::cal_distance ---------//
  620. // calculate the distance from this unit to the target
  621. // (assume the size of this unit is a square)
  622. //
  623. // <int> targetXLoc - x location of the target
  624. // <int> targetYLoc - y location of the target
  625. // <int> targetWidth - target width
  626. // <int> targetHeight - target height
  627. //
  628. int Unit::cal_distance(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight)
  629. {
  630. int curXLoc = next_x_loc();
  631. int curYLoc = next_y_loc();
  632. int dispX=0, dispY=0;
  633. if(curXLoc<targetXLoc)
  634. dispX = (targetXLoc - curXLoc - sprite_info->loc_width) + 1;
  635. else if((dispX=curXLoc-targetXLoc-targetWidth+1)<0)
  636. dispX = 0;
  637. err_when(dispX<0 || dispX>MAX_WORLD_X_LOC);
  638. if(curYLoc<targetYLoc)
  639. dispY = (targetYLoc - curYLoc - sprite_info->loc_height) + 1;
  640. else if((dispY=curYLoc-targetYLoc-targetHeight+1)<0)
  641. {
  642. err_when(mobile_type!=UNIT_AIR && !dispX); // inside the target
  643. return dispX;
  644. }
  645. err_when(dispY<0 || dispY>MAX_WORLD_Y_LOC);
  646. return (dispX>=dispY)? dispX : dispY;
  647. }
  648. //----------- End of function Unit::cal_distance -----------//
  649. //------------ Begin of function Unit::actual_damage --------------//
  650. //
  651. // return: return the actual hit damage this unit can do to a target.
  652. //
  653. float Unit::actual_damage()
  654. {
  655. AttackInfo *attackInfo = attack_info_array+cur_attack;
  656. int attackDamage = attackInfo->attack_damage;
  657. //-------- pierce damage --------//
  658. attackDamage += m.random(3) + attackInfo->pierce_damage
  659. * m.random(skill.combat_level-attackInfo->combat_level)
  660. / (100-attackInfo->combat_level);
  661. //--- if this unit is led by a general, its attacking ability is influenced by the general ---//
  662. //
  663. // The unit's attacking ability is increased by a percentage equivalent to
  664. // the leader unit's leadership.
  665. //
  666. //------------------------------------------------------------------------//
  667. if( leader_unit_recno )
  668. {
  669. if( unit_array.is_deleted(leader_unit_recno) )
  670. {
  671. leader_unit_recno = 0;
  672. }
  673. else
  674. {
  675. Unit* leaderUnit = unit_array[leader_unit_recno];
  676. int leaderXLoc, leaderYLoc;
  677. if( leaderUnit->is_visible() )
  678. {
  679. leaderXLoc = cur_x_loc();
  680. leaderYLoc = cur_y_loc();
  681. }
  682. else if( leaderUnit->unit_mode == UNIT_MODE_OVERSEE )
  683. {
  684. Firm* firmPtr = firm_array[leaderUnit->unit_mode_para];
  685. leaderXLoc = firmPtr->center_x;
  686. leaderYLoc = firmPtr->center_y;
  687. }
  688. else
  689. leaderXLoc = -1;
  690. if( leaderXLoc >= 0 &&
  691. m.points_distance(cur_x_loc(), cur_y_loc(), leaderXLoc, leaderYLoc) <= EFFECTIVE_LEADING_DISTANCE )
  692. {
  693. attackDamage += attackDamage * leaderUnit->skill.skill_level / 100;
  694. }
  695. }
  696. }
  697. return (float) attackDamage / ATTACK_SLOW_DOWN; // lessen all attacking damages, thus slowing down all battles.
  698. }
  699. //------------ End of function Unit::actual_damage --------------//
  700. //--------- Begin of function Unit::gain_experience ---------//
  701. void Unit::gain_experience()
  702. {
  703. if(unit_res[unit_id]->unit_class != UNIT_CLASS_HUMAN)
  704. return; // no experience gain if unit is not human
  705. //---- increase the unit's contribution to the nation ----//
  706. if( nation_contribution < MAX_NATION_CONTRIBUTION )
  707. {
  708. nation_contribution++;
  709. err_when( nation_contribution < 0 ); // overflow
  710. }
  711. //------ increase combat skill -------//
  712. err_when(skill.combat_level<0 || skill.combat_level>100);
  713. inc_minor_combat_level(6);
  714. //--- if this is a soldier led by a commander, increase the leadership of its commander -----//
  715. if( leader_unit_recno )
  716. {
  717. Unit* leaderUnit = unit_array[leader_unit_recno];
  718. int leaderXLoc= -1, leaderYLoc;
  719. if( leaderUnit->is_visible() )
  720. {
  721. leaderXLoc = cur_x_loc();
  722. leaderYLoc = cur_y_loc();
  723. }
  724. else if( leaderUnit->unit_mode == UNIT_MODE_OVERSEE )
  725. {
  726. Firm* firmPtr = firm_array[leaderUnit->unit_mode_para];
  727. leaderXLoc = firmPtr->center_x;
  728. leaderYLoc = firmPtr->center_y;
  729. }
  730. else
  731. leaderXLoc = -1;
  732. if( leaderXLoc >= 0 &&
  733. m.points_distance( cur_x_loc(), cur_y_loc(), leaderXLoc, leaderYLoc ) <= EFFECTIVE_LEADING_DISTANCE )
  734. {
  735. leaderUnit->inc_minor_skill_level(1);
  736. //-- give additional increase if the leader has skill potential on leadership --//
  737. if( leaderUnit->skill.skill_potential > 0 )
  738. {
  739. if( m.random(10-leaderUnit->skill.skill_potential/10)==0 )
  740. leaderUnit->inc_minor_skill_level(5);
  741. }
  742. }
  743. //--- if this soldier has leadership potential and is led by a commander ---//
  744. //--- he learns leadership by watching how the commander commands the troop --//
  745. if( skill.skill_potential > 0 )
  746. {
  747. if( m.random(10-skill.skill_potential/10)==0 )
  748. inc_minor_skill_level(5);
  749. }
  750. }
  751. }
  752. //------------ End of function Unit::gain_experience --------------//
  753. //--------- Begin of function Unit::can_attack ---------//
  754. // return 1 if can attack
  755. // return 0 otherwise
  756. //
  757. /*int Unit::can_attack()
  758. {
  759. return (can_attack_flag && attack_count);
  760. }*/
  761. //------------ End of function Unit::can_attack --------------//
  762. //--------- Begin of function Unit::nation_can_attack ---------//
  763. // return 1 for able to attack this nation i.e. relation is not
  764. // friendly or alliance
  765. // return 0 otherwise
  766. //
  767. // Whether this unit can attack others with the specified nation recno
  768. //
  769. // <short> nationRecno - nation recno to be checked
  770. //
  771. int Unit::nation_can_attack(short nationRecno)
  772. {
  773. if(!ai_unit)
  774. {
  775. //return 1;
  776. if( game.game_mode == GAME_TEST ) // in testing games, player units can attack their own units
  777. return 1;
  778. else
  779. return nationRecno!=nation_recno; // able to attack all nation except our own nation
  780. }
  781. else if(nation_recno == nationRecno)
  782. return 0; // ai unit don't attack its own nation, except special order
  783. if(!nation_recno || !nationRecno)
  784. return 1; // true if either nation is independent
  785. Nation *nationPtr = nation_array[nation_recno];
  786. char relatinStatus = nationPtr->get_relation_status(nationRecno);
  787. if(relatinStatus==NATION_FRIENDLY || relatinStatus==NATION_ALLIANCE)
  788. return 0;
  789. return 1;
  790. }
  791. //------------ End of function Unit::nation_can_attack --------------//
  792. //--------- Begin of function Unit::independent_nation_can_attack ---------//
  793. // Note: this unit should be an independent unit
  794. //
  795. // Should this independent unit attack other units with specified nation recno
  796. //
  797. // return 1 if decision is attacking
  798. // return 0 otherwise
  799. //
  800. // <short> nationRecno - nation recno to be checked
  801. //
  802. int Unit::independent_nation_can_attack(short nationRecno)
  803. {
  804. err_when(nation_recno);
  805. Town *townPtr;
  806. FirmMonster *firmMonster;
  807. Rebel *rebelPtr;
  808. switch(unit_mode)
  809. {
  810. case UNIT_MODE_DEFEND_TOWN:
  811. err_when(unit_mode_para<=0);
  812. if(town_array.is_deleted(unit_mode_para))
  813. return 0; // don't attack independent unit with no town
  814. townPtr = town_array[unit_mode_para];
  815. if( !townPtr->is_hostile_nation(nationRecno) )
  816. return 0; // false if the indepentent unit don't want to attack us
  817. break;
  818. case UNIT_MODE_REBEL:
  819. if(rebel_array.is_deleted(unit_mode_para))
  820. return 0;
  821. rebelPtr = rebel_array[unit_mode_para];
  822. if( !rebelPtr->is_hostile_nation(nationRecno) )
  823. return 0;
  824. break;
  825. //######## begin trevor 22/8 ##########//
  826. case UNIT_MODE_MONSTER:
  827. if( unit_mode_para==0 )
  828. return nationRecno; // attack anything that is not independent
  829. firmMonster = (FirmMonster*) firm_array[unit_mode_para];
  830. err_when( firmMonster->firm_id != FIRM_MONSTER );
  831. if( !firmMonster->is_hostile_nation(nationRecno) )
  832. return 0; // false if the indepentent unit don't want to attack us
  833. break;
  834. //######## end trevor 22/8 ##########//
  835. default:
  836. return 0;
  837. }
  838. return 1;
  839. }
  840. //------------ End of function Unit::independent_nation_can_attack --------------//
  841. //--------- Begin of function Unit::choose_best_attack_mode ---------//
  842. // if the unit has more than one attack mode, select the suitable mode
  843. // to attack the target
  844. //
  845. // <int> attackDistance - the distance from the target
  846. // [char] targetMobileType - the target's mobile_type (default: UNIT_LAND)
  847. //
  848. void Unit::choose_best_attack_mode(int attackDistance, char targetMobileType)
  849. {
  850. //------------ enable/disable range attack -----------//
  851. //cur_attack = 0;
  852. //return;
  853. //-------------------- define parameters -----------------------//
  854. UCHAR attackModeBeingUsed = cur_attack;
  855. err_when(attackModeBeingUsed<0 || attackModeBeingUsed>MAX_UNIT_ATTACK_TYPE);
  856. //UCHAR maxAttackRangeMode = 0;
  857. UCHAR maxAttackRangeMode = cur_attack;
  858. AttackInfo* attackInfoMaxRange = attack_info_array;
  859. AttackInfo* attackInfoChecking;
  860. AttackInfo* attackInfoSelected = attack_info_array+cur_attack;
  861. //--------------------------------------------------------------//
  862. // If targetMobileType==UNIT_AIR or mobile_type==UNIT_AIR,
  863. // force to use range_attack.
  864. // If there is no range_attack, return 0, i.e. cur_attack=0
  865. //--------------------------------------------------------------//
  866. if(attack_count>1)
  867. {
  868. int canAttack = 0;
  869. int checkingDamageWeight, selectedDamageWeight;
  870. for(UCHAR i=0; i<attack_count; i++)
  871. {
  872. if(attackModeBeingUsed==i)
  873. continue; // it is the mode already used
  874. attackInfoChecking = attack_info_array+i;
  875. if(can_attack_with(attackInfoChecking) && attackInfoChecking->attack_range>=attackDistance)
  876. {
  877. //-------------------- able to attack ----------------------//
  878. canAttack = 1;
  879. if(attackInfoSelected->attack_range<attackDistance)
  880. {
  881. attackModeBeingUsed = UCHAR(i);
  882. attackInfoSelected = attackInfoChecking;
  883. continue;
  884. }
  885. checkingDamageWeight = attackInfoChecking->attack_damage;
  886. selectedDamageWeight = attackInfoSelected->attack_damage;
  887. if(attackDistance==1 && (targetMobileType!=UNIT_AIR && mobile_type!=UNIT_AIR))
  888. {
  889. //------------ force to use close attack if possible -----------//
  890. if(attackInfoSelected->attack_range==attackDistance)
  891. {
  892. if(attackInfoChecking->attack_range==attackDistance && checkingDamageWeight>selectedDamageWeight)
  893. {
  894. attackModeBeingUsed = UCHAR(i); // choose the one with strongest damage
  895. attackInfoSelected = attackInfoChecking;
  896. }
  897. continue;
  898. }
  899. else if(attackInfoChecking->attack_range==1)
  900. {
  901. attackModeBeingUsed = UCHAR(i);
  902. attackInfoSelected = attackInfoChecking;
  903. continue;
  904. }
  905. }
  906. //----------------------------------------------------------------------//
  907. // further selection
  908. //----------------------------------------------------------------------//
  909. if(checkingDamageWeight == selectedDamageWeight)
  910. {
  911. if(attackInfoChecking->attack_range<attackInfoSelected->attack_range)
  912. {
  913. if(attackInfoChecking->attack_range>1 || (targetMobileType!=UNIT_AIR && mobile_type!=UNIT_AIR))
  914. {
  915. //--------------------------------------------------------------------------//
  916. // select one with shortest attack_range
  917. //--------------------------------------------------------------------------//
  918. attackModeBeingUsed = UCHAR(i);
  919. attackInfoSelected = attackInfoChecking;
  920. }
  921. }
  922. }
  923. else
  924. {
  925. //--------------------------------------------------------------------------//
  926. // select one that can do the attacking immediately with the strongest damage point
  927. //--------------------------------------------------------------------------//
  928. attackModeBeingUsed = UCHAR(i);
  929. attackInfoSelected = attackInfoChecking;
  930. }
  931. }
  932. if(!canAttack)
  933. {
  934. //------------------------------------------------------------------------------//
  935. // if unable to attack the target, choose the mode with longer attack_range and
  936. // heavier damage
  937. //------------------------------------------------------------------------------//
  938. if(can_attack_with(attackInfoChecking) &&
  939. (attackInfoChecking->attack_range>attackInfoMaxRange->attack_range ||
  940. (attackInfoChecking->attack_range==attackInfoMaxRange->attack_range &&
  941. attackInfoChecking->attack_damage>attackInfoMaxRange->attack_damage)))
  942. {
  943. maxAttackRangeMode = UCHAR(i);
  944. attackInfoMaxRange = attackInfoChecking;
  945. }
  946. }
  947. }
  948. if(canAttack)
  949. cur_attack = attackModeBeingUsed; // choose the strongest damage mode if able to attack
  950. else
  951. cur_attack = maxAttackRangeMode; // choose the longest attack range if unable to attack
  952. attack_range = attack_info_array[cur_attack].attack_range;
  953. err_when(final_dir<0 || final_dir>=MAX_SPRITE_DIR_TYPE);
  954. err_when(cur_attack>=attack_count || cur_attack<0);
  955. }
  956. else
  957. {
  958. cur_attack = 0; // only one mode is supported
  959. attack_range = attack_info_array[0].attack_range;
  960. return;
  961. }
  962. }
  963. //---------- End of function Unit::choose_best_attack_mode ----------//
  964. //------ Begin of function Unit::set_attack_dir ---------//
  965. // set direction for attacking
  966. //
  967. // <short> curX - x location of the unit
  968. // <short> curY - y location of the unit
  969. // <short> targetX - x location of the target
  970. // <short> targetY - y location of the target
  971. //
  972. void Unit::set_attack_dir(short curX, short curY, short targetX, short targetY)
  973. {
  974. UCHAR targetDir = get_dir(curX, curY, targetX, targetY);
  975. if(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP)
  976. {
  977. UCHAR attackDir1, attackDir2;
  978. attackDir1 = (targetDir+2)%MAX_SPRITE_DIR_TYPE;
  979. attackDir2 = (targetDir+6)%MAX_SPRITE_DIR_TYPE;
  980. if((attackDir1+8-final_dir)%MAX_SPRITE_DIR_TYPE <= (attackDir2+8-final_dir)%MAX_SPRITE_DIR_TYPE)
  981. final_dir = attackDir1;
  982. else
  983. final_dir = attackDir2;
  984. attack_dir = targetDir;
  985. err_when(attack_dir<0 || attack_dir>=MAX_SPRITE_DIR_TYPE);
  986. }
  987. else
  988. {
  989. attack_dir = targetDir;
  990. set_dir(targetDir);
  991. }
  992. }
  993. //---------- End of function Unit::set_attack_dir ----------//
  994. //--------- Begin of function Unit::set_unreachable_location ---------//
  995. // used to set the bit in the unreachable_flag (16 bits)
  996. //
  997. // The 16 bits of the flag are used to represent the 16 location of a unit
  998. // as follows:
  999. //
  1000. // 1 2 3 4 where x is the upper left corner of the unit.
  1001. // 5 x 6 7 For 1x1 unit, 1,2,3,5,6,8,9,10 are meaningful
  1002. // 8 9 10 11 For 2x2 unit, 1,2,3,4,5,7,8,11,12,13,14,15 are meaningful
  1003. // 12 13 14 15
  1004. //
  1005. void Unit::set_unreachable_location(int xLoc, int yLoc)
  1006. {
  1007. static unsigned short bitFlag[16] = {0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
  1008. 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000};
  1009. /*int curXLoc = next_x_loc();
  1010. int curYLoc = next_y_loc();
  1011. int xDist = xLoc-curXLoc+1;
  1012. int yDist = yLoc-curYLoc+1;
  1013. err_when(xDist<0 || xDist>3 || yDist<0 || yDist>3);
  1014. char bitNo = yDist*4 + xDist;
  1015. err_when(bitNo==5);
  1016. if(bitNo>5)
  1017. bitNo--;
  1018. unreachable_flag |= bitFlag[bitNo];*/
  1019. }
  1020. //----------- End of function Unit::set_unreachable_location -----------//
  1021. //--------- Begin of function Unit::check_self_surround ---------//
  1022. // Note : mobile_type used is this unit's mobile_type
  1023. //
  1024. void Unit::check_self_surround()
  1025. {
  1026. /*err_when(sprite_info->loc_height!=sprite_info->loc_width);
  1027. err_when(sprite_info->loc_width<1 || sprite_info->loc_width>2);
  1028. Location *locPtr;
  1029. int width = sprite_info->loc_width;
  1030. int curXLoc = next_x_loc();
  1031. int curYLoc = next_y_loc();
  1032. int startCount = (width==1) ? 2 : 5;
  1033. int endCount = (width==1) ? 9 : 16;
  1034. int xShift, yShift;
  1035. self_surround_flag = 0;
  1036. for(int i=startCount; i<=endCount; i++)
  1037. {
  1038. m.cal_move_around_a_point(i, width, width, xShift, yShift);
  1039. locPtr = world.get_loc(curXLoc+xShift, curYLoc+yShift);
  1040. if(!locPtr->can_move(mobile_type))
  1041. m.set_surround_bit(self_surround_flag, i-startCount);
  1042. }*/
  1043. }
  1044. //----------- End of function Unit::check_self_surround -----------//
  1045. //----------- Begin of function Unit::cycle_eqv_attack -----------//
  1046. void Unit::cycle_eqv_attack()
  1047. {
  1048. int trial = MAX_UNIT_ATTACK_TYPE+2;
  1049. if( attack_info_array[cur_attack].eqv_attack_next > 0)
  1050. {
  1051. do
  1052. {
  1053. cur_attack = attack_info_array[cur_attack].eqv_attack_next-1;
  1054. err_when(--trial == 0);
  1055. } while( !can_attack_with(cur_attack) );
  1056. }
  1057. else
  1058. {
  1059. if( !can_attack_with(cur_attack) )
  1060. {
  1061. err_here();
  1062. // force to search again
  1063. char attackRange = char(attack_info_array[cur_attack].attack_range);
  1064. err_when(attackRange != attack_range); // redundant check
  1065. AttackInfo *attackInfo = attack_info_array;
  1066. for(int i = 0; i < attack_count; ++i, ++attackInfo)
  1067. {
  1068. if( attackInfo->attack_range >= attackRange &&
  1069. can_attack_with(attackInfo))
  1070. {
  1071. cur_attack = i;
  1072. break;
  1073. }
  1074. err_when(i >= attack_count); // not found
  1075. }
  1076. }
  1077. }
  1078. err_when(cur_attack < 0 || cur_attack >= attack_count);
  1079. }
  1080. //----------- End of function Unit::cycle_eqv_attack -----------//
  1081. //----------- Begin of function Unit::max_attack_range -----------//
  1082. // return the maximum attack range the unit can make
  1083. //
  1084. //
  1085. //
  1086. int Unit::max_attack_range()
  1087. {
  1088. int maxRange=0;
  1089. AttackInfo *attackInfo = attack_info_array;
  1090. for(int i=0; i<attack_count; i++, attackInfo++)
  1091. {
  1092. if(can_attack_with(attackInfo) &&
  1093. attackInfo->attack_range>maxRange)
  1094. maxRange = attackInfo->attack_range;
  1095. }
  1096. return maxRange;
  1097. }
  1098. //----------- End of function Unit::max_attack_range -----------//
  1099. //----------- Begin of function Unit::can_attack_with -------//
  1100. int Unit::can_attack_with(int i)
  1101. {
  1102. err_when( i< 0 || i >= attack_count);
  1103. AttackInfo *attackInfo = attack_info_array+i;
  1104. return( skill.combat_level >= attackInfo->combat_level &&
  1105. cur_power >= attackInfo->min_power);
  1106. }
  1107. int Unit::can_attack_with(AttackInfo *attackInfo)
  1108. {
  1109. return( skill.combat_level >= attackInfo->combat_level &&
  1110. cur_power >= attackInfo->min_power);
  1111. }
  1112. //----------- End of function Unit::can_attack_with -------//
  1113. //----------- Begin of function Unit::get_hit_x_y -------//
  1114. void Unit::get_hit_x_y(short *xPtr, short *yPtr)
  1115. {
  1116. switch(cur_dir)
  1117. {
  1118. case 0: // north
  1119. *xPtr = cur_x;
  1120. *yPtr = cur_y - ZOOM_LOC_HEIGHT;
  1121. break;
  1122. case 1: // north east
  1123. *xPtr = cur_x + ZOOM_LOC_WIDTH;
  1124. *yPtr = cur_y - ZOOM_LOC_HEIGHT;
  1125. break;
  1126. case 2: // east
  1127. *xPtr = cur_x + ZOOM_LOC_WIDTH;
  1128. *yPtr = cur_y;
  1129. break;
  1130. case 3: // south east
  1131. *xPtr = cur_x + ZOOM_LOC_WIDTH;
  1132. *yPtr = cur_y + ZOOM_LOC_HEIGHT;
  1133. break;
  1134. case 4: // south
  1135. *xPtr = cur_x;
  1136. *yPtr = cur_y + ZOOM_LOC_HEIGHT;
  1137. break;
  1138. case 5: // south west
  1139. *xPtr = cur_x - ZOOM_LOC_WIDTH;
  1140. *yPtr = cur_y + ZOOM_LOC_HEIGHT;
  1141. break;
  1142. case 6: // west
  1143. *xPtr = cur_x - ZOOM_LOC_WIDTH;
  1144. *yPtr = cur_y;
  1145. break;
  1146. case 7: // north west
  1147. *xPtr = cur_x - ZOOM_LOC_WIDTH;
  1148. *yPtr = cur_y - ZOOM_LOC_HEIGHT;
  1149. break;
  1150. default:
  1151. err_here();
  1152. *xPtr = cur_x;
  1153. *yPtr = cur_y;
  1154. }
  1155. }
  1156. //----------- End of function Unit::get_hit_x_y -------//
  1157. //----------- Begin of function Unit::add_close_attack_effect -------//
  1158. void Unit::add_close_attack_effect()
  1159. {
  1160. short effectId = (attack_info_array+cur_attack)->effect_id;
  1161. if( effectId )
  1162. {
  1163. short x,y;
  1164. get_hit_x_y(&x, &y);
  1165. Effect::create(effectId, x, y, SPRITE_IDLE, cur_dir, mobile_type == UNIT_AIR ? 8 : 2, 0);
  1166. }
  1167. }
  1168. //----------- End of function Unit::add_close_attack_effect -------//
  1169. //----------- Begin of function Unit::is_action_attack -------//
  1170. // check whether the unit carrys on attacking action
  1171. //
  1172. int Unit::is_action_attack()
  1173. {
  1174. switch(action_mode2)
  1175. {
  1176. case ACTION_ATTACK_UNIT:
  1177. case ACTION_ATTACK_FIRM:
  1178. case ACTION_ATTACK_TOWN:
  1179. case ACTION_ATTACK_WALL:
  1180. case ACTION_AUTO_DEFENSE_ATTACK_TARGET:
  1181. case ACTION_AUTO_DEFENSE_DETECT_TARGET:
  1182. case ACTION_AUTO_DEFENSE_BACK_CAMP:
  1183. case ACTION_DEFEND_TOWN_ATTACK_TARGET:
  1184. case ACTION_DEFEND_TOWN_DETECT_TARGET:
  1185. case ACTION_DEFEND_TOWN_BACK_TOWN:
  1186. case ACTION_MONSTER_DEFEND_ATTACK_TARGET:
  1187. case ACTION_MONSTER_DEFEND_DETECT_TARGET:
  1188. case ACTION_MONSTER_DEFEND_BACK_FIRM:
  1189. return 1;
  1190. default: return 0;
  1191. }
  1192. return 0;
  1193. }
  1194. //----------- End of function Unit::is_action_attack -------//