ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/weather.C
Revision: 1.11
Committed: Mon Dec 25 14:54:44 2006 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.10: +4 -4 lines
Log Message:
the big rename

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