chiark / gitweb /
11b16a8e9055c2bd8c993e10a84d650f11d6157d
[newkind] / space.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  * space.c
17  *
18  * This module handles all the flight system and management of the space universe.
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <math.h>
24 #include <stdlib.h>
25
26 #include "vector.h"
27
28 #include "alg_data.h"
29
30 #include "config.h"
31 #include "elite.h"
32 #include "keyboard.h"
33 #include "gfx.h"
34 #include "docked.h"
35 #include "intro.h"
36 #include "shipdata.h"
37 #include "shipface.h"
38 #include "space.h" 
39 #include "threed.h"
40 #include "sound.h"
41 #include "main.h"
42 #include "swat.h"
43 #include "random.h"
44 #include "trade.h"
45 #include "stars.h"
46 #include "pilot.h"
47
48 extern int flight_climb;
49 extern int flight_roll;
50 extern int flight_speed;
51
52 struct galaxy_seed destination_planet;
53 int hyper_ready;
54 int hyper_countdown;
55 char hyper_name[16];
56 int hyper_distance;
57 int hyper_galactic;
58
59
60
61
62
63
64 void rotate_x_first (double *a, double *b, int direction)
65 {
66         double fx,ux;
67
68         fx = *a;
69         ux = *b;
70
71         if (direction < 0)
72         {       
73                 *a = fx - (fx / 512) + (ux / 19);
74                 *b = ux - (ux / 512) - (fx / 19);
75         }
76         else
77         {
78                 *a = fx - (fx / 512) - (ux / 19);
79                 *b = ux - (ux / 512) + (fx / 19);
80         }
81 }
82
83
84 void rotate_vec (struct vector *vec, double alpha, double beta)
85 {
86         double x,y,z;
87         
88         x = vec->x;
89         y = vec->y;
90         z = vec->z;
91
92         y = y - alpha * x;
93         x = x + alpha * y;
94         y = y - beta * z;
95         z = z + beta * y;
96         
97         vec->x = x;
98         vec->y = y;
99         vec->z = z;
100 }
101
102
103 /*
104  * Update an objects location in the universe.
105  */
106
107 void move_univ_object (struct univ_object *obj)
108 {
109         double x,y,z;
110         double k2;
111         double alpha;
112         double beta;
113         int rotx,rotz;
114         double speed;
115         
116         alpha = flight_roll / 256.0;
117         beta = flight_climb / 256.0;
118         
119         x = obj->location.x;
120         y = obj->location.y;
121         z = obj->location.z;
122
123         if (!(obj->flags & FLG_DEAD))
124         { 
125                 if (obj->velocity != 0)
126                 {
127                         speed = obj->velocity;
128                         speed *= 1.5;   
129                         x += obj->rotmat[2].x * speed; 
130                         y += obj->rotmat[2].y * speed; 
131                         z += obj->rotmat[2].z * speed; 
132                 }
133
134                 if (obj->acceleration != 0)
135                 {
136                         obj->velocity += obj->acceleration;
137                         obj->acceleration = 0;
138                         if (obj->velocity > ship_list[obj->type]->velocity)
139                                 obj->velocity = ship_list[obj->type]->velocity;
140                         
141                         if (obj->velocity <= 0)
142                                 obj->velocity = 1;
143                 }
144         }
145         
146         k2 = y - alpha * x;
147         z = z + beta * k2;
148         y = k2 - z * beta;
149         x = x + alpha * y;
150
151         z = z - flight_speed;
152
153         obj->location.x = x;
154         obj->location.y = y;
155         obj->location.z = z;    
156
157         obj->distance = sqrt (x*x + y*y + z*z);
158         
159         if (obj->type == SHIP_PLANET)
160                 beta = 0.0;
161         
162         rotate_vec (&obj->rotmat[2], alpha, beta);
163         rotate_vec (&obj->rotmat[1], alpha, beta);
164         rotate_vec (&obj->rotmat[0], alpha, beta);
165
166         if (obj->flags & FLG_DEAD)
167                 return;
168
169
170         rotx = obj->rotx;
171         rotz = obj->rotz;
172         
173         /* If necessary rotate the object around the X axis... */
174
175         if (rotx != 0)
176         {
177                 rotate_x_first (&obj->rotmat[2].x, &obj->rotmat[1].x, rotx);
178                 rotate_x_first (&obj->rotmat[2].y, &obj->rotmat[1].y, rotx);    
179                 rotate_x_first (&obj->rotmat[2].z, &obj->rotmat[1].z, rotx);
180
181                 if ((rotx != 127) && (rotx != -127))
182                         obj->rotx -= (rotx < 0) ? -1 : 1;
183         }       
184
185         
186         /* If necessary rotate the object around the Z axis... */
187
188         if (rotz != 0)
189         {       
190                 rotate_x_first (&obj->rotmat[0].x, &obj->rotmat[1].x, rotz);
191                 rotate_x_first (&obj->rotmat[0].y, &obj->rotmat[1].y, rotz);    
192                 rotate_x_first (&obj->rotmat[0].z, &obj->rotmat[1].z, rotz);    
193
194                 if ((rotz != 127) && (rotz != -127))
195                         obj->rotz -= (rotz < 0) ? -1 : 1;
196         }
197
198
199         /* Orthonormalize the rotation matrix... */
200
201         tidy_matrix (obj->rotmat);
202 }
203
204
205 /*
206  * Dock the player into the space station.
207  */
208
209 void dock_player (void)
210 {
211         disengage_auto_pilot();
212         docked = 1;
213         flight_speed = 0;
214         flight_roll = 0;
215         flight_climb = 0;
216         front_shield = 255;
217         aft_shield = 255;
218         energy = 255;
219         myship.altitude = 255;
220         myship.cabtemp = 30;
221         reset_weapons();
222 }
223
224
225 /*
226  * Check if we are correctly aligned to dock.
227  */
228
229 int is_docking (int sn)
230 {
231         struct vector vec;
232         double fz;
233         double ux;
234
235         if (universe[sn].flags & FLG_ANGRY)
236           return (0);
237
238         if (auto_pilot)         // Don't want it to kill anyone!
239                 return 1;
240         
241         fz = universe[sn].rotmat[2].z;
242
243         if (fz > -0.90)
244                 return 0;
245         
246         vec = unit_vector (&universe[sn].location);
247
248         if (vec.z < 0.927)
249                 return 0;
250         
251         ux = universe[sn].rotmat[1].x;
252         if (ux < 0)
253                 ux = -ux;
254         
255         if (ux < 0.84)
256                 return 0;
257          
258         return 1;
259 }
260
261
262 /*
263  * Game Over...
264  */
265
266 void do_game_over (void)
267 {
268         snd_play_sample (SND_GAMEOVER);
269         game_over = 1;
270 }
271
272
273 void update_altitude (void)
274 {
275         double x,y,z;
276         double dist;
277         
278         myship.altitude = 255;
279
280         if (witchspace)
281                 return;
282         
283         x = fabs(universe[0].location.x);
284         y = fabs(universe[0].location.y);
285         z = fabs(universe[0].location.z);
286         
287         if ((x > 65535) || (y > 65535) || (z > 65535))
288                 return;
289
290         x /= 256;
291         y /= 256;
292         z /= 256;
293         
294         dist = (x * x) + (y * y) + (z * z);
295
296         if (dist > 65535)
297                 return;
298         
299         dist -= 9472;
300         if (dist < 1)
301         {
302                 myship.altitude = 0;
303                 do_game_over ();
304                 return;
305         }
306
307         dist = sqrt (dist);
308         if (dist < 1)
309         {
310                 myship.altitude = 0;
311                 do_game_over ();
312                 return;
313         }
314
315         myship.altitude = dist; 
316 }
317
318
319 void update_cabin_temp (void)
320 {
321         int x,y,z;
322         int dist;
323         
324         myship.cabtemp = 30;
325
326         if (witchspace)
327                 return;
328         
329         if (ship_count[SHIP_CORIOLIS] || ship_count[SHIP_DODEC])
330                 return;
331         
332         x = abs((int)universe[1].location.x);
333         y = abs((int)universe[1].location.y);
334         z = abs((int)universe[1].location.z);
335         
336         if ((x > 65535) || (y > 65535) || (z > 65535))
337                 return;
338
339         x /= 256;
340         y /= 256;
341         z /= 256;
342         
343         dist = ((x * x) + (y * y) + (z * z)) / 256;
344
345         if (dist > 255)
346                 return;
347
348         dist ^=  255;
349
350         myship.cabtemp = dist + 30;
351
352         if (myship.cabtemp > 255)
353         {
354                 myship.cabtemp = 255;
355                 do_game_over ();
356                 return;
357         }
358         
359         if ((myship.cabtemp < 224) || (cmdr.fuel_scoop == 0))
360                 return;
361
362         cmdr.fuel += flight_speed / 2;
363         if (cmdr.fuel > myship.max_fuel)
364                 cmdr.fuel = myship.max_fuel;
365
366         info_message ("Fuel Scoop On"); 
367 }
368
369
370
371 /*
372  * Regenerate the shields and the energy banks.
373  */
374
375 void regenerate_shields (void)
376 {
377         if (energy > 127)
378         {
379                 if (front_shield < 255)
380                 {
381                         front_shield++;
382                         energy--;
383                 }
384         
385                 if (aft_shield < 255)
386                 {
387                         aft_shield++;
388                         energy--;
389                 }
390         }
391                 
392         energy++;
393         energy += cmdr.energy_unit;
394         if (energy > 255)
395                 energy = 255;
396 }
397
398
399 void decrease_energy (int amount)
400 {
401         energy += amount;
402
403         if (energy <= 0)
404                 do_game_over();
405 }
406
407
408 /*
409  * Deplete the shields.  Drain the energy banks if the shields fail.
410  */
411
412 void damage_ship (int damage, int front)
413 {
414         int shield;
415
416         if (damage <= 0)        /* sanity check */
417                 return;
418         
419         shield = front ? front_shield : aft_shield;
420         
421         shield -= damage;
422         if (shield < 0)
423         {
424                 decrease_energy (shield);
425                 shield = 0;
426         }
427         
428         if (front)
429                 front_shield = shield;
430         else
431                 aft_shield = shield;
432 }
433
434
435
436
437 void make_station_appear (void)
438 {
439         double px,py,pz;
440         double sx,sy,sz;
441         Vector vec;
442         Matrix rotmat;
443         
444         px = universe[0].location.x;
445         py = universe[0].location.y;
446         pz = universe[0].location.z;
447         
448         vec.x = (rand() & 32767) - 16384;       
449         vec.y = (rand() & 32767) - 16384;       
450         vec.z = rand() & 32767; 
451
452         vec = unit_vector (&vec);
453
454         sx = px - vec.x * 65792;
455         sy = py - vec.y * 65792;
456         sz = pz - vec.z * 65792;
457
458 //      set_init_matrix (rotmat);
459         
460         rotmat[0].x = 1.0;
461         rotmat[0].y = 0.0;
462         rotmat[0].z = 0.0;
463
464         rotmat[1].x = vec.x;
465         rotmat[1].y = vec.z;
466         rotmat[1].z = -vec.y;
467         
468         rotmat[2].x = vec.x;
469         rotmat[2].y = vec.y;
470         rotmat[2].z = vec.z;
471
472         tidy_matrix (rotmat);
473         
474         add_new_station (sx, sy, sz, rotmat);
475 }
476
477
478
479 void check_docking (int i)
480 {
481         if (is_docking(i))
482         {
483                 snd_play_sample (SND_DOCK);                                     
484                 dock_player();
485                 current_screen = SCR_BREAK_PATTERN;
486                 return;
487         }
488                                         
489         if (flight_speed >= 5)
490         {
491                 do_game_over();
492                 return;
493         }
494
495         flight_speed = 1;
496         damage_ship (5, universe[i].location.z > 0);
497         snd_play_sample (SND_CRASH);
498 }
499
500
501 void switch_to_view (struct univ_object *flip)
502 {
503         double tmp;
504         
505         if ((current_screen == SCR_REAR_VIEW) ||
506                 (current_screen == SCR_GAME_OVER))
507         {
508                 flip->location.x = -flip->location.x;
509                 flip->location.z = -flip->location.z;
510
511                 flip->rotmat[0].x = -flip->rotmat[0].x;
512                 flip->rotmat[0].z = -flip->rotmat[0].z;
513
514                 flip->rotmat[1].x = -flip->rotmat[1].x;
515                 flip->rotmat[1].z = -flip->rotmat[1].z;
516
517                 flip->rotmat[2].x = -flip->rotmat[2].x;
518                 flip->rotmat[2].z = -flip->rotmat[2].z;
519                 return;
520         }
521
522
523         if (current_screen == SCR_LEFT_VIEW)
524         {
525                 tmp = flip->location.x;
526                 flip->location.x = flip->location.z;
527                 flip->location.z = -tmp;
528
529                 if (flip->type < 0)
530                         return;
531                 
532                 tmp = flip->rotmat[0].x;
533                 flip->rotmat[0].x = flip->rotmat[0].z;
534                 flip->rotmat[0].z = -tmp;               
535
536                 tmp = flip->rotmat[1].x;
537                 flip->rotmat[1].x = flip->rotmat[1].z;
538                 flip->rotmat[1].z = -tmp;               
539
540                 tmp = flip->rotmat[2].x;
541                 flip->rotmat[2].x = flip->rotmat[2].z;
542                 flip->rotmat[2].z = -tmp;               
543                 return;
544         }
545
546         if (current_screen == SCR_RIGHT_VIEW)
547         {
548                 tmp = flip->location.x;
549                 flip->location.x = -flip->location.z;
550                 flip->location.z = tmp;
551
552                 if (flip->type < 0)
553                         return;
554                 
555                 tmp = flip->rotmat[0].x;
556                 flip->rotmat[0].x = -flip->rotmat[0].z;
557                 flip->rotmat[0].z = tmp;                
558
559                 tmp = flip->rotmat[1].x;
560                 flip->rotmat[1].x = -flip->rotmat[1].z;
561                 flip->rotmat[1].z = tmp;                
562
563                 tmp = flip->rotmat[2].x;
564                 flip->rotmat[2].x = -flip->rotmat[2].z;
565                 flip->rotmat[2].z = tmp;                
566
567         }
568 }
569
570
571 /*
572  * Update all the objects in the universe and render them.
573  */
574
575 void update_universe (void)
576 {
577         int i;
578         int type;
579         int bounty;
580         char str[80];
581         struct univ_object flip;
582         
583         
584         gfx_start_render();
585                                         
586         for (i = 0; i < MAX_UNIV_OBJECTS; i++)
587         {
588                 type = universe[i].type;
589                 
590                 if (type != 0)
591                 {
592                         if (universe[i].flags & FLG_REMOVE)
593                         {
594                                 if (!(universe[i].flags & FLG_TARGET))
595                                         cmdr.legal_status |= 64;
596                         
597                                 bounty = ship_list[type]->bounty;
598                                 
599                                 if ((bounty != 0) && (!witchspace))
600                                 {
601                                         cmdr.credits += bounty;
602                                         sprintf (str, "Bounty: %d.%d CR", bounty / 10, bounty % 10);
603                                         info_message (str);
604                                 }
605                                 
606                                 remove_ship (i);
607                                 continue;
608                         }
609
610                         if ((detonate_bomb) && ((universe[i].flags & FLG_DEAD) == 0) &&
611                                 (type != SHIP_PLANET) && (type != SHIP_SUN) &&
612                                 (type != SHIP_CONSTRICTOR) && (type != SHIP_COUGAR) &&
613                                 (type != SHIP_CORIOLIS) && (type != SHIP_DODEC))
614                         {
615                                 snd_play_sample (SND_EXPLODE);
616                                 universe[i].flags |= FLG_DEAD;          
617                         }
618
619                         if ((current_screen != SCR_INTRO_ONE) &&
620                                 (current_screen != SCR_INTRO_TWO) &&
621                                 (current_screen != SCR_GAME_OVER) &&
622                                 (current_screen != SCR_ESCAPE_POD))
623                         {
624                                 tactics (i);
625                         } 
626                 
627                         move_univ_object (&universe[i]);
628
629                         flip = universe[i];
630                         switch_to_view (&flip);
631                         
632                         if (type == SHIP_PLANET)
633                         {
634                                 if ((ship_count[SHIP_CORIOLIS] == 0) &&
635                                         (ship_count[SHIP_DODEC] == 0) &&
636                                         (universe[i].distance < 65792)) // was 49152
637                                 {
638                                         make_station_appear();
639                                 }                               
640
641                                 draw_ship (&flip);
642                                 continue;
643                         }
644
645                         if (type == SHIP_SUN)
646                         {
647                                 draw_ship (&flip);
648                                 continue;
649                         }
650                         
651                         
652                         if (universe[i].distance < 170)
653                         {
654                                 if ((type == SHIP_CORIOLIS) || (type == SHIP_DODEC))
655                                         check_docking (i);
656                                 else
657                                         scoop_item(i);
658                                 
659                                 continue;
660                         }
661
662                         if (universe[i].distance > 57344)
663                         {
664                                 remove_ship (i);
665                                 continue;
666                         }
667
668                         draw_ship (&flip);
669
670                         universe[i].flags = flip.flags;
671                         universe[i].exp_seed = flip.exp_seed;
672                         universe[i].exp_delta = flip.exp_delta;
673                         
674                         universe[i].flags &= ~FLG_FIRING;
675                         
676                         if (universe[i].flags & FLG_DEAD)
677                                 continue;
678
679                         check_target (i, &flip);
680                 }
681         }
682
683         gfx_finish_render();
684         detonate_bomb = 0;
685 }
686
687
688
689
690 /*
691  * Update the scanner and draw all the lollipops.
692  */
693
694 void update_scanner (void)
695 {
696         int i;
697         int x,y,z;
698         int x1,y1,y2;
699         int colour;
700         
701         for (i = 0; i < MAX_UNIV_OBJECTS; i++)
702         {
703                 if ((universe[i].type <= 0) ||
704                         (universe[i].flags & FLG_DEAD) ||
705                         (universe[i].flags & FLG_CLOAKED))
706                         continue;
707         
708                 x = universe[i].location.x * scanner_zoom / 256;
709                 y = universe[i].location.y * scanner_zoom / 256;
710                 z = universe[i].location.z * scanner_zoom / 256;
711
712                 x1 = x;
713                 y1 = -z / 4;
714                 y2 = y1 - y / 2;
715
716                 if ((y2 < -28) || (y2 > 28) ||
717                         (x1 < -50) || (x1 > 50))
718                         continue;
719
720                 x1 += scanner_cx;
721                 y1 += scanner_cy;
722                 y2 += scanner_cy;
723
724                 colour = (universe[i].flags & FLG_HOSTILE) ? GFX_COL_YELLOW_5 : GFX_COL_WHITE;
725                         
726                 switch (universe[i].type)
727                 {
728                         case SHIP_MISSILE:
729                                 colour = 137;
730                                 break;
731
732                         case SHIP_DODEC:
733                         case SHIP_CORIOLIS:
734                                 colour = GFX_COL_GREEN_1;
735                                 break;
736                                 
737                         case SHIP_VIPER:
738                                 colour = 252;
739                                 break;
740                 }
741                         
742                 gfx_draw_colour_line (x1+2, y2,   x1-3, y2, colour);
743                 gfx_draw_colour_line (x1+2, y2+1, x1-3, y2+1, colour);
744                 gfx_draw_colour_line (x1+2, y2+2, x1-3, y2+2, colour);
745                 gfx_draw_colour_line (x1+2, y2+3, x1-3, y2+3, colour);
746
747
748                 gfx_draw_colour_line (x1,   y1, x1,   y2, colour);
749                 gfx_draw_colour_line (x1+1, y1, x1+1, y2, colour);
750                 gfx_draw_colour_line (x1+2, y1, x1+2, y2, colour);
751         }
752 }
753
754
755 /*
756  * Update the compass which tracks the space station / planet.
757  */
758
759 void update_compass (void)
760 {
761         struct vector dest;
762         int compass_x;
763         int compass_y;
764         int un = 0;
765
766         if (witchspace)
767                 return;
768         
769         if (ship_count[SHIP_CORIOLIS] || ship_count[SHIP_DODEC])
770                 un = 1;
771         
772         dest = unit_vector (&universe[un].location);
773         
774         compass_x = compass_centre_x + (dest.x * 16);
775         compass_y = compass_centre_y + (dest.y * -16);
776         
777         if (dest.z < 0)
778         {
779                 gfx_draw_sprite (IMG_RED_DOT, compass_x, compass_y);
780         }
781         else
782         {
783                 gfx_draw_sprite (IMG_GREEN_DOT, compass_x, compass_y);
784         }
785                                 
786 }
787
788
789 /*
790  * Display the speed bar.
791  */
792
793 void display_speed (void)
794 {
795         int sx,sy;
796         int i;
797         int len;
798         int colour;
799
800         sx = 417;
801         sy = 384 + 9;
802
803         len = ((flight_speed * 64) / myship.max_speed) - 1;
804
805         colour = (flight_speed > (myship.max_speed * 2 / 3)) ? GFX_COL_DARK_RED : GFX_COL_GOLD;
806
807         for (i = 0; i < 6; i++)
808         {
809                 gfx_draw_colour_line (sx, sy + i, sx + len, sy + i, colour);
810         }
811 }
812
813
814 /*
815  * Draw an indicator bar.
816  * Used for shields and energy banks.
817  */
818
819 void display_dial_bar (int len, int x, int y)
820 {
821         int i = 0;
822
823         gfx_draw_colour_line (x, y + 384, x + len, y + 384, GFX_COL_GOLD);
824         i++;
825         gfx_draw_colour_line (x, y + i + 384, x + len, y + i + 384, GFX_COL_GOLD);
826         
827         for (i = 2; i < 7; i++)
828                 gfx_draw_colour_line (x, y + i + 384, x + len, y + i + 384, GFX_COL_YELLOW_1);
829
830         gfx_draw_colour_line (x, y + i + 384, x + len, y + i + 384, GFX_COL_DARK_RED);
831 }
832
833
834 /*
835  * Display the current shield strengths.
836  */
837
838 void display_shields (void)
839 {
840         if (front_shield > 3)
841                 display_dial_bar (front_shield / 4, 31, 7);
842
843         if (aft_shield > 3)
844                 display_dial_bar (aft_shield / 4, 31, 23);
845 }
846
847
848 void display_altitude (void)
849 {
850         if (myship.altitude > 3)
851                 display_dial_bar (myship.altitude / 4, 31, 92);
852 }
853
854 void display_cabin_temp (void)
855 {
856         if (myship.cabtemp > 3)
857                 display_dial_bar (myship.cabtemp / 4, 31, 60);
858 }
859
860
861 void display_laser_temp (void)
862 {
863         if (laser_temp > 0)
864                 display_dial_bar (laser_temp / 4, 31, 76);
865 }
866
867
868 /*
869  * Display the energy banks.
870  */
871
872 void display_energy (void)
873 {
874         int e1,e2,e3,e4;
875
876         e1 = energy > 64 ? 64 : energy;
877         e2 = energy > 128 ? 64 : energy - 64;
878         e3 = energy > 192 ? 64 : energy - 128;
879         e4 = energy - 192;      
880         
881         if (e4 > 0)
882                 display_dial_bar (e4, 416, 61);
883
884         if (e3 > 0)
885                 display_dial_bar (e3, 416, 79);
886
887         if (e2 > 0)
888                 display_dial_bar (e2, 416, 97);
889
890         if (e1 > 0)
891                 display_dial_bar (e1, 416, 115);
892 }
893
894
895
896 void display_flight_roll (void)
897 {
898         int sx,sy;
899         int i;
900         int pos;
901
902         sx = 416;
903         sy = 384 + 9 + 14;
904
905         pos = sx - ((flight_roll * 28) / myship.max_roll);
906         pos += 32;
907
908         for (i = 0; i < 4; i++)
909         {
910                 gfx_draw_colour_line (pos + i, sy, pos + i, sy + 7, GFX_COL_GOLD);
911         }
912 }
913
914 void display_flight_climb (void)
915 {
916         int sx,sy;
917         int i;
918         int pos;
919
920         sx = 416;
921         sy = 384 + 9 + 14 + 16;
922
923         pos = sx + ((flight_climb * 28) / myship.max_climb);
924         pos += 32;
925
926         for (i = 0; i < 4; i++)
927         {
928                 gfx_draw_colour_line (pos + i, sy, pos + i, sy + 7, GFX_COL_GOLD);
929         }
930 }
931
932
933 void display_fuel (void)
934 {
935         if (cmdr.fuel > 0)
936                 display_dial_bar ((cmdr.fuel * 64) / myship.max_fuel, 31, 44);
937 }
938
939
940 void display_missiles (void)
941 {
942         int nomiss;
943         int x,y;
944
945         if (cmdr.missiles == 0)
946                 return;
947         
948         nomiss = cmdr.missiles > 4 ? 4 : cmdr.missiles;
949
950         x = (4 - nomiss) * 16 + 35;
951         y = 113 + 385;
952         
953         if (missile_target != MISSILE_UNARMED)
954         {
955                 gfx_draw_sprite ((missile_target < 0) ? IMG_MISSILE_YELLOW :
956                                                                                             IMG_MISSILE_RED, x, y);
957                 x += 16;
958                 nomiss--;
959         }
960
961         for (; nomiss > 0; nomiss--)
962         {
963                 gfx_draw_sprite (IMG_MISSILE_GREEN, x, y);
964                 x += 16;
965         }
966 }
967
968
969
970 void display_condition(void)
971 {
972   static const int cc[] = { GFX_COL_BLACK, GFX_COL_GREEN_1, GFX_COL_YELLOW_1,
973                             GFX_COL_RED, GFX_COL_RED };
974   int c = cc[condition];
975   if (condition == COND_ALERT && (mcount & 4))
976     c = GFX_COL_BLACK;
977   gfx_draw_filled_circle(condition_x, condition_y, condition_r, c);
978 }
979
980 void update_console (void)
981 {
982         gfx_draw_scanner();
983         
984         display_speed();
985         display_flight_climb();
986         display_flight_roll();
987         display_shields();
988         display_altitude();
989         display_energy();
990         display_cabin_temp();
991         display_laser_temp();
992         display_fuel();
993         display_missiles();
994         update_condition();
995         
996         if (docked) {
997           gfx_set_clip_region (0, 0, 512, 512);
998           return;
999         }
1000
1001         update_scanner();
1002         update_compass();
1003         display_condition();
1004
1005         {
1006           char buf[5];
1007           sprintf(buf, "x%d", scanner_zoom);
1008           gfx_display_text(zoom_x, zoom_y, buf);
1009         }
1010
1011         if (ship_count[SHIP_CORIOLIS] || ship_count[SHIP_DODEC])
1012                 gfx_draw_sprite (IMG_BIG_S, 387, 490);
1013
1014         if (ecm_active)
1015                 gfx_draw_sprite (IMG_BIG_E, 115, 490);
1016
1017         gfx_set_clip_region (0, 0, 512, 512);
1018 }
1019
1020 void increase_flight_roll (void)
1021 {
1022         if (flight_roll < myship.max_roll)
1023                 flight_roll++;
1024 }
1025
1026
1027 void decrease_flight_roll (void)
1028 {
1029         if (flight_roll > -myship.max_roll)
1030                 flight_roll--;
1031 }
1032
1033
1034 void increase_flight_climb (void)
1035 {
1036         if (flight_climb < myship.max_climb)
1037                 flight_climb++;
1038 }
1039
1040 void decrease_flight_climb (void)
1041 {
1042         if (flight_climb > -myship.max_climb)
1043                 flight_climb--;
1044 }
1045
1046
1047 void start_hyperspace (void)
1048 {
1049         if (hyper_ready)
1050                 return;
1051                 
1052         hyper_distance = calc_distance_to_planet (docked_planet, hyperspace_planet);
1053
1054         if ((docked_planet.a == hyperspace_planet.a &&
1055              docked_planet.b == hyperspace_planet.b &&
1056              docked_planet.c == hyperspace_planet.c &&
1057              docked_planet.d == hyperspace_planet.d &&
1058              docked_planet.e == hyperspace_planet.e &&
1059              docked_planet.f == hyperspace_planet.f) ||
1060             (hyper_distance > cmdr.fuel))
1061                 return;
1062
1063         destination_planet = hyperspace_planet;
1064         name_planet (hyper_name, destination_planet);
1065         capitalise_name (hyper_name);
1066         
1067         hyper_ready = 1;
1068         hyper_countdown = 15;
1069         hyper_galactic = 0;
1070
1071         disengage_auto_pilot();
1072 }
1073
1074 void start_galactic_hyperspace (void)
1075 {
1076         if (hyper_ready)
1077                 return;
1078
1079         if (cmdr.galactic_hyperdrive == 0)
1080                 return;
1081                 
1082         hyper_ready = 1;
1083         hyper_countdown = 2;
1084         hyper_galactic = 1;
1085         disengage_auto_pilot();
1086 }
1087
1088
1089
1090 void display_hyper_status (void)
1091 {
1092         char str[80];
1093
1094         sprintf (str, "%d", hyper_countdown);   
1095
1096         if ((current_screen == SCR_FRONT_VIEW) || (current_screen == SCR_REAR_VIEW) ||
1097                 (current_screen == SCR_LEFT_VIEW) || (current_screen == SCR_RIGHT_VIEW))
1098         {
1099                 gfx_display_text (5, 5, str);
1100                 if (hyper_galactic)
1101                 {
1102                         gfx_display_centre_text (358, "Galactic Hyperspace", 120, GFX_COL_WHITE);
1103                 }
1104                 else
1105                 {
1106                         sprintf (str, "Hyperspace - %s", hyper_name);
1107                         gfx_display_centre_text (358, str, 120, GFX_COL_WHITE);
1108                 }       
1109         }
1110         else
1111         {
1112                 gfx_clear_area (5, 5, 25, 34);
1113                 gfx_display_text (5, 5, str);
1114         }
1115 }
1116
1117
1118 int rotate_byte_left (int x)
1119 {
1120         return ((x << 1) | (x >> 7)) & 255;
1121 }
1122
1123 void enter_next_galaxy (void)
1124 {
1125         cmdr.galaxy_number++;
1126         cmdr.galaxy_number &= 7;
1127         
1128         cmdr.galaxy.a = rotate_byte_left (cmdr.galaxy.a);
1129         cmdr.galaxy.b = rotate_byte_left (cmdr.galaxy.b);
1130         cmdr.galaxy.c = rotate_byte_left (cmdr.galaxy.c);
1131         cmdr.galaxy.d = rotate_byte_left (cmdr.galaxy.d);
1132         cmdr.galaxy.e = rotate_byte_left (cmdr.galaxy.e);
1133         cmdr.galaxy.f = rotate_byte_left (cmdr.galaxy.f);
1134
1135         docked_planet = find_planet (0x60, 0x60);
1136         hyperspace_planet = docked_planet;
1137 }
1138
1139
1140
1141
1142
1143 void enter_witchspace (void)
1144 {
1145         int i;
1146         int nthg;
1147
1148         witchspace = 1;
1149         docked_planet.b ^= 31;
1150         in_battle = 1;  
1151
1152         flight_speed = 12;
1153         flight_roll = 0;
1154         flight_climb = 0;
1155         create_new_stars();
1156         clear_universe();
1157
1158         nthg = (randint() & 3) + 1;
1159         
1160         for (i = 0; i < nthg; i++)
1161                 create_thargoid();      
1162         
1163         current_screen = SCR_BREAK_PATTERN;
1164         snd_play_sample (SND_HYPERSPACE);
1165 }
1166
1167
1168 void complete_hyperspace (void)
1169 {
1170         Matrix rotmat;
1171         int px,py,pz;
1172         
1173         hyper_ready = 0;
1174         witchspace = 0;
1175         
1176         if (hyper_galactic)
1177         {
1178                 cmdr.galactic_hyperdrive = 0;
1179                 enter_next_galaxy();
1180                 cmdr.legal_status = 0;
1181         }
1182         else
1183         {
1184                 cmdr.fuel -= hyper_distance;
1185                 cmdr.legal_status /= 2;
1186
1187                 if ((rand255() > 253) || (flight_climb == myship.max_climb))
1188                 {
1189                         enter_witchspace();
1190                         return;
1191                 }
1192
1193                 docked_planet = destination_planet; 
1194         }
1195
1196         cmdr.market_rnd = rand255();
1197         generate_planet_data (&current_planet_data, docked_planet);
1198         generate_stock_market ();
1199         
1200         flight_speed = 12;
1201         flight_roll = 0;
1202         flight_climb = 0;
1203         create_new_stars();
1204         clear_universe();
1205
1206         generate_landscape(docked_planet.a * 251 + docked_planet.b);
1207         set_init_matrix (rotmat);
1208
1209         pz = (((docked_planet.b) & 7) + 7) / 2;
1210         px = pz / 2;
1211         py = px;
1212
1213         px <<= 16;
1214         py <<= 16;
1215         pz <<= 16;
1216         
1217         if ((docked_planet.b & 1) == 0)
1218         {
1219                 px = -px;
1220                 py = -py;
1221         }
1222
1223         add_new_ship (SHIP_PLANET, px, py, pz, rotmat, 0, 0);
1224
1225
1226         pz = -(((docked_planet.d & 7) | 1) << 16);
1227         px = ((docked_planet.f & 3) << 16) | ((docked_planet.f & 3) << 8);
1228
1229         add_new_ship (SHIP_SUN, px, py, pz, rotmat, 0, 0);
1230
1231         current_screen = SCR_BREAK_PATTERN;
1232         snd_play_sample (SND_HYPERSPACE);
1233 }
1234
1235
1236 void countdown_hyperspace (void)
1237 {
1238         if (hyper_countdown == 0)
1239         {
1240                 complete_hyperspace();
1241                 return;
1242         }
1243
1244         hyper_countdown--;
1245 }
1246
1247
1248
1249 void jump_warp (void)
1250 {
1251         int i;
1252         int type;
1253         int jump;
1254
1255         if (!kbd_ctrl_pressed) {
1256           for (i = 0; i < MAX_UNIV_OBJECTS; i++)
1257           {
1258             type = universe[i].type;
1259                 
1260             if ((type > 0) && (type != SHIP_ASTEROID) && (type != SHIP_CARGO) &&
1261                 (type != SHIP_ALLOY) && (type != SHIP_ROCK) &&
1262                 (type != SHIP_BOULDER) && (type != SHIP_ESCAPE_CAPSULE))
1263             {
1264               info_message ("Mass Locked");
1265               return;
1266             }
1267           }
1268           if ((universe[0].distance < 75001) || (universe[1].distance < 75001))
1269           {
1270             info_message ("Mass Locked");
1271             return;
1272           }
1273
1274         }
1275
1276
1277         if (universe[0].distance < universe[1].distance)
1278                 jump = universe[0].distance - 75000;
1279         else
1280                 jump = universe[1].distance - 75000;    
1281
1282         if (jump > 1024 || kbd_ctrl_pressed)
1283                 jump = 1024;
1284         
1285         for (i = 0; i < MAX_UNIV_OBJECTS; i++)
1286         {
1287                 if (universe[i].type != 0)
1288                         universe[i].location.z -= jump;
1289         }
1290
1291         warp_stars = 1;
1292         if (!kbd_ctrl_pressed) {
1293           mcount &= 63;
1294           in_battle = 0;
1295         }
1296 }
1297
1298
1299 void launch_player (void)
1300 {
1301         Matrix rotmat;
1302
1303         docked = 0;
1304         flight_speed = 12;
1305         flight_roll = -15;
1306         flight_climb = 0;
1307         cmdr.legal_status |= carrying_contraband();
1308         create_new_stars();
1309         clear_universe();
1310         generate_landscape(docked_planet.a * 251 + docked_planet.b);
1311         set_init_matrix (rotmat);
1312         add_new_ship (SHIP_PLANET, 0, 0, 65536, rotmat, 0, 0);
1313         identify = 0;
1314         scanner_zoom = 1;
1315
1316         rotmat[2].x = -rotmat[2].x;
1317         rotmat[2].y = -rotmat[2].y;
1318         rotmat[2].z = -rotmat[2].z;
1319         add_new_station (0, 0, -256, rotmat);
1320
1321         current_screen = SCR_BREAK_PATTERN;
1322         snd_play_sample (SND_LAUNCH);
1323 }
1324
1325
1326
1327 /*
1328  * Engage the docking computer.
1329  * For the moment we just do an instant dock if we are in the safe zone.
1330  */
1331
1332 void engage_docking_computer (void)
1333 {
1334         if (ship_count[SHIP_CORIOLIS] || ship_count[SHIP_DODEC])
1335         {
1336                 snd_play_sample (SND_DOCK);
1337                 dock_player();
1338                 current_screen = SCR_BREAK_PATTERN;
1339         }
1340 }
1341
1342
1343 void update_condition(void)
1344 {
1345   if (docked)
1346     condition = COND_DOCKED;
1347   else if (energy < 50 || myship.altitude < 32 || myship.cabtemp > 224)
1348     condition = COND_ALERT;
1349   else if (energy < 128 || myship.altitude < 64 || myship.cabtemp > 192)
1350     condition = COND_RED;
1351   else {
1352     int i;
1353     condition = COND_GREEN;
1354     if (myship.altitude < 128 || myship.cabtemp >= 128)
1355       condition = COND_YELLOW;
1356     for (i = 0; i < MAX_UNIV_OBJECTS; i++) {
1357       struct univ_object *un = &universe[i];
1358       if (un->type <= 0)
1359         continue;
1360       if (un->flags & FLG_HOSTILE) {
1361         condition = COND_RED;
1362         break;
1363       }
1364       if (condition == COND_GREEN && 
1365           un->type != SHIP_ASTEROID && un->type != SHIP_CARGO &&
1366           un->type != SHIP_ALLOY && un->type != SHIP_ROCK &&
1367           un->type != SHIP_BOULDER && un->type != SHIP_ESCAPE_CAPSULE &&
1368           un->type != SHIP_CORIOLIS && un->type != SHIP_DODEC)
1369         condition = COND_YELLOW;
1370     }
1371   }
1372 }