Mercurial > ~darius > hgwebdir.cgi > paradise_server
diff src/terrain.c @ 8:0836fb919dfa
First entry of Paradise Server 2.9 patch 10 Beta
author | darius |
---|---|
date | Sat, 06 Dec 1997 04:37:05 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/terrain.c Sat Dec 06 04:37:05 1997 +0000 @@ -0,0 +1,365 @@ +/*-------------------------------------------------------------------------- +NETREK II -- Paradise + +Permission to use, copy, modify, and distribute this software and its +documentation for any NON-COMMERCIAL purpose (following the terms of +the GNU General Public License (read the file 'COPYING')) and without +fee is hereby granted, provided that this copyright notice appear in all +copies. No representations are made about the suitability of this +software for any purpose. This software is provided "as is" without +express or implied warranty. + + Xtrek Copyright 1986 Chris Guthrie + Netrek (Xtrek II) Copyright 1989 Kevin P. Smith + Scott Silvey + Paradise II (Netrek II) Copyright 1993 Larry Denys + Kurt Olsen + Brandon Gillespie + + Comprehensive credits are available in the file "CREDITS" +--------------------------------------------------------------------------*/ + +#include "config.h" +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "struct.h" +#include "data.h" +#include "shmem.h" +#include "terrain.h" + +#define MAXALTITUDE 255 +#define MAXSTARS 20 +#define X 0 +#define Y 1 + +void +generate_terrain() +/* + * Generates terrain based on specs in the system configuration. Places a + * number of "seeds" into the terrain grid, and then generates an "altitude" + * map based on those seeds' positions (which correspond to star positions). + * Place_nebula generates another altitude map for nebulae -- the first map + * is used for asteroids and generating the second map. + * + * This function is called within the galaxy generation stuff. + * + * 10/26/94 MM + */ +{ + int i, j, k; /* counters */ + int x, y; /* more counters, different purpose */ + double dist, val; /* for distance calculations */ + int num_seeds = 0; + int seed_xy[MAXSTARS][2]; + int qx[4] = {-1, 1, -1, 1}, qy[4] = {1, 1, -1, -1}; /* quadrant multipliers */ + + /* + * place seeds -- this would be easy to change if you just had a number of + * seeds you wanted to place, instead of basing it on stars. I won't + * bother doing it, even though it might be cool to see it work in a bronco + * game... MM + */ + + for (i = 0; i < NUMPLANETS; i++) + if (PL_TYPE(planets[i]) == PLSTAR) + { + terrain_grid[(planets[i].pl_x / TGRID_GRANULARITY) * TGRID_SIZE + + planets[i].pl_y / TGRID_GRANULARITY].alt1 = MAXALTITUDE; + + seed_xy[num_seeds][X] = planets[i].pl_x / TGRID_GRANULARITY; + seed_xy[num_seeds][Y] = planets[i].pl_y / TGRID_GRANULARITY; + num_seeds++; + } + + /* generate terrain -- simple, stupid version. */ + + + for (x = 0; x < TGRID_SIZE; x++) + for (y = 0; y < TGRID_SIZE; y++) + if (terrain_grid[x * TGRID_SIZE + y].alt1 != MAXALTITUDE) + { + val = 0.0; + for (i = 0; i < num_seeds; i++) + { + dist = (double) MAXALTITUDE - + sqrt((double) ((x - seed_xy[i][X]) * (x - seed_xy[i][X]) + + (y - seed_xy[i][Y]) * (y - seed_xy[i][Y]))); + if (dist > val) + val = dist; + } + /* reset any previous terrain values */ + terrain_grid[x * TGRID_SIZE + y].types = 0x00; + + terrain_grid[x * TGRID_SIZE + y].alt1 = (int) val; + terrain_grid[x * TGRID_SIZE + y].alt2 = 0; + } + + /* place nebula */ + if (num_nebula) + place_nebula(*num_nebula, *nebula_subclouds, *nebula_density); + /* place asteroids */ + if (num_asteroid) + place_asteroids(MAXALTITUDE - (*asteroid_radius)); +} + +void +place_nebula(int num_nebula, int num_seeds, int minalt) +/* + * Values inbetween MAXALTITUDE and minalt are considered nebulous terrain. + * Tries to cluster seeds in groups based on num_nebula and num_seeds. ...the + * number of seeds per nebula being num_seeds. 10/26/94 MM + */ +{ + int i = 0, j = 0, x, y, dx, dy, dist, lowdist = 2 * TGRID_SIZE; + int *seeds1, *seeds2; + + seeds1 = (int *) malloc(num_nebula * sizeof(int)); + if (num_seeds) + seeds2 = (int *) malloc(num_seeds * sizeof(int) * num_nebula); + + /* find a local minimum, and place a "seed" */ + while (i < num_nebula) + { + j = (int) lrand48() % (TGRID_SIZE * TGRID_SIZE); + if (j == 0) + j = 1; + while ((j < (TGRID_SIZE * TGRID_SIZE)) && + ((terrain_grid[j - 1].alt1 < terrain_grid[j].alt1) || + (terrain_grid[j + 1].alt1 < terrain_grid[j].alt1))) + j++; + seeds1[i] = j; + terrain_grid[seeds1[i]].alt2 = MAXALTITUDE; + i++; + } + /* group num_seeds more "sub seeds" around each seed */ + /* + * (there are a couple bugs in this algorithm yet -- theres a wierd + * wraparound occasionally. MDM, 8/23/95) + */ + + for (i = 0; i < num_nebula; i++) + for (j = 0; j < num_seeds; j++) + { + dx = (int) (lrand48() % ((MAXALTITUDE - minalt) * 3)) - + (int) (lrand48() % (int) ((MAXALTITUDE - minalt) * (1.5))); + dy = (int) (lrand48() % ((MAXALTITUDE - minalt) * 3)) - + (int) (lrand48() % (int) ((MAXALTITUDE - minalt) * (1.5))); + if (seeds1[i] / TGRID_SIZE + dx < 0) + dx -= (seeds1[i] / TGRID_SIZE + dx); + if (seeds1[i] / TGRID_SIZE + dx >= TGRID_SIZE) + dx -= (seeds1[i] / TGRID_SIZE + dx) - (TGRID_SIZE - 1); + if (seeds1[i] / TGRID_SIZE + dy < 0) + dy -= (seeds1[i] / TGRID_SIZE + dy); + if (seeds1[i] / TGRID_SIZE + dy >= TGRID_SIZE) + dy -= (seeds1[i] / TGRID_SIZE + dy) - (TGRID_SIZE - 1); + seeds2[i * num_seeds + j] = (seeds1[i] / TGRID_SIZE + dx) * TGRID_SIZE + + (seeds1[i] % TGRID_SIZE + dy); + terrain_grid[seeds2[i * num_seeds + j]].alt2 = MAXALTITUDE; + } + + /* + * assign random-ish values, from a distance-from-seed base value (density + * is the randomness -- low density values are smooth, high are rough) + */ + /* randomness NYI */ + /* + * these values could be used in combination with the alt1 values to do + * other funky terrain "shapes, but I'm putting in the ABS() speedup stuff + * in for now anyway. It'll result in alt2 values of 0 for any spot + * outside a nebulous radius -- MDM + */ + for (x = 0; x < TGRID_SIZE; x++) + for (y = 0; y < TGRID_SIZE; y++) + { + for (i = 0; i < num_nebula; i++) + { + dx = (seeds1[i] / TGRID_SIZE) - x; + dy = (seeds1[i] % TGRID_SIZE) - y; + /* loop speedup */ + if ((ABS(dx) <= MAXALTITUDE - minalt) && + (ABS(dy) <= MAXALTITUDE - minalt)) + { + dist = (int) sqrt(dx * dx + dy * dy); + if (dist < lowdist) + lowdist = dist; + } + if (num_seeds) + for (j = 0; j < num_seeds; j++) + { + dx = seeds2[i * num_seeds + j] / TGRID_SIZE - x; + dy = seeds2[i * num_seeds + j] % TGRID_SIZE - y; + /* loop speedup */ + if ((ABS(dx) <= MAXALTITUDE - minalt) && + (ABS(dy) <= MAXALTITUDE - minalt)) + { + dist = (int) sqrt(dx * dx + dy * dy); + if (dist < lowdist) + lowdist = dist; + } + } + } + terrain_grid[x * TGRID_SIZE + y].alt2 = MAXALTITUDE - lowdist; + lowdist = 2 * TGRID_SIZE; + } + + /* give each spot with a high enuf alt value the nebulous terrain flag. */ + for (i = 0; i < TGRID_SIZE; i++) + for (j = 0; j < TGRID_SIZE; j++) + if (terrain_grid[i * TGRID_SIZE + j].alt2 >= minalt) + terrain_grid[i * TGRID_SIZE + j].types |= T_NEBULA; + + free(seeds1); + free(seeds2); +} + +void +place_asteroids(int altitude) +/* + * Marks terrain grid locations within density of altitude as asteroid + * fields. I may make the chance of such a grid location becoming a field + * random (like 90% or something), so that fields will appear less uniform, + * and holes may exist in them. Makes for interesting terrain, IMO. 10/26/94 + * MM + */ +{ + int x, y, i, j, numstars = 0, attempts = 0; + int *systems_with_asteroids; + int *star_numbers; + int *varied_rad; + int *varied_dens; + float *varied_thick; + + printf("placing asteroids\n"); + star_numbers = (int *) malloc((NUMPLANETS) * sizeof(int)); + for (i = 0; i < NUMPLANETS; i++) + if (PL_TYPE(planets[i]) == PLSTAR) + { + star_numbers[numstars] = i; + numstars++; + } + systems_with_asteroids = (int *) malloc(numstars * sizeof(int)); + varied_rad = (int *) malloc(numstars * sizeof(int)); + varied_dens = (int *) malloc(numstars * sizeof(int)); + varied_thick = (float *) malloc(numstars * sizeof(float)); + for (i = 0; i < numstars; i++) + systems_with_asteroids[i] = 0; + + /* + * assign what stars have asteroid belts -- I could just start with system + * #1, since systems are placed randomly, but I might as well pick a random + * system to start with. The only prereq is that the system does NOT + * belong to a race. (prereq NYI) + */ + if (*num_asteroid > (numstars - 4)) + *num_asteroid = numstars - 4; + + i = 0; + while (i < *num_asteroid) + { + j = lrand48() % numstars; + + if (((planets[j].pl_system < 1) || (planets[j].pl_system > 4)) + && (systems_with_asteroids[j] == 0)) + systems_with_asteroids[j] = 1; + else + continue; + + i++; + + if ((*asteroid_rad_variance) == 0) + varied_rad[j] = altitude; + else + varied_rad[j] = altitude - ((*asteroid_rad_variance) / 2) + + lrand48() % (*asteroid_rad_variance); + + if ((*asteroid_dens_variance) == 0) + varied_dens[j] = *asteroid_density; + else + varied_dens[j] = (*asteroid_density) - ((*asteroid_dens_variance) / 2) + + lrand48() % (*asteroid_dens_variance); + + varied_thick[j] = (*asteroid_thickness) - ((*asteroid_thick_variance) / 2.0) + + drand48() * (*asteroid_thick_variance); + + attempts++; + + if (attempts > 1000) + { + printf("Too many attempts - giving up\n"); + break; + } + } + + for (i = 0; i < numstars; i++) + if (systems_with_asteroids[i]) + printf("System %s has an asteroid belt\n", planets[star_numbers[i]].pl_name); + + for (x = 0; x < TGRID_SIZE; x++) + { + for (y = 0; y < TGRID_SIZE; y++) + { + for (i = 0; i < numstars; i++) + { + /* + * if the tgrid locale is within a certain distance of a system that + * is supposed to have an asteroid belt, then, AST_CHANCE percent of + * the time, mark that locale as having asteroids + */ + if (systems_with_asteroids[i] && + terrain_grid[x * TGRID_SIZE + y].alt1 >= varied_rad[i] - + (varied_thick[i]) && terrain_grid[x * TGRID_SIZE + y].alt1 + <= varied_rad[i] + (varied_thick[i]) && (ABS(x * TGRID_GRANULARITY - + planets[star_numbers[i]].pl_x) < + (MAXALTITUDE - (varied_rad[i] - + (varied_thick[i] + 1.0))) + * TGRID_GRANULARITY) && + (ABS(y * TGRID_GRANULARITY - planets[star_numbers[i]].pl_y) < + (MAXALTITUDE - (varied_rad[i] - (varied_thick[i] + 1.0))) * TGRID_GRANULARITY) && + lrand48() % 100 < varied_dens[i]) + { + printf("terrain grid %d has asteroids\n", x * TGRID_SIZE + y); + terrain_grid[x * TGRID_SIZE + y].types |= T_ASTEROIDS; + } + } + } + } +} + +void +doTerrainEffects() +/* + * apply terrain effects to players + * + * I REALLY wish I could add a "skill" element to many of the effects, but its + * tough. Asteroid damage is the most notable example where skill *should* be + * a factor, but isn't. MDM + */ +{ + struct player *p; + int i, j, dam; + + for (i = 0; i < MAXPLAYER; i++) + { + p = &(players[i]); + if (p->p_status != PALIVE) + continue; + if (TERRAIN_TYPE((p->p_x) / TGRID_GRANULARITY, (p->p_y) / TGRID_GRANULARITY) & + T_ASTEROIDS) + { + j = lrand48() % 100; + /* the player is in an asteroid location */ + if (p->p_speed != 0) + { + if (ast_effect[SS_IMPULSE] && + (j < (100 - ((p->p_ship.s_turns / (p->p_speed * p->p_speed)) / 200)) || + (j < MIN_AST_HIT))) + { + dam = lrand48() % (VAR_AST_DAMAGE * p->p_speed) + MIN_AST_DAMAGE; + if (inflict_damage(0, 0, p, dam, KASTEROID) == 1) + p->p_whydead = KASTEROID; + } + } + } + } +}