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>
31 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
34 #define LAND_X_MAX 128
35 #define LAND_Y_MAX 128
37 static unsigned char landscape[LAND_X_MAX+1][LAND_Y_MAX+1];
39 static struct point point_list[100];
41 static void identify_ship(struct univ_object *univ)
46 lasv = ship_list[univ->type]->front_laser;
47 if (!(univ->flags & FLG_TACTICAL)) {
49 unsigned flags = univ->flags;
50 sprintf(buf, "%s %s%s%s%s", ship_list[univ->type]->name,
51 (flags & FLG_ANGRY) ? "A" : "",
52 (flags & FLG_TARGET) ? "T" : "",
53 (flags & FLG_HOSTILE) ? "H" : "",
54 (flags & FLG_POLICE) ? "P" : "");
56 sprintf(buf, "%s", ship_list[univ->type]->name);
60 unsigned flags = univ->flags;
61 sprintf(buf, "%s (%d) %s%s%s%s", ship_list[univ->type]->name,
63 (flags & FLG_ANGRY) ? "A" : "",
64 (flags & FLG_TARGET) ? "T" : "",
65 (flags & FLG_HOSTILE) ? "H" : "",
66 (flags & FLG_POLICE) ? "P" : "");
68 sprintf(buf, "%s (%d)", ship_list[univ->type]->name, univ->energy);
71 gfx_display_text(point_list[lasv].x + 4, point_list[lasv].y + 4, buf);
75 * The following routine is used to draw a wireframe represtation of a ship.
77 * caveat: it is a work in progress.
78 * A number of features (such as not showing detail at distance) have not yet been implemented.
82 void draw_wireframe_ship (struct univ_object *univ)
93 struct ship_face_normal *ship_norm;
95 struct ship_data *ship;
98 ship = ship_list[univ->type];
100 for (i = 0; i < 3; i++)
101 trans_mat[i] = univ->rotmat[i];
103 camera_vec = univ->location;
104 mult_vector (&camera_vec, trans_mat);
105 camera_vec = unit_vector (&camera_vec);
107 num_faces = ship->num_faces;
109 for (i = 0; i < num_faces; i++)
111 ship_norm = ship->normals;
113 vec.x = ship_norm[i].x;
114 vec.y = ship_norm[i].y;
115 vec.z = ship_norm[i].z;
117 if ((vec.x == 0) && (vec.y == 0) && (vec.z == 0))
121 vec = unit_vector (&vec);
122 cos_angle = vector_dot_product (&vec, &camera_vec);
123 visible[i] = (cos_angle < -0.2);
127 tmp = trans_mat[0].y;
128 trans_mat[0].y = trans_mat[1].x;
129 trans_mat[1].x = tmp;
131 tmp = trans_mat[0].z;
132 trans_mat[0].z = trans_mat[2].x;
133 trans_mat[2].x = tmp;
135 tmp = trans_mat[1].z;
136 trans_mat[1].z = trans_mat[2].y;
137 trans_mat[2].y = tmp;
139 for (i = 0; i < ship->num_points; i++)
141 vec.x = ship->points[i].x;
142 vec.y = ship->points[i].y;
143 vec.z = ship->points[i].z;
145 mult_vector (&vec, trans_mat);
147 rx = vec.x + univ->location.x;
148 ry = vec.y + univ->location.y;
149 rz = vec.z + univ->location.z;
151 sx = (rx * 256) / rz;
152 sy = (ry * 256) / rz;
162 point_list[i].x = sx;
163 point_list[i].y = sy;
167 for (i = 0; i < ship->num_lines; i++)
169 if (visible[ship->lines[i].face1] ||
170 visible[ship->lines[i].face2])
172 sx = point_list[ship->lines[i].start_point].x;
173 sy = point_list[ship->lines[i].start_point].y;
175 ex = point_list[ship->lines[i].end_point].x;
176 ey = point_list[ship->lines[i].end_point].y;
178 gfx_draw_line (sx, sy, ex, ey);
183 if (univ->flags & FLG_FIRING)
185 lasv = ship_list[univ->type]->front_laser;
186 gfx_draw_line (point_list[lasv].x, point_list[lasv].y,
187 univ->location.x > 0 ? 0 : 511, rand255() * 2);
198 * Hacked version of the draw ship routine to display solid ships...
199 * This needs a lot of tidying...
201 * Check for hidden surface supplied by T.Harte.
204 void draw_solid_ship (struct univ_object *univ)
210 struct vector camera_vec;
212 struct ship_face *face_data;
217 struct ship_solid *solid_data;
218 struct ship_data *ship;
223 solid_data = &ship_solids[univ->type];
224 ship = ship_list[univ->type];
226 for (i = 0; i < 3; i++)
227 trans_mat[i] = univ->rotmat[i];
229 camera_vec = univ->location;
230 mult_vector (&camera_vec, trans_mat);
231 camera_vec = unit_vector (&camera_vec);
233 num_faces = solid_data->num_faces;
234 face_data = solid_data->face_data;
237 for (i = 0; i < num_faces; i++)
239 vec.x = face_data[i].norm_x;
240 vec.y = face_data[i].norm_y;
241 vec.z = face_data[i].norm_z;
243 vec = unit_vector (&vec);
244 cos_angle = vector_dot_product (&vec, &camera_vec);
246 visible[i] = (cos_angle < -0.13);
250 tmp = trans_mat[0].y;
251 trans_mat[0].y = trans_mat[1].x;
252 trans_mat[1].x = tmp;
254 tmp = trans_mat[0].z;
255 trans_mat[0].z = trans_mat[2].x;
256 trans_mat[2].x = tmp;
258 tmp = trans_mat[1].z;
259 trans_mat[1].z = trans_mat[2].y;
260 trans_mat[2].y = tmp;
263 for (i = 0; i < ship->num_points; i++)
265 vec.x = ship->points[i].x;
266 vec.y = ship->points[i].y;
267 vec.z = ship->points[i].z;
269 mult_vector (&vec, trans_mat);
271 rx = vec.x + univ->location.x;
272 ry = vec.y + univ->location.y;
273 rz = vec.z + univ->location.z;
278 sx = (rx * 256) / rz;
279 sy = (ry * 256) / rz;
289 point_list[i].x = sx;
290 point_list[i].y = sy;
291 point_list[i].z = rz;
295 for (i = 0; i < num_faces; i++)
297 if (((point_list[face_data[i].p1].x - point_list[face_data[i].p2].x) *
298 (point_list[face_data[i].p3].y - point_list[face_data[i].p2].y) -
299 (point_list[face_data[i].p1].y - point_list[face_data[i].p2].y) *
300 (point_list[face_data[i].p3].x - point_list[face_data[i].p2].x)) <= 0)
302 num_points = face_data[i].points;
304 poly_list[0] = point_list[face_data[i].p1].x;
305 poly_list[1] = point_list[face_data[i].p1].y;
306 zavg = point_list[face_data[i].p1].z;
308 poly_list[2] = point_list[face_data[i].p2].x;
309 poly_list[3] = point_list[face_data[i].p2].y;
310 zavg = MAX(zavg,point_list[face_data[i].p2].z);
314 poly_list[4] = point_list[face_data[i].p3].x;
315 poly_list[5] = point_list[face_data[i].p3].y;
316 zavg = MAX(zavg,point_list[face_data[i].p3].z);
321 poly_list[6] = point_list[face_data[i].p4].x;
322 poly_list[7] = point_list[face_data[i].p4].y;
323 zavg = MAX(zavg,point_list[face_data[i].p4].z);
328 poly_list[8] = point_list[face_data[i].p5].x;
329 poly_list[9] = point_list[face_data[i].p5].y;
330 zavg = MAX(zavg,point_list[face_data[i].p5].z);
335 poly_list[10] = point_list[face_data[i].p6].x;
336 poly_list[11] = point_list[face_data[i].p6].y;
337 zavg = MAX(zavg,point_list[face_data[i].p6].z);
342 poly_list[12] = point_list[face_data[i].p7].x;
343 poly_list[13] = point_list[face_data[i].p7].y;
344 zavg = MAX(zavg,point_list[face_data[i].p7].z);
349 poly_list[14] = point_list[face_data[i].p8].x;
350 poly_list[15] = point_list[face_data[i].p8].y;
351 zavg = MAX(zavg,point_list[face_data[i].p8].z);
355 gfx_render_polygon (face_data[i].points, poly_list, face_data[i].colour, zavg);
360 if (univ->flags & FLG_FIRING)
362 lasv = ship_list[univ->type]->front_laser;
363 col = (univ->type == SHIP_VIPER) ? GFX_COL_CYAN : GFX_COL_WHITE;
365 gfx_render_line (point_list[lasv].x, point_list[lasv].y,
366 univ->location.x > 0 ? 0 : 511, rand255() * 2,
367 point_list[lasv].z, col);
379 * Colour map used to generate a SNES Elite style planet.
380 * This is a quick hack and needs tidying up.
383 int snes_planet_colour[] =
396 249,249,249,249,249,249,
409 * Generate a landscape map for a SNES Elite style planet.
412 void generate_snes_landscape (void)
417 for (y = 0; y <= LAND_Y_MAX; y++)
419 colour = snes_planet_colour[y * (sizeof(snes_planet_colour)/sizeof(int)) / LAND_Y_MAX];
420 for (x = 0; x <= LAND_X_MAX; x++)
422 landscape[x][y] = colour;
431 * Guassian random number generator.
432 * Returns a number between -7 and +8 with Gaussian distribution.
441 for (i = 0; i < 12; i++)
452 * Calculate the midpoint between two given points.
455 int calc_midpoint (int sx, int sy, int ex, int ey)
459 a = landscape[sx][sy];
460 b = landscape[ex][ey];
462 n = ((a + b) / 2) + grand();
473 * Calculate a square on the midpoint map.
476 void midpoint_square (int tx, int ty, int w)
488 landscape[mx][ty] = calc_midpoint(tx,ty,bx,ty);
489 landscape[mx][by] = calc_midpoint(tx,by,bx,by);
490 landscape[tx][my] = calc_midpoint(tx,ty,tx,by);
491 landscape[bx][my] = calc_midpoint(bx,ty,bx,by);
492 landscape[mx][my] = calc_midpoint(tx,my,bx,my);
497 midpoint_square (tx,ty,d);
498 midpoint_square (mx,ty,d);
499 midpoint_square (tx,my,d);
500 midpoint_square (mx,my,d);
505 * Generate a fractal landscape.
506 * Uses midpoint displacement method.
509 void generate_fractal_landscape (int rnd_seed)
516 old_seed = get_rand_seed();
517 set_rand_seed(rnd_seed);
521 for (y = 0; y <= LAND_Y_MAX; y += d)
522 for (x = 0; x <= LAND_X_MAX; x += d)
523 landscape[x][y] = randint() & 255;
525 for (y = 0; y < LAND_Y_MAX; y += d)
526 for (x = 0; x < LAND_X_MAX; x += d)
527 midpoint_square (x,y,d);
529 for (y = 0; y <= LAND_Y_MAX; y++)
531 for (x = 0; x <= LAND_X_MAX; x++)
537 landscape[x][y] = dark ? GFX_COL_GREEN_1 : GFX_COL_GREEN_2;
539 landscape[x][y] = dark ? GFX_COL_BLUE_2 : GFX_COL_BLUE_1;
544 set_rand_seed (old_seed);
548 void generate_landscape (int rnd_seed)
550 switch (planet_render_style)
552 case 0: /* Wireframe... do nothing for now... */
556 /* generate_green_landscape (); */
560 generate_snes_landscape();
564 generate_fractal_landscape (rnd_seed);
572 * Draw a line of the planet with appropriate rotation.
576 void render_planet_line (int xo, int yo, int x, int y, int radius, int vx, int vy)
587 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
588 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
594 rx = -x * vx - y * vy;
595 ry = -x * vy + y * vx;
598 div = radius << 10; /* radius * 2 * LAND_X_MAX >> 16 */
601 for (; sx <= ex; sx++)
603 if ((sx >= (GFX_VIEW_TX + GFX_X_OFFSET)) && (sx <= (GFX_VIEW_BX + GFX_X_OFFSET)))
607 colour = landscape[lx][ly];
609 gfx_fast_plot_pixel (sx, sy, colour);
618 * Draw a solid planet. Based on Doros circle drawing alogorithm.
621 void render_planet (int xo, int yo, int radius, struct vector *vec)
630 vx = vec[1].x * 65536;
631 vy = vec[1].y * 65536;
640 render_planet_line (xo, yo, x, y, radius, vx, vy);
641 render_planet_line (xo, yo, x,-y, radius, vx, vy);
642 render_planet_line (xo, yo, y, x, radius, vx, vy);
643 render_planet_line (xo, yo, y,-x, radius, vx, vy);
657 * Draw a wireframe planet.
658 * At the moment we just draw a circle.
659 * Need to add in the two arcs that the original Elite had.
662 void draw_wireframe_planet (int xo, int yo, int radius, struct vector *vec)
664 gfx_draw_circle (xo, yo, radius, GFX_COL_WHITE);
670 * We can currently do three different types of planet...
672 * - Fractal landscape.
673 * - SNES Elite style.
676 void draw_planet (struct univ_object *planet)
681 x = (planet->location.x * 256) / planet->location.z;
682 y = (planet->location.y * 256) / planet->location.z;
692 radius = 6291456 / planet->distance;
693 // radius = 6291456 / ship_vec.z; /* Planets are BIG! */
697 if ((x + radius < 0) ||
698 (x - radius > 511) ||
703 switch (planet_render_style)
706 draw_wireframe_planet (x, y, radius, planet->rotmat);
710 gfx_draw_filled_circle (x, y, radius, GFX_COL_GREEN_1);
715 render_planet (x, y, radius, planet->rotmat);
721 void render_sun_line (int xo, int yo, int x, int y, int radius)
732 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
733 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
739 sx -= (radius * (2 + (randint() & 7))) >> 8;
740 ex += (radius * (2 + (randint() & 7))) >> 8;
742 if ((sx > GFX_VIEW_BX + GFX_X_OFFSET) ||
743 (ex < GFX_VIEW_TX + GFX_X_OFFSET))
746 if (sx < GFX_VIEW_TX + GFX_X_OFFSET)
747 sx = GFX_VIEW_TX + GFX_X_OFFSET;
749 if (ex > GFX_VIEW_BX + GFX_X_OFFSET)
750 ex = GFX_VIEW_BX + GFX_X_OFFSET;
752 inner = (radius * (200 + (randint() & 7))) >> 8;
755 inner2 = (radius * (220 + (randint() & 7))) >> 8;
758 outer = (radius * (239 + (randint() & 7))) >> 8;
764 for (; sx <= ex; sx++,dx++)
767 distance = dx * dx + dy;
769 if (distance < inner)
770 colour = GFX_COL_WHITE;
771 else if (distance < inner2)
772 colour = GFX_COL_YELLOW_4;
773 else if (distance < outer)
774 colour = GFX_ORANGE_3;
776 colour = mix ? GFX_ORANGE_1 : GFX_ORANGE_2;
778 gfx_fast_plot_pixel (sx, sy, colour);
783 void render_sun (int xo, int yo, int radius)
798 render_sun_line (xo, yo, x, y, radius);
799 render_sun_line (xo, yo, x,-y, radius);
800 render_sun_line (xo, yo, y, x, radius);
801 render_sun_line (xo, yo, y,-x, radius);
815 void draw_sun (struct univ_object *planet)
820 x = (planet->location.x * 256) / planet->location.z;
821 y = (planet->location.y * 256) / planet->location.z;
831 radius = 6291456 / planet->distance;
835 if ((x + radius < 0) ||
836 (x - radius > 511) ||
841 render_sun (x, y, radius);
846 void draw_explosion (struct univ_object *univ)
854 int sizex,sizey,psx,psy;
860 struct vector camera_vec;
863 struct ship_face_normal *ship_norm;
864 struct ship_point *sp;
865 struct ship_data *ship;
870 if (univ->exp_delta > 251)
872 univ->flags |= FLG_REMOVE;
876 univ->exp_delta += 4;
878 if (univ->location.z <= 0)
881 ship = ship_list[univ->type];
883 for (i = 0; i < 3; i++)
884 trans_mat[i] = univ->rotmat[i];
886 camera_vec = univ->location;
887 mult_vector (&camera_vec, trans_mat);
888 camera_vec = unit_vector (&camera_vec);
890 ship_norm = ship->normals;
892 for (i = 0; i < ship->num_faces; i++)
894 vec.x = ship_norm[i].x;
895 vec.y = ship_norm[i].y;
896 vec.z = ship_norm[i].z;
898 vec = unit_vector (&vec);
899 cos_angle = vector_dot_product (&vec, &camera_vec);
901 visible[i] = (cos_angle < -0.13);
904 tmp = trans_mat[0].y;
905 trans_mat[0].y = trans_mat[1].x;
906 trans_mat[1].x = tmp;
908 tmp = trans_mat[0].z;
909 trans_mat[0].z = trans_mat[2].x;
910 trans_mat[2].x = tmp;
912 tmp = trans_mat[1].z;
913 trans_mat[1].z = trans_mat[2].y;
914 trans_mat[2].y = tmp;
919 for (i = 0; i < ship->num_points; i++)
921 if (visible[sp[i].face1] || visible[sp[i].face2] ||
922 visible[sp[i].face3] || visible[sp[i].face4])
928 mult_vector (&vec, trans_mat);
930 rx = vec.x + univ->location.x;
931 ry = vec.y + univ->location.y;
932 rz = vec.z + univ->location.z;
934 sx = (rx * 256) / rz;
935 sy = (ry * 256) / rz;
945 point_list[np].x = sx;
946 point_list[np].y = sy;
952 z = (int)univ->location.z;
959 pr = (univ->exp_delta * 256) / q;
967 old_seed = get_rand_seed();
968 set_rand_seed (univ->exp_seed);
970 for (cnt = 0; cnt < np; cnt++)
972 sx = point_list[cnt].x;
973 sy = point_list[cnt].y;
975 for (i = 0; i < 16; i++)
977 px = rand255() - 128;
978 py = rand255() - 128;
986 sizex = (randint() & 1) + 1;
987 sizey = (randint() & 1) + 1;
989 for (psy = 0; psy < sizey; psy++)
990 for (psx = 0; psx < sizex; psx++)
991 gfx_plot_pixel (px+psx, py+psy, GFX_COL_WHITE);
995 set_rand_seed (old_seed);
1001 * Draws an object in the universe.
1002 * (Ship, Planet, Sun etc).
1005 void draw_ship (struct univ_object *ship)
1008 if ((current_screen != SCR_FRONT_VIEW) && (current_screen != SCR_REAR_VIEW) &&
1009 (current_screen != SCR_LEFT_VIEW) && (current_screen != SCR_RIGHT_VIEW) &&
1010 (current_screen != SCR_INTRO_ONE) && (current_screen != SCR_INTRO_TWO) &&
1011 (current_screen != SCR_GAME_OVER) && (current_screen != SCR_ESCAPE_POD))
1014 if ((ship->flags & FLG_DEAD) && !(ship->flags & FLG_EXPLOSION))
1016 ship->flags |= FLG_EXPLOSION;
1017 ship->exp_seed = randint();
1018 ship->exp_delta = 18;
1021 if (ship->flags & FLG_EXPLOSION)
1023 draw_explosion (ship);
1027 if (ship->location.z <= 0) /* Only display ships in front of us. */
1030 if (ship->type == SHIP_PLANET)
1036 if (ship->type == SHIP_SUN)
1042 if ((fabs(ship->location.x) > ship->location.z) || /* Check for field of vision. */
1043 (fabs(ship->location.y) > ship->location.z))
1047 draw_wireframe_ship (ship);
1049 draw_solid_ship (ship);