1ea06a31534ca50ed4b1b5e0cbe666750c887431
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 * The following routine is used to draw a wireframe represtation of a ship.
45 * caveat: it is a work in progress.
46 * A number of features (such as not showing detail at distance) have not yet been implemented.
50 void draw_wireframe_ship (struct univ_object
*univ
)
61 struct ship_face_normal
*ship_norm
;
63 struct ship_data
*ship
;
66 ship
= ship_list
[univ
->type
];
68 for (i
= 0; i
< 3; i
++)
69 trans_mat
[i
] = univ
->rotmat
[i
];
71 camera_vec
= univ
->location
;
72 mult_vector (&camera_vec
, trans_mat
);
73 camera_vec
= unit_vector (&camera_vec
);
75 num_faces
= ship
->num_faces
;
77 for (i
= 0; i
< num_faces
; i
++)
79 ship_norm
= ship
->normals
;
81 vec
.x
= ship_norm
[i
].x
;
82 vec
.y
= ship_norm
[i
].y
;
83 vec
.z
= ship_norm
[i
].z
;
85 if ((vec
.x
== 0) && (vec
.y
== 0) && (vec
.z
== 0))
89 vec
= unit_vector (&vec
);
90 cos_angle
= vector_dot_product (&vec
, &camera_vec
);
91 visible
[i
] = (cos_angle
< -0.2);
96 trans_mat
[0].y
= trans_mat
[1].x
;
100 trans_mat
[0].z
= trans_mat
[2].x
;
101 trans_mat
[2].x
= tmp
;
103 tmp
= trans_mat
[1].z
;
104 trans_mat
[1].z
= trans_mat
[2].y
;
105 trans_mat
[2].y
= tmp
;
107 for (i
= 0; i
< ship
->num_points
; i
++)
109 vec
.x
= ship
->points
[i
].x
;
110 vec
.y
= ship
->points
[i
].y
;
111 vec
.z
= ship
->points
[i
].z
;
113 mult_vector (&vec
, trans_mat
);
115 rx
= vec
.x
+ univ
->location
.x
;
116 ry
= vec
.y
+ univ
->location
.y
;
117 rz
= vec
.z
+ univ
->location
.z
;
119 sx
= (rx
* 256) / rz
;
120 sy
= (ry
* 256) / rz
;
130 point_list
[i
].x
= sx
;
131 point_list
[i
].y
= sy
;
135 for (i
= 0; i
< ship
->num_lines
; i
++)
137 if (visible
[ship
->lines
[i
].face1
] ||
138 visible
[ship
->lines
[i
].face2
])
140 sx
= point_list
[ship
->lines
[i
].start_point
].x
;
141 sy
= point_list
[ship
->lines
[i
].start_point
].y
;
143 ex
= point_list
[ship
->lines
[i
].end_point
].x
;
144 ey
= point_list
[ship
->lines
[i
].end_point
].y
;
146 gfx_draw_line (sx
, sy
, ex
, ey
);
151 if (univ
->flags
& FLG_FIRING
)
153 lasv
= ship_list
[univ
->type
]->front_laser
;
154 gfx_draw_line (point_list
[lasv
].x
, point_list
[lasv
].y
,
155 univ
->location
.x
> 0 ?
0 : 511, rand255() * 2);
163 * Hacked version of the draw ship routine to display solid ships...
164 * This needs a lot of tidying...
166 * Check for hidden surface supplied by T.Harte.
169 void draw_solid_ship (struct univ_object
*univ
)
175 struct vector camera_vec
;
177 struct ship_face
*face_data
;
182 struct ship_solid
*solid_data
;
183 struct ship_data
*ship
;
188 solid_data
= &ship_solids
[univ
->type
];
189 ship
= ship_list
[univ
->type
];
191 for (i
= 0; i
< 3; i
++)
192 trans_mat
[i
] = univ
->rotmat
[i
];
194 camera_vec
= univ
->location
;
195 mult_vector (&camera_vec
, trans_mat
);
196 camera_vec
= unit_vector (&camera_vec
);
198 num_faces
= solid_data
->num_faces
;
199 face_data
= solid_data
->face_data
;
202 for (i = 0; i < num_faces; i++)
204 vec.x = face_data[i].norm_x;
205 vec.y = face_data[i].norm_y;
206 vec.z = face_data[i].norm_z;
208 vec = unit_vector (&vec);
209 cos_angle = vector_dot_product (&vec, &camera_vec);
211 visible[i] = (cos_angle < -0.13);
215 tmp
= trans_mat
[0].y
;
216 trans_mat
[0].y
= trans_mat
[1].x
;
217 trans_mat
[1].x
= tmp
;
219 tmp
= trans_mat
[0].z
;
220 trans_mat
[0].z
= trans_mat
[2].x
;
221 trans_mat
[2].x
= tmp
;
223 tmp
= trans_mat
[1].z
;
224 trans_mat
[1].z
= trans_mat
[2].y
;
225 trans_mat
[2].y
= tmp
;
228 for (i
= 0; i
< ship
->num_points
; i
++)
230 vec
.x
= ship
->points
[i
].x
;
231 vec
.y
= ship
->points
[i
].y
;
232 vec
.z
= ship
->points
[i
].z
;
234 mult_vector (&vec
, trans_mat
);
236 rx
= vec
.x
+ univ
->location
.x
;
237 ry
= vec
.y
+ univ
->location
.y
;
238 rz
= vec
.z
+ univ
->location
.z
;
243 sx
= (rx
* 256) / rz
;
244 sy
= (ry
* 256) / rz
;
254 point_list
[i
].x
= sx
;
255 point_list
[i
].y
= sy
;
256 point_list
[i
].z
= rz
;
260 for (i
= 0; i
< num_faces
; i
++)
262 if (((point_list
[face_data
[i
].p1
].x
- point_list
[face_data
[i
].p2
].x
) *
263 (point_list
[face_data
[i
].p3
].y
- point_list
[face_data
[i
].p2
].y
) -
264 (point_list
[face_data
[i
].p1
].y
- point_list
[face_data
[i
].p2
].y
) *
265 (point_list
[face_data
[i
].p3
].x
- point_list
[face_data
[i
].p2
].x
)) <= 0)
267 num_points
= face_data
[i
].points
;
269 poly_list
[0] = point_list
[face_data
[i
].p1
].x
;
270 poly_list
[1] = point_list
[face_data
[i
].p1
].y
;
271 zavg
= point_list
[face_data
[i
].p1
].z
;
273 poly_list
[2] = point_list
[face_data
[i
].p2
].x
;
274 poly_list
[3] = point_list
[face_data
[i
].p2
].y
;
275 zavg
= MAX(zavg
,point_list
[face_data
[i
].p2
].z
);
279 poly_list
[4] = point_list
[face_data
[i
].p3
].x
;
280 poly_list
[5] = point_list
[face_data
[i
].p3
].y
;
281 zavg
= MAX(zavg
,point_list
[face_data
[i
].p3
].z
);
286 poly_list
[6] = point_list
[face_data
[i
].p4
].x
;
287 poly_list
[7] = point_list
[face_data
[i
].p4
].y
;
288 zavg
= MAX(zavg
,point_list
[face_data
[i
].p4
].z
);
293 poly_list
[8] = point_list
[face_data
[i
].p5
].x
;
294 poly_list
[9] = point_list
[face_data
[i
].p5
].y
;
295 zavg
= MAX(zavg
,point_list
[face_data
[i
].p5
].z
);
300 poly_list
[10] = point_list
[face_data
[i
].p6
].x
;
301 poly_list
[11] = point_list
[face_data
[i
].p6
].y
;
302 zavg
= MAX(zavg
,point_list
[face_data
[i
].p6
].z
);
307 poly_list
[12] = point_list
[face_data
[i
].p7
].x
;
308 poly_list
[13] = point_list
[face_data
[i
].p7
].y
;
309 zavg
= MAX(zavg
,point_list
[face_data
[i
].p7
].z
);
314 poly_list
[14] = point_list
[face_data
[i
].p8
].x
;
315 poly_list
[15] = point_list
[face_data
[i
].p8
].y
;
316 zavg
= MAX(zavg
,point_list
[face_data
[i
].p8
].z
);
320 gfx_render_polygon (face_data
[i
].points
, poly_list
, face_data
[i
].colour
, zavg
);
325 if (univ
->flags
& FLG_FIRING
)
327 lasv
= ship_list
[univ
->type
]->front_laser
;
328 col
= (univ
->type
== SHIP_VIPER
) ? GFX_COL_CYAN
: GFX_COL_WHITE
;
330 gfx_render_line (point_list
[lasv
].x
, point_list
[lasv
].y
,
331 univ
->location
.x
> 0 ?
0 : 511, rand255() * 2,
332 point_list
[lasv
].z
, col
);
341 * Colour map used to generate a SNES Elite style planet.
342 * This is a quick hack and needs tidying up.
345 int snes_planet_colour
[] =
358 249,249,249,249,249,249,
371 * Generate a landscape map for a SNES Elite style planet.
374 void generate_snes_landscape (void)
379 for (y
= 0; y
<= LAND_Y_MAX
; y
++)
381 colour
= snes_planet_colour
[y
* (sizeof(snes_planet_colour
)/sizeof(int)) / LAND_Y_MAX
];
382 for (x
= 0; x
<= LAND_X_MAX
; x
++)
384 landscape
[x
][y
] = colour
;
393 * Guassian random number generator.
394 * Returns a number between -7 and +8 with Gaussian distribution.
403 for (i
= 0; i
< 12; i
++)
414 * Calculate the midpoint between two given points.
417 int calc_midpoint (int sx
, int sy
, int ex
, int ey
)
421 a
= landscape
[sx
][sy
];
422 b
= landscape
[ex
][ey
];
424 n
= ((a
+ b
) / 2) + grand();
435 * Calculate a square on the midpoint map.
438 void midpoint_square (int tx
, int ty
, int w
)
450 landscape
[mx
][ty
] = calc_midpoint(tx
,ty
,bx
,ty
);
451 landscape
[mx
][by
] = calc_midpoint(tx
,by
,bx
,by
);
452 landscape
[tx
][my
] = calc_midpoint(tx
,ty
,tx
,by
);
453 landscape
[bx
][my
] = calc_midpoint(bx
,ty
,bx
,by
);
454 landscape
[mx
][my
] = calc_midpoint(tx
,my
,bx
,my
);
459 midpoint_square (tx
,ty
,d
);
460 midpoint_square (mx
,ty
,d
);
461 midpoint_square (tx
,my
,d
);
462 midpoint_square (mx
,my
,d
);
467 * Generate a fractal landscape.
468 * Uses midpoint displacement method.
471 void generate_fractal_landscape (int rnd_seed
)
478 old_seed
= get_rand_seed();
479 set_rand_seed(rnd_seed
);
483 for (y
= 0; y
<= LAND_Y_MAX
; y
+= d
)
484 for (x
= 0; x
<= LAND_X_MAX
; x
+= d
)
485 landscape
[x
][y
] = randint() & 255;
487 for (y
= 0; y
< LAND_Y_MAX
; y
+= d
)
488 for (x
= 0; x
< LAND_X_MAX
; x
+= d
)
489 midpoint_square (x
,y
,d
);
491 for (y
= 0; y
<= LAND_Y_MAX
; y
++)
493 for (x
= 0; x
<= LAND_X_MAX
; x
++)
499 landscape
[x
][y
] = dark ? GFX_COL_GREEN_1
: GFX_COL_GREEN_2
;
501 landscape
[x
][y
] = dark ? GFX_COL_BLUE_2
: GFX_COL_BLUE_1
;
506 set_rand_seed (old_seed
);
510 void generate_landscape (int rnd_seed
)
512 switch (planet_render_style
)
514 case 0: /* Wireframe... do nothing for now... */
518 /* generate_green_landscape (); */
522 generate_snes_landscape();
526 generate_fractal_landscape (rnd_seed
);
534 * Draw a line of the planet with appropriate rotation.
538 void render_planet_line (int xo
, int yo
, int x
, int y
, int radius
, int vx
, int vy
)
549 if ((sy
< GFX_VIEW_TY
+ GFX_Y_OFFSET
) ||
550 (sy
> GFX_VIEW_BY
+ GFX_Y_OFFSET
))
556 rx
= -x
* vx
- y
* vy
;
557 ry
= -x
* vy
+ y
* vx
;
560 div
= radius
<< 10; /* radius * 2 * LAND_X_MAX >> 16 */
563 for (; sx
<= ex
; sx
++)
565 if ((sx
>= (GFX_VIEW_TX
+ GFX_X_OFFSET
)) && (sx
<= (GFX_VIEW_BX
+ GFX_X_OFFSET
)))
569 colour
= landscape
[lx
][ly
];
571 gfx_fast_plot_pixel (sx
, sy
, colour
);
580 * Draw a solid planet. Based on Doros circle drawing alogorithm.
583 void render_planet (int xo
, int yo
, int radius
, struct vector
*vec
)
592 vx
= vec
[1].x
* 65536;
593 vy
= vec
[1].y
* 65536;
602 render_planet_line (xo
, yo
, x
, y
, radius
, vx
, vy
);
603 render_planet_line (xo
, yo
, x
,-y
, radius
, vx
, vy
);
604 render_planet_line (xo
, yo
, y
, x
, radius
, vx
, vy
);
605 render_planet_line (xo
, yo
, y
,-x
, radius
, vx
, vy
);
619 * Draw a wireframe planet.
620 * At the moment we just draw a circle.
621 * Need to add in the two arcs that the original Elite had.
624 void draw_wireframe_planet (int xo
, int yo
, int radius
, struct vector
*vec
)
626 gfx_draw_circle (xo
, yo
, radius
, GFX_COL_WHITE
);
632 * We can currently do three different types of planet...
634 * - Fractal landscape.
635 * - SNES Elite style.
638 void draw_planet (struct univ_object
*planet
)
643 x
= (planet
->location
.x
* 256) / planet
->location
.z
;
644 y
= (planet
->location
.y
* 256) / planet
->location
.z
;
654 radius
= 6291456 / planet
->distance
;
655 // radius = 6291456 / ship_vec.z; /* Planets are BIG! */
659 if ((x
+ radius
< 0) ||
660 (x
- radius
> 511) ||
665 switch (planet_render_style
)
668 draw_wireframe_planet (x
, y
, radius
, planet
->rotmat
);
672 gfx_draw_filled_circle (x
, y
, radius
, GFX_COL_GREEN_1
);
677 render_planet (x
, y
, radius
, planet
->rotmat
);
683 void render_sun_line (int xo
, int yo
, int x
, int y
, int radius
)
694 if ((sy
< GFX_VIEW_TY
+ GFX_Y_OFFSET
) ||
695 (sy
> GFX_VIEW_BY
+ GFX_Y_OFFSET
))
701 sx
-= (radius
* (2 + (randint() & 7))) >> 8;
702 ex
+= (radius
* (2 + (randint() & 7))) >> 8;
704 if ((sx
> GFX_VIEW_BX
+ GFX_X_OFFSET
) ||
705 (ex
< GFX_VIEW_TX
+ GFX_X_OFFSET
))
708 if (sx
< GFX_VIEW_TX
+ GFX_X_OFFSET
)
709 sx
= GFX_VIEW_TX
+ GFX_X_OFFSET
;
711 if (ex
> GFX_VIEW_BX
+ GFX_X_OFFSET
)
712 ex
= GFX_VIEW_BX
+ GFX_X_OFFSET
;
714 inner
= (radius
* (200 + (randint() & 7))) >> 8;
717 inner2
= (radius
* (220 + (randint() & 7))) >> 8;
720 outer
= (radius
* (239 + (randint() & 7))) >> 8;
726 for (; sx
<= ex
; sx
++,dx
++)
729 distance
= dx
* dx
+ dy
;
731 if (distance
< inner
)
732 colour
= GFX_COL_WHITE
;
733 else if (distance
< inner2
)
734 colour
= GFX_COL_YELLOW_4
;
735 else if (distance
< outer
)
736 colour
= GFX_ORANGE_3
;
738 colour
= mix ? GFX_ORANGE_1
: GFX_ORANGE_2
;
740 gfx_fast_plot_pixel (sx
, sy
, colour
);
745 void render_sun (int xo
, int yo
, int radius
)
760 render_sun_line (xo
, yo
, x
, y
, radius
);
761 render_sun_line (xo
, yo
, x
,-y
, radius
);
762 render_sun_line (xo
, yo
, y
, x
, radius
);
763 render_sun_line (xo
, yo
, y
,-x
, radius
);
777 void draw_sun (struct univ_object
*planet
)
782 x
= (planet
->location
.x
* 256) / planet
->location
.z
;
783 y
= (planet
->location
.y
* 256) / planet
->location
.z
;
793 radius
= 6291456 / planet
->distance
;
797 if ((x
+ radius
< 0) ||
798 (x
- radius
> 511) ||
803 render_sun (x
, y
, radius
);
808 void draw_explosion (struct univ_object
*univ
)
816 int sizex
,sizey
,psx
,psy
;
822 struct vector camera_vec
;
825 struct ship_face_normal
*ship_norm
;
826 struct ship_point
*sp
;
827 struct ship_data
*ship
;
832 if (univ
->exp_delta
> 251)
834 univ
->flags
|= FLG_REMOVE
;
838 univ
->exp_delta
+= 4;
840 if (univ
->location
.z
<= 0)
843 ship
= ship_list
[univ
->type
];
845 for (i
= 0; i
< 3; i
++)
846 trans_mat
[i
] = univ
->rotmat
[i
];
848 camera_vec
= univ
->location
;
849 mult_vector (&camera_vec
, trans_mat
);
850 camera_vec
= unit_vector (&camera_vec
);
852 ship_norm
= ship
->normals
;
854 for (i
= 0; i
< ship
->num_faces
; i
++)
856 vec
.x
= ship_norm
[i
].x
;
857 vec
.y
= ship_norm
[i
].y
;
858 vec
.z
= ship_norm
[i
].z
;
860 vec
= unit_vector (&vec
);
861 cos_angle
= vector_dot_product (&vec
, &camera_vec
);
863 visible
[i
] = (cos_angle
< -0.13);
866 tmp
= trans_mat
[0].y
;
867 trans_mat
[0].y
= trans_mat
[1].x
;
868 trans_mat
[1].x
= tmp
;
870 tmp
= trans_mat
[0].z
;
871 trans_mat
[0].z
= trans_mat
[2].x
;
872 trans_mat
[2].x
= tmp
;
874 tmp
= trans_mat
[1].z
;
875 trans_mat
[1].z
= trans_mat
[2].y
;
876 trans_mat
[2].y
= tmp
;
881 for (i
= 0; i
< ship
->num_points
; i
++)
883 if (visible
[sp
[i
].face1
] || visible
[sp
[i
].face2
] ||
884 visible
[sp
[i
].face3
] || visible
[sp
[i
].face4
])
890 mult_vector (&vec
, trans_mat
);
892 rx
= vec
.x
+ univ
->location
.x
;
893 ry
= vec
.y
+ univ
->location
.y
;
894 rz
= vec
.z
+ univ
->location
.z
;
896 sx
= (rx
* 256) / rz
;
897 sy
= (ry
* 256) / rz
;
907 point_list
[np
].x
= sx
;
908 point_list
[np
].y
= sy
;
914 z
= (int)univ
->location
.z
;
921 pr
= (univ
->exp_delta
* 256) / q
;
929 old_seed
= get_rand_seed();
930 set_rand_seed (univ
->exp_seed
);
932 for (cnt
= 0; cnt
< np
; cnt
++)
934 sx
= point_list
[cnt
].x
;
935 sy
= point_list
[cnt
].y
;
937 for (i
= 0; i
< 16; i
++)
939 px
= rand255() - 128;
940 py
= rand255() - 128;
948 sizex
= (randint() & 1) + 1;
949 sizey
= (randint() & 1) + 1;
951 for (psy
= 0; psy
< sizey
; psy
++)
952 for (psx
= 0; psx
< sizex
; psx
++)
953 gfx_plot_pixel (px
+psx
, py
+psy
, GFX_COL_WHITE
);
957 set_rand_seed (old_seed
);
963 * Draws an object in the universe.
964 * (Ship, Planet, Sun etc).
967 void draw_ship (struct univ_object
*ship
)
970 if ((current_screen
!= SCR_FRONT_VIEW
) && (current_screen
!= SCR_REAR_VIEW
) &&
971 (current_screen
!= SCR_LEFT_VIEW
) && (current_screen
!= SCR_RIGHT_VIEW
) &&
972 (current_screen
!= SCR_INTRO_ONE
) && (current_screen
!= SCR_INTRO_TWO
) &&
973 (current_screen
!= SCR_GAME_OVER
) && (current_screen
!= SCR_ESCAPE_POD
))
976 if ((ship
->flags
& FLG_DEAD
) && !(ship
->flags
& FLG_EXPLOSION
))
978 ship
->flags
|= FLG_EXPLOSION
;
979 ship
->exp_seed
= randint();
980 ship
->exp_delta
= 18;
983 if (ship
->flags
& FLG_EXPLOSION
)
985 draw_explosion (ship
);
989 if (ship
->location
.z
<= 0) /* Only display ships in front of us. */
992 if (ship
->type
== SHIP_PLANET
)
998 if (ship
->type
== SHIP_SUN
)
1004 if ((fabs(ship
->location
.x
) > ship
->location
.z
) || /* Check for field of vision. */
1005 (fabs(ship
->location
.y
) > ship
->location
.z
))
1009 draw_wireframe_ship (ship
);
1011 draw_solid_ship (ship
);