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