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
);