OBULLET.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  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 : OBULLET.CPP
  21. //Description : Object Bullet
  22. //Owner : Alex
  23. #include <OVGA.h>
  24. #include <OUNIT.h>
  25. #include <OBULLET.h>
  26. #include <OWORLD.h>
  27. #include <OSERES.h>
  28. #include <OU_CART.h>
  29. #include <OTOWN.h>
  30. #include <ONATIONA.h>
  31. // -------- Define constant ---------//
  32. const int SCAN_RADIUS = 2;
  33. const int SCAN_RANGE = SCAN_RADIUS * 2 + 1;
  34. // from the closet to the far
  35. static char spiral_x[SCAN_RANGE*SCAN_RANGE] =
  36. { 0, 0,-1, 0, 1,-1,-1, 1, 1, 0,-2, 0, 2, -1,-2,-2,-1, 1, 2, 2, 1,-2,-2, 2, 2};
  37. static char spiral_y[SCAN_RANGE*SCAN_RANGE] =
  38. { 0,-1, 0, 1, 0,-1, 1, 1,-1,-2, 0, 2, 0, -2,-1, 1, 2, 2, 1,-1,-2,-2, 2, 2,-2};
  39. //--------- Begin of function Bullet::Bullet -------//
  40. Bullet::Bullet()
  41. {
  42. sprite_id = 0;
  43. }
  44. //--------- End of function Bullet::Bullet -------//
  45. //--------- Begin of function Bullet::init ---------//
  46. //
  47. // <char> parentType - the type of object emits the bullet
  48. // <short> parentRecno - the recno of the object
  49. // <short> targetXLoc - the x loc of the target
  50. // <short> targetYLoc - the y loc of the target
  51. // <char> targetMobileType - target mobile type
  52. //
  53. void Bullet::init(char parentType, short parentRecno, short targetXLoc, short targetYLoc, char targetMobileType)
  54. {
  55. parent_type = parentType;
  56. parent_recno = parentRecno;
  57. target_mobile_type = targetMobileType;
  58. //**** BUGHERE, using parentType and parentRecno to allow bullet by firm, town, etc.
  59. //**** BUGHERE, only allow bullet by unit for this version
  60. err_when(parent_type!=BULLET_BY_UNIT);
  61. Unit *parentUnit = unit_array[parentRecno];
  62. //---------- copy attack info from the parent unit --------//
  63. AttackInfo* attackInfo = parentUnit->attack_info_array+parentUnit->cur_attack;
  64. attack_damage = parentUnit->actual_damage();
  65. damage_radius = attackInfo->bullet_radius;
  66. nation_recno = parentUnit->nation_recno;
  67. // ###### begin Gilbert 26/6 ########## //
  68. fire_radius = attackInfo->fire_radius;
  69. // ###### end Gilbert 26/6 ########## //
  70. //----- clone vars from sprite_res for fast access -----//
  71. sprite_id = attackInfo->bullet_sprite_id;
  72. sprite_info = sprite_res[sprite_id];
  73. sprite_info->load_bitmap_res(); // the sprite bitmap will be freed by ~Sprite(), so we don't have to add ~Bullet() to free it.
  74. //--------- set the starting position of the bullet -------//
  75. cur_action = SPRITE_MOVE;
  76. cur_frame = 1;
  77. set_dir(parentUnit->attack_dir);
  78. SpriteFrame* spriteFrame = cur_sprite_frame();
  79. origin_x = cur_x = parentUnit->cur_x;
  80. origin_y = cur_y = parentUnit->cur_y;
  81. //------ set the target position and bullet mobile_type -------//
  82. target_x_loc = targetXLoc;
  83. target_y_loc = targetYLoc;
  84. go_x = target_x_loc * ZOOM_LOC_WIDTH + ZOOM_LOC_WIDTH/2 - spriteFrame->offset_x - spriteFrame->width/2; // -spriteFrame->offset_x to make abs_x1 & abs_y1 = original x1 & y1. So the bullet will be centered on the target
  85. go_y = target_y_loc * ZOOM_LOC_HEIGHT + ZOOM_LOC_HEIGHT/2 - spriteFrame->offset_y - spriteFrame->height/2;
  86. mobile_type = parentUnit->mobile_type;
  87. //---------- set bullet movement steps -----------//
  88. int xStep = (go_x - cur_x)/attackInfo->bullet_speed;
  89. int yStep = (go_y - cur_y)/attackInfo->bullet_speed;
  90. total_step = max(1, max(abs(xStep), abs(yStep)));
  91. cur_step = 0;
  92. err_when( total_step < 0 ); // number overflow
  93. }
  94. //----------- End of function Bullet::init -----------//
  95. //--------- Begin of function Bullet::process_move --------//
  96. void Bullet::process_move()
  97. {
  98. //-------------- update position -----------------//
  99. //
  100. // If it gets very close to the destination, fit it
  101. // to the destination ingoring the normal vector.
  102. //
  103. //------------------------------------------------//
  104. cur_x = origin_x + (int)(go_x-origin_x) * cur_step / total_step;
  105. cur_y = origin_y + (int)(go_y-origin_y) * cur_step / total_step;
  106. //cur_step++;
  107. //------- update frame id. --------//
  108. if( ++cur_frame > cur_sprite_move()->frame_count )
  109. cur_frame = 1;
  110. //----- if the sprite has reach the destintion ----//
  111. //if( cur_step > total_step )
  112. if( ++cur_step > total_step )
  113. {
  114. check_hit();
  115. cur_action = SPRITE_DIE; // Explosion
  116. // ###### begin Gilbert 17/5 #########//
  117. // if it has die frame, adjust cur_x, cur_y to be align with the target_x_loc, target_y_loc
  118. if( sprite_info->die.first_frame_recno )
  119. {
  120. next_x = cur_x = target_x_loc * ZOOM_LOC_WIDTH;
  121. next_y =cur_y = target_y_loc * ZOOM_LOC_HEIGHT;
  122. }
  123. // ###### end Gilbert 17/5 #########//
  124. cur_frame = 1;
  125. }
  126. else if( total_step - cur_step == 1 )
  127. {
  128. warn_target();
  129. }
  130. }
  131. //---------- End of function Bullet::process_move ----------//
  132. //--------- Begin of function Bullet::process_die --------//
  133. //
  134. // return : <int> 1 - dying animation completes.
  135. // 0 - still dying
  136. //
  137. int Bullet::process_die()
  138. {
  139. // ------- sound effect --------//
  140. se_res.sound(cur_x_loc(), cur_y_loc(), cur_frame, 'S',sprite_id,"DIE");
  141. //--------- next frame ---------//
  142. if( ++cur_frame > sprite_info->die.frame_count )
  143. // ####### begin Gilbert 28/6 ########//
  144. if( ++cur_frame > sprite_info->die.frame_count )
  145. {
  146. // ------- set fire on the target area --------//
  147. if( fire_radius > 0)
  148. {
  149. Location *locPtr;
  150. if( fire_radius == 1)
  151. {
  152. locPtr = world.get_loc(target_x_loc, target_y_loc);
  153. if( locPtr->can_set_fire() && locPtr->fire_str() < 30 )
  154. locPtr->set_fire_str(30);
  155. if( locPtr->fire_src() > 0 )
  156. locPtr->set_fire_src(1); // such that the fire will be put out quickly
  157. }
  158. else
  159. {
  160. short x, y, x1, y1, x2, y2;
  161. // ##### begin Gilbert 2/10 ######//
  162. x1 = target_x_loc - fire_radius + 1;
  163. if( x1 < 0 )
  164. x1 = 0;
  165. y1 = target_y_loc - fire_radius + 1;
  166. if( y1 < 0 )
  167. y1 = 0;
  168. x2 = target_x_loc + fire_radius - 1;
  169. if( x2 >= world.max_x_loc )
  170. x2 = world.max_x_loc-1;
  171. y2 = target_y_loc + fire_radius - 1;
  172. if( y2 >= world.max_y_loc )
  173. y2 = world.max_y_loc-1;
  174. // ##### end Gilbert 2/10 ######//
  175. for( y = y1; y <= y2; ++y)
  176. {
  177. locPtr = world.get_loc(x1, y);
  178. for( x = x1; x <= x2; ++x, ++locPtr)
  179. {
  180. // ##### begin Gilbert 30/10 ######//
  181. int dist = abs(x-target_x_loc) + abs(y-target_y_loc);
  182. if( dist > fire_radius)
  183. continue;
  184. int fl = 30 - dist * 7;
  185. if( fl < 10 )
  186. fl = 10;
  187. if( locPtr->can_set_fire() && locPtr->fire_str() < fl )
  188. locPtr->set_fire_str(fl);
  189. if( locPtr->fire_src() > 0 )
  190. locPtr->set_fire_src(1); // such that the fire will be put out quickly
  191. // ##### begin Gilbert 30/10 ######//
  192. }
  193. }
  194. }
  195. }
  196. return 1;
  197. }
  198. // ####### end Gilbert 28/6 ########//
  199. return 0;
  200. }
  201. //--------- End of function Bullet::process_die --------//
  202. //--------- Begin of function Bullet::hit_target --------//
  203. // ####### begin Gilbert 14/5 #########//
  204. void Bullet::hit_target(short x, short y)
  205. {
  206. //---- check if there is any unit in the target location ----//
  207. Location* locPtr = world.get_loc(x, y);
  208. // ####### end Gilbert 14/5 #########//
  209. short targetUnitRecno = locPtr->unit_recno(target_mobile_type);
  210. if(unit_array.is_deleted(targetUnitRecno))
  211. return; // the target unit is deleted
  212. Unit* targetUnit = unit_array[targetUnitRecno];
  213. Unit* parentUnit;
  214. if(unit_array.is_deleted(parent_recno))
  215. //### begin alex 26/9 ###//
  216. // parentUnit = NULL; // parent is dead
  217. {
  218. parentUnit = NULL; // parent is dead
  219. if(nation_array.is_deleted(nation_recno))
  220. return;
  221. }
  222. //#### end alex 26/9 ####//
  223. else
  224. {
  225. parentUnit = unit_array[parent_recno];
  226. nation_recno = parentUnit->nation_recno;
  227. }
  228. float attackDamage = attenuated_damage(targetUnit->cur_x, targetUnit->cur_y);
  229. // -------- if the unit is guarding reduce damage ----------//
  230. err_when(unit_array.is_deleted(locPtr->unit_recno(target_mobile_type)));
  231. // ##### begin Gilbert 14/5 #########//
  232. if( attackDamage == 0 )
  233. return;
  234. if( targetUnit->is_nation(nation_recno) )
  235. {
  236. if( targetUnit->unit_id == UNIT_EXPLOSIVE_CART )
  237. ((UnitExpCart *)targetUnit)->trigger_explode();
  238. return;
  239. }
  240. // ##### end Gilbert 14/5 #########//
  241. // ##### begin Gilbert 3/9 #########//
  242. if( !nation_array.should_attack(nation_recno, targetUnit->nation_recno) )
  243. return;
  244. // ##### end Gilbert 3/9 #########//
  245. if(targetUnit->is_guarding())
  246. {
  247. switch(targetUnit->cur_action)
  248. {
  249. case SPRITE_IDLE:
  250. case SPRITE_READY_TO_MOVE:
  251. case SPRITE_TURN:
  252. case SPRITE_MOVE:
  253. // #ifdef AMPLUS
  254. case SPRITE_ATTACK:
  255. // #endif
  256. // ####### begin Gilbert 9/9 #######//
  257. // check if on the opposite direction
  258. if( (targetUnit->cur_dir & 7)== ((cur_dir + 4 ) & 7)
  259. || (targetUnit->cur_dir & 7)== ((cur_dir + 3 ) & 7)
  260. || (targetUnit->cur_dir & 7)== ((cur_dir + 5 ) & 7) )
  261. // ####### end Gilbert 9/9 #######//
  262. {
  263. attackDamage = attackDamage > (float)10/ATTACK_SLOW_DOWN ? attackDamage - (float)10/ATTACK_SLOW_DOWN : 0;
  264. se_res.sound( targetUnit->cur_x_loc(), targetUnit->cur_y_loc(), 1,
  265. 'S', targetUnit->sprite_id, "DEF", 'S', sprite_id );
  266. }
  267. break;
  268. }
  269. }
  270. targetUnit->hit_target(parentUnit, targetUnit, attackDamage);
  271. }
  272. //---------- End of function Bullet::hit_target ----------//
  273. //------- Begin of function Bullet::hit_building -----//
  274. // building means firm or town
  275. //
  276. // ###### begin Gilbert 14/5 #########//
  277. void Bullet::hit_building(short x, short y)
  278. {
  279. Location* locPtr = world.get_loc(x, y);
  280. if(locPtr->is_firm())
  281. {
  282. Firm *firmPtr = firm_array[locPtr->firm_recno()];
  283. // ##### begin Gilbert 3/9 #########//
  284. if( !firmPtr || !nation_array.should_attack(nation_recno, firmPtr->nation_recno) )
  285. // ##### end Gilbert 3/9 #########//
  286. return;
  287. }
  288. else if(locPtr->is_town())
  289. {
  290. Town *townPtr = town_array[locPtr->town_recno()];
  291. // ##### begin Gilbert 3/9 #########//
  292. if( !townPtr || !nation_array.should_attack(nation_recno, townPtr->nation_recno) )
  293. // ##### end Gilbert 3/9 #########//
  294. return;
  295. }
  296. else
  297. return;
  298. float attackDamage = attenuated_damage(x * ZOOM_LOC_WIDTH, y * ZOOM_LOC_HEIGHT );
  299. // BUGHERE : hit building of same nation?
  300. if( attackDamage == 0)
  301. return;
  302. Unit *virtualUnit, *parentUnit;
  303. if(unit_array.is_deleted(parent_recno))
  304. {
  305. parentUnit = NULL;
  306. //### begin alex 26/9 ###//
  307. if(nation_array.is_deleted(nation_recno))
  308. return;
  309. //#### end alex 26/9 ####//
  310. for(int i=unit_array.size(); i>0; i--)
  311. {
  312. if(unit_array.is_deleted(i))
  313. continue;
  314. virtualUnit = unit_array[i];
  315. break;
  316. }
  317. if(!virtualUnit)
  318. return; //**** BUGHERE
  319. }
  320. else
  321. virtualUnit = parentUnit = unit_array[parent_recno];
  322. virtualUnit->hit_building(parentUnit, target_x_loc, target_y_loc, attackDamage);
  323. // ####### end Gilbert 14/5 ########//
  324. }
  325. //---------- End of function Bullet::hit_building ----------//
  326. //------- Begin of function Bullet::hit_wall -----//
  327. // ###### begin Gilbert 14/5 #########//
  328. void Bullet::hit_wall(short x, short y)
  329. {
  330. Location* locPtr = world.get_loc(x, y);
  331. if(!locPtr->is_wall())
  332. return;
  333. float attackDamage = attenuated_damage(x * ZOOM_LOC_WIDTH, y * ZOOM_LOC_HEIGHT );
  334. if( attackDamage == 0)
  335. return;
  336. // ###### end Gilbert 14/5 #########//
  337. Unit *virtualUnit, *parentUnit;
  338. if(unit_array.is_deleted(parent_recno))
  339. {
  340. parentUnit = NULL;
  341. //### begin alex 26/9 ###//
  342. if(nation_array.is_deleted(nation_recno))
  343. return;
  344. //#### end alex 26/9 ####//
  345. for(int i=unit_array.size(); i>0; i--)
  346. {
  347. if(unit_array.is_deleted(i))
  348. continue;
  349. virtualUnit = unit_array[i];
  350. break;
  351. }
  352. if(!virtualUnit)
  353. return; //**** BUGHERE
  354. }
  355. else
  356. virtualUnit = parentUnit = unit_array[parent_recno];
  357. // ###### begin Gilbert 14/5 #########//
  358. virtualUnit->hit_wall(parentUnit, target_x_loc, target_y_loc, attackDamage);
  359. // ###### end Gilbert 14/5 ########//
  360. }
  361. //---------- End of function Bullet::hit_wall ----------//
  362. //--------- Begin of function Bullet::check_hit -------//
  363. // check if the bullet hit a target
  364. // return true if hit
  365. int Bullet::check_hit()
  366. {
  367. err_when(SCAN_RANGE != 5);
  368. short x,y;
  369. short townHit[SCAN_RANGE*SCAN_RANGE];
  370. short firmHit[SCAN_RANGE*SCAN_RANGE];
  371. int hitCount = 0;
  372. int townHitCount = 0;
  373. int firmHitCount = 0;
  374. for( int c = 0; c < SCAN_RANGE*SCAN_RANGE; ++c )
  375. {
  376. x = target_x_loc + spiral_x[c];
  377. y = target_y_loc + spiral_y[c];
  378. if( x >= 0 && x < world.max_x_loc && y >= 0 && y < world.max_y_loc )
  379. {
  380. Location *locPtr = world.get_loc(x, y);
  381. if(target_mobile_type==UNIT_AIR)
  382. {
  383. if(locPtr->has_unit(UNIT_AIR))
  384. {
  385. hit_target(x,y);
  386. hitCount++;
  387. }
  388. }
  389. else
  390. {
  391. if(locPtr->is_firm())
  392. {
  393. short firmRecno = locPtr->firm_recno();
  394. // check this firm has not been attacked
  395. short *firmHitPtr;
  396. for( firmHitPtr = firmHit+firmHitCount-1; firmHitPtr >= firmHit; --firmHitPtr )
  397. {
  398. if( *firmHitPtr == firmRecno )
  399. break;
  400. }
  401. if( firmHitPtr < firmHit ) // not found
  402. {
  403. firmHit[firmHitCount++] = firmRecno;
  404. hit_building(x,y);
  405. hitCount++;
  406. }
  407. }
  408. else if( locPtr->is_town() )
  409. {
  410. short townRecno = locPtr->town_recno();
  411. // check this town has not been attacked
  412. short *townHitPtr;
  413. for( townHitPtr = townHit+townHitCount-1; townHitPtr >= townHit; --townHitPtr )
  414. {
  415. if( *townHitPtr == townRecno )
  416. break;
  417. }
  418. if( townHitPtr < townHit ) // not found
  419. {
  420. townHit[townHitCount++] = townRecno;
  421. hit_building(x,y);
  422. hitCount++;
  423. }
  424. }
  425. else if(locPtr->is_wall())
  426. {
  427. hit_wall(x,y);
  428. hitCount++;
  429. }
  430. else
  431. {
  432. hit_target(x,y); // note: no error checking here because mobile_type should be taken into account
  433. hitCount++;
  434. }
  435. }
  436. }
  437. }
  438. return hitCount;
  439. }
  440. //--------- End of function Bullet::check_hit -------//
  441. //--------- Begin of function Bullet::warn_target -------//
  442. //
  443. // warn a unit before hit
  444. // return true if a unit is warned
  445. int Bullet::warn_target()
  446. {
  447. err_when(SCAN_RANGE != 5);
  448. short x,y;
  449. int warnCount = 0;
  450. for( int c = 0; c < SCAN_RANGE*SCAN_RANGE; ++c )
  451. {
  452. x = target_x_loc + spiral_x[c];
  453. y = target_y_loc + spiral_y[c];
  454. if( x >= 0 && x < world.max_x_loc && y >= 0 && y < world.max_y_loc )
  455. {
  456. Location *locPtr = world.get_loc(x, y);
  457. //char targetMobileType;
  458. //if( (targetMobileType = locPtr->has_any_unit()) != 0)
  459. //{
  460. // short unitRecno = locPtr->unit_recno(UNIT_LAND);
  461. short unitRecno = locPtr->unit_recno(target_mobile_type);
  462. if( !unit_array.is_deleted(unitRecno) )
  463. {
  464. Unit *unitPtr = unit_array[unitRecno];
  465. // ####### begin Gilbert 9/9 ########//
  466. if( attenuated_damage( unitPtr->cur_x, unitPtr->cur_y) > 0 )
  467. // ####### end Gilbert 9/9 ########//
  468. {
  469. warnCount++;
  470. switch(unitPtr->cur_action)
  471. {
  472. case SPRITE_IDLE:
  473. case SPRITE_READY_TO_MOVE:
  474. //case SPRITE_TURN:
  475. if( unitPtr->can_stand_guard() && !unitPtr->is_guarding() )
  476. {
  477. unitPtr->set_dir( (cur_dir + 4 ) & 7); // opposite direction of arrow
  478. unitPtr->set_guard_on();
  479. }
  480. break;
  481. case SPRITE_MOVE:
  482. if( unitPtr->can_move_guard() && !unitPtr->is_guarding()
  483. // ###### begin Gilbert 9/9 #######//
  484. && ( (unitPtr->cur_dir & 7)== ((cur_dir + 4 ) & 7)
  485. || (unitPtr->cur_dir & 7)== ((cur_dir + 5 ) & 7)
  486. || (unitPtr->cur_dir & 7)== ((cur_dir + 3 ) & 7)
  487. )
  488. )
  489. // ###### end Gilbert 9/9 #######//
  490. {
  491. unitPtr->set_guard_on();
  492. }
  493. break;
  494. #ifdef AMPLUS
  495. case SPRITE_ATTACK:
  496. if( unitPtr->can_attack_guard() && !unitPtr->is_guarding()
  497. && unitPtr->remain_attack_delay >= GUARD_COUNT_MAX
  498. && ( (unitPtr->cur_dir & 7)== ((cur_dir + 4 ) & 7)
  499. || (unitPtr->cur_dir & 7)== ((cur_dir + 5 ) & 7)
  500. || (unitPtr->cur_dir & 7)== ((cur_dir + 3 ) & 7)
  501. )
  502. )
  503. {
  504. unitPtr->set_guard_on();
  505. }
  506. break;
  507. #endif
  508. }
  509. }
  510. }
  511. //}
  512. }
  513. }
  514. return warnCount;
  515. }
  516. //--------- End of function Bullet::warn_target -------//
  517. //--------- Begin of function Bullet::display_layer -------//
  518. char Bullet::display_layer()
  519. {
  520. if( mobile_type == UNIT_AIR || target_mobile_type == UNIT_AIR )
  521. return 8;
  522. else
  523. return 1;
  524. }
  525. //--------- End of function Bullet::display_layer -------//
  526. //------- Begin of function Bullet::attenuated_damage -----//
  527. float Bullet::attenuated_damage(short curX, short curY)
  528. {
  529. short d = m.points_distance(curX, curY, target_x_loc * ZOOM_LOC_WIDTH, target_y_loc * ZOOM_LOC_HEIGHT);
  530. // damage drops from attack_damage to attack_damage/2, as range drops from 0 to damage_radius
  531. err_when(damage_radius == 0);
  532. if( d > damage_radius)
  533. return (float) 0;
  534. else
  535. //return ((attack_damage * (2*damage_radius-d) + 2*damage_radius-1)/ (2*damage_radius) ); // ceiling
  536. return attack_damage - attack_damage*d/(2*damage_radius);
  537. }
  538. //------- End of function Bullet::attenuated_damage -----//
  539. #ifdef DEBUG
  540. //------- Begin of function BulletArray::operator[] -----//
  541. Bullet* BulletArray::operator[](int recNo)
  542. {
  543. Bullet* bulletPtr = (Bullet*) get_ptr(recNo);
  544. if( !bulletPtr )
  545. err.run( "BulletArray[] is deleted" );
  546. return bulletPtr;
  547. }
  548. //--------- End of function BulletArray::operator[] ----//
  549. #endif