1 /*
2 Copyright (C) 2004 by James Gregory
3 Part of the GalaxyHack project
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY.
9
10 See the COPYING file for more details.
11 */
12
13 #include "Projectile.h"
14 #include "Globals.h"
15 #include "Group.h"
16 #include "Inlines.h"
17 #include "Random.h"
18
19 #include <stdexcept>
20 #include <cmath>
21
22 using std::runtime_error;
23
Projectile(float ix,float iy,CoordsInt target,WeaponType iType,Uint16 iColor)24 Projectile::Projectile(float ix, float iy, CoordsInt target, WeaponType iType, Uint16 iColor) {
25 if (weaponLookup[iType].category == WCAT_Twin)
26 hProj = new TwinLaserBolt(ix, iy, target, iType, iColor);
27
28 else if (weaponLookup[iType].category == WCAT_Small)
29 hProj = new SmallLaserBolt(ix, iy, target, iType, iColor);
30
31 else if (weaponLookup[iType].category == WCAT_Missile)
32 hProj = new Missile(ix, iy, target, iType);
33
34 else if (weaponLookup[iType].category == WCAT_Torpedo)
35 hProj = new Torpedo(ix, iy, target, iType);
36
37 else throw runtime_error("Projectile constructor didn't recognise iType");
38 }
39
Projectile(float ix,float iy)40 Projectile::Projectile(float ix, float iy) {
41 hProj = new LaserExplosion(ix, iy);
42 }
43
44 ////
45
Projectile_Base(float ix,float iy,CoordsInt target,WeaponType iType,Uint16 iColor)46 Projectile_Base::Projectile_Base(float ix, float iy, CoordsInt target, WeaponType iType, Uint16 iColor):
47 x(ix), y(iy), color(iColor), timer(frameCounter), myType(iType) {
48 targetSide = target.x;
49 targetGroup = target.y;
50
51 mySpeed = weaponLookup[myType].speed;
52 myLength = weaponLookup[myType].length;
53
54 sides[targetSide].groups[targetGroup].FiredAt(targetInfo);
55
56 targetUnit = targetInfo.whichUnit;
57
58 weHit = CheckToHit(weaponLookup[myType].accuracy, targetInfo.difficulty);
59 }
60
Projectile_Base(float ix,float iy)61 Projectile_Base::Projectile_Base(float ix, float iy):
62 x(ix), y(iy)
63 {}
64
PropsToSpeedAndLength(float dx,float dy)65 void Projectile_Base::PropsToSpeedAndLength(float dx, float dy) {
66 float propx;
67 float propy;
68
69 GetMoveProps(propx, propy, dx, dy);
70
71 //vital to do this properly, this caused a most annoying bug
72 float propz = propx*propx + propy*propy;
73 propz = std::sqrt(propz);
74 speedx = (propx / propz) * mySpeed;
75 speedy = (propy / propz) * mySpeed;
76
77 //this isn't quite right but who cares, we're in 3 dimensions, right?
78 //the real answer is:
79 //length in x = ((speed in x) / (speed in x + speed in y)) * length
80 lengthx = static_cast<int>(myLength * propx);
81 lengthy = static_cast<int>(myLength * propy);
82 }
83
StandardLineDraw()84 void Projectile_Base::StandardLineDraw() {
85 int x0 = static_cast<int>(x) - viewx;
86 int y0 = static_cast<int>(y) - viewy;
87 int x1 = static_cast<int>(x) + lengthx - viewx;
88 int y1 = static_cast<int>(y) + lengthy - viewy;
89 if (ClipLine(x0, y0, x1, y1))
90 DrawLine(x0, y0, x1, y1, color);
91 }
92
Move()93 bool Projectile_Base::Move() {
94 if (frameCounter - timer > duration) {
95 if (weHit)
96 sides[targetSide].groups[targetGroup].BeenHit(targetUnit, weaponLookup[myType].power);
97 return false;
98 }
99 else {
100 x += speedx;
101 y += speedy;
102
103 return true;
104 }
105 }
106
SetDuration(float distance)107 void Projectile_Base::SetDuration(float distance) {
108 //+1 because move (and hence erasure) comes before drawing
109 duration = static_cast<int>(((distance - myLength) / mySpeed) + 1);
110
111 //if we're right on top of them..
112 if (duration < 1) {
113 //right right on top of them, in which case we need
114 //to make up arbitrary lengths and speeds
115 if (speedx == 0 && speedy == 0) {
116 speedx = mySpeed / 2;
117 speedy = mySpeed / 2;
118 lengthx = myLength / 4;
119 lengthy = myLength / 4;
120 }
121
122 duration = 1;
123 }
124 }
125
126 ///
127
LaserBolt_Base(float ix,float iy,CoordsInt target,WeaponType iType,Uint16 iColor)128 LaserBolt_Base::LaserBolt_Base(float ix, float iy, CoordsInt target, WeaponType iType, Uint16 iColor):
129 Projectile_Base(ix, iy, target, iType, iColor) {
130 PredictTarget();
131 }
132
PredictTarget()133 void LaserBolt_Base::PredictTarget() {
134 /*
135 Another way to do this would be:
136 mx = m.x + c, so x = c / (m. - m)
137 with x being time
138
139 int time = distance / (laserSpeed - targetInfo.speed);
140
141 this must be done in each dimension, so:
142
143 int timex = dx / (laserSpeedx - targetInfo.speedx);
144 int timey = dy / (laserSpeedy - targetInfo.speedy);
145
146 watching out for division by 0 and/or negative values
147
148 However, we do not know the proportions of laserSpeed
149 in x and y, because that's what we're trying to work out!
150
151 For this to work, we'd also need to know the direction of
152 laserSpeed in each dimension, so we could deal with them
153 moving towards us
154
155
156 what we actually do is two iterations of where they will
157 be in the amount of time it takes us to reach them
158 */
159
160 float predx = targetInfo.currentx + targetInfo.weakSpot.x;
161 float predy = targetInfo.currenty + targetInfo.weakSpot.y;
162
163 float dx = predx - x;
164 float dy = predy - y;
165 float distance = FastDist(dx, dy);
166
167 float time = distance / mySpeed;
168
169 predx += targetInfo.speedx * time;
170 predy += targetInfo.speedy * time;
171
172 dx = predx - x;
173 dy = predy - y;
174 PropsToSpeedAndLength(dx, dy);
175
176 float totalDistance = FastDist(dx, dy);
177 SetDuration(totalDistance);
178 }
179
180 ///
181
SmallLaserBolt(float ix,float iy,CoordsInt target,WeaponType iType,Uint16 iColor)182 SmallLaserBolt::SmallLaserBolt(float ix, float iy, CoordsInt target, WeaponType iType, Uint16 iColor):
183 LaserBolt_Base(ix, iy, target, iType, iColor) {}
184
DrawSelfPixels()185 void SmallLaserBolt::DrawSelfPixels() {
186 StandardLineDraw();
187 }
188
189
190 ////
191
TwinLaserBolt(float ix,float iy,CoordsInt target,WeaponType iType,Uint16 iColor)192 TwinLaserBolt::TwinLaserBolt(float ix, float iy, CoordsInt target, WeaponType iType, Uint16 iColor):
193 LaserBolt_Base(ix, iy, target, iType, iColor) {}
194
DrawSelfPixels()195 void TwinLaserBolt::DrawSelfPixels() {
196 if (speedy > speedx) {
197 int x0 = static_cast<int>(x) - viewx - 3;
198 int y0 = static_cast<int>(y) - viewy;
199 int x1 = static_cast<int>(x) + lengthx - viewx - 3;
200 int y1 = static_cast<int>(y) + lengthy - viewy;
201
202 if (ClipLine(x0, y0, x1, y1))
203 DrawLine(x0, y0, x1, y1, color);
204
205 x0+= 6;
206 x1+= 6;
207
208 if (ClipLine(x0, y0, x1, y1))
209 DrawLine(x0, y0, x1, y1, color);
210 }
211 else {
212 int x0 = static_cast<int>(x) - viewx;
213 int y0 = static_cast<int>(y) - viewy - 3;
214 int x1 = static_cast<int>(x) + lengthx - viewx;
215 int y1 = static_cast<int>(y) + lengthy - viewy - 3;
216
217 if (ClipLine(x0, y0, x1, y1))
218 DrawLine(x0, y0, x1, y1, color);
219
220 y0+= 6;
221 y1+= 6;
222
223 if (ClipLine(x0, y0, x1, y1))
224 DrawLine(x0, y0, x1, y1, color);
225 }
226 }
227
228 ////
DrawBigLaser(int x0,int y0,int x1,int y1,Uint16 color)229 void Projectile_Base::DrawBigLaser(int x0, int y0, int x1, int y1, Uint16 color) {
230 x0-= viewx;
231 y0-= viewy;
232 x1-= viewx;
233 y1-= viewy;
234
235 if (ClipLine(x0, y0, x1, y1)) {
236 DrawLine(x0, y0, x1, y1, color);
237
238 //only have to cast immediately if not floats
239 float dx = x1 - x0;
240 float dy = y1 - y0;
241 float distance = FastDist(dx, dy);
242
243 float propx, propy;
244
245 //dont need the sign
246 if (distance) {
247 propx = fabs(dx) / distance;
248 propy = fabs(dy) / distance;
249 }
250
251 if (propy > propx) {
252 ++x0;
253 ++x1;
254
255 if (ClipLine(x0, y0, x1, y1))
256 DrawLine(x0, y0, x1, y1, color);
257
258 x0-= 2;
259 x1-= 2;
260
261 if (ClipLine(x0, y0, x1, y1))
262 DrawLine(x0, y0, x1, y1, color);
263 }
264 else {
265 ++y0;
266 ++y1;
267
268 if (ClipLine(x0, y0, x1, y1))
269 DrawLine(x0, y0, x1, y1, color);
270
271 y0-= 2;
272 y1-= 2;
273
274 if (ClipLine(x0, y0, x1, y1))
275 DrawLine(x0, y0, x1, y1, color);
276 }
277 }
278 }
279
280 ////
281
282
283
284 // this function clips the sent line
ClipLine(int & x1,int & y1,int & x2,int & y2)285 int Projectile_Base::ClipLine(int& x1, int& y1,int& x2, int& y2) {
286 //The screen dimensions to clip to
287 static const int min_clip_x = 0;
288 int max_clip_x = globalSettings.screenWidth - 1;
289 static const int min_clip_y = 0;
290 int max_clip_y = globalSettings.screenHeight - 1;
291
292 // internal clipping codes
293 #define CLIP_CODE_C 0x0000
294 #define CLIP_CODE_N 0x0008
295 #define CLIP_CODE_S 0x0004
296 #define CLIP_CODE_E 0x0002
297 #define CLIP_CODE_W 0x0001
298
299 #define CLIP_CODE_NE 0x000a
300 #define CLIP_CODE_SE 0x0006
301 #define CLIP_CODE_NW 0x0009
302 #define CLIP_CODE_SW 0x0005
303
304 int xc1=x1, yc1=y1, xc2=x2, yc2=y2;
305
306 int p1_code=0, p2_code=0;
307
308 // determine codes for p1 and p2
309 if (y1 < min_clip_y)
310 p1_code|=CLIP_CODE_N;
311 else if (y1 > max_clip_y)
312 p1_code|=CLIP_CODE_S;
313
314 if (x1 < min_clip_x)
315 p1_code|=CLIP_CODE_W;
316 else if (x1 > max_clip_x)
317 p1_code|=CLIP_CODE_E;
318
319 if (y2 < min_clip_y)
320 p2_code|=CLIP_CODE_N;
321 else if (y2 > max_clip_y)
322 p2_code|=CLIP_CODE_S;
323
324 if (x2 < min_clip_x)
325 p2_code|=CLIP_CODE_W;
326 else if (x2 > max_clip_x)
327 p2_code|=CLIP_CODE_E;
328
329 // try and trivially reject
330 if ((p1_code & p2_code))
331 return 0;
332
333 // test for totally visible, if so leave points untouched
334 if (p1_code==0 && p2_code==0)
335 return 1;
336
337 // determine end clip point for p1
338 switch(p1_code) {
339 case CLIP_CODE_C:
340
341 break;
342
343 case CLIP_CODE_N:
344 yc1 = min_clip_y;
345 xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
346 break;
347
348 case CLIP_CODE_S:
349 yc1 = max_clip_y;
350 xc1 = x1 + 0.5+(max_clip_y - y1)*(x2-x1)/(y2-y1);
351 break;
352
353 case CLIP_CODE_W:
354 xc1 = min_clip_x;
355 yc1 = y1 + 0.5+(min_clip_x - x1)*(y2-y1)/(x2-x1);
356 break;
357
358 case CLIP_CODE_E:
359 xc1 = max_clip_x;
360 yc1 = y1 + 0.5+(max_clip_x - x1)*(y2-y1)/(x2-x1);
361 break;
362
363 // these cases are more complex, must compute 2 intersections
364 case CLIP_CODE_NE:
365 // north hline intersection
366 yc1 = min_clip_y;
367 xc1 = x1 + 0.5+(min_clip_y - y1)*(x2 - x1)/(y2 - y1);
368
369 // test if intersection is valid, of so then done, else compute next
370 if (xc1 < min_clip_x || xc1 > max_clip_x) {
371 // east vline intersection
372 xc1 = max_clip_x;
373 yc1 = y1 + 0.5 + (max_clip_x - x1)*(y2 - y1)/(x2 - x1);
374 }
375 break;
376
377 case CLIP_CODE_SE:
378 // south hline intersection
379 yc1 = max_clip_y;
380 xc1 = x1 + 0.5 + (max_clip_y-y1) * (x2-x1) / (y2-y1);
381
382 // test if intersection is valid, of so then done, else compute next
383 if (xc1 < min_clip_x || xc1 > max_clip_x) {
384 // east vline intersection
385 xc1 = max_clip_x;
386 yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
387 }
388 break;
389
390 case CLIP_CODE_NW:
391 // north hline intersection
392 yc1 = min_clip_y;
393 xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
394
395 // test if intersection is valid, of so then done, else compute next
396 if (xc1 < min_clip_x || xc1 > max_clip_x) {
397 xc1 = min_clip_x;
398 yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
399 }
400 break;
401
402 case CLIP_CODE_SW:
403 // south hline intersection
404 yc1 = max_clip_y;
405 xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
406
407 // test if intersection is valid, of so then done, else compute next
408 if (xc1 < min_clip_x || xc1 > max_clip_x) {
409 xc1 = min_clip_x;
410 yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
411 }
412 break;
413 }
414
415 // determine clip point for p2
416 switch(p2_code) {
417 case CLIP_CODE_C:
418
419 break;
420
421 case CLIP_CODE_N:
422 yc2 = min_clip_y;
423 xc2 = x2 + (min_clip_y-y2)*(x1-x2)/(y1-y2);
424 break;
425
426 case CLIP_CODE_S: {
427 yc2 = max_clip_y;
428 xc2 = x2 + (max_clip_y-y2)*(x1-x2)/(y1-y2);
429 }
430 break;
431
432 case CLIP_CODE_W: {
433 xc2 = min_clip_x;
434 yc2 = y2 + (min_clip_x-x2)*(y1-y2)/(x1-x2);
435 }
436 break;
437
438 case CLIP_CODE_E: {
439 xc2 = max_clip_x;
440 yc2 = y2 + (max_clip_x-x2)*(y1-y2)/(x1-x2);
441 }
442 break;
443
444 // these cases are more complex, must compute 2 intersections
445 case CLIP_CODE_NE: {
446 // north hline intersection
447 yc2 = min_clip_y;
448 xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
449
450 // test if intersection is valid, of so then done, else compute next
451 if (xc2 < min_clip_x || xc2 > max_clip_x) {
452 // east vline intersection
453 xc2 = max_clip_x;
454 yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
455 } // end if
456
457 }
458 break;
459
460 case CLIP_CODE_SE: {
461 // south hline intersection
462 yc2 = max_clip_y;
463 xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);
464
465 // test if intersection is valid, of so then done, else compute next
466 if (xc2 < min_clip_x || xc2 > max_clip_x) {
467 // east vline intersection
468 xc2 = max_clip_x;
469 yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
470 } // end if
471
472
473 }
474 break;
475
476 case CLIP_CODE_NW: {
477 // north hline intersection
478 yc2 = min_clip_y;
479 xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);
480
481 // test if intersection is valid, of so then done, else compute next
482 if (xc2 < min_clip_x || xc2 > max_clip_x) {
483 xc2 = min_clip_x;
484 yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);
485 } // end if
486
487 }
488 break;
489
490 case CLIP_CODE_SW: {
491 // south hline intersection
492 yc2 = max_clip_y;
493 xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);
494
495 // test if intersection is valid, of so then done, else compute next
496 if (xc2 < min_clip_x || xc2 > max_clip_x) {
497 xc2 = min_clip_x;
498 yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);
499 } // end if
500
501 }
502 break;
503
504 default:break;
505
506 } // end switch
507
508 // do bounds check
509 if ((xc1 < min_clip_x) || (xc1 > max_clip_x) ||
510 (yc1 < min_clip_y) || (yc1 > max_clip_y) ||
511 (xc2 < min_clip_x) || (xc2 > max_clip_x) ||
512 (yc2 < min_clip_y) || (yc2 > max_clip_y) )
513 return 0;
514
515 // store vars back
516 x1 = xc1;
517 y1 = yc1;
518
519 x2 = xc2;
520 y2 = yc2;
521
522 return 1;
523 }
524
525
526 // this function draws a line from xo,yo to x1,y1 using differential error
527 // terms (based on Bresenahams work)
DrawLine(int x0,int y0,int x1,int y1,Uint16 color)528 void Projectile_Base::DrawLine(int x0, int y0, int x1, int y1, Uint16 color) {
529 int dx, // difference in x's
530 dy, // difference in y's
531 dx2, // dx,dy * 2
532 dy2,
533 x_inc, // amount in pixel space to move during drawing
534 y_inc, // amount in pixel space to move during drawing
535 error, // the discriminant i.e. error i.e. decision variable
536 index; // used for looping
537
538 static const int lpitch_2 = JSDL.screen->pitch >> 1; // Uint16 strided lpitch
539
540 // pre-compute first pixel address in video buffer based on 16bit data
541 Uint16* vb_start2 = reinterpret_cast<Uint16*>(JSDL.screen->pixels) + x0 + y0 * lpitch_2;
542
543 // compute horizontal and vertical deltas
544 dx = x1 - x0;
545 dy = y1 - y0;
546
547 // test which direction the line is going in i.e. slope angle
548 if (dx>=0)
549 x_inc = 1;
550 else {
551 x_inc = -1;
552 dx = -dx; // need absolute value
553 }
554
555 // test y component of slope
556 if (dy>=0)
557 y_inc = lpitch_2;
558 else {
559
560 y_inc = -lpitch_2;
561 dy = -dy; // need absolute value
562 }
563
564 //compute (dx,dy) * 2
565 dx2 = dx << 1;
566 dy2 = dy << 1;
567
568 //now based on which delta is greater we can draw the line
569 //if |slope| <= 1
570 if (dx > dy) {
571 // initialize error term
572 error = dy2 - dx;
573
574 // draw the line
575 for (index=0; index <= dx; index++) {
576 // set the pixel
577 *vb_start2 = color;
578
579 // test if error has overflowed
580 if (error >= 0) {
581 error-=dx2;
582
583 // move to next line
584 vb_start2+=y_inc;
585 }
586
587 // adjust the error term
588 error+=dy2;
589
590 // move to the next pixel
591 vb_start2+=x_inc;
592 }
593 }
594 else
595 //else |slope| > 1
596 {
597 // initialize error term
598 error = dx2 - dy;
599
600 // draw the line
601 for (index=0; index <= dy; index++) {
602 // set the pixel
603 *vb_start2 = color;
604
605 // test if error overflowed
606 if (error >= 0) {
607 error-=dy2;
608
609 // move to next line
610 vb_start2+=x_inc;
611 }
612
613 // adjust the error term
614 error+=dx2;
615
616 // move to the next pixel
617
618 vb_start2+=y_inc;
619 }
620 }
621 }
622
Missile(float ix,float iy,CoordsInt target,WeaponType iType)623 Missile::Missile(float ix, float iy, CoordsInt target, WeaponType iType):
624 Projectile_Base(ix, iy, target, iType, missileGrey), exploding(0), targetDead(0) {
625 //get it to sort out some props because it will be drawn before it first gets to move
626 Move();
627 x-= speedx;
628 y-= speedy;
629 }
630
Move()631 bool Missile::Move() {
632 if (exploding) {
633 if (weHit)
634 sides[targetSide].groups[targetGroup].BeenHit(targetUnit, weaponLookup[myType].power);
635 return false;
636 }
637
638 if (!targetDead) {
639 targetCoords = sides[targetSide].groups[targetGroup].GetUnitCenter(targetUnit);
640
641 if (!sides[targetSide].groups[targetGroup].GetUnitAlive(targetUnit)) {
642 targetCoords.x += Random() % static_cast<int>(mySpeed / 2) - static_cast<int>(mySpeed);
643 targetCoords.y += Random() % static_cast<int>(mySpeed / 2) - static_cast<int>(mySpeed);
644 targetDead = 1;
645 }
646 }
647
648 float dx = targetCoords.x - x;
649 float dy = targetCoords.y - y;
650 float distance = FastDist(dx, dy);
651
652 if (distance < weaponLookup[myType].speed)
653 exploding = true;
654
655 else {
656 PropsToSpeedAndLength(dx, dy);
657
658 x+= speedx;
659 y+= speedy;
660 }
661
662 return true;
663 }
664
DrawSelfPixels()665 void Missile::DrawSelfPixels() {
666 StandardLineDraw();
667 }
668
Torpedo(float ix,float iy,CoordsInt target,WeaponType iType)669 Torpedo::Torpedo(float ix, float iy, CoordsInt target, WeaponType iType):
670 Projectile_Base(ix, iy, target, iType, torpedoBlue), exploding(false) {
671 float dx = targetInfo.currentx + targetInfo.weakSpot.x - x;
672 float dy = targetInfo.currenty + targetInfo.weakSpot.y - y;
673 float distance = FastDist(dx, dy);
674
675 PropsToSpeedAndLength(dx, dy);
676
677 SetDuration(distance);
678 }
679
680
DrawSelfPixels()681 void Torpedo::DrawSelfPixels() {
682 if (exploding)
683 return;
684
685 int x0 = static_cast<int>(x) - viewx;
686 int y0 = static_cast<int>(y) - viewy;
687 int x1 = static_cast<int>(x) + lengthx - viewx;
688 int y1 = static_cast<int>(y) + lengthy - viewy;
689
690 if (ClipLine(x0, y0, x1, y1)) {
691 DrawLine(x0, y0, x1, y1, color);
692
693 //only have to cast immediately if not floats
694 float dx = x1 - x0;
695 float dy = y1 - y0;
696 float distance = FastDist(dx, dy);
697
698 float propx, propy;
699
700 //dont need the sign
701 if (distance) {
702 propx = fabs(dx) / distance;
703 propy = fabs(dy) / distance;
704 }
705
706 if (propy > propx) {
707 ++x0;
708 ++x1;
709
710 if (ClipLine(x0, y0, x1, y1))
711 DrawLine(x0, y0, x1, y1, color);
712 }
713 else {
714 ++y0;
715 ++y1;
716
717 if (ClipLine(x0, y0, x1, y1))
718 DrawLine(x0, y0, x1, y1, color);
719 }
720 }
721 }
722
Move()723 bool Torpedo::Move() {
724 if (exploding) {
725 if (explodeTimer)
726 --explodeTimer;
727 else
728 //already dealt damage
729 return false;
730 } else if (!Projectile_Base::Move()) {
731 exploding = true;
732 explodeTimer = explosionExplodeFrames * framesPerAnimFrame;
733 }
734
735 return true;
736 }
737
DrawSelfBitmap()738 void Torpedo::DrawSelfBitmap() {
739 if (exploding) {
740 SDL_Rect tempRect = {static_cast<int>(x) - viewx, static_cast<int>(y) - viewy, 0, 0};
741
742 if (explodeTimer > framesPerAnimFrame * 5)
743 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE1], tempRect);
744 else if (explodeTimer > framesPerAnimFrame * 4)
745 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE2], tempRect);
746 else if (explodeTimer > framesPerAnimFrame * 3)
747 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE3], tempRect);
748 else if (explodeTimer > framesPerAnimFrame * 2)
749 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE4], tempRect);
750 else if (explodeTimer > framesPerAnimFrame)
751 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE5], tempRect);
752 else
753 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE6], tempRect);
754 }
755 }
756
CheckToHit(int accuracy,int difficulty)757 bool Projectile_Base::CheckToHit(int accuracy, int difficulty) {
758 if (difficulty == 0)
759 return true;
760 else if (Random() % 100 + accuracy - difficulty > 99)
761 return true;
762 else
763 return false;
764 }
765
LaserExplosion(float ix,float iy)766 LaserExplosion::LaserExplosion(float ix, float iy):
767 Projectile_Base(ix, iy), explodeTimer(explosionExplodeFrames * framesPerAnimFrame)
768 {}
769
Move()770 bool LaserExplosion::Move() {
771 if (explodeTimer)
772 --explodeTimer;
773 else
774 return false;
775
776 return true;
777 }
778
DrawSelfBitmap()779 void LaserExplosion::DrawSelfBitmap() {
780 SDL_Rect tempRect = {static_cast<int>(x) - viewx, static_cast<int>(y) - viewy, 0, 0};
781
782 if (explodeTimer > framesPerAnimFrame * 5)
783 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE1], tempRect);
784 else if (explodeTimer > framesPerAnimFrame * 4)
785 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE2], tempRect);
786 else if (explodeTimer > framesPerAnimFrame * 3)
787 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE3], tempRect);
788 else if (explodeTimer > framesPerAnimFrame * 2)
789 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE4], tempRect);
790 else if (explodeTimer > framesPerAnimFrame)
791 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE5], tempRect);
792 else
793 JSDL.Blt(genPictures[GENPIC_SMSHEXPLODE6], tempRect);
794 }
795
796