Add remapped keys setting.
[newkind] / swat.c
1 /*
2 * Elite - The New Kind.
3 *
4 * Reverse engineered from the BBC disk version of Elite.
5 * Additional material by C.J.Pinder.
6 *
7 * The original Elite code is (C) I.Bell & D.Braben 1984.
8 * This version re-engineered in C by C.J.Pinder 1999-2001.
9 *
10 * email: <christian@newkind.co.uk>
11 *
12 *
13 */
14
15 /*
16 * swat.c
17 *
18 * Special Weapons And Tactics.
19 */
20
21 #include <math.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "config.h"
26 #include "gfx.h"
27 #include "elite.h"
28 #include "vector.h"
29 #include "swat.h"
30 #include "shipdata.h"
31 #include "space.h"
32 #include "main.h"
33 #include "sound.h"
34 #include "random.h"
35 #include "trade.h"
36 #include "pilot.h"
37
38 int laser_counter;
39 int laser;
40 int laser2;
41 int laser_x;
42 int laser_y;
43
44 int ecm_active;
45 int missile_target;
46 int ecm_ours;
47 int in_battle;
48
49 struct univ_object universe[MAX_UNIV_OBJECTS];
50 int ship_count[NO_OF_SHIPS + 1]; /* many */
51
52
53 int initial_flags[NO_OF_SHIPS + 1] =
54 {
55 0, // NULL,
56 FLG_TARGET, // missile
57 0, // coriolis
58 FLG_SLOW | FLG_FLY_TO_PLANET, // escape
59 FLG_INACTIVE | FLG_TARGET, // alloy
60 FLG_INACTIVE | FLG_TARGET, // cargo
61 FLG_INACTIVE | FLG_TARGET, // boulder
62 FLG_INACTIVE | FLG_TARGET, // asteroid
63 FLG_INACTIVE | FLG_TARGET, // rock
64 FLG_FLY_TO_PLANET | FLG_SLOW, // shuttle
65 FLG_FLY_TO_PLANET | FLG_SLOW, // transporter
66 0, // cobra3
67 0, // python
68 0, // boa
69 FLG_SLOW, // anaconda
70 FLG_SLOW, // hermit
71 FLG_BOLD | FLG_POLICE, // viper
72 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // sidewinder
73 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // mamba
74 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // krait
75 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // adder
76 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // gecko
77 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // cobra1
78 FLG_SLOW | FLG_ANGRY | FLG_TARGET, // worm
79 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // cobra3
80 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // asp2
81 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // python
82 FLG_POLICE, // fer_de_lance
83 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // moray
84 FLG_BOLD | FLG_ANGRY | FLG_TARGET, // thargoid
85 FLG_ANGRY | FLG_TARGET, // thargon
86 FLG_ANGRY, // constrictor
87 FLG_POLICE | FLG_CLOAKED, // cougar
88 0 // dodec
89 };
90
91
92
93
94 void clear_universe (void)
95 {
96 int i;
97
98 for (i = 0; i < MAX_UNIV_OBJECTS; i++)
99 universe[i].type = 0;
100
101 for (i = 0; i <= NO_OF_SHIPS; i++)
102 ship_count[i] = 0;
103
104 in_battle = 0;
105 }
106
107
108 int add_new_ship (int ship_type, int x, int y, int z, struct vector *rotmat, int rotx, int rotz)
109 {
110 int i;
111
112 for (i = 0; i < MAX_UNIV_OBJECTS; i++)
113 {
114 if (universe[i].type == 0)
115 {
116 universe[i].type = ship_type;
117 universe[i].location.x = x;
118 universe[i].location.y = y;
119 universe[i].location.z = z;
120
121 universe[i].distance = sqrt(x*x + y*y + z*z);
122
123 universe[i].rotmat[0] = rotmat[0];
124 universe[i].rotmat[1] = rotmat[1];
125 universe[i].rotmat[2] = rotmat[2];
126
127 universe[i].rotx = rotx;
128 universe[i].rotz = rotz;
129
130 universe[i].velocity = 0;
131 universe[i].acceleration = 0;
132 universe[i].bravery = 0;
133 universe[i].target = 0;
134
135 universe[i].flags = initial_flags[ship_type];
136
137 if ((ship_type != SHIP_PLANET) && (ship_type != SHIP_SUN))
138 {
139 universe[i].energy = ship_list[ship_type]->energy;
140 universe[i].missiles = ship_list[ship_type]->missiles;
141 ship_count[ship_type]++;
142 }
143
144 return i;
145 }
146 }
147
148 return -1;
149 }
150
151
152
153
154 void check_missiles (int un)
155 {
156 int i;
157
158 if (missile_target == un)
159 {
160 missile_target = MISSILE_UNARMED;
161 info_message ("Target Lost");
162 }
163
164 for (i = 0; i < MAX_UNIV_OBJECTS; i++)
165 {
166 if ((universe[i].type == SHIP_MISSILE) && (universe[i].target == un))
167 universe[i].flags |= FLG_DEAD;
168 }
169 }
170
171
172 void remove_ship (int un)
173 {
174 int type;
175 Matrix rotmat;
176 int px,py,pz;
177
178 type = universe[un].type;
179
180 if (type == 0)
181 return;
182
183 if (type > 0)
184 ship_count[type]--;
185
186 universe[un].type = 0;
187
188 check_missiles (un);
189
190 if ((type == SHIP_CORIOLIS) || (type == SHIP_DODEC))
191 {
192 set_init_matrix (rotmat);
193 px = universe[un].location.x;
194 py = universe[un].location.y;
195 pz = universe[un].location.z;
196
197 py &= 0xFFFF;
198 py |= 0x60000;
199
200 add_new_ship (SHIP_SUN, px, py, pz, rotmat, 0, 0);
201 }
202 }
203
204
205 void add_new_station (double sx, double sy, double sz, Matrix rotmat)
206 {
207 int station;
208
209 station = (current_planet_data.techlevel >= 10) ? SHIP_DODEC : SHIP_CORIOLIS;
210 universe[1].type = 0;
211 add_new_ship (station, sx, sy, sz, rotmat, 0, -127);
212 }
213
214
215
216
217 void reset_weapons (void)
218 {
219 laser_temp = 0;
220 laser_counter = 0;
221 laser = 0;
222 ecm_active = 0;
223 missile_target = MISSILE_UNARMED;
224 }
225
226
227 void launch_enemy (int un, int type, int flags, int bravery)
228 {
229 int newship;
230 struct univ_object *ns;
231
232 newship = add_new_ship (type, universe[un].location.x, universe[un].location.y,
233 universe[un].location.z, universe[un].rotmat,
234 universe[un].rotx, universe[un].rotz);
235
236 if (newship == -1)
237 {
238 return;
239 }
240
241 ns = &universe[newship];
242
243 if ((universe[un].type == SHIP_CORIOLIS) || (universe[un].type == SHIP_DODEC))
244 {
245 ns->velocity = 32;
246 ns->location.x += ns->rotmat[2].x * 2;
247 ns->location.y += ns->rotmat[2].y * 2;
248 ns->location.z += ns->rotmat[2].z * 2;
249 }
250
251 ns->flags |= flags;
252 ns->rotz /= 2;
253 ns->rotz *= 2;
254 ns->bravery = bravery;
255
256 if ((type == SHIP_CARGO) || (type == SHIP_ALLOY) || (type == SHIP_ROCK))
257 {
258 ns->rotz = ((rand255() * 2) & 255) - 128;
259 ns->rotx = ((rand255() * 2) & 255) - 128;
260 ns->velocity = rand255() & 15;
261 }
262 }
263
264
265 void launch_loot (int un, int loot)
266 {
267 int i,cnt;
268
269 if (loot == SHIP_ROCK)
270 {
271 cnt = rand255() & 3;
272 }
273 else
274 {
275 cnt = rand255();
276 if (cnt >= 128)
277 return;
278
279 cnt &= ship_list[universe[un].type]->max_loot;
280 cnt &= 15;
281 }
282
283 for (i = 0; i < cnt; i++)
284 {
285 launch_enemy (un, loot, 0,0);
286 }
287 }
288
289
290
291
292 int in_target (int type, double x, double y, double z)
293 {
294 double size;
295
296 if (z < 0)
297 return 0;
298
299 size = ship_list[type]->size;
300
301 return ((x*x + y*y) <= size);
302 }
303
304
305
306 void make_angry (int un)
307 {
308 int type;
309 int flags;
310
311 type = universe[un].type;
312 flags = universe[un].flags;
313
314 if (flags & FLG_INACTIVE) {
315 universe[un].flags |= FLG_TACTICAL;
316 return;
317 }
318
319 if ((type == SHIP_CORIOLIS) || (type == SHIP_DODEC))
320 {
321 universe[un].flags |= FLG_ANGRY;
322 return;
323 }
324
325 if (!(universe[un].flags & FLG_TARGET) &&
326 (universe[1].type == SHIP_CORIOLIS ||
327 universe[1].type == SHIP_DODEC))
328 universe[1].flags |= FLG_ANGRY;
329
330 if (type > SHIP_ROCK)
331 {
332 universe[un].rotx = 4;
333 universe[un].acceleration = 2;
334 universe[un].flags |= FLG_ANGRY | FLG_TACTICAL;
335 }
336 }
337
338
339 void explode_object (int un)
340 {
341
342 cmdr.score++;
343
344 if ((cmdr.score & 255) == 0)
345 info_message ("Right On Commander!");
346
347 snd_play_sample (SND_EXPLODE);
348 universe[un].flags |= FLG_DEAD;
349
350 if (universe[un].type == SHIP_CONSTRICTOR)
351 cmdr.mission = 2;
352 }
353
354
355 void check_target (int un, struct univ_object *flip)
356 {
357 struct univ_object *univ;
358
359 univ = &universe[un];
360
361 if (in_target (univ->type, flip->location.x, flip->location.y, flip->location.z))
362 {
363 if ((missile_target == MISSILE_ARMED) && (univ->type >= 0))
364 {
365 missile_target = un;
366 info_message ("Target Locked");
367 snd_play_sample (SND_BEEP);
368 }
369
370 if (laser)
371 {
372 snd_play_sample (SND_HIT_ENEMY);
373
374 if ((univ->type != SHIP_CORIOLIS) && (univ->type != SHIP_DODEC))
375 {
376 if ((univ->type == SHIP_CONSTRICTOR) || (univ->type == SHIP_COUGAR))
377 {
378 if (laser == (MILITARY_LASER & 127))
379 univ->energy -= laser / 4;
380 }
381 else
382 {
383 univ->energy -= laser;
384 }
385 }
386
387 if (univ->energy <= 0)
388 {
389 explode_object (un);
390
391 if (univ->type == SHIP_ASTEROID)
392 {
393 if (laser == (MINING_LASER & 127))
394 launch_loot (un, SHIP_ROCK);
395 }
396 else
397 {
398 launch_loot (un, SHIP_ALLOY);
399 launch_loot (un, SHIP_CARGO);
400 }
401 }
402
403 make_angry (un);
404 }
405 }
406 }
407
408
409
410 void activate_ecm (int ours)
411 {
412 if (ecm_active == 0)
413 {
414 ecm_active = 32;
415 ecm_ours = ours;
416 snd_play_sample (SND_ECM);
417 }
418 }
419
420
421 void time_ecm (void)
422 {
423 if (ecm_active != 0)
424 {
425 ecm_active--;
426 if (ecm_ours)
427 decrease_energy (-1);
428 }
429 }
430
431
432 void arm_missile (void)
433 {
434 if ((cmdr.missiles != 0) && (missile_target == MISSILE_UNARMED))
435 missile_target = MISSILE_ARMED;
436 }
437
438
439 void unarm_missile (void)
440 {
441 missile_target = MISSILE_UNARMED;
442 snd_play_sample (SND_BOOP);
443 }
444
445 void fire_missile (void)
446 {
447 int newship;
448 struct univ_object *ns;
449 Matrix rotmat;
450
451 if (missile_target < 0)
452 return;
453
454 set_init_matrix (rotmat);
455 rotmat[2].z = 1.0;
456 rotmat[0].x = -1.0;
457
458 newship = add_new_ship (SHIP_MISSILE, 0, -28, 14, rotmat, 0, 0);
459
460 if (newship == -1)
461 {
462 info_message ("Missile Jammed");
463 return;
464 }
465
466 ns = &universe[newship];
467
468 ns->velocity = flight_speed * 2;
469 ns->flags |= FLG_TACTICAL;
470 ns->target = missile_target;
471
472 if (universe[missile_target].type > SHIP_ROCK)
473 universe[missile_target].flags |= FLG_ANGRY;
474
475 cmdr.missiles--;
476 missile_target = MISSILE_UNARMED;
477
478 snd_play_sample (SND_MISSILE);
479 }
480
481
482
483 void track_object (struct univ_object *ship, double direction, Vector nvec)
484 {
485 double dir;
486 int rat;
487 double rat2;
488
489 rat = 3;
490 rat2 = 0.111;
491
492 dir = vector_dot_product (&nvec, &ship->rotmat[1]);
493
494 if (direction < -0.861)
495 {
496 ship->rotx = (dir < 0) ? 7 : -7;
497 ship->rotz = 0;
498 return;
499 }
500
501 ship->rotx = 0;
502
503 if ((fabs(dir) * 2) >= rat2)
504 {
505 ship->rotx = (dir < 0) ? rat : -rat;
506 }
507
508 if (abs(ship->rotz) < 16)
509 {
510 dir = vector_dot_product (&nvec, &ship->rotmat[0]);
511
512 ship->rotz = 0;
513
514 if ((fabs(dir) * 2) > rat2)
515 {
516 ship->rotz = (dir < 0) ? rat : -rat;
517
518 if (ship->rotx < 0)
519 ship->rotz = -ship->rotz;
520 }
521 }
522 }
523
524
525
526 void missile_tactics (int un)
527 {
528 struct univ_object *missile;
529 struct univ_object *target;
530 Vector vec;
531 Vector nvec;
532 double direction;
533 double cnt2 = 0.223;
534
535 missile = &universe[un];
536
537 if (ecm_active)
538 {
539 snd_play_sample (SND_EXPLODE);
540 missile->flags |= FLG_DEAD;
541 return;
542 }
543
544 if (missile->target == 0)
545 {
546 if (missile->distance < 256)
547 {
548 missile->flags |= FLG_DEAD;
549 snd_play_sample (SND_EXPLODE);
550 damage_ship (250, missile->location.z >= 0.0);
551 return;
552 }
553
554 vec.x = missile->location.x;
555 vec.y = missile->location.y;
556 vec.z = missile->location.z;
557 }
558 else
559 {
560 target = &universe[missile->target];
561
562 vec.x = missile->location.x - target->location.x;
563 vec.y = missile->location.y - target->location.y;
564 vec.z = missile->location.z - target->location.z;
565
566 if ((fabs(vec.x) < 256) && (fabs(vec.y) < 256) && (fabs(vec.z) < 256))
567 {
568 missile->flags |= FLG_DEAD;
569
570 if ((target->type != SHIP_CORIOLIS) && (target->type != SHIP_DODEC))
571 explode_object (missile->target);
572 else
573 snd_play_sample (SND_EXPLODE);
574
575 return;
576 }
577
578 if ((rand255() < 16) && (target->flags & FLG_HAS_ECM))
579 {
580 activate_ecm (0);
581 return;
582 }
583 }
584
585 if ((rand255() < 16) &&
586 (ship_count[SHIP_CORIOLIS] || ship_count[SHIP_DODEC])) {
587 activate_ecm(0);
588 return;
589 }
590
591 nvec = unit_vector(&vec);
592 direction = vector_dot_product (&nvec, &missile->rotmat[2]);
593 nvec.x = -nvec.x;
594 nvec.y = -nvec.y;
595 nvec.z = -nvec.z;
596 direction = -direction;
597
598 track_object (missile, direction, nvec);
599
600 if (direction <= -0.167)
601 {
602 missile->acceleration = -2;
603 return;
604 }
605
606 if (direction >= cnt2)
607 {
608 missile->acceleration = 3;
609 return;
610 }
611
612 if (missile->velocity < 6)
613 missile->acceleration = 3;
614 else
615 if (rand255() >= 200)
616 missile->acceleration = -2;
617 return;
618 }
619
620
621
622 void launch_shuttle (void)
623 {
624 int type;
625
626 if ((ship_count[SHIP_TRANSPORTER] != 0) ||
627 (ship_count[SHIP_SHUTTLE] != 0) ||
628 (rand255() < 253) || (auto_pilot))
629 return;
630
631 type = rand255() & 1 ? SHIP_SHUTTLE : SHIP_TRANSPORTER;
632 launch_enemy (1, type, FLG_HAS_ECM | FLG_FLY_TO_PLANET, 113);
633 }
634
635
636 void tactics (int un)
637 {
638 int type;
639 int energy;
640 int maxeng;
641 int flags;
642 struct univ_object *ship;
643 Vector nvec;
644 double cnt2 = 0.223;
645 double direction;
646 int attacking;
647
648 ship = &universe[un];
649 type = ship->type;
650 flags = ship->flags;
651
652 if ((type == SHIP_PLANET) || (type == SHIP_SUN))
653 return;
654
655 if (flags & FLG_DEAD)
656 return;
657
658 if (flags & FLG_INACTIVE)
659 return;
660
661 if (type == SHIP_MISSILE)
662 {
663 if (flags & FLG_ANGRY)
664 missile_tactics (un);
665 return;
666 }
667
668 if (((un ^ mcount) & 7) != 0)
669 return;
670
671 if ((type == SHIP_CORIOLIS) || (type == SHIP_DODEC))
672 {
673 if (flags & FLG_ANGRY)
674 {
675 if ((rand() & 255) < 240)
676 return;
677
678 if (ship_count[SHIP_VIPER] >= 4)
679 return;
680
681 launch_enemy (un, SHIP_VIPER, FLG_ANGRY | FLG_HAS_ECM, 113);
682 return;
683 }
684
685 launch_shuttle ();
686 return;
687 }
688
689 if (type == SHIP_HERMIT)
690 {
691 if (rand255() > 200)
692 {
693 launch_enemy (un, SHIP_SIDEWINDER + (rand255() & 3), FLG_ANGRY | FLG_HAS_ECM, 113);
694 ship->flags |= FLG_INACTIVE | FLG_TARGET;
695 }
696
697 return;
698 }
699
700
701 if (ship->energy < ship_list[type]->energy)
702 ship->energy++;
703
704 if ((type == SHIP_THARGLET) && (ship_count[SHIP_THARGOID] == 0))
705 {
706 ship->flags &= FLG_TARGET | FLG_TACTICAL;
707 ship->velocity /= 2;
708 return;
709 }
710
711 if (flags & FLG_SLOW)
712 {
713 if (rand255() > 50)
714 return;
715 }
716
717 if (flags & FLG_POLICE)
718 {
719 if (cmdr.legal_status >= 64)
720 {
721 flags |= FLG_ANGRY | FLG_TARGET;
722 ship->flags = flags;
723 }
724 }
725
726 if ((flags & FLG_ANGRY) == 0)
727 {
728 if ((flags & FLG_FLY_TO_PLANET) || (flags & FLG_FLY_TO_STATION))
729 {
730 auto_pilot_ship (&universe[un]);
731 }
732
733 return;
734 }
735
736
737 /* If we get to here then the ship is angry so start attacking... */
738
739 if (ship_count[SHIP_CORIOLIS] || ship_count[SHIP_DODEC])
740 {
741 if ((flags & FLG_BOLD) == 0)
742 ship->bravery = 0;
743 }
744
745
746 if (type == SHIP_ANACONDA)
747 {
748 if (rand255() > 200)
749 {
750 launch_enemy (un, rand255() > 100 ? SHIP_WORM : SHIP_SIDEWINDER,
751 FLG_ANGRY | FLG_HAS_ECM, 113);
752 return;
753 }
754 }
755
756
757 if (rand255() >= 250)
758 {
759 ship->rotz = rand255() | 0x68;
760 if (ship->rotz > 127)
761 ship->rotz = -(ship->rotz & 127);
762 }
763
764 maxeng = ship_list[type]->energy;
765 energy = ship->energy;
766
767 if (energy < (maxeng / 2))
768 {
769 if ((energy < (maxeng / 8)) && (rand255() > 230) && (type != SHIP_THARGOID))
770 {
771 ship->flags &= ~FLG_ANGRY;
772 ship->flags |= FLG_INACTIVE;
773 launch_enemy (un, SHIP_ESCAPE_CAPSULE, 0, 126);
774 return;
775 }
776
777 if ((ship->missiles != 0) && (ecm_active == 0) &&
778 (ship->missiles >= (rand255() & 31)))
779 {
780 ship->missiles--;
781 ship->flags |= FLG_TACTICAL;
782 if (type == SHIP_THARGOID)
783 launch_enemy (un, SHIP_THARGLET, FLG_ANGRY, ship->bravery);
784 else
785 {
786 launch_enemy (un, SHIP_MISSILE, FLG_ANGRY, 126);
787 ship->flags |= FLG_HOSTILE;
788 info_message ("INCOMING MISSILE");
789 }
790 return;
791 }
792 }
793
794 nvec = unit_vector(&universe[un].location);
795 direction = vector_dot_product (&nvec, &ship->rotmat[2]);
796
797 if ((ship->distance < 8192) && (direction <= -0.833) &&
798 (ship_list[type]->laser_strength != 0))
799 {
800 if (direction <= -0.917)
801 ship->flags |= FLG_FIRING | FLG_HOSTILE | FLG_TACTICAL;
802
803 if (direction <= -0.972)
804 {
805 damage_ship (ship_list[type]->laser_strength, ship->location.z >= 0.0);
806 ship->acceleration--;
807 if (((ship->location.z >= 0.0) && (front_shield == 0)) ||
808 ((ship->location.z < 0.0) && (aft_shield == 0)))
809 snd_play_sample (SND_INCOMMING_FIRE_2);
810 else
811 snd_play_sample (SND_INCOMMING_FIRE_1);
812 }
813 else
814 {
815 nvec.x = -nvec.x;
816 nvec.y = -nvec.y;
817 nvec.z = -nvec.z;
818 direction = -direction;
819 track_object (&universe[un], direction, nvec);
820 }
821
822 // if ((fabs(ship->location.z) < 768) && (ship->bravery <= ((rand255() & 127) | 64)))
823 if (fabs(ship->location.z) < 768)
824 {
825 ship->rotx = rand255() & 0x87;
826 if (ship->rotx > 127)
827 ship->rotx = -(ship->rotx & 127);
828
829 ship->acceleration = 3;
830 return;
831 }
832
833 if (ship->distance < 8192)
834 ship->acceleration = -1;
835 else
836 ship->acceleration = 3;
837 return;
838 }
839
840 attacking = 0;
841
842 if ((fabs(ship->location.z) >= 768) ||
843 (fabs(ship->location.x) >= 512) ||
844 (fabs(ship->location.y) >= 512))
845 {
846 if (ship->bravery > (rand255() & 127))
847 {
848 attacking = 1;
849 nvec.x = -nvec.x;
850 nvec.y = -nvec.y;
851 nvec.z = -nvec.z;
852 direction = -direction;
853 }
854 }
855
856 track_object (&universe[un], direction, nvec);
857
858 if ((attacking == 1) && (ship->distance < 2048))
859 {
860 if (direction >= cnt2)
861 {
862 ship->acceleration = -1;
863 return;
864 }
865
866 if (ship->velocity < 6)
867 ship->acceleration = 3;
868 else
869 if (rand255() >= 200)
870 ship->acceleration = -1;
871 return;
872 }
873
874 if (direction <= -0.167)
875 {
876 ship->acceleration = -1;
877 return;
878 }
879
880 if (direction >= cnt2)
881 {
882 ship->acceleration = 3;
883 return;
884 }
885
886 if (ship->velocity < 6)
887 ship->acceleration = 3;
888 else
889 if (rand255() >= 200)
890 ship->acceleration = -1;
891 }
892
893
894 void draw_laser_lines (void)
895 {
896 if (wireframe)
897 {
898 gfx_draw_colour_line (32 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, GFX_COL_WHITE);
899 gfx_draw_colour_line (48 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, GFX_COL_WHITE);
900 gfx_draw_colour_line (208 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, GFX_COL_WHITE);
901 gfx_draw_colour_line (224 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, GFX_COL_WHITE);
902 }
903 else
904 {
905 gfx_draw_triangle (32 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, 48 * GFX_SCALE, GFX_VIEW_BY, GFX_COL_RED);
906 gfx_draw_triangle (208 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, 224 * GFX_SCALE, GFX_VIEW_BY, GFX_COL_RED);
907 }
908 }
909
910
911 int fire_laser (void)
912 {
913 if ((laser_counter == 0) && (laser_temp < 242))
914 {
915 switch (current_screen)
916 {
917 case SCR_FRONT_VIEW:
918 laser = cmdr.front_laser;
919 break;
920
921 case SCR_REAR_VIEW:
922 laser = cmdr.rear_laser;
923 break;
924
925 case SCR_RIGHT_VIEW:
926 laser = cmdr.right_laser;
927 break;
928
929 case SCR_LEFT_VIEW:
930 laser = cmdr.left_laser;
931 break;
932
933 default:
934 laser = 0;
935 }
936
937 if (laser != 0)
938 {
939 laser_counter = (laser > 127) ? 0 : (laser & 0xFA);
940 laser &= 127;
941 laser2 = laser;
942
943 snd_play_sample (SND_PULSE);
944 laser_temp += 8;
945 if (energy > 1)
946 energy--;
947
948 laser_x = ((rand() & 3) + 128 - 2) * GFX_SCALE;
949 laser_y = ((rand() & 3) + 96 - 2) * GFX_SCALE;
950
951 return 2;
952 }
953 }
954
955 return 0;
956 }
957
958
959 void cool_laser (void)
960 {
961 laser = 0;
962
963 if (laser_temp > 0)
964 laser_temp--;
965
966 if (laser_counter > 0)
967 laser_counter--;
968
969 if (laser_counter > 0)
970 laser_counter--;
971 }
972
973
974 int create_other_ship (int type)
975 {
976 Matrix rotmat;
977 int x,y,z;
978 int newship;
979
980 set_init_matrix (rotmat);
981
982 z = 12000;
983 x = 1000 + (randint() & 8191);
984 y = 1000 + (randint() & 8191);
985
986 if (rand255() > 127)
987 x = -x;
988 if (rand255() > 127)
989 y = -y;
990
991 newship = add_new_ship (type, x, y, z, rotmat, 0, 0);
992
993 return newship;
994 }
995
996
997 void create_thargoid (void)
998 {
999 int newship;
1000
1001 newship = create_other_ship (SHIP_THARGOID);
1002 if (newship != -1)
1003 {
1004 universe[newship].flags = FLG_ANGRY | FLG_HAS_ECM | FLG_TARGET;
1005 universe[newship].bravery = 113;
1006
1007 if (rand255() > 64)
1008 launch_enemy (newship, SHIP_THARGLET, FLG_ANGRY | FLG_HAS_ECM,
1009 96);
1010 in_battle = 1;
1011 }
1012 }
1013
1014
1015
1016 void create_cougar (void)
1017 {
1018 int newship;
1019
1020 if (ship_count[SHIP_COUGAR] != 0)
1021 return;
1022
1023 newship = create_other_ship (SHIP_COUGAR);
1024 if (newship != -1)
1025 {
1026 universe[newship].flags = FLG_HAS_ECM; // | FLG_CLOAKED;
1027 universe[newship].bravery = 121;
1028 universe[newship].velocity = 18;
1029 }
1030 }
1031
1032
1033
1034 void create_trader (void)
1035 {
1036 int newship;
1037 int rnd;
1038 int type;
1039
1040 type = SHIP_COBRA3 + (rand255() & 3);
1041
1042 newship = create_other_ship (type);
1043
1044 if (newship != -1)
1045 {
1046 universe[newship].rotmat[2].z = -1.0;
1047 universe[newship].rotz = rand255() & 7;
1048
1049 rnd = rand255();
1050 universe[newship].velocity = (rnd & 31) | 16;
1051 universe[newship].bravery = rnd / 2;
1052
1053 if (rnd & 1)
1054 universe[newship].flags |= FLG_HAS_ECM;
1055
1056 if (rnd > (type == SHIP_ANACONDA ? 250 : 220))
1057 universe[newship].flags |= FLG_ANGRY | FLG_TARGET;
1058 }
1059 }
1060
1061
1062 void create_lone_hunter (void)
1063 {
1064 int rnd;
1065 int type;
1066 int newship;
1067
1068 if ((cmdr.mission == 1) && (cmdr.galaxy_number == 1) &&
1069 (docked_planet.d == 144) && (docked_planet.b == 33) &&
1070 (ship_count[SHIP_CONSTRICTOR] == 0))
1071 {
1072 type = SHIP_CONSTRICTOR;
1073 }
1074 else
1075 {
1076 rnd = rand255();
1077 type = SHIP_COBRA3_LONE + (rnd & 3) + (rnd > 127);
1078 }
1079
1080 newship = create_other_ship (type);
1081
1082 if (newship != -1)
1083 {
1084 // universe[newship].flags = FLG_ANGRY;
1085 if ((rand255() > 200) || (type == SHIP_CONSTRICTOR))
1086 universe[newship].flags |= FLG_HAS_ECM;
1087
1088 universe[newship].bravery = ((rand255() * 2) | 64) & 127;
1089 if (type == SHIP_FER_DE_LANCE) {
1090 if (rand255() > 160)
1091 universe[newship].flags |= FLG_ANGRY | FLG_TARGET;
1092 else {
1093 universe[newship].rotmat[2].z = -1.0;
1094 universe[newship].rotz = rand255() & 7;
1095 rnd = rand255();
1096 universe[newship].velocity = (rnd & 31) | 16;
1097 }
1098 }
1099
1100 if (universe[newship].flags & FLG_ANGRY)
1101 in_battle = 1;
1102 }
1103 }
1104
1105
1106
1107 /* Check for a random asteroid encounter... */
1108
1109 void check_for_asteroids (void)
1110 {
1111 int newship;
1112 int type;
1113
1114 if ((rand255() >= 35) || (ship_count[SHIP_ASTEROID] >= 3))
1115 return;
1116
1117 if (rand255() > 253)
1118 type = SHIP_HERMIT;
1119 else
1120 type = SHIP_ASTEROID;
1121
1122 newship = create_other_ship (type);
1123
1124 if (newship != -1)
1125 {
1126 // universe[newship].velocity = (rand255() & 31) | 16;
1127 universe[newship].velocity = 8;
1128 universe[newship].rotz = rand255() > 127 ? -127 : 127;
1129 universe[newship].rotx = 16;
1130 }
1131 }
1132
1133
1134
1135 /* If we've been a bad boy then send the cops after us... */
1136
1137 void check_for_cops (void)
1138 {
1139 int newship;
1140 int offense;
1141
1142 offense = carrying_contraband() * 2;
1143 if (ship_count[SHIP_VIPER] == 0)
1144 offense |= cmdr.legal_status;
1145
1146 if (rand255() >= offense)
1147 return;
1148
1149 newship = create_other_ship (SHIP_VIPER);
1150
1151 if (newship != -1)
1152 {
1153 universe[newship].flags |= FLG_ANGRY | FLG_TARGET;
1154 if (rand255() > 245)
1155 universe[newship].flags |= FLG_HAS_ECM;
1156
1157 universe[newship].bravery = ((rand255() * 2) | 64) & 127;
1158 }
1159 }
1160
1161
1162 void check_for_others (void)
1163 {
1164 int x,y,z;
1165 int newship;
1166 Matrix rotmat;
1167 int gov;
1168 int rnd;
1169 int type;
1170 int i;
1171
1172 gov = current_planet_data.government;
1173 rnd = rand255();
1174
1175 if ((gov != 0) && ((rnd >= 90) || ((rnd & 7) < gov)))
1176 return;
1177
1178 if (rand255() < 100)
1179 {
1180 create_lone_hunter();
1181 return;
1182 }
1183
1184 /* Pack hunters... */
1185
1186 set_init_matrix (rotmat);
1187
1188 z = 12000;
1189 x = 1000 + (randint() & 8191);
1190 y = 1000 + (randint() & 8191);
1191
1192 if (rand255() > 127)
1193 x = -x;
1194 if (rand255() > 127)
1195 y = -y;
1196
1197 rnd = rand255() & 3;
1198
1199 for (i = 0; i <= rnd; i++)
1200 {
1201 type = SHIP_SIDEWINDER + (rand255() & rand255() & 7);
1202 newship = add_new_ship (type, x, y, z, rotmat, 0, 0);
1203 if (newship != -1)
1204 {
1205 universe[newship].flags |= FLG_ANGRY | FLG_TARGET;
1206 if (rand255() > 245)
1207 universe[newship].flags |= FLG_HAS_ECM;
1208
1209 universe[newship].bravery = ((rand255() * 2) | 64) & 127;
1210 in_battle++;
1211 }
1212 }
1213
1214 }
1215
1216
1217 void random_encounter (void)
1218 {
1219 if ((ship_count[SHIP_CORIOLIS] != 0) || (ship_count[SHIP_DODEC] != 0))
1220 return;
1221
1222 if (rand255() == 136)
1223 {
1224 if (((int)(universe[0].location.z) & 0x3e) != 0)
1225 create_thargoid ();
1226 else
1227 create_cougar();
1228
1229 return;
1230 }
1231
1232 if ((rand255() & 7) == 0)
1233 {
1234 create_trader();
1235 return;
1236 }
1237
1238 check_for_asteroids();
1239
1240 check_for_cops();
1241
1242 if (ship_count[SHIP_VIPER] != 0)
1243 return;
1244
1245 if (in_battle)
1246 return;
1247
1248 if ((cmdr.mission == 5) && (rand255() >= 200))
1249 create_thargoid ();
1250
1251 check_for_others();
1252 }
1253
1254
1255 void abandon_ship (void)
1256 {
1257 int i;
1258
1259 cmdr.escape_pod = 0;
1260 cmdr.legal_status = 0;
1261 cmdr.fuel = myship.max_fuel;
1262
1263 for (i = 0; i < NO_OF_STOCK_ITEMS; i++)
1264 cmdr.current_cargo[i] = 0;
1265
1266 snd_play_sample (SND_DOCK);
1267 dock_player();
1268 current_screen = SCR_BREAK_PATTERN;
1269 }
1270