ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/weather.c
Revision: 1.1.1.1 (vendor branch)
Committed: Fri Feb 3 07:14:43 2006 UTC (18 years, 4 months ago) by root
Content type: text/plain
Branch: UPSTREAM
CVS Tags: UPSTREAM_2006_03_15, UPSTREAM_2006_02_22, UPSTREAM_2006_02_03
Changes since 1.1: +0 -0 lines
Log Message:
initial import

File Contents

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