chiark / gitweb /
Ignore binary.
[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 (type > SHIP_ROCK)
326         {
327                 universe[un].rotx = 4;
328                 universe[un].acceleration = 2;
329                 universe[un].flags |= FLG_ANGRY | FLG_TACTICAL;
330         }
331 }
332
333
334 void explode_object (int un)
335 {
336
337         cmdr.score++;
338
339         if ((cmdr.score & 255) == 0)
340                 info_message ("Right On Commander!");
341         
342         snd_play_sample (SND_EXPLODE);
343         universe[un].flags |= FLG_DEAD;
344
345         if (universe[un].type == SHIP_CONSTRICTOR)
346                 cmdr.mission = 2;
347 }
348
349
350 void check_target (int un, struct univ_object *flip)
351 {
352         struct univ_object *univ;
353         
354         univ = &universe[un];
355         
356         if (in_target (univ->type, flip->location.x, flip->location.y, flip->location.z))
357         {
358                 if ((missile_target == MISSILE_ARMED) && (univ->type >= 0))
359                 {
360                         missile_target = un;
361                         info_message ("Target Locked");
362                         snd_play_sample (SND_BEEP);
363                 }
364         
365                 if (laser)
366                 {
367                         snd_play_sample (SND_HIT_ENEMY);
368
369                         if ((univ->type != SHIP_CORIOLIS) && (univ->type != SHIP_DODEC))
370                         {                       
371                                 if ((univ->type == SHIP_CONSTRICTOR) || (univ->type == SHIP_COUGAR))
372                                 {
373                                         if (laser == (MILITARY_LASER & 127))
374                                                 univ->energy -= laser / 4;
375                                 }
376                                 else
377                                 {
378                                         univ->energy -= laser;
379                                 }
380                         }
381
382                         if (univ->energy <= 0)
383                         {
384                                 explode_object (un);
385                                 
386                                 if (univ->type == SHIP_ASTEROID)
387                                 {
388                                         if (laser == (MINING_LASER & 127))
389                                             launch_loot (un, SHIP_ROCK);
390                                 }
391                                 else
392                                 {
393                                         launch_loot (un, SHIP_ALLOY);
394                                         launch_loot (un, SHIP_CARGO); 
395                                 }
396                         }
397                                         
398                         make_angry (un);
399                 }
400         }
401 }
402
403
404
405 void activate_ecm (int ours)
406 {
407         if (ecm_active == 0)
408         {
409                 ecm_active = 32;
410                 ecm_ours = ours;
411                 snd_play_sample (SND_ECM);
412         }
413 }
414
415
416 void time_ecm (void)
417 {
418         if (ecm_active != 0)
419         {
420                 ecm_active--;
421                 if (ecm_ours)
422                         decrease_energy (-1);
423         }
424 }
425
426
427 void arm_missile (void)
428 {
429         if ((cmdr.missiles != 0) && (missile_target == MISSILE_UNARMED))
430                 missile_target = MISSILE_ARMED;
431 }
432
433
434 void unarm_missile (void)
435 {
436         missile_target = MISSILE_UNARMED;
437         snd_play_sample (SND_BOOP);
438 }
439
440 void fire_missile (void)
441 {
442         int newship;
443         struct univ_object *ns;
444         Matrix rotmat;
445
446         if (missile_target < 0)
447                 return;
448         
449         set_init_matrix (rotmat);
450         rotmat[2].z = 1.0;
451         rotmat[0].x = -1.0;
452         
453         newship = add_new_ship (SHIP_MISSILE, 0, -28, 14, rotmat, 0, 0);
454
455         if (newship == -1)
456         {
457                 info_message ("Missile Jammed");
458                 return;
459         }
460
461         ns = &universe[newship];
462         
463         ns->velocity = flight_speed * 2;
464         ns->flags |= FLG_TACTICAL;
465         ns->target = missile_target;
466
467         if (universe[missile_target].type > SHIP_ROCK)
468                 universe[missile_target].flags |= FLG_ANGRY;
469         
470         cmdr.missiles--;
471         missile_target = MISSILE_UNARMED;
472         
473         snd_play_sample (SND_MISSILE);
474 }
475
476
477
478 void track_object (struct univ_object *ship, double direction, Vector nvec)
479 {       
480         double dir;
481         int rat;
482         double rat2;
483         
484         rat = 3;
485         rat2 = 0.111;
486         
487         dir = vector_dot_product (&nvec, &ship->rotmat[1]);
488
489         if (direction < -0.861)
490         {
491                 ship->rotx = (dir < 0) ? 7 : -7;
492                 ship->rotz = 0;
493                 return; 
494         }
495         
496         ship->rotx = 0;
497         
498         if ((fabs(dir) * 2) >= rat2)
499         {
500                 ship->rotx = (dir < 0) ? rat : -rat;
501         }
502                 
503         if (abs(ship->rotz) < 16)
504         {
505                 dir = vector_dot_product (&nvec, &ship->rotmat[0]);
506
507                 ship->rotz = 0;
508
509                 if ((fabs(dir) * 2) > rat2)
510                 {
511                         ship->rotz = (dir < 0) ? rat : -rat;
512
513                         if (ship->rotx < 0)
514                                 ship->rotz = -ship->rotz;
515                 }               
516         }
517 }
518
519
520
521 void missile_tactics (int un)
522 {
523         struct univ_object *missile;
524         struct univ_object *target;
525         Vector vec;
526         Vector nvec;
527         double direction;
528         double cnt2 = 0.223;
529         
530         missile = &universe[un];
531         
532         if (ecm_active)
533         {
534                 snd_play_sample (SND_EXPLODE);
535                 missile->flags |= FLG_DEAD;             
536                 return;
537         }
538
539         if (missile->target == 0)
540         {
541                 if (missile->distance < 256)
542                 {
543                         missile->flags |= FLG_DEAD;
544                         snd_play_sample (SND_EXPLODE);
545                         damage_ship (250, missile->location.z >= 0.0);
546                         return;
547                 }
548
549                 vec.x = missile->location.x;
550                 vec.y = missile->location.y;
551                 vec.z = missile->location.z;
552         }
553         else
554         {
555                 target = &universe[missile->target];
556
557                 vec.x = missile->location.x - target->location.x;
558                 vec.y = missile->location.y - target->location.y;
559                 vec.z = missile->location.z - target->location.z;
560         
561                 if ((fabs(vec.x) < 256) && (fabs(vec.y) < 256) && (fabs(vec.z) < 256))
562                 {
563                         missile->flags |= FLG_DEAD;             
564
565                         if ((target->type != SHIP_CORIOLIS) && (target->type != SHIP_DODEC))
566                                 explode_object (missile->target);
567                         else
568                                 snd_play_sample (SND_EXPLODE);
569
570                         return;
571                 }
572
573                 if ((rand255() < 16) && (target->flags & FLG_HAS_ECM))
574                 {
575                         activate_ecm (0);
576                         return;
577                 }
578         }
579
580         if ((rand255() < 16) &&
581                 (ship_count[SHIP_CORIOLIS] || ship_count[SHIP_DODEC])) {
582           activate_ecm(0);
583           return;
584         }
585
586         nvec = unit_vector(&vec);
587         direction = vector_dot_product (&nvec, &missile->rotmat[2]); 
588         nvec.x = -nvec.x;
589         nvec.y = -nvec.y;
590         nvec.z = -nvec.z;
591         direction = -direction;
592
593         track_object (missile, direction, nvec);
594
595         if (direction <= -0.167)
596         {
597                 missile->acceleration = -2;
598                 return;
599         }
600
601         if (direction >= cnt2)
602         {
603                 missile->acceleration = 3;
604                 return;
605         }
606
607         if (missile->velocity < 6)
608                 missile->acceleration = 3;
609         else
610                 if (rand255() >= 200)
611                         missile->acceleration = -2;
612         return;
613 }
614
615
616
617 void launch_shuttle (void)
618 {
619         int type;
620
621         if ((ship_count[SHIP_TRANSPORTER] != 0) ||
622                 (ship_count[SHIP_SHUTTLE] != 0) ||
623                 (rand255() < 253) || (auto_pilot))
624                 return;
625
626         type = rand255() & 1 ? SHIP_SHUTTLE : SHIP_TRANSPORTER; 
627         launch_enemy (1, type, FLG_HAS_ECM | FLG_FLY_TO_PLANET, 113);
628 }
629
630
631 void tactics (int un)
632 {
633         int type;
634         int energy;
635         int maxeng;
636         int flags;
637         struct univ_object *ship;
638         Vector nvec;
639         double cnt2 = 0.223;
640         double direction;
641         int attacking;
642         
643         ship = &universe[un];
644         type = ship->type;
645         flags = ship->flags;
646
647         if ((type == SHIP_PLANET) || (type == SHIP_SUN))
648                 return;
649         
650         if (flags & FLG_DEAD)
651                 return;
652
653         if (flags & FLG_INACTIVE)
654                 return;
655         
656         if (type == SHIP_MISSILE)
657         {
658                 if (flags & FLG_ANGRY)
659                         missile_tactics (un);
660                 return;
661         }
662
663         if (((un ^ mcount) & 7) != 0)
664                 return;
665
666         if ((type == SHIP_CORIOLIS) || (type == SHIP_DODEC))
667         {
668                 if (flags & FLG_ANGRY) 
669                 {
670                         if ((rand() & 255) < 240)
671                                 return;
672                 
673                         if (ship_count[SHIP_VIPER] >= 4)
674                                 return; 
675
676                         launch_enemy (un, SHIP_VIPER, FLG_ANGRY | FLG_HAS_ECM, 113);
677                         return;
678                 }
679
680                 launch_shuttle ();
681                 return;
682         }
683
684         if (type == SHIP_HERMIT)
685         {
686                 if (rand255() > 200)
687                 {
688                         launch_enemy (un, SHIP_SIDEWINDER + (rand255() & 3), FLG_ANGRY | FLG_HAS_ECM, 113);
689                         ship->flags |= FLG_INACTIVE | FLG_TARGET;
690                 }
691
692                 return;
693         }
694         
695         
696         if (ship->energy < ship_list[type]->energy)
697                 ship->energy++;
698
699         if ((type == SHIP_THARGLET) && (ship_count[SHIP_THARGOID] == 0))
700         {
701                 ship->flags &= FLG_TARGET | FLG_TACTICAL;
702                 ship->velocity /= 2;
703                 return;
704         }
705
706         if (flags & FLG_SLOW)
707         {
708                 if (rand255() > 50)
709                         return;
710         }
711
712         if (flags & FLG_POLICE)
713         {
714                 if (cmdr.legal_status >= 64)
715                 {
716                         flags |= FLG_ANGRY;
717                         ship->flags = flags;
718                 }
719         }
720         
721         if ((flags & FLG_ANGRY) == 0)
722         {
723                 if ((flags & FLG_FLY_TO_PLANET) || (flags & FLG_FLY_TO_STATION))
724                 {
725                         auto_pilot_ship (&universe[un]);
726                 }
727
728                 return;
729         }
730
731         
732         /* If we get to here then the ship is angry so start attacking... */
733
734         if (ship_count[SHIP_CORIOLIS] || ship_count[SHIP_DODEC])
735         {
736                 if ((flags & FLG_BOLD) == 0)
737                         ship->bravery = 0;
738         }
739
740         
741         if (type == SHIP_ANACONDA)
742         {
743                 if (rand255() > 200)
744                 {
745                         launch_enemy (un, rand255() > 100 ? SHIP_WORM : SHIP_SIDEWINDER,
746                                                   FLG_ANGRY | FLG_HAS_ECM, 113);
747                         return;
748                 }
749         }
750
751         
752         if (rand255() >= 250)
753         {
754                 ship->rotz = rand255() | 0x68;
755                 if (ship->rotz > 127)
756                         ship->rotz = -(ship->rotz & 127);
757         }
758         
759         maxeng = ship_list[type]->energy;
760         energy = ship->energy;
761
762         if (energy < (maxeng / 2))
763         {
764                 if ((energy < (maxeng / 8)) && (rand255() > 230) && (type != SHIP_THARGOID))
765                 {
766                         ship->flags &= ~FLG_ANGRY;
767                         ship->flags |= FLG_INACTIVE;
768                         launch_enemy (un, SHIP_ESCAPE_CAPSULE, 0, 126);
769                         return;                         
770                 }
771
772                 if ((ship->missiles != 0) && (ecm_active == 0) &&
773                         (ship->missiles >= (rand255() & 31)))
774                 {
775                         ship->missiles--;
776                         ship->flags |= FLG_TACTICAL;
777                         if (type == SHIP_THARGOID)
778                                 launch_enemy (un, SHIP_THARGLET, FLG_ANGRY, ship->bravery);
779                         else
780                         {
781                                 launch_enemy (un, SHIP_MISSILE, FLG_ANGRY, 126);
782                                 ship->flags |= FLG_HOSTILE;
783                                 info_message ("INCOMING MISSILE");
784                         }
785                         return;
786                 }
787         }
788
789         nvec = unit_vector(&universe[un].location);
790         direction = vector_dot_product (&nvec, &ship->rotmat[2]); 
791         
792         if      ((ship->distance < 8192) && (direction <= -0.833) &&
793                  (ship_list[type]->laser_strength != 0))
794         {
795                 if (direction <= -0.917)
796                         ship->flags |= FLG_FIRING | FLG_HOSTILE | FLG_TACTICAL;         
797
798                 if (direction <= -0.972)
799                 {
800                         damage_ship (ship_list[type]->laser_strength, ship->location.z >= 0.0);
801                         ship->acceleration--;
802                         if (((ship->location.z >= 0.0) && (front_shield == 0)) ||
803                                 ((ship->location.z < 0.0) && (aft_shield == 0)))
804                                 snd_play_sample (SND_INCOMMING_FIRE_2);
805                         else
806                                 snd_play_sample (SND_INCOMMING_FIRE_1);
807                 }                               
808                 else
809                 {
810                         nvec.x = -nvec.x;
811                         nvec.y = -nvec.y;
812                         nvec.z = -nvec.z;
813                         direction = -direction;
814                         track_object (&universe[un], direction, nvec);
815                 }
816
817 //              if ((fabs(ship->location.z) < 768) && (ship->bravery <= ((rand255() & 127) | 64)))
818                 if (fabs(ship->location.z) < 768)
819                 {
820                         ship->rotx = rand255() & 0x87;
821                         if (ship->rotx > 127)
822                                 ship->rotx = -(ship->rotx & 127);
823
824                         ship->acceleration = 3;
825                         return;
826                 }
827
828                 if (ship->distance < 8192)
829                         ship->acceleration = -1;
830                 else
831                         ship->acceleration = 3;
832                 return;
833         } 
834
835         attacking = 0;
836
837         if ((fabs(ship->location.z) >= 768) ||
838                 (fabs(ship->location.x) >= 512) ||
839                 (fabs(ship->location.y) >= 512))
840         {
841                 if (ship->bravery > (rand255() & 127))
842                 {
843                         attacking = 1;
844                         nvec.x = -nvec.x;
845                         nvec.y = -nvec.y;
846                         nvec.z = -nvec.z;
847                         direction = -direction;
848                 }
849         }
850
851         track_object (&universe[un], direction, nvec);
852
853         if ((attacking == 1) && (ship->distance < 2048))
854         {
855                 if (direction >= cnt2)
856                 {
857                         ship->acceleration = -1;
858                         return;
859                 }
860
861                 if (ship->velocity < 6)
862                         ship->acceleration = 3;
863                 else
864                         if (rand255() >= 200)
865                                 ship->acceleration = -1;
866                 return;
867         }
868         
869         if (direction <= -0.167)
870         {
871                 ship->acceleration = -1;
872                 return;
873         }
874
875         if (direction >= cnt2)
876         {
877                 ship->acceleration = 3;
878                 return;
879         }
880                  
881         if (ship->velocity < 6)
882                 ship->acceleration = 3;
883         else
884                 if (rand255() >= 200)
885                         ship->acceleration = -1;
886 }
887
888
889 void draw_laser_lines (void)
890 {
891         if (wireframe)
892         {
893                 gfx_draw_colour_line (32 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, GFX_COL_WHITE);
894                 gfx_draw_colour_line (48 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, GFX_COL_WHITE);
895                 gfx_draw_colour_line (208 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, GFX_COL_WHITE);
896                 gfx_draw_colour_line (224 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, GFX_COL_WHITE);
897         }
898         else
899         {
900                 gfx_draw_triangle (32 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y,  48 * GFX_SCALE, GFX_VIEW_BY, GFX_COL_RED);
901                 gfx_draw_triangle (208 * GFX_SCALE, GFX_VIEW_BY, laser_x, laser_y, 224 * GFX_SCALE, GFX_VIEW_BY, GFX_COL_RED);
902         }                
903 }
904
905
906 int fire_laser (void)
907 {
908         if ((laser_counter == 0) && (laser_temp < 242))
909         {
910                 switch (current_screen)
911                 {
912                         case SCR_FRONT_VIEW:
913                                 laser = cmdr.front_laser;
914                                 break;
915                         
916                         case SCR_REAR_VIEW:
917                                 laser = cmdr.rear_laser;
918                                 break;
919                                         
920                         case SCR_RIGHT_VIEW:
921                                 laser = cmdr.right_laser;
922                                 break;
923                                         
924                         case SCR_LEFT_VIEW:
925                                 laser = cmdr.left_laser;
926                                 break;
927                                 
928                         default:
929                                 laser = 0;
930                 }
931
932                 if (laser != 0)
933                 {
934                         laser_counter = (laser > 127) ? 0 : (laser & 0xFA);
935                         laser &= 127;
936                         laser2 = laser;
937
938                         snd_play_sample (SND_PULSE);
939                         laser_temp += 8;
940                         if (energy > 1)
941                                 energy--;
942                         
943                         laser_x = ((rand() & 3) + 128 - 2) * GFX_SCALE;
944                         laser_y = ((rand() & 3) + 96 - 2) * GFX_SCALE;
945                         
946                         return 2;
947                 }
948         }
949
950         return 0;
951 }
952
953
954 void cool_laser (void)
955 {
956         laser = 0;
957
958         if (laser_temp > 0)
959                 laser_temp--;
960                                         
961         if (laser_counter > 0)
962                 laser_counter--;
963                                 
964         if (laser_counter > 0)
965                 laser_counter--;
966 }
967
968
969 int create_other_ship (int type)
970 {
971         Matrix rotmat;
972         int x,y,z;
973         int newship;
974         
975         set_init_matrix (rotmat);
976
977         z = 12000;
978         x = 1000 + (randint() & 8191);
979         y = 1000 + (randint() & 8191);
980
981         if (rand255() > 127)
982                 x = -x;
983         if (rand255() > 127)
984                 y = -y;
985
986         newship = add_new_ship (type, x, y, z, rotmat, 0, 0);
987
988         return newship;
989 }
990
991
992 void create_thargoid (void)
993 {
994         int newship;
995         
996         newship = create_other_ship (SHIP_THARGOID);
997         if (newship != -1)
998         {
999                 universe[newship].flags = FLG_ANGRY | FLG_HAS_ECM | FLG_TARGET;
1000                 universe[newship].bravery = 113;
1001
1002                 if (rand255() > 64)
1003                         launch_enemy (newship, SHIP_THARGLET, FLG_ANGRY | FLG_HAS_ECM,
1004                                                   96);
1005                 in_battle = 1;
1006         }       
1007 }
1008
1009
1010
1011 void create_cougar (void)
1012 {
1013         int newship;
1014
1015         if (ship_count[SHIP_COUGAR] != 0)
1016                 return;
1017         
1018         newship = create_other_ship (SHIP_COUGAR);
1019         if (newship != -1)
1020         {
1021                 universe[newship].flags = FLG_HAS_ECM; // | FLG_CLOAKED;
1022                 universe[newship].bravery = 121;
1023                 universe[newship].velocity = 18;
1024         }       
1025 }
1026
1027
1028
1029 void create_trader (void)
1030 {
1031         int newship;
1032         int rnd;
1033         int type;
1034
1035         type = SHIP_COBRA3 + (rand255() & 3);
1036
1037         newship = create_other_ship (type);
1038         
1039         if (newship != -1)
1040         {
1041                 universe[newship].rotmat[2].z = -1.0;
1042                 universe[newship].rotz = rand255() & 7;
1043                 
1044                 rnd = rand255();
1045                 universe[newship].velocity = (rnd & 31) | 16;
1046                 universe[newship].bravery = rnd / 2;
1047
1048                 if (rnd & 1)
1049                         universe[newship].flags |= FLG_HAS_ECM;
1050
1051                 if (rnd > 200)
1052                         universe[newship].flags |= FLG_ANGRY | FLG_TARGET; 
1053         }
1054 }
1055
1056
1057 void create_lone_hunter (void)
1058 {
1059         int rnd;
1060         int type;
1061         int newship;
1062
1063         if ((cmdr.mission == 1) && (cmdr.galaxy_number == 1) &&
1064                 (docked_planet.d == 144) && (docked_planet.b == 33) &&
1065                 (ship_count[SHIP_CONSTRICTOR] == 0))
1066         {
1067                 type = SHIP_CONSTRICTOR;
1068         }
1069         else
1070         {
1071                 rnd = rand255();
1072                 type = SHIP_COBRA3_LONE + (rnd & 3) + (rnd > 127);
1073         }
1074                 
1075         newship = create_other_ship (type);
1076
1077         if (newship != -1)
1078         {
1079                 // universe[newship].flags = FLG_ANGRY;
1080                 if ((rand255() > 200) || (type == SHIP_CONSTRICTOR))
1081                         universe[newship].flags |= FLG_HAS_ECM;
1082                 
1083                 universe[newship].bravery = ((rand255() * 2) | 64) & 127;
1084                 if (type == SHIP_FER_DE_LANCE) {
1085                   if (rand255() > 160)
1086                         universe[newship].flags |= FLG_ANGRY | FLG_TARGET;
1087                   else {
1088                         universe[newship].rotmat[2].z = -1.0;
1089                         universe[newship].rotz = rand255() & 7;         
1090                         rnd = rand255();
1091                         universe[newship].velocity = (rnd & 31) | 16;
1092                   }
1093                 }
1094                         
1095                 if (universe[newship].flags & FLG_ANGRY)
1096                   in_battle = 1;  
1097         }       
1098 }
1099
1100
1101
1102 /* Check for a random asteroid encounter... */
1103
1104 void check_for_asteroids (void)
1105 {
1106         int newship;
1107         int type;
1108
1109         if ((rand255() >= 35) || (ship_count[SHIP_ASTEROID] >= 3))
1110                 return;
1111
1112         if (rand255() > 253)
1113                 type = SHIP_HERMIT;
1114         else
1115                 type = SHIP_ASTEROID;
1116                 
1117         newship = create_other_ship (type);
1118         
1119         if (newship != -1)
1120         {
1121 //              universe[newship].velocity = (rand255() & 31) | 16; 
1122                 universe[newship].velocity = 8;
1123                 universe[newship].rotz = rand255() > 127 ? -127 : 127; 
1124                 universe[newship].rotx = 16; 
1125         }
1126 }
1127
1128
1129
1130 /* If we've been a bad boy then send the cops after us... */
1131
1132 void check_for_cops (void)
1133 {
1134         int newship;
1135         int offense;
1136
1137         offense = carrying_contraband() * 2;
1138         if (ship_count[SHIP_VIPER] == 0)
1139                 offense |= cmdr.legal_status;
1140
1141         if (rand255() >= offense)
1142                 return;
1143
1144         newship = create_other_ship (SHIP_VIPER);
1145         
1146         if (newship != -1)
1147         {
1148                 universe[newship].flags |= FLG_ANGRY;
1149                 if (rand255() > 245)
1150                         universe[newship].flags |= FLG_HAS_ECM;
1151                 
1152                 universe[newship].bravery = ((rand255() * 2) | 64) & 127;  
1153         }
1154 }
1155
1156
1157 void check_for_others (void)
1158 {
1159         int x,y,z;
1160         int newship;
1161         Matrix rotmat;
1162         int gov;
1163         int rnd;
1164         int type;
1165         int i;
1166
1167         gov = current_planet_data.government; 
1168         rnd = rand255();
1169
1170         if ((gov != 0) && ((rnd >= 90) || ((rnd & 7) < gov)))
1171                 return; 
1172
1173         if (rand255() < 100)
1174         {
1175                 create_lone_hunter();
1176                 return;
1177         }       
1178
1179         /* Pack hunters... */
1180         
1181         set_init_matrix (rotmat);
1182
1183         z = 12000;
1184         x = 1000 + (randint() & 8191);
1185         y = 1000 + (randint() & 8191);
1186
1187         if (rand255() > 127)
1188                 x = -x;
1189         if (rand255() > 127)
1190                 y = -y;
1191
1192         rnd = rand255() & 3;
1193         
1194         for (i = 0; i <= rnd; i++)
1195         {
1196                 type = SHIP_SIDEWINDER + (rand255() & rand255() & 7);
1197                 newship = add_new_ship (type, x, y, z, rotmat, 0, 0);
1198                 if (newship != -1)
1199                 {
1200                         universe[newship].flags |= FLG_ANGRY | FLG_TARGET;
1201                         if (rand255() > 245)
1202                                 universe[newship].flags |= FLG_HAS_ECM;
1203                 
1204                         universe[newship].bravery = ((rand255() * 2) | 64) & 127;
1205                         in_battle++;  
1206                 }
1207         }
1208         
1209 }
1210
1211
1212 void random_encounter (void)
1213 {
1214         if ((ship_count[SHIP_CORIOLIS] != 0) || (ship_count[SHIP_DODEC] != 0))
1215                 return;
1216
1217         if (rand255() == 136)
1218         {
1219                 if (((int)(universe[0].location.z) & 0x3e) != 0)
1220                         create_thargoid ();
1221                 else
1222                         create_cougar();                        
1223
1224                 return;
1225         }               
1226
1227         if ((rand255() & 7) == 0)
1228         {
1229                 create_trader();
1230                 return;
1231         }
1232                 
1233         check_for_asteroids();
1234
1235         check_for_cops();       
1236
1237         if (ship_count[SHIP_VIPER] != 0)
1238                 return;
1239
1240         if (in_battle)
1241                 return;
1242
1243         if ((cmdr.mission == 5) && (rand255() >= 200))
1244                 create_thargoid ();
1245                 
1246         check_for_others();     
1247 }
1248
1249
1250 void abandon_ship (void)
1251 {
1252         int i;
1253
1254         cmdr.escape_pod = 0;
1255         cmdr.legal_status = 0;
1256         cmdr.fuel = myship.max_fuel;
1257         
1258         for (i = 0; i < NO_OF_STOCK_ITEMS; i++)
1259                 cmdr.current_cargo[i] = 0;
1260         
1261         snd_play_sample (SND_DOCK);                                     
1262         dock_player();
1263         current_screen = SCR_BREAK_PATTERN;
1264 }
1265