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