8
|
1 /*--------------------------------------------------------------------------
|
|
2 NETREK II -- Paradise
|
|
3
|
|
4 Permission to use, copy, modify, and distribute this software and its
|
|
5 documentation for any NON-COMMERCIAL purpose (following the terms of
|
|
6 the GNU General Public License (read the file 'COPYING')) and without
|
|
7 fee is hereby granted, provided that this copyright notice appear in all
|
|
8 copies. No representations are made about the suitability of this
|
|
9 software for any purpose. This software is provided "as is" without
|
|
10 express or implied warranty.
|
|
11
|
|
12 Xtrek Copyright 1986 Chris Guthrie
|
|
13 Netrek (Xtrek II) Copyright 1989 Kevin P. Smith
|
|
14 Scott Silvey
|
|
15 Paradise II (Netrek II) Copyright 1993 Larry Denys
|
|
16 Kurt Olsen
|
|
17 Brandon Gillespie
|
|
18
|
|
19 Comprehensive credits are available in the file "CREDITS"
|
|
20 --------------------------------------------------------------------------*/
|
|
21
|
|
22 #include "config.h"
|
|
23 #include <stdio.h>
|
|
24 #include <stdlib.h>
|
|
25 #include <math.h>
|
|
26 #include "struct.h"
|
|
27 #include "data.h"
|
|
28 #include "shmem.h"
|
|
29 #include "terrain.h"
|
|
30
|
|
31 #define MAXALTITUDE 255
|
|
32 #define MAXSTARS 20
|
|
33 #define X 0
|
|
34 #define Y 1
|
|
35
|
|
36 void
|
|
37 generate_terrain()
|
|
38 /*
|
|
39 * Generates terrain based on specs in the system configuration. Places a
|
|
40 * number of "seeds" into the terrain grid, and then generates an "altitude"
|
|
41 * map based on those seeds' positions (which correspond to star positions).
|
|
42 * Place_nebula generates another altitude map for nebulae -- the first map
|
|
43 * is used for asteroids and generating the second map.
|
|
44 *
|
|
45 * This function is called within the galaxy generation stuff.
|
|
46 *
|
|
47 * 10/26/94 MM
|
|
48 */
|
|
49 {
|
|
50 int i, j, k; /* counters */
|
|
51 int x, y; /* more counters, different purpose */
|
|
52 double dist, val; /* for distance calculations */
|
|
53 int num_seeds = 0;
|
|
54 int seed_xy[MAXSTARS][2];
|
|
55 int qx[4] = {-1, 1, -1, 1}, qy[4] = {1, 1, -1, -1}; /* quadrant multipliers */
|
|
56
|
|
57 /*
|
|
58 * place seeds -- this would be easy to change if you just had a number of
|
|
59 * seeds you wanted to place, instead of basing it on stars. I won't
|
|
60 * bother doing it, even though it might be cool to see it work in a bronco
|
|
61 * game... MM
|
|
62 */
|
|
63
|
|
64 for (i = 0; i < NUMPLANETS; i++)
|
|
65 if (PL_TYPE(planets[i]) == PLSTAR)
|
|
66 {
|
|
67 terrain_grid[(planets[i].pl_x / TGRID_GRANULARITY) * TGRID_SIZE +
|
|
68 planets[i].pl_y / TGRID_GRANULARITY].alt1 = MAXALTITUDE;
|
|
69
|
|
70 seed_xy[num_seeds][X] = planets[i].pl_x / TGRID_GRANULARITY;
|
|
71 seed_xy[num_seeds][Y] = planets[i].pl_y / TGRID_GRANULARITY;
|
|
72 num_seeds++;
|
|
73 }
|
|
74
|
|
75 /* generate terrain -- simple, stupid version. */
|
|
76
|
|
77
|
|
78 for (x = 0; x < TGRID_SIZE; x++)
|
|
79 for (y = 0; y < TGRID_SIZE; y++)
|
|
80 if (terrain_grid[x * TGRID_SIZE + y].alt1 != MAXALTITUDE)
|
|
81 {
|
|
82 val = 0.0;
|
|
83 for (i = 0; i < num_seeds; i++)
|
|
84 {
|
|
85 dist = (double) MAXALTITUDE -
|
|
86 sqrt((double) ((x - seed_xy[i][X]) * (x - seed_xy[i][X]) +
|
|
87 (y - seed_xy[i][Y]) * (y - seed_xy[i][Y])));
|
|
88 if (dist > val)
|
|
89 val = dist;
|
|
90 }
|
|
91 /* reset any previous terrain values */
|
|
92 terrain_grid[x * TGRID_SIZE + y].types = 0x00;
|
|
93
|
|
94 terrain_grid[x * TGRID_SIZE + y].alt1 = (int) val;
|
|
95 terrain_grid[x * TGRID_SIZE + y].alt2 = 0;
|
|
96 }
|
|
97
|
|
98 /* place nebula */
|
|
99 if (num_nebula)
|
|
100 place_nebula(*num_nebula, *nebula_subclouds, *nebula_density);
|
|
101 /* place asteroids */
|
|
102 if (num_asteroid)
|
|
103 place_asteroids(MAXALTITUDE - (*asteroid_radius));
|
|
104 }
|
|
105
|
|
106 void
|
|
107 place_nebula(int num_nebula, int num_seeds, int minalt)
|
|
108 /*
|
|
109 * Values inbetween MAXALTITUDE and minalt are considered nebulous terrain.
|
|
110 * Tries to cluster seeds in groups based on num_nebula and num_seeds. ...the
|
|
111 * number of seeds per nebula being num_seeds. 10/26/94 MM
|
|
112 */
|
|
113 {
|
|
114 int i = 0, j = 0, x, y, dx, dy, dist, lowdist = 2 * TGRID_SIZE;
|
|
115 int *seeds1, *seeds2;
|
|
116
|
|
117 seeds1 = (int *) malloc(num_nebula * sizeof(int));
|
|
118 if (num_seeds)
|
|
119 seeds2 = (int *) malloc(num_seeds * sizeof(int) * num_nebula);
|
|
120
|
|
121 /* find a local minimum, and place a "seed" */
|
|
122 while (i < num_nebula)
|
|
123 {
|
|
124 j = (int) lrand48() % (TGRID_SIZE * TGRID_SIZE);
|
|
125 if (j == 0)
|
|
126 j = 1;
|
|
127 while ((j < (TGRID_SIZE * TGRID_SIZE)) &&
|
|
128 ((terrain_grid[j - 1].alt1 < terrain_grid[j].alt1) ||
|
|
129 (terrain_grid[j + 1].alt1 < terrain_grid[j].alt1)))
|
|
130 j++;
|
|
131 seeds1[i] = j;
|
|
132 terrain_grid[seeds1[i]].alt2 = MAXALTITUDE;
|
|
133 i++;
|
|
134 }
|
|
135 /* group num_seeds more "sub seeds" around each seed */
|
|
136 /*
|
|
137 * (there are a couple bugs in this algorithm yet -- theres a wierd
|
|
138 * wraparound occasionally. MDM, 8/23/95)
|
|
139 */
|
|
140
|
|
141 for (i = 0; i < num_nebula; i++)
|
|
142 for (j = 0; j < num_seeds; j++)
|
|
143 {
|
|
144 dx = (int) (lrand48() % ((MAXALTITUDE - minalt) * 3)) -
|
|
145 (int) (lrand48() % (int) ((MAXALTITUDE - minalt) * (1.5)));
|
|
146 dy = (int) (lrand48() % ((MAXALTITUDE - minalt) * 3)) -
|
|
147 (int) (lrand48() % (int) ((MAXALTITUDE - minalt) * (1.5)));
|
|
148 if (seeds1[i] / TGRID_SIZE + dx < 0)
|
|
149 dx -= (seeds1[i] / TGRID_SIZE + dx);
|
|
150 if (seeds1[i] / TGRID_SIZE + dx >= TGRID_SIZE)
|
|
151 dx -= (seeds1[i] / TGRID_SIZE + dx) - (TGRID_SIZE - 1);
|
|
152 if (seeds1[i] / TGRID_SIZE + dy < 0)
|
|
153 dy -= (seeds1[i] / TGRID_SIZE + dy);
|
|
154 if (seeds1[i] / TGRID_SIZE + dy >= TGRID_SIZE)
|
|
155 dy -= (seeds1[i] / TGRID_SIZE + dy) - (TGRID_SIZE - 1);
|
|
156 seeds2[i * num_seeds + j] = (seeds1[i] / TGRID_SIZE + dx) * TGRID_SIZE +
|
|
157 (seeds1[i] % TGRID_SIZE + dy);
|
|
158 terrain_grid[seeds2[i * num_seeds + j]].alt2 = MAXALTITUDE;
|
|
159 }
|
|
160
|
|
161 /*
|
|
162 * assign random-ish values, from a distance-from-seed base value (density
|
|
163 * is the randomness -- low density values are smooth, high are rough)
|
|
164 */
|
|
165 /* randomness NYI */
|
|
166 /*
|
|
167 * these values could be used in combination with the alt1 values to do
|
|
168 * other funky terrain "shapes, but I'm putting in the ABS() speedup stuff
|
|
169 * in for now anyway. It'll result in alt2 values of 0 for any spot
|
|
170 * outside a nebulous radius -- MDM
|
|
171 */
|
|
172 for (x = 0; x < TGRID_SIZE; x++)
|
|
173 for (y = 0; y < TGRID_SIZE; y++)
|
|
174 {
|
|
175 for (i = 0; i < num_nebula; i++)
|
|
176 {
|
|
177 dx = (seeds1[i] / TGRID_SIZE) - x;
|
|
178 dy = (seeds1[i] % TGRID_SIZE) - y;
|
|
179 /* loop speedup */
|
|
180 if ((ABS(dx) <= MAXALTITUDE - minalt) &&
|
|
181 (ABS(dy) <= MAXALTITUDE - minalt))
|
|
182 {
|
|
183 dist = (int) sqrt(dx * dx + dy * dy);
|
|
184 if (dist < lowdist)
|
|
185 lowdist = dist;
|
|
186 }
|
|
187 if (num_seeds)
|
|
188 for (j = 0; j < num_seeds; j++)
|
|
189 {
|
|
190 dx = seeds2[i * num_seeds + j] / TGRID_SIZE - x;
|
|
191 dy = seeds2[i * num_seeds + j] % TGRID_SIZE - y;
|
|
192 /* loop speedup */
|
|
193 if ((ABS(dx) <= MAXALTITUDE - minalt) &&
|
|
194 (ABS(dy) <= MAXALTITUDE - minalt))
|
|
195 {
|
|
196 dist = (int) sqrt(dx * dx + dy * dy);
|
|
197 if (dist < lowdist)
|
|
198 lowdist = dist;
|
|
199 }
|
|
200 }
|
|
201 }
|
|
202 terrain_grid[x * TGRID_SIZE + y].alt2 = MAXALTITUDE - lowdist;
|
|
203 lowdist = 2 * TGRID_SIZE;
|
|
204 }
|
|
205
|
|
206 /* give each spot with a high enuf alt value the nebulous terrain flag. */
|
|
207 for (i = 0; i < TGRID_SIZE; i++)
|
|
208 for (j = 0; j < TGRID_SIZE; j++)
|
|
209 if (terrain_grid[i * TGRID_SIZE + j].alt2 >= minalt)
|
|
210 terrain_grid[i * TGRID_SIZE + j].types |= T_NEBULA;
|
|
211
|
|
212 free(seeds1);
|
|
213 free(seeds2);
|
|
214 }
|
|
215
|
|
216 void
|
|
217 place_asteroids(int altitude)
|
|
218 /*
|
|
219 * Marks terrain grid locations within density of altitude as asteroid
|
|
220 * fields. I may make the chance of such a grid location becoming a field
|
|
221 * random (like 90% or something), so that fields will appear less uniform,
|
|
222 * and holes may exist in them. Makes for interesting terrain, IMO. 10/26/94
|
|
223 * MM
|
|
224 */
|
|
225 {
|
|
226 int x, y, i, j, numstars = 0, attempts = 0;
|
|
227 int *systems_with_asteroids;
|
|
228 int *star_numbers;
|
|
229 int *varied_rad;
|
|
230 int *varied_dens;
|
|
231 float *varied_thick;
|
|
232
|
|
233 printf("placing asteroids\n");
|
|
234 star_numbers = (int *) malloc((NUMPLANETS) * sizeof(int));
|
|
235 for (i = 0; i < NUMPLANETS; i++)
|
|
236 if (PL_TYPE(planets[i]) == PLSTAR)
|
|
237 {
|
|
238 star_numbers[numstars] = i;
|
|
239 numstars++;
|
|
240 }
|
|
241 systems_with_asteroids = (int *) malloc(numstars * sizeof(int));
|
|
242 varied_rad = (int *) malloc(numstars * sizeof(int));
|
|
243 varied_dens = (int *) malloc(numstars * sizeof(int));
|
|
244 varied_thick = (float *) malloc(numstars * sizeof(float));
|
|
245 for (i = 0; i < numstars; i++)
|
|
246 systems_with_asteroids[i] = 0;
|
|
247
|
|
248 /*
|
|
249 * assign what stars have asteroid belts -- I could just start with system
|
|
250 * #1, since systems are placed randomly, but I might as well pick a random
|
|
251 * system to start with. The only prereq is that the system does NOT
|
|
252 * belong to a race. (prereq NYI)
|
|
253 */
|
|
254 if (*num_asteroid > (numstars - 4))
|
|
255 *num_asteroid = numstars - 4;
|
|
256
|
|
257 i = 0;
|
|
258 while (i < *num_asteroid)
|
|
259 {
|
|
260 j = lrand48() % numstars;
|
|
261
|
|
262 if (((planets[j].pl_system < 1) || (planets[j].pl_system > 4))
|
|
263 && (systems_with_asteroids[j] == 0))
|
|
264 systems_with_asteroids[j] = 1;
|
|
265 else
|
|
266 continue;
|
|
267
|
|
268 i++;
|
|
269
|
|
270 if ((*asteroid_rad_variance) == 0)
|
|
271 varied_rad[j] = altitude;
|
|
272 else
|
|
273 varied_rad[j] = altitude - ((*asteroid_rad_variance) / 2) +
|
|
274 lrand48() % (*asteroid_rad_variance);
|
|
275
|
|
276 if ((*asteroid_dens_variance) == 0)
|
|
277 varied_dens[j] = *asteroid_density;
|
|
278 else
|
|
279 varied_dens[j] = (*asteroid_density) - ((*asteroid_dens_variance) / 2) +
|
|
280 lrand48() % (*asteroid_dens_variance);
|
|
281
|
|
282 varied_thick[j] = (*asteroid_thickness) - ((*asteroid_thick_variance) / 2.0)
|
|
283 + drand48() * (*asteroid_thick_variance);
|
|
284
|
|
285 attempts++;
|
|
286
|
|
287 if (attempts > 1000)
|
|
288 {
|
|
289 printf("Too many attempts - giving up\n");
|
|
290 break;
|
|
291 }
|
|
292 }
|
|
293
|
|
294 for (i = 0; i < numstars; i++)
|
|
295 if (systems_with_asteroids[i])
|
|
296 printf("System %s has an asteroid belt\n", planets[star_numbers[i]].pl_name);
|
|
297
|
|
298 for (x = 0; x < TGRID_SIZE; x++)
|
|
299 {
|
|
300 for (y = 0; y < TGRID_SIZE; y++)
|
|
301 {
|
|
302 for (i = 0; i < numstars; i++)
|
|
303 {
|
|
304 /*
|
|
305 * if the tgrid locale is within a certain distance of a system that
|
|
306 * is supposed to have an asteroid belt, then, AST_CHANCE percent of
|
|
307 * the time, mark that locale as having asteroids
|
|
308 */
|
|
309 if (systems_with_asteroids[i] &&
|
|
310 terrain_grid[x * TGRID_SIZE + y].alt1 >= varied_rad[i] -
|
|
311 (varied_thick[i]) && terrain_grid[x * TGRID_SIZE + y].alt1
|
|
312 <= varied_rad[i] + (varied_thick[i]) && (ABS(x * TGRID_GRANULARITY -
|
|
313 planets[star_numbers[i]].pl_x) <
|
|
314 (MAXALTITUDE - (varied_rad[i] -
|
|
315 (varied_thick[i] + 1.0)))
|
|
316 * TGRID_GRANULARITY) &&
|
|
317 (ABS(y * TGRID_GRANULARITY - planets[star_numbers[i]].pl_y) <
|
|
318 (MAXALTITUDE - (varied_rad[i] - (varied_thick[i] + 1.0))) * TGRID_GRANULARITY) &&
|
|
319 lrand48() % 100 < varied_dens[i])
|
|
320 {
|
|
321 printf("terrain grid %d has asteroids\n", x * TGRID_SIZE + y);
|
|
322 terrain_grid[x * TGRID_SIZE + y].types |= T_ASTEROIDS;
|
|
323 }
|
|
324 }
|
|
325 }
|
|
326 }
|
|
327 }
|
|
328
|
|
329 void
|
|
330 doTerrainEffects()
|
|
331 /*
|
|
332 * apply terrain effects to players
|
|
333 *
|
|
334 * I REALLY wish I could add a "skill" element to many of the effects, but its
|
|
335 * tough. Asteroid damage is the most notable example where skill *should* be
|
|
336 * a factor, but isn't. MDM
|
|
337 */
|
|
338 {
|
|
339 struct player *p;
|
|
340 int i, j, dam;
|
|
341
|
|
342 for (i = 0; i < MAXPLAYER; i++)
|
|
343 {
|
|
344 p = &(players[i]);
|
|
345 if (p->p_status != PALIVE)
|
|
346 continue;
|
|
347 if (TERRAIN_TYPE((p->p_x) / TGRID_GRANULARITY, (p->p_y) / TGRID_GRANULARITY) &
|
|
348 T_ASTEROIDS)
|
|
349 {
|
|
350 j = lrand48() % 100;
|
|
351 /* the player is in an asteroid location */
|
|
352 if (p->p_speed != 0)
|
|
353 {
|
|
354 if (ast_effect[SS_IMPULSE] &&
|
|
355 (j < (100 - ((p->p_ship.s_turns / (p->p_speed * p->p_speed)) / 200)) ||
|
|
356 (j < MIN_AST_HIT)))
|
|
357 {
|
|
358 dam = lrand48() % (VAR_AST_DAMAGE * p->p_speed) + MIN_AST_DAMAGE;
|
|
359 if (inflict_damage(0, 0, p, dam, KASTEROID) == 1)
|
|
360 p->p_whydead = KASTEROID;
|
|
361 }
|
|
362 }
|
|
363 }
|
|
364 }
|
|
365 }
|