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