ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/weather.C
Revision: 1.8
Committed: Sat Sep 16 22:24:13 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.7: +21 -21 lines
Log Message:
mapstruct => maptile
removed many ytypedefs in favor of structure tags

File Contents

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