Make traders (and particularly Anacondas) less hostile.
[newkind] / threed.c
1 /*
2 * Elite - The New Kind.
3 *
4 * Reverse engineered from the BBC disk version of Elite.
5 * Additional material by C.J.Pinder.
6 *
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.
9 *
10 * email: <christian@newkind.co.uk>
11 *
12 */
13
14 #include <string.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <math.h>
18 #include <ctype.h>
19
20 #include "config.h"
21 #include "elite.h"
22 #include "gfx.h"
23 #include "planet.h"
24 #include "vector.h"
25 #include "shipdata.h"
26 #include "shipface.h"
27 #include "threed.h"
28 #include "space.h"
29 #include "random.h"
30
31 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
32
33
34 #define LAND_X_MAX 128
35 #define LAND_Y_MAX 128
36
37 static unsigned char landscape[LAND_X_MAX+1][LAND_Y_MAX+1];
38
39 static struct point point_list[100];
40
41 static void identify_ship(struct univ_object *univ)
42 {
43 char buf[64];
44 int lasv;
45
46 lasv = ship_list[univ->type]->front_laser;
47 if (!(univ->flags & FLG_TACTICAL)) {
48 #ifdef HACKING
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" : "");
55 #else
56 sprintf(buf, "%s", ship_list[univ->type]->name);
57 #endif
58 } else {
59 #ifdef HACKING
60 unsigned flags = univ->flags;
61 sprintf(buf, "%s (%d) %s%s%s%s", ship_list[univ->type]->name,
62 univ->energy,
63 (flags & FLG_ANGRY) ? "A" : "",
64 (flags & FLG_TARGET) ? "T" : "",
65 (flags & FLG_HOSTILE) ? "H" : "",
66 (flags & FLG_POLICE) ? "P" : "");
67 #else
68 sprintf(buf, "%s (%d)", ship_list[univ->type]->name, univ->energy);
69 #endif
70 }
71 gfx_display_text(point_list[lasv].x + 4, point_list[lasv].y + 4, buf);
72 }
73
74 /*
75 * The following routine is used to draw a wireframe represtation of a ship.
76 *
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.
79 *
80 */
81
82 void draw_wireframe_ship (struct univ_object *univ)
83 {
84 Matrix trans_mat;
85 int i;
86 int sx,sy,ex,ey;
87 double rx,ry,rz;
88 int visible[32];
89 Vector vec;
90 Vector camera_vec;
91 double cos_angle;
92 double tmp;
93 struct ship_face_normal *ship_norm;
94 int num_faces;
95 struct ship_data *ship;
96 int lasv;
97
98 ship = ship_list[univ->type];
99
100 for (i = 0; i < 3; i++)
101 trans_mat[i] = univ->rotmat[i];
102
103 camera_vec = univ->location;
104 mult_vector (&camera_vec, trans_mat);
105 camera_vec = unit_vector (&camera_vec);
106
107 num_faces = ship->num_faces;
108
109 for (i = 0; i < num_faces; i++)
110 {
111 ship_norm = ship->normals;
112
113 vec.x = ship_norm[i].x;
114 vec.y = ship_norm[i].y;
115 vec.z = ship_norm[i].z;
116
117 if ((vec.x == 0) && (vec.y == 0) && (vec.z == 0))
118 visible[i] = 1;
119 else
120 {
121 vec = unit_vector (&vec);
122 cos_angle = vector_dot_product (&vec, &camera_vec);
123 visible[i] = (cos_angle < -0.2);
124 }
125 }
126
127 tmp = trans_mat[0].y;
128 trans_mat[0].y = trans_mat[1].x;
129 trans_mat[1].x = tmp;
130
131 tmp = trans_mat[0].z;
132 trans_mat[0].z = trans_mat[2].x;
133 trans_mat[2].x = tmp;
134
135 tmp = trans_mat[1].z;
136 trans_mat[1].z = trans_mat[2].y;
137 trans_mat[2].y = tmp;
138
139 for (i = 0; i < ship->num_points; i++)
140 {
141 vec.x = ship->points[i].x;
142 vec.y = ship->points[i].y;
143 vec.z = ship->points[i].z;
144
145 mult_vector (&vec, trans_mat);
146
147 rx = vec.x + univ->location.x;
148 ry = vec.y + univ->location.y;
149 rz = vec.z + univ->location.z;
150
151 sx = (rx * 256) / rz;
152 sy = (ry * 256) / rz;
153
154 sy = -sy;
155
156 sx += 128;
157 sy += 96;
158
159 sx *= GFX_SCALE;
160 sy *= GFX_SCALE;
161
162 point_list[i].x = sx;
163 point_list[i].y = sy;
164
165 }
166
167 for (i = 0; i < ship->num_lines; i++)
168 {
169 if (visible[ship->lines[i].face1] ||
170 visible[ship->lines[i].face2])
171 {
172 sx = point_list[ship->lines[i].start_point].x;
173 sy = point_list[ship->lines[i].start_point].y;
174
175 ex = point_list[ship->lines[i].end_point].x;
176 ey = point_list[ship->lines[i].end_point].y;
177
178 gfx_draw_line (sx, sy, ex, ey);
179 }
180 }
181
182
183 if (univ->flags & FLG_FIRING)
184 {
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);
188 }
189
190 if (identify)
191 identify_ship(univ);
192 }
193
194
195
196
197 /*
198 * Hacked version of the draw ship routine to display solid ships...
199 * This needs a lot of tidying...
200 *
201 * Check for hidden surface supplied by T.Harte.
202 */
203
204 void draw_solid_ship (struct univ_object *univ)
205 {
206 int i;
207 int sx,sy;
208 double rx,ry,rz;
209 struct vector vec;
210 struct vector camera_vec;
211 double tmp;
212 struct ship_face *face_data;
213 int num_faces;
214 int num_points;
215 int poly_list[16];
216 int zavg;
217 struct ship_solid *solid_data;
218 struct ship_data *ship;
219 Matrix trans_mat;
220 int lasv;
221 int col;
222
223 solid_data = &ship_solids[univ->type];
224 ship = ship_list[univ->type];
225
226 for (i = 0; i < 3; i++)
227 trans_mat[i] = univ->rotmat[i];
228
229 camera_vec = univ->location;
230 mult_vector (&camera_vec, trans_mat);
231 camera_vec = unit_vector (&camera_vec);
232
233 num_faces = solid_data->num_faces;
234 face_data = solid_data->face_data;
235
236 /*
237 for (i = 0; i < num_faces; i++)
238 {
239 vec.x = face_data[i].norm_x;
240 vec.y = face_data[i].norm_y;
241 vec.z = face_data[i].norm_z;
242
243 vec = unit_vector (&vec);
244 cos_angle = vector_dot_product (&vec, &camera_vec);
245
246 visible[i] = (cos_angle < -0.13);
247 }
248 */
249
250 tmp = trans_mat[0].y;
251 trans_mat[0].y = trans_mat[1].x;
252 trans_mat[1].x = tmp;
253
254 tmp = trans_mat[0].z;
255 trans_mat[0].z = trans_mat[2].x;
256 trans_mat[2].x = tmp;
257
258 tmp = trans_mat[1].z;
259 trans_mat[1].z = trans_mat[2].y;
260 trans_mat[2].y = tmp;
261
262
263 for (i = 0; i < ship->num_points; i++)
264 {
265 vec.x = ship->points[i].x;
266 vec.y = ship->points[i].y;
267 vec.z = ship->points[i].z;
268
269 mult_vector (&vec, trans_mat);
270
271 rx = vec.x + univ->location.x;
272 ry = vec.y + univ->location.y;
273 rz = vec.z + univ->location.z;
274
275 if (rz <= 0)
276 rz = 1;
277
278 sx = (rx * 256) / rz;
279 sy = (ry * 256) / rz;
280
281 sy = -sy;
282
283 sx += 128;
284 sy += 96;
285
286 sx *= GFX_SCALE;
287 sy *= GFX_SCALE;
288
289 point_list[i].x = sx;
290 point_list[i].y = sy;
291 point_list[i].z = rz;
292
293 }
294
295 for (i = 0; i < num_faces; i++)
296 {
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)
301 {
302 num_points = face_data[i].points;
303
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;
307
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);
311
312 if (num_points > 2)
313 {
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);
317 }
318
319 if (num_points > 3)
320 {
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);
324 }
325
326 if (num_points > 4)
327 {
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);
331 }
332
333 if (num_points > 5)
334 {
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);
338 }
339
340 if (num_points > 6)
341 {
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);
345 }
346
347 if (num_points > 7)
348 {
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);
352 }
353
354
355 gfx_render_polygon (face_data[i].points, poly_list, face_data[i].colour, zavg);
356
357 }
358 }
359
360 if (univ->flags & FLG_FIRING)
361 {
362 lasv = ship_list[univ->type]->front_laser;
363 col = (univ->type == SHIP_VIPER) ? GFX_COL_CYAN : GFX_COL_WHITE;
364
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);
368 }
369
370 if (identify)
371 identify_ship(univ);
372 }
373
374
375
376
377
378 /*
379 * Colour map used to generate a SNES Elite style planet.
380 * This is a quick hack and needs tidying up.
381 */
382
383 int snes_planet_colour[] =
384 {
385 102, 102,
386 134, 134, 134, 134,
387 167, 167, 167, 167,
388 213, 213,
389 255,
390 83,83,83,83,
391 122,
392 83,83,
393 249,249,249,249,
394 83,
395 122,
396 249,249,249,249,249,249,
397 83, 83,
398 122,
399 83,83, 83, 83,
400 255,
401 213, 213,
402 167,167, 167, 167,
403 134,134, 134, 134,
404 102, 102
405 };
406
407
408 /*
409 * Generate a landscape map for a SNES Elite style planet.
410 */
411
412 void generate_snes_landscape (void)
413 {
414 int x,y;
415 int colour;
416
417 for (y = 0; y <= LAND_Y_MAX; y++)
418 {
419 colour = snes_planet_colour[y * (sizeof(snes_planet_colour)/sizeof(int)) / LAND_Y_MAX];
420 for (x = 0; x <= LAND_X_MAX; x++)
421 {
422 landscape[x][y] = colour;
423 }
424 }
425 }
426
427
428
429
430 /*
431 * Guassian random number generator.
432 * Returns a number between -7 and +8 with Gaussian distribution.
433 */
434
435 int grand (void)
436 {
437 int i;
438 int r;
439
440 r = 0;
441 for (i = 0; i < 12; i++)
442 r += randint() & 15;
443
444 r /= 12;
445 r -= 7;
446
447 return r;
448 }
449
450
451 /*
452 * Calculate the midpoint between two given points.
453 */
454
455 int calc_midpoint (int sx, int sy, int ex, int ey)
456 {
457 int a,b,n;
458
459 a = landscape[sx][sy];
460 b = landscape[ex][ey];
461
462 n = ((a + b) / 2) + grand();
463 if (n < 0)
464 n = 0;
465 if (n > 255)
466 n = 255;
467
468 return n;
469 }
470
471
472 /*
473 * Calculate a square on the midpoint map.
474 */
475
476 void midpoint_square (int tx, int ty, int w)
477 {
478 int mx,my;
479 int bx,by;
480 int d;
481
482 d = w / 2;
483 mx = tx + d;
484 my = ty + d;
485 bx = tx + w;
486 by = ty + w;
487
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);
493
494 if (d == 1)
495 return;
496
497 midpoint_square (tx,ty,d);
498 midpoint_square (mx,ty,d);
499 midpoint_square (tx,my,d);
500 midpoint_square (mx,my,d);
501 }
502
503
504 /*
505 * Generate a fractal landscape.
506 * Uses midpoint displacement method.
507 */
508
509 void generate_fractal_landscape (int rnd_seed)
510 {
511 int x,y,d,h;
512 double dist;
513 int dark;
514 int old_seed;
515
516 old_seed = get_rand_seed();
517 set_rand_seed(rnd_seed);
518
519 d = LAND_X_MAX / 8;
520
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;
524
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);
528
529 for (y = 0; y <= LAND_Y_MAX; y++)
530 {
531 for (x = 0; x <= LAND_X_MAX; x++)
532 {
533 dist = x*x + y*y;
534 dark = dist > 10000;
535 h = landscape[x][y];
536 if (h > 166)
537 landscape[x][y] = dark ? GFX_COL_GREEN_1 : GFX_COL_GREEN_2;
538 else
539 landscape[x][y] = dark ? GFX_COL_BLUE_2 : GFX_COL_BLUE_1;
540
541 }
542 }
543
544 set_rand_seed (old_seed);
545 }
546
547
548 void generate_landscape (int rnd_seed)
549 {
550 switch (planet_render_style)
551 {
552 case 0: /* Wireframe... do nothing for now... */
553 break;
554
555 case 1:
556 /* generate_green_landscape (); */
557 break;
558
559 case 2:
560 generate_snes_landscape();
561 break;
562
563 case 3:
564 generate_fractal_landscape (rnd_seed);
565 break;
566 }
567 }
568
569
570
571 /*
572 * Draw a line of the planet with appropriate rotation.
573 */
574
575
576 void render_planet_line (int xo, int yo, int x, int y, int radius, int vx, int vy)
577 {
578 int lx, ly;
579 int rx, ry;
580 int colour;
581 int sx,sy;
582 int ex;
583 int div;
584
585 sy = y + yo;
586
587 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
588 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
589 return;
590
591 sx = xo - x;
592 ex = xo + x;
593
594 rx = -x * vx - y * vy;
595 ry = -x * vy + y * vx;
596 rx += radius << 16;
597 ry += radius << 16;
598 div = radius << 10; /* radius * 2 * LAND_X_MAX >> 16 */
599
600
601 for (; sx <= ex; sx++)
602 {
603 if ((sx >= (GFX_VIEW_TX + GFX_X_OFFSET)) && (sx <= (GFX_VIEW_BX + GFX_X_OFFSET)))
604 {
605 lx = rx / div;
606 ly = ry / div;
607 colour = landscape[lx][ly];
608
609 gfx_fast_plot_pixel (sx, sy, colour);
610 }
611 rx += vx;
612 ry += vy;
613 }
614 }
615
616
617 /*
618 * Draw a solid planet. Based on Doros circle drawing alogorithm.
619 */
620
621 void render_planet (int xo, int yo, int radius, struct vector *vec)
622 {
623 int x,y;
624 int s;
625 int vx,vy;
626
627 xo += GFX_X_OFFSET;
628 yo += GFX_Y_OFFSET;
629
630 vx = vec[1].x * 65536;
631 vy = vec[1].y * 65536;
632
633 s = radius;
634 x = radius;
635 y = 0;
636
637 s -= x + x;
638 while (y <= x)
639 {
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);
644
645 s += y + y + 1;
646 y++;
647 if (s >= 0)
648 {
649 s -= x + x + 2;
650 x--;
651 }
652 }
653 }
654
655
656 /*
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.
660 */
661
662 void draw_wireframe_planet (int xo, int yo, int radius, struct vector *vec)
663 {
664 gfx_draw_circle (xo, yo, radius, GFX_COL_WHITE);
665 }
666
667
668 /*
669 * Draw a planet.
670 * We can currently do three different types of planet...
671 * - Wireframe.
672 * - Fractal landscape.
673 * - SNES Elite style.
674 */
675
676 void draw_planet (struct univ_object *planet)
677 {
678 int x,y;
679 int radius;
680
681 x = (planet->location.x * 256) / planet->location.z;
682 y = (planet->location.y * 256) / planet->location.z;
683
684 y = -y;
685
686 x += 128;
687 y += 96;
688
689 x *= GFX_SCALE;
690 y *= GFX_SCALE;
691
692 radius = 6291456 / planet->distance;
693 // radius = 6291456 / ship_vec.z; /* Planets are BIG! */
694
695 radius *= GFX_SCALE;
696
697 if ((x + radius < 0) ||
698 (x - radius > 511) ||
699 (y + radius < 0) ||
700 (y - radius > 383))
701 return;
702
703 switch (planet_render_style)
704 {
705 case 0:
706 draw_wireframe_planet (x, y, radius, planet->rotmat);
707 break;
708
709 case 1:
710 gfx_draw_filled_circle (x, y, radius, GFX_COL_GREEN_1);
711 break;
712
713 case 2:
714 case 3:
715 render_planet (x, y, radius, planet->rotmat);
716 break;
717 }
718 }
719
720
721 void render_sun_line (int xo, int yo, int x, int y, int radius)
722 {
723 int sy = yo + y;
724 int sx,ex;
725 int colour;
726 int dx,dy;
727 int distance;
728 int inner,outer;
729 int inner2;
730 int mix;
731
732 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
733 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
734 return;
735
736 sx = xo - x;
737 ex = xo + x;
738
739 sx -= (radius * (2 + (randint() & 7))) >> 8;
740 ex += (radius * (2 + (randint() & 7))) >> 8;
741
742 if ((sx > GFX_VIEW_BX + GFX_X_OFFSET) ||
743 (ex < GFX_VIEW_TX + GFX_X_OFFSET))
744 return;
745
746 if (sx < GFX_VIEW_TX + GFX_X_OFFSET)
747 sx = GFX_VIEW_TX + GFX_X_OFFSET;
748
749 if (ex > GFX_VIEW_BX + GFX_X_OFFSET)
750 ex = GFX_VIEW_BX + GFX_X_OFFSET;
751
752 inner = (radius * (200 + (randint() & 7))) >> 8;
753 inner *= inner;
754
755 inner2 = (radius * (220 + (randint() & 7))) >> 8;
756 inner2 *= inner2;
757
758 outer = (radius * (239 + (randint() & 7))) >> 8;
759 outer *= outer;
760
761 dy = y * y;
762 dx = sx - xo;
763
764 for (; sx <= ex; sx++,dx++)
765 {
766 mix = (sx ^ y) & 1;
767 distance = dx * dx + dy;
768
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;
775 else
776 colour = mix ? GFX_ORANGE_1 : GFX_ORANGE_2;
777
778 gfx_fast_plot_pixel (sx, sy, colour);
779 }
780 }
781
782
783 void render_sun (int xo, int yo, int radius)
784 {
785 int x,y;
786 int s;
787
788 xo += GFX_X_OFFSET;
789 yo += GFX_Y_OFFSET;
790
791 s = -radius;
792 x = radius;
793 y = 0;
794
795 // s -= x + x;
796 while (y <= x)
797 {
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);
802
803 s += y + y + 1;
804 y++;
805 if (s >= 0)
806 {
807 s -= x + x + 2;
808 x--;
809 }
810 }
811 }
812
813
814
815 void draw_sun (struct univ_object *planet)
816 {
817 int x,y;
818 int radius;
819
820 x = (planet->location.x * 256) / planet->location.z;
821 y = (planet->location.y * 256) / planet->location.z;
822
823 y = -y;
824
825 x += 128;
826 y += 96;
827
828 x *= GFX_SCALE;
829 y *= GFX_SCALE;
830
831 radius = 6291456 / planet->distance;
832
833 radius *= GFX_SCALE;
834
835 if ((x + radius < 0) ||
836 (x - radius > 511) ||
837 (y + radius < 0) ||
838 (y - radius > 383))
839 return;
840
841 render_sun (x, y, radius);
842 }
843
844
845
846 void draw_explosion (struct univ_object *univ)
847 {
848 int i;
849 int z;
850 int q;
851 int pr;
852 int px,py;
853 int cnt;
854 int sizex,sizey,psx,psy;
855 Matrix trans_mat;
856 int sx,sy;
857 double rx,ry,rz;
858 int visible[32];
859 struct vector vec;
860 struct vector camera_vec;
861 double cos_angle;
862 double tmp;
863 struct ship_face_normal *ship_norm;
864 struct ship_point *sp;
865 struct ship_data *ship;
866 int np;
867 int old_seed;
868
869
870 if (univ->exp_delta > 251)
871 {
872 univ->flags |= FLG_REMOVE;
873 return;
874 }
875
876 univ->exp_delta += 4;
877
878 if (univ->location.z <= 0)
879 return;
880
881 ship = ship_list[univ->type];
882
883 for (i = 0; i < 3; i++)
884 trans_mat[i] = univ->rotmat[i];
885
886 camera_vec = univ->location;
887 mult_vector (&camera_vec, trans_mat);
888 camera_vec = unit_vector (&camera_vec);
889
890 ship_norm = ship->normals;
891
892 for (i = 0; i < ship->num_faces; i++)
893 {
894 vec.x = ship_norm[i].x;
895 vec.y = ship_norm[i].y;
896 vec.z = ship_norm[i].z;
897
898 vec = unit_vector (&vec);
899 cos_angle = vector_dot_product (&vec, &camera_vec);
900
901 visible[i] = (cos_angle < -0.13);
902 }
903
904 tmp = trans_mat[0].y;
905 trans_mat[0].y = trans_mat[1].x;
906 trans_mat[1].x = tmp;
907
908 tmp = trans_mat[0].z;
909 trans_mat[0].z = trans_mat[2].x;
910 trans_mat[2].x = tmp;
911
912 tmp = trans_mat[1].z;
913 trans_mat[1].z = trans_mat[2].y;
914 trans_mat[2].y = tmp;
915
916 sp = ship->points;
917 np = 0;
918
919 for (i = 0; i < ship->num_points; i++)
920 {
921 if (visible[sp[i].face1] || visible[sp[i].face2] ||
922 visible[sp[i].face3] || visible[sp[i].face4])
923 {
924 vec.x = sp[i].x;
925 vec.y = sp[i].y;
926 vec.z = sp[i].z;
927
928 mult_vector (&vec, trans_mat);
929
930 rx = vec.x + univ->location.x;
931 ry = vec.y + univ->location.y;
932 rz = vec.z + univ->location.z;
933
934 sx = (rx * 256) / rz;
935 sy = (ry * 256) / rz;
936
937 sy = -sy;
938
939 sx += 128;
940 sy += 96;
941
942 sx *= GFX_SCALE;
943 sy *= GFX_SCALE;
944
945 point_list[np].x = sx;
946 point_list[np].y = sy;
947 np++;
948 }
949 }
950
951
952 z = (int)univ->location.z;
953
954 if (z >= 0x2000)
955 q = 254;
956 else
957 q = (z / 32) | 1;
958
959 pr = (univ->exp_delta * 256) / q;
960
961 // if (pr > 0x1C00)
962 // q = 254;
963 // else
964
965 q = pr / 32;
966
967 old_seed = get_rand_seed();
968 set_rand_seed (univ->exp_seed);
969
970 for (cnt = 0; cnt < np; cnt++)
971 {
972 sx = point_list[cnt].x;
973 sy = point_list[cnt].y;
974
975 for (i = 0; i < 16; i++)
976 {
977 px = rand255() - 128;
978 py = rand255() - 128;
979
980 px = (px * q) / 256;
981 py = (py * q) / 256;
982
983 px = px + px + sx;
984 py = py + py + sy;
985
986 sizex = (randint() & 1) + 1;
987 sizey = (randint() & 1) + 1;
988
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);
992 }
993 }
994
995 set_rand_seed (old_seed);
996 }
997
998
999
1000 /*
1001 * Draws an object in the universe.
1002 * (Ship, Planet, Sun etc).
1003 */
1004
1005 void draw_ship (struct univ_object *ship)
1006 {
1007
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))
1012 return;
1013
1014 if ((ship->flags & FLG_DEAD) && !(ship->flags & FLG_EXPLOSION))
1015 {
1016 ship->flags |= FLG_EXPLOSION;
1017 ship->exp_seed = randint();
1018 ship->exp_delta = 18;
1019 }
1020
1021 if (ship->flags & FLG_EXPLOSION)
1022 {
1023 draw_explosion (ship);
1024 return;
1025 }
1026
1027 if (ship->location.z <= 0) /* Only display ships in front of us. */
1028 return;
1029
1030 if (ship->type == SHIP_PLANET)
1031 {
1032 draw_planet (ship);
1033 return;
1034 }
1035
1036 if (ship->type == SHIP_SUN)
1037 {
1038 draw_sun (ship);
1039 return;
1040 }
1041
1042 if ((fabs(ship->location.x) > ship->location.z) || /* Check for field of vision. */
1043 (fabs(ship->location.y) > ship->location.z))
1044 return;
1045
1046 if (wireframe)
1047 draw_wireframe_ship (ship);
1048 else
1049 draw_solid_ship (ship);
1050 }
1051