version 1.10 | | version 1.11 |
---|
| | |
/* | | /* |
* static char *rcsid_weather_c = | | * static char *rcsid_weather_c = |
* "$Id: weather.c,v 1.10 2002/10/29 10:24:53 garbled Exp $"; | | * "$Id: weather.c,v 1.11 2002/10/31 04:50:12 garbled Exp $"; |
*/ | | */ |
/* | | /* |
CrossFire, A Multiplayer game for X-windows | | CrossFire, A Multiplayer game for X-windows |
| | |
write_gulfstreammap(); | | write_gulfstreammap(); |
if (todtick%28 == 0 && settings.fastclock > 0) | | if (todtick%28 == 0 && settings.fastclock > 0) |
write_skymap(); | | write_skymap(); |
| | if (todtick&29 == 0) |
| | write_rainfallmap(); |
} | | } |
get_tod(&tod); | | get_tod(&tod); |
dawn_to_dusk(&tod); | | dawn_to_dusk(&tod); |
| | |
update_humid(); | | update_humid(); |
init_temperature(); | | init_temperature(); |
compute_sky(); | | compute_sky(); |
| | if (tod.hour == 0) |
| | process_rain(); |
} | | } |
/* perform_weather must follow calculators */ | | /* perform_weather must follow calculators */ |
perform_weather(); | | perform_weather(); |
| | |
for (ny=0,ay=ty; (ny < spwty && ay < settings.worldmaptilesizey && | | for (ny=0,ay=ty; (ny < spwty && ay < settings.worldmaptilesizey && |
space < spwtx*spwty); | | space < spwtx*spwty); |
ay++,ny++,space++) { | | ay++,ny++,space++) { |
if (QUERY_FLAG(m->spaces[ax+ay].bottom, | | if (QUERY_FLAG(GET_MAP_OB(m, ax, ay), FLAG_IS_WATER)) |
FLAG_IS_WATER)) | | |
water++; | | water++; |
elev += m->spaces[ax+ay].bottom->elevation; | | elev += GET_MAP_OB(m, ax, ay)->elevation; |
} | | } |
} | | } |
delete_map(m); | | delete_map(m); |
| | |
for (ny=j,ay=MAX(0, ty - (spwty-1)); (ny < spwty && ay <= ty && | | for (ny=j,ay=MAX(0, ty - (spwty-1)); (ny < spwty && ay <= ty && |
space < spwtx*spwty); | | space < spwtx*spwty); |
space++,ay++,ny++) { | | space++,ay++,ny++) { |
if (QUERY_FLAG(m->spaces[ax+ay].bottom, | | if (QUERY_FLAG(GET_MAP_OB(m, ax, ay), FLAG_IS_WATER)) |
FLAG_IS_WATER)) | | |
water++; | | water++; |
elev += m->spaces[ax+ay].bottom->elevation; | | elev += GET_MAP_OB(m, ax, ay)->elevation; |
} | | } |
} | | } |
delete_map(m); | | delete_map(m); |
| | |
for (ny=0,ay=ty; (ny < spwty && ay < settings.worldmaptilesizey && | | for (ny=0,ay=ty; (ny < spwty && ay < settings.worldmaptilesizey && |
space < spwtx*spwty); | | space < spwtx*spwty); |
ay++,ny++,space++) { | | ay++,ny++,space++) { |
if (QUERY_FLAG(m->spaces[ax+ay].bottom, | | if (QUERY_FLAG(GET_MAP_OB(m, ax, ay), FLAG_IS_WATER)) |
FLAG_IS_WATER)) | | |
water++; | | water++; |
elev += m->spaces[ax+ay].bottom->elevation; | | elev += GET_MAP_OB(m, ax, ay)->elevation; |
} | | } |
} | | } |
delete_map(m); | | delete_map(m); |
| | |
for (ny=0,ay=MAX(0, ty - (spwty-1)); (ny < spwty && ay <= ty && | | for (ny=0,ay=MAX(0, ty - (spwty-1)); (ny < spwty && ay <= ty && |
space < spwtx*spwty); | | space < spwtx*spwty); |
space++,ay++,ny++) { | | space++,ay++,ny++) { |
if (QUERY_FLAG(m->spaces[ax+ay].bottom, | | if (QUERY_FLAG(GET_MAP_OB(m, ax, ay), FLAG_IS_WATER)) |
FLAG_IS_WATER)) | | |
water++; | | water++; |
elev += m->spaces[ax+ay].bottom->elevation; | | elev += GET_MAP_OB(m, ax, ay)->elevation; |
} | | } |
} | | } |
delete_map(m); | | delete_map(m); |
| | |
temperature_calc(x, y, &tod); | | temperature_calc(x, y, &tod); |
} | | } |
| | |
| | /* rainfall */ |
| | |
| | void write_rainfallmap() |
| | { |
| | char filename[MAX_BUF]; |
| | FILE *fp; |
| | int x, y; |
| | |
| | sprintf(filename, "%s/rainfallmap", settings.localdir); |
| | if ((fp = fopen(filename, "w")) == NULL) { |
| | LOG(llevError, "Cannot open %s for writing\n", filename); |
| | return; |
| | } |
| | for (x=0; x < WEATHERMAPTILESX; x++) { |
| | for (y=0; y < WEATHERMAPTILESY; y++) |
| | fprintf(fp, "%u ", weathermap[x][y].rainfall); |
| | fprintf(fp, "\n"); |
| | } |
| | fclose(fp); |
| | } |
| | |
| | void read_rainfallmap() |
| | { |
| | char filename[MAX_BUF]; |
| | FILE *fp; |
| | int x, y; |
| | |
| | sprintf(filename, "%s/rainfallmap", settings.localdir); |
| | LOG(llevDebug, "Reading rainfall data from %s...", filename); |
| | if ((fp = fopen(filename, "r")) == NULL) { |
| | LOG(llevError, "Cannot open %s for reading\n", filename); |
| | init_rainfall(); |
| | write_rainfallmap(); |
| | return; |
| | } |
| | for (x=0; x < WEATHERMAPTILESX; x++) { |
| | for (y=0; y < WEATHERMAPTILESY; y++) { |
| | fscanf(fp, "%u ", &weathermap[x][y].rainfall); |
| | } |
| | fscanf(fp, "\n"); |
| | } |
| | LOG(llevDebug, "Done.\n"); |
| | fclose(fp); |
| | } |
| | |
| | void init_rainfall() |
| | { |
| | int x, y; |
| | int days; |
| | |
| | for (x=0; x < WEATHERMAPTILESX; x++) |
| | for (y=0; y < WEATHERMAPTILESY; y++) { |
| | days = todtick / HOURS_PER_DAY; |
| | if (weathermap[x][y].humid < 10) |
| | weathermap[x][y].rainfall = days / 20; |
| | else if (weathermap[x][y].humid < 20) |
| | weathermap[x][y].rainfall = days / 15; |
| | else if (weathermap[x][y].humid < 30) |
| | weathermap[x][y].rainfall = days / 10; |
| | else if (weathermap[x][y].humid < 40) |
| | weathermap[x][y].rainfall = days / 5; |
| | else if (weathermap[x][y].humid < 50) |
| | weathermap[x][y].rainfall = days / 2; |
| | else if (weathermap[x][y].humid < 60) |
| | weathermap[x][y].rainfall = days; |
| | else if (weathermap[x][y].humid < 80) |
| | weathermap[x][y].rainfall = days * 2; |
| | else |
| | weathermap[x][y].rainfall = days * 3; |
| | } |
| | } |
| | |
/* END of read/write/init */ | | /* END of read/write/init */ |
| | |
| | |
| | |
case 8: gulf_stream_dir[tx][ty] = 4; break; | | case 8: gulf_stream_dir[tx][ty] = 4; break; |
} | | } |
gulf_stream_start = rndm(GULF_STREAM_WIDTH, WEATHERMAPTILESY-GULF_STREAM_WIDTH); | | gulf_stream_start = rndm(GULF_STREAM_WIDTH, WEATHERMAPTILESY-GULF_STREAM_WIDTH); |
| | read_rainfallmap(); |
| | |
LOG(llevDebug, "Done reading weathermaps\n"); | | LOG(llevDebug, "Done reading weathermaps\n"); |
sprintf(filename, "%s/wmapcurpos", settings.localdir); | | sprintf(filename, "%s/wmapcurpos", settings.localdir); |
| | |
| | |
/* for now, all we do is decay stuff. more to come */ | | /* for now, all we do is decay stuff. more to come */ |
decay_objects(m); | | decay_objects(m); |
| | weather_effect(filename); |
| | |
| | /* done */ |
new_save_map(m, 2); /* write the overlay */ | | new_save_map(m, 2); /* write the overlay */ |
m->in_memory = MAP_IN_MEMORY; /*reset this*/ | | m->in_memory = MAP_IN_MEMORY; /*reset this*/ |
sprintf(filename, "%s/wmapcurpos", settings.localdir); | | sprintf(filename, "%s/wmapcurpos", settings.localdir); |
| | |
fclose(fp); | | fclose(fp); |
} | | } |
| | |
| | /* perform actual effect of weather. Should be called from perform_weather, |
| | or when a map is loaded. (player enter map). Filename is the name of |
| | the map. The map *must allready be loaded*. |
| | |
| | This is where things like snow, herbs, earthly rototilling, etc should |
| | occur. |
| | */ |
| | |
| | void weather_effect(char *filename) |
| | { |
| | mapstruct *m; |
| | int wx, wy, x, y; |
| | |
| | /* if the dm shut off weather, go home */ |
| | if (settings.dynamiclevel < 1) |
| | return; |
| | |
| | m = ready_map_name(filename, 0); |
| | if (!m->outdoor) |
| | return; |
| | |
| | x = 0; |
| | y = 0; |
| | /* for now, just bail if it's not the worldmap */ |
| | if (worldmap_to_weathermap(x, y, &wx, &wy, filename) != 0) |
| | return; |
| | |
| | if (settings.dynamiclevel < 2) |
| | return; |
| | |
| | let_it_snow(m, wx, wy, filename); |
| | |
| | } |
| | |
| | void let_it_snow(mapstruct *m, int wx, int wy, char *filename) |
| | { |
| | int x, y; |
| | int avoid, two, temp, sky; |
| | object *ob, *tmp; |
| | archetype *at; |
| | |
| | for (x=0; x < settings.worldmaptilesizex; x++) { |
| | for (y=0; y < settings.worldmaptilesizey; y++) { |
| | (void)worldmap_to_weathermap(x, y, &wx, &wy, filename); |
| | ob = NULL; |
| | at = NULL; |
| | /* this will definately need tuning */ |
| | avoid = 0; |
| | two = 0; |
| | temp = real_world_temperature(x, y, m); |
| | sky = weathermap[wx][wy].sky; |
| | if (temp <= 0 && sky > SKY_OVERCAST && sky < SKY_FOG) |
| | sky += 10; /*let it snow*/ |
| | for (tmp=GET_MAP_OB(m, x, y); tmp; tmp = tmp->above) { |
| | if (!strcasecmp(tmp->name, "snow")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "snow2")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "drifts")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "cforest1")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "sea")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "sea1")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "deep_sea")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "shallow_sea")) |
| | avoid++; |
| | } |
| | if (!avoid) { |
| | if (sky >= SKY_LIGHT_SNOW && sky < SKY_HEAVY_SNOW) |
| | at = find_archetype("snow"); |
| | if (sky >= SKY_HEAVY_SNOW) |
| | at = find_archetype("snow2"); |
| | if (!strcmp(GET_MAP_OB(m, x, y)->name, "hills") && |
| | sky >= SKY_LIGHT_SNOW) |
| | at = find_archetype("drifts"); |
| | if (!strcmp(GET_MAP_OB(m, x, y)->name, "evergreens") && |
| | sky >= SKY_LIGHT_SNOW) |
| | at = find_archetype("cforest1"); |
| | if (!strcmp(GET_MAP_OB(m, x, y)->name, "wasteland") && |
| | sky >= SKY_LIGHT_SNOW) |
| | at = find_archetype("glacier"); |
| | if (!strcmp(GET_MAP_OB(m, x, y)->name, "evergreen")) |
| | two++; |
| | if (!strcmp(GET_MAP_OB(m, x, y)->name, "tree")) |
| | two++; |
| | if (at != NULL) { |
| | ob = get_object(); |
| | copy_object(&at->clone, ob); |
| | ob->x = x; |
| | ob->y = y; |
| | insert_ob_in_map(ob, m, ob, |
| | INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY); |
| | if (two) { |
| | if (!strcmp(GET_MAP_OB(m, x, y)->name, "evergreen")) |
| | at = find_archetype("tree5"); |
| | if (!strcmp(GET_MAP_OB(m, x, y)->name, "tree")) |
| | at = find_archetype("tree3"); |
| | ob = get_object(); |
| | copy_object(&at->clone, ob); |
| | ob->x = x; |
| | ob->y = y; |
| | insert_ob_in_map(ob, m, ob, |
| | INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP); |
| | } |
| | } |
| | } |
| | if (temp > 8) { |
| | /* melt some snow */ |
| | for (tmp=GET_MAP_OB(m, x, y)->above; tmp; tmp = tmp->above) { |
| | avoid = 0; |
| | if (!strcmp(tmp->name, "snow")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "snow2")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "drifts")) |
| | avoid++; |
| | else if (!strcmp(tmp->name, "cforest1")) |
| | avoid++; |
| | if (avoid) { |
| | remove_ob(tmp); |
| | free_object(tmp); |
| | tmp=GET_MAP_OB(m, x, y); |
| | /* clean up the trees we put over the snow */ |
| | if (!strcmp(tmp->name, "evergreen")) |
| | tmp = tmp->above; |
| | else if (!strcmp(tmp->name, "tree")) |
| | tmp = tmp->above; |
| | if (tmp != NULL) |
| | if (strcmp(tmp->name, "tree3") == 0 || |
| | strcmp(tmp->name, "tree5") == 0) { |
| | remove_ob(tmp); |
| | free_object(tmp); |
| | } |
| | break; |
| | } |
| | } |
| | } |
| | /* woo it's cold out */ |
| | if (temp < -8) { |
| | avoid = 0; |
| | for (tmp=GET_MAP_OB(m, x, y); tmp; tmp = tmp->above) { |
| | if (!strcasecmp(tmp->name, "glacier")) |
| | avoid--; |
| | } |
| | tmp = GET_MAP_OB(m, x, y); |
| | if (!strcasecmp(tmp->name, "sea")) |
| | avoid++; |
| | else if (!strcasecmp(tmp->name, "sea1")) |
| | avoid++; |
| | else if (!strcasecmp(tmp->name, "deep_sea")) |
| | avoid++; |
| | else if (!strcasecmp(tmp->name, "shallow_sea")) |
| | avoid++; |
| | if (avoid > 0) { |
| | at = find_archetype("glacier"); |
| | ob = get_object(); |
| | copy_object(&at->clone, ob); |
| | ob->x = x; |
| | ob->y = y; |
| | insert_ob_in_map(ob, m, ob, |
| | INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY); |
| | } |
| | } |
| | } |
| | } |
| | } |
| | |
| | |
| | |
/* provide wx and wy. Will fill in with weathermap coordinates. Requires | | /* provide wx and wy. Will fill in with weathermap coordinates. Requires |
the current mapname (must be a worldmap), and your coordinates on the | | the current mapname (must be a worldmap), and your coordinates on the |
map. returns -1 if you give it something it can't figure out. 0 normally. | | map. returns -1 if you give it something it can't figure out. 0 normally. |
| | |
/* Compute the real (adjusted) temperature of a given weathermap tile. | | /* Compute the real (adjusted) temperature of a given weathermap tile. |
This takes into account the wind, base temp, sunlight, and other fun | | This takes into account the wind, base temp, sunlight, and other fun |
things. Seasons are automatically handled by moving the equator. | | things. Seasons are automatically handled by moving the equator. |
Elevation is considered in the base temp. | | Elevation is partially considered in the base temp. |
*/ | | */ |
| | |
int real_temperature(int x, int y) | | int real_temperature(int x, int y) |
| | |
return temp; | | return temp; |
} | | } |
| | |
| | /* Given a worldmap name, and x and y on that map, compute the temperature |
| | for a specific square. Used to normalize elevation. |
| | */ |
| | |
| | int real_world_temperature(int x, int y, mapstruct *m) |
| | { |
| | int wx, wy, temp, eleva, elevb; |
| | |
| | worldmap_to_weathermap(x, y, &wx, &wy, m->path); |
| | temp = real_temperature(wx, wy); |
| | if (weathermap[wx][wy].avgelev < 0) |
| | eleva = 0; |
| | else |
| | eleva = weathermap[x][y].avgelev; |
| | elevb = GET_MAP_OB(m, x, y)->elevation; |
| | if (elevb < 0) |
| | elevb = 0; |
| | if (elevb > eleva) { |
| | elevb -= eleva; |
| | temp -= elevb/1000; |
| | } else { |
| | elevb = eleva - elevb; |
| | temp += elevb/1000; |
| | } |
| | return temp; |
| | } |
| | |
/* this code simply smooths the pressure map */ | | /* this code simply smooths the pressure map */ |
| | |
void smooth_pressure() | | void smooth_pressure() |
| | |
} | | } |
} | | } |
} | | } |
| | |
| | void process_rain() |
| | { |
| | int x, y, rain; |
| | |
| | for (x=0; x < WEATHERMAPTILESX; x++) |
| | for (y=0; y < WEATHERMAPTILESY; y++) { |
| | rain = weathermap[x][y].sky; |
| | if (rain >= SKY_LIGHT_SNOW) |
| | rain -= 10; |
| | if (rain > SKY_OVERCAST && rain < SKY_FOG) { |
| | rain -= SKY_OVERCAST; |
| | weathermap[x][y].rainfall += rain; |
| | } |
| | } |
| | } |
| | |