| version 1.12 | | version 1.13 |
|---|
| | |
| /* | | /* |
| * static char *rcsid_weather_c = | | * static char *rcsid_weather_c = |
| * "$Id: weather.c,v 1.12 2002/11/06 09:47:23 garbled Exp $"; | | * "$Id: weather.c,v 1.13 2002/11/08 08:54:07 garbled Exp $"; |
| */ | | */ |
| /* | | /* |
| CrossFire, A Multiplayer game for X-windows | | CrossFire, A Multiplayer game for X-windows |
| | |
| extern unsigned long todtick; | | extern unsigned long todtick; |
| extern weathermap_t **weathermap; | | extern weathermap_t **weathermap; |
| | | |
| #define POLAR_BASE_TEMP 0 /* C */ | | |
| #define EQUATOR_BASE_TEMP 25 /* C */ | | |
| #define SEASONAL_ADJUST 10 /* polar distance */ | | |
| #define GULF_STREAM_WIDTH 3 /* width of gulf stream */ | | |
| #define GULF_STREAM_BASE_SPEED 40 /* base speed of gulf stream */ | | |
| | | |
| /* don't muck with these unless you are sure you know what they do */ | | |
| #define PRESSURE_ITERATIONS 30 | | |
| #define PRESSURE_AREA 180 | | |
| #define PRESSURE_ROUNDING_FACTOR 2 | | |
| #define PRESSURE_ROUNDING_ITER 1 | | |
| #define PRESSURE_SPIKES 3 | | |
| #define PRESSURE_MAX 1040 | | |
| #define PRESSURE_MIN 960 | | |
| | | |
| /* editing the below might require actual changes to code */ | | |
| #define WEATHERMAPTILESX 100 | | |
| #define WEATHERMAPTILESY 100 | | |
| | | |
| /* sky conditions */ | | |
| #define SKY_CLEAR 0 | | |
| #define SKY_LIGHTCLOUD 1 | | |
| #define SKY_OVERCAST 2 | | |
| #define SKY_LIGHT_RAIN 3 | | |
| #define SKY_RAIN 4 /* rain -> storm has lightning */ | | |
| #define SKY_HEAVY_RAIN 5 | | |
| #define SKY_HURRICANE 6 | | |
| /* wierd weather 7-12 */ | | |
| #define SKY_FOG 7 | | |
| #define SKY_HAIL 8 | | |
| /* snow */ | | |
| #define SKY_LIGHT_SNOW 13 /* add 10 to rain to get snow */ | | |
| #define SKY_SNOW 14 | | |
| #define SKY_HEAVY_SNOW 15 | | |
| #define SKY_BLIZZARD 16 | | |
| | | |
| int gulf_stream_speed[GULF_STREAM_WIDTH][WEATHERMAPTILESY]; | | int gulf_stream_speed[GULF_STREAM_WIDTH][WEATHERMAPTILESY]; |
| int gulf_stream_dir[GULF_STREAM_WIDTH][WEATHERMAPTILESY]; | | int gulf_stream_dir[GULF_STREAM_WIDTH][WEATHERMAPTILESY]; |
| int gulf_stream_start; | | int gulf_stream_start; |
| | |
| } | | } |
| delete_map(m); | | delete_map(m); |
| /* jesus thats confusing as all hell */ | | /* jesus thats confusing as all hell */ |
| printf("water %d humid %d\n", water, water*100/(spwtx*spwty)); | | |
| weathermap[x][y].humid = water*100/(spwtx*spwty); | | weathermap[x][y].humid = water*100/(spwtx*spwty); |
| weathermap[x][y].avgelev = elev/(spwtx*spwty); | | weathermap[x][y].avgelev = elev/(spwtx*spwty); |
| weathermap[x][y].water = weathermap[x][y].humid; | | weathermap[x][y].water = weathermap[x][y].humid; |
| | |
| return; | | return; |
| | | |
| /* move right to left, top to bottom */ | | /* move right to left, top to bottom */ |
| if (wmperformstartx == settings.worldmaptilesx) { | | if (wmperformstartx+1 == settings.worldmaptilesx) { |
| wmperformstartx = 0; | | wmperformstartx = 0; |
| wmperformstarty++; | | wmperformstarty++; |
| } else | | } else |
| | |
| return; | | return; |
| | | |
| let_it_snow(m, wx, wy, filename); | | let_it_snow(m, wx, wy, filename); |
| | | singing_in_the_rain(m, wx, wy, filename); |
| | | |
| } | | } |
| | | |
| void let_it_snow(mapstruct *m, int wx, int wy, char *filename) | | object *avoid_weather(int *av, mapstruct *m, int x, int y, int *gs) |
| { | | { |
| int x, y; | | int avoid, gotsnow; |
| int avoid, two, temp, sky, gotsnow; | | object *tmp; |
| object *ob, *tmp, *oldsnow; | | |
| 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; | | avoid = 0; |
| two = 0; | | |
| gotsnow = 0; | | gotsnow = 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) { | | for (tmp=GET_MAP_OB(m, x, y); tmp; tmp = tmp->above) { |
| /* problem: snow never gets upgraded */ | | |
| if (!strcmp(tmp->arch->name, "snow")) { | | if (!strcmp(tmp->arch->name, "snow")) { |
| gotsnow++; | | gotsnow++; |
| oldsnow = tmp; | | break; |
| } else if (!strcmp(tmp->arch->name, "snow2")) { | | } else if (!strcmp(tmp->arch->name, "snow2")) { |
| gotsnow++; | | gotsnow++; |
| oldsnow = tmp; | | break; |
| } else if (!strcmp(tmp->arch->name, "snow4")) { | | } else if (!strcmp(tmp->arch->name, "snow4")) { |
| gotsnow++; | | gotsnow++; |
| oldsnow = tmp; | | break; |
| | | } else if (!strcmp(tmp->arch->name, "rain1")) { |
| | | gotsnow++; |
| | | break; |
| | | } else if (!strcmp(tmp->arch->name, "rain2")) { |
| | | gotsnow++; |
| | | break; |
| | | } else if (!strcmp(tmp->arch->name, "rain3")) { |
| | | gotsnow++; |
| | | break; |
| | | } else if (!strcmp(tmp->arch->name, "rain4")) { |
| | | gotsnow++; |
| | | break; |
| | | } else if (!strcmp(tmp->arch->name, "rain5")) { |
| | | gotsnow++; |
| | | break; |
| } else if (!strcmp(tmp->name, "drifts")) | | } else if (!strcmp(tmp->name, "drifts")) |
| avoid++; | | avoid++; |
| else if (!strcmp(tmp->arch->name, "cforest1")) | | else if (!strcmp(tmp->arch->name, "cforest1")) |
| | |
| else if (!strcmp(tmp->name, "shallow_sea")) | | else if (!strcmp(tmp->name, "shallow_sea")) |
| avoid++; | | avoid++; |
| } | | } |
| | | *gs = gotsnow; |
| | | *av = avoid; |
| | | return tmp; |
| | | } |
| | | |
| | | void let_it_snow(mapstruct *m, int wx, int wy, char *filename) |
| | | { |
| | | int x, y; |
| | | int avoid, two, temp, sky, gotsnow; |
| | | object *ob, *tmp, *oldsnow; |
| | | 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; |
| | | gotsnow = 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*/ |
| | | oldsnow = avoid_weather(&avoid, m, x, y, &gotsnow); |
| if (!avoid) { | | if (!avoid) { |
| if (sky >= SKY_LIGHT_SNOW && sky < SKY_HEAVY_SNOW) | | if (sky >= SKY_LIGHT_SNOW && sky < SKY_HEAVY_SNOW) |
| at = find_archetype("snow"); | | at = find_archetype("snow"); |
| | |
| if (!strcmp(GET_MAP_OB(m, x, y)->name, "hills") && | | if (!strcmp(GET_MAP_OB(m, x, y)->name, "hills") && |
| sky >= SKY_LIGHT_SNOW) | | sky >= SKY_LIGHT_SNOW) |
| at = find_archetype("drifts"); | | at = find_archetype("drifts"); |
| | | /* special case scorn, where the no-magic field wrecks my |
| | | logic */ |
| | | if (GET_MAP_OB(m, x, y)->above != NULL) { |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->above->name, |
| | | "cobblestones") && sky >= SKY_LIGHT_SNOW) |
| | | at = find_archetype("snow4"); |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->above->arch->name, |
| | | "cobblestones2") && sky >= SKY_LIGHT_SNOW) |
| | | at = find_archetype("snow4"); |
| | | } |
| if (!strcmp(GET_MAP_OB(m, x, y)->name, "cobblestones") && | | if (!strcmp(GET_MAP_OB(m, x, y)->name, "cobblestones") && |
| sky >= SKY_LIGHT_SNOW) | | sky >= SKY_LIGHT_SNOW) |
| at = find_archetype("snow4"); | | at = find_archetype("snow4"); |
| | |
| two++; | | two++; |
| if (!strcmp(GET_MAP_OB(m, x, y)->name, "tree")) | | if (!strcmp(GET_MAP_OB(m, x, y)->name, "tree")) |
| two++; | | two++; |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->arch->name, "woods")) |
| | | two++; |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->arch->name, "woods_3")) |
| | | two++; |
| if (gotsnow && at) { | | if (gotsnow && at) { |
| if (!strcmp(oldsnow->arch->name, at->name)) | | if (!strcmp(oldsnow->arch->name, at->name)) |
| at = NULL; | | at = NULL; |
| | |
| tmp = tmp->above; | | tmp = tmp->above; |
| else if (!strcmp(tmp->name, "tree")) | | else if (!strcmp(tmp->name, "tree")) |
| tmp = tmp->above; | | tmp = tmp->above; |
| | | else if (!strcmp(tmp->arch->name, "woods")) |
| | | tmp = tmp->above; |
| | | else if (!strcmp(tmp->arch->name, "woods_3")) |
| | | tmp = tmp->above; |
| if (tmp != NULL) | | if (tmp != NULL) |
| if (strcmp(tmp->arch->name, "tree3") == 0 || | | if (strcmp(tmp->arch->name, "tree3") == 0 || |
| strcmp(tmp->arch->name, "tree5") == 0) { | | strcmp(tmp->arch->name, "tree5") == 0 || |
| | | strcmp(tmp->arch->name, "woods4") == 0 || |
| | | strcmp(tmp->arch->name, "woods5") == 0) { |
| remove_ob(tmp); | | remove_ob(tmp); |
| free_object(tmp); | | free_object(tmp); |
| } | | } |
| | |
| copy_object(&at->clone, ob); | | copy_object(&at->clone, ob); |
| ob->x = x; | | ob->x = x; |
| ob->y = y; | | ob->y = y; |
| | | ob->material = M_ICE; |
| if (!strcmp(ob->arch->name, "snow4")) | | if (!strcmp(ob->arch->name, "snow4")) |
| SET_FLAG(ob, FLAG_OVERLAY_FLOOR); | | SET_FLAG(ob, FLAG_OVERLAY_FLOOR); |
| insert_ob_in_map(ob, m, ob, | | insert_ob_in_map(ob, m, ob, |
| INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY); | | INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY); |
| if (two) { | | if (two) { |
| | | at = NULL; |
| if (!strcmp(GET_MAP_OB(m, x, y)->name, "evergreen")) | | if (!strcmp(GET_MAP_OB(m, x, y)->name, "evergreen")) |
| at = find_archetype("tree5"); | | at = find_archetype("tree5"); |
| if (!strcmp(GET_MAP_OB(m, x, y)->name, "tree")) | | if (!strcmp(GET_MAP_OB(m, x, y)->name, "tree")) |
| at = find_archetype("tree3"); | | at = find_archetype("tree3"); |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->arch->name, "woods")) |
| | | at = find_archetype("woods4"); |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->arch->name, "woods3")) |
| | | at = find_archetype("woods5"); |
| | | if (at != NULL) { |
| ob = get_object(); | | ob = get_object(); |
| copy_object(&at->clone, ob); | | copy_object(&at->clone, ob); |
| ob->x = x; | | ob->x = x; |
| | |
| } | | } |
| } | | } |
| } | | } |
| | | } |
| if (temp > 8) { | | if (temp > 8) { |
| /* melt some snow */ | | /* melt some snow */ |
| for (tmp=GET_MAP_OB(m, x, y)->above; tmp; tmp = tmp->above) { | | for (tmp=GET_MAP_OB(m, x, y)->above; tmp; tmp = tmp->above) { |
| | |
| else if (!strcmp(tmp->arch->name, "glacier")) | | else if (!strcmp(tmp->arch->name, "glacier")) |
| avoid++; | | avoid++; |
| if (avoid) { | | if (avoid) { |
| | | /* replace snow with a big puddle */ |
| remove_ob(tmp); | | remove_ob(tmp); |
| free_object(tmp); | | free_object(tmp); |
| tmp=GET_MAP_OB(m, x, y); | | at = find_archetype("rain5"); |
| /* clean up the trees we put over the snow */ | | if (at != NULL) { |
| if (!strcmp(tmp->name, "evergreen")) | | ob = get_object(); |
| tmp = tmp->above; | | copy_object(&at->clone, ob); |
| else if (!strcmp(tmp->name, "tree")) | | ob->x = x; |
| tmp = tmp->above; | | ob->y = y; |
| if (tmp != NULL) | | SET_FLAG(ob, FLAG_OVERLAY_FLOOR); |
| if (strcmp(tmp->arch->name, "tree3") == 0 || | | ob->material = M_LIQUID; |
| strcmp(tmp->arch->name, "tree5") == 0) { | | insert_ob_in_map(ob, m, ob, INS_NO_MERGE | |
| remove_ob(tmp); | | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY); |
| free_object(tmp); | | |
| } | | } |
| break; | | |
| } | | } |
| } | | } |
| } | | } |
| | |
| } | | } |
| } | | } |
| | | |
| | | void singing_in_the_rain(mapstruct *m, int wx, int wy, char *filename) |
| | | { |
| | | int x, y; |
| | | int avoid, two, temp, sky, gotsnow; |
| | | object *ob, *tmp, *oldsnow; |
| | | 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; |
| | | avoid = 0; |
| | | two = 0; |
| | | gotsnow = 0; |
| | | temp = real_world_temperature(x, y, m); |
| | | sky = weathermap[wx][wy].sky; |
| | | /* it's probably allready snowing */ |
| | | if (temp < 0) |
| | | continue; |
| | | oldsnow = avoid_weather(&avoid, m, x, y, &gotsnow); |
| | | if (!avoid) { |
| | | if (sky == SKY_LIGHT_RAIN || sky == SKY_RAIN) |
| | | switch (rndm(0, SKY_HAIL-sky)) { |
| | | case 0: at = find_archetype("rain1"); break; |
| | | case 1: at = find_archetype("rain2"); break; |
| | | default: at = NULL; |
| | | } |
| | | if (sky >= SKY_HEAVY_RAIN && sky <= SKY_HURRICANE) |
| | | switch (rndm(0, SKY_HAIL-sky)) { |
| | | case 0: at = find_archetype("rain3"); break; |
| | | case 1: at = find_archetype("rain4"); break; |
| | | case 2: at = find_archetype("rain5"); break; |
| | | default: at = NULL; |
| | | } |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->name, "evergreen")) |
| | | two++; |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->name, "tree")) |
| | | two++; |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->arch->name, "woods")) |
| | | two++; |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->arch->name, "woods_3")) |
| | | two++; |
| | | if (gotsnow && at) { |
| | | if (!strcmp(oldsnow->arch->name, at->name)) |
| | | at = NULL; |
| | | else { |
| | | remove_ob(oldsnow); |
| | | free_object(oldsnow); |
| | | 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; |
| | | else if (!strcmp(tmp->arch->name, "woods")) |
| | | tmp = tmp->above; |
| | | else if (!strcmp(tmp->arch->name, "woods_3")) |
| | | tmp = tmp->above; |
| | | if (tmp != NULL) |
| | | if (strcmp(tmp->arch->name, "tree3") == 0 || |
| | | strcmp(tmp->arch->name, "tree5") == 0 || |
| | | strcmp(tmp->arch->name, "woods4") == 0 || |
| | | strcmp(tmp->arch->name, "woods5") == 0) { |
| | | remove_ob(tmp); |
| | | free_object(tmp); |
| | | } |
| | | } |
| | | } |
| | | if (at != NULL) { |
| | | ob = get_object(); |
| | | copy_object(&at->clone, ob); |
| | | ob->x = x; |
| | | ob->y = y; |
| | | SET_FLAG(ob, FLAG_OVERLAY_FLOOR); |
| | | ob->material = M_LIQUID; |
| | | insert_ob_in_map(ob, m, ob, |
| | | INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY); |
| | | if (two) { |
| | | at = NULL; |
| | | 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"); |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->arch->name, "woods")) |
| | | at = find_archetype("woods4"); |
| | | if (!strcmp(GET_MAP_OB(m, x, y)->arch->name, "woods3")) |
| | | at = find_archetype("woods5"); |
| | | 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_ON_TOP); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | /* Things evaporate fast in the heat */ |
| | | if (temp > 8 && sky < SKY_OVERCAST && rndm(temp, 60) > 50) { |
| | | /* evaporate */ |
| | | for (tmp=GET_MAP_OB(m, x, y)->above; tmp; tmp = tmp->above) { |
| | | avoid = 0; |
| | | if (!strcmp(tmp->arch->name, "rain1")) |
| | | avoid++; |
| | | else if (!strcmp(tmp->arch->name, "rain2")) |
| | | avoid++; |
| | | else if (!strcmp(tmp->arch->name, "rain3")) |
| | | avoid++; |
| | | else if (!strcmp(tmp->arch->name, "rain4")) |
| | | avoid++; |
| | | else if (!strcmp(tmp->arch->name, "rain5")) |
| | | avoid++; |
| | | if (avoid) { |
| | | remove_ob(tmp); |
| | | free_object(tmp); |
| | | if (weathermap[wx][wy].humid < 100 && rndm(0, 50) == 0) |
| | | weathermap[wx][wy].humid++; |
| | | tmp=GET_MAP_OB(m, x, y); |
| | | /* clean up the trees we put over the rain */ |
| | | if (!strcmp(tmp->name, "evergreen")) |
| | | tmp = tmp->above; |
| | | else if (!strcmp(tmp->name, "tree")) |
| | | tmp = tmp->above; |
| | | else if (!strcmp(tmp->arch->name, "woods")) |
| | | tmp = tmp->above; |
| | | else if (!strcmp(tmp->arch->name, "woods_3")) |
| | | tmp = tmp->above; |
| | | if (tmp != NULL) |
| | | if (strcmp(tmp->arch->name, "tree3") == 0 || |
| | | strcmp(tmp->arch->name, "tree5") == 0 || |
| | | strcmp(tmp->arch->name, "woods4") == 0 || |
| | | strcmp(tmp->arch->name, "woods5") == 0) { |
| | | remove_ob(tmp); |
| | | free_object(tmp); |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| /* 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 |
| | |
| spwtx = (settings.worldmaptilesx * settings.worldmaptilesizex) / WEATHERMAPTILESX; | | spwtx = (settings.worldmaptilesx * settings.worldmaptilesizex) / WEATHERMAPTILESX; |
| spwty = (settings.worldmaptilesy * settings.worldmaptilesizey) / WEATHERMAPTILESY; | | spwty = (settings.worldmaptilesy * settings.worldmaptilesizey) / WEATHERMAPTILESY; |
| | | |
| | | while (*filename == '/') |
| | | *filename++; |
| | | |
| fx = -1; | | fx = -1; |
| fy = -1; | | fy = -1; |
| sscanf(filename, "world/world_%d_%d", &fx, &fy); | | sscanf(filename, "world/world_%d_%d", &fx, &fy); |