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);
372 double cx = univ->location.x;
373 double cy = univ->location.y;
374 double cz = univ->location.z;
376 cx = (cx * 256) / cz + 128;
377 cy = -(cy * 256) / cz + 96;
378 gfx_draw_circle(cx * GFX_SCALE, cy * GFX_SCALE, sqrt(ship_list[univ->type]->size) * 256 /
379 cz * GFX_SCALE, GFX_COL_RED);
392 * Colour map used to generate a SNES Elite style planet.
393 * This is a quick hack and needs tidying up.
396 int snes_planet_colour[] =
409 249,249,249,249,249,249,
422 * Generate a landscape map for a SNES Elite style planet.
425 void generate_snes_landscape (void)
430 for (y = 0; y <= LAND_Y_MAX; y++)
432 colour = snes_planet_colour[y * (sizeof(snes_planet_colour)/sizeof(int)) / LAND_Y_MAX];
433 for (x = 0; x <= LAND_X_MAX; x++)
435 landscape[x][y] = colour;
444 * Guassian random number generator.
445 * Returns a number between -7 and +8 with Gaussian distribution.
454 for (i = 0; i < 12; i++)
465 * Calculate the midpoint between two given points.
468 int calc_midpoint (int sx, int sy, int ex, int ey)
472 a = landscape[sx][sy];
473 b = landscape[ex][ey];
475 n = ((a + b) / 2) + grand();
486 * Calculate a square on the midpoint map.
489 void midpoint_square (int tx, int ty, int w)
501 landscape[mx][ty] = calc_midpoint(tx,ty,bx,ty);
502 landscape[mx][by] = calc_midpoint(tx,by,bx,by);
503 landscape[tx][my] = calc_midpoint(tx,ty,tx,by);
504 landscape[bx][my] = calc_midpoint(bx,ty,bx,by);
505 landscape[mx][my] = calc_midpoint(tx,my,bx,my);
510 midpoint_square (tx,ty,d);
511 midpoint_square (mx,ty,d);
512 midpoint_square (tx,my,d);
513 midpoint_square (mx,my,d);
518 * Generate a fractal landscape.
519 * Uses midpoint displacement method.
522 void generate_fractal_landscape (int rnd_seed)
529 old_seed = get_rand_seed();
530 set_rand_seed(rnd_seed);
534 for (y = 0; y <= LAND_Y_MAX; y += d)
535 for (x = 0; x <= LAND_X_MAX; x += d)
536 landscape[x][y] = randint() & 255;
538 for (y = 0; y < LAND_Y_MAX; y += d)
539 for (x = 0; x < LAND_X_MAX; x += d)
540 midpoint_square (x,y,d);
542 for (y = 0; y <= LAND_Y_MAX; y++)
544 for (x = 0; x <= LAND_X_MAX; x++)
550 landscape[x][y] = dark ? GFX_COL_GREEN_1 : GFX_COL_GREEN_2;
552 landscape[x][y] = dark ? GFX_COL_BLUE_2 : GFX_COL_BLUE_1;
557 set_rand_seed (old_seed);
561 void generate_landscape (int rnd_seed)
563 switch (planet_render_style)
565 case 0: /* Wireframe... do nothing for now... */
569 /* generate_green_landscape (); */
573 generate_snes_landscape();
577 generate_fractal_landscape (rnd_seed);
585 * Draw a line of the planet with appropriate rotation.
589 void render_planet_line (int xo, int yo, int x, int y, int radius, int vx, int vy)
600 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
601 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
607 rx = -x * vx - y * vy;
608 ry = -x * vy + y * vx;
611 div = radius << 10; /* radius * 2 * LAND_X_MAX >> 16 */
614 for (; sx <= ex; sx++)
616 if ((sx >= (GFX_VIEW_TX + GFX_X_OFFSET)) && (sx <= (GFX_VIEW_BX + GFX_X_OFFSET)))
620 colour = landscape[lx][ly];
622 gfx_fast_plot_pixel (sx, sy, colour);
631 * Draw a solid planet. Based on Doros circle drawing alogorithm.
634 void render_planet (int xo, int yo, int radius, struct vector *vec)
643 vx = vec[1].x * 65536;
644 vy = vec[1].y * 65536;
653 render_planet_line (xo, yo, x, y, radius, vx, vy);
654 render_planet_line (xo, yo, x,-y, radius, vx, vy);
655 render_planet_line (xo, yo, y, x, radius, vx, vy);
656 render_planet_line (xo, yo, y,-x, radius, vx, vy);
670 * Draw a wireframe planet.
671 * At the moment we just draw a circle.
672 * Need to add in the two arcs that the original Elite had.
675 void draw_wireframe_planet (int xo, int yo, int radius, struct vector *vec)
677 gfx_draw_circle (xo, yo, radius, GFX_COL_WHITE);
683 * We can currently do three different types of planet...
685 * - Fractal landscape.
686 * - SNES Elite style.
689 void draw_planet (struct univ_object *planet)
694 x = (planet->location.x * 256) / planet->location.z;
695 y = (planet->location.y * 256) / planet->location.z;
705 radius = 6291456 / planet->distance;
706 // radius = 6291456 / ship_vec.z; /* Planets are BIG! */
710 if ((x + radius < 0) ||
711 (x - radius > 511) ||
716 switch (planet_render_style)
719 draw_wireframe_planet (x, y, radius, planet->rotmat);
723 gfx_draw_filled_circle (x, y, radius, GFX_COL_GREEN_1);
728 render_planet (x, y, radius, planet->rotmat);
734 void render_sun_line (int xo, int yo, int x, int y, int radius)
745 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
746 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
752 sx -= (radius * (2 + (randint() & 7))) >> 8;
753 ex += (radius * (2 + (randint() & 7))) >> 8;
755 if ((sx > GFX_VIEW_BX + GFX_X_OFFSET) ||
756 (ex < GFX_VIEW_TX + GFX_X_OFFSET))
759 if (sx < GFX_VIEW_TX + GFX_X_OFFSET)
760 sx = GFX_VIEW_TX + GFX_X_OFFSET;
762 if (ex > GFX_VIEW_BX + GFX_X_OFFSET)
763 ex = GFX_VIEW_BX + GFX_X_OFFSET;
765 inner = (radius * (200 + (randint() & 7))) >> 8;
768 inner2 = (radius * (220 + (randint() & 7))) >> 8;
771 outer = (radius * (239 + (randint() & 7))) >> 8;
777 for (; sx <= ex; sx++,dx++)
780 distance = dx * dx + dy;
782 if (distance < inner)
783 colour = GFX_COL_WHITE;
784 else if (distance < inner2)
785 colour = GFX_COL_YELLOW_4;
786 else if (distance < outer)
787 colour = GFX_ORANGE_3;
789 colour = mix ? GFX_ORANGE_1 : GFX_ORANGE_2;
791 gfx_fast_plot_pixel (sx, sy, colour);
796 void render_sun (int xo, int yo, int radius)
811 render_sun_line (xo, yo, x, y, radius);
812 render_sun_line (xo, yo, x,-y, radius);
813 render_sun_line (xo, yo, y, x, radius);
814 render_sun_line (xo, yo, y,-x, radius);
828 void draw_sun (struct univ_object *planet)
833 x = (planet->location.x * 256) / planet->location.z;
834 y = (planet->location.y * 256) / planet->location.z;
844 radius = 6291456 / planet->distance;
848 if ((x + radius < 0) ||
849 (x - radius > 511) ||
854 render_sun (x, y, radius);
859 void draw_explosion (struct univ_object *univ)
867 int sizex,sizey,psx,psy;
873 struct vector camera_vec;
876 struct ship_face_normal *ship_norm;
877 struct ship_point *sp;
878 struct ship_data *ship;
883 if (univ->exp_delta > 251)
885 univ->flags |= FLG_REMOVE;
889 univ->exp_delta += 4;
891 if (univ->location.z <= 0)
894 ship = ship_list[univ->type];
896 for (i = 0; i < 3; i++)
897 trans_mat[i] = univ->rotmat[i];
899 camera_vec = univ->location;
900 mult_vector (&camera_vec, trans_mat);
901 camera_vec = unit_vector (&camera_vec);
903 ship_norm = ship->normals;
905 for (i = 0; i < ship->num_faces; i++)
907 vec.x = ship_norm[i].x;
908 vec.y = ship_norm[i].y;
909 vec.z = ship_norm[i].z;
911 vec = unit_vector (&vec);
912 cos_angle = vector_dot_product (&vec, &camera_vec);
914 visible[i] = (cos_angle < -0.13);
917 tmp = trans_mat[0].y;
918 trans_mat[0].y = trans_mat[1].x;
919 trans_mat[1].x = tmp;
921 tmp = trans_mat[0].z;
922 trans_mat[0].z = trans_mat[2].x;
923 trans_mat[2].x = tmp;
925 tmp = trans_mat[1].z;
926 trans_mat[1].z = trans_mat[2].y;
927 trans_mat[2].y = tmp;
932 for (i = 0; i < ship->num_points; i++)
934 if (visible[sp[i].face1] || visible[sp[i].face2] ||
935 visible[sp[i].face3] || visible[sp[i].face4])
941 mult_vector (&vec, trans_mat);
943 rx = vec.x + univ->location.x;
944 ry = vec.y + univ->location.y;
945 rz = vec.z + univ->location.z;
947 sx = (rx * 256) / rz;
948 sy = (ry * 256) / rz;
958 point_list[np].x = sx;
959 point_list[np].y = sy;
965 z = (int)univ->location.z;
972 pr = (univ->exp_delta * 256) / q;
980 old_seed = get_rand_seed();
981 set_rand_seed (univ->exp_seed);
983 for (cnt = 0; cnt < np; cnt++)
985 sx = point_list[cnt].x;
986 sy = point_list[cnt].y;
988 for (i = 0; i < 16; i++)
990 px = rand255() - 128;
991 py = rand255() - 128;
999 sizex = (randint() & 1) + 1;
1000 sizey = (randint() & 1) + 1;
1002 for (psy = 0; psy < sizey; psy++)
1003 for (psx = 0; psx < sizex; psx++)
1004 gfx_plot_pixel (px+psx, py+psy, GFX_COL_WHITE);
1008 set_rand_seed (old_seed);
1014 * Draws an object in the universe.
1015 * (Ship, Planet, Sun etc).
1018 void draw_ship (struct univ_object *ship)
1021 if ((current_screen != SCR_FRONT_VIEW) && (current_screen != SCR_REAR_VIEW) &&
1022 (current_screen != SCR_LEFT_VIEW) && (current_screen != SCR_RIGHT_VIEW) &&
1023 (current_screen != SCR_INTRO_ONE) && (current_screen != SCR_INTRO_TWO) &&
1024 (current_screen != SCR_GAME_OVER) && (current_screen != SCR_ESCAPE_POD))
1027 if ((ship->flags & FLG_DEAD) && !(ship->flags & FLG_EXPLOSION))
1029 ship->flags |= FLG_EXPLOSION;
1030 ship->exp_seed = randint();
1031 ship->exp_delta = 18;
1034 if (ship->flags & FLG_EXPLOSION)
1036 draw_explosion (ship);
1040 if (ship->location.z <= 0) /* Only display ships in front of us. */
1043 if (ship->type == SHIP_PLANET)
1049 if (ship->type == SHIP_SUN)
1055 if ((fabs(ship->location.x) > ship->location.z) || /* Check for field of vision. */
1056 (fabs(ship->location.y) > ship->location.z))
1060 draw_wireframe_ship (ship);
1062 draw_solid_ship (ship);