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.11 by root, Mon Dec 25 14:54:44 2006 UTC vs.
Revision 1.16 by pippijn, Mon Jan 15 21:06:20 2007 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines