Mercurial > ~darius > hgwebdir.cgi > paradise_server
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--------*/ |