ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/weather.C
Revision: 1.5
Committed: Sun Sep 10 15:59:58 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.4: +2825 -2398 lines
Log Message:
indent

File Contents

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