chiark / gitweb /
c44d939a8b080ddb4be695a8c68111073b7dc40e
[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