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];
43 static void identify_ship(struct univ_object *univ)
48 lasv = ship_list[univ->type]->front_laser;
49 if (!(univ->flags & FLG_TACTICAL)) {
50 unsigned flags = univ->flags;
51 sprintf(buf, "%s %s%s%s%s", ship_list[univ->type]->name,
52 (flags & FLG_ANGRY) ? "A" : "",
53 (flags & FLG_TARGET) ? "T" : "",
54 (flags & FLG_HOSTILE) ? "H" : "",
55 (flags & FLG_POLICE) ? "P" : "");
57 unsigned flags = univ->flags;
58 sprintf(buf, "%s (%d) %s%s%s%s", ship_list[univ->type]->name,
60 (flags & FLG_ANGRY) ? "A" : "",
61 (flags & FLG_TARGET) ? "T" : "",
62 (flags & FLG_HOSTILE) ? "H" : "",
63 (flags & FLG_POLICE) ? "P" : "");
65 gfx_display_text(point_list[lasv].x + 4, point_list[lasv].y + 4, buf);
71 * The following routine is used to draw a wireframe represtation of a ship.
73 * caveat: it is a work in progress.
74 * A number of features (such as not showing detail at distance) have not yet been implemented.
78 void draw_wireframe_ship (struct univ_object *univ)
89 struct ship_face_normal *ship_norm;
91 struct ship_data *ship;
94 ship = ship_list[univ->type];
96 for (i = 0; i < 3; i++)
97 trans_mat[i] = univ->rotmat[i];
99 camera_vec = univ->location;
100 mult_vector (&camera_vec, trans_mat);
101 camera_vec = unit_vector (&camera_vec);
103 num_faces = ship->num_faces;
105 for (i = 0; i < num_faces; i++)
107 ship_norm = ship->normals;
109 vec.x = ship_norm[i].x;
110 vec.y = ship_norm[i].y;
111 vec.z = ship_norm[i].z;
113 if ((vec.x == 0) && (vec.y == 0) && (vec.z == 0))
117 vec = unit_vector (&vec);
118 cos_angle = vector_dot_product (&vec, &camera_vec);
119 visible[i] = (cos_angle < -0.2);
123 tmp = trans_mat[0].y;
124 trans_mat[0].y = trans_mat[1].x;
125 trans_mat[1].x = tmp;
127 tmp = trans_mat[0].z;
128 trans_mat[0].z = trans_mat[2].x;
129 trans_mat[2].x = tmp;
131 tmp = trans_mat[1].z;
132 trans_mat[1].z = trans_mat[2].y;
133 trans_mat[2].y = tmp;
135 for (i = 0; i < ship->num_points; i++)
137 vec.x = ship->points[i].x;
138 vec.y = ship->points[i].y;
139 vec.z = ship->points[i].z;
141 mult_vector (&vec, trans_mat);
143 rx = vec.x + univ->location.x;
144 ry = vec.y + univ->location.y;
145 rz = vec.z + univ->location.z;
147 sx = (rx * 256) / rz;
148 sy = (ry * 256) / rz;
158 point_list[i].x = sx;
159 point_list[i].y = sy;
163 for (i = 0; i < ship->num_lines; i++)
165 if (visible[ship->lines[i].face1] ||
166 visible[ship->lines[i].face2])
168 sx = point_list[ship->lines[i].start_point].x;
169 sy = point_list[ship->lines[i].start_point].y;
171 ex = point_list[ship->lines[i].end_point].x;
172 ey = point_list[ship->lines[i].end_point].y;
174 gfx_draw_line (sx, sy, ex, ey);
179 if (univ->flags & FLG_FIRING)
181 lasv = ship_list[univ->type]->front_laser;
182 gfx_draw_line (point_list[lasv].x, point_list[lasv].y,
183 univ->location.x > 0 ? 0 : 511, rand255() * 2);
196 * Hacked version of the draw ship routine to display solid ships...
197 * This needs a lot of tidying...
199 * Check for hidden surface supplied by T.Harte.
202 void draw_solid_ship (struct univ_object *univ)
208 struct vector camera_vec;
210 struct ship_face *face_data;
215 struct ship_solid *solid_data;
216 struct ship_data *ship;
221 solid_data = &ship_solids[univ->type];
222 ship = ship_list[univ->type];
224 for (i = 0; i < 3; i++)
225 trans_mat[i] = univ->rotmat[i];
227 camera_vec = univ->location;
228 mult_vector (&camera_vec, trans_mat);
229 camera_vec = unit_vector (&camera_vec);
231 num_faces = solid_data->num_faces;
232 face_data = solid_data->face_data;
235 for (i = 0; i < num_faces; i++)
237 vec.x = face_data[i].norm_x;
238 vec.y = face_data[i].norm_y;
239 vec.z = face_data[i].norm_z;
241 vec = unit_vector (&vec);
242 cos_angle = vector_dot_product (&vec, &camera_vec);
244 visible[i] = (cos_angle < -0.13);
248 tmp = trans_mat[0].y;
249 trans_mat[0].y = trans_mat[1].x;
250 trans_mat[1].x = tmp;
252 tmp = trans_mat[0].z;
253 trans_mat[0].z = trans_mat[2].x;
254 trans_mat[2].x = tmp;
256 tmp = trans_mat[1].z;
257 trans_mat[1].z = trans_mat[2].y;
258 trans_mat[2].y = tmp;
261 for (i = 0; i < ship->num_points; i++)
263 vec.x = ship->points[i].x;
264 vec.y = ship->points[i].y;
265 vec.z = ship->points[i].z;
267 mult_vector (&vec, trans_mat);
269 rx = vec.x + univ->location.x;
270 ry = vec.y + univ->location.y;
271 rz = vec.z + univ->location.z;
276 sx = (rx * 256) / rz;
277 sy = (ry * 256) / rz;
287 point_list[i].x = sx;
288 point_list[i].y = sy;
289 point_list[i].z = rz;
293 for (i = 0; i < num_faces; i++)
295 if (((point_list[face_data[i].p1].x - point_list[face_data[i].p2].x) *
296 (point_list[face_data[i].p3].y - point_list[face_data[i].p2].y) -
297 (point_list[face_data[i].p1].y - point_list[face_data[i].p2].y) *
298 (point_list[face_data[i].p3].x - point_list[face_data[i].p2].x)) <= 0)
300 num_points = face_data[i].points;
302 poly_list[0] = point_list[face_data[i].p1].x;
303 poly_list[1] = point_list[face_data[i].p1].y;
304 zavg = point_list[face_data[i].p1].z;
306 poly_list[2] = point_list[face_data[i].p2].x;
307 poly_list[3] = point_list[face_data[i].p2].y;
308 zavg = MAX(zavg,point_list[face_data[i].p2].z);
312 poly_list[4] = point_list[face_data[i].p3].x;
313 poly_list[5] = point_list[face_data[i].p3].y;
314 zavg = MAX(zavg,point_list[face_data[i].p3].z);
319 poly_list[6] = point_list[face_data[i].p4].x;
320 poly_list[7] = point_list[face_data[i].p4].y;
321 zavg = MAX(zavg,point_list[face_data[i].p4].z);
326 poly_list[8] = point_list[face_data[i].p5].x;
327 poly_list[9] = point_list[face_data[i].p5].y;
328 zavg = MAX(zavg,point_list[face_data[i].p5].z);
333 poly_list[10] = point_list[face_data[i].p6].x;
334 poly_list[11] = point_list[face_data[i].p6].y;
335 zavg = MAX(zavg,point_list[face_data[i].p6].z);
340 poly_list[12] = point_list[face_data[i].p7].x;
341 poly_list[13] = point_list[face_data[i].p7].y;
342 zavg = MAX(zavg,point_list[face_data[i].p7].z);
347 poly_list[14] = point_list[face_data[i].p8].x;
348 poly_list[15] = point_list[face_data[i].p8].y;
349 zavg = MAX(zavg,point_list[face_data[i].p8].z);
353 gfx_render_polygon (face_data[i].points, poly_list, face_data[i].colour, zavg);
358 if (univ->flags & FLG_FIRING)
360 lasv = ship_list[univ->type]->front_laser;
361 col = (univ->type == SHIP_VIPER) ? GFX_COL_CYAN : GFX_COL_WHITE;
363 gfx_render_line (point_list[lasv].x, point_list[lasv].y,
364 univ->location.x > 0 ? 0 : 511, rand255() * 2,
365 point_list[lasv].z, col);
370 double cx = univ->location.x;
371 double cy = univ->location.y;
372 double cz = univ->location.z;
374 cx = (cx * 256) / cz + 128;
375 cy = -(cy * 256) / cz + 96;
376 gfx_draw_circle(cx * GFX_SCALE, cy * GFX_SCALE, sqrt(ship_list[univ->type]->size) * 256 /
377 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);