OBULLETA.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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 : OBULLETA.CPP
  21. //Description : Object Bullet Array
  22. //Owner : Alex
  23. #include <OVGA.h>
  24. #include <OUNIT.h>
  25. #include <OBULLET.h>
  26. #include <OWORLD.h>
  27. #include <OTOWN.h>
  28. #include <OB_PROJ.h>
  29. #include <OB_HOMIN.h>
  30. #include <OB_FLAME.h>
  31. //--------- Begin of function BulletArray::BulletArray ---------//
  32. //
  33. // <int> initArraySize - the initial size of this array.
  34. //
  35. BulletArray::BulletArray(int initArraySize) : SpriteArray(initArraySize)
  36. {
  37. }
  38. //----------- End of function BulletArray::BulletArray -----------//
  39. //--------- Begin of function BulletArray::create_bullet ---------//
  40. //
  41. // return: <int> the recno of the bullet created.
  42. //
  43. int BulletArray::create_bullet(short spriteId, Bullet** bpp)
  44. {
  45. Bullet* bulletPtr;
  46. SpriteInfo *spriteInfo = sprite_res[spriteId];
  47. err_when(!spriteInfo);
  48. err_when(spriteInfo->sprite_type != 'B');
  49. switch(spriteInfo->sprite_sub_type)
  50. {
  51. case 0:
  52. case ' ':
  53. bulletPtr = new Bullet;
  54. break;
  55. case 'P':
  56. bulletPtr = new Projectile;
  57. break;
  58. case 'H':
  59. bulletPtr = new BulletHoming;
  60. break;
  61. case 'F':
  62. bulletPtr = new BulletFlame;
  63. break;
  64. default:
  65. err_here(); // undefined bullet type
  66. if( bpp )
  67. *bpp = NULL;
  68. return 0;
  69. }
  70. add(bulletPtr);
  71. if( bpp )
  72. *bpp = bulletPtr;
  73. return recno();
  74. }
  75. //----------- End of function BulletArray::create_bullet -----------//
  76. //--------- Begin of function BulletArray::bullet_class_size ---------//
  77. int BulletArray::bullet_class_size(int spriteId)
  78. {
  79. SpriteInfo *spriteInfo = sprite_res[spriteId];
  80. err_when(spriteInfo->sprite_type != 'B');
  81. switch(spriteInfo->sprite_sub_type)
  82. {
  83. case 0:
  84. case ' ':
  85. return sizeof(Bullet);
  86. case 'P':
  87. return sizeof(Projectile);
  88. case 'H':
  89. return sizeof(BulletHoming);
  90. case 'F':
  91. return sizeof(BulletFlame);
  92. default:
  93. err_here(); // undefined bullet type
  94. return 0;
  95. }
  96. }
  97. //----------- End of function BulletArray::bullet_class_size -----------//
  98. //--------- Begin of function BulletArray::bullet_path_possible ---------//
  99. // For default bullet:
  100. // if the bullet is not blocked by building in its path, this
  101. // function return 1 for success, otherwise return 0.
  102. // For projectile bullet:
  103. // always return 1
  104. //
  105. int BulletArray::bullet_path_possible(short startXLoc, short startYLoc, char attackerMobileType,
  106. short destXLoc, short destYLoc, char targetMobileType,
  107. char bulletSpeed, short bulletSpriteId)
  108. {
  109. if(attackerMobileType==UNIT_AIR || targetMobileType==UNIT_AIR)
  110. return 1;
  111. //-------- skip the checking for projectile -----------//
  112. SpriteInfo *spriteInfo = sprite_res[bulletSpriteId];
  113. if(spriteInfo->sprite_sub_type == 'P')
  114. return 1;
  115. err_when(spriteInfo->sprite_sub_type == 'P');
  116. //----------------------- define variables ---------------//
  117. int originX = startXLoc*ZOOM_LOC_WIDTH;
  118. int originY = startYLoc*ZOOM_LOC_HEIGHT;
  119. int goX = destXLoc*ZOOM_LOC_WIDTH;
  120. int goY = destYLoc*ZOOM_LOC_HEIGHT;
  121. int xStep = (goX - originX)/bulletSpeed;
  122. int yStep = (goY - originY)/bulletSpeed;
  123. int totalStep = max(1, max(abs(xStep), abs(yStep)));
  124. int curStep = 0;
  125. //------------------------------------------------------//
  126. // if the path of the bullet is blocked, return 0
  127. //------------------------------------------------------//
  128. int curX = originX + ZOOM_LOC_WIDTH/2;
  129. int curY = originY + ZOOM_LOC_HEIGHT/2;
  130. int curXLoc, curYLoc;
  131. Location *locPtr;
  132. while(curStep++<totalStep)
  133. {
  134. err_when(curStep > 200);
  135. curX += xStep;
  136. curY += yStep;
  137. curXLoc = curX/ZOOM_LOC_WIDTH;
  138. curYLoc = curY/ZOOM_LOC_HEIGHT;
  139. if(curXLoc==startXLoc && curYLoc==startYLoc)
  140. continue;
  141. if(curXLoc==destXLoc && curYLoc==destYLoc)
  142. break; // is destination
  143. locPtr = world.get_loc(curXLoc, curYLoc);
  144. //### begin alex 2/6 ###//
  145. //if(!locPtr->walkable(3) || locPtr->has_unit(UNIT_LAND) || locPtr->has_unit(UNIT_SEA))
  146. if(!locPtr->walkable(3))
  147. //#### end alex 2/6 ####//
  148. return 0;
  149. }
  150. return 1;
  151. }
  152. //----------- End of function BulletArray::bullet_path_possible -----------//
  153. //--------- Begin of function BulletArray::add_bullet_possible ---------//
  154. // call bullet_possible to check whether bullets emitted from this position
  155. // can reach the target location with blocking
  156. //
  157. // return 1 if bullets are able to reach the target location
  158. // return 0 if not
  159. //
  160. int BulletArray::add_bullet_possible(short startXLoc, short startYLoc, char attackerMobileType,
  161. short targetXLoc, short targetYLoc, char targetMobileType,
  162. short targetWidth, short targetHeight, short& resultXLoc, short& resultYLoc,
  163. char bulletSpeed, short bulletSpriteId)
  164. {
  165. resultXLoc = resultYLoc = -1;
  166. //----------------------------------------------------------------------//
  167. // for target with size 1x1
  168. //----------------------------------------------------------------------//
  169. if(targetWidth==1 && targetHeight==1)
  170. {
  171. if(bullet_path_possible(startXLoc, startYLoc, attackerMobileType, targetXLoc, targetYLoc, targetMobileType, bulletSpeed, bulletSpriteId))
  172. {
  173. resultXLoc = targetXLoc;
  174. resultYLoc = targetYLoc;
  175. return 1;
  176. }
  177. else
  178. return 0;
  179. }
  180. err_when(targetWidth==1 && targetHeight==1);
  181. //----------------------------------------------------------------------//
  182. // choose the closest corner to be the default attacking point of range attack
  183. //
  184. // generalized case for range-attack is coded below. Work for target with
  185. // size > 1x1
  186. //----------------------------------------------------------------------//
  187. //-------------- define parameters --------------------//
  188. short adjWidth = targetWidth-1; // adjusted width;
  189. short adjHeight = targetHeight-1; // adjusted height
  190. short xOffset=0, yOffset=0; // the 1st(default) location for range attack
  191. short atEdge = 0; // i.e. the attacking point is at the corner or edge of the target
  192. // 1 for at the edge, 0 for at corner
  193. //----------------------------------------------------------------------//
  194. // determine initial xOffset
  195. //----------------------------------------------------------------------//
  196. if(startXLoc <= targetXLoc)
  197. xOffset = 0; // the left hand side of the target
  198. else if(startXLoc >= targetXLoc+adjWidth)
  199. xOffset = adjWidth; // the right hand side of the target
  200. else
  201. {
  202. xOffset = startXLoc - targetXLoc; // in the middle(vertical) of the target
  203. atEdge++;
  204. }
  205. //----------------------------------------------------------------------//
  206. // determine initial yOffset
  207. //----------------------------------------------------------------------//
  208. if(startYLoc <= targetYLoc)
  209. yOffset = 0; // the upper of the target
  210. else if(startYLoc >= targetYLoc+adjHeight)
  211. yOffset = adjHeight;
  212. else
  213. {
  214. yOffset = startYLoc - targetYLoc; // in the middle(horizontal) of the target
  215. atEdge++;
  216. }
  217. //----------------------------------------------------------------------//
  218. // checking whether it is possible to add bullet
  219. //----------------------------------------------------------------------//
  220. if(bullet_path_possible(startXLoc, startYLoc, attackerMobileType, targetXLoc+xOffset, targetYLoc+yOffset, targetMobileType, bulletSpeed, bulletSpriteId))
  221. {
  222. resultXLoc = targetXLoc+xOffset;
  223. resultYLoc = targetYLoc+yOffset;
  224. return 1;
  225. }
  226. short leftXOffset, leftYOffset;
  227. short rightXOffset, rightYOffset;
  228. short leftX, leftY, rightX, rightY;
  229. short found=0; // found a location to attack the target and the path is not blocked
  230. short end=0;
  231. if(atEdge) // only check one edge of the target
  232. {
  233. if(xOffset==0 || xOffset==adjWidth) // horizontal edge
  234. {
  235. leftYOffset = rightYOffset = 0;
  236. leftXOffset = 1;
  237. rightXOffset = -1;
  238. }
  239. else if(yOffset==0 || yOffset==adjHeight) // vertical edge
  240. {
  241. leftXOffset = rightXOffset = 0;
  242. leftYOffset = 1;
  243. rightYOffset = -1;
  244. }
  245. else
  246. err_here(); // the sprite is within the target ???
  247. }
  248. else // at the corner, need to check two edges of the target
  249. {
  250. leftYOffset = rightXOffset = 0;
  251. leftXOffset = (xOffset==0) ? 1 : -1;
  252. rightYOffset = (yOffset==0) ? 1 : -1;
  253. }
  254. leftX = rightX = xOffset;
  255. leftY = rightY = yOffset;
  256. while(!found)
  257. {
  258. end = 0;
  259. //-------------------------------------------//
  260. // for the leftX, leftY
  261. //-------------------------------------------//
  262. leftX += leftXOffset;
  263. leftY += leftYOffset;
  264. if(leftX>=0 && leftX<targetWidth && leftY>=0 && leftY<targetHeight)
  265. {
  266. if(bullet_path_possible(startXLoc, startYLoc, attackerMobileType, targetXLoc+leftX, targetYLoc+leftY, targetMobileType, bulletSpeed, bulletSpriteId))
  267. {
  268. resultXLoc = targetXLoc+leftX;
  269. resultYLoc = targetYLoc+leftY;
  270. return 1;
  271. }
  272. }
  273. else
  274. end++;
  275. //-------------------------------------------//
  276. // for the rightX, rightY
  277. //-------------------------------------------//
  278. rightX += rightXOffset;
  279. rightY += rightYOffset;
  280. if(rightX>=0 && rightX<targetWidth && rightY>=0 && rightY<targetHeight)
  281. {
  282. if(bullet_path_possible(startXLoc, startYLoc, attackerMobileType, targetXLoc+rightX, targetYLoc+rightY, targetMobileType, bulletSpeed, bulletSpriteId))
  283. {
  284. resultXLoc = targetXLoc+rightX;
  285. resultYLoc = targetYLoc+rightY;
  286. return 1;
  287. }
  288. }
  289. else
  290. {
  291. if(end) // all locations have been checked, all are blocked
  292. return 0;
  293. }
  294. }
  295. return 0;
  296. }
  297. //----------- End of function BulletArray::add_bullet_possible -----------//
  298. //--------- Begin of function BulletArray::add_bullet ---------//
  299. // unit attacks unit by bullet
  300. //
  301. // <Unit*> parentUnit - pointer to the attacking target unit
  302. // <Unit*> targetUnit - pointer to the target unit
  303. //
  304. // return 1 if bullet is added successfully otherwise return 0.
  305. //
  306. short BulletArray::add_bullet(Unit* parentUnit, Unit* targetUnit)
  307. {
  308. //------------------------------------------------------//
  309. // define parameters
  310. //------------------------------------------------------//
  311. SpriteInfo *targetSpriteInfo = targetUnit->sprite_info;
  312. AttackInfo *attackInfo = parentUnit->attack_info_array+parentUnit->cur_attack;
  313. short attackXLoc = parentUnit->range_attack_x_loc;
  314. short attackYLoc = parentUnit->range_attack_y_loc;
  315. short targetXLoc = targetUnit->next_x_loc();
  316. short targetYLoc = targetUnit->next_y_loc();
  317. if(attackXLoc >= targetXLoc && attackXLoc < targetXLoc+targetSpriteInfo->loc_width &&
  318. attackYLoc >= targetYLoc && attackYLoc < targetYLoc+targetSpriteInfo->loc_height)
  319. {
  320. //-------------------------------------------------------//
  321. // the previous used range attack destination can be reused,
  322. // time is saved 'cos no need to check for bullet_path_possible()
  323. //-------------------------------------------------------//
  324. short bulletId = (parentUnit->attack_info_array+parentUnit->cur_attack)->bullet_sprite_id;
  325. Bullet* bulletPtr;
  326. create_bullet( bulletId, &bulletPtr);
  327. bulletPtr->init(BULLET_BY_UNIT, parentUnit->sprite_recno, attackXLoc, attackYLoc, targetUnit->mobile_type);
  328. err_when(parentUnit->cur_dir!=parentUnit->final_dir);
  329. //parentUnit->get_dir(parentUnit->next_x_loc(), parentUnit->next_y_loc(), attackXLoc, attackYLoc);
  330. return 1;
  331. }
  332. err_here();
  333. return 0;
  334. }
  335. //----------- End of function BulletArray::add_bullet -----------//
  336. //--------- Begin of function Bullet::add_bullet ---------//
  337. // Overload of add_bullet(), unit attack firm/town/wall
  338. //
  339. // <Unit*> parentUnit - pointer to the attacking target unit
  340. // <short> xLoc - the target upper left corner x loc
  341. // note: taregt can be firm, town or wall
  342. // <short> yLoc - the target upper left corner y loc
  343. //
  344. // return 1 if bullet is added successfully otherwise return 0.
  345. //
  346. // note: unit attacks firm or town by bullet will call this
  347. // function. The location of the firm or town is
  348. // specified by xLoc and yLoc.
  349. //
  350. short BulletArray::add_bullet(Unit* parentUnit, short xLoc, short yLoc)
  351. {
  352. //------------------------------------------------------//
  353. // define parameters
  354. //------------------------------------------------------//
  355. AttackInfo *attackInfo = parentUnit->attack_info_array+parentUnit->cur_attack;
  356. short attackXLoc = parentUnit->range_attack_x_loc;
  357. short attackYLoc = parentUnit->range_attack_y_loc;
  358. short targetXLoc = xLoc;
  359. short targetYLoc = yLoc;
  360. short width, height;
  361. Firm* targetFirm = NULL;
  362. Town* targetTown = NULL;
  363. FirmInfo* firmInfo = NULL;
  364. Location* locPtr = world.get_loc(xLoc, yLoc);
  365. if(locPtr->is_firm())
  366. {
  367. targetFirm = firm_array[locPtr->firm_recno()];
  368. firmInfo = firm_res[targetFirm->firm_id];
  369. width = firmInfo->loc_width;
  370. height = firmInfo->loc_height;
  371. }
  372. else if(locPtr->is_town())
  373. {
  374. targetTown = town_array[locPtr->town_recno()];
  375. width = targetTown->loc_width();
  376. height = targetTown->loc_height();
  377. }
  378. else if(locPtr->is_wall())
  379. width = height = 1;
  380. else
  381. err_here();
  382. if(attackXLoc >= targetXLoc && attackXLoc < targetXLoc+width &&
  383. attackYLoc >= targetYLoc && attackYLoc < targetYLoc+height)
  384. {
  385. //-------------------------------------------------------//
  386. // the previous used range attack destination can be reused,
  387. // time is saved 'cos no need to check for bullet_path_possible()
  388. //-------------------------------------------------------//
  389. short bulletId = (parentUnit->attack_info_array+parentUnit->cur_attack)->bullet_sprite_id;
  390. Bullet* bulletPtr;
  391. create_bullet( bulletId, &bulletPtr);
  392. bulletPtr->init(BULLET_BY_UNIT, parentUnit->sprite_recno, attackXLoc, attackYLoc, UNIT_LAND);
  393. err_when(parentUnit->cur_dir!=parentUnit->final_dir);
  394. //parentUnit->get_dir(parentUnit->next_x_loc(), parentUnit->next_y_loc(), attackXLoc, attackYLoc);
  395. return 1;
  396. }
  397. err_here();
  398. return 0;
  399. }
  400. //----------- End of function BulletArray::add_bullet -----------//
  401. //--------- Begin of function Bullet::add_bullet ---------//
  402. // Overload of add_bullet()
  403. //
  404. // <Unit*> parentFirm - pointer to the attacking target Firm
  405. // <Unit*> targetUnit - pointer to the target Unit
  406. //
  407. // return 1 if bullet is added successfully otherwise return 0.
  408. short BulletArray::add_bullet(Firm* parentFirm, Unit* targetUnit)
  409. {
  410. return 0;
  411. }
  412. //----------- End of function BulletArray::add_bullet -----------//
  413. //--------- Begin of function Bullet::add_bullet ---------//
  414. // Overload of add_bullet()
  415. //
  416. // <Unit*> parentFirm - pointer to the attacking target Firm
  417. // <Unit*> targetFirm - pointer to the target Firm
  418. //
  419. // return 1 if bullet is added successfully otherwise return 0.
  420. short BulletArray::add_bullet(Firm* parentFirm, Firm* targetFirm)
  421. {
  422. return 0;
  423. }
  424. //----------- End of function BulletArray::add_bullet -----------//