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
);
379 * Colour map used to generate a SNES Elite style planet.
380 * This is a quick hack and needs tidying up.
383 int snes_planet_colour
[] =
396 249,249,249,249,249,249,
409 * Generate a landscape map for a SNES Elite style planet.
412 void generate_snes_landscape (void)
417 for (y
= 0; y
<= LAND_Y_MAX
; y
++)
419 colour
= snes_planet_colour
[y
* (sizeof(snes_planet_colour
)/sizeof(int)) / LAND_Y_MAX
];
420 for (x
= 0; x
<= LAND_X_MAX
; x
++)
422 landscape
[x
][y
] = colour
;
431 * Guassian random number generator.
432 * Returns a number between -7 and +8 with Gaussian distribution.
441 for (i
= 0; i
< 12; i
++)
452 * Calculate the midpoint between two given points.
455 int calc_midpoint (int sx
, int sy
, int ex
, int ey
)
459 a
= landscape
[sx
][sy
];
460 b
= landscape
[ex
][ey
];
462 n
= ((a
+ b
) / 2) + grand();
473 * Calculate a square on the midpoint map.
476 void midpoint_square (int tx
, int ty
, int w
)
488 landscape
[mx
][ty
] = calc_midpoint(tx
,ty
,bx
,ty
);
489 landscape
[mx
][by
] = calc_midpoint(tx
,by
,bx
,by
);
490 landscape
[tx
][my
] = calc_midpoint(tx
,ty
,tx
,by
);
491 landscape
[bx
][my
] = calc_midpoint(bx
,ty
,bx
,by
);
492 landscape
[mx
][my
] = calc_midpoint(tx
,my
,bx
,my
);
497 midpoint_square (tx
,ty
,d
);
498 midpoint_square (mx
,ty
,d
);
499 midpoint_square (tx
,my
,d
);
500 midpoint_square (mx
,my
,d
);
505 * Generate a fractal landscape.
506 * Uses midpoint displacement method.
509 void generate_fractal_landscape (int rnd_seed
)
516 old_seed
= get_rand_seed();
517 set_rand_seed(rnd_seed
);
521 for (y
= 0; y
<= LAND_Y_MAX
; y
+= d
)
522 for (x
= 0; x
<= LAND_X_MAX
; x
+= d
)
523 landscape
[x
][y
] = randint() & 255;
525 for (y
= 0; y
< LAND_Y_MAX
; y
+= d
)
526 for (x
= 0; x
< LAND_X_MAX
; x
+= d
)
527 midpoint_square (x
,y
,d
);
529 for (y
= 0; y
<= LAND_Y_MAX
; y
++)
531 for (x
= 0; x
<= LAND_X_MAX
; x
++)
537 landscape
[x
][y
] = dark ? GFX_COL_GREEN_1
: GFX_COL_GREEN_2
;
539 landscape
[x
][y
] = dark ? GFX_COL_BLUE_2
: GFX_COL_BLUE_1
;
544 set_rand_seed (old_seed
);
548 void generate_landscape (int rnd_seed
)
550 switch (planet_render_style
)
552 case 0: /* Wireframe... do nothing for now... */
556 /* generate_green_landscape (); */
560 generate_snes_landscape();
564 generate_fractal_landscape (rnd_seed
);
572 * Draw a line of the planet with appropriate rotation.
576 void render_planet_line (int xo
, int yo
, int x
, int y
, int radius
, int vx
, int vy
)
587 if ((sy
< GFX_VIEW_TY
+ GFX_Y_OFFSET
) ||
588 (sy
> GFX_VIEW_BY
+ GFX_Y_OFFSET
))
594 rx
= -x
* vx
- y
* vy
;
595 ry
= -x
* vy
+ y
* vx
;
598 div
= radius
<< 10; /* radius * 2 * LAND_X_MAX >> 16 */
601 for (; sx
<= ex
; sx
++)
603 if ((sx
>= (GFX_VIEW_TX
+ GFX_X_OFFSET
)) && (sx
<= (GFX_VIEW_BX
+ GFX_X_OFFSET
)))
607 colour
= landscape
[lx
][ly
];
609 gfx_fast_plot_pixel (sx
, sy
, colour
);
618 * Draw a solid planet. Based on Doros circle drawing alogorithm.
621 void render_planet (int xo
, int yo
, int radius
, struct vector
*vec
)
630 vx
= vec
[1].x
* 65536;
631 vy
= vec
[1].y
* 65536;
640 render_planet_line (xo
, yo
, x
, y
, radius
, vx
, vy
);
641 render_planet_line (xo
, yo
, x
,-y
, radius
, vx
, vy
);
642 render_planet_line (xo
, yo
, y
, x
, radius
, vx
, vy
);
643 render_planet_line (xo
, yo
, y
,-x
, radius
, vx
, vy
);
657 * Draw a wireframe planet.
658 * At the moment we just draw a circle.
659 * Need to add in the two arcs that the original Elite had.
662 void draw_wireframe_planet (int xo
, int yo
, int radius
, struct vector
*vec
)
664 gfx_draw_circle (xo
, yo
, radius
, GFX_COL_WHITE
);
670 * We can currently do three different types of planet...
672 * - Fractal landscape.
673 * - SNES Elite style.
676 void draw_planet (struct univ_object
*planet
)
681 x
= (planet
->location
.x
* 256) / planet
->location
.z
;
682 y
= (planet
->location
.y
* 256) / planet
->location
.z
;
692 radius
= 6291456 / planet
->distance
;
693 // radius = 6291456 / ship_vec.z; /* Planets are BIG! */
697 if ((x
+ radius
< 0) ||
698 (x
- radius
> 511) ||
703 switch (planet_render_style
)
706 draw_wireframe_planet (x
, y
, radius
, planet
->rotmat
);
710 gfx_draw_filled_circle (x
, y
, radius
, GFX_COL_GREEN_1
);
715 render_planet (x
, y
, radius
, planet
->rotmat
);
721 void render_sun_line (int xo
, int yo
, int x
, int y
, int radius
)
732 if ((sy
< GFX_VIEW_TY
+ GFX_Y_OFFSET
) ||
733 (sy
> GFX_VIEW_BY
+ GFX_Y_OFFSET
))
739 sx
-= (radius
* (2 + (randint() & 7))) >> 8;
740 ex
+= (radius
* (2 + (randint() & 7))) >> 8;
742 if ((sx
> GFX_VIEW_BX
+ GFX_X_OFFSET
) ||
743 (ex
< GFX_VIEW_TX
+ GFX_X_OFFSET
))
746 if (sx
< GFX_VIEW_TX
+ GFX_X_OFFSET
)
747 sx
= GFX_VIEW_TX
+ GFX_X_OFFSET
;
749 if (ex
> GFX_VIEW_BX
+ GFX_X_OFFSET
)
750 ex
= GFX_VIEW_BX
+ GFX_X_OFFSET
;
752 inner
= (radius
* (200 + (randint() & 7))) >> 8;
755 inner2
= (radius
* (220 + (randint() & 7))) >> 8;
758 outer
= (radius
* (239 + (randint() & 7))) >> 8;
764 for (; sx
<= ex
; sx
++,dx
++)
767 distance
= dx
* dx
+ dy
;
769 if (distance
< inner
)
770 colour
= GFX_COL_WHITE
;
771 else if (distance
< inner2
)
772 colour
= GFX_COL_YELLOW_4
;
773 else if (distance
< outer
)
774 colour
= GFX_ORANGE_3
;
776 colour
= mix ? GFX_ORANGE_1
: GFX_ORANGE_2
;
778 gfx_fast_plot_pixel (sx
, sy
, colour
);
783 void render_sun (int xo
, int yo
, int radius
)
798 render_sun_line (xo
, yo
, x
, y
, radius
);
799 render_sun_line (xo
, yo
, x
,-y
, radius
);
800 render_sun_line (xo
, yo
, y
, x
, radius
);
801 render_sun_line (xo
, yo
, y
,-x
, radius
);
815 void draw_sun (struct univ_object
*planet
)
820 x
= (planet
->location
.x
* 256) / planet
->location
.z
;
821 y
= (planet
->location
.y
* 256) / planet
->location
.z
;
831 radius
= 6291456 / planet
->distance
;
835 if ((x
+ radius
< 0) ||
836 (x
- radius
> 511) ||
841 render_sun (x
, y
, radius
);
846 void draw_explosion (struct univ_object
*univ
)
854 int sizex
,sizey
,psx
,psy
;
860 struct vector camera_vec
;
863 struct ship_face_normal
*ship_norm
;
864 struct ship_point
*sp
;
865 struct ship_data
*ship
;
870 if (univ
->exp_delta
> 251)
872 univ
->flags
|= FLG_REMOVE
;
876 univ
->exp_delta
+= 4;
878 if (univ
->location
.z
<= 0)
881 ship
= ship_list
[univ
->type
];
883 for (i
= 0; i
< 3; i
++)
884 trans_mat
[i
] = univ
->rotmat
[i
];
886 camera_vec
= univ
->location
;
887 mult_vector (&camera_vec
, trans_mat
);
888 camera_vec
= unit_vector (&camera_vec
);
890 ship_norm
= ship
->normals
;
892 for (i
= 0; i
< ship
->num_faces
; i
++)
894 vec
.x
= ship_norm
[i
].x
;
895 vec
.y
= ship_norm
[i
].y
;
896 vec
.z
= ship_norm
[i
].z
;
898 vec
= unit_vector (&vec
);
899 cos_angle
= vector_dot_product (&vec
, &camera_vec
);
901 visible
[i
] = (cos_angle
< -0.13);
904 tmp
= trans_mat
[0].y
;
905 trans_mat
[0].y
= trans_mat
[1].x
;
906 trans_mat
[1].x
= tmp
;
908 tmp
= trans_mat
[0].z
;
909 trans_mat
[0].z
= trans_mat
[2].x
;
910 trans_mat
[2].x
= tmp
;
912 tmp
= trans_mat
[1].z
;
913 trans_mat
[1].z
= trans_mat
[2].y
;
914 trans_mat
[2].y
= tmp
;
919 for (i
= 0; i
< ship
->num_points
; i
++)
921 if (visible
[sp
[i
].face1
] || visible
[sp
[i
].face2
] ||
922 visible
[sp
[i
].face3
] || visible
[sp
[i
].face4
])
928 mult_vector (&vec
, trans_mat
);
930 rx
= vec
.x
+ univ
->location
.x
;
931 ry
= vec
.y
+ univ
->location
.y
;
932 rz
= vec
.z
+ univ
->location
.z
;
934 sx
= (rx
* 256) / rz
;
935 sy
= (ry
* 256) / rz
;
945 point_list
[np
].x
= sx
;
946 point_list
[np
].y
= sy
;
952 z
= (int)univ
->location
.z
;
959 pr
= (univ
->exp_delta
* 256) / q
;
967 old_seed
= get_rand_seed();
968 set_rand_seed (univ
->exp_seed
);
970 for (cnt
= 0; cnt
< np
; cnt
++)
972 sx
= point_list
[cnt
].x
;
973 sy
= point_list
[cnt
].y
;
975 for (i
= 0; i
< 16; i
++)
977 px
= rand255() - 128;
978 py
= rand255() - 128;
986 sizex
= (randint() & 1) + 1;
987 sizey
= (randint() & 1) + 1;
989 for (psy
= 0; psy
< sizey
; psy
++)
990 for (psx
= 0; psx
< sizex
; psx
++)
991 gfx_plot_pixel (px
+psx
, py
+psy
, GFX_COL_WHITE
);
995 set_rand_seed (old_seed
);
1001 * Draws an object in the universe.
1002 * (Ship, Planet, Sun etc).
1005 void draw_ship (struct univ_object
*ship
)
1008 if ((current_screen
!= SCR_FRONT_VIEW
) && (current_screen
!= SCR_REAR_VIEW
) &&
1009 (current_screen
!= SCR_LEFT_VIEW
) && (current_screen
!= SCR_RIGHT_VIEW
) &&
1010 (current_screen
!= SCR_INTRO_ONE
) && (current_screen
!= SCR_INTRO_TWO
) &&
1011 (current_screen
!= SCR_GAME_OVER
) && (current_screen
!= SCR_ESCAPE_POD
))
1014 if ((ship
->flags
& FLG_DEAD
) && !(ship
->flags
& FLG_EXPLOSION
))
1016 ship
->flags
|= FLG_EXPLOSION
;
1017 ship
->exp_seed
= randint();
1018 ship
->exp_delta
= 18;
1021 if (ship
->flags
& FLG_EXPLOSION
)
1023 draw_explosion (ship
);
1027 if (ship
->location
.z
<= 0) /* Only display ships in front of us. */
1030 if (ship
->type
== SHIP_PLANET
)
1036 if (ship
->type
== SHIP_SUN
)
1042 if ((fabs(ship
->location
.x
) > ship
->location
.z
) || /* Check for field of vision. */
1043 (fabs(ship
->location
.y
) > ship
->location
.z
))
1047 draw_wireframe_ship (ship
);
1049 draw_solid_ship (ship
);