ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/weather.C
Revision: 1.12
Committed: Wed Dec 27 09:28:02 2006 UTC (17 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.11: +2 -7 lines
Log Message:
introduce for_all_maps

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