comparison src/weapons.c @ 9:331055a97a9d

Initial revision
author darius
date Sat, 06 Dec 1997 04:37:05 +0000
parents
children ed82a42ba89d
comparison
equal deleted inserted replaced
8:0836fb919dfa 9:331055a97a9d
1 /*--------------------------------------------------------------------------
2 NETREK II -- Paradise
3
4 Permission to use, copy, modify, and distribute this software and its
5 documentation, or any derivative works thereof, for any NON-COMMERCIAL
6 purpose and without fee is hereby granted, provided that this copyright
7 notice appear in all copies. No representations are made about the
8 suitability of this software for any purpose. This software is provided
9 "as is" without express or implied warranty.
10
11 Xtrek Copyright 1986 Chris Guthrie
12 Netrek (Xtrek II) Copyright 1989 Kevin P. Smith
13 Scott Silvey
14 Paradise II (Netrek II) Copyright 1993 Larry Denys
15 Kurt Olsen
16 Brandon Gillespie
17 --------------------------------------------------------------------------*/
18
19 #include "config.h"
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <math.h>
25 #include <setjmp.h>
26
27 #include "defs.h"
28 #include "struct.h"
29 #include "data.h"
30 #include "daemonII.h"
31 #include "weapons.h"
32 #include "shmem.h"
33
34
35
36 /*------------------------------VISIBLE FUNCTIONS-------------------------*/
37
38 /*---------------------------------HOSTILE_TO-----------------------------*/
39 /*
40 * This returns whether an object is hostile to another object. It returns 1
41 * if we are hostile or at war with the object
42 */
43
44
45 extern int inflict_damage();
46 int torp_track_opportunity();
47 extern void move_torp();
48 extern void move_missile();
49
50 int
51 hostile_to(warmask, team, pl)
52 int warmask, team;
53 struct player *pl;
54 {
55 return (warmask & pl->p_team) || (team & (pl->p_swar | pl->p_hostile));
56 }
57
58
59
60
61 /*----------------------------------EXPLODE-------------------------------*/
62 /*
63 * This function decides which players to inflict damage on when a torp
64 * explodes.
65 */
66
67 void
68 explode_damage(torp, radius, why)
69 struct basetorp *torp;
70 int radius;
71 int why;
72 {
73 register int i; /* looping var */
74 int dx, dy, dist; /* to calc distance from torp to players */
75 int damage; /* to hold damage inflicted */
76 register struct player *j; /* to point to players */
77
78 for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++)
79 {
80 if (j->p_status != PALIVE) /* no need to check players not alive */
81 continue;
82
83 if (j->p_no == torp->bt_owner) /* General Vote, September, 1995. */
84 continue; /* Torps no longer damage owner. */
85
86 if ((torp->bt_status == TDET) /* if torp was detted then */
87 && ((j->p_no == torp->bt_owner) || /* cannot damage firing
88 * player */
89 ((j->p_no != torp->bt_whodet) /* cannot damage players on
90 * same team */
91 && (j->p_team == players[torp->bt_whodet].p_team)))
92 ) /* except the detter */
93 continue;
94
95 dx = torp->bt_x - j->p_x; /* calc delta x and y */
96 dy = torp->bt_y - j->p_y;
97 if (ABS(dx) > radius || ABS(dy) > radius)
98 continue; /* continue if obviously too far */
99
100 dist = dx * dx + dy * dy; /* calc distnace squared */
101 if (dist > radius * radius) /* if not within damage distance */
102 continue; /* then continue */
103 if (dist > EXPDIST * EXPDIST) /* if not direct hit */
104 damage = torp->bt_damage * (radius - sqrt((double) dist)) /
105 (radius - EXPDIST);
106 else /* else if direct hit */
107 damage = torp->bt_damage; /* do torp damage */
108
109 if (damage > 0)
110 { /* if damage was done then */
111 if (players[torp->bt_owner].p_hostile & j->p_team) /* start war if */
112 players[torp->bt_owner].p_swar |= j->p_team; /* necessary */
113 inflict_damage(&players[torp->bt_owner], &players[torp->bt_whodet],
114 j, damage, why);
115 }
116 }
117 }
118
119 void
120 explode(torp)
121 struct basetorp *torp; /* pointer to exploding torp's struct */
122 {
123 explode_damage(torp, DAMDIST, KTORP);
124 torp->bt_status = TEXPLODE; /* set the torp to explode */
125 torp->bt_fuse = 10 / TORPFUSE;
126 }
127
128
129
130
131 /*---------------------------------PEXPLODE-------------------------------*/
132 /*
133 * This function does the explosion of a plasma torp. It goes through all
134 * players and damages them if they are close enough to get damaged
135 */
136
137 void
138 pexplode(plasmatorp)
139 struct plasmatorp *plasmatorp;/* ptr to plasma to explode */
140 {
141 explode_damage(&plasmatorp->pt_base, PLASDAMDIST, KPLASMA);
142 plasmatorp->pt_status = PTEXPLODE; /* set the plasma to explode */
143 plasmatorp->pt_fuse = 10 / PLASMAFUSE;
144 }
145
146
147
148
149 /*-------------------------------UDPHASER----------------------------------*/
150 /*
151 * This function goes through all players and calcs the damage from a phaser
152 * hit if the phaser hit a target.
153 */
154
155 void
156 udphaser()
157 {
158 register int i; /* looping var */
159 register struct phaser *j; /* to point to phaser being fired */
160 register struct player *victim; /* to point to the poor victim */
161
162 for (i = 0, j = &phasers[i]; i < MAXPLAYER; i++, j++)
163 { /* all players */
164 switch (j->ph_status)
165 { /* check player's phaser status */
166 case PHFREE: /* if not beging fired */
167 continue; /* then continue */
168 case PHMISS: /* if it missed */
169 case PHHIT2: /* or ????? */
170 if (j->ph_fuse-- == 1) /* dec count of phaser */
171 j->ph_status = PHFREE; /* free it up if count done */
172 break;
173 case PHHIT: /* if it hit someone then */
174 if (j->ph_fuse-- == players[i].p_ship.s_phaser.fuse)
175 {
176 victim = &players[j->ph_target]; /* get the victim */
177 if (players[i].p_hostile & victim->p_team) /* start war if */
178 players[i].p_swar |= victim->p_team; /* necessary */
179 if (victim->p_status == PALIVE) /* only damage if alive */
180 inflict_damage(&players[i], 0, victim, j->ph_damage, KPHASER);
181 } /* end of if phaser hit someone */
182 if (j->ph_fuse == 0)
183 j->ph_status = PHFREE;
184 break;
185 } /* end of switch */
186 } /* end of for loop through players */
187 }
188
189
190
191 /*----------------------------WEAP_NEAR_OBJECT-----------------------------*/
192 /* This function checks for objects within *dist* of a weapon. */
193 /* this function will use the space grid */
194
195 int
196 weap_near_object(torp, type, dist)
197 struct basetorp *torp;
198 int type;
199 int dist;
200 {
201 register struct planet *pl; /* to point to the planets */
202 int dx, dy, i;
203
204 for (i = 0, pl = &planets[i]; i < NUMPLANETS; i++, pl = &planets[i])
205 {
206 if (PL_TYPE(*pl) != type)
207 /* if not of the type specified, don't bother */
208 continue;
209 dx = torp->bt_x - pl->pl_x;
210 dy = torp->bt_y - pl->pl_y;
211 if (ABS(dx) > dist || ABS(dy) > dist)
212 continue; /* the obvious thing */
213 if (dx * dx + dy * dy < dist * dist)
214 return 1; /* yep, it hit. return a 1. */
215 }
216 return 0; /* return that it should continue */
217 }
218
219
220 #if 0 /* I think this is now unused */
221 /*----------------------------------NEAR----------------------------------*/
222 /*
223 * This function checks to see if a player is close enough to a torp for the
224 * torp to explode on. This function returns a 1 if the torp should explode
225 * and a zero if not.
226 */
227
228 int
229 near(torp)
230 struct torp *torp; /* the torp to check for */
231 {
232 #if 1
233 return near_player(&torp->t_base, EXPDIST);
234 #else
235 register int i; /* looping var */
236 int dx, dy; /* to calc torp-player distance */
237 register struct player *j; /* to point to players */
238
239 for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++)
240 {
241 if (j->p_status != PALIVE)
242 continue; /* don't check players not alive */
243 if (j->p_no == torp->t_owner)
244 continue; /* no exploding on self */
245 if (!hostile_to(torp->t_war, torp->t_team, j))
246 continue; /* disregard if both teams not at war */
247 dx = torp->t_x - j->p_x; /* calc delta coords */
248 dy = torp->t_y - j->p_y;
249 if (ABS(dx) > EXPDIST || ABS(dy) > EXPDIST)
250 continue; /* disregard if obviously too far */
251 if (dx * dx + dy * dy < EXPDIST * EXPDIST)
252 return 1; /* if close enough to explode then return 1 */
253 }
254 return 0; /* return that torp should continue */
255 #endif
256 }
257 #endif
258
259 int
260 near_player(torp, dist)
261 struct basetorp *torp; /* the torp to check for */
262 int dist;
263 {
264 register int i; /* looping var */
265 int dx, dy; /* to calc torp-player distance */
266 register struct player *j; /* to point to players */
267
268 for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++)
269 {
270 if (j->p_status != PALIVE)
271 continue; /* don't check players not alive */
272 if (j->p_no == torp->bt_owner)
273 continue; /* no exploding on self */
274 if (!hostile_to(torp->bt_war, torp->bt_team, j))
275 continue; /* disregard if both teams not at war */
276 dx = torp->bt_x - j->p_x; /* calc delta coords */
277 dy = torp->bt_y - j->p_y;
278 if (ABS(dx) > dist || ABS(dy) > dist)
279 continue; /* disregard if obviously too far */
280 if (dx * dx + dy * dy < dist * dist)
281 {
282 torp->bt_whodet = i; /* this guy is the detonator */
283 return 1; /* if close enough to explode then return 1 */
284 }
285 }
286 return 0; /* return that torp should continue */
287 }
288
289
290 int
291 f_land(mis) /* the fighter landing function */
292 struct missile *mis; /* the fighter to check for */
293 {
294 int dx, dy; /* to calc fighter-player distance */
295 register struct player *j; /* to point to players */
296
297 j = &players[mis->ms_owner];
298
299 if (!(j->p_armies < j->p_ship.s_maxarmies))
300 return 0; /* no room! */
301 dx = mis->ms_x - j->p_x; /* calc delta coords */
302 dy = mis->ms_y - j->p_y;
303 if (ABS(dx) > EXPDIST || ABS(dy) > EXPDIST)
304 return 0; /* obviously too far */
305 if (dx * dx + dy * dy < EXPDIST * EXPDIST)
306 return 1; /* if close enough to land then return 1 */
307
308 return 0; /* return that fighter should continue */
309 }
310
311
312 /*----------------------------------PNEAR----------------------------------*/
313 /*
314 * This function goes through the players and sees if there is a player close
315 * enough for a plasma torp to explode on. This function returns a 1 if the
316 * plasma should explode and a 0 if it should continue to travel through
317 * spac.
318 */
319
320 int
321 pnear(plasmatorp)
322 struct plasmatorp *plasmatorp;/* the plasma torp to check for */
323 {
324 #if 1
325 return near_player(&plasmatorp->pt_base, EXPDIST);
326 #else
327 register int i; /* looping var */
328 int dx, dy; /* to calc distances with */
329 register struct player *j; /* to point to players */
330 /* fprintf(stderr, "ENTERING PNEAR\n"); */
331 for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++)
332 {
333 if (!(j->p_status == PALIVE))
334 continue; /* don't check players not alive */
335 if (plasmatorp->pt_owner == j->p_no)
336 continue; /* no exploding on self */
337 if (!hostile_to(plasmatorp->pt_war, plasmatorp->pt_team, j))
338 continue; /* disregard if both teams not at war */
339 dx = plasmatorp->pt_x - j->p_x; /* calc delta coords */
340 dy = plasmatorp->pt_y - j->p_y;
341 /* fprintf(stderr, "ENTERING UDORPS #1\n"); */
342 if (ABS(dx) > EXPDIST || ABS(dy) > EXPDIST)
343 continue; /* disregard if obviously too far */
344 /* fprintf(stderr, "ENTERING UDORPS #2\n"); */
345 if (dx * dx + dy * dy < EXPDIST * EXPDIST)
346 return 1; /* if close enough to explode then return 1 */
347 /* fprintf(stderr, "ENTERING UDORPS #3\n"); */
348 }
349 return 0; /* return that plasma torp should continue */
350 #endif
351 }
352
353
354 int
355 outofbounds(x, y)
356 int x, y;
357 {
358 return x < 0 || x > GWIDTH || y < 0 || y > GWIDTH;
359 }
360
361 /*--------------------------------UDTORPS----------------------------------*/
362 /*
363 * This function updates the torps. It goes through all torps and checks to
364 * see if they need to be updated. It they are mving they track toward the
365 * nearest target. this function also handles the explosion and makes sure
366 * that torps do not go off the edge of the galaxy.
367 */
368
369 void
370 udtorps()
371 {
372 register int i; /* looping var--to loop through torps */
373 int turn; /* to get whether to go right or left */
374 int heading; /* to hold torps heading */
375 register struct torp *j; /* to point to torps */
376
377 for (i = 0, j = &torps[i]; i < MAXPLAYER * MAXTORP; i++, j++)
378 {
379 switch (j->t_status)
380 { /* check status of torp */
381 case TFREE: /* if torp not active then */
382 continue; /* go on to next torp */
383 case TMOVE:
384 case TSTRAIGHT: /* if torp moving then */
385 if (j->t_turns > 0)
386 { /* if torp can turn then */
387 turn = torp_track_opportunity
388 (&j->t_base, j->t_turns,
389 configvals->improved_tracking[SS_PHOTON]);
390 /* should we go right or left */
391 if (turn < 0)
392 { /* we will go left */
393 heading = ((int) j->t_dir) - j->t_turns; /* turn left */
394 if (heading < 0)
395 j->t_dir = heading + 256;
396 /*
397 * j->t_dir = ((heading < 0) ? ((unsigned char) (256 + heading)) :
398 * ((unsigned char) heading)); * no underflow
399 */
400 }
401 else if (turn > 0)
402 { /* we will go right */
403 heading = ((int) j->t_dir) + j->t_turns; /* turn right */
404 if (heading > 255)
405 j->t_dir = heading - 256;
406 /*
407 * j->t_dir = ((heading > 255) ? ((unsigned char) (heading - 256))
408 * : ((unsigned char) heading)); * no overflow
409 */
410 }
411 }
412 j->t_x += (double) j->t_speed * Cos[j->t_dir] * WARP1;
413 j->t_y += (double) j->t_speed * Sin[j->t_dir] * WARP1;
414
415 #if 0
416 if (outofbounds(j->t_x, j->t_y))
417 { /* hit top wall? */
418 j->t_status = TEXPLODE; /* so you cannot wall kill */
419 j->t_whodet = j->t_owner;
420 /* explode(&j->t_base); eliminate self wallkills */
421 break; /* done with this torp */
422 }
423 #endif
424
425 move_torp(i, j->t_x, j->t_y, 1);
426
427 if (j->t_status == TMOVE) /* if a TMOVE torp then */
428 j->t_dir += (lrand48() % 3) - 1; /* make the torp wobble */
429 if (j->t_fuse-- <= 0)
430 { /* dec torp's life and see if dead */
431 j->t_status = TFREE; /* dead, free the torp */
432 move_torp(i, -1, -1, 1);
433 players[j->t_owner].p_ntorp--; /* let player fire another */
434 break; /* no more torp processing */
435 }
436 if ((sun_effect[SS_PHOTON] && weap_near_object(&j->t_base, PLSTAR, ORBDIST))
437 ||
438 (wh_effect[SS_PHOTON] && weap_near_object(&j->t_base, PLWHOLE, ORBDIST)))
439 {
440 /* did it hit a star or wormhole? */
441 j->t_whodet = j->t_owner;
442 explode(&j->t_base);
443 break;
444 }
445
446 if ((terrain_grid[(int) (j->t_x) / TGRID_GRANULARITY * TGRID_SIZE +
447 (int) (j->t_y) / TGRID_GRANULARITY].types
448 & T_ASTEROIDS) &&
449 ast_effect[SS_PHOTON])
450 if (TORP_HIT_AST > (lrand48() % 100))
451 {
452 explode(&j->t_base);
453 break;
454 }
455
456 if (near_player(&j->t_base, EXPDIST))
457 {
458 /* if torp near enough to hit */
459 explode(&j->t_base); /* let torp explode on player */
460 }
461
462 break;
463 case TDET: /* if torp was detted */
464 explode(&j->t_base); /* make it explode */
465 break; /* on to next torp */
466 case TEXPLODE: /* if torp exploding */
467 if (j->t_fuse-- <= 0)
468 { /* dec explosion timer */
469 j->t_status = TFREE; /* if torp done, free it up */
470 move_torp(i, -1, -1, 1);
471 players[j->t_owner].p_ntorp--; /* let player fire another */
472 }
473 break; /* on to next torp */
474 case TOFF:
475 j->t_status = TFREE;
476 move_torp(i, -1, -1, 1);
477 players[j->t_owner].p_ntorp--;
478 break;
479 default: /* Shouldn't happen */
480 j->t_status = TFREE;
481 break;
482 } /* end of switch */
483 } /* end of for */
484 }
485
486 void
487 udmissiles()
488 {
489 int i;
490 int x, y, turn;
491 struct missile *mis;
492 struct player *j;
493
494 for (i = 0; i < MAXPLAYER * NPTHINGIES; i++)
495 {
496 mis = &missiles[i];
497 switch (mis->ms_status)
498 {
499 case TFREE:
500 break;
501 case TLAND:
502 j = &players[mis->ms_owner];
503 j->p_ship.s_missilestored++;
504 j->p_armies = (int) (j->p_ship.s_missilestored / FAE_RATE);
505 mis->ms_status = TFREE;
506 j->p_nthingys--;
507 break;
508 #if 0
509 case TRETURN:
510 j = &players[mis->ms_owner];
511 if (!(j->p_ship.s_nflags & SFNHASFIGHTERS))
512 {
513 mis->ms_type = MISSILETHINGY; /* If the player no longer has em, */
514 mis->ms_status = TMOVE; /* make his fighters kamikazes */
515 mis->fi_hasfired = 0;
516 break;
517 }
518
519
520 if (mis->ms_fuse-- <= 0)
521 {
522 mis->ms_status = TFREE;
523 move_missile(i, -1, -1, 1);
524 break;
525 }
526
527 if (((sun_effect[SS_MISSILE] && mis->ms_type == MISSILETHINGY
528 || sun_effect[SS_FIGHTER] && mis->ms_type == FIGHTERTHINGY)
529 && weap_near_object(&mis->ms_base, PLSTAR, ORBDIST)) ||
530 ((wh_effect[SS_MISSILE] && mis->ms_type == MISSILETHINGY
531 || wh_effect[SS_FIGHTER] && mis->ms_type == FIGHTERTHINGY)
532 && weap_near_object(&mis->ms_base, PLWHOLE, ORBDIST)))
533 {
534 /* did it hit a star or wormhole? */
535 explode(&mis->ms_base);
536 break;
537 }
538 if (mis->ms_turns > 0)
539 {
540 turn = fighter_track_target(&mis->ms_base, mis->ms_turns);
541 mis->ms_dir = (unsigned char) (mis->ms_dir + turn * mis->ms_turns);
542 }
543 x = mis->ms_x + mis->ms_speed * Cos[mis->ms_dir] * WARP1;
544 y = mis->ms_y + mis->ms_speed * Sin[mis->ms_dir] * WARP1;
545 move_missile(i, x, y, 1);
546
547 if (mis->ms_fuse-- <= 0)
548 {
549 mis->ms_status = TFREE;
550 move_missile(i, -1, -1, 1);
551 }
552 else if (f_land(mis))
553 {
554 mis->ms_status = TLAND;
555 move_missile(i, -1, -1, 1);
556 }
557 break;
558 #endif
559 case TRETURN:
560 case TMOVE:
561 case TSTRAIGHT:
562
563 if (mis->ms_fuse-- <= 0)
564 {
565 mis->ms_status = TFREE;
566 move_missile(i, -1, -1, 1);
567 break;
568 }
569
570 if (terrain_grid[(int) (mis->ms_x) / TGRID_GRANULARITY * TGRID_SIZE +
571 (int) (mis->ms_y) / TGRID_GRANULARITY].types
572 & T_ASTEROIDS)
573 if ((mis->ms_type == FIGHTERTHINGY) &&
574 ast_effect[SS_FIGHTER] &&
575 (FIGHTER_HIT_AST > (lrand48() % 100)))
576 {
577 mis->ms_whodet = mis->ms_owner;
578 explode(&mis->ms_base);
579 break;
580 }
581 else if ((MISSILE_HIT_AST > (lrand48() % 100)) &&
582 ast_effect[SS_MISSILE])
583 {
584 mis->ms_whodet = mis->ms_owner;
585 explode(&mis->ms_base);
586 break;
587 }
588
589 if ((((sun_effect[SS_MISSILE] && mis->ms_type == MISSILETHINGY)
590 || (sun_effect[SS_FIGHTER] && mis->ms_type == FIGHTERTHINGY))
591 && weap_near_object(&mis->ms_base, PLSTAR, ORBDIST))
592 ||
593 (((wh_effect[SS_MISSILE] && mis->ms_type == MISSILETHINGY)
594 || (wh_effect[SS_FIGHTER] && mis->ms_type == FIGHTERTHINGY))
595 && weap_near_object(&mis->ms_base, PLWHOLE, ORBDIST)))
596 {
597 /* did it hit a star? */
598 explode(&mis->ms_base);
599 break;
600 }
601
602 j = &players[mis->ms_owner];
603
604 if (mis->ms_type == FIGHTERTHINGY &&
605 !(j->p_ship.s_nflags & SFNHASFIGHTERS))
606 {
607 mis->ms_type = MISSILETHINGY; /* If the player no longer has em, */
608 mis->ms_status = TMOVE; /* make his fighters kamikazes */
609 mis->fi_hasfired = 0;
610 break;
611 }
612
613 if ((mis->ms_type == FIGHTERTHINGY)
614 && ((mis->ms_fuse < .6 * j->p_ship.s_missile.fuse)
615 || (mis->fi_hasfired))
616 && mis->ms_status != TRETURN)
617 mis->ms_status = TRETURN;
618
619 if (mis->ms_turns > 0)
620 {
621 if (mis->ms_type == FIGHTERTHINGY)
622 {
623 turn = fighter_track_target(&mis->ms_base, mis->ms_turns);
624 }
625 else
626 {
627 turn = torp_track_opportunity
628 (&mis->ms_base, mis->ms_turns,
629 configvals->improved_tracking[SS_MISSILE]);
630 }
631 mis->ms_dir = (unsigned char) (mis->ms_dir + turn * mis->ms_turns);
632 }
633 x = mis->ms_x + mis->ms_speed * Cos[mis->ms_dir] * WARP1;
634 y = mis->ms_y + mis->ms_speed * Sin[mis->ms_dir] * WARP1;
635
636 #if 0
637 if (outofbounds(x, y))
638 {
639 explode(&mis->ms_base);
640 break;
641 }
642 #endif
643
644 move_missile(i, x, y, 1);
645
646 if (mis->ms_status != TSTRAIGHT)
647 mis->ms_dir += (lrand48() % 3) - 1;
648
649 if (mis->ms_type == MISSILETHINGY
650 && near_player(&mis->ms_base, EXPDIST))
651 {
652 explode(&mis->ms_base);
653 }
654 else if (mis->ms_type == FIGHTERTHINGY
655 && near_player(&mis->ms_base, FSTRIKEDIST)
656 && !mis->fi_hasfired)
657 {
658 if (f_torp(mis))
659 mis->fi_hasfired = 1; /* if within strike range, fire a torp */
660 }
661
662 if (mis->ms_status == TRETURN &&
663 f_land(mis))
664 {
665 mis->ms_status = TLAND;
666 move_missile(i, -1, -1, 1);
667 }
668
669 break;
670
671 case TDET:
672 explode(&mis->ms_base);
673 break;
674
675 case TEXPLODE:
676 if (mis->ms_fuse-- <= 0)
677 {
678 mis->ms_status = TFREE;
679 players[mis->ms_owner].p_nthingys--;
680 move_missile(i, -1, -1, 1);
681 }
682 break;
683 default:
684 mis->ms_status = TFREE;
685 break;
686 }
687 }
688 }
689
690 int
691 anticipate_impact(w, dx, dy, s, dir)
692 int w; /* speed of torp */
693 int dx, dy; /* distance to target */
694 int s, dir; /* speed of target */
695 {
696 float sdx, sdy;
697 float a, b, c, d;
698 float t;
699 float tdx, tdy;
700 float theta;
701
702 #if 1 /* mathematically, these affect t, but not
703 * the return value */
704 s *= WARP1 * TICKSPERSEC;
705 w *= WARP1 * TICKSPERSEC;
706 #endif
707
708 sdx = s * Cos[dir];
709 sdy = s * Sin[dir];
710
711 a = s * (float) s - w * (float) w;
712 b = 2 * (sdx * (float) dx + sdy * (float) dy);
713 c = dx * (float) dx + dy * (float) dy;
714
715 if (a == 0)
716 {
717 t = -c / b;
718 }
719 else
720 {
721
722 d = b * b - 4 * a * c;
723 if (d < 0)
724 return -1;
725 d = sqrt(d);
726
727 if (a < 0)
728 {
729 a = -a;
730 b = -b;
731 }
732
733 t = (-b - d) / (2 * a);
734
735 if (t < 0)
736 t = (-b + d) / (2 * a);
737 }
738
739 if (t < 0)
740 return -1;
741
742 if (t > 10)
743 return -1;
744
745 tdx = dx / t + sdx;
746 tdy = dy / t + sdy;
747
748 theta = atan2(tdx, -tdy);
749 return (unsigned char) (int) (theta * 128 / 3.14159);
750 }
751
752 /*----------------------------TORP_TRACK_OPPORTUNITY----------------------*/
753 /*
754 * This function finds the closest ship to a torp and returns -1 if the ship
755 * is to the left of the torp on its current heading and a 1 if the ship is
756 * to the right. If no target is found then a 0 is return indicating the
757 * torp should go straight.
758 */
759
760 int
761 torp_track_opportunity(torp, turnspeed, smart)
762 struct basetorp *torp; /* the torp to check for */
763 int turnspeed;
764 int smart; /* which tracking algorithm? */
765 {
766 int i; /* looping var */
767 int closest; /* to hold closest player */
768 int clbearing; /* bearing to closest player */
769 int min_distsq; /* to hold closest distance */
770 int war_mask; /* who torp own is at war with */
771 int x, y; /* to hold torps x, y coords */
772 int bearing; /* to get bearing to hit player */
773 int dir; /* to hold torps direction */
774 int range;
775
776 closest = -1; /* initialize closest player--no plyr */
777 x = torp->bt_x; /* get the coords of torp */
778 y = torp->bt_y;
779 dir = torp->bt_dir; /* get torp's directions */
780 war_mask = torp->bt_war; /* and who he as war with */
781
782 range = torp->bt_fuse * torp->bt_speed * WARP1;
783
784 min_distsq = range * range * 4; /* intialize closest player distance */
785
786 for (i = 0; i < MAXPLAYER; i++)
787 { /* check all other players */
788 int dx, dy;
789 if (!(isAlive(&players[i]) &&
790 hostile_to(war_mask, torp->bt_team, &players[i])))
791 continue; /* only do if player alive and at war */
792
793 dx = players[i].p_x - x;
794 dy = players[i].p_y - y;
795
796 if (ABS(dx) > range || ABS(dy) > range)
797 continue; /* clearly out of range */
798
799 if (smart)
800 {
801 bearing = anticipate_impact(torp->bt_speed, dx, dy,
802 players[i].p_speed, players[i].p_dir);
803 if (bearing < 0)
804 bearing = get_bearing(dx, dy, dir);
805 else
806 bearing = (unsigned char) (bearing - dir);
807 }
808 else
809 {
810 bearing = get_bearing(dx, dy, dir);
811 }
812 /* torps will only track to targets they have a reasonable chance */
813 /* of hitting */
814 if ((turnspeed * torp->bt_fuse > 127) ||
815 (bearing < ((unsigned char) turnspeed * torp->bt_fuse)) ||
816 (bearing > ((unsigned char) (256 - turnspeed * torp->bt_fuse))))
817 {
818 int distsq;
819 distsq = dx * dx + dy * dy;
820 if (distsq < min_distsq)
821 { /* record it if it is */
822 min_distsq = distsq; /* less than current closest */
823 closest = i; /* player */
824 clbearing = bearing;
825 }
826 }
827 }
828 if (closest >= 0)
829 { /* if a target found then */
830 if (clbearing > 128)
831 return (-1); /* Target is on the left */
832 else
833 return (1); /* Target is on the right */
834 }
835 return (0); /* No target ... go straight. */
836 }
837
838
839
840
841 /*------------------------------UDPLASMATORPS-----------------------------*/
842 /*
843 * This function updates the plasma torps. It goes through all the plasma
844 * torps and if they are alive it adjusts their heading to track players. It
845 * then moves the plasma torp and checks to see if the plasma should explode.
846 * It will ensure that a plasma torp explodes when it hits the edge of the
847 * galaxy.
848 */
849
850 void
851 udplasmatorps()
852 {
853 register int i; /* looping var--loop through plasmas */
854 int turn; /* to get whether to go left or right */
855 int heading; /* to hold plasma heading */
856 struct plasmatorp *j; /* to point to a plasma */
857
858 for (i = 0, j = &plasmatorps[i]; i < MAXPLAYER * MAXPLASMA; i++, j++)
859 {
860 switch (j->pt_status)
861 { /* check torp's status */
862 case PTFREE: /* if plasma not being fired */
863 continue; /* go to next plasma */
864 case PTMOVE: /* if plasma moving */
865 turn = torp_track_opportunity
866 (&j->pt_base, j->pt_turns,
867 configvals->improved_tracking[SS_PLASMA]);
868 /* should we go right or left */
869 if (turn < 0)
870 { /* if left then */
871 heading = ((int) j->pt_dir) - j->pt_turns;
872 j->pt_dir = ((heading < 0) ? ((unsigned char) (256 + heading)) :
873 ((unsigned char) heading)); /* no rollunder */
874 }
875 else if (turn > 0)
876 { /* else if right */
877 heading = ((int) j->pt_dir) + j->pt_turns;
878 j->pt_dir = ((heading > 255) ? ((unsigned char) (heading - 256)) :
879 ((unsigned char) heading)); /* no rollover */
880 }
881 j->pt_x += (double) j->pt_speed * Cos[j->pt_dir] * WARP1;
882
883 #if 0
884 if (j->pt_x < 0)
885 { /* if torp at left edge */
886 j->pt_x = 0; /* set x to left edge */
887 pexplode(j); /* make torp explode */
888 break; /* go to next torp */
889 }
890 else if (j->pt_x > GWIDTH)
891 { /* if torp is at right edge */
892 j->pt_x = GWIDTH; /* set x to right edge */
893 pexplode(j); /* make torp explode */
894 break; /* on to next torp */
895 }
896 #endif
897 j->pt_y += (double) j->pt_speed * Sin[j->pt_dir] * WARP1;
898 #if 0
899 if (j->pt_y < 0)
900 { /* if torp at top */
901 j->pt_y = 0; /* set torp to top edge */
902 pexplode(j); /* make torp explode */
903 break; /* on to next torp */
904 }
905 else if (j->pt_y > GWIDTH)
906 { /* if torp is at bottom */
907 j->pt_y = GWIDTH; /* set y to bottom */
908 pexplode(j); /* make torp explode */
909 break; /* on to next torp */
910 }
911 #endif
912
913 if (j->pt_fuse-- <= 0)
914 { /* dec the torp fuse. if torp done */
915 j->pt_status = PTFREE; /* free it up */
916 players[j->pt_owner].p_nplasmatorp--; /* dec p-torps fired */
917 break;
918 }
919
920 if ((terrain_grid[(int) (j->pt_x) / TGRID_GRANULARITY * TGRID_SIZE +
921 (int) (j->pt_y) / TGRID_GRANULARITY].types
922 & T_ASTEROIDS) &&
923 ast_effect[SS_PLASMA])
924 if (PLASMA_HIT_AST > (lrand48() % 100))
925 {
926 pexplode(j);
927 break;
928 }
929
930 if ((sun_effect[SS_PLASMA] && weap_near_object(&j->pt_base, PLSTAR, ORBDIST))
931 ||
932 (sun_effect[SS_PLASMA] && weap_near_object(&j->pt_base, PLWHOLE, ORBDIST))
933 /* did it hit a star? */
934 || pnear(j) /* or a player */ )
935 {
936 pexplode(j);
937 }
938 break; /* on to next torp */
939 case PTDET: /* if torp was detted */
940 pexplode(j); /* make it explode */
941 break; /* on to next torp */
942 case PTEXPLODE: /* if torp is exploding */
943 if (j->pt_fuse-- <= 0)
944 { /* dec the timer until torp dead */
945 j->pt_status = PTFREE; /* set the torp free is timer zero */
946 players[j->pt_owner].p_nplasmatorp--; /* dec ptorps fired by player */
947 }
948 break;
949 default: /* Shouldn't happen */
950 j->pt_status = PTFREE; /* free torp if it got screwed */
951 break; /* on to next torp */
952 }
953 }
954 }
955
956
957
958 /*--------------------------------GET_BEARING------------------------------*/
959 /*
960 * This function takes two set of coordinates and a direction. One set of
961 * coordinates is the current coords of a trop. The other set is some other
962 * coords you want to get a change in direction for. The direction is the
963 * current direction of the torp. The function returns the angle that the
964 * dir need to be changed by to travel to the new points.
965 */
966
967 unsigned char
968 get_bearing(dx, dy, dir)
969 int dx, dy; /* delta x, y coords */
970 int dir; /* current direction travelling */
971 {
972 int phi; /* to hold angle */
973
974 phi = (int) (atan2((double) dx, (double) -dy) / 3.14159 * 128.0);
975 if (phi < 0) /* make phi positive */
976 phi = 256 + phi;
977 if (phi >= dir)
978 return ((unsigned char) (phi - dir));
979 else
980 return ((unsigned char) (256 + phi - dir));
981 }
982
983 /*------------------------------------------------------------------------*/
984
985
986
987
988 /*------------------------------------------------------------------------*/
989 /*--------------------------FIGHTER_TRACK_TARGET--------------------------*/
990 /*
991 * This function finds the closest ship to a fighter and returns -1 if the
992 * ship is to the left of the fighter on its current heading and a 1 if the
993 * ship is to the right. If no target is found then a 0 is return indicating
994 * the fighter should go straight. Also returns fighters to the CV. If the
995 * player is locked onto an enemy ship, that's the only ship that gets
996 * checked.
997 */
998
999 int
1000 fighter_track_target(mis, turnspeed)
1001 struct missile *mis; /* the torp to check for */
1002 int turnspeed;
1003 {
1004 int i; /* looping var */
1005 int closest; /* to hold closest player */
1006 int min_dist; /* to hold closest distance */
1007 int dist; /* temp var to hold distance */
1008 int war_mask; /* who fighter own is at war with */
1009 int x, y; /* to hold fighters x, y coords */
1010 int owner; /* to hold fighters owner */
1011 int bearing; /* to get bearing to hit player */
1012 int dir; /* to hold fighters direction */
1013 int range;
1014 int dx, dy;
1015
1016 min_dist = GWIDTH * 2; /* intialize closest player distance */
1017 closest = -1; /* initialize closest player--no plyr */
1018 x = mis->ms_x; /* get the coords of torp */
1019 y = mis->ms_y;
1020 dir = mis->ms_dir; /* get fighter's directions */
1021 owner = mis->ms_owner; /* get the fighter's owner */
1022 war_mask = mis->ms_war; /* and who he as war with */
1023
1024 range = mis->ms_fuse * mis->ms_speed * WARP1;
1025
1026 for (i = 0; i < MAXPLAYER; i++)
1027 { /* check all other players */
1028 if (mis->ms_status == TRETURN)
1029 {
1030 if (!(isAlive(&players[i])) || (owner != i))
1031 continue;
1032 } /* if returning, only check owning player */
1033 else if ((players[owner].p_flags & PFPLOCK) &&
1034 (players[owner].p_playerl != i))
1035 continue; /* if player is locked onto a player, only
1036 * check that player */
1037 else if (!(isAlive(&players[i]) &&
1038 hostile_to(war_mask, mis->ms_team, &players[i])))
1039 continue; /* only do if player alive and at war */
1040
1041 dx = players[i].p_x - x;
1042 dy = players[i].p_y - y;
1043
1044 if (ABS(dx) > range || ABS(dy) > range)
1045 continue; /* clearly out of range */
1046
1047 bearing = get_bearing(dx, dy, dir);
1048 if ((turnspeed * mis->ms_fuse > 127) ||
1049 (bearing < ((unsigned char) turnspeed * mis->ms_fuse)) ||
1050 (bearing > ((unsigned char) (256 - turnspeed * mis->ms_fuse))))
1051 {
1052 dist = ihypot(dx, dy);
1053 if (dist < min_dist)
1054 { /* record it if it is */
1055 min_dist = dist; /* less than current closest */
1056 closest = i; /* player */
1057 }
1058 }
1059 }
1060 if (closest >= 0)
1061 { /* if a target found then */
1062 if (get_bearing(players[closest].p_x - x,
1063 players[closest].p_y - y, dir) > 128)
1064 {
1065 return (-1); /* Target is on the left */
1066 }
1067 else
1068 return (1); /* Target is on the right */
1069 }
1070 return (0); /* No target ... go straight. */
1071 }
1072
1073
1074 /*--------------------------------------------------------------------------*/
1075 /*------------------------------------F_TORP--------------------------------*/
1076 /* Checks to see if a valid target is within a certain forward firing angle */
1077 /* then fires a torpedo at that target. A return value of 1 indicates firing */
1078
1079 int
1080 f_torp(mis)
1081 struct missile *mis;
1082 {
1083 register int i;
1084 int torp2fire = -1, targetdist = FSTRIKEDIST + 1, tdist, target;
1085 unsigned char bearing;
1086 register struct torp *k;
1087 int dx, dy;
1088 register struct player *j; /* to point to players */
1089
1090 for (i = mis->ms_owner * MAXTORP, k = &torps[i]; /* Find a free torp */
1091 i < mis->ms_owner * MAXTORP + MAXTORP; i++, k++)
1092 if (k->t_status == TFREE)
1093 {
1094 torp2fire = i;
1095 break;
1096 }
1097 if (torp2fire == -1)
1098 return 0;
1099
1100
1101 for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++)
1102 {
1103 if (j->p_status != PALIVE)
1104 continue; /* don't check players not alive */
1105 if (j->p_no == mis->ms_owner)
1106 continue; /* no firing on self */
1107 if (!hostile_to(mis->ms_war, mis->ms_team, j))
1108 continue; /* disregard if both teams not at war */
1109 if ((players[mis->ms_owner].p_flags & PFPLOCK) &&
1110 (players[mis->ms_owner].p_playerl != i))
1111 continue; /* ignore if this isn't the target */
1112
1113 dx = mis->ms_x - j->p_x; /* calc delta coords */
1114 dy = mis->ms_y - j->p_y;
1115 if (ABS(dx) > FSTRIKEDIST || ABS(dy) > FSTRIKEDIST)
1116 continue; /* disregard if obviously too far */
1117
1118 tdist = ihypot(dx, dy);
1119 if (tdist < FSTRIKEDIST)
1120 {
1121 bearing = (int) get_bearing(dx, dy, mis->ms_dir);
1122 targetdist = tdist; /* record the target ship */
1123 target = i;
1124 }
1125 }
1126
1127 if (targetdist < FSTRIKEDIST)
1128 {
1129 j = &players[mis->ms_owner];
1130 k = &torps[torp2fire];
1131 k->t_no = torp2fire;
1132 k->t_status = TMOVE;
1133 k->t_owner = mis->ms_owner;
1134 k->t_team = mis->ms_team;
1135
1136 move_torp(torp2fire, mis->ms_x, mis->ms_y, 0);
1137
1138 k->t_damage = FTORP_DAMAGE;
1139 k->t_speed = FTORP_SPEED;
1140 k->t_war = j->p_hostile |
1141 j->p_swar;
1142 k->t_fuse = FTORP_FUSE + (lrand48() % 20);
1143 k->t_turns = FTORP_TRACK;
1144
1145 /*
1146 * here's the biggie -- what angle do I fire this torp at, so I have a
1147 * reasonable chance of hitting? Especially since I only get one shot.
1148 * But, then, I have a bunch of buddies, too...
1149 */
1150
1151 if ((mis->ms_no % MAXPLAYER % 3) == 0)
1152 k->t_dir = mis->ms_dir;
1153 else if ((mis->ms_no % MAXPLAYER % 3) == 1)
1154 k->t_dir = mis->ms_dir - 8;
1155 else if ((mis->ms_no % MAXPLAYER % 3) == 2)
1156 k->t_dir = mis->ms_dir + 8;
1157 return 1;
1158 }
1159 return 0;
1160 }
1161
1162
1163 /*----------END OF FILE--------*/