1 #include <math.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "weather.h"
5 #include "actors.h"
6 #include "asc.h"
7 #include "client_serv.h"
8 #include "draw_scene.h"
9 #include "elconfig.h"
10 #include "interface.h"
11 #include "map.h"
12 #include "misc.h"
13 #include "particles.h"
14 #include "textures.h"
15 #include "shadows.h"
16 #include "sound.h"
17 #include <SDL_timer.h>
18 #include "errors.h"
19 #include "text.h"
20 #ifdef OPENGL_TRACE
21 #include "gl_init.h"
22 #endif
23 #include "sky.h"
24
25 int use_fog = 1;
26 int show_weather = 1;
27
28 int wind_speed_srv = 0; //strength of wind, as set by server. 100 is about the max
29 int wind_direction_srv = 0; //wind direction, in degrees, as set by server. 0 and 360 == north
30 int wind_speed = 0; //strength of wind, based on server's setting and local randomization
31 int wind_direction = 0; //wind direction, based on server's setting and local randomization
32
33
34 /* N E W W E A T H E R *****************************************************/
35
36 #define MAX_RAIN_DROPS 10000
37 #define MAX_LIGHTNING_DEFS 20
38 #define MAX_THUNDERS 20
39
40 #define LIGHTNING_LIGHT_RADIUS 20.0
41 #define SOUND_SPEED 0.1 // real sound speed = 0.34029 m/ms
42
43 #define WEATHER_NONE 0
44 #define WEATHER_RAIN 1
45
46 typedef struct
47 {
48 float pos1[3];
49 float pos2[3];
50 } weather_drop;
51
52 typedef struct {
53 int use_sprites;
54 float density;
55 float color[4];
56 float size;
57 float speed;
58 float wind_effect;
59 int texture;
60 } weather_def;
61
62 typedef struct
63 {
64 float x_pos;
65 float y_pos;
66 float radius;
67 int type;
68 float intensity;
69 float intensity_change_speed;
70 int intensity_change_duration;
71 } weather_area;
72
73 typedef struct {
74 int type;
75 float x_pos;
76 float y_pos;
77 Uint32 time;
78 } thunder;
79
80 typedef struct {
81 int texture;
82 float coords[4]; // left bottom right top
83 } lightning_def;
84
85 weather_drop weather_drops[MAX_WEATHER_TYPES][MAX_RAIN_DROPS];
86 int weather_drops_count[MAX_WEATHER_TYPES];
87
88 weather_def weather_defs[MAX_WEATHER_TYPES];
89
90 weather_area weather_areas[MAX_WEATHER_AREAS];
91
92 lightning_def lightnings_defs[MAX_LIGHTNING_DEFS];
93 int lightnings_defs_count = 0;
94
95 thunder thunders[MAX_THUNDERS];
96 int thunders_count = 0;
97
98 Uint32 lightning_stop = 0;
99 int lightning_type;
100 float lightning_position[4] = {0.0, 0.0, 100.0, 1.0};
101 float lightning_sky_position[4] = {0.0, 0.0, 0.0, 1.0};
102 float lightning_color[4] = {0.9, 0.85, 1.0, 1.0};
103 float lightning_ambient_color[4] = {0.50, 0.45, 0.55, 1.0};
104 int lightning_falling = 0;
105
106 float weather_ratios[MAX_WEATHER_TYPES];
107
108 float current_weather_density;
109
110 #define RANDOM_TABLE_SIZE 100000
111 #define RAND_ONE (next_random_number())
112
113 float random_table[RANDOM_TABLE_SIZE];
114 int last_random_number = -1;
115
116 #ifdef NEW_SOUND
117 unsigned int rain_sound = 0;
118 #endif //NEW_SOUND
119
120 float weather_color[4] = {0.0, 0.0, 0.0, 1.0};
121 float fog_alpha;
122
123 // array used to build coordinates of quads to display particles
124 float weather_particles_coords[MAX_RAIN_DROPS*20];
125
next_random_number()126 static __inline__ float next_random_number()
127 {
128 last_random_number = (last_random_number+1)%RANDOM_TABLE_SIZE;
129 return random_table[last_random_number];
130 }
131
132 int weather_read_defs(const char *file_name);
133
get_weather_type_for_map(void)134 weather_type get_weather_type_for_map(void)
135 {
136 if ((cur_map < 0) || (continent_maps[cur_map].weather == 0))
137 return weather_effect_rain;
138 return continent_maps[cur_map].weather;
139 }
140
get_weather_type_from_string(const char * weather_name)141 weather_type get_weather_type_from_string(const char *weather_name)
142 {
143 size_t i;
144 const weather_type w_types[] = {weather_effect_rain, weather_effect_snow, weather_effect_hail,
145 weather_effect_sand, weather_effect_dust, weather_effect_lava };
146 const char* const w_names[] = { "rain", "snow", "hail", "sand", "dust", "lava" };
147 if (strlen(weather_name) > 0)
148 for (i=0; i<6; i++)
149 if (strcasecmp(w_names[i], weather_name) == 0)
150 return w_types[i];
151 return 0;
152 }
153
weather_init()154 void weather_init()
155 {
156 int i;
157
158 for (i = 0; i < MAX_WEATHER_TYPES; ++i)
159 {
160 weather_ratios[i] = 0.0;
161 weather_drops_count[i] = 0;
162 weather_defs[i].use_sprites = 0;
163 weather_defs[i].density = 0.0;
164 weather_defs[i].color[0] = 0.0;
165 weather_defs[i].color[1] = 0.0;
166 weather_defs[i].color[2] = 0.0;
167 weather_defs[i].color[3] = 0.0;
168 weather_defs[i].size = 0.0;
169 weather_defs[i].speed = 0.0;
170 weather_defs[i].wind_effect = 0.0;
171 weather_defs[i].texture = -1;
172 }
173 weather_ratios[0] = 1.0;
174
175 for (i = 0; i < MAX_WEATHER_AREAS; ++i)
176 {
177 weather_areas[i].type = 0;
178 }
179
180 // init the random numbers table
181 for (i = 0; i < RANDOM_TABLE_SIZE; ++i)
182 random_table[i] = (float)rand() / (float)RAND_MAX;
183
184 // init the particles texture coordinates
185 for (i = 0; i < MAX_RAIN_DROPS; ++i)
186 {
187 const int j = i*20;
188 weather_particles_coords[j ] = 0.0f;
189 weather_particles_coords[j+1 ] = 0.0f;
190 weather_particles_coords[j+5 ] = 1.0f;
191 weather_particles_coords[j+6 ] = 0.0f;
192 weather_particles_coords[j+10] = 1.0f;
193 weather_particles_coords[j+11] = 1.0f;
194 weather_particles_coords[j+15] = 0.0f;
195 weather_particles_coords[j+16] = 1.0f;
196 }
197
198 weather_read_defs("./weather.xml");
199 }
200
weather_clear()201 void weather_clear()
202 {
203 int i;
204 thunders_count = 0;
205 lightning_stop = 0;
206 lightning_falling = 0;
207 weather_ratios[0] = 1.0;
208 for(i = 1; i < MAX_WEATHER_TYPES; ++i)
209 {
210 weather_ratios[i] = 0.0;
211 weather_drops_count[i] = 0;
212 }
213
214 for (i = 0; i < MAX_WEATHER_AREAS; ++i)
215 {
216 weather_areas[i].type = 0;
217 }
218 }
219
weather_set_area(int area,float x,float y,float radius,int type,float intensity,int change_duration)220 void weather_set_area(int area, float x, float y, float radius, int type, float intensity, int change_duration)
221 {
222 if (weather_areas[area].type == 0) weather_areas[area].intensity = 0.0;
223
224 weather_areas[area].type = type;
225 weather_areas[area].x_pos = x;
226 weather_areas[area].y_pos = y;
227 weather_areas[area].radius = radius;
228 weather_areas[area].intensity_change_duration = 1 + change_duration * 1000;
229 weather_areas[area].intensity_change_speed = (intensity - weather_areas[area].intensity) / weather_areas[area].intensity_change_duration;
230
231 #ifdef DEBUG
232 printf("setting area %d at %f,%f with radius %f\n",
233 area, x, y, radius);
234 #endif // DEBUG
235 }
236
weather_get_from_server(const Uint8 * data)237 void weather_get_from_server(const Uint8* data)
238 {
239 /*
240 //first, catch non-precipitations
241 if(data[0] == weather_effect_wind){
242 wind_direction_srv = (2 * data[1])%360;
243 wind_speed_srv = data[2];
244 return;
245 } else if(data[0] == weather_effect_leaves){
246 //EC_TAG
247 return;
248 } else if(data[0] > MAX_WEATHER_TYPES){
249 #ifdef DEBUG
250 LOG_TO_CONSOLE(c_red1, "Server sent an unknown weather type");
251 #endif // DEBUG
252 LOG_ERROR("Server sent unknown weather type %d", data[0]);
253 return;
254 //from now on, deal with the set of precipitations
255 } else if(data[2] == 0 && !weather_active()){
256 return; //stop? but we're already stopped...
257 } else if(data[2] != 0 && weather_active()){
258 set_weather_ratio(data[0], data[2]);
259 return;
260 } else if(data[2] != 0 && !weather_active()){
261 set_weather_ratio(data[0], data[2]);
262 start_weather(data[1], ((float)(data[2]))/100.0f);
263 return;
264 } else {
265 stop_weather(data[1], ((float)(data[2]))/100.0f);
266 }
267 */
268 }
269
weather_compute_ratios(float ratios[MAX_WEATHER_TYPES],float x,float y)270 void weather_compute_ratios(float ratios[MAX_WEATHER_TYPES], float x, float y)
271 {
272 int i;
273 float sum = 0.0;
274
275 // we reset all the values
276 for (i = 0; i < MAX_WEATHER_TYPES; ++i)
277 ratios[i] = 0.0;
278
279 // we compute the intensity for each type of weather according to the areas
280 for (i = 0; i < MAX_WEATHER_AREAS; ++i)
281 if (weather_areas[i].type > 0)
282 {
283 float dx = x - weather_areas[i].x_pos;
284 float dy = y - weather_areas[i].y_pos;
285 float dist = dx*dx + dy*dy;
286 float r = weather_areas[i].radius*weather_areas[i].radius;
287 if (dist < r)
288 ratios[weather_areas[i].type] += (1.0 - dist/r) * weather_areas[i].intensity;
289 }
290
291 // we compute the sum of all the intensities
292 for (i = 1; i < MAX_WEATHER_TYPES; ++i)
293 sum += ratios[i];
294
295 if (sum < 1.0)
296 {
297 ratios[0] = 1.0 - sum;
298 }
299 else
300 {
301 // we normalize the intensities if needed
302 ratios[0] = 0.0;
303 for (i = 1; i < MAX_WEATHER_TYPES; ++i)
304 ratios[i] /= sum;
305 }
306 }
307
weather_get_color_from_ratios(float color[4],float ratios[MAX_WEATHER_TYPES])308 void weather_get_color_from_ratios(float color[4], float ratios[MAX_WEATHER_TYPES])
309 {
310 int i, j;
311 for(i = 0; i < 4; ++i)
312 {
313 color[i] = 0.0;
314 for(j = 0; j < MAX_WEATHER_TYPES; ++j)
315 {
316 color[i] += weather_defs[j].color[i] * ratios[j];
317 }
318 }
319 }
320
make_drop(int type,int i,float x,float y,float z)321 static __inline__ void make_drop(int type, int i, float x, float y, float z)
322 {
323 weather_drops[type][i].pos1[0] = x + 16.0f * RAND_ONE - 8.0f;
324 weather_drops[type][i].pos1[1] = y + 16.0f * RAND_ONE - 8.0f;
325 weather_drops[type][i].pos1[2] = z + 10.0f * RAND_ONE + 2.0f;
326 }
327
update_wind(void)328 void update_wind(void)
329 {
330 int dir_d = wind_direction_srv + (int)((float)(RAND_ONE * 60 - 30));
331 int speed_d = wind_speed_srv + (int)((float)(RAND_ONE * ((float)wind_speed)/5.0f - ((float)wind_speed)/10.0f));
332 if(dir_d < wind_direction){
333 --wind_direction;
334 } else if(dir_d > wind_direction){
335 ++wind_direction;
336 }
337 wind_direction %= 360;
338 if(speed_d <= 0){
339 speed_d = 0;
340 } else if(speed_d > 1000){
341 speed_d = 1000;
342 }
343 if(speed_d < wind_speed){
344 --wind_speed;
345 } else if(speed_d > wind_speed){
346 ++wind_speed;
347 }
348 }
349
update_weather_type(int type,float x,float y,float z,int ticks)350 void update_weather_type(int type, float x, float y, float z, int ticks)
351 {
352 int num_drops = weather_ratios[type] * weather_defs[type].density * particles_percentage * 0.01 * MAX_RAIN_DROPS;
353
354 if (num_drops > MAX_RAIN_DROPS) num_drops = MAX_RAIN_DROPS;
355
356 if (weather_drops_count[type] > num_drops)
357 weather_drops_count[type] = num_drops;
358
359 if (num_drops > 0)
360 {
361 int i;
362 float x_move = weather_defs[type].wind_effect * sinf((float)wind_direction*M_PI/180) * wind_speed;
363 float y_move = weather_defs[type].wind_effect * cosf((float)wind_direction*M_PI/180) * wind_speed;
364 float z_move = -weather_defs[type].speed;
365 float dt = ticks * 1E-3;
366 float dx, dy, dz;
367
368 for(i = 0; i < weather_drops_count[type]; ++i)
369 {
370 dx = x_move*(1.1-0.2*RAND_ONE);
371 dy = y_move*(1.1-0.2*RAND_ONE);
372 dz = z_move*(1.1-0.2*RAND_ONE);
373
374 if (weather_drops[type][i].pos1[2] < z-1.0f)
375 {
376 // the drop should still exist so we recreate it
377 make_drop(type, i, x, y, z);
378 }
379 else
380 {
381 // it's moving. so find out how much by, and wrap around the X/Y if it's too far away (as wind can cause)
382 weather_drops[type][i].pos1[0] += dx * dt;
383 if (weather_drops[type][i].pos1[0] < x - 8.0f)
384 {
385 weather_drops[type][i].pos1[0] += 16.0f;
386 weather_drops[type][i].pos2[0] += 16.0f;
387 }
388 else if(weather_drops[type][i].pos1[0] > x + 8.0f)
389 {
390 weather_drops[type][i].pos1[0] -= 16.0f;
391 weather_drops[type][i].pos2[0] -= 16.0f;
392 }
393
394 weather_drops[type][i].pos1[1] += dy * dt;
395 if (weather_drops[type][i].pos1[1] < y - 8.0f)
396 {
397 weather_drops[type][i].pos1[1] += 16.0f;
398 weather_drops[type][i].pos2[1] += 16.0f;
399 }
400 else if(weather_drops[type][i].pos1[1] > y + 8.0f)
401 {
402 weather_drops[type][i].pos1[1] -= 16.0f;
403 weather_drops[type][i].pos2[1] -= 16.0f;
404 }
405
406 weather_drops[type][i].pos1[2] += dz * dt;
407 }
408
409 weather_drops[type][i].pos2[0] = weather_drops[type][i].pos1[0] - dx * 0.02;
410 weather_drops[type][i].pos2[1] = weather_drops[type][i].pos1[1] - dy * 0.02;
411 weather_drops[type][i].pos2[2] = weather_drops[type][i].pos1[2] - dz * 0.02;
412 }
413
414 // if there are not enough drops, we recreate new ones
415 if (weather_drops_count[type] < num_drops)
416 {
417 for (i = weather_drops_count[type]; i < num_drops; ++i)
418 {
419 make_drop(type, i, x, y, z);
420 weather_drops[type][i].pos2[0] = weather_drops[type][i].pos1[0] - x_move * 0.02;
421 weather_drops[type][i].pos2[1] = weather_drops[type][i].pos1[1] - y_move * 0.02;
422 weather_drops[type][i].pos2[2] = weather_drops[type][i].pos1[2] - z_move * 0.02;
423 }
424 weather_drops_count[type] = num_drops;
425 }
426 }
427 }
428
weather_update()429 void weather_update()
430 {
431 static Uint32 last_update = 0;
432 Uint32 ticks = cur_time - last_update;
433 int i;
434
435 update_wind();
436
437 // we update the lightning
438 if (lightning_falling && cur_time > lightning_stop)
439 {
440 lightning_falling = 0;
441 calc_shadow_matrix();
442 if (skybox_update_delay > 0)
443 skybox_update_colors();
444 }
445
446 // we update the areas
447 for (i = 0; i < MAX_WEATHER_AREAS; ++i)
448 if (weather_areas[i].type > 0 && weather_areas[i].intensity_change_duration > 0)
449 {
450 if (weather_areas[i].intensity_change_duration <= ticks)
451 {
452 weather_areas[i].intensity += weather_areas[i].intensity_change_speed*weather_areas[i].intensity_change_duration;
453 weather_areas[i].intensity_change_duration = 0;
454 }
455 else
456 {
457 weather_areas[i].intensity += weather_areas[i].intensity_change_speed*ticks;
458 weather_areas[i].intensity_change_duration -= ticks;
459 }
460 if (weather_areas[i].intensity_change_speed < 0.0)
461 {
462 if (weather_areas[i].intensity <= 0.001)
463 {
464 weather_areas[i].intensity = 0.0;
465 weather_areas[i].type = 0;
466 }
467 }
468 else
469 {
470 if (weather_areas[i].intensity > 1.0)
471 weather_areas[i].intensity = 1.0;
472 }
473 }
474
475 // we compute the ratios at the actor position
476 weather_compute_ratios(weather_ratios, -camera_x, -camera_y);
477
478 current_weather_density = weather_get_density_from_ratios(weather_ratios);
479
480 // we compute the weather color at the actor position
481 weather_get_color_from_ratios(weather_color, weather_ratios);
482
483 // we update the weather types
484 for (i = 1; i < MAX_WEATHER_TYPES; ++i)
485 update_weather_type(i, -camera_x, -camera_y, 0.0, ticks);
486
487 last_update = cur_time;
488 }
489
weather_render_fog()490 void weather_render_fog()
491 {
492 glEnable(GL_FOG);
493 glFogi(GL_FOG_MODE, GL_EXP2);
494 glFogf(GL_FOG_DENSITY, skybox_fog_density);
495 glFogfv(GL_FOG_COLOR, skybox_fog_color);
496
497 #ifdef OPENGL_TRACE
498 CHECK_GL_ERRORS();
499 #endif //OPENGL_TRACE
500 }
501
weather_render()502 void weather_render()
503 {
504 int type;
505 int i;
506 float modelview[16];
507 float delta1[3], delta2[3];
508 float color1[4], color2[4], light_level[3];
509
510 skybox_get_current_color(color1, skybox_light_ambient);
511 skybox_get_current_color(color2, skybox_light_diffuse);
512
513 light_level[0] = 0.5 + (0.2 + color1[0] + color2[0]) * 0.5;
514 light_level[1] = 0.5 + (0.2 + color1[1] + color2[1]) * 0.5;
515 light_level[2] = 0.5 + (0.2 + color1[2] + color2[2]) * 0.5;
516
517 if (lightning_falling)
518 {
519 light_level[0] += 0.5 * lightning_color[0];
520 light_level[1] += 0.5 * lightning_color[1];
521 light_level[2] += 0.5 * lightning_color[2];
522 }
523
524 if (light_level[0] > 1.0) light_level[0] = 1.0;
525 if (light_level[1] > 1.0) light_level[1] = 1.0;
526 if (light_level[2] > 1.0) light_level[2] = 1.0;
527
528 glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
529
530 glPushAttrib(GL_ENABLE_BIT);
531 glDisable(GL_LIGHTING);
532
533 glDisable(GL_ALPHA_TEST);
534 glEnable(GL_BLEND);
535 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
536
537 // we first render the weather that don't use particles
538 glEnableClientState(GL_VERTEX_ARRAY);
539 glDisableClientState(GL_NORMAL_ARRAY);
540 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
541 glDisableClientState(GL_COLOR_ARRAY);
542 glDisable(GL_TEXTURE_2D);
543
544 for (type = 1; type < MAX_WEATHER_TYPES; ++type)
545 if (!weather_defs[type].use_sprites && weather_drops_count[type] > 0)
546 {
547 glLineWidth(weather_defs[type].size);
548 glColor4f(weather_defs[type].color[0]*light_level[0],
549 weather_defs[type].color[1]*light_level[1],
550 weather_defs[type].color[2]*light_level[2],
551 weather_defs[type].color[3]);
552 glVertexPointer(3, GL_FLOAT, 0, weather_drops[type]);
553
554 for (i = 0; i < weather_drops_count[type]; i += 1000) // to avoid long arrays
555 {
556 int nb = weather_drops_count[type] - i;
557 if (nb > 1000) nb = 1000;
558 glDrawArrays(GL_LINES, i, nb);
559 }
560 }
561
562 glLineWidth(1.0);
563 glEnable(GL_TEXTURE_2D);
564 glEnable(GL_ALPHA_TEST);
565 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
566
567 // we then render the other precipitations as sprites
568 glTexCoordPointer(2, GL_FLOAT, 5*sizeof(float), weather_particles_coords);
569 glVertexPointer(3, GL_FLOAT, 5*sizeof(float), weather_particles_coords+2);
570 for (type = 2; type < MAX_WEATHER_TYPES; ++type)
571 if (weather_defs[type].use_sprites && weather_drops_count[type] > 0)
572 {
573 delta1[0] = weather_defs[type].size*(modelview[0]+modelview[1]);
574 delta1[1] = weather_defs[type].size*(modelview[4]+modelview[5]);
575 delta1[2] = weather_defs[type].size*(modelview[8]+modelview[9]);
576 delta2[0] = weather_defs[type].size*(modelview[0]-modelview[1]);
577 delta2[1] = weather_defs[type].size*(modelview[4]-modelview[5]);
578 delta2[2] = weather_defs[type].size*(modelview[8]-modelview[9]);
579
580 for (i = 0; i < weather_drops_count[type]; ++i)
581 {
582 const weather_drop *d = &weather_drops[type][i];
583 const int j = i*20;
584 weather_particles_coords[j+2 ] = d->pos1[0]-delta1[0];
585 weather_particles_coords[j+3 ] = d->pos1[1]-delta1[1];
586 weather_particles_coords[j+4 ] = d->pos1[2]-delta1[2];
587 weather_particles_coords[j+7 ] = d->pos1[0]+delta2[0];
588 weather_particles_coords[j+8 ] = d->pos1[1]+delta2[1];
589 weather_particles_coords[j+9 ] = d->pos1[2]+delta2[2];
590 weather_particles_coords[j+12] = d->pos1[0]+delta1[0];
591 weather_particles_coords[j+13] = d->pos1[1]+delta1[1];
592 weather_particles_coords[j+14] = d->pos1[2]+delta1[2];
593 weather_particles_coords[j+17] = d->pos1[0]-delta2[0];
594 weather_particles_coords[j+18] = d->pos1[1]-delta2[1];
595 weather_particles_coords[j+19] = d->pos1[2]-delta2[2];
596 }
597
598 glColor4f(weather_defs[type].color[0]*light_level[0],
599 weather_defs[type].color[1]*light_level[1],
600 weather_defs[type].color[2]*light_level[2],
601 weather_defs[type].color[3]);
602
603 bind_texture(weather_defs[type].texture);
604 glDrawArrays(GL_QUADS, 0, weather_drops_count[type]);
605 }
606
607 glDisableClientState(GL_VERTEX_ARRAY);
608 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
609 glDisable(GL_BLEND);
610 glPopAttrib();
611 #ifdef OPENGL_TRACE
612 CHECK_GL_ERRORS();
613 #endif //OPENGL_TRACE
614 }
615
weather_get_drops_count(int type)616 int weather_get_drops_count(int type)
617 {
618 return weather_drops_count[type];
619 }
620
weather_get_intensity()621 float weather_get_intensity()
622 {
623 return (1.0 - weather_ratios[0]);
624 }
625
weather_get_density_from_ratios(float ratios[MAX_WEATHER_TYPES])626 float weather_get_density_from_ratios(float ratios[MAX_WEATHER_TYPES])
627 {
628 float density = 0.0;
629 int i;
630 for(i = 0; i < MAX_WEATHER_TYPES; ++i)
631 density += weather_defs[i].density * ratios[i];
632 return density;
633 }
634
weather_get_density()635 float weather_get_density()
636 {
637 return current_weather_density;
638 }
639
weather_add_lightning(int type,float x,float y)640 void weather_add_lightning(int type, float x, float y)
641 {
642 weather_type map_weather_type = get_weather_type_for_map();
643 if (thunders_count < MAX_THUNDERS && lightnings_defs_count > 0 &&
644 ((map_weather_type == weather_effect_rain) || (map_weather_type == weather_effect_hail)))
645 {
646 // store the thunder
647 thunders[thunders_count].type = type;
648 thunders[thunders_count].x_pos = x;
649 thunders[thunders_count].y_pos = y;
650 thunders[thunders_count].time = cur_time;
651 ++thunders_count;
652
653 lightning_type = rand()%lightnings_defs_count;
654 lightning_position[0] = x;
655 lightning_position[1] = y;
656 lightning_stop = cur_time + 200 + rand()%200;
657 lightning_falling = 1;
658
659 skybox_coords_from_ground_coords(lightning_sky_position,
660 lightning_position[0] + camera_x,
661 lightning_position[1] + camera_y);
662
663 lightning_sky_position[0] -= camera_x;
664 lightning_sky_position[1] -= camera_y;
665
666 calc_shadow_matrix();
667
668 if (skybox_update_delay > 0)
669 skybox_update_colors();
670 }
671 }
672
weather_init_lightning_light()673 void weather_init_lightning_light()
674 {
675 if (lightning_falling)
676 {
677 glLightfv(GL_LIGHT7, GL_AMBIENT, lightning_ambient_color);
678 glLightfv(GL_LIGHT7, GL_DIFFUSE, lightning_color);
679 glLightfv(GL_LIGHT7, GL_POSITION, lightning_position);
680 }
681 }
682
weather_render_lightning()683 void weather_render_lightning()
684 {
685 if (lightning_falling)
686 {
687 const float *tex_coords = lightnings_defs[lightning_type].coords;
688 float size = lightning_sky_position[2]*0.5*(tex_coords[2]-tex_coords[0])/(tex_coords[3]-tex_coords[1]);
689 float dx = size*cosf(-rz*M_PI/180.0);
690 float dy = size*sinf(-rz*M_PI/180.0);
691
692 glPushAttrib(GL_ENABLE_BIT);
693 glDisable(GL_LIGHTING);
694 glDisable(GL_FOG);
695 glEnable(GL_COLOR_MATERIAL);
696 glEnable(GL_TEXTURE_2D);
697 glEnable(GL_BLEND);
698 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
699
700 bind_texture(lightnings_defs[lightning_type%lightnings_defs_count].texture);
701
702 glColor4fv(lightning_color);
703 glBegin(GL_QUADS);
704 glTexCoord2f(tex_coords[0], tex_coords[1]);
705 glVertex3f(lightning_position[0]-dx, lightning_position[1]-dy, 0.0);
706 glTexCoord2f(tex_coords[2], tex_coords[1]);
707 glVertex3f(lightning_position[0]+dx, lightning_position[1]+dy, 0.0);
708 glTexCoord2f(tex_coords[2], tex_coords[3]);
709 glVertex3f(lightning_sky_position[0]+dx, lightning_sky_position[1]+dy, lightning_sky_position[2]);
710 glTexCoord2f(tex_coords[0], tex_coords[3]);
711 glVertex3f(lightning_sky_position[0]-dx, lightning_sky_position[1]-dy, lightning_sky_position[2]);
712 glEnd();
713 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
714 glPopAttrib();
715 }
716 }
717
weather_get_lightning_intensity(float x,float y)718 float weather_get_lightning_intensity(float x, float y)
719 {
720 float dx = x-lightning_position[0];
721 float dy = y-lightning_position[1];
722 float dist = dx*dx + dy*dy;
723
724 if (!lightning_falling || dist > LIGHTNING_LIGHT_RADIUS*LIGHTNING_LIGHT_RADIUS)
725 return 0.0;
726 else
727 return 1.0 - dist / (LIGHTNING_LIGHT_RADIUS*LIGHTNING_LIGHT_RADIUS);
728 }
729
730 #ifdef NEW_SOUND
weather_sound_control()731 void weather_sound_control()
732 {
733 static Uint32 last_sound_update = 0;
734 int i;
735
736 if (cur_time < last_sound_update + 200) return;
737 else last_sound_update = cur_time;
738
739 if (!sound_on)
740 {
741 rain_sound = 0;
742 }
743 else
744 {
745 if (weather_ratios[WEATHER_RAIN] > 0.0)
746 {
747 // Torg: Only load sounds when we need them so we aren't wasting sources.
748 // This is really only for NEW_SOUND.
749 if (rain_sound == 0)
750 #ifdef NEW_SOUND
751 rain_sound = add_server_sound(snd_rain, 0, 0, weather_ratios[WEATHER_RAIN]);
752 else
753 sound_source_set_gain(rain_sound, weather_ratios[WEATHER_RAIN]);
754 #endif //NEW_SOUND
755 }
756 else
757 {
758 if (rain_sound > 0)
759 {
760 stop_sound(rain_sound);
761 rain_sound = 0;
762 }
763 }
764 }
765
766 for (i = 0; i < thunders_count; )
767 {
768 float dx = thunders[i].x_pos + camera_x;
769 float dy = thunders[i].y_pos + camera_y;
770 float dist = sqrtf(dx*dx + dy*dy);
771 if (cur_time >= thunders[i].time + dist/SOUND_SPEED)
772 {
773 if (sound_on)
774 {
775 int snd_thunder = 0;
776
777 switch (thunders[i].type)
778 {
779 case 0: snd_thunder = snd_thndr_1; break;
780 case 1: snd_thunder = snd_thndr_2; break;
781 case 2: snd_thunder = snd_thndr_3; break;
782 case 3: snd_thunder = snd_thndr_4; break;
783 case 4: snd_thunder = snd_thndr_5; break;
784 default: snd_thunder = 0;
785 }
786
787 if (snd_thunder)
788 {
789 #ifdef NEW_SOUND
790 add_server_sound(snd_thunder, 0, 0, 1.0f);
791 #endif //NEW_SOUND
792 }
793 }
794
795 // we remove the thunder from the list
796 if (i < --thunders_count)
797 memcpy(&thunders[i], &thunders[thunders_count], sizeof(thunder));
798 }
799 else ++i;
800 }
801 }
802 #endif //NEW_SOUND
803
804 #ifdef NEW_SOUND
weather_adjust_gain(float in_gain,int in_cookie)805 float weather_adjust_gain(float in_gain, int in_cookie)
806 {
807 if (weather_ratios[WEATHER_RAIN] > 0.0 && in_cookie != rain_sound)
808 {
809 // Dim down all the sounds, except the rain
810 return in_gain * (1.0f - 0.5*weather_ratios[WEATHER_RAIN]);
811 }
812
813 return in_gain;
814 }
815 #endif // NEW_SOUND
816
weather_parse_effect(xmlNode * node)817 int weather_parse_effect(xmlNode *node)
818 {
819 xmlNode *item;
820 xmlAttr *attr;
821 int ok = 1;
822 int id = -1;
823
824 for (attr = node->properties; attr; attr = attr->next)
825 {
826 if (attr->type == XML_ATTRIBUTE_NODE)
827 {
828 if (!xmlStrcasecmp (attr->name, (xmlChar*)"id"))
829 id = atoi((char*)attr->children->content);
830 else {
831 LOG_ERROR("unknown attribute for effect: %s", (char*)attr->name);
832 ok = 0;
833 }
834 }
835 }
836
837 if (id < 1)
838 {
839 LOG_ERROR("wrong or missing id for weather effect");
840 return 0;
841 }
842
843 for(item = node->children; item; item = item->next) {
844 if(item->type == XML_ELEMENT_NODE) {
845 if (xmlStrcasecmp(item->name, (xmlChar*)"sprites") == 0) {
846 weather_defs[id].use_sprites = get_bool_value(item);
847 }
848 else if (xmlStrcasecmp(item->name, (xmlChar*)"density") == 0) {
849 weather_defs[id].density = get_float_value(item);
850 }
851 else if (xmlStrcasecmp(item->name, (xmlChar*)"color") == 0) {
852 weather_defs[id].color[0] = 0.0;
853 weather_defs[id].color[1] = 0.0;
854 weather_defs[id].color[2] = 0.0;
855 weather_defs[id].color[3] = 0.0;
856 for (attr = item->properties; attr; attr = attr->next)
857 {
858 if (attr->type == XML_ATTRIBUTE_NODE)
859 {
860 if (!xmlStrcasecmp (attr->name, (xmlChar*)"r"))
861 weather_defs[id].color[0] = atof((char*)attr->children->content);
862 else if (!xmlStrcasecmp (attr->name, (xmlChar*)"g"))
863 weather_defs[id].color[1] = atof((char*)attr->children->content);
864 else if (!xmlStrcasecmp (attr->name, (xmlChar*)"b"))
865 weather_defs[id].color[2] = atof((char*)attr->children->content);
866 else if (!xmlStrcasecmp (attr->name, (xmlChar*)"a"))
867 weather_defs[id].color[3] = atof((char*)attr->children->content);
868 else {
869 LOG_ERROR("unknown attribute for weather effect color: %s", (char*)attr->name);
870 ok = 0;
871 }
872 }
873 }
874 weather_defs[id].color[0] /= 255.0;
875 weather_defs[id].color[1] /= 255.0;
876 weather_defs[id].color[2] /= 255.0;
877 weather_defs[id].color[3] /= 255.0;
878 }
879 else if (xmlStrcasecmp(item->name, (xmlChar*)"size") == 0) {
880 weather_defs[id].size = get_float_value(item);
881 }
882 else if (xmlStrcasecmp(item->name, (xmlChar*)"speed") == 0) {
883 weather_defs[id].speed = get_float_value(item);
884 }
885 else if (xmlStrcasecmp(item->name, (xmlChar*)"wind_effect") == 0) {
886 weather_defs[id].wind_effect = get_float_value(item);
887 }
888 else if (xmlStrcasecmp(item->name, (xmlChar*)"texture") == 0) {
889 weather_defs[id].texture = load_texture_cached((char*)item->children->content, tt_mesh);
890 }
891 else {
892 LOG_ERROR("unknown node for weather effect: %s", item->name);
893 ok = 0;
894 }
895 }
896 else if (item->type == XML_ENTITY_REF_NODE) {
897 ok &= weather_parse_effect(item->children);
898 }
899 }
900
901 return ok;
902 }
903
weather_parse_lightning(xmlNode * node)904 int weather_parse_lightning(xmlNode *node)
905 {
906 xmlAttr *attr;
907 int ok = 1;
908 int id = lightnings_defs_count++;
909
910 lightnings_defs[id].texture = -1;
911 lightnings_defs[id].coords[0] = 0.0;
912 lightnings_defs[id].coords[1] = 0.0;
913 lightnings_defs[id].coords[2] = 0.0;
914 lightnings_defs[id].coords[3] = 0.0;
915
916 for (attr = node->properties; attr; attr = attr->next)
917 {
918 if (attr->type == XML_ATTRIBUTE_NODE)
919 {
920 if (!xmlStrcasecmp (attr->name, (xmlChar*)"texture"))
921 lightnings_defs[id].texture = load_texture_cached((char*)attr->children->content, tt_mesh);
922 else if (!xmlStrcasecmp (attr->name, (xmlChar*)"x1"))
923 lightnings_defs[id].coords[0] = atof((char*)attr->children->content);
924 else if (!xmlStrcasecmp (attr->name, (xmlChar*)"y1"))
925 lightnings_defs[id].coords[1] = atof((char*)attr->children->content);
926 else if (!xmlStrcasecmp (attr->name, (xmlChar*)"x2"))
927 lightnings_defs[id].coords[2] = atof((char*)attr->children->content);
928 else if (!xmlStrcasecmp (attr->name, (xmlChar*)"y2"))
929 lightnings_defs[id].coords[3] = atof((char*)attr->children->content);
930 else {
931 LOG_ERROR("unknown attribute for weather effect color: %s", (char*)attr->name);
932 ok = 0;
933 }
934 }
935 }
936
937 return ok;
938 }
939
weather_parse_defs(xmlNode * node)940 int weather_parse_defs(xmlNode *node)
941 {
942 xmlNode *def;
943 int ok = 1;
944
945 for (def = node->children; def; def = def->next) {
946 if (def->type == XML_ELEMENT_NODE)
947 if (xmlStrcasecmp(def->name, (xmlChar*)"effect") == 0) {
948 ok &= weather_parse_effect(def);
949 }
950 else if (xmlStrcasecmp(def->name, (xmlChar*)"lightning") == 0) {
951 ok &= weather_parse_lightning(def);
952 }
953 else {
954 LOG_ERROR("unknown element for weather: %s", def->name);
955 ok = 0;
956 }
957 else if (def->type == XML_ENTITY_REF_NODE) {
958 ok &= weather_parse_defs(def->children);
959 }
960 }
961
962 return ok;
963 }
964
weather_read_defs(const char * file_name)965 int weather_read_defs(const char *file_name)
966 {
967 xmlNode *root;
968 xmlDoc *doc;
969 int ok = 1;
970
971 doc = xmlReadFile(file_name, NULL, 0);
972 if (doc == NULL) {
973 LOG_ERROR("Unable to read weather definition file %s", file_name);
974 return 0;
975 }
976
977 root = xmlDocGetRootElement(doc);
978 if (root == NULL) {
979 LOG_ERROR("Unable to parse weather definition file %s", file_name);
980 ok = 0;
981 } else if (xmlStrcasecmp(root->name, (xmlChar*)"weather") != 0) {
982 LOG_ERROR("Unknown key \"%s\" (\"weather\" expected).", root->name);
983 ok = 0;
984 } else {
985 ok = weather_parse_defs(root);
986 }
987
988 xmlFreeDoc(doc);
989 return ok;
990 }
991