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

File Contents

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