ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/weather.C
Revision: 1.7
Committed: Thu Sep 14 22:34:05 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.6: +1 -7 lines
Log Message:
indent

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     static object *avoid_weather (int *av, mapstruct *m, int x, int y, int *gs, int grow);
66     static void calculate_temperature (mapstruct *m, int wx, int wy);
67     static void let_it_snow (mapstruct *m, int wx, int wy);
68     static void singing_in_the_rain (mapstruct *m, int wx, int wy);
69     static void plant_a_garden (mapstruct *m, int wx, int wy);
70     static void change_the_world (mapstruct *m, int wx, int wy);
71    
72 pippijn 1.4 //static void feather_map(mapstruct *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     set_darkness_map (mapstruct *m)
348 elmex 1.1 {
349 root 1.5 int i;
350     timeofday_t tod;
351 elmex 1.1
352 root 1.5 if (!m->outdoor)
353     return;
354 elmex 1.1
355 root 1.5 get_tod (&tod);
356     m->darkness = 0;
357     for (i = HOURS_PER_DAY / 2; i < HOURS_PER_DAY; i++)
358     change_map_light (m, season_timechange[tod.season][i]);
359     for (i = 0; i <= tod.hour; i++)
360     change_map_light (m, season_timechange[tod.season][i]);
361 elmex 1.1 }
362    
363     /*
364     * Compute the darkness level for all maps in the game. Requires the
365     * time of day as an argument.
366     */
367    
368 root 1.5 static void
369     dawn_to_dusk (const timeofday_t * tod)
370 elmex 1.1 {
371 root 1.5 mapstruct *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     mapstruct *m;
1083    
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.5 mapstruct *m;
1470     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.5 mapstruct *m;
1527     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     avoid_weather (int *av, mapstruct *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     calculate_temperature (mapstruct *m, int wx, int wy)
1640     {
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     let_it_snow (mapstruct *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     remove_ob (oldsnow);
1765     free_object (oldsnow);
1766     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     if (weather_replace[i].arch_or_name == 1)
1776     {
1777     if (!strcmp (tmp->arch->name, weather_replace[i].tile))
1778     found++;
1779     }
1780     else
1781     {
1782     if (!strcmp (tmp->name, weather_replace[i].tile))
1783     found++;
1784     }
1785     if (found)
1786     {
1787 root 1.3 tmp = tmp->above;
1788     doublestack2 = weather_replace[i].doublestack_arch;
1789     break;
1790 root 1.5 }
1791     }
1792     if (tmp != NULL && doublestack2 != NULL)
1793     if (strcmp (tmp->arch->name, doublestack2) == 0)
1794     {
1795     remove_ob (tmp);
1796     free_object (tmp);
1797     }
1798     }
1799     }
1800     if (at != NULL)
1801     {
1802     ob = arch_to_object (at);
1803     ob->x = x;
1804     ob->y = y;
1805     ob->material = M_ICE;
1806     SET_FLAG (ob, FLAG_OVERLAY_FLOOR);
1807     CLEAR_FLAG (ob, FLAG_IS_FLOOR);
1808     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
1809     if (two)
1810     {
1811     at = NULL;
1812 root 1.6 at = archetype::find (doublestack);
1813 root 1.5 if (at != NULL)
1814     {
1815     ob = arch_to_object (at);
1816     ob->x = x;
1817     ob->y = y;
1818     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP);
1819 root 1.3 }
1820     }
1821     }
1822     }
1823 root 1.5 if (temp > 8 && GET_MAP_OB (m, x, y) != NULL)
1824     {
1825     /* melt some snow */
1826     for (tmp = GET_MAP_OB (m, x, y)->above; tmp; tmp = tmp->above)
1827     {
1828     avoid = 0;
1829     for (i = 0; weather_replace[i].tile != NULL; i++)
1830     {
1831     if (weather_replace[i].special_snow == NULL)
1832     continue;
1833     if (!strcmp (tmp->arch->name, weather_replace[i].special_snow))
1834     avoid++;
1835     if (avoid)
1836     break;
1837 root 1.3 }
1838 root 1.5 if (avoid)
1839     {
1840     /* replace snow with a big puddle */
1841     remove_ob (tmp);
1842     free_object (tmp);
1843     tmp = GET_MAP_OB (m, x, y);
1844     if (tmp && (!strcmp (tmp->arch->name, "mountain")))
1845     {
1846 root 1.6 at = archetype::find ("mountain1_rivlets");
1847 root 1.5 }
1848     else if (tmp && (!strcmp (tmp->arch->name, "mountain2")))
1849     {
1850 root 1.6 at = archetype::find ("mountain2_rivlets");
1851 root 1.5 }
1852     else if (tmp && (!strcmp (tmp->arch->name, "mountain4")))
1853     {
1854 root 1.6 at = archetype::find ("mountain2_rivlets");
1855 root 1.5 }
1856     else
1857     {
1858 root 1.6 at = archetype::find ("rain5");
1859 root 1.5 }
1860     if (at != NULL)
1861     {
1862     ob = arch_to_object (at);
1863     ob->x = x;
1864     ob->y = y;
1865     SET_FLAG (ob, FLAG_OVERLAY_FLOOR);
1866     ob->material = M_LIQUID;
1867     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
1868 root 1.3 }
1869     }
1870     }
1871     }
1872 root 1.5 /* woo it's cold out */
1873     if (temp < -8)
1874     {
1875     avoid = 0;
1876     for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
1877     {
1878     if (!strcasecmp (tmp->name, "ice"))
1879     avoid--;
1880     }
1881     tmp = GET_MAP_OB (m, x, y);
1882     if (tmp && (!strcasecmp (tmp->name, "sea")))
1883     avoid++;
1884     else if (tmp && (!strcasecmp (tmp->name, "sea1")))
1885     avoid++;
1886     else if (tmp && (!strcasecmp (tmp->name, "deep_sea")))
1887     avoid++;
1888     else if (tmp && (!strcasecmp (tmp->name, "shallow_sea")))
1889     avoid++;
1890     if (avoid > 0)
1891     {
1892 root 1.6 at = archetype::find ("ice");
1893 root 1.5 ob = arch_to_object (at);
1894     ob->x = x;
1895     ob->y = y;
1896     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
1897 root 1.3 }
1898     }
1899     }
1900 elmex 1.1 }
1901     }
1902    
1903     /*
1904     * Process rain. m is the map we are currently processing. wx and wy are
1905     * the weathermap coordinates for the weathermap square we want to work on.
1906     * filename is the pathname for the current map. This should be called from
1907     * weather_effect()
1908     */
1909    
1910 root 1.5 static void
1911     singing_in_the_rain (mapstruct *m, int wx, int wy)
1912 elmex 1.1 {
1913 root 1.5 int x, y, i;
1914     uint32 nx, ny, d, j;
1915     int avoid, two, temp, sky, gotsnow, found, nodstk;
1916     object *ob, *tmp, *oldsnow, *topfloor;
1917     const char *doublestack, *doublestack2;
1918     archetype *at;
1919    
1920     for (nx = 0; nx < settings.worldmaptilesizex; nx++)
1921     {
1922     for (ny = 0; ny < settings.worldmaptilesizey; ny++)
1923     {
1924     /* jitter factor */
1925     if (rndm (0, 2) > 0)
1926     {
1927     x = y = d = -1;
1928     while (OUT_OF_REAL_MAP (m, x, y))
1929     {
1930     d++;
1931     j = rndm (1, 8);
1932     x = nx + freearr_x[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
1933     y = ny + freearr_y[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
1934     if (d > 15)
1935     {
1936     x = nx;
1937     y = ny;
1938     }
1939     }
1940     }
1941     else
1942     {
1943     x = nx;
1944     y = ny;
1945     }
1946     /* we use the unjittered coordinates */
1947     (void) worldmap_to_weathermap (nx, ny, &wx, &wy, m);
1948     ob = NULL;
1949     at = NULL;
1950     avoid = 0;
1951     two = 0;
1952     gotsnow = 0;
1953     nodstk = 0;
1954     /*temp = real_world_temperature(x, y, m); */
1955     temp = weathermap[wx][wy].realtemp;
1956     sky = weathermap[wx][wy].sky;
1957     /* it's probably allready snowing */
1958     if (temp < 0)
1959     continue;
1960     oldsnow = avoid_weather (&avoid, m, x, y, &gotsnow, 0);
1961     if (!avoid)
1962     {
1963     tmp = GET_MAP_OB (m, x, y);
1964     if (tmp && (!strcmp (tmp->arch->name, "mountain")))
1965     {
1966 root 1.6 at = archetype::find ("mountain1_rivlets");
1967 root 1.5 break;
1968     }
1969     else if (tmp && (!strcmp (tmp->arch->name, "mountain2")))
1970     {
1971 root 1.6 at = archetype::find ("mountain2_rivlets");
1972 root 1.5 break;
1973     }
1974     else if (tmp && (!strcmp (tmp->arch->name, "mountain4")))
1975     {
1976 root 1.6 at = archetype::find ("mountain2_rivlets");
1977 root 1.5 break;
1978     }
1979     if (sky == SKY_LIGHT_RAIN || sky == SKY_RAIN)
1980     {
1981     switch (rndm (0, SKY_HAIL - sky))
1982     {
1983     case 0:
1984 root 1.6 at = archetype::find ("rain1");
1985 root 1.5 break;
1986     case 1:
1987 root 1.6 at = archetype::find ("rain2");
1988 root 1.5 break;
1989     default:
1990     at = NULL;
1991     }
1992     }
1993     if (sky >= SKY_HEAVY_RAIN && sky <= SKY_HURRICANE)
1994     {
1995     switch (rndm (0, SKY_HAIL - sky))
1996     {
1997     case 0:
1998 root 1.6 at = archetype::find ("rain3");
1999 root 1.5 break;
2000     case 1:
2001 root 1.6 at = archetype::find ("rain4");
2002 root 1.5 break;
2003     case 2:
2004 root 1.6 at = archetype::find ("rain5");
2005 root 1.5 break;
2006     default:
2007     at = NULL;
2008     }
2009     }
2010     /* the bottom floor of scorn is not IS_FLOOR */
2011     topfloor = NULL;
2012     for (tmp = GET_MAP_OB (m, x, y); tmp; topfloor = tmp, tmp = tmp->above)
2013     {
2014     if (strcmp (tmp->arch->name, "dungeon_magic") != 0)
2015     if (!QUERY_FLAG (tmp, FLAG_IS_FLOOR))
2016     break;
2017     }
2018     /* topfloor should now be the topmost IS_FLOOR=1 */
2019     if (topfloor == NULL)
2020 root 1.3 continue;
2021 root 1.5 if (tmp != NULL)
2022     nodstk++;
2023     /* something is wrong with that sector. just skip it */
2024     found = 0;
2025     for (i = 0; weather_replace[i].tile != NULL; i++)
2026     {
2027     if (weather_replace[i].arch_or_name == 1)
2028     {
2029     if (!strcmp (topfloor->arch->name, weather_replace[i].tile))
2030     found++;
2031     }
2032     else
2033     {
2034     if (!strcmp (topfloor->name, weather_replace[i].tile))
2035     found++;
2036 root 1.3 }
2037 root 1.5 if (found)
2038     {
2039     if (weather_replace[i].doublestack_arch != NULL && !nodstk)
2040     {
2041     two++;
2042     doublestack = weather_replace[i].doublestack_arch;
2043 root 1.3 }
2044 root 1.5 break;
2045 root 1.3 }
2046     }
2047 root 1.5 if (gotsnow && at)
2048     {
2049     if (!strcmp (oldsnow->arch->name, at->name))
2050     at = NULL;
2051     else
2052     {
2053     tmp = GET_MAP_OB (m, x, y);
2054     remove_ob (oldsnow);
2055     /* clean up the trees we put over the snow */
2056     found = 0;
2057     doublestack2 = NULL;
2058     for (i = 0; weather_replace[i].tile != NULL; i++)
2059     {
2060     if (weather_replace[i].doublestack_arch == NULL)
2061     continue;
2062     if (weather_replace[i].arch_or_name == 1)
2063     {
2064     if (!strcmp (tmp->arch->name, weather_replace[i].tile))
2065     found++;
2066     }
2067     else
2068     {
2069     if (!strcmp (tmp->name, weather_replace[i].tile))
2070     found++;
2071 root 1.3 }
2072 root 1.5 if (found)
2073     {
2074     tmp = tmp->above;
2075     doublestack2 = weather_replace[i].doublestack_arch;
2076     break;
2077 root 1.3 }
2078     }
2079 root 1.5 free_object (oldsnow);
2080     if (tmp != NULL && doublestack2 != NULL)
2081     if (strcmp (tmp->arch->name, doublestack2) == 0)
2082     {
2083     remove_ob (tmp);
2084     free_object (tmp);
2085     }
2086     }
2087     }
2088     if (at != NULL)
2089     {
2090     ob = arch_to_object (at);
2091     ob->x = x;
2092     ob->y = y;
2093     SET_FLAG (ob, FLAG_OVERLAY_FLOOR);
2094     ob->material = M_LIQUID;
2095     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2096     if (two)
2097     {
2098 root 1.6 at = archetype::find (doublestack);
2099 root 1.5 if (at != NULL)
2100     {
2101     ob = arch_to_object (at);
2102     ob->x = x;
2103     ob->y = y;
2104     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP);
2105 root 1.3 }
2106     }
2107     }
2108     }
2109 root 1.5 /* Things evaporate fast in the heat */
2110     if (GET_MAP_OB (m, x, y) && temp > 8 && sky < SKY_OVERCAST && rndm (temp, 60) > 50)
2111     {
2112     /* evaporate */
2113     for (tmp = GET_MAP_OB (m, x, y)->above; tmp; tmp = tmp->above)
2114     {
2115     avoid = 0;
2116     if (!strcmp (tmp->arch->name, "rain1"))
2117     avoid++;
2118     else if (!strcmp (tmp->arch->name, "rain2"))
2119     avoid++;
2120     else if (!strcmp (tmp->arch->name, "rain3"))
2121     avoid++;
2122     else if (!strcmp (tmp->arch->name, "rain4"))
2123     avoid++;
2124     else if (!strcmp (tmp->arch->name, "rain5"))
2125     avoid++;
2126     else if (!strcmp (tmp->arch->name, "mountain1_rivlets"))
2127     avoid++;
2128     else if (!strcmp (tmp->arch->name, "mountain2_rivlets"))
2129     avoid++;
2130     if (avoid)
2131     {
2132     remove_ob (tmp);
2133     free_object (tmp);
2134     if (weathermap[wx][wy].humid < 100 && rndm (0, 50) == 0)
2135     weathermap[wx][wy].humid++;
2136     tmp = GET_MAP_OB (m, x, y);
2137     /* clean up the trees we put over the rain */
2138     found = 0;
2139     doublestack2 = NULL;
2140     for (i = 0; weather_replace[i].tile != NULL; i++)
2141     {
2142     if (weather_replace[i].doublestack_arch == NULL)
2143     continue;
2144     if (weather_replace[i].arch_or_name == 1)
2145     {
2146     if (!strcmp (tmp->arch->name, weather_replace[i].tile))
2147     found++;
2148     }
2149     else
2150     {
2151     if (!strcmp (tmp->name, weather_replace[i].tile))
2152     found++;
2153 root 1.3 }
2154 root 1.5 if (found)
2155     {
2156     tmp = tmp->above;
2157     doublestack2 = weather_replace[i].doublestack_arch;
2158     break;
2159 root 1.3 }
2160     }
2161 root 1.5 if (tmp != NULL && doublestack2 != NULL)
2162     if (strcmp (tmp->arch->name, doublestack2) == 0)
2163     {
2164     remove_ob (tmp);
2165     free_object (tmp);
2166     }
2167     break;
2168 root 1.3 }
2169     }
2170     }
2171     }
2172 elmex 1.1 }
2173     }
2174    
2175     /*
2176     * Process growth. m is the map we are currently processing. wx and wy are
2177     * the weathermap coordinates for the weathermap square we want to work on.
2178     * filename is the pathname for the current map. This should be called from
2179     * weather_effect()
2180     */
2181    
2182 root 1.5 static void
2183     plant_a_garden (mapstruct *m, int wx, int wy)
2184 elmex 1.1 {
2185 root 1.5 uint32 x, y, i;
2186     int avoid, two, temp, sky, gotsnow, found, days;
2187     object *ob, *tmp;
2188     archetype *at;
2189    
2190     days = todtick / HOURS_PER_DAY;
2191     for (x = 0; x < settings.worldmaptilesizex; x++)
2192     {
2193     for (y = 0; y < settings.worldmaptilesizey; y++)
2194     {
2195     (void) worldmap_to_weathermap (x, y, &wx, &wy, m);
2196     ob = NULL;
2197     at = NULL;
2198     avoid = 0;
2199     two = 0;
2200     gotsnow = 0;
2201     /*temp = real_world_temperature(x, y, m); */
2202     temp = weathermap[wx][wy].realtemp;
2203     sky = weathermap[wx][wy].sky;
2204     (void) avoid_weather (&avoid, m, x, y, &gotsnow, 1);
2205     if (!avoid)
2206     {
2207     found = 0;
2208     for (i = 0; weather_grow[i].herb != NULL; i++)
2209     {
2210     for (tmp = GET_MAP_OB (m, x, y); tmp; tmp = tmp->above)
2211     {
2212     if (strcmp (tmp->arch->name, weather_grow[i].herb) != 0)
2213     continue;
2214     /* we found there is a herb here allready */
2215     found++;
2216     if ((float) weathermap[wx][wy].rainfall / days < weather_grow[i].rfmin ||
2217     (float) weathermap[wx][wy].rainfall / days > weather_grow[i].rfmax ||
2218     weathermap[wx][wy].humid < weather_grow[i].humin ||
2219     weathermap[wx][wy].humid > weather_grow[i].humax ||
2220     temp < weather_grow[i].tempmin ||
2221     temp > weather_grow[i].tempmax || rndm (0, MIN (weather_grow[i].random / 2, 1)) == 0)
2222     {
2223     /* the herb does not belong, randomly delete
2224     herbs to prevent overgrowth. */
2225     remove_ob (tmp);
2226     free_object (tmp);
2227     break;
2228 root 1.3 }
2229     }
2230 root 1.5 /* don't doublestack herbs */
2231     if (found)
2232     continue;
2233     /* add a random factor */
2234     if (rndm (1, weather_grow[i].random) != 1)
2235     continue;
2236     /* we look up through two tiles for a matching tile */
2237     if (weather_grow[i].tile != NULL && GET_MAP_OB (m, x, y) != NULL)
2238     {
2239     if (strcmp (GET_MAP_OB (m, x, y)->arch->name, weather_grow[i].tile) != 0)
2240     {
2241     if (GET_MAP_OB (m, x, y)->above != NULL)
2242     {
2243     if (strcmp (GET_MAP_OB (m, x, y)->above->arch->name, weather_grow[i].tile) != 0)
2244 root 1.3 continue;
2245 root 1.5 }
2246     else
2247     continue;
2248 root 1.3 }
2249     }
2250 root 1.5 if ((float) weathermap[wx][wy].rainfall / days < weather_grow[i].rfmin ||
2251     (float) weathermap[wx][wy].rainfall / days > weather_grow[i].rfmax)
2252     continue;
2253     if (weathermap[wx][wy].humid < weather_grow[i].humin || weathermap[wx][wy].humid > weather_grow[i].humax)
2254     continue;
2255     if (temp < weather_grow[i].tempmin || temp > weather_grow[i].tempmax)
2256     continue;
2257     if ((!GET_MAP_OB (m, x, y)) ||
2258     GET_MAP_OB (m, x, y)->elevation < weather_grow[i].elevmin ||
2259     GET_MAP_OB (m, x, y)->elevation > weather_grow[i].elevmax)
2260     continue;
2261     /* we got this far.. must be a match */
2262 root 1.6 at = archetype::find (weather_grow[i].herb);
2263 root 1.5 break;
2264     }
2265     if (at != NULL)
2266     {
2267     ob = arch_to_object (at);
2268     ob->x = x;
2269     ob->y = y;
2270     /* XXX is this right? maybe.. */
2271     SET_FLAG (ob, FLAG_OVERLAY_FLOOR);
2272     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2273 root 1.3 }
2274     }
2275     }
2276 elmex 1.1 }
2277     }
2278    
2279     /*
2280     * Process worldmap regrowth. m is the map we are currently processing.
2281     * wx and wy are
2282     * the weathermap coordinates for the weathermap square we want to work on.
2283     * This should be called from weather_effect()
2284     */
2285    
2286 root 1.5 static void
2287     change_the_world (mapstruct *m, int wx, int wy)
2288 elmex 1.1 {
2289 root 1.5 int x, y, i;
2290     uint32 nx, ny, j, d;
2291     int avoid, two, temp, sky, gotsnow, found, days;
2292     object *ob, *tmp, *doublestack;
2293     archetype *at, *dat;
2294    
2295     days = todtick / HOURS_PER_DAY;
2296     for (nx = 0; nx < settings.worldmaptilesizex; nx++)
2297     {
2298     for (ny = 0; ny < settings.worldmaptilesizey; ny++)
2299     {
2300     /* jitter factor */
2301     if (rndm (0, 2) > 0)
2302     {
2303     x = y = d = -1;
2304     while (OUT_OF_REAL_MAP (m, x, y))
2305     {
2306     d++;
2307     j = rndm (1, 8);
2308     x = nx + freearr_x[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
2309     y = ny + freearr_y[j] * (rndm (0, 1) + rndm (0, 1) + rndm (0, 1) + 1);
2310     if (d > 15)
2311     {
2312     x = nx;
2313     y = ny;
2314     }
2315     }
2316     }
2317     else
2318     {
2319     x = nx;
2320     y = ny;
2321     }
2322     /* we use the unjittered coordinates */
2323     (void) worldmap_to_weathermap (nx, ny, &wx, &wy, m);
2324     ob = NULL;
2325     at = NULL;
2326     dat = NULL;
2327     avoid = 0;
2328     two = 0;
2329     gotsnow = 0;
2330     /*temp = real_world_temperature(x, y, m); */
2331     temp = weathermap[wx][wy].realtemp;
2332     sky = weathermap[wx][wy].sky;
2333     (void) avoid_weather (&avoid, m, x, y, &gotsnow, 1);
2334     if (!avoid)
2335     {
2336     for (i = 0; weather_tile[i].herb != NULL; i++)
2337     {
2338     found = 0;
2339     doublestack = NULL;
2340     if (GET_MAP_OB (m, x, y))
2341     for (tmp = GET_MAP_OB (m, x, y)->above; tmp; tmp = tmp->above)
2342     {
2343 root 1.3 if (weather_tile[i].tile != NULL)
2344 root 1.5 if (strcmp (tmp->arch->name, weather_tile[i].tile) == 0)
2345     {
2346     doublestack = tmp;
2347     continue;
2348 root 1.3 }
2349 root 1.5 if (strcmp (tmp->arch->name, weather_tile[i].herb) != 0)
2350     continue;
2351     if ((float) weathermap[wx][wy].rainfall / days < weather_tile[i].rfmin ||
2352     (float) weathermap[wx][wy].rainfall / days > weather_tile[i].rfmax ||
2353 root 1.3 weathermap[wx][wy].humid < weather_tile[i].humin ||
2354     weathermap[wx][wy].humid > weather_tile[i].humax ||
2355 root 1.5 temp < weather_tile[i].tempmin || temp > weather_tile[i].tempmax)
2356     {
2357     remove_ob (tmp);
2358     free_object (tmp);
2359     if (doublestack)
2360     {
2361     remove_ob (doublestack);
2362     free_object (doublestack);
2363     }
2364 root 1.3 break;
2365 root 1.5 }
2366     else
2367     {
2368     found++; /* there is one here allready. leave it */
2369 root 1.3 break;
2370 root 1.5 }
2371     }
2372     if (found)
2373 root 1.3 break;
2374 root 1.5 /* add a random factor */
2375     if (rndm (1, weather_tile[i].random) != 1)
2376     continue;
2377     if ((float) weathermap[wx][wy].rainfall / days < weather_tile[i].rfmin ||
2378     (float) weathermap[wx][wy].rainfall / days > weather_tile[i].rfmax)
2379     continue;
2380     if (weathermap[wx][wy].humid < weather_tile[i].humin || weathermap[wx][wy].humid > weather_tile[i].humax)
2381     continue;
2382     if (temp < weather_tile[i].tempmin || temp > weather_tile[i].tempmax)
2383     continue;
2384     if ((!GET_MAP_OB (m, x, y)) ||
2385     GET_MAP_OB (m, x, y)->elevation < weather_tile[i].elevmin ||
2386     GET_MAP_OB (m, x, y)->elevation > weather_tile[i].elevmax)
2387     continue;
2388     /* we got this far.. must be a match */
2389     if (GET_MAP_OB (m, x, y) && strcmp (GET_MAP_OB (m, x, y)->arch->name, weather_tile[i].herb) == 0)
2390     break; /* no sense in doubling up */
2391 root 1.6 at = archetype::find (weather_tile[i].herb);
2392 root 1.5 break;
2393     }
2394     if (at != NULL)
2395     {
2396     if (weather_tile[i].tile != NULL && GET_MAP_OB (m, x, y) &&
2397     strcmp (weather_tile[i].tile, GET_MAP_OB (m, x, y)->arch->name) != 0)
2398 root 1.6 dat = archetype::find (weather_tile[i].tile);
2399 root 1.5 if (dat != NULL)
2400     {
2401     ob = arch_to_object (dat);
2402     ob->x = x;
2403     ob->y = y;
2404     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2405     }
2406     if (gotsnow == 0)
2407     {
2408     ob = arch_to_object (at);
2409     ob->x = x;
2410     ob->y = y;
2411     if (dat != NULL)
2412     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP);
2413     else
2414     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2415 root 1.3 }
2416     }
2417     }
2418     }
2419 elmex 1.1 }
2420     }
2421    
2422    
2423     /*
2424     * Reduce the blockiness of the maps. m is the map we are currently processing.
2425     * wx and wy are
2426     * the weathermap coordinates for the weathermap square we want to work on.
2427     * This should be called from weather_effect()
2428     */
2429 pippijn 1.4 #if 0
2430 root 1.5 static void
2431     feather_map (mapstruct *m, int wx, int wy)
2432 elmex 1.1 {
2433 root 1.5 uint32 x, y, i, nx, ny, j;
2434     int avoid, two, gotsnow, nodstk;
2435     object *ob, *tmp, *oldsnow, *topfloor, *ntmp, *ntopfloor;
2436     archetype *at;
2437    
2438     for (x = 0; x < settings.worldmaptilesizex; x++)
2439     {
2440     for (y = 0; y < settings.worldmaptilesizey; y++)
2441     {
2442     (void) worldmap_to_weathermap (x, y, &wx, &wy, m);
2443     ob = NULL;
2444     at = NULL;
2445     avoid = 0;
2446     two = 0;
2447     j = 0;
2448     gotsnow = 0;
2449     nodstk = 0;
2450     oldsnow = avoid_weather (&avoid, m, x, y, &gotsnow, 1);
2451     if (avoid)
2452     continue;
2453     if (rndm (0, 20) == 0)
2454     continue;
2455     // the bottom floor of scorn is not IS_FLOOR
2456     topfloor = NULL;
2457     for (tmp = GET_MAP_OB (m, x, y); tmp; topfloor = tmp, tmp = tmp->above)
2458     {
2459     if (strcmp (tmp->arch->name, "dungeon_magic") != 0)
2460     if (!QUERY_FLAG (tmp, FLAG_IS_FLOOR) && !QUERY_FLAG (tmp, FLAG_OVERLAY_FLOOR))
2461     break;
2462 root 1.3 }
2463 root 1.5 // topfloor should now be the topmost IS_FLOOR=1
2464     if (topfloor == NULL)
2465     continue;
2466     if (tmp != NULL)
2467     nodstk++;
2468     // something is wrong with that sector. just skip it
2469    
2470     j = rndm (1, 8);
2471     nx = freearr_x[j] + x;
2472     ny = freearr_y[j] + y;
2473     if (OUT_OF_REAL_MAP (m, nx, ny))
2474     continue;
2475     oldsnow = avoid_weather (&avoid, m, nx, ny, &gotsnow, 1);
2476     if (avoid)
2477     continue;
2478     ntopfloor = NULL;
2479     for (ntmp = GET_MAP_OB (m, nx, ny); ntmp; ntopfloor = ntmp, ntmp = ntmp->above)
2480     {
2481     if (strcmp (ntmp->arch->name, "dungeon_magic") != 0)
2482     if (!QUERY_FLAG (ntmp, FLAG_IS_FLOOR) && !QUERY_FLAG (ntmp, FLAG_OVERLAY_FLOOR))
2483     break;
2484     }
2485     if (ntopfloor != NULL && QUERY_FLAG (ntopfloor, FLAG_IS_FLOOR))
2486     {
2487     remove_ob (topfloor);
2488     free_object (topfloor);
2489     if (tmp != NULL)
2490     {
2491     for (i = 0; weather_tile[i].herb != NULL; i++)
2492     {
2493     if (strcmp (tmp->arch->name, weather_tile[i].herb) == 0)
2494     {
2495     remove_ob (tmp);
2496     free_object (tmp);
2497     break;
2498 root 1.3 }
2499     }
2500     }
2501     }
2502 root 1.5 else
2503     {
2504     continue;
2505     }
2506     ob = arch_to_object (ntopfloor->arch);
2507     ob->x = x;
2508     ob->y = y;
2509     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ABOVE_FLOOR_ONLY);
2510     if (ntmp != NULL && nodstk == 0)
2511     {
2512     for (i = 0; weather_tile[i].herb != NULL; i++)
2513     {
2514     if (strcmp (ntmp->arch->name, weather_tile[i].herb) == 0)
2515     {
2516     ob = arch_to_object (ntmp->arch);
2517     ob->x = x;
2518     ob->y = y;
2519     insert_ob_in_map (ob, m, ob, INS_NO_MERGE | INS_NO_WALK_ON | INS_ON_TOP);
2520     break;
2521 root 1.3 }
2522     }
2523     }
2524     }
2525 elmex 1.1 }
2526     }
2527 pippijn 1.4 #endif
2528 elmex 1.1
2529     /* provide wx and wy. Will fill in with weathermap coordinates. Requires
2530     the current mapname (must be a worldmap), and your coordinates on the
2531     map. returns -1 if you give it something it can't figure out. 0 normally.
2532     */
2533    
2534 root 1.5 int
2535     worldmap_to_weathermap (int x, int y, int *wx, int *wy, mapstruct *m)
2536 elmex 1.1 {
2537 root 1.5 int spwtx, spwty;
2538     uint32 fx, fy;
2539     uint32 nx, ny;
2540     char *filename = m->path;
2541    
2542     spwtx = (settings.worldmaptilesx * settings.worldmaptilesizex) / WEATHERMAPTILESX;
2543     spwty = (settings.worldmaptilesy * settings.worldmaptilesizey) / WEATHERMAPTILESY;
2544    
2545     while (*filename == '/')
2546     *filename++;
2547    
2548     fx = MAP_WORLDPARTX (m);
2549     fy = MAP_WORLDPARTY (m);
2550     if (fx > settings.worldmapstartx + settings.worldmaptilesx ||
2551     fx < settings.worldmapstartx || fy > settings.worldmapstarty + settings.worldmaptilesy || fy < settings.worldmapstarty)
2552     {
2553     LOG (llevDebug, "worldmap_to_weathermap(%s)\n", filename);
2554     sscanf (filename, "world/world_%d_%d", &fx, &fy);
2555     MAP_WORLDPARTX (m) = fx;
2556     MAP_WORLDPARTY (m) = fy;
2557     }
2558     if (fx > settings.worldmapstartx + settings.worldmaptilesx || fx < settings.worldmapstartx)
2559     return -1;
2560     if (fy > settings.worldmapstarty + settings.worldmaptilesy || fy < settings.worldmapstarty)
2561     return -1;
2562     fx -= settings.worldmapstartx;
2563     fy -= settings.worldmapstarty;
2564 elmex 1.1
2565 root 1.5 nx = fx * settings.worldmaptilesizex + x;
2566     ny = fy * settings.worldmaptilesizey + y;
2567 elmex 1.1
2568 root 1.5 *wx = nx / spwtx;
2569     *wy = ny / spwty;
2570 elmex 1.1
2571 root 1.5 return 0;
2572 elmex 1.1 }
2573    
2574     /* provide x and y. Will fill in with the requested corner of the real
2575     * world map, given the current weathermap section. dir selects which
2576     * corner to return. Valid values are 2 4 6 8 for the corners. return
2577     * value is the name of the map that corner resides in.
2578     */
2579    
2580 root 1.5 static const char *
2581     weathermap_to_worldmap_corner (int wx, int wy, int *x, int *y, int dir)
2582 elmex 1.1 {
2583 root 1.5 int spwtx, spwty;
2584     int tx, ty, nx, ny;
2585     static char mapname[MAX_BUF];
2586    
2587     spwtx = (settings.worldmaptilesx * settings.worldmaptilesizex) / WEATHERMAPTILESX;
2588     spwty = (settings.worldmaptilesy * settings.worldmaptilesizey) / WEATHERMAPTILESY;
2589     switch (dir)
2590     {
2591     case 2:
2592     wx++;
2593     break;
2594     case 4:
2595     wx++;
2596     wy++;
2597     break;
2598     case 6:
2599     wy++;
2600     break;
2601     case 8:
2602     break;
2603     }
2604     if (wx > 0)
2605     tx = (wx * spwtx) - 1;
2606     else
2607     tx = wx;
2608     if (wy > 0)
2609     ty = (wy * spwty) - 1;
2610     else
2611     ty = wy;
2612    
2613     nx = (tx / settings.worldmaptilesizex) + settings.worldmapstartx;
2614     ny = (ty / settings.worldmaptilesizey) + settings.worldmapstarty;
2615     snprintf (mapname, MAX_BUF, "world/world_%d_%d", nx, ny);
2616    
2617     *x = tx % settings.worldmaptilesizex;
2618     *y = ty % settings.worldmaptilesizey;
2619     return mapname;
2620 elmex 1.1 }
2621    
2622     /*
2623     * Calculates the distance to the nearest pole. x,y are the weathermap
2624     * coordinates, equator is the current location of the equator. returns
2625     * distance as an int.
2626     */
2627    
2628    
2629 root 1.5 static int
2630     polar_distance (int x, int y, int equator)
2631 elmex 1.1 {
2632 root 1.5 if ((x + y) > equator)
2633     { /* south pole */
2634     x = WEATHERMAPTILESX - x;
2635     y = WEATHERMAPTILESY - y;
2636     return ((x + y) / 2);
2637     }
2638     else if ((x + y) < equator)
2639     { /* north pole */
2640     return ((x + y) / 2);
2641     }
2642     else
2643     {
2644     return equator / 2;
2645 elmex 1.1 }
2646     }
2647    
2648     /*
2649     * update the humidity for all weathermap tiles.
2650     */
2651    
2652 root 1.5 static void
2653     update_humid (void)
2654 elmex 1.1 {
2655 root 1.5 int x, y;
2656 elmex 1.1
2657 root 1.5 for (y = 0; y < WEATHERMAPTILESY; y++)
2658     for (x = 0; x < WEATHERMAPTILESX; x++)
2659     weathermap[x][y].humid = humid_tile (x, y);
2660 elmex 1.1 }
2661    
2662     /*
2663     * calculate the humidity of this tile. x and y are the weathermap coordinates
2664     * we wish to calculate humidity for. Returns the humidity of the weathermap
2665     * square.
2666     */
2667    
2668 root 1.5 static int
2669     humid_tile (int x, int y)
2670 elmex 1.1 {
2671 root 1.5 int ox, oy, humid;
2672 elmex 1.1
2673 root 1.5 ox = x;
2674     oy = y;
2675 elmex 1.1
2676 root 1.5 /* find the square the wind is coming from, without going out of bounds */
2677    
2678     if (weathermap[x][y].winddir == 8 || weathermap[x][y].winddir <= 2)
2679     {
2680     if (y != 0)
2681     oy = y - 1;
2682     }
2683     if (weathermap[x][y].winddir >= 6)
2684     {
2685     if (x != 0)
2686     ox = x - 1;
2687     }
2688     if (weathermap[x][y].winddir >= 4 && weathermap[x][y].winddir <= 6)
2689     {
2690     if (y < WEATHERMAPTILESY - 1)
2691     oy = y + 1;
2692     }
2693     if (weathermap[x][y].winddir >= 2 && weathermap[x][y].winddir <= 4)
2694     {
2695     if (x < WEATHERMAPTILESX - 1)
2696     ox = x + 1;
2697     }
2698     humid = (weathermap[x][y].humid * 2 +
2699     weathermap[ox][oy].humid * weathermap[ox][oy].windspeed +
2700     weathermap[x][y].water + rndm (0, 10)) / (weathermap[ox][oy].windspeed + 3) + rndm (0, 5);
2701     if (humid < 0)
2702     humid = 1;
2703     if (humid > 100)
2704     humid = 100;
2705     return humid;
2706 elmex 1.1 }
2707    
2708     /*
2709     * calculate temperature of the weathermap square x,y. Requires the current
2710     * time of day in *tod.
2711     */
2712    
2713 root 1.5 static void
2714     temperature_calc (int x, int y, const timeofday_t * tod)
2715 elmex 1.1 {
2716 root 1.5 int dist, equator, elev, n;
2717     float diff, tdiff;
2718 elmex 1.1
2719 root 1.5 equator = (WEATHERMAPTILESX + WEATHERMAPTILESY) / 4;
2720     diff = (float) (EQUATOR_BASE_TEMP - POLAR_BASE_TEMP) / (float) equator;
2721     tdiff = (float) SEASONAL_ADJUST / ((float) MONTHS_PER_YEAR / 2.0);
2722     equator *= 2;
2723     n = 0;
2724     /* we essentially move the equator during the season */
2725     if (tod->month > (MONTHS_PER_YEAR / 2))
2726     { /* EOY */
2727     n -= (int) (tod->month * tdiff);
2728     }
2729     else
2730     {
2731     n = (int) ((MONTHS_PER_YEAR - tod->month) * tdiff);
2732     }
2733     dist = polar_distance (x - n / 2, y - n / 2, equator);
2734    
2735     /* now we have the base temp, unadjusted for time. Time adjustment
2736     is not recorded on the map, rather, it's done JIT. */
2737     weathermap[x][y].temp = (int) (dist * diff);
2738     /* just scrap these for now, its mostly ocean */
2739     if (weathermap[x][y].avgelev < 0)
2740     elev = 0;
2741     else
2742     elev = MAX (10000, weathermap[x][y].avgelev) / 1000;
2743     weathermap[x][y].temp -= elev;
2744 elmex 1.1 }
2745    
2746     /* Compute the real (adjusted) temperature of a given weathermap tile.
2747     * This takes into account the wind, base temp, sunlight, and other fun
2748     * things. Seasons are automatically handled by moving the equator.
2749     * Elevation is partially considered in the base temp. x and y are the
2750     * weathermap coordinates.
2751     */
2752    
2753 root 1.5 static int
2754     real_temperature (int x, int y)
2755 elmex 1.1 {
2756 root 1.5 int i, temp;
2757     timeofday_t tod;
2758 elmex 1.1
2759 root 1.5 /* adjust for time of day */
2760     temp = weathermap[x][y].temp;
2761     get_tod (&tod);
2762     for (i = HOURS_PER_DAY / 2; i < HOURS_PER_DAY; i++)
2763     {
2764     temp += season_tempchange[i];
2765     /* high amounts of water has a buffering effect on the temp */
2766     if (weathermap[x][y].water > 33)
2767     i++;
2768     }
2769     for (i = 0; i <= tod.hour; i++)
2770     {
2771     temp += season_tempchange[i];
2772     if (weathermap[x][y].water > 33)
2773     i++;
2774     }
2775    
2776     /* windchill */
2777     for (i = 1; i < weathermap[x][y].windspeed; i += i)
2778     temp--;
2779 elmex 1.1
2780 root 1.5 return temp;
2781 elmex 1.1 }
2782    
2783     /* Given a worldmap name, and x and y on that map, compute the temperature
2784     for a specific square. Used to normalize elevation.
2785     */
2786    
2787 root 1.5 int
2788     real_world_temperature (int x, int y, mapstruct *m)
2789 elmex 1.1 {
2790 root 1.5 int wx, wy, temp, eleva, elevb;
2791     object *op;
2792    
2793     /*LOG(llevDebug, "real_world_temperature: worldmaptoweathermap : %s\n",m->path); */
2794     worldmap_to_weathermap (x, y, &wx, &wy, /*m->path */ m);
2795     temp = real_temperature (wx, wy);
2796     if (weathermap[wx][wy].avgelev < 0)
2797     eleva = 0;
2798     else
2799     eleva = weathermap[x][y].avgelev;
2800    
2801     op = GET_MAP_OB (m, x, y);
2802     if (!op)
2803     return eleva;
2804    
2805     elevb = op->elevation;
2806     if (elevb < 0)
2807     elevb = 0;
2808     if (elevb > eleva)
2809     {
2810     elevb -= eleva;
2811     temp -= elevb / 1000;
2812     }
2813     else
2814     {
2815     elevb = eleva - elevb;
2816     temp += elevb / 1000;
2817 elmex 1.1 }
2818 root 1.5 return temp;
2819 elmex 1.1 }
2820    
2821     /* this code simply smooths the pressure map */
2822    
2823 root 1.5 static void
2824     smooth_pressure (void)
2825 elmex 1.1 {
2826 root 1.5 int x, y;
2827     int k;
2828 elmex 1.1
2829 root 1.5 for (k = 0; k < PRESSURE_ROUNDING_ITER; k++)
2830     {
2831     for (x = 2; x < WEATHERMAPTILESX - 2; x++)
2832     {
2833     for (y = 2; y < WEATHERMAPTILESY - 2; y++)
2834     {
2835     weathermap[x][y].pressure = (weathermap[x][y].pressure *
2836     PRESSURE_ROUNDING_FACTOR + weathermap[x - 1][y].pressure +
2837     weathermap[x][y - 1].pressure + weathermap[x - 1][y - 1].pressure +
2838     weathermap[x + 1][y].pressure + weathermap[x][y + 1].pressure +
2839     weathermap[x + 1][y + 1].pressure + weathermap[x + 1][y - 1].pressure +
2840     weathermap[x - 1][y + 1].pressure) / (PRESSURE_ROUNDING_FACTOR + 8);
2841     }
2842     }
2843     for (x = WEATHERMAPTILESX - 2; x > 2; x--)
2844     {
2845     for (y = WEATHERMAPTILESY - 2; y > 2; y--)
2846     {
2847     weathermap[x][y].pressure = (weathermap[x][y].pressure *
2848     PRESSURE_ROUNDING_FACTOR + weathermap[x - 1][y].pressure +
2849     weathermap[x][y - 1].pressure + weathermap[x - 1][y - 1].pressure +
2850     weathermap[x + 1][y].pressure + weathermap[x][y + 1].pressure +
2851     weathermap[x + 1][y + 1].pressure + weathermap[x + 1][y - 1].pressure +
2852     weathermap[x - 1][y + 1].pressure) / (PRESSURE_ROUNDING_FACTOR + 8);
2853 root 1.3 }
2854     }
2855 elmex 1.1 }
2856    
2857 root 1.5 for (x = 0; x < WEATHERMAPTILESX; x++)
2858     for (y = 0; y < WEATHERMAPTILESY; y++)
2859     {
2860     weathermap[x][y].pressure = MIN (weathermap[x][y].pressure, PRESSURE_MAX);
2861     weathermap[x][y].pressure = MAX (weathermap[x][y].pressure, PRESSURE_MIN);
2862     }
2863 elmex 1.1
2864     }
2865    
2866     /*
2867     * perform small randomizations in the pressure map. Then, apply the
2868     * smoothing algorithim.. This causes the pressure to change very slowly
2869     */
2870    
2871 root 1.5 static void
2872     perform_pressure (void)
2873 elmex 1.1 {
2874 root 1.5 int x, y, l, n, j, k;
2875 elmex 1.1
2876 root 1.5 /* create random spikes in the pressure */
2877     for (l = 0; l < PRESSURE_SPIKES; l++)
2878     {
2879     x = rndm (0, WEATHERMAPTILESX - 1);
2880     y = rndm (0, WEATHERMAPTILESY - 1);
2881     n = rndm (600, 1300);
2882     weathermap[x][y].pressure = n;
2883     if (x > 5 && y > 5 && x < WEATHERMAPTILESX - 5 && y < WEATHERMAPTILESY - 5)
2884     {
2885     for (j = x - 2; j < x + 2; j++)
2886     for (k = y - 2; k < y + 2; k++)
2887     {
2888     weathermap[j][k].pressure = n;
2889     /* occasionally add a storm */
2890     if (rndm (1, 20) == 1)
2891     weathermap[j][k].humid = rndm (50, 80);
2892     }
2893 root 1.3 }
2894 elmex 1.1 }
2895    
2896 root 1.5 for (x = 0; x < WEATHERMAPTILESX; x++)
2897     for (y = 0; y < WEATHERMAPTILESY; y++)
2898     weathermap[x][y].pressure += rndm (-1, 4);
2899 elmex 1.1
2900 root 1.5 smooth_pressure ();
2901 elmex 1.1 }
2902    
2903    
2904     /*
2905     * is direction a similar to direction b? Find out in this exciting function
2906     * below. Returns 1 if true, 0 for false.
2907     */
2908    
2909 root 1.5 int
2910     similar_direction (int a, int b)
2911 elmex 1.1 {
2912 root 1.5 /* shortcut the obvious */
2913     if (a == b)
2914     return 1;
2915    
2916     switch (a)
2917     {
2918     case 1:
2919     if (b <= 2 || b == 8)
2920     return 1;
2921     break;
2922     case 2:
2923     if (b > 0 && b < 4)
2924     return 1;
2925     break;
2926     case 3:
2927     if (b > 1 && b < 5)
2928     return 1;
2929     break;
2930     case 4:
2931     if (b > 2 && b < 6)
2932     return 1;
2933     break;
2934     case 5:
2935     if (b > 3 && b < 7)
2936     return 1;
2937     break;
2938     case 6:
2939     if (b > 4 && b < 8)
2940     return 1;
2941     break;
2942     case 7:
2943     if (b > 5)
2944     return 1;
2945     break;
2946     case 8:
2947     if (b > 6 || b == 1)
2948     return 1;
2949     break;
2950 elmex 1.1 }
2951 root 1.5 return 0;
2952 elmex 1.1 }
2953    
2954     /*
2955     * It doesn't really smooth it as such. The main function of this is to
2956     * apply the pressuremap to the wind direction and speed. Then, we run
2957     * a quick pass to update the windspeed.
2958     */
2959    
2960 root 1.5 static void
2961     smooth_wind (void)
2962 elmex 1.1 {
2963 root 1.5 int x, y;
2964     int tx, ty, dx, dy;
2965     int minp;
2966    
2967     /* skip the outer squares.. it makes handling alot easier */
2968     dx = 0;
2969     dy = 0;
2970     for (x = 1; x < WEATHERMAPTILESX - 1; x++)
2971     for (y = 1; y < WEATHERMAPTILESY - 1; y++)
2972     {
2973     minp = PRESSURE_MAX + 1;
2974     for (tx = -1; tx < 2; tx++)
2975     for (ty = -1; ty < 2; ty++)
2976     if (!(tx == 0 && ty == 0))
2977     if (weathermap[x + tx][y + ty].pressure < minp)
2978     {
2979     minp = weathermap[x + tx][y + ty].pressure;
2980     dx = tx;
2981     dy = ty;
2982     }
2983    
2984     /* if the wind is strong, the pressure won't decay it completely */
2985     if (weathermap[x][y].windspeed > 5 && !similar_direction (weathermap[x][y].winddir, find_dir_2 (dx, dy)))
2986     {
2987     weathermap[x][y].windspeed -= 2 * 2;
2988     }
2989     else
2990     {
2991     weathermap[x][y].winddir = find_dir_2 (dx, dy);
2992     weathermap[x][y].windspeed = (sint8) ((weathermap[x][y].pressure - weathermap[x + dx][y + dy].pressure) * WIND_FACTOR);
2993     }
2994     /* Add in sea breezes. */
2995     weathermap[x][y].windspeed += weathermap[x][y].water / 4;
2996     if (weathermap[x][y].windspeed < 0)
2997     weathermap[x][y].windspeed = 0;
2998     }
2999    
3000     /* now, lets crank on the speed. When surrounding tiles all have
3001     the same speed, inc ours. If it's chaos. drop it.
3002     */
3003     for (x = 1; x < WEATHERMAPTILESX - 1; x++)
3004     for (y = 1; y < WEATHERMAPTILESY - 1; y++)
3005     {
3006     minp = 0;
3007     for (tx = -1; tx < 2; tx++)
3008     for (ty = -1; ty < 2; ty++)
3009     if (ty != 0 && ty != 0)
3010     if (similar_direction (weathermap[x][y].winddir, weathermap[x + tx][y + ty].winddir))
3011     minp++;
3012     if (minp > 4)
3013     weathermap[x][y].windspeed++;
3014     if (minp > 6)
3015     weathermap[x][y].windspeed += 2;
3016     if (minp < 2)
3017     weathermap[x][y].windspeed--;
3018     if (weathermap[x][y].windspeed < 0)
3019     weathermap[x][y].windspeed = 0;
3020     }
3021 elmex 1.1 }
3022    
3023     /*
3024     * Plot the gulfstream map over the wind map. This is done after the wind,
3025     * to avoid the windsmoothing scrambling the jet stream.
3026     */
3027    
3028 root 1.5 static void
3029     plot_gulfstream (void)
3030 elmex 1.1 {
3031 root 1.5 int x, y, tx;
3032 elmex 1.1
3033 root 1.5 x = gulf_stream_start;
3034 elmex 1.1
3035 root 1.5 if (gulf_stream_direction)
3036     {
3037     for (y = WEATHERMAPTILESY - 1; y > 0; y--)
3038     {
3039     for (tx = 0; tx < GULF_STREAM_WIDTH && x + tx < WEATHERMAPTILESX; tx++)
3040     {
3041     if (similar_direction (weathermap[x + tx][y].winddir,
3042     gulf_stream_dir[tx][y]) && weathermap[x + tx][y].windspeed < GULF_STREAM_BASE_SPEED - 5)
3043     weathermap[x + tx][y].windspeed += gulf_stream_speed[tx][y];
3044     else
3045     weathermap[x + tx][y].windspeed = gulf_stream_speed[tx][y];
3046     weathermap[x + tx][y].winddir = gulf_stream_dir[tx][y];
3047     if (tx == GULF_STREAM_WIDTH - 1)
3048     {
3049     switch (gulf_stream_dir[tx][y])
3050     {
3051     case 6:
3052     x--;
3053     break;
3054     case 7:
3055     break;
3056     case 8:
3057     x++;;
3058     break;
3059     }
3060     }
3061     if (x < 0)
3062     x++;
3063     if (x >= WEATHERMAPTILESX - GULF_STREAM_WIDTH)
3064     x--;
3065     }
3066     }
3067     }
3068     else
3069     {
3070     for (y = 0; y < WEATHERMAPTILESY - 1; y++)
3071     {
3072     for (tx = 0; tx < GULF_STREAM_WIDTH && x + tx < WEATHERMAPTILESX; tx++)
3073     {
3074     if (similar_direction (weathermap[x + tx][y].winddir,
3075     gulf_stream_dir[tx][y]) && weathermap[x + tx][y].windspeed < GULF_STREAM_BASE_SPEED - 5)
3076     weathermap[x + tx][y].windspeed += gulf_stream_speed[tx][y];
3077     else
3078     weathermap[x + tx][y].windspeed = gulf_stream_speed[tx][y];
3079     weathermap[x + tx][y].winddir = gulf_stream_dir[tx][y];
3080     if (tx == GULF_STREAM_WIDTH - 1)
3081     {
3082     switch (gulf_stream_dir[tx][y])
3083     {
3084     case 2:
3085     x++;
3086     break;
3087     case 3:
3088     break;
3089     case 4:
3090     x--;
3091     break;
3092     }
3093     }
3094     if (x < 0)
3095     x++;
3096     if (x >= WEATHERMAPTILESX - GULF_STREAM_WIDTH)
3097     x--;
3098     }
3099     }
3100     }
3101     /* occasionally move the stream */
3102     if (rndm (1, 500) == 1)
3103     {
3104     gulf_stream_direction = rndm (0, 1);
3105     for (tx = 0; tx < GULF_STREAM_WIDTH; tx++)
3106     for (y = 0; y < WEATHERMAPTILESY - 1; y++)
3107     if (gulf_stream_direction)
3108     switch (gulf_stream_dir[tx][y])
3109     {
3110     case 2:
3111     gulf_stream_dir[tx][y] = 6;
3112     break;
3113     case 3:
3114     gulf_stream_dir[tx][y] = 7;
3115     break;
3116     case 4:
3117     gulf_stream_dir[tx][y] = 8;
3118     break;
3119     }
3120     else
3121     switch (gulf_stream_dir[tx][y])
3122     {
3123     case 6:
3124     gulf_stream_dir[tx][y] = 2;
3125     break;
3126     case 7:
3127     gulf_stream_dir[tx][y] = 3;
3128     break;
3129     case 8:
3130     gulf_stream_dir[tx][y] = 4;
3131     break;
3132     }
3133 elmex 1.1 }
3134 root 1.5 if (rndm (1, 25) == 1)
3135     gulf_stream_start += rndm (-1, 1);
3136     if (gulf_stream_start >= WEATHERMAPTILESX - GULF_STREAM_WIDTH)
3137     gulf_stream_start--;
3138     if (gulf_stream_start < 1)
3139     gulf_stream_start++;
3140 elmex 1.1
3141     }
3142    
3143     /*
3144     * let the madness, begin.
3145     *
3146     * This function is the one that ties everything together. Here we loop
3147     * over all the weathermaps, and compare the various conditions we have
3148     * calculated up to now, to figure out what the sky conditions are for this
3149     * square.
3150     */
3151    
3152 root 1.5 static void
3153     compute_sky (void)
3154 elmex 1.1 {
3155 root 1.5 int x, y;
3156     int temp;
3157 elmex 1.1
3158 root 1.5 for (x = 0; x < WEATHERMAPTILESX; x++)
3159     {
3160     for (y = 0; y < WEATHERMAPTILESY; y++)
3161     {
3162     temp = real_temperature (x, y);
3163     if (weathermap[x][y].pressure < 980)
3164     {
3165     if (weathermap[x][y].humid < 20)
3166     weathermap[x][y].sky = SKY_LIGHTCLOUD;
3167     else if (weathermap[x][y].humid < 30)
3168     weathermap[x][y].sky = SKY_OVERCAST;
3169     else if (weathermap[x][y].humid < 40)
3170     weathermap[x][y].sky = SKY_LIGHT_RAIN;
3171     else if (weathermap[x][y].humid < 55)
3172     weathermap[x][y].sky = SKY_RAIN;
3173     else if (weathermap[x][y].humid < 70)
3174     weathermap[x][y].sky = SKY_HEAVY_RAIN;
3175     else
3176     weathermap[x][y].sky = SKY_HURRICANE;
3177     if (weathermap[x][y].sky < SKY_HURRICANE && weathermap[x][y].windspeed > 30)
3178     weathermap[x][y].sky++;
3179     if (temp <= 0 && weathermap[x][y].sky > SKY_OVERCAST)
3180     weathermap[x][y].sky += 10; /*let it snow */
3181     }
3182     else if (weathermap[x][y].pressure < 1000)
3183     {
3184     if (weathermap[x][y].humid < 10)
3185     weathermap[x][y].sky = SKY_CLEAR;
3186     else if (weathermap[x][y].humid < 25)
3187     weathermap[x][y].sky = SKY_LIGHTCLOUD;
3188     else if (weathermap[x][y].humid < 45)
3189     weathermap[x][y].sky = SKY_OVERCAST;
3190     else if (weathermap[x][y].humid < 60)
3191     weathermap[x][y].sky = SKY_LIGHT_RAIN;
3192     else if (weathermap[x][y].humid < 75)
3193     weathermap[x][y].sky = SKY_RAIN;
3194     else
3195     weathermap[x][y].sky = SKY_HEAVY_RAIN;
3196     if (weathermap[x][y].sky < SKY_HURRICANE && weathermap[x][y].windspeed > 30)
3197     weathermap[x][y].sky++;
3198     if (temp <= 0 && weathermap[x][y].sky > SKY_OVERCAST)
3199     weathermap[x][y].sky += 10; /*let it snow */
3200     if (temp > 0 && temp < 5 && weathermap[x][y].humid > 95 && weathermap[x][y].windspeed < 3)
3201     weathermap[x][y].sky = SKY_FOG; /* rare */
3202     if (temp > 0 && temp < 5 && weathermap[x][y].humid > 70 && weathermap[x][y].windspeed > 35)
3203     weathermap[x][y].sky = SKY_HAIL; /* rare */
3204     }
3205     else if (weathermap[x][y].pressure < 1020)
3206     {
3207     if (weathermap[x][y].humid < 20)
3208     weathermap[x][y].sky = SKY_CLEAR;
3209     else if (weathermap[x][y].humid < 30)
3210     weathermap[x][y].sky = SKY_LIGHTCLOUD;
3211     else if (weathermap[x][y].humid < 40)
3212     weathermap[x][y].sky = SKY_OVERCAST;
3213     else if (weathermap[x][y].humid < 55)
3214     weathermap[x][y].sky = SKY_LIGHT_RAIN;
3215     else if (weathermap[x][y].humid < 70)
3216     weathermap[x][y].sky = SKY_RAIN;
3217     else
3218     weathermap[x][y].sky = SKY_HEAVY_RAIN;
3219     if (weathermap[x][y].sky < SKY_HURRICANE && weathermap[x][y].windspeed > 30)
3220     weathermap[x][y].sky++;
3221     if (temp <= 0 && weathermap[x][y].sky > SKY_OVERCAST)
3222     weathermap[x][y].sky += 10; /*let it snow */
3223     }
3224     else
3225     {
3226     if (weathermap[x][y].humid < 35)
3227     weathermap[x][y].sky = SKY_CLEAR;
3228     else if (weathermap[x][y].humid < 55)
3229     weathermap[x][y].sky = SKY_LIGHTCLOUD;
3230     else if (weathermap[x][y].humid < 70)
3231     weathermap[x][y].sky = SKY_OVERCAST;
3232     else if (weathermap[x][y].humid < 85)
3233     weathermap[x][y].sky = SKY_LIGHT_RAIN;
3234     else if (weathermap[x][y].humid < 95)
3235     weathermap[x][y].sky = SKY_RAIN;
3236     else
3237     weathermap[x][y].sky = SKY_HEAVY_RAIN;
3238     if (weathermap[x][y].sky < SKY_HURRICANE && weathermap[x][y].windspeed > 30)
3239     weathermap[x][y].sky++;
3240     if (temp <= 0 && weathermap[x][y].sky > SKY_OVERCAST)
3241     weathermap[x][y].sky += 10; /*let it snow */
3242 root 1.3 }
3243     }
3244 elmex 1.1 }
3245     }
3246    
3247     /*
3248     * Keep track of how much rain has fallen in a given weathermap square.
3249     */
3250    
3251 root 1.5 static void
3252     process_rain (void)
3253 elmex 1.1 {
3254 root 1.5 int x, y, rain;
3255 elmex 1.1
3256 root 1.5 for (x = 0; x < WEATHERMAPTILESX; x++)
3257     for (y = 0; y < WEATHERMAPTILESY; y++)
3258     {
3259     rain = weathermap[x][y].sky;
3260     if (rain >= SKY_LIGHT_SNOW)
3261     rain -= 10;
3262     if (rain > SKY_OVERCAST && rain < SKY_FOG)
3263     {
3264     rain -= SKY_OVERCAST;
3265     weathermap[x][y].rainfall += rain;
3266     }
3267     }
3268 elmex 1.1 }
3269    
3270     /*
3271     * The world spinning drags the weather with it.
3272     * The equator is diagonal, and the poles are 45 degrees from north /south.
3273     * What the hell, lets spin the planet backwards.
3274     */
3275    
3276 root 1.5 static void
3277     spin_globe (void)
3278 elmex 1.1 {
3279 root 1.5 int x, y;
3280     int buffer_humid;
3281     int buffer_sky;
3282    
3283     for (y = 0; y < WEATHERMAPTILESY; y++)
3284     {
3285     buffer_humid = weathermap[0][y].humid;
3286     buffer_sky = weathermap[0][y].sky;
3287     for (x = 0; x < (WEATHERMAPTILESX - 1); x++)
3288     {
3289     weathermap[x][y].humid = weathermap[x + 1][y].humid;
3290     weathermap[x][y].sky = weathermap[x + 1][y].sky;
3291 root 1.3 }
3292 root 1.5 weathermap[WEATHERMAPTILESX - 1][y].humid = buffer_humid;
3293     weathermap[WEATHERMAPTILESX - 1][y].sky = buffer_sky;
3294     }
3295 elmex 1.1 }
3296    
3297     /*
3298     * Dump all the weather data as an image.
3299     * Writes two other files that are useful for creating animations and web pages.
3300     */
3301    
3302 root 1.5 static void
3303     write_weather_images (void)
3304 elmex 1.1 {
3305 root 1.5 char filename[MAX_BUF];
3306     FILE *fp;
3307     int x, y;
3308     sint32 min[10], max[10], realmaxwind;
3309     uint32 avgrain, avgwind;
3310     double scale[10], realscalewind;
3311     uint8 pixels[3 * 3 * WEATHERMAPTILESX];
3312     sint64 total_rainfall = 0;
3313     sint64 total_wind = 0;
3314    
3315     min[0] = 0;
3316     max[0] = 100;
3317     min[1] = 0;
3318     max[1] = 0;
3319     min[2] = 0;
3320     max[2] = 0;
3321     min[3] = PRESSURE_MIN;
3322     max[3] = PRESSURE_MAX;
3323     min[4] = 0;
3324     max[4] = 0;
3325     min[5] = 1;
3326     max[5] = 8;
3327     min[6] = 0;
3328     max[6] = 100;
3329     min[7] = -45;
3330     max[7] = 45;
3331     min[8] = 0;
3332     max[8] = 16;
3333     min[9] = 0;
3334     max[9] = 0;
3335     for (x = 0; x < WEATHERMAPTILESX; x++)
3336     {
3337     for (y = 0; y < WEATHERMAPTILESY; y++)
3338     {
3339    
3340 elmex 1.1 /* min[0] = MIN(min[0], weathermap[x][y].water); */
3341 root 1.5 min[1] = MIN (min[1], weathermap[x][y].avgelev);
3342     min[2] = MIN ((uint32) min[2], weathermap[x][y].rainfall);
3343    
3344 elmex 1.1 /* min[3] = MIN(min[3], weathermap[x][y].pressure); */
3345 root 1.5 min[4] = MIN (min[4], weathermap[x][y].windspeed);
3346    
3347 elmex 1.1 /* min[5] = MIN(min[5], weathermap[x][y].winddir); */
3348 root 1.5
3349 elmex 1.1 /* min[6] = MIN(min[6], weathermap[x][y].humid); */
3350 root 1.5
3351 elmex 1.1 /* min[7] = MIN(min[7], real_temp[x][y]); */
3352 root 1.5
3353 elmex 1.1 /* min[8] = MIN(min[8], weathermap[x][y].sky); */
3354 root 1.5
3355 elmex 1.1 /* min[9] = MIN(min[9], weathermap[x][y].darkness); */
3356    
3357     /* max[0] = MAX(max[0], weathermap[x][y].water); */
3358 root 1.5 max[1] = MAX (max[1], weathermap[x][y].avgelev);
3359     max[2] = MAX ((uint32) max[2], weathermap[x][y].rainfall);
3360    
3361 elmex 1.1 /* max[3] = MAX(max[3], weathermap[x][y].pressure); */
3362 root 1.5 max[4] = MAX (max[4], weathermap[x][y].windspeed);
3363    
3364 elmex 1.1 /* max[5] = MAX(max[5], weathermap[x][y].winddir); */
3365 root 1.5
3366 elmex 1.1 /* max[6] = MAX(max[6], weathermap[x][y].humid); */
3367 root 1.5
3368 elmex 1.1 /* max[7] = MAX(max[7], real_temp[x][y]); */
3369 root 1.5
3370 elmex 1.1 /* max[8] = MAX(max[8], weathermap[x][y].sky); */
3371 root 1.5
3372 elmex 1.1 /* max[9] = MAX(max[9], weathermap[x][y].darkness); */
3373 root 1.5 total_rainfall += weathermap[x][y].rainfall;
3374     total_wind += weathermap[x][y].windspeed;
3375 root 1.3 }
3376 elmex 1.1 }
3377 root 1.5 avgrain = total_rainfall / (WEATHERMAPTILESX * WEATHERMAPTILESY);
3378     avgwind = (total_wind / ((WEATHERMAPTILESX * WEATHERMAPTILESY) * 3 / 2));
3379     max[2] = avgrain - 1;
3380     realscalewind = 255.0l / (max[4] - min[4]);
3381     realmaxwind = max[4];
3382     max[4] = avgwind - 1;
3383     for (x = 0; x < 10; x++)
3384     scale[x] = 255.0l / (max[x] - min[x]);
3385    
3386     sprintf (filename, "%s/weather.ppm", settings.localdir);
3387     if ((fp = fopen (filename, "w")) == NULL)
3388     {
3389     LOG (llevError, "Cannot open %s for writing\n", filename);
3390     return;
3391     }
3392     fprintf (fp, "P6\n%d %d\n", 3 * WEATHERMAPTILESX, 3 * WEATHERMAPTILESY);
3393     fprintf (fp, "255\n");
3394     for (y = 0; y < WEATHERMAPTILESY; y++)
3395     {
3396     for (x = 0; x < (3 * 3 * WEATHERMAPTILESX); x++)
3397     pixels[x] = 0;
3398     for (x = 0; x < WEATHERMAPTILESX; x++)
3399     {
3400     pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((weathermap[x][y].water - min[0]) * scale[0]);
3401     if (weathermap[x][y].avgelev >= 0)
3402     pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + GREEN)] = (uint8) ((weathermap[x][y].avgelev - min[1]) * scale[1]);
3403     else
3404     pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((weathermap[x][y].avgelev - min[1]) * scale[1]);
3405     if (weathermap[x][y].rainfall >= avgrain) /* rainfall is rather spikey, this gives us more detail. */
3406     pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + RED)] = 255;
3407     else
3408     pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((weathermap[x][y].rainfall - min[2]) * scale[2]);
3409     }
3410     fwrite (pixels, sizeof (uint8), (3 * 3 * WEATHERMAPTILESX), fp);
3411     }
3412     for (y = 0; y < WEATHERMAPTILESY; y++)
3413     {
3414     for (x = 0; x < WEATHERMAPTILESX; x++)
3415     {
3416     uint32 dir = directions[weathermap[x][y].winddir - 1];
3417     uint32 speed = weathermap[x][y].windspeed;
3418     uint8 pressure = (uint8) ((weathermap[x][y].pressure - min[3]) * scale[3]);
3419    
3420     pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + RED)] = pressure;
3421     pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + GREEN)] = pressure;
3422     pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + BLUE)] = pressure;
3423     if (speed < avgwind)
3424     {
3425     speed = (uint32) ((speed - min[4]) * scale[4]);
3426     pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + RED)] = speed;
3427     pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + GREEN)] = speed;
3428     pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + BLUE)] = speed;
3429     }
3430     else
3431     {
3432     speed = (uint32) ((speed - realmaxwind) * realscalewind);
3433    
3434 elmex 1.1 /* if (speed < 100)*/
3435 root 1.5
3436 elmex 1.1 /* speed = 100;*/
3437 root 1.5 pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + RED)] = speed;
3438     pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + GREEN)] = 0;
3439     pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + BLUE)] = 0;
3440     }
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     fwrite (pixels, sizeof (uint8), (3 * 3 * WEATHERMAPTILESX), fp);
3446     }
3447     for (y = 0; y < WEATHERMAPTILESY; y++)
3448     {
3449     for (x = 0; x < (3 * 3 * WEATHERMAPTILESX); x++)
3450     pixels[x] = 0;
3451     for (x = 0; x < WEATHERMAPTILESX; x++)
3452     {
3453     uint32 dir = skies[weathermap[x][y].sky];
3454    
3455     pixels[3 * x + (0 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((weathermap[x][y].humid - min[6]) * scale[6]);
3456     /*pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + RED)] = (uint8) ((real_temp[x][y] - min[7]) * scale[7]); */
3457     pixels[3 * x + (1 * WEATHERMAPTILESX * 3 + RED)] = 1;
3458     pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + RED)] = (uint8) ((dir & 0x00FF0000) >> 16);
3459     pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + GREEN)] = (uint8) ((dir & 0x0000FF00) >> 8);
3460     pixels[3 * x + (2 * WEATHERMAPTILESX * 3 + BLUE)] = (uint8) ((dir & 0x000000FF));
3461    
3462     }
3463     fwrite (pixels, sizeof (uint8), (3 * 3 * WEATHERMAPTILESX), fp);
3464     }
3465     fclose (fp);
3466    
3467     sprintf (filename, "%s/todtick", settings.localdir);
3468     if ((fp = fopen (filename, "w")) == NULL)
3469     {
3470     LOG (llevError, "Cannot open %s for writing\n", filename);
3471     return;
3472 elmex 1.1 }
3473 root 1.5 fprintf (fp, "%lu", todtick);
3474     fclose (fp);
3475 elmex 1.1 }