ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/weather.C
Revision: 1.13
Committed: Wed Dec 27 13:13:47 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.12: +3 -1 lines
Log Message:
misc stuff

File Contents

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