ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/weather.C
(Generate patch)

Comparing deliantra/server/server/weather.C (file contents):
Revision 1.6 by root, Thu Sep 14 21:16:13 2006 UTC vs.
Revision 1.17 by root, Sat Mar 17 22:11:23 2007 UTC

1
2/* 1/*
3 * static char *rcsid_weather_c = 2 * CrossFire, A Multiplayer game for X-windows
4 * "$Id: weather.C,v 1.6 2006/09/14 21:16:13 root Exp $"; 3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5 * Copyright (C) 2002 Tim Rightnour
6 * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
7 * Copyright (C) 1992 Frank Tore Johansen
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 * The authors can be reached via e-mail to <crossfire@schmorp.de>
5 */ 24 */
6
7/*
8 CrossFire, A Multiplayer game for X-windows
9
10 Copyright (C) 2002 Tim Rightnour
11 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
12 Copyright (C) 1992 Frank Tore Johansen
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27
28 The authors can be reached via e-mail to crossfire-devel@real-time.com
29*/
30 25
31/* This weather system was written for crossfire by Tim Rightnour */ 26/* This weather system was written for crossfire by Tim Rightnour */
32 27
33#include <global.h> 28#include <global.h>
34#include <tod.h> 29#include <tod.h>
35#include <map.h> 30#include <map.h>
36#ifndef __CEXTRACT__ 31#ifndef __CEXTRACT__
37# include <sproto.h> 32# include <sproto.h>
38#endif 33#endif
39 34
40extern unsigned long todtick;
41extern weathermap_t **weathermap;
42
43static void dawn_to_dusk (const timeofday_t * tod);
44static void write_skymap (void);
45static void write_pressuremap (void);
46static void read_pressuremap (void);
47static void init_pressure (void);
48static void write_winddirmap (void);
49static void read_winddirmap (void);
50static void write_windspeedmap (void);
51static void read_windspeedmap (void);
52static void init_wind (void);
53static void write_gulfstreammap (void);
54static void read_gulfstreammap (void);
55static void init_gulfstreammap (void);
56static void write_humidmap (void);
57static void read_humidmap (void);
58static void write_elevmap (void);
59static void read_elevmap (void);
60static void write_watermap (void);
61static void read_watermap (void);
62static void init_humid_elev (void);
63static void write_temperaturemap (void);
64static void read_temperaturemap (void);
65static void init_temperature (void);
66static void write_rainfallmap (void);
67static void read_rainfallmap (void);
68static void init_rainfall (void);
69static void init_weatheravoid (weather_avoids_t wa[]);
70static void perform_weather (void);
71static object *avoid_weather (int *av, mapstruct *m, int x, int y, int *gs, int grow);
72static void calculate_temperature (mapstruct *m, int wx, int wy);
73static void let_it_snow (mapstruct *m, int wx, int wy);
74static void singing_in_the_rain (mapstruct *m, int wx, int wy);
75static void plant_a_garden (mapstruct *m, int wx, int wy);
76static void change_the_world (mapstruct *m, int wx, int wy);
77
78//static void feather_map(mapstruct *m, int wx, int wy);
79static const char *weathermap_to_worldmap_corner (int wx, int wy, int *x, int *y, int dir);
80static int polar_distance (int x, int y, int equator);
81static void update_humid (void);
82static int humid_tile (int x, int y);
83static void temperature_calc (int x, int y, const timeofday_t * tod);
84static int real_temperature (int x, int y);
85static void smooth_pressure (void);
86static void perform_pressure (void);
87static void smooth_wind (void);
88static void plot_gulfstream (void);
89static void compute_sky (void);
90static void process_rain (void);
91static void spin_globe (void);
92static void write_weather_images (void);
93
94static int gulf_stream_speed[GULF_STREAM_WIDTH][WEATHERMAPTILESY];
95static int gulf_stream_dir[GULF_STREAM_WIDTH][WEATHERMAPTILESY];
96static int gulf_stream_start;
97static int gulf_stream_direction;
98
99static const int season_timechange[5][HOURS_PER_DAY] = { 35static const int season_timechange[5][HOURS_PER_DAY] = {
100
101/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 2 3 4 5 6 7 36 /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 2 3 4 5 6 7 8 9 10 11 12 13 */
102 8 9 10 11 12 13 */
103 {0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 37 { 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
104 1, 1, 1, 1, 1, 1},
105 {0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 38 { 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0},
106 1, 1, 1, 1, 1, 0},
107 {0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 39 { 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0},
108 1, 1, 1, 1, 1, 0},
109 {0, 0, 0, 0, 0, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40 { 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0},
110 1, 1, 1, 1, 1, 0},
111 {0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 41 { 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0}
112 1, 1, 1, 1, 1, 0}
113}; 42};
114 43
115static const int season_tempchange[HOURS_PER_DAY] = {
116
117/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 2 3 4 5 6 7
118 8 9 10 11 12 13 */
119 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1,
120 1, 1, 1, 1, 1, 1
121};
122
123/*
124 * The table below is used to set which tiles the weather will avoid
125 * processing. This keeps it from putting snow on snow, and putting snow
126 * on the ocean, and other things like that.
127 */
128
129static weather_avoids_t weather_avoids[] = {
130 {"snow", 1, NULL},
131 {"snow2", 1, NULL},
132 {"snow3", 1, NULL},
133 {"snow4", 1, NULL},
134 {"snow5", 1, NULL},
135 {"mountain1_snow", 1, NULL},
136 {"mountain2_snow", 1, NULL},
137 {"rain1", 1, NULL},
138 {"rain2", 1, NULL},
139 {"rain3", 1, NULL},
140 {"rain4", 1, NULL},
141 {"rain5", 1, NULL},
142 {"mountain1_rivlets", 1, NULL},
143 {"mountain2_rivlets", 1, NULL},
144 {"drifts", 0, NULL},
145 {"glacier", 0, NULL},
146 {"cforest1", 0, NULL},
147 {"sea", 0, NULL},
148 {"sea1", 0, NULL},
149 {"deep_sea", 0, NULL},
150 {"shallow_sea", 0, NULL},
151 {"lava", 0, NULL},
152 {"permanent_lava", 0, NULL},
153 {NULL, 0, NULL}
154};
155
156/*
157 * this table is identical to the one above, except these are tiles to avoid
158 * when processing growth. IE, don't grow herbs in the ocean. The second
159 * field is unused.
160 */
161
162static weather_avoids_t growth_avoids[] = {
163 {"cobblestones", 0, NULL},
164 {"cobblestones2", 0, NULL},
165 {"flagstone", 0, NULL},
166 {"stonefloor2", 0, NULL},
167 {"lava", 0, NULL},
168 {"permanent_lava", 0, NULL},
169 {"sea", 0, NULL},
170 {"sea1", 0, NULL},
171 {"deep_sea", 0, NULL},
172 {"shallow_sea", 0, NULL},
173 {"farmland", 0, NULL},
174 {"dungeon_magic", 0, NULL},
175 {"dungeon_floor", 0, NULL},
176 {"lake", 0, NULL},
177 {"grasspond", 0, NULL},
178 {NULL, 0, NULL}
179};
180
181/*
182 * The table below is used in let_it_snow() and singing_in_the_rain() to
183 * decide what type of snow/rain/etc arch to put down. The first field is the
184 * name of the arch we want to match. The second field is the special snow
185 * type we use to cover that arch. The third field is the doublestack arch,
186 * NULL if none, used to stack over the snow after covering the tile.
187 * The fourth field is 1 if you want to match arch->name, 0 to match ob->name.
188 */
189
190static weather_replace_t weather_replace[] = {
191 {"impossible_match", "snow5", NULL, 0},
192 {"impossible_match2", "snow4", NULL, 0}, /* placeholders */
193 {"impossible_match3", "snow3", NULL, 0},
194 {"hills", "drifts", NULL, 0},
195 {"treed_hills", "drifts", "woods5", 1},
196 {"grass", "snow", NULL, 0},
197 {"sand", "snow", NULL, 0},
198 {"stones", "snow2", NULL, 0},
199 {"steppe", "snow2", NULL, 0},
200 {"brush", "snow2", NULL, 0},
201 {"farmland", "snow3", NULL, 0},
202 {"wasteland", "glacier", NULL, 0},
203 {"mountain", "mountain1_snow", NULL, 1},
204 {"mountain2", "mountain2_snow", NULL, 1},
205 {"mountain4", "mountain2_snow", NULL, 1},
206 {"evergreens", "snow", "evergreens2", 1},
207 {"evergreen", "snow", "tree5", 1},
208 {"tree", "snow", "tree3", 0},
209 {"woods", "snow3", "woods4", 1},
210 {"woods_3", "snow", "woods5", 1},
211 {NULL, NULL, NULL, 0},
212};
213
214/*
215 * The table below is used to grow things on the map. See include/tod.h for
216 * the meanings of all of the fields.
217 */
218
219static const weather_grow_t weather_grow[] = {
220 /* herb, tile, random, rfmin, rfmax, humin, humax, tempmin, tempmax, elevmin, elevmax, season */
221 {"mint", "grass", 10, 1.0, 2.0, 30, 100, 10, 25, -100, 9999, 2},
222 {"rose_red", "grass", 15, 1.0, 2.0, 30, 100, 10, 25, -100, 9999, 2},
223 {"rose_red", "hills", 15, 1.0, 2.0, 30, 100, 10, 25, -100, 9999, 2},
224 {"mint", "brush", 8, 1.0, 2.0, 30, 100, 10, 25, -100, 9999, 2},
225 {"blackroot", "swamp", 15, 1.6, 2.0, 60, 100, 20, 30, -100, 1500, 0},
226 {"mushroom_1", "grass", 15, 1.6, 2.0, 60, 100, 3, 30, -100, 1500, 0},
227 {"mushroom_2", "grass", 15, 1.6, 2.0, 60, 100, 3, 30, -100, 1500, 0},
228 {"mushroom_1", "swamp", 15, 1.6, 2.0, 60, 100, 3, 30, -100, 1500, 0},
229 {"mushroom_2", "swamp", 15, 1.6, 2.0, 60, 100, 3, 30, -100, 1500, 0},
230 {"mushroom_1", "hills", 15, 1.6, 2.0, 60, 100, 3, 30, -100, 1500, 0},
231 {"mushroom_2", "hills", 15, 1.6, 2.0, 60, 100, 3, 30, -100, 1500, 0},
232 {"pipeweed", "farmland", 20, 1.0, 2.0, 30, 100, 10, 25, 100, 5000, 0},
233 {"cabbage", "farmland", 10, 1.0, 2.0, 30, 100, 10, 25, -100, 9999, 0},
234 {"onion", "farmland", 10, 1.0, 2.0, 30, 100, 10, 25, 100, 9999, 0},
235 {"carrot", "farmland", 10, 1.0, 2.0, 30, 100, 10, 25, 100, 9999, 0},
236 {"thorns", "brush", 15, 0.5, 1.3, 30, 100, 10, 25, -100, 9999, 0},
237 {"mountain_foilage", "mountain", 6, 1.0, 2.0, 25, 100, 5, 30, 0, 15999, 2},
238 {NULL, NULL, 1, 0.0, 0.0, 0, 0, 0, 0, 0, 0, 0}
239};
240
241/*
242 * The table below uses the same format as the one above. However this
243 * table is used to change the layout of the worldmap itself. The tile
244 * parameter is a base tile to lay down underneath the herb tile.
245 */
246
247static const weather_grow_t weather_tile[] = {
248 /* herb, tile, random, rfmin, rfmax, humin, humax, tempmin, tempmax, elevmin, elevmax */
249 {"dunes", NULL, 2, 0.0, 0.03, 0, 20, 10, 99, 0, 4000, 0},
250 {"desert", NULL, 1, 0.0, 0.05, 0, 20, 10, 99, 0, 4000, 0},
251 {"pstone_2", NULL, 1, 0.0, 0.05, 0, 20, -30, 10, 0, 4000, 0},
252 {"pstone_3", NULL, 1, 0.0, 0.05, 0, 20, -30, 10, 0, 4000, 0},
253 {"grassbrown", NULL, 1, 0.05, 1.0, 20, 80, -20, -3, 0, 5000, 0},
254 {"grass_br_gr", NULL, 1, 0.05, 1.0, 20, 80, -3, 5, 0, 5000, 0},
255 {"grass", NULL, 1, 0.05, 1.0, 20, 80, 5, 15, 0, 5000, 0},
256 {"grassmedium", NULL, 1, 0.05, 1.0, 20, 80, 15, 25, 0, 5000, 0},
257 {"grassdark", NULL, 1, 0.05, 1.0, 20, 80, 25, 35, 0, 5000, 0},
258 {"brush", NULL, 1, 0.2, 1.0, 25, 70, 0, 30, 500, 6000, 0},
259 /* small */
260 {"evergreens2", "brush", 1, 0.5, 1.8, 30, 90, -30, 24, 3000, 8000, 0},
261 {"fernsdense", "brush", 1, 0.9, 2.5, 50, 100, 10, 35, 1000, 6000, 0},
262 {"fernssparse", "brush", 1, 0.7, 2.0, 30, 90, -15, 35, 0, 4000, 0},
263 {"woods4", "brush", 1, 0.1, 0.8, 30, 60, -5, 25, 1000, 4500, 0},
264 {"woods5", "brush", 1, 0.6, 1.5, 20, 70, -15, 20, 2000, 5500, 0},
265 {"forestsparse", "brush", 1, 0.3, 1.5, 15, 60, -20, 25, 0, 4500, 0},
266 /* big */
267 /*
268 {"ytree_2", "brush", 2, 0.1, 0.6, 30, 60, 10, 25, 1000, 3500, 0},
269 {"tree3", "grass", 2, 0.9, 2.5, 50, 100, 10, 35, 1000, 4000, 0},
270 {"tree5", "grass", 2, 0.5, 1.5, 40, 90, -10, 24, 3000, 8000, 0},
271 {"tree3", "grassmeduim", 2, 0.9, 2.5, 50, 100, 10, 35, 1000, 4000, 0},
272 {"tree5", "grassmedium", 2, 0.5, 1.5, 40, 90, -10, 24, 3000, 8000, 0},
273 {"tree3", "grassdark", 2, 0.9, 2.5, 50, 100, 10, 35, 1000, 4000, 0},
274 {"tree5", "grassdark", 2, 0.5, 1.5, 40, 90, -10, 24, 3000, 8000, 0}, */
275 /* mountians */
276 {"steppe", NULL, 1, 0.5, 1.3, 0, 30, -20, 35, 1000, 6000, 0},
277 {"steppelight", NULL, 1, 0.0, 0.6, 0, 20, -50, 35, 0, 5000, 0},
278 {"hills", NULL, 1, 0.1, 0.9, 20, 80, -10, 30, 5000, 8500, 0},
279 {"hills_rocky", NULL, 1, 0.0, 0.9, 0, 100, -50, 50, 5000, 8500, 0},
280 {"swamp", NULL, 1, 1.0, 9.9, 55, 80, 10, 50, 0, 1000, 0},
281 {"deep_swamp", NULL, 1, 1.0, 9.9, 80, 100, 10, 50, 0, 1000, 0},
282 {"mountain", NULL, 1, 0.0, 9.9, 0, 100, -50, 50, 8000, 10000, 0},
283 {"mountain2", NULL, 1, 0.0, 9.9, 0, 100, -50, 50, 9500, 11000, 0},
284 {"mountain4", NULL, 1, 0.0, 9.9, 0, 100, -50, 50, 10500, 12000, 0},
285 {"mountain5", NULL, 1, 0.0, 9.9, 0, 100, -50, 50, 11500, 13500, 0},
286 {"wasteland", NULL, 1, 0.0, 9.9, 0, 100, -50, 50, 13000, 99999, 0},
287 /* catchalls */
288 {"palms", "pstone_1", 1, 0.01, 0.1, 0, 30, 5, 99, 0, 4000, 0},
289 {"large_stones", NULL, 1, 0.0, 9.9, 0, 100, -50, 50, 6000, 8000, 0},
290 {"earth", NULL, 1, 0.0, 1.0, 0, 70, -30, 15, 0, 6000, 0},
291 {"medium_stones", NULL, 1, 1.0, 3.0, 70, 100, -30, 10, 0, 4000, 0}, /*unsure */
292 {"earth", NULL, 1, 0.1, 0.9, 20, 80, -30, 30, 0, 4999, 0}, /* tundra */
293 {"swamp", NULL, 1, 1.0, 9.9, 50, 100, -30, 10, 0, 4000, 0}, /* cold marsh */
294 {"earth", NULL, 1, 0.0, 99.9, 0, 100, -99, 99, 0, 99999, 0}, /* debug */
295 {NULL, NULL, 1, 0.0, 0.0, 0, 0, 0, 0, 0, 0, 0}
296};
297
298/* This stuff is for creating the images. */
299
300/* Colour offsets into pixel array. */
301#define RED 0
302#define GREEN 1
303#define BLUE 2
304
305/* Colours used for wind directions.
306 * winddir is the directoin wind is coming from.
307 * 812 456
308 * 7 3 3 7
309 * 654 218
310 */
311static const uint32 directions[] = {
312 0x0000FFFF, /* south */
313 0x000000FF, /* south west */
314 0x00FF00FF, /* west */
315 0x00FFFFFF, /* north west */
316 0x00000000, /* north */
317 0x00FF0000, /* north east */
318 0x00FFFF00, /* east */
319 0x0000FF00 /* south east */
320};
321
322/* Colours used for weather types. */
323static const uint32 skies[] = {
324 0x000000FF, /* SKY_CLEAR 0 */
325 0x000000BD, /* SKY_LIGHTCLOUD 1 */
326 0x0000007E, /* SKY_OVERCAST 2 */
327 0x0000FF00, /* SKY_LIGHT_RAIN 3 */
328 0x0000BD00, /* SKY_RAIN 4 */
329 0x00007E00, /* SKY_HEAVY_RAIN 5 */
330 0x00FFFF00, /* SKY_HURRICANE 6 */
331
332/* wierd weather 7-12 */
333 0x00FF0000, /* SKY_FOG 7 */
334 0x00FF00FF, /* SKY_HAIL 8 */
335 0x00000000,
336 0x00000000,
337 0x00000000,
338 0x00000000,
339
340/* snow */
341 0x003F3F3F, /* SKY_LIGHT_SNOW 13 */
342 0x007E7E7E, /* SKY_SNOW 14 */
343 0x00BDBDBD, /* SKY_HEAVY_SNOW 15 */
344 0x00FFFFFF /* SKY_BLIZZARD 16 */
345};
346
347
348/*
349 * Set the darkness level for a map. Requires the map pointer.
350 */
351
352void 44void
353set_darkness_map (mapstruct *m) 45maptile::set_darkness_map ()
354{ 46{
355 int i;
356 timeofday_t tod; 47 timeofday_t tod;
357 48
358 if (!m->outdoor) 49 if (!outdoor)
359 return; 50 return;
360 51
361 get_tod (&tod); 52 get_tod (&tod);
362 m->darkness = 0; 53 darkness = 0;
54
363 for (i = HOURS_PER_DAY / 2; i < HOURS_PER_DAY; i++) 55 for (int i = HOURS_PER_DAY / 2; i < HOURS_PER_DAY; i++)
364 change_map_light (m, season_timechange[tod.season][i]); 56 change_map_light (season_timechange[tod.season][i]);
57
365 for (i = 0; i <= tod.hour; i++) 58 for (int i = 0; i <= tod.hour; i++)
366 change_map_light (m, season_timechange[tod.season][i]); 59 change_map_light (season_timechange[tod.season][i]);
367} 60}
368 61
369/* 62/*
370 * Compute the darkness level for all maps in the game. Requires the 63 * Compute the darkness level for all maps in the game. Requires the
371 * time of day as an argument. 64 * time of day as an argument.
372 */ 65 */
373 66
374static void 67static void
375dawn_to_dusk (const timeofday_t * tod) 68dawn_to_dusk (const timeofday_t * tod)
376{ 69{
377 mapstruct *m;
378
379 /* If the light level isn't changing, no reason to do all 70 /* If the light level isn't changing, no reason to do all
380 * the work below. 71 * the work below.
381 */ 72 */
382 if (season_timechange[tod->season][tod->hour] == 0) 73 if (season_timechange[tod->season][tod->hour] == 0)
383 return; 74 return;
384 75
385 for (m = first_map; m != NULL; m = m->next)
386 {
387 if (!m->outdoor)
388 continue;
389 change_map_light (m, season_timechange[tod->season][tod->hour]); 76 maptile::change_all_map_light (season_timechange[tod->season][tod->hour]);
390 }
391} 77}
392 78
393/*
394 * This performs the basic function of advancing the clock one tick
395 * forward. Every 20 ticks, the clock is saved to disk. It is also
396 * saved on shutdown. Any time dependant functions should be called
397 * from this function, and probably be passed tod as an argument.
398 * Please don't modify tod in the dependant function.
399 */
400
401void 79void
402tick_the_clock (void) 80adjust_daylight ()
403{ 81{
404 timeofday_t tod; 82 timeofday_t tod;
405 83
406 todtick++;
407 if (todtick % 20 == 0)
408 write_todclock ();
409 if (settings.dynamiclevel > 0)
410 {
411 if (todtick % 21 == 0)
412 write_pressuremap ();
413 if (todtick % 22 == 0)
414 write_winddirmap ();
415 if (todtick % 23 == 0)
416 write_windspeedmap ();
417 if (todtick % 24 == 0)
418 write_humidmap ();
419
420/* if (todtick%25 == 0)
421 write_elevmap(); */
422 if (todtick % 26 == 0)
423 write_temperaturemap ();
424 if (todtick % 27 == 0)
425 write_gulfstreammap ();
426 if (todtick % 28 == 0)
427 write_skymap ();
428 if (todtick % 29 == 0)
429 write_rainfallmap ();
430 }
431 get_tod (&tod); 84 get_tod (&tod);
432 dawn_to_dusk (&tod); 85 dawn_to_dusk (&tod);
433 /* call the weather calculators, here, in order */
434 if (settings.dynamiclevel > 0)
435 {
436 perform_pressure (); /* pressure is the random factor */
437 smooth_wind (); /* calculate the wind. depends on pressure */
438 plot_gulfstream ();
439 update_humid ();
440 init_temperature ();
441 compute_sky ();
442 if (tod.hour == 0)
443 process_rain ();
444 }
445 /* perform_weather must follow calculators */
446 perform_weather ();
447 if (settings.dynamiclevel > 0)
448 {
449 write_weather_images ();
450 spin_globe ();
451 }
452} 86}
453 87
454/*
455 * This batch of routines reads and writes the various
456 * weathermap structures. Each type of data is stored
457 * in a separate file to allow the size of these structures to be
458 * changed more or less on the fly. If weather goes haywire, the admin
459 * can simply delete and boot the server, and it will regen.
460 *
461 * The write functions should be called occasionally to keep the data
462 * in the maps current. Whereas the read functions should only be called
463 * at boot. If the read function cannot find the appropriate map, it
464 * calls the init function, to initialize that map.
465 */
466
467/* sky. We never read this map, only write it for debugging purposes */
468
469static void
470write_skymap (void)
471{
472 char filename[MAX_BUF];
473 FILE *fp;
474 int x, y;
475
476 sprintf (filename, "%s/skymap", settings.localdir);
477 if ((fp = fopen (filename, "w")) == NULL)
478 {
479 LOG (llevError, "Cannot open %s for writing\n", filename);
480 return;
481 }
482 for (x = 0; x < WEATHERMAPTILESX; x++)
483 {
484 for (y = 0; y < WEATHERMAPTILESY; y++)
485 fprintf (fp, "%d ", weathermap[x][y].sky);
486 fprintf (fp, "\n");
487 }
488 fclose (fp);
489}
490
491/* pressure */
492
493static void
494write_pressuremap (void)
495{
496 char filename[MAX_BUF];
497 FILE *fp;
498 int x, y;
499
500 sprintf (filename, "%s/pressuremap", settings.localdir);
501 if ((fp = fopen (filename, "w")) == NULL)
502 {
503 LOG (llevError, "Cannot open %s for writing\n", filename);
504 return;
505 }
506 for (x = 0; x < WEATHERMAPTILESX; x++)
507 {
508 for (y = 0; y < WEATHERMAPTILESY; y++)
509 fprintf (fp, "%d ", weathermap[x][y].pressure);
510 fprintf (fp, "\n");
511 }
512 fclose (fp);
513}
514
515static void
516read_pressuremap (void)
517{
518 char filename[MAX_BUF];
519 FILE *fp;
520 int x, y;
521
522 sprintf (filename, "%s/pressuremap", settings.localdir);
523 LOG (llevDebug, "Reading pressure data from %s...", filename);
524 if ((fp = fopen (filename, "r")) == NULL)
525 {
526 LOG (llevError, "Cannot open %s for reading\n", filename);
527 LOG (llevDebug, "Initializing pressure maps...");
528 init_pressure ();
529 write_pressuremap ();
530 LOG (llevDebug, "Done\n");
531 return;
532 }
533 for (x = 0; x < WEATHERMAPTILESX; x++)
534 {
535 for (y = 0; y < WEATHERMAPTILESY; y++)
536 {
537 fscanf (fp, "%hd ", &weathermap[x][y].pressure);
538 if (weathermap[x][y].pressure < 960 || weathermap[x][y].pressure > 1040)
539 weathermap[x][y].pressure = rndm (960, 1040);
540 }
541 fscanf (fp, "\n");
542 }
543 LOG (llevDebug, "Done.\n");
544 fclose (fp);
545}
546
547static void
548init_pressure (void)
549{
550 int x, y;
551 int l, n, k, r;
552
553 for (x = 0; x < WEATHERMAPTILESX; x++)
554 for (y = 0; y < WEATHERMAPTILESY; y++)
555 weathermap[x][y].pressure = 1000;
556
557 for (l = 0; l < PRESSURE_ITERATIONS; l++)
558 {
559 x = rndm (0, WEATHERMAPTILESX - 1);
560 y = rndm (0, WEATHERMAPTILESY - 1);
561 n = rndm (PRESSURE_MIN, PRESSURE_MAX);
562 for (k = 1; k < PRESSURE_AREA; k++)
563 {
564 r = rndm (0, 3);
565 switch (r)
566 {
567 case 0:
568 if (x < WEATHERMAPTILESX - 1)
569 x++;
570 break;
571 case 1:
572 if (y < WEATHERMAPTILESY - 1)
573 y++;
574 break;
575 case 2:
576 if (x)
577 x--;
578 break;
579 case 3:
580 if (y)
581 y--;
582 break;
583 }
584 weathermap[x][y].pressure = (weathermap[x][y].pressure + n) / 2;
585 }
586 }
587 /* create random spikes in the pressure */
588 for (l = 0; l < PRESSURE_SPIKES; l++)
589 {
590 x = rndm (0, WEATHERMAPTILESX - 1);
591 y = rndm (0, WEATHERMAPTILESY - 1);
592 n = rndm (500, 2000);
593 weathermap[x][y].pressure = n;
594 }
595 smooth_pressure ();
596}
597
598/* winddir */
599
600static void
601write_winddirmap (void)
602{
603 char filename[MAX_BUF];
604 FILE *fp;
605 int x, y;
606
607 sprintf (filename, "%s/winddirmap", settings.localdir);
608 if ((fp = fopen (filename, "w")) == NULL)
609 {
610 LOG (llevError, "Cannot open %s for writing\n", filename);
611 return;
612 }
613 for (x = 0; x < WEATHERMAPTILESX; x++)
614 {
615 for (y = 0; y < WEATHERMAPTILESY; y++)
616 fprintf (fp, "%d ", weathermap[x][y].winddir);
617 fprintf (fp, "\n");
618 }
619 fclose (fp);
620}
621
622static void
623read_winddirmap (void)
624{
625 char filename[MAX_BUF];
626 FILE *fp;
627 int x, y, d;
628
629 sprintf (filename, "%s/winddirmap", settings.localdir);
630 LOG (llevDebug, "Reading wind direction data from %s...", filename);
631 if ((fp = fopen (filename, "r")) == NULL)
632 {
633 LOG (llevError, "Cannot open %s for reading\n", filename);
634 LOG (llevDebug, "Initializing wind maps...");
635 init_wind ();
636 write_winddirmap ();
637 LOG (llevDebug, "Done\n");
638 return;
639 }
640 for (x = 0; x < WEATHERMAPTILESX; x++)
641 {
642 for (y = 0; y < WEATHERMAPTILESY; y++)
643 {
644 fscanf (fp, "%d ", &d);
645 weathermap[x][y].winddir = d;
646 if (weathermap[x][y].winddir < 1 || weathermap[x][y].winddir > 8)
647 weathermap[x][y].winddir = rndm (1, 8);
648 }
649 fscanf (fp, "\n");
650 }
651 LOG (llevDebug, "Done.\n");
652 fclose (fp);
653}
654
655/* windspeed */
656
657static void
658write_windspeedmap (void)
659{
660 char filename[MAX_BUF];
661 FILE *fp;
662 int x, y;
663
664 sprintf (filename, "%s/windspeedmap", settings.localdir);
665 if ((fp = fopen (filename, "w")) == NULL)
666 {
667 LOG (llevError, "Cannot open %s for writing\n", filename);
668 return;
669 }
670 for (x = 0; x < WEATHERMAPTILESX; x++)
671 {
672 for (y = 0; y < WEATHERMAPTILESY; y++)
673 fprintf (fp, "%d ", weathermap[x][y].windspeed);
674 fprintf (fp, "\n");
675 }
676 fclose (fp);
677}
678
679static void
680read_windspeedmap (void)
681{
682 char filename[MAX_BUF];
683 FILE *fp;
684 int x, y, d;
685
686 sprintf (filename, "%s/windspeedmap", settings.localdir);
687 LOG (llevDebug, "Reading wind speed data from %s...", filename);
688 if ((fp = fopen (filename, "r")) == NULL)
689 {
690 LOG (llevError, "Cannot open %s for reading\n", filename);
691 LOG (llevDebug, "Initializing wind maps...");
692 init_wind ();
693 write_windspeedmap ();
694 LOG (llevDebug, "Done\n");
695 return;
696 }
697 for (x = 0; x < WEATHERMAPTILESX; x++)
698 {
699 for (y = 0; y < WEATHERMAPTILESY; y++)
700 {
701 fscanf (fp, "%d ", &d);
702 weathermap[x][y].windspeed = d;
703 if (weathermap[x][y].windspeed < 0 || weathermap[x][y].windspeed > 120)
704 weathermap[x][y].windspeed = rndm (1, 30);
705 }
706 fscanf (fp, "\n");
707 }
708 LOG (llevDebug, "Done.\n");
709 fclose (fp);
710}
711
712/* initialize the wind randomly. Does both direction and speed in one pass */
713
714static void
715init_wind (void)
716{
717 int x, y;
718
719 for (x = 0; x < WEATHERMAPTILESX; x++)
720 for (y = 0; y < WEATHERMAPTILESY; y++)
721 {
722 weathermap[x][y].winddir = rndm (1, 8);
723 weathermap[x][y].windspeed = rndm (1, 10);
724 }
725}
726
727/* gulf stream */
728
729static void
730write_gulfstreammap (void)
731{
732 char filename[MAX_BUF];
733 FILE *fp;
734 int x, y;
735
736 sprintf (filename, "%s/gulfstreammap", settings.localdir);
737 if ((fp = fopen (filename, "w")) == NULL)
738 {
739 LOG (llevError, "Cannot open %s for writing\n", filename);
740 return;
741 }
742 for (x = 0; x < GULF_STREAM_WIDTH; x++)
743 {
744 for (y = 0; y < WEATHERMAPTILESY; y++)
745 fprintf (fp, "%d ", gulf_stream_speed[x][y]);
746 fprintf (fp, "\n");
747 }
748 for (x = 0; x < GULF_STREAM_WIDTH; x++)
749 {
750 for (y = 0; y < WEATHERMAPTILESY; y++)
751 fprintf (fp, "%d ", gulf_stream_dir[x][y]);
752 fprintf (fp, "\n");
753 }
754 fclose (fp);
755}
756
757static void
758read_gulfstreammap (void)
759{
760 char filename[MAX_BUF];
761 FILE *fp;
762 int x, y;
763
764 sprintf (filename, "%s/gulfstreammap", settings.localdir);
765 LOG (llevDebug, "Reading gulf stream data from %s...", filename);
766 if ((fp = fopen (filename, "r")) == NULL)
767 {
768 LOG (llevError, "Cannot open %s for reading\n", filename);
769 LOG (llevDebug, "Initializing gulf stream maps...");
770 init_gulfstreammap ();
771 write_gulfstreammap ();
772 LOG (llevDebug, "Done\n");
773 return;
774 }
775 for (x = 0; x < GULF_STREAM_WIDTH; x++)
776 {
777 for (y = 0; y < WEATHERMAPTILESY; y++)
778 {
779 fscanf (fp, "%d ", &gulf_stream_speed[x][y]);
780 if (gulf_stream_speed[x][y] < 0 || gulf_stream_speed[x][y] > 120)
781 gulf_stream_speed[x][y] = rndm (GULF_STREAM_BASE_SPEED, GULF_STREAM_BASE_SPEED + 10);
782 }
783 fscanf (fp, "\n");
784 }
785 for (x = 0; x < GULF_STREAM_WIDTH; x++)
786 {
787 for (y = 0; y < WEATHERMAPTILESY; y++)
788 {
789 fscanf (fp, "%d ", &gulf_stream_dir[x][y]);
790 if (gulf_stream_dir[x][y] < 0 || gulf_stream_dir[x][y] > 120)
791 gulf_stream_dir[x][y] = rndm (1, 8);
792 }
793 fscanf (fp, "\n");
794 }
795 LOG (llevDebug, "Done.\n");
796 fclose (fp);
797}
798
799static void
800init_gulfstreammap (void)
801{
802 int x, y, tx;
803
804 /* build a gulf stream */
805 x = rndm (GULF_STREAM_WIDTH, WEATHERMAPTILESX - GULF_STREAM_WIDTH);
806 /* doth the great bob inhale or exhale? */
807 gulf_stream_direction = rndm (0, 1);
808 gulf_stream_start = x;
809
810 if (gulf_stream_direction)
811 {
812 for (y = WEATHERMAPTILESY - 1; y >= 0; y--)
813 {
814 switch (rndm (0, 6))
815 {
816 case 0:
817 case 1:
818 case 2:
819 for (tx = 0; tx < GULF_STREAM_WIDTH; tx++)
820 {
821 gulf_stream_speed[tx][y] = rndm (GULF_STREAM_BASE_SPEED, GULF_STREAM_BASE_SPEED + 10);
822 if (x == 0)
823 gulf_stream_dir[tx][y] = 7;
824 else
825 {
826 gulf_stream_dir[tx][y] = 8;
827 if (tx == 0)
828 x--;
829 }
830 }
831 break;
832 case 3:
833 for (tx = 0; tx < GULF_STREAM_WIDTH; tx++)
834 {
835 gulf_stream_speed[tx][y] = rndm (GULF_STREAM_BASE_SPEED, GULF_STREAM_BASE_SPEED + 10);
836 gulf_stream_dir[tx][y] = 7;
837 }
838 break;
839 case 4:
840 case 5:
841 case 6:
842 for (tx = 0; tx < GULF_STREAM_WIDTH; tx++)
843 {
844 gulf_stream_speed[tx][y] = rndm (GULF_STREAM_BASE_SPEED, GULF_STREAM_BASE_SPEED + 10);
845 if (x == WEATHERMAPTILESX - 1)
846 gulf_stream_dir[tx][y] = 7;
847 else
848 {
849 gulf_stream_dir[tx][y] = 6;
850 if (tx == 0)
851 x++;
852 }
853 }
854 break;
855 }
856 }
857 }
858 else
859 { /* go right to left */
860 for (y = 0; y < WEATHERMAPTILESY; y++)
861 {
862 switch (rndm (0, 6))
863 {
864 case 0:
865 case 1:
866 case 2:
867 for (tx = 0; tx < GULF_STREAM_WIDTH; tx++)
868 {
869 gulf_stream_speed[tx][y] = rndm (GULF_STREAM_BASE_SPEED, GULF_STREAM_BASE_SPEED + 10);
870 if (x == 0)
871 gulf_stream_dir[tx][y] = 3;
872 else
873 {
874 gulf_stream_dir[tx][y] = 2;
875 if (tx == 0)
876 x--;
877 }
878 }
879 break;
880 case 3:
881 for (tx = 0; tx < GULF_STREAM_WIDTH; tx++)
882 {
883 gulf_stream_speed[tx][y] = rndm (GULF_STREAM_BASE_SPEED, GULF_STREAM_BASE_SPEED + 10);
884 gulf_stream_dir[tx][y] = 3;
885 }
886 break;
887 case 4:
888 case 5:
889 case 6:
890 for (tx = 0; tx < GULF_STREAM_WIDTH; tx++)
891 {
892 gulf_stream_speed[tx][y] = rndm (GULF_STREAM_BASE_SPEED, GULF_STREAM_BASE_SPEED + 10);
893 if (x == WEATHERMAPTILESX - 1)
894 gulf_stream_dir[tx][y] = 3;
895 else
896 {
897 gulf_stream_dir[tx][y] = 4;
898 if (tx == 0)
899 x++;
900 }
901 }
902 break;
903 }
904 }
905 } /* done */
906}
907
908/* humidity */
909
910static void
911write_humidmap (void)
912{
913 char filename[MAX_BUF];
914 FILE *fp;
915 int x, y;
916
917 sprintf (filename, "%s/humidmap", settings.localdir);
918 if ((fp = fopen (filename, "w")) == NULL)
919 {
920 LOG (llevError, "Cannot open %s for writing\n", filename);
921 return;
922 }
923 for (x = 0; x < WEATHERMAPTILESX; x++)
924 {
925 for (y = 0; y < WEATHERMAPTILESY; y++)
926 fprintf (fp, "%d ", weathermap[x][y].humid);
927 fprintf (fp, "\n");
928 }
929 fclose (fp);
930}
931
932static void
933read_humidmap (void)
934{
935 char filename[MAX_BUF];
936 FILE *fp;
937 int x, y, d;
938
939 sprintf (filename, "%s/humidmap", settings.localdir);
940 LOG (llevDebug, "Reading humidity data from %s...", filename);
941 if ((fp = fopen (filename, "r")) == NULL)
942 {
943 LOG (llevError, "Cannot open %s for reading\n", filename);
944 LOG (llevDebug, "Initializing humidity and elevation maps...");
945 init_humid_elev ();
946 write_elevmap ();
947 write_humidmap ();
948 write_watermap ();
949 LOG (llevDebug, "Done\n");
950 return;
951 }
952 for (x = 0; x < WEATHERMAPTILESX; x++)
953 {
954 for (y = 0; y < WEATHERMAPTILESY; y++)
955 {
956 fscanf (fp, "%d ", &d);
957 weathermap[x][y].humid = d;
958 if (weathermap[x][y].humid < 0 || weathermap[x][y].humid > 100)
959 weathermap[x][y].humid = rndm (0, 100);
960 }
961 fscanf (fp, "\n");
962 }
963 LOG (llevDebug, "Done.\n");
964 fclose (fp);
965}
966
967/* average elevation */
968
969static void
970write_elevmap (void)
971{
972 char filename[MAX_BUF];
973 FILE *fp;
974 int x, y;
975
976 sprintf (filename, "%s/elevmap", settings.localdir);
977 if ((fp = fopen (filename, "w")) == NULL)
978 {
979 LOG (llevError, "Cannot open %s for writing\n", filename);
980 return;
981 }
982 for (x = 0; x < WEATHERMAPTILESX; x++)
983 {
984 for (y = 0; y < WEATHERMAPTILESY; y++)
985 fprintf (fp, "%d ", weathermap[x][y].avgelev);
986 fprintf (fp, "\n");
987 }
988 fclose (fp);
989}
990
991static void
992read_elevmap (void)
993{
994 char filename[MAX_BUF];
995 FILE *fp;
996 int x, y;
997
998 sprintf (filename, "%s/elevmap", settings.localdir);
999 LOG (llevDebug, "Reading elevation data from %s...", filename);
1000 if ((fp = fopen (filename, "r")) == NULL)
1001 {
1002 LOG (llevError, "Cannot open %s for reading\n", filename);
1003 /* initializing these is expensive, and should have been done
1004 by the humidity. It's not worth the wait to do it twice. */
1005 return;
1006 }
1007 for (x = 0; x < WEATHERMAPTILESX; x++)
1008 {
1009 for (y = 0; y < WEATHERMAPTILESY; y++)
1010 {
1011 fscanf (fp, "%d ", &weathermap[x][y].avgelev);
1012 if (weathermap[x][y].avgelev < -10000 || weathermap[x][y].avgelev > 15000)
1013 weathermap[x][y].avgelev = rndm (-1000, 10000);
1014 }
1015 fscanf (fp, "\n");
1016 }
1017 LOG (llevDebug, "Done.\n");
1018 fclose (fp);
1019}
1020
1021/* water % */
1022
1023static void
1024write_watermap (void)
1025{
1026 char filename[MAX_BUF];
1027 FILE *fp;
1028 int x, y;
1029
1030 sprintf (filename, "%s/watermap", settings.localdir);
1031 if ((fp = fopen (filename, "w")) == NULL)
1032 {
1033 LOG (llevError, "Cannot open %s for writing\n", filename);
1034 return;
1035 }
1036 for (x = 0; x < WEATHERMAPTILESX; x++)
1037 {
1038 for (y = 0; y < WEATHERMAPTILESY; y++)
1039 fprintf (fp, "%d ", weathermap[x][y].water);
1040 fprintf (fp, "\n");
1041 }
1042 fclose (fp);
1043}
1044
1045static void
1046read_watermap (void)
1047{
1048 char filename[MAX_BUF];
1049 FILE *fp;
1050 int x, y, d;
1051
1052 sprintf (filename, "%s/watermap", settings.localdir);
1053 LOG (llevDebug, "Reading water data from %s...", filename);
1054 if ((fp = fopen (filename, "r")) == NULL)
1055 {
1056 LOG (llevError, "Cannot open %s for reading\n", filename);
1057 /* initializing these is expensive, and should have been done
1058 by the humidity. It's not worth the wait to do it twice. */
1059 return;
1060 }
1061 for (x = 0; x < WEATHERMAPTILESX; x++)
1062 {
1063 for (y = 0; y < WEATHERMAPTILESY; y++)
1064 {
1065 fscanf (fp, "%d ", &d);
1066 weathermap[x][y].water = d;
1067 if (weathermap[x][y].water > 100)
1068 weathermap[x][y].water = rndm (0, 100);
1069 }
1070 fscanf (fp, "\n");
1071 }
1072 LOG (llevDebug, "Done.\n");
1073 fclose (fp);
1074}
1075
1076/*
1077 * initialize both humidity and elevation
1078 */
1079
1080static void
1081init_humid_elev (void)
1082{
1083 int x, y, tx, ty, nx, ny, ax, ay, j;
1084 int spwtx, spwty;
1085 const char *mapname;
1086 long int elev;
1087 int water, space;
1088 mapstruct *m;
1089
1090 /* handling of this is kinda nasty. For that reason,
1091 * we do the elevation here too. Not because it makes the
1092 * code cleaner, or makes handling easier, but because I do *not*
1093 * want to maintain two of these nightmares.
1094 */
1095
1096 spwtx = (settings.worldmaptilesx * settings.worldmaptilesizex) / WEATHERMAPTILESX;
1097 spwty = (settings.worldmaptilesy * settings.worldmaptilesizey) / WEATHERMAPTILESY;
1098 for (x = 0; x < WEATHERMAPTILESX; x++)
1099 {
1100 for (y = 0; y < WEATHERMAPTILESY; y++)
1101 {
1102 water = 0;
1103 elev = 0;
1104 nx = 0;
1105 ny = 0;
1106 space = 0;
1107
1108 /* top left */
1109 mapname = weathermap_to_worldmap_corner (x, y, &tx, &ty, 8);
1110 m = load_original_map (mapname, 0);
1111 if (m == NULL)
1112 continue;
1113 m = load_overlay_map (mapname, m);
1114 if (m == NULL)
1115 continue;
1116 for (nx = 0, ax = tx; (nx < spwtx && (uint32) ax < settings.worldmaptilesizex && space < spwtx * spwty); ax++, nx++)
1117 {
1118 for (ny = 0, ay = ty; (ny < spwty && (uint32) ay < settings.worldmaptilesizey && space < spwtx * spwty); ay++, ny++, space++)
1119 if (GET_MAP_OB (m, ax, ay))
1120 {
1121 if (QUERY_FLAG (GET_MAP_OB (m, ax, ay), FLAG_IS_WATER))
1122 water++;
1123 elev += GET_MAP_OB (m, ax, ay)->elevation;
1124 }
1125 }
1126 delete_map (m);
1127
1128 /* bottom left */
1129 mapname = weathermap_to_worldmap_corner (x, y, &tx, &ty, 6);
1130 m = load_original_map (mapname, 0);
1131 if (m == NULL)
1132 continue;
1133 m = load_overlay_map (mapname, m);
1134 if (m == NULL)
1135 continue;
1136 j = ny;
1137 for (nx = 0, ax = tx; (nx < spwtx && (uint32) ax < settings.worldmaptilesizex && space < spwtx * spwty); ax++, nx++)
1138 {
1139 for (ny = j, ay = MAX (0, ty - (spwty - 1)); (ny < spwty && ay <= ty && space < spwtx * spwty); space++, ay++, ny++)
1140 if (GET_MAP_OB (m, ax, ay))
1141 {
1142 if (QUERY_FLAG (GET_MAP_OB (m, ax, ay), FLAG_IS_WATER))
1143 water++;
1144 elev += GET_MAP_OB (m, ax, ay)->elevation;
1145 }
1146 }
1147 delete_map (m);
1148
1149 /* top right */
1150 mapname = weathermap_to_worldmap_corner (x, y, &tx, &ty, 2);
1151 m = load_original_map (mapname, 0);
1152 if (m == NULL)
1153 continue;
1154 m = load_overlay_map (mapname, m);
1155 if (m == NULL)
1156 continue;
1157 for (ax = MAX (0, tx - (spwtx - 1)); (nx < spwtx && ax < tx && space < spwtx * spwty); ax++, nx++)
1158 {
1159 for (ny = 0, ay = ty; (ny < spwty && (uint32) ay < settings.worldmaptilesizey && space < spwtx * spwty); ay++, ny++, space++)
1160 if (GET_MAP_OB (m, ax, ay))
1161 {
1162 if (QUERY_FLAG (GET_MAP_OB (m, ax, ay), FLAG_IS_WATER))
1163 water++;
1164 elev += GET_MAP_OB (m, ax, ay)->elevation;
1165 }
1166 }
1167 delete_map (m);
1168
1169 /* bottom left */
1170 mapname = weathermap_to_worldmap_corner (x, y, &tx, &ty, 4);
1171 m = load_original_map (mapname, 0);
1172 if (m == NULL)
1173 continue;
1174 m = load_overlay_map (mapname, m);
1175 if (m == NULL)
1176 continue;
1177 for (nx = 0, ax = MAX (0, tx - (spwtx - 1)); (nx < spwtx && ax < tx && space < spwtx * spwty); ax++, nx++)
1178 {
1179 for (ny = 0, ay = MAX (0, ty - (spwty - 1)); (ny < spwty && ay <= ty && space < spwtx * spwty); space++, ay++, ny++)
1180 if (GET_MAP_OB (m, ax, ay))
1181 {
1182 if (QUERY_FLAG (GET_MAP_OB (m, ax, ay), FLAG_IS_WATER))
1183 water++;
1184 elev += GET_MAP_OB (m, ax, ay)->elevation;
1185 }
1186 }
1187 delete_map (m);
1188 /* jesus thats confusing as all hell */
1189 weathermap[x][y].humid = water * 100 / (spwtx * spwty);
1190 weathermap[x][y].avgelev = elev / (spwtx * spwty);
1191 weathermap[x][y].water = weathermap[x][y].humid;
1192 }
1193 }
1194
1195 /* and this does all the real work */
1196 for (x = 0; x < WEATHERMAPTILESX; x++)
1197 for (y = 0; y < WEATHERMAPTILESY; y++)
1198 weathermap[x][y].humid = humid_tile (x, y);
1199}
1200
1201/* temperature */
1202
1203static void
1204write_temperaturemap (void)
1205{
1206 char filename[MAX_BUF];
1207 FILE *fp;
1208 int x, y;
1209
1210 sprintf (filename, "%s/temperaturemap", settings.localdir);
1211 if ((fp = fopen (filename, "w")) == NULL)
1212 {
1213 LOG (llevError, "Cannot open %s for writing\n", filename);
1214 return;
1215 }
1216 for (x = 0; x < WEATHERMAPTILESX; x++)
1217 {
1218 for (y = 0; y < WEATHERMAPTILESY; y++)
1219 fprintf (fp, "%d ", weathermap[x][y].temp);
1220 fprintf (fp, "\n");
1221 }
1222 fclose (fp);
1223}
1224
1225static void
1226read_temperaturemap (void)
1227{
1228 char filename[MAX_BUF];
1229 FILE *fp;
1230 int x, y;
1231
1232 sprintf (filename, "%s/temperaturemap", settings.localdir);
1233 LOG (llevDebug, "Reading temperature data from %s...", filename);
1234 if ((fp = fopen (filename, "r")) == NULL)
1235 {
1236 LOG (llevError, "Cannot open %s for reading\n", filename);
1237 init_temperature ();
1238 write_temperaturemap ();
1239 return;
1240 }
1241 for (x = 0; x < WEATHERMAPTILESX; x++)
1242 {
1243 for (y = 0; y < WEATHERMAPTILESY; y++)
1244 {
1245 fscanf (fp, "%hd ", &weathermap[x][y].temp);
1246 if (weathermap[x][y].temp < -30 || weathermap[x][y].temp > 60)
1247 weathermap[x][y].temp = rndm (-10, 40);
1248 }
1249 fscanf (fp, "\n");
1250 }
1251 LOG (llevDebug, "Done.\n");
1252 fclose (fp);
1253}
1254
1255static void
1256init_temperature (void)
1257{
1258 int x, y;
1259 timeofday_t tod;
1260
1261 get_tod (&tod);
1262 for (x = 0; x < WEATHERMAPTILESX; x++)
1263 for (y = 0; y < WEATHERMAPTILESY; y++)
1264 temperature_calc (x, y, &tod);
1265}
1266
1267/* rainfall */
1268
1269static void
1270write_rainfallmap (void)
1271{
1272 char filename[MAX_BUF];
1273 FILE *fp;
1274 int x, y;
1275
1276 sprintf (filename, "%s/rainfallmap", settings.localdir);
1277 if ((fp = fopen (filename, "w")) == NULL)
1278 {
1279 LOG (llevError, "Cannot open %s for writing\n", filename);
1280 return;
1281 }
1282 for (x = 0; x < WEATHERMAPTILESX; x++)
1283 {
1284 for (y = 0; y < WEATHERMAPTILESY; y++)
1285 fprintf (fp, "%u ", weathermap[x][y].rainfall);
1286 fprintf (fp, "\n");
1287 }
1288 fclose (fp);
1289}
1290
1291static void
1292read_rainfallmap (void)
1293{
1294 char filename[MAX_BUF];
1295 FILE *fp;
1296 int x, y;
1297
1298 sprintf (filename, "%s/rainfallmap", settings.localdir);
1299 LOG (llevDebug, "Reading rainfall data from %s...", filename);
1300 if ((fp = fopen (filename, "r")) == NULL)
1301 {
1302 LOG (llevError, "Cannot open %s for reading\n", filename);
1303 init_rainfall ();
1304 write_rainfallmap ();
1305 return;
1306 }
1307 for (x = 0; x < WEATHERMAPTILESX; x++)
1308 {
1309 for (y = 0; y < WEATHERMAPTILESY; y++)
1310 {
1311 fscanf (fp, "%u ", &weathermap[x][y].rainfall);
1312 }
1313 fscanf (fp, "\n");
1314 }
1315 LOG (llevDebug, "Done.\n");
1316 fclose (fp);
1317}
1318
1319static void
1320init_rainfall (void)
1321{
1322 int x, y;
1323 int days;
1324
1325 for (x = 0; x < WEATHERMAPTILESX; x++)
1326 for (y = 0; y < WEATHERMAPTILESY; y++)
1327 {
1328 days = todtick / HOURS_PER_DAY;
1329 if (weathermap[x][y].humid < 10)
1330 weathermap[x][y].rainfall = days / 20;
1331 else if (weathermap[x][y].humid < 20)
1332 weathermap[x][y].rainfall = days / 15;
1333 else if (weathermap[x][y].humid < 30)
1334 weathermap[x][y].rainfall = days / 10;
1335 else if (weathermap[x][y].humid < 40)
1336 weathermap[x][y].rainfall = days / 5;
1337 else if (weathermap[x][y].humid < 50)
1338 weathermap[x][y].rainfall = days / 2;
1339 else if (weathermap[x][y].humid < 60)
1340 weathermap[x][y].rainfall = days;
1341 else if (weathermap[x][y].humid < 80)
1342 weathermap[x][y].rainfall = days * 2;
1343 else
1344 weathermap[x][y].rainfall = days * 3;
1345 }
1346}
1347
1348/* END of read/write/init */
1349
1350
1351
1352static void
1353init_weatheravoid (weather_avoids_t wa[])
1354{
1355 int i;
1356
1357 for (i = 0; wa[i].name != NULL; i++)
1358 {
1359 wa[i].what = archetype::find (wa[i].name);
1360 }
1361}
1362
1363static int wmperformstartx;
1364static int wmperformstarty;
1365
1366/*
1367 * This function initializes the weather system. It should be called once,
1368 * at game startup only.
1369 */
1370
1371
1372void
1373init_weather (void)
1374{
1375 int y, tx, ty;
1376 char filename[MAX_BUF];
1377 FILE *fp;
1378
1379 /* all this stuff needs to be set, otherwise this function will cause
1380 * chaos and destruction.
1381 */
1382 if (settings.dynamiclevel < 1)
1383 return;
1384 if (settings.worldmapstartx < 1 || settings.worldmapstarty < 1 ||
1385 settings.worldmaptilesx < 1 || settings.worldmaptilesy < 1 || settings.worldmaptilesizex < 1 || settings.worldmaptilesizex < 1)
1386 return;
1387 /*prepare structures used for avoidance */
1388 init_weatheravoid (weather_avoids);
1389 init_weatheravoid (growth_avoids);
1390
1391
1392 LOG (llevDebug, "Initializing the weathermap...\n");
1393
1394 weathermap = (weathermap_t **) malloc (sizeof (weathermap_t *) * WEATHERMAPTILESX);
1395 if (weathermap == NULL)
1396 fatal (OUT_OF_MEMORY);
1397 for (y = 0; y < WEATHERMAPTILESY; y++)
1398 {
1399 weathermap[y] = (weathermap_t *) malloc (sizeof (weathermap_t) * WEATHERMAPTILESY);
1400 if (weathermap[y] == NULL)
1401 fatal (OUT_OF_MEMORY);
1402 }
1403 /* now we load the values in the big worldmap weather array */
1404 /* do not re-order these */
1405 read_pressuremap ();
1406 read_winddirmap ();
1407 read_windspeedmap ();
1408 read_gulfstreammap ();
1409 read_watermap ();
1410 read_humidmap ();
1411 read_elevmap (); /* elevation must allways follow humidity */
1412 read_temperaturemap ();
1413 gulf_stream_direction = rndm (0, 1);
1414 for (tx = 0; tx < GULF_STREAM_WIDTH; tx++)
1415 for (ty = 0; ty < WEATHERMAPTILESY - 1; ty++)
1416 if (gulf_stream_direction)
1417 switch (gulf_stream_dir[tx][ty])
1418 {
1419 case 2:
1420 gulf_stream_dir[tx][ty] = 6;
1421 break;
1422 case 3:
1423 gulf_stream_dir[tx][ty] = 7;
1424 break;
1425 case 4:
1426 gulf_stream_dir[tx][ty] = 8;
1427 break;
1428 }
1429 else
1430 switch (gulf_stream_dir[tx][ty])
1431 {
1432 case 6:
1433 gulf_stream_dir[tx][ty] = 2;
1434 break;
1435 case 7:
1436 gulf_stream_dir[tx][ty] = 3;
1437 break;
1438 case 8:
1439 gulf_stream_dir[tx][ty] = 4;
1440 break;
1441 }
1442 gulf_stream_start = rndm (GULF_STREAM_WIDTH, WEATHERMAPTILESY - GULF_STREAM_WIDTH);
1443 read_rainfallmap ();
1444
1445 LOG (llevDebug, "Done reading weathermaps\n");
1446 sprintf (filename, "%s/wmapcurpos", settings.localdir);
1447 LOG (llevDebug, "Reading current weather position from %s...", filename);
1448 if ((fp = fopen (filename, "r")) == NULL)
1449 {
1450 LOG (llevError, "Can't open %s.\n", filename);
1451 wmperformstartx = -1;
1452 return;
1453 }
1454 fscanf (fp, "%d %d", &wmperformstartx, &wmperformstarty);
1455 LOG (llevDebug, "curposx=%d curposy=%d\n", wmperformstartx, wmperformstarty);
1456 fclose (fp);
1457 if ((uint32) wmperformstartx > settings.worldmaptilesx)
1458 wmperformstartx = -1;
1459 if ((uint32) wmperformstarty > settings.worldmaptilesy)
1460 wmperformstarty = 0;
1461}
1462
1463/*
1464 * This routine slowly loads the world, patches it up due to the weather,
1465 * and saves it back to disk. In this way, the world constantly feels the
1466 * effects of weather uniformly, without relying on players wandering.
1467 *
1468 * The main point of this is stuff like growing herbs, soil, decaying crap,
1469 * etc etc etc. Not actual *weather*, but weather *effects*.
1470 */
1471
1472static void
1473perform_weather (void)
1474{
1475 mapstruct *m;
1476 char filename[MAX_BUF];
1477 FILE *fp;
1478
1479 if (!settings.dynamiclevel)
1480 return;
1481
1482 /* move right to left, top to bottom */
1483 if ((uint32) wmperformstartx + 1 == settings.worldmaptilesx)
1484 {
1485 wmperformstartx = 0;
1486 wmperformstarty++;
1487 }
1488 else
1489 wmperformstartx++;
1490 if ((uint32) wmperformstarty == settings.worldmaptilesy)
1491 wmperformstartx = wmperformstarty = 0;
1492
1493 sprintf (filename, "world/world_%d_%d", wmperformstartx + settings.worldmapstartx, wmperformstarty + settings.worldmapstarty);
1494
1495 m = ready_map_name (filename, 0);
1496 if (m == NULL)
1497 return; /* hrmm */
1498
1499 /* for now, all we do is decay stuff. more to come */
1500 decay_objects (m);
1501 weather_effect (filename);
1502
1503 /* done */
1504 new_save_map (m, 2); /* write the overlay */
1505 m->in_memory = MAP_IN_MEMORY; /*reset this */
1506 sprintf (filename, "%s/wmapcurpos", settings.localdir);
1507 if ((fp = fopen (filename, "w")) == NULL)
1508 {
1509 LOG (llevError, "Cannot open %s for writing\n", filename);
1510 return;
1511 }
1512
1513 if (players_on_map (m, TRUE) == 0)
1514 delete_map (m);
1515
1516 fprintf (fp, "%d %d", wmperformstartx, wmperformstarty);
1517 fclose (fp);
1518}
1519
1520/*
1521 * perform actual effect of weather. Should be called from perform_weather,
1522 * or when a map is loaded. (player enter map). Filename is the name of
1523 * the map. The map *must allready be loaded*.
1524 *
1525 * This is where things like snow, herbs, earthly rototilling, etc should
1526 * occur.
1527 */
1528
1529void
1530weather_effect (const char *filename)
1531{
1532 mapstruct *m;
1533 int wx, wy, x, y;
1534
1535 /* if the dm shut off weather, go home */
1536 if (settings.dynamiclevel < 1)
1537 return;
1538
1539 m = ready_map_name (filename, 0);
1540 if (!m->outdoor)
1541 return;
1542
1543 x = 0;
1544 y = 0;
1545 /* for now, just bail if it's not the worldmap */
1546 if (worldmap_to_weathermap (x, y, &wx, &wy, m) != 0)
1547 return;
1548 /*First, calculate temperature */
1549 calculate_temperature (m, wx, wy);
1550 /* we change the world first, if needed */
1551 if (settings.dynamiclevel >= 5)
1552 {
1553 change_the_world (m, wx, wy);
1554 }
1555 if (settings.dynamiclevel >= 2)
1556 {
1557 let_it_snow (m, wx, wy);
1558 singing_in_the_rain (m, wx, wy);
1559 }
1560 /* if (settings.dynamiclevel >= 4) {
1561 feather_map(m, wx, wy, filename);
1562 } */
1563 if (settings.dynamiclevel >= 3)
1564 {
1565 plant_a_garden (m, wx, wy);
1566 }
1567}
1568
1569/*
1570 * Check the current square to see if we should avoid this one for
1571 * weather processing. Must pass av and gs, which will be filled in
1572 * with 1 or 0. gs will be 1 if we found snow/rain here. av will be
1573 * 1 if we should avoid processing this tile. (don't rain on lakes)
1574 * x and y are the coordinates inside the current map m. If grow is
1575 * 1, we use the growth table, rather than the avoidance table.
1576 *
1577 * Returns the object pointer for any snow item it found, so you can
1578 * destroy/melt it.
1579 */
1580
1581static object *
1582avoid_weather (int *av, mapstruct *m, int x, int y, int *gs, int grow)
1583{
1584 int avoid, gotsnow, i, n;
1585
1586 object *tmp;
1587
1588 avoid = 0;
1589 gotsnow = 0;
1590 if (grow)
1591 {
1592 for (tmp = GET_MAP_OB (m, x, y), n = 0; tmp; tmp = tmp->above, n++)
1593 {
1594 /* look for things like walls, holes, etc */
1595 if (n)
1596 if (!QUERY_FLAG (tmp, FLAG_IS_FLOOR) && !(tmp->material & M_ICE || tmp->material & M_LIQUID))
1597 gotsnow++;
1598 for (i = 0; growth_avoids[i].name != NULL; i++)
1599 {
1600 /*if (!strcmp(tmp->arch->name, growth_avoids[i].name)) { */
1601 if (tmp->arch == growth_avoids[i].what)
1602 {
1603 avoid++;
1604 break;
1605 }
1606 }
1607 if (!strncmp (tmp->arch->name, "biglake_", 8))
1608 {
1609 avoid++;
1610 break;
1611 }
1612 if (avoid)
1613 break;
1614 }
1615 }
1616 else
1617 {
1618 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
1619 {
1620 for (i = 0; weather_avoids[i].name != NULL; i++)
1621 {
1622 /*if (!strcmp(tmp->arch->name, weather_avoids[i].name)) { */
1623 if (tmp->arch == weather_avoids[i].what)
1624 {
1625 if (weather_avoids[i].snow == 1)
1626 gotsnow++;
1627 else
1628 avoid++;
1629 break;
1630 }
1631 }
1632 if (avoid || gotsnow)
1633 break;
1634 }
1635 }
1636 *gs = gotsnow;
1637 *av = avoid;
1638 return tmp;
1639}
1640
1641/* Temperature is used in a lot of weather function.
1642 * This need to be precalculated before used.
1643 */
1644static void
1645calculate_temperature (mapstruct *m, int wx, int wy)
1646{
1647 uint32 x, y;
1648
1649 for (x = 0; x < settings.worldmaptilesizex; x++)
1650 {
1651 for (y = 0; y < settings.worldmaptilesizey; y++)
1652 {
1653 weathermap[wx][wy].realtemp = real_world_temperature (x, y, m);
1654 }
1655 }
1656}
1657
1658/*
1659 * Process snow. m is the map we are currently processing. wx and wy are
1660 * the weathermap coordinates for the weathermap square we want to work on.
1661 * filename is the pathname for the current map. This should be called from
1662 * weather_effect()
1663 */
1664
1665static void
1666let_it_snow (mapstruct *m, int wx, int wy)
1667{
1668 int x, y, i;
1669 uint32 nx, ny, j, d;
1670 int avoid, two, temp, sky, gotsnow, found, nodstk;
1671 const char *doublestack, *doublestack2;
1672 object *ob, *tmp, *oldsnow, *topfloor;
1673 archetype *at;
1674
1675 for (nx = 0; nx < settings.worldmaptilesizex; nx++)
1676 {
1677 for (ny = 0; ny < settings.worldmaptilesizey; ny++)
1678 {
1679 /* jitter factor */
1680 if (rndm (0, 2) > 0)
1681 {
1682 x = y = d = -1;
1683 while (OUT_OF_REAL_MAP (m, x, y))
1684 {
1685 d++;
1686 j = rndm (1, 8);
1687 x = nx + freearr_x[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
1688 y = ny + freearr_y[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
1689 if (d > 15)
1690 {
1691 x = nx;
1692 y = ny;
1693 }
1694 }
1695 }
1696 else
1697 {
1698 x = nx;
1699 y = ny;
1700 }
1701 /* we use the unjittered coordinates */
1702 (void) worldmap_to_weathermap (nx, ny, &wx, &wy, m);
1703 ob = NULL;
1704 at = NULL;
1705 /* this will definately need tuning */
1706 avoid = 0;
1707 two = 0;
1708 gotsnow = 0;
1709 nodstk = 0;
1710 /*temp = real_world_temperature(x, y, m); */
1711 temp = weathermap[wx][wy].realtemp;
1712 sky = weathermap[wx][wy].sky;
1713 if (temp <= 0 && sky > SKY_OVERCAST && sky < SKY_FOG)
1714 sky += 10; /*let it snow */
1715 oldsnow = avoid_weather (&avoid, m, x, y, &gotsnow, 0);
1716 if (!avoid)
1717 {
1718 if (sky >= SKY_LIGHT_SNOW && sky < SKY_HEAVY_SNOW)
1719 at = archetype::find (weather_replace[0].special_snow);
1720 if (sky >= SKY_HEAVY_SNOW)
1721 at = archetype::find (weather_replace[1].special_snow);
1722 if (sky >= SKY_LIGHT_SNOW)
1723 {
1724 /* the bottom floor of scorn is not IS_FLOOR */
1725 topfloor = NULL;
1726 for (tmp = GET_MAP_OB (m, x, y); tmp; topfloor = tmp, tmp = tmp->above)
1727 {
1728 if (strcmp (tmp->arch->name, "dungeon_magic") != 0)
1729 if (!QUERY_FLAG (tmp, FLAG_IS_FLOOR))
1730 break;
1731 }
1732 /* topfloor should now be the topmost IS_FLOOR=1 */
1733 if (topfloor == NULL)
1734 continue;
1735 if (tmp != NULL)
1736 nodstk++;
1737 /* something is wrong with that sector. just skip it */
1738 found = 0;
1739 for (i = 0; weather_replace[i].tile != NULL; i++)
1740 {
1741 if (weather_replace[i].arch_or_name == 1)
1742 {
1743 if (!strcmp (topfloor->arch->name, weather_replace[i].tile))
1744 found++;
1745 }
1746 else
1747 {
1748 if (!strcmp (topfloor->name, weather_replace[i].tile))
1749 found++;
1750 }
1751 if (found)
1752 {
1753 if (weather_replace[i].special_snow != NULL)
1754 at = archetype::find (weather_replace[i].special_snow);
1755 if (weather_replace[i].doublestack_arch != NULL && !nodstk)
1756 {
1757 two++;
1758 doublestack = weather_replace[i].doublestack_arch;
1759 }
1760 break;
1761 }
1762 }
1763 }
1764 if (gotsnow && at)
1765 {
1766 if (!strcmp (oldsnow->arch->name, at->name))
1767 at = NULL;
1768 else
1769 {
1770 remove_ob (oldsnow);
1771 free_object (oldsnow);
1772 tmp = GET_MAP_OB (m, x, y);
1773 /* clean up the trees we put over the snow */
1774 found = 0;
1775 doublestack2 = NULL;
1776 if (tmp)
1777 for (i = 0; weather_replace[i].tile != NULL; i++)
1778 {
1779 if (weather_replace[i].doublestack_arch == NULL)
1780 continue;
1781 if (weather_replace[i].arch_or_name == 1)
1782 {
1783 if (!strcmp (tmp->arch->name, weather_replace[i].tile))
1784 found++;
1785 }
1786 else
1787 {
1788 if (!strcmp (tmp->name, weather_replace[i].tile))
1789 found++;
1790 }
1791 if (found)
1792 {
1793 tmp = tmp->above;
1794 doublestack2 = weather_replace[i].doublestack_arch;
1795 break;
1796 }
1797 }
1798 if (tmp != NULL && doublestack2 != NULL)
1799 if (strcmp (tmp->arch->name, doublestack2) == 0)
1800 {
1801 remove_ob (tmp);
1802 free_object (tmp);
1803 }
1804 }
1805 }
1806 if (at != NULL)
1807 {
1808 ob = arch_to_object (at);
1809 ob->x = x;
1810 ob->y = y;
1811 ob->material = M_ICE;
1812 SET_FLAG (ob, FLAG_OVERLAY_FLOOR);
1813 CLEAR_FLAG (ob, FLAG_IS_FLOOR);
1814 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
1815 if (two)
1816 {
1817 at = NULL;
1818 at = archetype::find (doublestack);
1819 if (at != NULL)
1820 {
1821 ob = arch_to_object (at);
1822 ob->x = x;
1823 ob->y = y;
1824 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP);
1825 }
1826 }
1827 }
1828 }
1829 if (temp > 8 && GET_MAP_OB (m, x, y) != NULL)
1830 {
1831 /* melt some snow */
1832 for (tmp = GET_MAP_OB (m, x, y)->above; tmp; tmp = tmp->above)
1833 {
1834 avoid = 0;
1835 for (i = 0; weather_replace[i].tile != NULL; i++)
1836 {
1837 if (weather_replace[i].special_snow == NULL)
1838 continue;
1839 if (!strcmp (tmp->arch->name, weather_replace[i].special_snow))
1840 avoid++;
1841 if (avoid)
1842 break;
1843 }
1844 if (avoid)
1845 {
1846 /* replace snow with a big puddle */
1847 remove_ob (tmp);
1848 free_object (tmp);
1849 tmp = GET_MAP_OB (m, x, y);
1850 if (tmp && (!strcmp (tmp->arch->name, "mountain")))
1851 {
1852 at = archetype::find ("mountain1_rivlets");
1853 }
1854 else if (tmp && (!strcmp (tmp->arch->name, "mountain2")))
1855 {
1856 at = archetype::find ("mountain2_rivlets");
1857 }
1858 else if (tmp && (!strcmp (tmp->arch->name, "mountain4")))
1859 {
1860 at = archetype::find ("mountain2_rivlets");
1861 }
1862 else
1863 {
1864 at = archetype::find ("rain5");
1865 }
1866 if (at != NULL)
1867 {
1868 ob = arch_to_object (at);
1869 ob->x = x;
1870 ob->y = y;
1871 SET_FLAG (ob, FLAG_OVERLAY_FLOOR);
1872 ob->material = M_LIQUID;
1873 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
1874 }
1875 }
1876 }
1877 }
1878 /* woo it's cold out */
1879 if (temp < -8)
1880 {
1881 avoid = 0;
1882 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
1883 {
1884 if (!strcasecmp (tmp->name, "ice"))
1885 avoid--;
1886 }
1887 tmp = GET_MAP_OB (m, x, y);
1888 if (tmp && (!strcasecmp (tmp->name, "sea")))
1889 avoid++;
1890 else if (tmp && (!strcasecmp (tmp->name, "sea1")))
1891 avoid++;
1892 else if (tmp && (!strcasecmp (tmp->name, "deep_sea")))
1893 avoid++;
1894 else if (tmp && (!strcasecmp (tmp->name, "shallow_sea")))
1895 avoid++;
1896 if (avoid > 0)
1897 {
1898 at = archetype::find ("ice");
1899 ob = arch_to_object (at);
1900 ob->x = x;
1901 ob->y = y;
1902 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
1903 }
1904 }
1905 }
1906 }
1907}
1908
1909/*
1910 * Process rain. m is the map we are currently processing. wx and wy are
1911 * the weathermap coordinates for the weathermap square we want to work on.
1912 * filename is the pathname for the current map. This should be called from
1913 * weather_effect()
1914 */
1915
1916static void
1917singing_in_the_rain (mapstruct *m, int wx, int wy)
1918{
1919 int x, y, i;
1920 uint32 nx, ny, d, j;
1921 int avoid, two, temp, sky, gotsnow, found, nodstk;
1922 object *ob, *tmp, *oldsnow, *topfloor;
1923 const char *doublestack, *doublestack2;
1924 archetype *at;
1925
1926 for (nx = 0; nx < settings.worldmaptilesizex; nx++)
1927 {
1928 for (ny = 0; ny < settings.worldmaptilesizey; ny++)
1929 {
1930 /* jitter factor */
1931 if (rndm (0, 2) > 0)
1932 {
1933 x = y = d = -1;
1934 while (OUT_OF_REAL_MAP (m, x, y))
1935 {
1936 d++;
1937 j = rndm (1, 8);
1938 x = nx + freearr_x[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
1939 y = ny + freearr_y[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
1940 if (d > 15)
1941 {
1942 x = nx;
1943 y = ny;
1944 }
1945 }
1946 }
1947 else
1948 {
1949 x = nx;
1950 y = ny;
1951 }
1952 /* we use the unjittered coordinates */
1953 (void) worldmap_to_weathermap (nx, ny, &wx, &wy, m);
1954 ob = NULL;
1955 at = NULL;
1956 avoid = 0;
1957 two = 0;
1958 gotsnow = 0;
1959 nodstk = 0;
1960 /*temp = real_world_temperature(x, y, m); */
1961 temp = weathermap[wx][wy].realtemp;
1962 sky = weathermap[wx][wy].sky;
1963 /* it's probably allready snowing */
1964 if (temp < 0)
1965 continue;
1966 oldsnow = avoid_weather (&avoid, m, x, y, &gotsnow, 0);
1967 if (!avoid)
1968 {
1969 tmp = GET_MAP_OB (m, x, y);
1970 if (tmp && (!strcmp (tmp->arch->name, "mountain")))
1971 {
1972 at = archetype::find ("mountain1_rivlets");
1973 break;
1974 }
1975 else if (tmp && (!strcmp (tmp->arch->name, "mountain2")))
1976 {
1977 at = archetype::find ("mountain2_rivlets");
1978 break;
1979 }
1980 else if (tmp && (!strcmp (tmp->arch->name, "mountain4")))
1981 {
1982 at = archetype::find ("mountain2_rivlets");
1983 break;
1984 }
1985 if (sky == SKY_LIGHT_RAIN || sky == SKY_RAIN)
1986 {
1987 switch (rndm (0, SKY_HAIL - sky))
1988 {
1989 case 0:
1990 at = archetype::find ("rain1");
1991 break;
1992 case 1:
1993 at = archetype::find ("rain2");
1994 break;
1995 default:
1996 at = NULL;
1997 }
1998 }
1999 if (sky >= SKY_HEAVY_RAIN && sky <= SKY_HURRICANE)
2000 {
2001 switch (rndm (0, SKY_HAIL - sky))
2002 {
2003 case 0:
2004 at = archetype::find ("rain3");
2005 break;
2006 case 1:
2007 at = archetype::find ("rain4");
2008 break;
2009 case 2:
2010 at = archetype::find ("rain5");
2011 break;
2012 default:
2013 at = NULL;
2014 }
2015 }
2016 /* the bottom floor of scorn is not IS_FLOOR */
2017 topfloor = NULL;
2018 for (tmp = GET_MAP_OB (m, x, y); tmp; topfloor = tmp, tmp = tmp->above)
2019 {
2020 if (strcmp (tmp->arch->name, "dungeon_magic") != 0)
2021 if (!QUERY_FLAG (tmp, FLAG_IS_FLOOR))
2022 break;
2023 }
2024 /* topfloor should now be the topmost IS_FLOOR=1 */
2025 if (topfloor == NULL)
2026 continue;
2027 if (tmp != NULL)
2028 nodstk++;
2029 /* something is wrong with that sector. just skip it */
2030 found = 0;
2031 for (i = 0; weather_replace[i].tile != NULL; i++)
2032 {
2033 if (weather_replace[i].arch_or_name == 1)
2034 {
2035 if (!strcmp (topfloor->arch->name, weather_replace[i].tile))
2036 found++;
2037 }
2038 else
2039 {
2040 if (!strcmp (topfloor->name, weather_replace[i].tile))
2041 found++;
2042 }
2043 if (found)
2044 {
2045 if (weather_replace[i].doublestack_arch != NULL && !nodstk)
2046 {
2047 two++;
2048 doublestack = weather_replace[i].doublestack_arch;
2049 }
2050 break;
2051 }
2052 }
2053 if (gotsnow && at)
2054 {
2055 if (!strcmp (oldsnow->arch->name, at->name))
2056 at = NULL;
2057 else
2058 {
2059 tmp = GET_MAP_OB (m, x, y);
2060 remove_ob (oldsnow);
2061 /* clean up the trees we put over the snow */
2062 found = 0;
2063 doublestack2 = NULL;
2064 for (i = 0; weather_replace[i].tile != NULL; i++)
2065 {
2066 if (weather_replace[i].doublestack_arch == NULL)
2067 continue;
2068 if (weather_replace[i].arch_or_name == 1)
2069 {
2070 if (!strcmp (tmp->arch->name, weather_replace[i].tile))
2071 found++;
2072 }
2073 else
2074 {
2075 if (!strcmp (tmp->name, weather_replace[i].tile))
2076 found++;
2077 }
2078 if (found)
2079 {
2080 tmp = tmp->above;
2081 doublestack2 = weather_replace[i].doublestack_arch;
2082 break;
2083 }
2084 }
2085 free_object (oldsnow);
2086 if (tmp != NULL && doublestack2 != NULL)
2087 if (strcmp (tmp->arch->name, doublestack2) == 0)
2088 {
2089 remove_ob (tmp);
2090 free_object (tmp);
2091 }
2092 }
2093 }
2094 if (at != NULL)
2095 {
2096 ob = arch_to_object (at);
2097 ob->x = x;
2098 ob->y = y;
2099 SET_FLAG (ob, FLAG_OVERLAY_FLOOR);
2100 ob->material = M_LIQUID;
2101 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2102 if (two)
2103 {
2104 at = archetype::find (doublestack);
2105 if (at != NULL)
2106 {
2107 ob = arch_to_object (at);
2108 ob->x = x;
2109 ob->y = y;
2110 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP);
2111 }
2112 }
2113 }
2114 }
2115 /* Things evaporate fast in the heat */
2116 if (GET_MAP_OB (m, x, y) && temp > 8 && sky < SKY_OVERCAST && rndm (temp, 60) > 50)
2117 {
2118 /* evaporate */
2119 for (tmp = GET_MAP_OB (m, x, y)->above; tmp; tmp = tmp->above)
2120 {
2121 avoid = 0;
2122 if (!strcmp (tmp->arch->name, "rain1"))
2123 avoid++;
2124 else if (!strcmp (tmp->arch->name, "rain2"))
2125 avoid++;
2126 else if (!strcmp (tmp->arch->name, "rain3"))
2127 avoid++;
2128 else if (!strcmp (tmp->arch->name, "rain4"))
2129 avoid++;
2130 else if (!strcmp (tmp->arch->name, "rain5"))
2131 avoid++;
2132 else if (!strcmp (tmp->arch->name, "mountain1_rivlets"))
2133 avoid++;
2134 else if (!strcmp (tmp->arch->name, "mountain2_rivlets"))
2135 avoid++;
2136 if (avoid)
2137 {
2138 remove_ob (tmp);
2139 free_object (tmp);
2140 if (weathermap[wx][wy].humid < 100 && rndm (0, 50) == 0)
2141 weathermap[wx][wy].humid++;
2142 tmp = GET_MAP_OB (m, x, y);
2143 /* clean up the trees we put over the rain */
2144 found = 0;
2145 doublestack2 = NULL;
2146 for (i = 0; weather_replace[i].tile != NULL; i++)
2147 {
2148 if (weather_replace[i].doublestack_arch == NULL)
2149 continue;
2150 if (weather_replace[i].arch_or_name == 1)
2151 {
2152 if (!strcmp (tmp->arch->name, weather_replace[i].tile))
2153 found++;
2154 }
2155 else
2156 {
2157 if (!strcmp (tmp->name, weather_replace[i].tile))
2158 found++;
2159 }
2160 if (found)
2161 {
2162 tmp = tmp->above;
2163 doublestack2 = weather_replace[i].doublestack_arch;
2164 break;
2165 }
2166 }
2167 if (tmp != NULL && doublestack2 != NULL)
2168 if (strcmp (tmp->arch->name, doublestack2) == 0)
2169 {
2170 remove_ob (tmp);
2171 free_object (tmp);
2172 }
2173 break;
2174 }
2175 }
2176 }
2177 }
2178 }
2179}
2180
2181/*
2182 * Process growth. m is the map we are currently processing. wx and wy are
2183 * the weathermap coordinates for the weathermap square we want to work on.
2184 * filename is the pathname for the current map. This should be called from
2185 * weather_effect()
2186 */
2187
2188static void
2189plant_a_garden (mapstruct *m, int wx, int wy)
2190{
2191 uint32 x, y, i;
2192 int avoid, two, temp, sky, gotsnow, found, days;
2193 object *ob, *tmp;
2194 archetype *at;
2195
2196 days = todtick / HOURS_PER_DAY;
2197 for (x = 0; x < settings.worldmaptilesizex; x++)
2198 {
2199 for (y = 0; y < settings.worldmaptilesizey; y++)
2200 {
2201 (void) worldmap_to_weathermap (x, y, &wx, &wy, m);
2202 ob = NULL;
2203 at = NULL;
2204 avoid = 0;
2205 two = 0;
2206 gotsnow = 0;
2207 /*temp = real_world_temperature(x, y, m); */
2208 temp = weathermap[wx][wy].realtemp;
2209 sky = weathermap[wx][wy].sky;
2210 (void) avoid_weather (&avoid, m, x, y, &gotsnow, 1);
2211 if (!avoid)
2212 {
2213 found = 0;
2214 for (i = 0; weather_grow[i].herb != NULL; i++)
2215 {
2216 for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
2217 {
2218 if (strcmp (tmp->arch->name, weather_grow[i].herb) != 0)
2219 continue;
2220 /* we found there is a herb here allready */
2221 found++;
2222 if ((float) weathermap[wx][wy].rainfall / days < weather_grow[i].rfmin ||
2223 (float) weathermap[wx][wy].rainfall / days > weather_grow[i].rfmax ||
2224 weathermap[wx][wy].humid < weather_grow[i].humin ||
2225 weathermap[wx][wy].humid > weather_grow[i].humax ||
2226 temp < weather_grow[i].tempmin ||
2227 temp > weather_grow[i].tempmax || rndm (0, MIN (weather_grow[i].random / 2, 1)) == 0)
2228 {
2229 /* the herb does not belong, randomly delete
2230 herbs to prevent overgrowth. */
2231 remove_ob (tmp);
2232 free_object (tmp);
2233 break;
2234 }
2235 }
2236 /* don't doublestack herbs */
2237 if (found)
2238 continue;
2239 /* add a random factor */
2240 if (rndm (1, weather_grow[i].random) != 1)
2241 continue;
2242 /* we look up through two tiles for a matching tile */
2243 if (weather_grow[i].tile != NULL && GET_MAP_OB (m, x, y) != NULL)
2244 {
2245 if (strcmp (GET_MAP_OB (m, x, y)->arch->name, weather_grow[i].tile) != 0)
2246 {
2247 if (GET_MAP_OB (m, x, y)->above != NULL)
2248 {
2249 if (strcmp (GET_MAP_OB (m, x, y)->above->arch->name, weather_grow[i].tile) != 0)
2250 continue;
2251 }
2252 else
2253 continue;
2254 }
2255 }
2256 if ((float) weathermap[wx][wy].rainfall / days < weather_grow[i].rfmin ||
2257 (float) weathermap[wx][wy].rainfall / days > weather_grow[i].rfmax)
2258 continue;
2259 if (weathermap[wx][wy].humid < weather_grow[i].humin || weathermap[wx][wy].humid > weather_grow[i].humax)
2260 continue;
2261 if (temp < weather_grow[i].tempmin || temp > weather_grow[i].tempmax)
2262 continue;
2263 if ((!GET_MAP_OB (m, x, y)) ||
2264 GET_MAP_OB (m, x, y)->elevation < weather_grow[i].elevmin ||
2265 GET_MAP_OB (m, x, y)->elevation > weather_grow[i].elevmax)
2266 continue;
2267 /* we got this far.. must be a match */
2268 at = archetype::find (weather_grow[i].herb);
2269 break;
2270 }
2271 if (at != NULL)
2272 {
2273 ob = arch_to_object (at);
2274 ob->x = x;
2275 ob->y = y;
2276 /* XXX is this right? maybe.. */
2277 SET_FLAG (ob, FLAG_OVERLAY_FLOOR);
2278 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2279 }
2280 }
2281 }
2282 }
2283}
2284
2285/*
2286 * Process worldmap regrowth. m is the map we are currently processing.
2287 * wx and wy are
2288 * the weathermap coordinates for the weathermap square we want to work on.
2289 * This should be called from weather_effect()
2290 */
2291
2292static void
2293change_the_world (mapstruct *m, int wx, int wy)
2294{
2295 int x, y, i;
2296 uint32 nx, ny, j, d;
2297 int avoid, two, temp, sky, gotsnow, found, days;
2298 object *ob, *tmp, *doublestack;
2299 archetype *at, *dat;
2300
2301 days = todtick / HOURS_PER_DAY;
2302 for (nx = 0; nx < settings.worldmaptilesizex; nx++)
2303 {
2304 for (ny = 0; ny < settings.worldmaptilesizey; ny++)
2305 {
2306 /* jitter factor */
2307 if (rndm (0, 2) > 0)
2308 {
2309 x = y = d = -1;
2310 while (OUT_OF_REAL_MAP (m, x, y))
2311 {
2312 d++;
2313 j = rndm (1, 8);
2314 x = nx + freearr_x[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
2315 y = ny + freearr_y[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
2316 if (d > 15)
2317 {
2318 x = nx;
2319 y = ny;
2320 }
2321 }
2322 }
2323 else
2324 {
2325 x = nx;
2326 y = ny;
2327 }
2328 /* we use the unjittered coordinates */
2329 (void) worldmap_to_weathermap (nx, ny, &wx, &wy, m);
2330 ob = NULL;
2331 at = NULL;
2332 dat = NULL;
2333 avoid = 0;
2334 two = 0;
2335 gotsnow = 0;
2336 /*temp = real_world_temperature(x, y, m); */
2337 temp = weathermap[wx][wy].realtemp;
2338 sky = weathermap[wx][wy].sky;
2339 (void) avoid_weather (&avoid, m, x, y, &gotsnow, 1);
2340 if (!avoid)
2341 {
2342 for (i = 0; weather_tile[i].herb != NULL; i++)
2343 {
2344 found = 0;
2345 doublestack = NULL;
2346 if (GET_MAP_OB (m, x, y))
2347 for (tmp = GET_MAP_OB (m, x, y)->above; tmp; tmp = tmp->above)
2348 {
2349 if (weather_tile[i].tile != NULL)
2350 if (strcmp (tmp->arch->name, weather_tile[i].tile) == 0)
2351 {
2352 doublestack = tmp;
2353 continue;
2354 }
2355 if (strcmp (tmp->arch->name, weather_tile[i].herb) != 0)
2356 continue;
2357 if ((float) weathermap[wx][wy].rainfall / days < weather_tile[i].rfmin ||
2358 (float) weathermap[wx][wy].rainfall / days > weather_tile[i].rfmax ||
2359 weathermap[wx][wy].humid < weather_tile[i].humin ||
2360 weathermap[wx][wy].humid > weather_tile[i].humax ||
2361 temp < weather_tile[i].tempmin || temp > weather_tile[i].tempmax)
2362 {
2363 remove_ob (tmp);
2364 free_object (tmp);
2365 if (doublestack)
2366 {
2367 remove_ob (doublestack);
2368 free_object (doublestack);
2369 }
2370 break;
2371 }
2372 else
2373 {
2374 found++; /* there is one here allready. leave it */
2375 break;
2376 }
2377 }
2378 if (found)
2379 break;
2380 /* add a random factor */
2381 if (rndm (1, weather_tile[i].random) != 1)
2382 continue;
2383 if ((float) weathermap[wx][wy].rainfall / days < weather_tile[i].rfmin ||
2384 (float) weathermap[wx][wy].rainfall / days > weather_tile[i].rfmax)
2385 continue;
2386 if (weathermap[wx][wy].humid < weather_tile[i].humin || weathermap[wx][wy].humid > weather_tile[i].humax)
2387 continue;
2388 if (temp < weather_tile[i].tempmin || temp > weather_tile[i].tempmax)
2389 continue;
2390 if ((!GET_MAP_OB (m, x, y)) ||
2391 GET_MAP_OB (m, x, y)->elevation < weather_tile[i].elevmin ||
2392 GET_MAP_OB (m, x, y)->elevation > weather_tile[i].elevmax)
2393 continue;
2394 /* we got this far.. must be a match */
2395 if (GET_MAP_OB (m, x, y) && strcmp (GET_MAP_OB (m, x, y)->arch->name, weather_tile[i].herb) == 0)
2396 break; /* no sense in doubling up */
2397 at = archetype::find (weather_tile[i].herb);
2398 break;
2399 }
2400 if (at != NULL)
2401 {
2402 if (weather_tile[i].tile != NULL && GET_MAP_OB (m, x, y) &&
2403 strcmp (weather_tile[i].tile, GET_MAP_OB (m, x, y)->arch->name) != 0)
2404 dat = archetype::find (weather_tile[i].tile);
2405 if (dat != NULL)
2406 {
2407 ob = arch_to_object (dat);
2408 ob->x = x;
2409 ob->y = y;
2410 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2411 }
2412 if (gotsnow == 0)
2413 {
2414 ob = arch_to_object (at);
2415 ob->x = x;
2416 ob->y = y;
2417 if (dat != NULL)
2418 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP);
2419 else
2420 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2421 }
2422 }
2423 }
2424 }
2425 }
2426}
2427
2428
2429/*
2430 * Reduce the blockiness of the maps. m is the map we are currently processing.
2431 * wx and wy are
2432 * the weathermap coordinates for the weathermap square we want to work on.
2433 * This should be called from weather_effect()
2434 */
2435#if 0
2436static void
2437feather_map (mapstruct *m, int wx, int wy)
2438{
2439 uint32 x, y, i, nx, ny, j;
2440 int avoid, two, gotsnow, nodstk;
2441 object *ob, *tmp, *oldsnow, *topfloor, *ntmp, *ntopfloor;
2442 archetype *at;
2443
2444 for (x = 0; x < settings.worldmaptilesizex; x++)
2445 {
2446 for (y = 0; y < settings.worldmaptilesizey; y++)
2447 {
2448 (void) worldmap_to_weathermap (x, y, &wx, &wy, m);
2449 ob = NULL;
2450 at = NULL;
2451 avoid = 0;
2452 two = 0;
2453 j = 0;
2454 gotsnow = 0;
2455 nodstk = 0;
2456 oldsnow = avoid_weather (&avoid, m, x, y, &gotsnow, 1);
2457 if (avoid)
2458 continue;
2459 if (rndm (0, 20) == 0)
2460 continue;
2461 // the bottom floor of scorn is not IS_FLOOR
2462 topfloor = NULL;
2463 for (tmp = GET_MAP_OB (m, x, y); tmp; topfloor = tmp, tmp = tmp->above)
2464 {
2465 if (strcmp (tmp->arch->name, "dungeon_magic") != 0)
2466 if (!QUERY_FLAG (tmp, FLAG_IS_FLOOR) && !QUERY_FLAG (tmp, FLAG_OVERLAY_FLOOR))
2467 break;
2468 }
2469 // topfloor should now be the topmost IS_FLOOR=1
2470 if (topfloor == NULL)
2471 continue;
2472 if (tmp != NULL)
2473 nodstk++;
2474 // something is wrong with that sector. just skip it
2475
2476 j = rndm (1, 8);
2477 nx = freearr_x[j] + x;
2478 ny = freearr_y[j] + y;
2479 if (OUT_OF_REAL_MAP (m, nx, ny))
2480 continue;
2481 oldsnow = avoid_weather (&avoid, m, nx, ny, &gotsnow, 1);
2482 if (avoid)
2483 continue;
2484 ntopfloor = NULL;
2485 for (ntmp = GET_MAP_OB (m, nx, ny); ntmp; ntopfloor = ntmp, ntmp = ntmp->above)
2486 {
2487 if (strcmp (ntmp->arch->name, "dungeon_magic") != 0)
2488 if (!QUERY_FLAG (ntmp, FLAG_IS_FLOOR) && !QUERY_FLAG (ntmp, FLAG_OVERLAY_FLOOR))
2489 break;
2490 }
2491 if (ntopfloor != NULL && QUERY_FLAG (ntopfloor, FLAG_IS_FLOOR))
2492 {
2493 remove_ob (topfloor);
2494 free_object (topfloor);
2495 if (tmp != NULL)
2496 {
2497 for (i = 0; weather_tile[i].herb != NULL; i++)
2498 {
2499 if (strcmp (tmp->arch->name, weather_tile[i].herb) == 0)
2500 {
2501 remove_ob (tmp);
2502 free_object (tmp);
2503 break;
2504 }
2505 }
2506 }
2507 }
2508 else
2509 {
2510 continue;
2511 }
2512 ob = arch_to_object (ntopfloor->arch);
2513 ob->x = x;
2514 ob->y = y;
2515 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2516 if (ntmp != NULL && nodstk == 0)
2517 {
2518 for (i = 0; weather_tile[i].herb != NULL; i++)
2519 {
2520 if (strcmp (ntmp->arch->name, weather_tile[i].herb) == 0)
2521 {
2522 ob = arch_to_object (ntmp->arch);
2523 ob->x = x;
2524 ob->y = y;
2525 insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP);
2526 break;
2527 }
2528 }
2529 }
2530 }
2531 }
2532}
2533#endif
2534
2535/* provide wx and wy. Will fill in with weathermap coordinates. Requires
2536 the current mapname (must be a worldmap), and your coordinates on the
2537 map. returns -1 if you give it something it can't figure out. 0 normally.
2538*/
2539
2540int
2541worldmap_to_weathermap (int x, int y, int *wx, int *wy, mapstruct *m)
2542{
2543 int spwtx, spwty;
2544 uint32 fx, fy;
2545 uint32 nx, ny;
2546 char *filename = m->path;
2547
2548 spwtx = (settings.worldmaptilesx * settings.worldmaptilesizex) / WEATHERMAPTILESX;
2549 spwty = (settings.worldmaptilesy * settings.worldmaptilesizey) / WEATHERMAPTILESY;
2550
2551 while (*filename == '/')
2552 *filename++;
2553
2554 fx = MAP_WORLDPARTX (m);
2555 fy = MAP_WORLDPARTY (m);
2556 if (fx > settings.worldmapstartx + settings.worldmaptilesx ||
2557 fx < settings.worldmapstartx || fy > settings.worldmapstarty + settings.worldmaptilesy || fy < settings.worldmapstarty)
2558 {
2559 LOG (llevDebug, "worldmap_to_weathermap(%s)\n", filename);
2560 sscanf (filename, "world/world_%d_%d", &fx, &fy);
2561 MAP_WORLDPARTX (m) = fx;
2562 MAP_WORLDPARTY (m) = fy;
2563 }
2564 if (fx > settings.worldmapstartx + settings.worldmaptilesx || fx < settings.worldmapstartx)
2565 return -1;
2566 if (fy > settings.worldmapstarty + settings.worldmaptilesy || fy < settings.worldmapstarty)
2567 return -1;
2568 fx -= settings.worldmapstartx;
2569 fy -= settings.worldmapstarty;
2570
2571 nx = fx * settings.worldmaptilesizex + x;
2572 ny = fy * settings.worldmaptilesizey + y;
2573
2574 *wx = nx / spwtx;
2575 *wy = ny / spwty;
2576
2577 return 0;
2578}
2579
2580/* provide x and y. Will fill in with the requested corner of the real
2581 * world map, given the current weathermap section. dir selects which
2582 * corner to return. Valid values are 2 4 6 8 for the corners. return
2583 * value is the name of the map that corner resides in.
2584 */
2585
2586static const char *
2587weathermap_to_worldmap_corner (int wx, int wy, int *x, int *y, int dir)
2588{
2589 int spwtx, spwty;
2590 int tx, ty, nx, ny;
2591 static char mapname[MAX_BUF];
2592
2593 spwtx = (settings.worldmaptilesx * settings.worldmaptilesizex) / WEATHERMAPTILESX;
2594 spwty = (settings.worldmaptilesy * settings.worldmaptilesizey) / WEATHERMAPTILESY;
2595 switch (dir)
2596 {
2597 case 2:
2598 wx++;
2599 break;
2600 case 4:
2601 wx++;
2602 wy++;
2603 break;
2604 case 6:
2605 wy++;
2606 break;
2607 case 8:
2608 break;
2609 }
2610 if (wx > 0)
2611 tx = (wx * spwtx) - 1;
2612 else
2613 tx = wx;
2614 if (wy > 0)
2615 ty = (wy * spwty) - 1;
2616 else
2617 ty = wy;
2618
2619 nx = (tx / settings.worldmaptilesizex) + settings.worldmapstartx;
2620 ny = (ty / settings.worldmaptilesizey) + settings.worldmapstarty;
2621 snprintf (mapname, MAX_BUF, "world/world_%d_%d", nx, ny);
2622
2623 *x = tx % settings.worldmaptilesizex;
2624 *y = ty % settings.worldmaptilesizey;
2625 return mapname;
2626}
2627
2628/*
2629 * Calculates the distance to the nearest pole. x,y are the weathermap
2630 * coordinates, equator is the current location of the equator. returns
2631 * distance as an int.
2632 */
2633
2634
2635static int
2636polar_distance (int x, int y, int equator)
2637{
2638 if ((x + y) > equator)
2639 { /* south pole */
2640 x = WEATHERMAPTILESX - x;
2641 y = WEATHERMAPTILESY - y;
2642 return ((x + y) / 2);
2643 }
2644 else if ((x + y) < equator)
2645 { /* north pole */
2646 return ((x + y) / 2);
2647 }
2648 else
2649 {
2650 return equator / 2;
2651 }
2652}
2653
2654/*
2655 * update the humidity for all weathermap tiles.
2656 */
2657
2658static void
2659update_humid (void)
2660{
2661 int x, y;
2662
2663 for (y = 0; y < WEATHERMAPTILESY; y++)
2664 for (x = 0; x < WEATHERMAPTILESX; x++)
2665 weathermap[x][y].humid = humid_tile (x, y);
2666}
2667
2668/*
2669 * calculate the humidity of this tile. x and y are the weathermap coordinates
2670 * we wish to calculate humidity for. Returns the humidity of the weathermap
2671 * square.
2672 */
2673
2674static int
2675humid_tile (int x, int y)
2676{
2677 int ox, oy, humid;
2678
2679 ox = x;
2680 oy = y;
2681
2682 /* find the square the wind is coming from, without going out of bounds */
2683
2684 if (weathermap[x][y].winddir == 8 || weathermap[x][y].winddir <= 2)
2685 {
2686 if (y != 0)
2687 oy = y - 1;
2688 }
2689 if (weathermap[x][y].winddir >= 6)
2690 {
2691 if (x != 0)
2692 ox = x - 1;
2693 }
2694 if (weathermap[x][y].winddir >= 4 && weathermap[x][y].winddir <= 6)
2695 {
2696 if (y < WEATHERMAPTILESY - 1)
2697 oy = y + 1;
2698 }
2699 if (weathermap[x][y].winddir >= 2 && weathermap[x][y].winddir <= 4)
2700 {
2701 if (x < WEATHERMAPTILESX - 1)
2702 ox = x + 1;
2703 }
2704 humid = (weathermap[x][y].humid * 2 +
2705 weathermap[ox][oy].humid * weathermap[ox][oy].windspeed +
2706 weathermap[x][y].water + rndm (0, 10)) / (weathermap[ox][oy].windspeed + 3) + rndm (0, 5);
2707 if (humid < 0)
2708 humid = 1;
2709 if (humid > 100)
2710 humid = 100;
2711 return humid;
2712}
2713
2714/*
2715 * calculate temperature of the weathermap square x,y. Requires the current
2716 * time of day in *tod.
2717 */
2718
2719static void
2720temperature_calc (int x, int y, const timeofday_t * tod)
2721{
2722 int dist, equator, elev, n;
2723 float diff, tdiff;
2724
2725 equator = (WEATHERMAPTILESX + WEATHERMAPTILESY) / 4;
2726 diff = (float) (EQUATOR_BASE_TEMP - POLAR_BASE_TEMP) / (float) equator;
2727 tdiff = (float) SEASONAL_ADJUST / ((float) MONTHS_PER_YEAR / 2.0);
2728 equator *= 2;
2729 n = 0;
2730 /* we essentially move the equator during the season */
2731 if (tod->month > (MONTHS_PER_YEAR / 2))
2732 { /* EOY */
2733 n -= (int) (tod->month * tdiff);
2734 }
2735 else
2736 {
2737 n = (int) ((MONTHS_PER_YEAR - tod->month) * tdiff);
2738 }
2739 dist = polar_distance (x - n / 2, y - n / 2, equator);
2740
2741 /* now we have the base temp, unadjusted for time. Time adjustment
2742 is not recorded on the map, rather, it's done JIT. */
2743 weathermap[x][y].temp = (int) (dist * diff);
2744 /* just scrap these for now, its mostly ocean */
2745 if (weathermap[x][y].avgelev < 0)
2746 elev = 0;
2747 else
2748 elev = MAX (10000, weathermap[x][y].avgelev) / 1000;
2749 weathermap[x][y].temp -= elev;
2750}
2751
2752/* Compute the real (adjusted) temperature of a given weathermap tile.
2753 * This takes into account the wind, base temp, sunlight, and other fun
2754 * things. Seasons are automatically handled by moving the equator.
2755 * Elevation is partially considered in the base temp. x and y are the
2756 * weathermap coordinates.
2757*/
2758
2759static int
2760real_temperature (int x, int y)
2761{
2762 int i, temp;
2763 timeofday_t tod;
2764
2765 /* adjust for time of day */
2766 temp = weathermap[x][y].temp;
2767 get_tod (&tod);
2768 for (i = HOURS_PER_DAY / 2; i < HOURS_PER_DAY; i++)
2769 {
2770 temp += season_tempchange[i];
2771 /* high amounts of water has a buffering effect on the temp */
2772 if (weathermap[x][y].water > 33)
2773 i++;
2774 }
2775 for (i = 0; i <= tod.hour; i++)
2776 {
2777 temp += season_tempchange[i];
2778 if (weathermap[x][y].water > 33)
2779 i++;
2780 }
2781
2782 /* windchill */
2783 for (i = 1; i < weathermap[x][y].windspeed; i += i)
2784 temp--;
2785
2786 return temp;
2787}
2788
2789/* Given a worldmap name, and x and y on that map, compute the temperature
2790 for a specific square. Used to normalize elevation.
2791*/
2792
2793int
2794real_world_temperature (int x, int y, mapstruct *m)
2795{
2796 int wx, wy, temp, eleva, elevb;
2797 object *op;
2798
2799 /*LOG(llevDebug, "real_world_temperature: worldmaptoweathermap : %s\n",m->path); */
2800 worldmap_to_weathermap (x, y, &wx, &wy, /*m->path */ m);
2801 temp = real_temperature (wx, wy);
2802 if (weathermap[wx][wy].avgelev < 0)
2803 eleva = 0;
2804 else
2805 eleva = weathermap[x][y].avgelev;
2806
2807 op = GET_MAP_OB (m, x, y);
2808 if (!op)
2809 return eleva;
2810
2811 elevb = op->elevation;
2812 if (elevb < 0)
2813 elevb = 0;
2814 if (elevb > eleva)
2815 {
2816 elevb -= eleva;
2817 temp -= elevb / 1000;
2818 }
2819 else
2820 {
2821 elevb = eleva - elevb;
2822 temp += elevb / 1000;
2823 }
2824 return temp;
2825}
2826
2827/* this code simply smooths the pressure map */
2828
2829static void
2830smooth_pressure (void)
2831{
2832 int x, y;
2833 int k;
2834
2835 for (k = 0; k < PRESSURE_ROUNDING_ITER; k++)
2836 {
2837 for (x = 2; x < WEATHERMAPTILESX - 2; x++)
2838 {
2839 for (y = 2; y < WEATHERMAPTILESY - 2; y++)
2840 {
2841 weathermap[x][y].pressure = (weathermap[x][y].pressure *
2842 PRESSURE_ROUNDING_FACTOR + weathermap[x - 1][y].pressure +
2843 weathermap[x][y - 1].pressure + weathermap[x - 1][y - 1].pressure +
2844 weathermap[x + 1][y].pressure + weathermap[x][y + 1].pressure +
2845 weathermap[x + 1][y + 1].pressure + weathermap[x + 1][y - 1].pressure +
2846 weathermap[x - 1][y + 1].pressure) / (PRESSURE_ROUNDING_FACTOR + 8);
2847 }
2848 }
2849 for (x = WEATHERMAPTILESX - 2; x > 2; x--)
2850 {
2851 for (y = WEATHERMAPTILESY - 2; y > 2; y--)
2852 {
2853 weathermap[x][y].pressure = (weathermap[x][y].pressure *
2854 PRESSURE_ROUNDING_FACTOR + weathermap[x - 1][y].pressure +
2855 weathermap[x][y - 1].pressure + weathermap[x - 1][y - 1].pressure +
2856 weathermap[x + 1][y].pressure + weathermap[x][y + 1].pressure +
2857 weathermap[x + 1][y + 1].pressure + weathermap[x + 1][y - 1].pressure +
2858 weathermap[x - 1][y + 1].pressure) / (PRESSURE_ROUNDING_FACTOR + 8);
2859 }
2860 }
2861 }
2862
2863 for (x = 0; x < WEATHERMAPTILESX; x++)
2864 for (y = 0; y < WEATHERMAPTILESY; y++)
2865 {
2866 weathermap[x][y].pressure = MIN (weathermap[x][y].pressure, PRESSURE_MAX);
2867 weathermap[x][y].pressure = MAX (weathermap[x][y].pressure, PRESSURE_MIN);
2868 }
2869
2870}
2871
2872/*
2873 * perform small randomizations in the pressure map. Then, apply the
2874 * smoothing algorithim.. This causes the pressure to change very slowly
2875 */
2876
2877static void
2878perform_pressure (void)
2879{
2880 int x, y, l, n, j, k;
2881
2882 /* create random spikes in the pressure */
2883 for (l = 0; l < PRESSURE_SPIKES; l++)
2884 {
2885 x = rndm (0, WEATHERMAPTILESX - 1);
2886 y = rndm (0, WEATHERMAPTILESY - 1);
2887 n = rndm (600, 1300);
2888 weathermap[x][y].pressure = n;
2889 if (x > 5 && y > 5 && x < WEATHERMAPTILESX - 5 && y < WEATHERMAPTILESY - 5)
2890 {
2891 for (j = x - 2; j < x + 2; j++)
2892 for (k = y - 2; k < y + 2; k++)
2893 {
2894 weathermap[j][k].pressure = n;
2895 /* occasionally add a storm */
2896 if (rndm (1, 20) == 1)
2897 weathermap[j][k].humid = rndm (50, 80);
2898 }
2899 }
2900 }
2901
2902 for (x = 0; x < WEATHERMAPTILESX; x++)
2903 for (y = 0; y < WEATHERMAPTILESY; y++)
2904 weathermap[x][y].pressure += rndm (-1, 4);
2905
2906 smooth_pressure ();
2907}
2908
2909
2910/*
2911 * is direction a similar to direction b? Find out in this exciting function
2912 * below. Returns 1 if true, 0 for false.
2913 */
2914
2915int
2916similar_direction (int a, int b)
2917{
2918 /* shortcut the obvious */
2919 if (a == b)
2920 return 1;
2921
2922 switch (a)
2923 {
2924 case 1:
2925 if (b <= 2 || b == 8)
2926 return 1;
2927 break;
2928 case 2:
2929 if (b > 0 && b < 4)
2930 return 1;
2931 break;
2932 case 3:
2933 if (b > 1 && b < 5)
2934 return 1;
2935 break;
2936 case 4:
2937 if (b > 2 && b < 6)
2938 return 1;
2939 break;
2940 case 5:
2941 if (b > 3 && b < 7)
2942 return 1;
2943 break;
2944 case 6:
2945 if (b > 4 && b < 8)
2946 return 1;
2947 break;
2948 case 7:
2949 if (b > 5)
2950 return 1;
2951 break;
2952 case 8:
2953 if (b > 6 || b == 1)
2954 return 1;
2955 break;
2956 }
2957 return 0;
2958}
2959
2960/*
2961 * It doesn't really smooth it as such. The main function of this is to
2962 * apply the pressuremap to the wind direction and speed. Then, we run
2963 * a quick pass to update the windspeed.
2964 */
2965
2966static void
2967smooth_wind (void)
2968{
2969 int x, y;
2970 int tx, ty, dx, dy;
2971 int minp;
2972
2973 /* skip the outer squares.. it makes handling alot easier */
2974 dx = 0;
2975 dy = 0;
2976 for (x = 1; x < WEATHERMAPTILESX - 1; x++)
2977 for (y = 1; y < WEATHERMAPTILESY - 1; y++)
2978 {
2979 minp = PRESSURE_MAX + 1;
2980 for (tx = -1; tx < 2; tx++)
2981 for (ty = -1; ty < 2; ty++)
2982 if (!(tx == 0 && ty == 0))
2983 if (weathermap[x + tx][y + ty].pressure < minp)
2984 {
2985 minp = weathermap[x + tx][y + ty].pressure;
2986 dx = tx;
2987 dy = ty;
2988 }
2989
2990 /* if the wind is strong, the pressure won't decay it completely */
2991 if (weathermap[x][y].windspeed > 5 && !similar_direction (weathermap[x][y].winddir, find_dir_2 (dx, dy)))
2992 {
2993 weathermap[x][y].windspeed -= 2 * 2;
2994 }
2995 else
2996 {
2997 weathermap[x][y].winddir = find_dir_2 (dx, dy);
2998 weathermap[x][y].windspeed = (sint8) ((weathermap[x][y].pressure - weathermap[x + dx][y + dy].pressure) * WIND_FACTOR);
2999 }
3000 /* Add in sea breezes. */
3001 weathermap[x][y].windspeed += weathermap[x][y].water / 4;
3002 if (weathermap[x][y].windspeed < 0)
3003 weathermap[x][y].windspeed = 0;
3004 }
3005
3006 /* now, lets crank on the speed. When surrounding tiles all have
3007 the same speed, inc ours. If it's chaos. drop it.
3008 */
3009 for (x = 1; x < WEATHERMAPTILESX - 1; x++)
3010 for (y = 1; y < WEATHERMAPTILESY - 1; y++)
3011 {
3012 minp = 0;
3013 for (tx = -1; tx < 2; tx++)
3014 for (ty = -1; ty < 2; ty++)
3015 if (ty != 0 && ty != 0)
3016 if (similar_direction (weathermap[x][y].winddir, weathermap[x + tx][y + ty].winddir))
3017 minp++;
3018 if (minp > 4)
3019 weathermap[x][y].windspeed++;
3020 if (minp > 6)
3021 weathermap[x][y].windspeed += 2;
3022 if (minp < 2)
3023 weathermap[x][y].windspeed--;
3024 if (weathermap[x][y].windspeed < 0)
3025 weathermap[x][y].windspeed = 0;
3026 }
3027}
3028
3029/*
3030 * Plot the gulfstream map over the wind map. This is done after the wind,
3031 * to avoid the windsmoothing scrambling the jet stream.
3032 */
3033
3034static void
3035plot_gulfstream (void)
3036{
3037 int x, y, tx;
3038
3039 x = gulf_stream_start;
3040
3041 if (gulf_stream_direction)
3042 {
3043 for (y = WEATHERMAPTILESY - 1; y > 0; y--)
3044 {
3045 for (tx = 0; tx < GULF_STREAM_WIDTH && x + tx < WEATHERMAPTILESX; tx++)
3046 {
3047 if (similar_direction (weathermap[x + tx][y].winddir,
3048 gulf_stream_dir[tx][y]) && weathermap[x + tx][y].windspeed < GULF_STREAM_BASE_SPEED - 5)
3049 weathermap[x + tx][y].windspeed += gulf_stream_speed[tx][y];
3050 else
3051 weathermap[x + tx][y].windspeed = gulf_stream_speed[tx][y];
3052 weathermap[x + tx][y].winddir = gulf_stream_dir[tx][y];
3053 if (tx == GULF_STREAM_WIDTH - 1)
3054 {
3055 switch (gulf_stream_dir[tx][y])
3056 {
3057 case 6:
3058 x--;
3059 break;
3060 case 7:
3061 break;
3062 case 8:
3063 x++;;
3064 break;
3065 }
3066 }
3067 if (x < 0)
3068 x++;
3069 if (x >= WEATHERMAPTILESX - GULF_STREAM_WIDTH)
3070 x--;
3071 }
3072 }
3073 }
3074 else
3075 {
3076 for (y = 0; y < WEATHERMAPTILESY - 1; y++)
3077 {
3078 for (tx = 0; tx < GULF_STREAM_WIDTH && x + tx < WEATHERMAPTILESX; tx++)
3079 {
3080 if (similar_direction (weathermap[x + tx][y].winddir,
3081 gulf_stream_dir[tx][y]) && weathermap[x + tx][y].windspeed < GULF_STREAM_BASE_SPEED - 5)
3082 weathermap[x + tx][y].windspeed += gulf_stream_speed[tx][y];
3083 else
3084 weathermap[x + tx][y].windspeed = gulf_stream_speed[tx][y];
3085 weathermap[x + tx][y].winddir = gulf_stream_dir[tx][y];
3086 if (tx == GULF_STREAM_WIDTH - 1)
3087 {
3088 switch (gulf_stream_dir[tx][y])
3089 {
3090 case 2:
3091 x++;
3092 break;
3093 case 3:
3094 break;
3095 case 4:
3096 x--;
3097 break;
3098 }
3099 }
3100 if (x < 0)
3101 x++;
3102 if (x >= WEATHERMAPTILESX - GULF_STREAM_WIDTH)
3103 x--;
3104 }
3105 }
3106 }
3107 /* occasionally move the stream */
3108 if (rndm (1, 500) == 1)
3109 {
3110 gulf_stream_direction = rndm (0, 1);
3111 for (tx = 0; tx < GULF_STREAM_WIDTH; tx++)
3112 for (y = 0; y < WEATHERMAPTILESY - 1; y++)
3113 if (gulf_stream_direction)
3114 switch (gulf_stream_dir[tx][y])
3115 {
3116 case 2:
3117 gulf_stream_dir[tx][y] = 6;
3118 break;
3119 case 3:
3120 gulf_stream_dir[tx][y] = 7;
3121 break;
3122 case 4:
3123 gulf_stream_dir[tx][y] = 8;
3124 break;
3125 }
3126 else
3127 switch (gulf_stream_dir[tx][y])
3128 {
3129 case 6:
3130 gulf_stream_dir[tx][y] = 2;
3131 break;
3132 case 7:
3133 gulf_stream_dir[tx][y] = 3;
3134 break;
3135 case 8:
3136 gulf_stream_dir[tx][y] = 4;
3137 break;
3138 }
3139 }
3140 if (rndm (1, 25) == 1)
3141 gulf_stream_start += rndm (-1, 1);
3142 if (gulf_stream_start >= WEATHERMAPTILESX - GULF_STREAM_WIDTH)
3143 gulf_stream_start--;
3144 if (gulf_stream_start < 1)
3145 gulf_stream_start++;
3146
3147}
3148
3149/*
3150 * let the madness, begin.
3151 *
3152 * This function is the one that ties everything together. Here we loop
3153 * over all the weathermaps, and compare the various conditions we have
3154 * calculated up to now, to figure out what the sky conditions are for this
3155 * square.
3156 */
3157
3158static void
3159compute_sky (void)
3160{
3161 int x, y;
3162 int temp;
3163
3164 for (x = 0; x < WEATHERMAPTILESX; x++)
3165 {
3166 for (y = 0; y < WEATHERMAPTILESY; y++)
3167 {
3168 temp = real_temperature (x, y);
3169 if (weathermap[x][y].pressure < 980)
3170 {
3171 if (weathermap[x][y].humid < 20)
3172 weathermap[x][y].sky = SKY_LIGHTCLOUD;
3173 else if (weathermap[x][y].humid < 30)
3174 weathermap[x][y].sky = SKY_OVERCAST;
3175 else if (weathermap[x][y].humid < 40)
3176 weathermap[x][y].sky = SKY_LIGHT_RAIN;
3177 else if (weathermap[x][y].humid < 55)
3178 weathermap[x][y].sky = SKY_RAIN;
3179 else if (weathermap[x][y].humid < 70)
3180 weathermap[x][y].sky = SKY_HEAVY_RAIN;
3181 else
3182 weathermap[x][y].sky = SKY_HURRICANE;
3183 if (weathermap[x][y].sky < SKY_HURRICANE && weathermap[x][y].windspeed > 30)
3184 weathermap[x][y].sky++;
3185 if (temp <= 0 && weathermap[x][y].sky > SKY_OVERCAST)
3186 weathermap[x][y].sky += 10; /*let it snow */
3187 }
3188 else if (weathermap[x][y].pressure < 1000)
3189 {
3190 if (weathermap[x][y].humid < 10)
3191 weathermap[x][y].sky = SKY_CLEAR;
3192 else if (weathermap[x][y].humid < 25)
3193 weathermap[x][y].sky = SKY_LIGHTCLOUD;
3194 else if (weathermap[x][y].humid < 45)
3195 weathermap[x][y].sky = SKY_OVERCAST;
3196 else if (weathermap[x][y].humid < 60)
3197 weathermap[x][y].sky = SKY_LIGHT_RAIN;
3198 else if (weathermap[x][y].humid < 75)
3199 weathermap[x][y].sky = SKY_RAIN;
3200 else
3201 weathermap[x][y].sky = SKY_HEAVY_RAIN;
3202 if (weathermap[x][y].sky < SKY_HURRICANE && weathermap[x][y].windspeed > 30)
3203 weathermap[x][y].sky++;
3204 if (temp <= 0 && weathermap[x][y].sky > SKY_OVERCAST)
3205 weathermap[x][y].sky += 10; /*let it snow */
3206 if (temp > 0 && temp < 5 && weathermap[x][y].humid > 95 && weathermap[x][y].windspeed < 3)
3207 weathermap[x][y].sky = SKY_FOG; /* rare */
3208 if (temp > 0 && temp < 5 && weathermap[x][y].humid > 70 && weathermap[x][y].windspeed > 35)
3209 weathermap[x][y].sky = SKY_HAIL; /* rare */
3210 }
3211 else if (weathermap[x][y].pressure < 1020)
3212 {
3213 if (weathermap[x][y].humid < 20)
3214 weathermap[x][y].sky = SKY_CLEAR;
3215 else if (weathermap[x][y].humid < 30)
3216 weathermap[x][y].sky = SKY_LIGHTCLOUD;
3217 else if (weathermap[x][y].humid < 40)
3218 weathermap[x][y].sky = SKY_OVERCAST;
3219 else if (weathermap[x][y].humid < 55)
3220 weathermap[x][y].sky = SKY_LIGHT_RAIN;
3221 else if (weathermap[x][y].humid < 70)
3222 weathermap[x][y].sky = SKY_RAIN;
3223 else
3224 weathermap[x][y].sky = SKY_HEAVY_RAIN;
3225 if (weathermap[x][y].sky < SKY_HURRICANE && weathermap[x][y].windspeed > 30)
3226 weathermap[x][y].sky++;
3227 if (temp <= 0 && weathermap[x][y].sky > SKY_OVERCAST)
3228 weathermap[x][y].sky += 10; /*let it snow */
3229 }
3230 else
3231 {
3232 if (weathermap[x][y].humid < 35)
3233 weathermap[x][y].sky = SKY_CLEAR;
3234 else if (weathermap[x][y].humid < 55)
3235 weathermap[x][y].sky = SKY_LIGHTCLOUD;
3236 else if (weathermap[x][y].humid < 70)
3237 weathermap[x][y].sky = SKY_OVERCAST;
3238 else if (weathermap[x][y].humid < 85)
3239 weathermap[x][y].sky = SKY_LIGHT_RAIN;
3240 else if (weathermap[x][y].humid < 95)
3241 weathermap[x][y].sky = SKY_RAIN;
3242 else
3243 weathermap[x][y].sky = SKY_HEAVY_RAIN;
3244 if (weathermap[x][y].sky < SKY_HURRICANE && weathermap[x][y].windspeed > 30)
3245 weathermap[x][y].sky++;
3246 if (temp <= 0 && weathermap[x][y].sky > SKY_OVERCAST)
3247 weathermap[x][y].sky += 10; /*let it snow */
3248 }
3249 }
3250 }
3251}
3252
3253/*
3254 * Keep track of how much rain has fallen in a given weathermap square.
3255 */
3256
3257static void
3258process_rain (void)
3259{
3260 int x, y, rain;
3261
3262 for (x = 0; x < WEATHERMAPTILESX; x++)
3263 for (y = 0; y < WEATHERMAPTILESY; y++)
3264 {
3265 rain = weathermap[x][y].sky;
3266 if (rain >= SKY_LIGHT_SNOW)
3267 rain -= 10;
3268 if (rain > SKY_OVERCAST && rain < SKY_FOG)
3269 {
3270 rain -= SKY_OVERCAST;
3271 weathermap[x][y].rainfall += rain;
3272 }
3273 }
3274}
3275
3276/*
3277 * The world spinning drags the weather with it.
3278 * The equator is diagonal, and the poles are 45 degrees from north /south.
3279 * What the hell, lets spin the planet backwards.
3280 */
3281
3282static void
3283spin_globe (void)
3284{
3285 int x, y;
3286 int buffer_humid;
3287 int buffer_sky;
3288
3289 for (y = 0; y < WEATHERMAPTILESY; y++)
3290 {
3291 buffer_humid = weathermap[0][y].humid;
3292 buffer_sky = weathermap[0][y].sky;
3293 for (x = 0; x < (WEATHERMAPTILESX - 1); x++)
3294 {
3295 weathermap[x][y].humid = weathermap[x + 1][y].humid;
3296 weathermap[x][y].sky = weathermap[x + 1][y].sky;
3297 }
3298 weathermap[WEATHERMAPTILESX - 1][y].humid = buffer_humid;
3299 weathermap[WEATHERMAPTILESX - 1][y].sky = buffer_sky;
3300 }
3301}
3302
3303/*
3304 * Dump all the weather data as an image.
3305 * Writes two other files that are useful for creating animations and web pages.
3306 */
3307
3308static void
3309write_weather_images (void)
3310{
3311 char filename[MAX_BUF];
3312 FILE *fp;
3313 int x, y;
3314 sint32 min[10], max[10], realmaxwind;
3315 uint32 avgrain, avgwind;
3316 double scale[10], realscalewind;
3317 uint8 pixels[3 * 3 * WEATHERMAPTILESX];
3318 sint64 total_rainfall = 0;
3319 sint64 total_wind = 0;
3320
3321 min[0] = 0;
3322 max[0] = 100;
3323 min[1] = 0;
3324 max[1] = 0;
3325 min[2] = 0;
3326 max[2] = 0;
3327 min[3] = PRESSURE_MIN;
3328 max[3] = PRESSURE_MAX;
3329 min[4] = 0;
3330 max[4] = 0;
3331 min[5] = 1;
3332 max[5] = 8;
3333 min[6] = 0;
3334 max[6] = 100;
3335 min[7] = -45;
3336 max[7] = 45;
3337 min[8] = 0;
3338 max[8] = 16;
3339 min[9] = 0;
3340 max[9] = 0;
3341 for (x = 0; x < WEATHERMAPTILESX; x++)
3342 {
3343 for (y = 0; y < WEATHERMAPTILESY; y++)
3344 {
3345
3346/* min[0] = MIN(min[0], weathermap[x][y].water); */
3347 min[1] = MIN (min[1], weathermap[x][y].avgelev);
3348 min[2] = MIN ((uint32) min[2], weathermap[x][y].rainfall);
3349
3350/* min[3] = MIN(min[3], weathermap[x][y].pressure); */
3351 min[4] = MIN (min[4], weathermap[x][y].windspeed);
3352
3353/* min[5] = MIN(min[5], weathermap[x][y].winddir); */
3354
3355/* min[6] = MIN(min[6], weathermap[x][y].humid); */
3356
3357/* min[7] = MIN(min[7], real_temp[x][y]); */
3358
3359/* min[8] = MIN(min[8], weathermap[x][y].sky); */
3360
3361/* min[9] = MIN(min[9], weathermap[x][y].darkness); */
3362
3363/* max[0] = MAX(max[0], weathermap[x][y].water); */
3364 max[1] = MAX (max[1], weathermap[x][y].avgelev);
3365 max[2] = MAX ((uint32) max[2], weathermap[x][y].rainfall);
3366
3367/* max[3] = MAX(max[3], weathermap[x][y].pressure); */
3368 max[4] = MAX (max[4], weathermap[x][y].windspeed);
3369
3370/* max[5] = MAX(max[5], weathermap[x][y].winddir); */
3371
3372/* max[6] = MAX(max[6], weathermap[x][y].humid); */
3373
3374/* max[7] = MAX(max[7], real_temp[x][y]); */
3375
3376/* max[8] = MAX(max[8], weathermap[x][y].sky); */
3377
3378/* max[9] = MAX(max[9], weathermap[x][y].darkness); */
3379 total_rainfall += weathermap[x][y].rainfall;
3380 total_wind += weathermap[x][y].windspeed;
3381 }
3382 }
3383 avgrain = total_rainfall / (WEATHERMAPTILESX * WEATHERMAPTILESY);
3384 avgwind = (total_wind / ((WEATHERMAPTILESX * WEATHERMAPTILESY) * 3 / 2));
3385 max[2] = avgrain - 1;
3386 realscalewind = 255.0l / (max[4] - min[4]);
3387 realmaxwind = max[4];
3388 max[4] = avgwind - 1;
3389 for (x = 0; x < 10; x++)
3390 scale[x] = 255.0l / (max[x] - min[x]);
3391
3392 sprintf (filename, "%s/weather.ppm", settings.localdir);
3393 if ((fp = fopen (filename, "w")) == NULL)
3394 {
3395 LOG (llevError, "Cannot open %s for writing\n", filename);
3396 return;
3397 }
3398 fprintf (fp, "P6\n%d %d\n", 3 * WEATHERMAPTILESX, 3 * WEATHERMAPTILESY);
3399 fprintf (fp, "255\n");
3400 for (y = 0; y < WEATHERMAPTILESY; y++)
3401 {
3402 for (x = 0; x < (3 * 3 * WEATHERMAPTILESX); x++)
3403 pixels[x] = 0;
3404 for (x = 0; x < WEATHERMAPTILESX; x++)
3405 {
3406 pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((weathermap[x][y].water - min[0]) * scale[0]);
3407 if (weathermap[x][y].avgelev >= 0)
3408 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + GREEN)] = (uint8) ((weathermap[x][y].avgelev - min[1]) * scale[1]);
3409 else
3410 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((weathermap[x][y].avgelev - min[1]) * scale[1]);
3411 if (weathermap[x][y].rainfall >= avgrain) /* rainfall is rather spikey, this gives us more detail. */
3412 pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + RED)] = 255;
3413 else
3414 pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((weathermap[x][y].rainfall - min[2]) * scale[2]);
3415 }
3416 fwrite (pixels, sizeof (uint8), (3 * 3 * WEATHERMAPTILESX), fp);
3417 }
3418 for (y = 0; y < WEATHERMAPTILESY; y++)
3419 {
3420 for (x = 0; x < WEATHERMAPTILESX; x++)
3421 {
3422 uint32 dir = directions[weathermap[x][y].winddir - 1];
3423 uint32 speed = weathermap[x][y].windspeed;
3424 uint8 pressure = (uint8) ((weathermap[x][y].pressure - min[3]) * scale[3]);
3425
3426 pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + RED)] = pressure;
3427 pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + GREEN)] = pressure;
3428 pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + BLUE)] = pressure;
3429 if (speed < avgwind)
3430 {
3431 speed = (uint32) ((speed - min[4]) * scale[4]);
3432 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + RED)] = speed;
3433 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + GREEN)] = speed;
3434 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + BLUE)] = speed;
3435 }
3436 else
3437 {
3438 speed = (uint32) ((speed - realmaxwind) * realscalewind);
3439
3440/* if (speed < 100)*/
3441
3442/* speed = 100;*/
3443 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + RED)] = speed;
3444 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + GREEN)] = 0;
3445 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + BLUE)] = 0;
3446 }
3447 pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + RED)] = (uint8) ((dir & 0x00FF0000) >> 16);
3448 pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + GREEN)] = (uint8) ((dir & 0x0000FF00) >> 8);
3449 pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((dir & 0x000000FF));
3450 }
3451 fwrite (pixels, sizeof (uint8), (3 * 3 * WEATHERMAPTILESX), fp);
3452 }
3453 for (y = 0; y < WEATHERMAPTILESY; y++)
3454 {
3455 for (x = 0; x < (3 * 3 * WEATHERMAPTILESX); x++)
3456 pixels[x] = 0;
3457 for (x = 0; x < WEATHERMAPTILESX; x++)
3458 {
3459 uint32 dir = skies[weathermap[x][y].sky];
3460
3461 pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((weathermap[x][y].humid - min[6]) * scale[6]);
3462 /*pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + RED)] = (uint8) ((real_temp[x][y] - min[7]) * scale[7]); */
3463 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + RED)] = 1;
3464 pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + RED)] = (uint8) ((dir & 0x00FF0000) >> 16);
3465 pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + GREEN)] = (uint8) ((dir & 0x0000FF00) >> 8);
3466 pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((dir & 0x000000FF));
3467
3468 }
3469 fwrite (pixels, sizeof (uint8), (3 * 3 * WEATHERMAPTILESX), fp);
3470 }
3471 fclose (fp);
3472
3473 sprintf (filename, "%s/todtick", settings.localdir);
3474 if ((fp = fopen (filename, "w")) == NULL)
3475 {
3476 LOG (llevError, "Cannot open %s for writing\n", filename);
3477 return;
3478 }
3479 fprintf (fp, "%lu", todtick);
3480 fclose (fp);
3481}

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines