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