2 * Elite - The New Kind.
4 * Reverse engineered from the BBC disk version of Elite.
5 * Additional material by C.J.Pinder.
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.
10 * email: <christian@newkind.co.uk>
18 * Special Weapons And Tactics.
49 struct univ_object universe[MAX_UNIV_OBJECTS];
50 int ship_count[NO_OF_SHIPS + 1]; /* many */
53 int initial_flags[NO_OF_SHIPS + 1] =
58 FLG_SLOW | FLG_FLY_TO_PLANET, // escape
59 FLG_INACTIVE, // alloy
60 FLG_INACTIVE, // cargo
61 FLG_INACTIVE, // boulder
62 FLG_INACTIVE, // asteroid
64 FLG_FLY_TO_PLANET | FLG_SLOW, // shuttle
65 FLG_FLY_TO_PLANET | FLG_SLOW, // transporter
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
86 FLG_ANGRY, // constrictor
87 FLG_POLICE | FLG_CLOAKED, // cougar
94 void clear_universe (void)
98 for (i = 0; i < MAX_UNIV_OBJECTS; i++)
101 for (i = 0; i <= NO_OF_SHIPS; i++)
108 int add_new_ship (int ship_type, int x, int y, int z, struct vector *rotmat, int rotx, int rotz)
112 for (i = 0; i < MAX_UNIV_OBJECTS; i++)
114 if (universe[i].type == 0)
116 universe[i].type = ship_type;
117 universe[i].location.x = x;
118 universe[i].location.y = y;
119 universe[i].location.z = z;
121 universe[i].distance = sqrt(x*x + y*y + z*z);
123 universe[i].rotmat[0] = rotmat[0];
124 universe[i].rotmat[1] = rotmat[1];
125 universe[i].rotmat[2] = rotmat[2];
127 universe[i].rotx = rotx;
128 universe[i].rotz = rotz;
130 universe[i].velocity = 0;
131 universe[i].acceleration = 0;
132 universe[i].bravery = 0;
133 universe[i].target = 0;
135 universe[i].flags = initial_flags[ship_type];
137 if ((ship_type != SHIP_PLANET) && (ship_type != SHIP_SUN))
139 universe[i].energy = ship_list[ship_type]->energy;
140 universe[i].missiles = ship_list[ship_type]->missiles;
141 ship_count[ship_type]++;
154 void check_missiles (int un)
158 if (missile_target == un)
160 missile_target = MISSILE_UNARMED;
161 info_message ("Target Lost");
164 for (i = 0; i < MAX_UNIV_OBJECTS; i++)
166 if ((universe[i].type == SHIP_MISSILE) && (universe[i].target == un))
167 universe[i].flags |= FLG_DEAD;
172 void remove_ship (int un)
178 type = universe[un].type;
186 universe[un].type = 0;
190 if ((type == SHIP_CORIOLIS) || (type == SHIP_DODEC))
192 set_init_matrix (rotmat);
193 px = universe[un].location.x;
194 py = universe[un].location.y;
195 pz = universe[un].location.z;
200 add_new_ship (SHIP_SUN, px, py, pz, rotmat, 0, 0);
205 void add_new_station (double sx, double sy, double sz, Matrix rotmat)
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);
217 void reset_weapons (void)
223 missile_target = MISSILE_UNARMED;
227 void launch_enemy (int un, int type, int flags, int bravery)
230 struct univ_object *ns;
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);
241 ns = &universe[newship];
243 if ((universe[un].type == SHIP_CORIOLIS) || (universe[un].type == SHIP_DODEC))
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;
254 ns->bravery = bravery;
256 if ((type == SHIP_CARGO) || (type == SHIP_ALLOY) || (type == SHIP_ROCK))
258 ns->rotz = ((rand255() * 2) & 255) - 128;
259 ns->rotx = ((rand255() * 2) & 255) - 128;
260 ns->velocity = rand255() & 15;
265 void launch_loot (int un, int loot)
269 if (loot == SHIP_ROCK)
279 cnt &= ship_list[universe[un].type]->max_loot;
283 for (i = 0; i < cnt; i++)
285 launch_enemy (un, loot, 0,0);
292 int in_target (int type, double x, double y, double z)
299 size = ship_list[type]->size;
301 return ((x*x + y*y) <= size);
306 void make_angry (int un)
311 type = universe[un].type;
312 flags = universe[un].flags;
314 if (flags & FLG_INACTIVE)
317 if ((type == SHIP_CORIOLIS) || (type == SHIP_DODEC))
319 universe[un].flags |= FLG_ANGRY;
323 if (type > SHIP_ROCK)
325 universe[un].rotx = 4;
326 universe[un].acceleration = 2;
327 universe[un].flags |= FLG_ANGRY;
332 void explode_object (int un)
337 if ((cmdr.score & 255) == 0)
338 info_message ("Right On Commander!");
340 snd_play_sample (SND_EXPLODE);
341 universe[un].flags |= FLG_DEAD;
343 if (universe[un].type == SHIP_CONSTRICTOR)
348 void check_target (int un, struct univ_object *flip)
350 struct univ_object *univ;
352 univ = &universe[un];
354 if (in_target (univ->type, flip->location.x, flip->location.y, flip->location.z))
356 if ((missile_target == MISSILE_ARMED) && (univ->type >= 0))
359 info_message ("Target Locked");
360 snd_play_sample (SND_BEEP);
365 snd_play_sample (SND_HIT_ENEMY);
367 if ((univ->type != SHIP_CORIOLIS) && (univ->type != SHIP_DODEC))
369 if ((univ->type == SHIP_CONSTRICTOR) || (univ->type == SHIP_COUGAR))
371 if (laser == (MILITARY_LASER & 127))
372 univ->energy -= laser / 4;
376 univ->energy -= laser;
380 if (univ->energy <= 0)
384 if (univ->type == SHIP_ASTEROID)
386 if (laser == (MINING_LASER & 127))
387 launch_loot (un, SHIP_ROCK);
391 launch_loot (un, SHIP_ALLOY);
392 launch_loot (un, SHIP_CARGO);
403 void activate_ecm (int ours)
409 snd_play_sample (SND_ECM);
420 decrease_energy (-1);
425 void arm_missile (void)
427 if ((cmdr.missiles != 0) && (missile_target == MISSILE_UNARMED))
428 missile_target = MISSILE_ARMED;
432 void unarm_missile (void)
434 missile_target = MISSILE_UNARMED;
435 snd_play_sample (SND_BOOP);
438 void fire_missile (void)
441 struct univ_object *ns;
444 if (missile_target < 0)
447 set_init_matrix (rotmat);
451 newship = add_new_ship (SHIP_MISSILE, 0, -28, 14, rotmat, 0, 0);
455 info_message ("Missile Jammed");
459 ns = &universe[newship];
461 ns->velocity = flight_speed * 2;
462 ns->flags = FLG_ANGRY;
463 ns->target = missile_target;
465 if (universe[missile_target].type > SHIP_ROCK)
466 universe[missile_target].flags |= FLG_ANGRY;
469 missile_target = MISSILE_UNARMED;
471 snd_play_sample (SND_MISSILE);
476 void track_object (struct univ_object *ship, double direction, Vector nvec)
485 dir = vector_dot_product (&nvec, &ship->rotmat[1]);
487 if (direction < -0.861)
489 ship->rotx = (dir < 0) ? 7 : -7;
496 if ((fabs(dir) * 2) >= rat2)
498 ship->rotx = (dir < 0) ? rat : -rat;
501 if (abs(ship->rotz) < 16)
503 dir = vector_dot_product (&nvec, &ship->rotmat[0]);
507 if ((fabs(dir) * 2) > rat2)
509 ship->rotz = (dir < 0) ? rat : -rat;
512 ship->rotz = -ship->rotz;
519 void missile_tactics (int un)
521 struct univ_object *missile;
522 struct univ_object *target;
528 missile = &universe[un];
532 snd_play_sample (SND_EXPLODE);
533 missile->flags |= FLG_DEAD;
537 if (missile->target == 0)
539 if (missile->distance < 256)
541 missile->flags |= FLG_DEAD;
542 snd_play_sample (SND_EXPLODE);
543 damage_ship (250, missile->location.z >= 0.0);
547 vec.x = missile->location.x;
548 vec.y = missile->location.y;
549 vec.z = missile->location.z;
553 target = &universe[missile->target];
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;
559 if ((fabs(vec.x) < 256) && (fabs(vec.y) < 256) && (fabs(vec.z) < 256))
561 missile->flags |= FLG_DEAD;
563 if ((target->type != SHIP_CORIOLIS) && (target->type != SHIP_DODEC))
564 explode_object (missile->target);
566 snd_play_sample (SND_EXPLODE);
571 if ((rand255() < 16) && (target->flags & FLG_HAS_ECM))
578 nvec = unit_vector(&vec);
579 direction = vector_dot_product (&nvec, &missile->rotmat[2]);
583 direction = -direction;
585 track_object (missile, direction, nvec);
587 if (direction <= -0.167)
589 missile->acceleration = -2;
593 if (direction >= cnt2)
595 missile->acceleration = 3;
599 if (missile->velocity < 6)
600 missile->acceleration = 3;
602 if (rand255() >= 200)
603 missile->acceleration = -2;
609 void launch_shuttle (void)
613 if ((ship_count[SHIP_TRANSPORTER] != 0) ||
614 (ship_count[SHIP_SHUTTLE] != 0) ||
615 (rand255() < 253) || (auto_pilot))
618 type = rand255() & 1 ? SHIP_SHUTTLE : SHIP_TRANSPORTER;
619 launch_enemy (1, type, FLG_HAS_ECM | FLG_FLY_TO_PLANET, 113);
623 void tactics (int un)
629 struct univ_object *ship;
635 ship = &universe[un];
639 if ((type == SHIP_PLANET) || (type == SHIP_SUN))
642 if (flags & FLG_DEAD)
645 if (flags & FLG_INACTIVE)
648 if (type == SHIP_MISSILE)
650 if (flags & FLG_ANGRY)
651 missile_tactics (un);
655 if (((un ^ mcount) & 7) != 0)
658 if ((type == SHIP_CORIOLIS) || (type == SHIP_DODEC))
660 if (flags & FLG_ANGRY)
662 if ((rand() & 255) < 240)
665 if (ship_count[SHIP_VIPER] >= 4)
668 launch_enemy (un, SHIP_VIPER, FLG_ANGRY | FLG_HAS_ECM, 113);
676 if (type == SHIP_HERMIT)
680 launch_enemy (un, SHIP_SIDEWINDER + (rand255() & 3), FLG_ANGRY | FLG_HAS_ECM, 113);
681 ship->flags |= FLG_INACTIVE;
688 if (ship->energy < ship_list[type]->energy)
691 if ((type == SHIP_THARGLET) && (ship_count[SHIP_THARGOID] == 0))
698 if (flags & FLG_SLOW)
704 if (flags & FLG_POLICE)
706 if (cmdr.legal_status >= 64)
713 if ((flags & FLG_ANGRY) == 0)
715 if ((flags & FLG_FLY_TO_PLANET) || (flags & FLG_FLY_TO_STATION))
717 auto_pilot_ship (&universe[un]);
724 /* If we get to here then the ship is angry so start attacking... */
726 if (ship_count[SHIP_CORIOLIS] || ship_count[SHIP_DODEC])
728 if ((flags & FLG_BOLD) == 0)
733 if (type == SHIP_ANACONDA)
737 launch_enemy (un, rand255() > 100 ? SHIP_WORM : SHIP_SIDEWINDER,
738 FLG_ANGRY | FLG_HAS_ECM, 113);
744 if (rand255() >= 250)
746 ship->rotz = rand255() | 0x68;
747 if (ship->rotz > 127)
748 ship->rotz = -(ship->rotz & 127);
751 maxeng = ship_list[type]->energy;
752 energy = ship->energy;
754 if (energy < (maxeng / 2))
756 if ((energy < (maxeng / 8)) && (rand255() > 230) && (type != SHIP_THARGOID))
758 ship->flags &= ~FLG_ANGRY;
759 ship->flags |= FLG_INACTIVE;
760 launch_enemy (un, SHIP_ESCAPE_CAPSULE, 0, 126);
764 if ((ship->missiles != 0) && (ecm_active == 0) &&
765 (ship->missiles >= (rand255() & 31)))
768 if (type == SHIP_THARGOID)
769 launch_enemy (un, SHIP_THARGLET, FLG_ANGRY, ship->bravery);
772 launch_enemy (un, SHIP_MISSILE, FLG_ANGRY, 126);
773 info_message ("INCOMING MISSILE");
779 nvec = unit_vector(&universe[un].location);
780 direction = vector_dot_product (&nvec, &ship->rotmat[2]);
782 if ((ship->distance < 8192) && (direction <= -0.833) &&
783 (ship_list[type]->laser_strength != 0))
785 if (direction <= -0.917)
786 ship->flags |= FLG_FIRING | FLG_HOSTILE;
788 if (direction <= -0.972)
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);
796 snd_play_sample (SND_INCOMMING_FIRE_1);
803 direction = -direction;
804 track_object (&universe[un], direction, nvec);
807 // if ((fabs(ship->location.z) < 768) && (ship->bravery <= ((rand255() & 127) | 64)))
808 if (fabs(ship->location.z) < 768)
810 ship->rotx = rand255() & 0x87;
811 if (ship->rotx > 127)
812 ship->rotx = -(ship->rotx & 127);
814 ship->acceleration = 3;
818 if (ship->distance < 8192)
819 ship->acceleration = -1;
821 ship->acceleration = 3;
827 if ((fabs(ship->location.z) >= 768) ||
828 (fabs(ship->location.x) >= 512) ||
829 (fabs(ship->location.y) >= 512))
831 if (ship->bravery > (rand255() & 127))
837 direction = -direction;
841 track_object (&universe[un], direction, nvec);
843 if ((attacking == 1) && (ship->distance < 2048))
845 if (direction >= cnt2)
847 ship->acceleration = -1;
851 if (ship->velocity < 6)
852 ship->acceleration = 3;
854 if (rand255() >= 200)
855 ship->acceleration = -1;
859 if (direction <= -0.167)
861 ship->acceleration = -1;
865 if (direction >= cnt2)
867 ship->acceleration = 3;
871 if (ship->velocity < 6)
872 ship->acceleration = 3;
874 if (rand255() >= 200)
875 ship->acceleration = -1;
879 void draw_laser_lines (void)
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);
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);
896 int fire_laser (void)
898 if ((laser_counter == 0) && (laser_temp < 242))
900 switch (current_screen)
903 laser = cmdr.front_laser;
907 laser = cmdr.rear_laser;
911 laser = cmdr.right_laser;
915 laser = cmdr.left_laser;
924 laser_counter = (laser > 127) ? 0 : (laser & 0xFA);
928 snd_play_sample (SND_PULSE);
933 laser_x = ((rand() & 3) + 128 - 2) * GFX_SCALE;
934 laser_y = ((rand() & 3) + 96 - 2) * GFX_SCALE;
944 void cool_laser (void)
951 if (laser_counter > 0)
954 if (laser_counter > 0)
959 int create_other_ship (int type)
965 set_init_matrix (rotmat);
968 x = 1000 + (randint() & 8191);
969 y = 1000 + (randint() & 8191);
976 newship = add_new_ship (type, x, y, z, rotmat, 0, 0);
982 void create_thargoid (void)
986 newship = create_other_ship (SHIP_THARGOID);
989 universe[newship].flags = FLG_ANGRY | FLG_HAS_ECM;
990 universe[newship].bravery = 113;
993 launch_enemy (newship, SHIP_THARGLET, FLG_ANGRY | FLG_HAS_ECM, 96);
999 void create_cougar (void)
1003 if (ship_count[SHIP_COUGAR] != 0)
1006 newship = create_other_ship (SHIP_COUGAR);
1009 universe[newship].flags = FLG_HAS_ECM; // | FLG_CLOAKED;
1010 universe[newship].bravery = 121;
1011 universe[newship].velocity = 18;
1017 void create_trader (void)
1023 type = SHIP_COBRA3 + (rand255() & 3);
1025 newship = create_other_ship (type);
1029 universe[newship].rotmat[2].z = -1.0;
1030 universe[newship].rotz = rand255() & 7;
1033 universe[newship].velocity = (rnd & 31) | 16;
1034 universe[newship].bravery = rnd / 2;
1037 universe[newship].flags |= FLG_HAS_ECM;
1040 // universe[newship].flags |= FLG_ANGRY;
1045 void create_lone_hunter (void)
1051 if ((cmdr.mission == 1) && (cmdr.galaxy_number == 1) &&
1052 (docked_planet.d == 144) && (docked_planet.b == 33) &&
1053 (ship_count[SHIP_CONSTRICTOR] == 0))
1055 type = SHIP_CONSTRICTOR;
1060 type = SHIP_COBRA3_LONE + (rnd & 3) + (rnd > 127);
1063 newship = create_other_ship (type);
1067 universe[newship].flags = FLG_ANGRY;
1068 if ((rand255() > 200) || (type == SHIP_CONSTRICTOR))
1069 universe[newship].flags |= FLG_HAS_ECM;
1071 universe[newship].bravery = ((rand255() * 2) | 64) & 127;
1078 /* Check for a random asteroid encounter... */
1080 void check_for_asteroids (void)
1085 if ((rand255() >= 35) || (ship_count[SHIP_ASTEROID] >= 3))
1088 if (rand255() > 253)
1091 type = SHIP_ASTEROID;
1093 newship = create_other_ship (type);
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;
1106 /* If we've been a bad boy then send the cops after us... */
1108 void check_for_cops (void)
1113 offense = carrying_contraband() * 2;
1114 if (ship_count[SHIP_VIPER] == 0)
1115 offense |= cmdr.legal_status;
1117 if (rand255() >= offense)
1120 newship = create_other_ship (SHIP_VIPER);
1124 universe[newship].flags = FLG_ANGRY;
1125 if (rand255() > 245)
1126 universe[newship].flags |= FLG_HAS_ECM;
1128 universe[newship].bravery = ((rand255() * 2) | 64) & 127;
1133 void check_for_others (void)
1143 gov = current_planet_data.government;
1146 if ((gov != 0) && ((rnd >= 90) || ((rnd & 7) < gov)))
1149 if (rand255() < 100)
1151 create_lone_hunter();
1155 /* Pack hunters... */
1157 set_init_matrix (rotmat);
1160 x = 1000 + (randint() & 8191);
1161 y = 1000 + (randint() & 8191);
1163 if (rand255() > 127)
1165 if (rand255() > 127)
1168 rnd = rand255() & 3;
1170 for (i = 0; i <= rnd; i++)
1172 type = SHIP_SIDEWINDER + (rand255() & rand255() & 7);
1173 newship = add_new_ship (type, x, y, z, rotmat, 0, 0);
1176 universe[newship].flags = FLG_ANGRY;
1177 if (rand255() > 245)
1178 universe[newship].flags |= FLG_HAS_ECM;
1180 universe[newship].bravery = ((rand255() * 2) | 64) & 127;
1188 void random_encounter (void)
1190 if ((ship_count[SHIP_CORIOLIS] != 0) || (ship_count[SHIP_DODEC] != 0))
1193 if (rand255() == 136)
1195 if (((int)(universe[0].location.z) & 0x3e) != 0)
1203 if ((rand255() & 7) == 0)
1209 check_for_asteroids();
1213 if (ship_count[SHIP_VIPER] != 0)
1219 if ((cmdr.mission == 5) && (rand255() >= 200))
1226 void abandon_ship (void)
1230 cmdr.escape_pod = 0;
1231 cmdr.legal_status = 0;
1232 cmdr.fuel = myship.max_fuel;
1234 for (i = 0; i < NO_OF_STOCK_ITEMS; i++)
1235 cmdr.current_cargo[i] = 0;
1237 snd_play_sample (SND_DOCK);
1239 current_screen = SCR_BREAK_PATTERN;