ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/weather.C
(Generate patch)

Comparing deliantra/server/server/weather.C (file contents):
Revision 1.5 by root, Sun Sep 10 15:59:58 2006 UTC vs.
Revision 1.14 by root, Sat Dec 30 10:16:11 2006 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines