]> icculus.org git repositories - taylor/freespace2.git/blob - src/nebula/neblightning.cpp
get rid of some platform specific stuff
[taylor/freespace2.git] / src / nebula / neblightning.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Nebula/NebLightning.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Nebula effect
16  *
17  * $Log$
18  * Revision 1.7  2004/09/20 01:31:44  theoddone33
19  * GCC 3.4 fixes.
20  *
21  * Revision 1.6  2004/07/04 11:39:06  taylor
22  * fix missing debrief text, crash on exit, path separator's, warning fixes, no GR_SOFT
23  *
24  * Revision 1.5  2003/05/25 02:30:43  taylor
25  * Freespace 1 support
26  *
27  * Revision 1.4  2002/06/17 06:33:09  relnev
28  * ryan's struct patch for gcc 2.95
29  *
30  * Revision 1.3  2002/06/09 04:41:23  relnev
31  * added copyright header
32  *
33  * Revision 1.2  2002/05/07 03:16:47  theoddone33
34  * The Great Newline Fix
35  *
36  * Revision 1.1.1.1  2002/05/03 03:28:10  root
37  * Initial import.
38  * 
39  * 
40  * 10    8/15/99 3:50p Dave
41  * Don't process lightning at the very beginning of a mission.
42  * 
43  * 9     8/12/99 10:38a Anoop
44  * Removed unnecessary Int3().
45  * 
46  * 8     8/05/99 2:06a Dave
47  * Whee.
48  * 
49  * 7     7/27/99 9:51p Andsager
50  * make mprintf's into nprintf's
51  * 
52  * 6     7/03/99 5:50p Dave
53  * Make rotated bitmaps draw properly in padlock views.
54  * 
55  * 5     7/02/99 4:31p Dave
56  * Much more sophisticated lightning support.
57  * 
58  * 4     6/09/99 10:32a Dave
59  * Made random lighting bolts behave more like the E3 demo. Generally more
60  * active.
61  * 
62  * 3     5/26/99 11:46a Dave
63  * Added ship-blasting lighting and made the randomization of lighting
64  * much more customizable.
65  * 
66  * 2     5/24/99 5:45p Dave
67  * Added detail levels to the nebula, with a decent speedup. Split nebula
68  * lightning into its own section.
69  * 
70  * $NoKeywords: $
71  */
72
73 #include "parselo.h"
74 #include "linklist.h"
75 #include "bmpman.h"
76 #include "timer.h"
77 #include "freespace.h"
78 #include "gamesnd.h"
79 #include "3d.h"
80 #include "missionparse.h"
81 #include "neb.h"
82 #include "neblightning.h"
83 #include "multi.h"
84 #include "emp.h"
85 #include "multimsgs.h"
86
87 // ------------------------------------------------------------------------------------------------------
88 // NEBULA LIGHTNING DEFINES/VARS
89 //
90
91 // debug stuff
92 #define MAX_BOLT_TYPES_INTERNAL         11
93
94 // see lightning.tbl for explanations of these values
95 typedef struct bolt_type {
96         char            name[NAME_LENGTH];
97
98         float           b_scale;
99         float           b_shrink;
100         float           b_poly_pct;     
101         float           b_add;
102         float           b_rand;
103
104         float           noise;
105         int             lifetime;
106         int             num_strikes;
107
108         float           emp_intensity;
109         float           emp_time;
110         
111         int             texture;
112         int             glow;   
113
114         float           b_bright;
115 } bolt_type;
116
117 int Num_bolt_types = 0;
118 bolt_type Bolt_types[MAX_BOLT_TYPES_INTERNAL];
119
120 // storm types
121 int Num_storm_types = 0;
122 storm_type Storm_types[MAX_STORM_TYPES];
123
124
125 // actual lightning bolt stuff -------
126
127 #define MAX_LIGHTNING_NODES                                     500
128
129 // nodes in a lightning bolt
130 #define LINK_LEFT               0
131 #define LINK_RIGHT      1
132 #define LINK_CHILD      2
133 typedef struct l_node {
134         vector  pos;                            // world position
135         l_node  *links[3];              // 3 links for lightning children
136
137         l_node *next, *prev;            // for used and free-lists only
138 } l_node;
139
140
141 // nodes
142 l_node Nebl_nodes[MAX_LIGHTNING_NODES];
143 int Num_lnodes = 0;
144
145 // lightning node lists
146 l_node Nebl_free_list;
147 l_node Nebl_used_list;
148
149 // actual lightning bolt themselves
150 typedef struct l_bolt {
151         l_node *head;                           // head of the lightning bolt
152         int bolt_life;                          // remaining life timestamp
153         ubyte used;                                     // used or not
154         ubyte   first_frame;            // if he hasn't been rendered at least once     
155         char type;
156
157         // bolt info
158         vector start, strike, midpoint;
159         int delay;                                      // delay stamp
160         int strikes_left;                       // #of strikes left
161         float width;
162 } l_bolt;
163
164 #define MAX_LIGHTNING_BOLTS                                     10
165
166 // lightning bolts
167 l_bolt Nebl_bolts[MAX_LIGHTNING_BOLTS];
168 int Nebl_bolt_count = 0;
169
170 // one cross-section of a lightning bolt
171 typedef struct l_section {              
172         vertex  vex[3];
173         vertex  glow_vex[2];
174 } l_section;
175
176 // points on the basic cross section
177 vector Nebl_ring[3] = { 
178         { { { -1.0f, 0.0f, 0.0f } } },
179         { { { 1.0f, 0.70f, 0.0f } } },
180         { { { 1.0f, -0.70f, 0.0f } } }  
181 };
182
183 // pinched off cross-section
184 vector Nebl_ring_pinched[3] = { 
185         { { { -0.05f, 0.0f, 0.0f } } },
186         { { { 0.05f, 0.035f, 0.0f } } },
187         { { { 0.05f, -0.035f, 0.0f } } }        
188 };
189
190 // globals used for rendering and generating bolts
191 int Nebl_flash_count = 0;               // # of points rendered onscreen for this bolt
192 float Nebl_flash_x = 0.0f;              // avg x of the points rendered
193 float Nebl_flash_y = 0.0f;              // avg y of the points rendered
194 float Nebl_bang = 0.0;                  // distance to the viewer object
195 float Nebl_alpha = 0.0f;                // alpha to use when rendering the bolt itself
196 float Nebl_glow_alpha = 0.0f;   // alpha to use when rendering the bolt glow
197 int Nebl_stamp = -1;                            // random timestamp for making bolts
198 float Nebl_bolt_len;                            // length of the current bolt being generated
199 bolt_type *Nebl_type;                   // bolt type
200 matrix Nebl_bolt_dir;                   // orientation matrix of the bolt being generated
201 vector Nebl_bolt_start;                 // start point of the bolt being generated
202 vector Nebl_bolt_strike;                // strike point of the bolt being generated
203
204 // the type of active storm
205 storm_type *Storm = NULL;
206
207 // vars
208 DCF(b_scale, "")
209 {
210         dc_get_arg(ARG_FLOAT);
211         Bolt_types[DEBUG_BOLT].b_scale = Dc_arg_float;
212 }
213 DCF(b_rand, "")
214 {
215         dc_get_arg(ARG_FLOAT);
216         Bolt_types[DEBUG_BOLT].b_rand = Dc_arg_float;
217 }
218 DCF(b_shrink, "")
219 {
220         dc_get_arg(ARG_FLOAT);
221         Bolt_types[DEBUG_BOLT].b_shrink = Dc_arg_float;
222 }
223 DCF(b_poly_pct, "")
224 {
225         dc_get_arg(ARG_FLOAT);
226         Bolt_types[DEBUG_BOLT].b_poly_pct = Dc_arg_float;
227 }
228 DCF(b_add, "")
229 {
230         dc_get_arg(ARG_FLOAT);
231         Bolt_types[DEBUG_BOLT].b_add = Dc_arg_float;
232 }
233 DCF(b_strikes, "")
234 {
235         dc_get_arg(ARG_INT);
236         Bolt_types[DEBUG_BOLT].num_strikes = Dc_arg_int;
237 }
238 DCF(b_noise, "")
239 {
240         dc_get_arg(ARG_FLOAT);
241         Bolt_types[DEBUG_BOLT].noise = Dc_arg_float;
242 }
243 DCF(b_bright, "")
244 {
245         dc_get_arg(ARG_FLOAT);
246         Bolt_types[DEBUG_BOLT].b_bright = Dc_arg_float;
247 }
248 DCF(b_lifetime, "")
249 {
250         dc_get_arg(ARG_INT);
251         Bolt_types[DEBUG_BOLT].lifetime = Dc_arg_int;
252 }
253 DCF(b_list, "")
254 {
255         dc_printf("Debug lightning bolt settings :\n");
256
257         dc_printf("b_scale : %f\n", Bolt_types[DEBUG_BOLT].b_scale);
258         dc_printf("b_rand : %f\n", Bolt_types[DEBUG_BOLT].b_rand);
259         dc_printf("b_shrink : %f\n", Bolt_types[DEBUG_BOLT].b_shrink);
260         dc_printf("b_poly_pct : %f\n", Bolt_types[DEBUG_BOLT].b_poly_pct);
261         dc_printf("b_add : %f\n", Bolt_types[DEBUG_BOLT].b_add);
262         dc_printf("b_strikes : %d\n", Bolt_types[DEBUG_BOLT].num_strikes);
263         dc_printf("b_noise : %f\n", Bolt_types[DEBUG_BOLT].noise);
264         dc_printf("b_bright : %f\n", Bolt_types[DEBUG_BOLT].b_bright);
265         dc_printf("b_lifetime : %d\n", Bolt_types[DEBUG_BOLT].lifetime);
266 }
267
268
269 // nebula lightning intensity (0.0 to 1.0)
270 float Nebl_intensity = 0.6667f;
271
272 // min and max times for random lightning
273 int Nebl_random_min = 750;                              // min random time
274 int Nebl_random_max = 10000;                    // max random time
275
276 // min and max times for cruiser lightning
277 int Nebl_cruiser_min = 5000;                    // min cruiser time
278 int Nebl_cruiser_max = 25000;                   // max cruiser time
279
280 // min and max times for cap ships
281 int Nebl_cap_min = 4000;                                // min cap time
282 int Nebl_cap_max = 18000;                               // max cap time
283
284 // min and max time for super caps
285 int Nebl_supercap_min = 3000;                   // min supercap time
286 int Nebl_supercap_max = 12000;          // max supercap time
287
288 DCF(lightning_intensity, "")
289 {
290         dc_get_arg(ARG_FLOAT);
291         float val = Dc_arg_float;
292         if(val < 0.0f){
293                 val = 0.0f;
294         } else if(val > 1.0f){
295                 val = 1.0f;
296         }
297
298         Nebl_intensity = 1.0f - val;
299 }
300
301 // ------------------------------------------------------------------------------------------------------
302 // NEBULA LIGHTNING FORWARD DECLARATIONS
303 //
304
305 // "new" a lightning node
306 l_node *nebl_new();
307
308 // "delete" a lightning node
309 void nebl_delete(l_node *lp);
310
311 // free up a the nodes of the passed in bolt
312 void nebl_release(l_node *bolt_head);
313
314 // generate a lightning bolt, returns l_left (the "head") and l_right (the "tail")
315 int nebl_gen(vector *left, vector *right, float depth, float max_depth, int child, l_node **l_left, l_node **l_right);
316
317 // output top and bottom vectors
318 // fvec == forward vector (eye viewpoint basically. in world coords)
319 // pos == world coordinate of the point we're calculating "around"
320 // w == width of the diff between top and bottom around pos
321 void nebl_calc_facing_pts_smart( vector *top, vector *bot, vector *fvec, vector *pos, float w, float z_add );
322
323 // render a section of the bolt
324 void nebl_render_section(bolt_type *bi, l_section *a, l_section *b);
325
326 // generate a section
327 void nebl_generate_section(bolt_type *bi, float width, l_node *a, l_node *b, l_section *c, l_section *cap, int pinch_a, int pinch_b);
328
329 // render the bolt
330 void nebl_render(bolt_type *bi, l_node *whee, float width, l_section *prev = NULL);
331
332 // given a valid, complete bolt, jitter him based upon his noise
333 void nebl_jitter(l_bolt *b);
334
335 // return the index of a given bolt type by name
336 int nebl_get_bolt_index(char *name);
337
338 // return the index of a given storm type by name
339 int nebl_get_storm_index(char *name);
340
341
342 // ------------------------------------------------------------------------------------------------------
343 // NEBULA LIGHTNING FUNCTIONS
344 //
345
346 // initialize nebula lightning at game startup
347 void nebl_init()
348 {
349 #ifndef MAKE_FS1
350         char name[NAME_LENGTH+10] = "";
351         bolt_type bogus_lightning, *l;
352         storm_type bogus_storm, *s;
353         int temp;
354
355         // parse the lightning table
356         read_file_text("lightning.tbl");
357         reset_parse();
358
359         Num_bolt_types = 0;
360         Num_storm_types = 0;
361
362         memset(Bolt_types, 0, sizeof(bolt_type) * MAX_BOLT_TYPES_INTERNAL);
363
364         // parse the individual lightning bolt types
365         required_string("#Bolts begin");
366         while(!optional_string("#Bolts end")){
367                 // get a pointer
368                 if(Num_bolt_types >= MAX_BOLT_TYPES){
369                         l = &bogus_lightning;
370                 } else {
371                         l = &Bolt_types[Num_bolt_types];
372                 }
373
374                 // bolt title
375                 required_string("$Bolt:");
376                 stuff_string(l->name, F_NAME, NULL);
377
378                 // b_scale
379                 required_string("+b_scale:");
380                 stuff_float(&l->b_scale);
381
382                 // b_shrink
383                 required_string("+b_shrink:");
384                 stuff_float(&l->b_shrink);
385
386                 // b_poly_pct
387                 required_string("+b_poly_pct:");
388                 stuff_float(&l->b_poly_pct);            
389
390                 // child rand
391                 required_string("+b_rand:");
392                 stuff_float(&l->b_rand);
393
394                 // z add
395                 required_string("+b_add:");
396                 stuff_float(&l->b_add);
397
398                 // # strikes
399                 required_string("+b_strikes:");
400                 stuff_int(&l->num_strikes);
401
402                 // lifetime
403                 required_string("+b_lifetime:");
404                 stuff_int(&l->lifetime);
405
406                 // noise
407                 required_string("+b_noise:");
408                 stuff_float(&l->noise);
409
410                 // emp effect
411                 required_string("+b_emp:");
412                 stuff_float(&l->emp_intensity);
413                 stuff_float(&l->emp_time);
414
415                 // texture
416                 required_string("+b_texture:");
417                 stuff_string(name, F_NAME, NULL);
418                 if((l != &bogus_lightning) && !Fred_running){
419                         l->texture = bm_load(name);
420                 }
421
422                 // glow
423                 required_string("+b_glow:");
424                 stuff_string(name, F_NAME, NULL);
425                 if((l != &bogus_lightning) && !Fred_running){
426                         l->glow = bm_load(name);
427                 }
428
429                 // brightness
430                 required_string("+b_bright:");
431                 stuff_float(&l->b_bright);
432
433                 // increment the # of bolt types
434                 if(l != &bogus_lightning){
435                         Num_bolt_types++;
436                 }
437         }
438
439         // copy the first bolt to the debug bolt
440         memcpy(&Bolt_types[DEBUG_BOLT], &Bolt_types[0], sizeof(bolt_type));
441
442         // parse storm types
443         required_string("#Storms begin");
444         while(!optional_string("#Storms end")){
445                 // get a pointer
446                 if(Num_storm_types >= MAX_STORM_TYPES){
447                         s = &bogus_storm;
448                 } else {
449                         s = &Storm_types[Num_storm_types];
450                 }
451
452                 // bolt title
453                 required_string("$Storm:");
454                 stuff_string(s->name, F_NAME, NULL);
455
456                 // bolt types
457                 s->num_bolt_types = 0;
458                 while(optional_string("+bolt:")){                       
459                         stuff_string(name, F_NAME, NULL);                       
460
461                         // fill this guy in
462                         if(s->num_bolt_types < MAX_BOLT_TYPES){
463                                 s->bolt_types[s->num_bolt_types] = (char)nebl_get_bolt_index(name);
464                                 SDL_assert(s->bolt_types[s->num_bolt_types] != -1);                                                             
465
466                                 s->num_bolt_types++;
467                         } 
468                         // bogus 
469                         else {
470                                 required_string("+bolt_prec:");
471                                 stuff_int(&temp);
472                         }                       
473                 }
474
475                 // flavor
476                 required_string("+flavor:");
477                 stuff_float(&s->flavor.xyz.x);
478                 stuff_float(&s->flavor.xyz.y);
479                 stuff_float(&s->flavor.xyz.z);
480
481                 // frequencies
482                 required_string("+random_freq:");
483                 stuff_int(&s->min);
484                 stuff_int(&s->max);
485
486                 // counts
487                 required_string("+random_count:");
488                 stuff_int(&s->min_count);
489                 stuff_int(&s->max_count);
490
491                 // increment the # of bolt types
492                 if(s != &bogus_storm){
493                         Num_storm_types++;
494                 }
495         }
496 #endif
497 }
498
499 // initialize lightning before entering a level
500 void nebl_level_init()
501 {
502         int idx;        
503
504         // zero all lightning bolts
505         for(idx=0; idx<MAX_LIGHTNING_BOLTS; idx++){
506                 Nebl_bolts[idx].head = NULL;
507                 Nebl_bolts[idx].bolt_life = -1;
508                 Nebl_bolts[idx].used = 0;
509         }       
510         
511         // initialize node list
512         Num_lnodes = 0;
513         list_init( &Nebl_free_list );
514         list_init( &Nebl_used_list );
515
516         // Link all object slots into the free list
517         for (idx=0; idx<MAX_LIGHTNING_NODES; idx++)     {
518                 list_append(&Nebl_free_list, &Nebl_nodes[idx] );
519         }
520
521         // zero the random timestamp
522         Nebl_stamp = -1;                
523
524         // null the storm. let mission parsing set it up
525         Storm = NULL;
526 }
527
528 // render all lightning bolts
529 void nebl_render_all()
530 {
531         int idx;
532         l_bolt *b;
533         bolt_type *bi;
534
535         // no lightning in non-nebula missions
536         if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
537                 return;
538         }
539
540         // if we have no storm
541         if(Storm == NULL){
542                 return;
543         }
544
545         // traverse the list
546         for(idx=0; idx<MAX_LIGHTNING_BOLTS; idx++){
547                 b = &Nebl_bolts[idx];           
548
549                 // if this is being used
550                 if(b->used){
551                         SDL_assert(b->head != NULL);
552
553                         // bogus bolt
554                         if(b->head == NULL){
555                                 b->used = 0;
556                                 continue;
557                         }
558                         if((b->type < 0) || ((b->type >= Num_bolt_types) && (b->type != DEBUG_BOLT)) ){
559                                 Int3();
560                                 b->used = 0;
561                                 continue;
562                         }
563                         bi = &Bolt_types[(int)b->type];
564
565                         // if this guy is still on a delay
566                         if(b->delay != -1){
567                                 if(timestamp_elapsed(b->delay)){
568                                         b->delay = -1;
569                                 } else {
570                                         continue;
571                                 }
572                         }
573
574                         // if the timestamp on this guy has expired
575                         if((b->bolt_life < 0) || timestamp_elapsed(b->bolt_life)){
576                                 // if this is a multiple strike bolt, jitter it and reset
577                                 if(b->strikes_left-1 > 0){
578                                         b->bolt_life = timestamp(bi->lifetime / bi->num_strikes);
579                                         b->first_frame = 1;
580                                         b->strikes_left--;
581                                         nebl_jitter(b);
582
583                                         // by continuing here we skip rendering for one frame, which makes it look more like real lightning
584                                         continue;
585                                 }
586                                 // otherwise he's completely done, so release him
587                                 else {
588                                         // maybe free up node data
589                                         if(b->head != NULL){
590                                                 nebl_release(b->head);
591                                                 b->head = NULL;
592
593                                                 Nebl_bolt_count--;
594
595                                                 nprintf(("lightning", "Released bolt. %d used nodes!\n", Num_lnodes));
596                                         }
597
598                                         b->used = 0;
599                                 }
600                         }
601
602                         // pick some cool alpha values
603                         Nebl_alpha = frand();
604                         Nebl_glow_alpha = frand();
605
606                         // otherwise render him
607                         Nebl_flash_count = 0;
608                         Nebl_flash_x = 0.0f;
609                         Nebl_flash_y = 0.0f;
610                         Nebl_bang = 10000000.0f;
611                         nebl_render(bi, b->head, b->width);
612
613                         // if this is the first frame he has been rendered, determine if we need to make a flash and sound effect
614                         if(b->first_frame){
615                                 float flash = 0.0f;                             
616
617                                 b->first_frame = 0;
618
619                                 // if we rendered any points
620                                 if(Nebl_flash_count){
621                                         Nebl_flash_x /= (float)Nebl_flash_count;
622                                         Nebl_flash_y /= (float)Nebl_flash_count;
623
624                                         // quick distance from the center of the screen                 
625                                         float x = Nebl_flash_x - (gr_screen.max_w / 2.0f);
626                                         float y = Nebl_flash_y - (gr_screen.max_h / 2.0f);
627                                         float dist = fl_sqrt((x * x) + (y * y));                
628                                         if(dist / (gr_screen.max_w / 2.0f) < 1.0f){
629                                                 flash = 1.0f - (dist / (gr_screen.max_w / 2.0f));                                                                               
630
631                                                 // scale the flash by bolt type
632                                                 flash *= bi->b_bright;
633
634                                                 game_flash(flash, flash, flash);                                                                                
635                                         }                                       
636
637                                         // do some special stuff on the very first strike of the bolt
638                                         if(b->strikes_left == bi->num_strikes){                                 
639                                                 // play a sound                                         
640                                                 float bang;
641                                                 if(Nebl_bang < 40.0f){
642                                                         bang = 1.0f;
643                                                 } else if(Nebl_bang > 400.0f){
644                                                         bang = 0.0f;
645                                                 } else {
646                                                         bang = 1.0f - (Nebl_bang / 400.0f);
647                                                 }
648                                                 if(frand_range(0.0f, 1.0f) < 0.5f){
649                                                         snd_play(&Snds[SND_LIGHTNING_2], 0.0f, bang, SND_PRIORITY_DOUBLE_INSTANCE);
650                                                 } else {
651                                                         snd_play(&Snds[SND_LIGHTNING_1], 0.0f, bang, SND_PRIORITY_DOUBLE_INSTANCE);
652                                                 }                                               
653
654                                                 // apply em pulse
655                                                 if(bi->emp_intensity > 0.0f){
656                                                         emp_apply(&b->midpoint, 0.0f, vm_vec_dist(&b->start, &b->strike), bi->emp_intensity, bi->emp_time);
657                                                 }
658                                         }
659                                 }                               
660                         }
661                 }
662         }       
663 }
664
665 // process lightning (randomly generate bolts, etc, etc);
666 void nebl_process()
667 {               
668         int num_bolts, idx;
669
670         // non-nebula mission
671         if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
672                 return;
673         }               
674         
675         // non servers in multiplayer don't do this
676         if((Game_mode & GM_MULTIPLAYER) && !MULTIPLAYER_MASTER){
677                 return;
678         }
679
680         // if there's no chosen storm
681         if(Storm == NULL){
682                 return;
683         }
684
685         // don't process lightning bolts unless we're a few seconds in
686         if(f2fl(Missiontime) < 3.0f){
687                 return;
688         }
689                 
690         // random stamp
691         if(Nebl_stamp == -1){
692                 Nebl_stamp = timestamp((int)frand_range((float)Storm->min, (float)Storm->max));
693                 return;
694         }       
695
696         // maybe make a bolt
697         if(timestamp_elapsed(Nebl_stamp)){
698                 // determine how many bolts to spew
699                 num_bolts = (int)frand_range((float)Storm->min_count, (float)Storm->max_count);
700                 for(idx=0; idx<num_bolts; idx++){
701                         // hmm. for now just pick a random bolt type and run with it
702                         int s1, s2, s3;
703                         int e1, e2, e3;
704                         do {
705                                 s1 = (int)frand_range(0.0f, (float)Neb2_slices);
706                                 s2 = (int)frand_range(0.0f, (float)Neb2_slices);
707                                 s3 = (int)frand_range(0.0f, (float)Neb2_slices);
708
709                                 e1 = (int)frand_range(0.0f, (float)Neb2_slices);
710                                 e2 = (int)frand_range(0.0f, (float)Neb2_slices);
711                                 e3 = (int)frand_range(0.0f, (float)Neb2_slices);
712                         
713                                 // never choose the middle cube
714                                 if((s1 == 2) && (s2 == 2) && (s3 == 2)){
715                                         s1 = 4;
716                                         s2 = 0;
717                                 }
718                                 if((e1 == 2) && (e2 == 2) && (e3 == 2)){
719                                         e1 = 0;
720                                         e2 = 4;
721                                 }
722
723                         // sanity
724                         } while((s1 == e1) && (s2 == e2) && (s3 == e3));
725
726                         vector start = Neb2_cubes[s1][s2][s3].pt;
727                         vector strike = Neb2_cubes[e1][e2][e3].pt;
728
729                         // add some flavor to the bolt. mmmmmmmm, lightning
730                         if(!IS_VEC_NULL(&Storm->flavor)){                       
731                                 // start with your basic hot sauce. measure how much you have                   
732                                 vector your_basic_hot_sauce;
733                                 vm_vec_sub(&your_basic_hot_sauce, &strike, &start);
734                                 float how_much_hot_sauce = vm_vec_normalize(&your_basic_hot_sauce);
735
736                                 // now figure out how much of that good wing sauce to add
737                                 vector wing_sauce = Storm->flavor;
738                                 if(frand_range(0.0, 1.0f) < 0.5f){
739                                         vm_vec_scale(&wing_sauce, -1.0f);
740                                 }
741                                 float how_much_of_that_good_wing_sauce_to_add = vm_vec_normalize(&wing_sauce);
742
743                                 // mix the two together, taking care not to add too much
744                                 vector the_mixture;
745                                 if(how_much_of_that_good_wing_sauce_to_add > 1000.0f){
746                                         how_much_of_that_good_wing_sauce_to_add = 1000.0f;
747                                 }
748                                 vm_vec_interp_constant(&the_mixture, &your_basic_hot_sauce, &wing_sauce, how_much_of_that_good_wing_sauce_to_add / 1000.0f);
749
750                                 // take the final sauce and store it in the proper container
751                                 vm_vec_scale(&the_mixture, how_much_hot_sauce);
752
753                                 // make sure to put it on everything! whee!                     
754                                 vm_vec_add(&strike, &start, &the_mixture);
755                         }
756
757                         int type = (int)frand_range(0.0f, (float)(Storm->num_bolt_types-1));
758                         nebl_bolt(Storm->bolt_types[type], &start, &strike);
759                 }
760
761                 // reset the timestamp
762                 Nebl_stamp = timestamp((int)frand_range((float)Storm->min, (float)Storm->max));
763         }       
764 }
765
766 // create a lightning bolt
767 void nebl_bolt(int type, vector *start, vector *strike)
768 {
769         vector dir;
770         l_bolt *bolt;
771         l_node *tail;
772         int idx;
773         int found;              
774         bolt_type *bi;
775         float bolt_len;
776
777         if(!(The_mission.flags & MISSION_FLAG_FULLNEB)){
778                 return;
779         }
780
781         // find a free bolt
782         found = 0;
783         for(idx=0; idx<MAX_LIGHTNING_BOLTS; idx++){
784                 if(!Nebl_bolts[idx].used){
785                         found = 1;
786                         break;
787                 }
788         }
789         if(!found){
790                 // Int3();
791                 return;
792         }
793
794         if((type < 0) || ((type >= Num_bolt_types) && (type != DEBUG_BOLT)) ){
795                 return;
796         }
797         bi = &Bolt_types[type]; 
798
799         // get a pointer to the bolt
800         bolt = &Nebl_bolts[idx];        
801
802         // setup bolt into
803         bolt->start = *start;
804         bolt->strike = *strike;
805         bolt->strikes_left = bi->num_strikes;
806         bolt->delay = -1;
807         bolt->type = (char)type;
808         bolt->first_frame = 1;
809         bolt->bolt_life = timestamp(bi->lifetime / bi->num_strikes);            
810
811         Nebl_bolt_start = *start;
812         Nebl_bolt_strike = *strike;
813
814         // setup fire delay
815         if(bolt->delay != -1){
816                 bolt->delay = timestamp(bolt->delay);
817         }
818
819         // setup the rest of the important bolt data
820         if(vm_vec_same(&Nebl_bolt_start, &Nebl_bolt_strike)){
821                 Nebl_bolt_strike.xyz.z += 150.0f;
822         }
823         Nebl_bolt_len = vm_vec_dist(&Nebl_bolt_start, &Nebl_bolt_strike);       
824         vm_vec_sub(&dir, &Nebl_bolt_strike, &Nebl_bolt_start);
825
826         // setup midpoint
827         vm_vec_scale_add(&bolt->midpoint, &Nebl_bolt_start, &dir, 0.5f);
828
829         bolt_len = vm_vec_normalize(&dir);
830         vm_vector_2_matrix(&Nebl_bolt_dir, &dir, NULL, NULL);
831
832         // global type for generating the bolt
833         Nebl_type = bi;
834
835         // try and make the bolt
836         if(!nebl_gen(&Nebl_bolt_start, &Nebl_bolt_strike, 0, 4, 0, &bolt->head, &tail)){
837                 if(bolt->head != NULL){
838                         nebl_release(bolt->head);
839                 }
840
841                 return;
842         }
843
844         Nebl_bolt_count++;      
845         
846         // setup the rest of the data   
847         bolt->used = 1; 
848         bolt->width = bi->b_poly_pct * bolt_len;
849
850         // if i'm a multiplayer master, send a bolt packet
851         if(MULTIPLAYER_MASTER){
852                 send_lightning_packet(type, start, strike);
853         }
854 }
855
856 // get the current # of active lightning bolts
857 int nebl_get_active_bolts()
858 {
859         return Nebl_bolt_count;
860 }
861
862 // get the current # of active nodes
863 int nebl_get_active_nodes()
864 {
865         return Num_lnodes;
866 }
867
868 // set the storm (call from mission parse)
869 void nebl_set_storm(char *name)
870 {
871         int index = nebl_get_storm_index(name);
872
873         // sanity
874         Storm = NULL;
875         if((index >= 0) && (index < Num_storm_types)){
876                 Storm = &Storm_types[index];
877         }
878 }
879
880 // ------------------------------------------------------------------------------------------------------
881 // NEBULA LIGHTNING FORWARD DEFINITIONS
882 //
883
884 // "new" a lightning node
885 l_node *nebl_new()
886 {
887         l_node *lp;
888
889         // if we're out of nodes
890         if(Num_lnodes >= MAX_LIGHTNING_NODES){
891                 // Int3();
892                 nprintf(("lightning", "Out of lightning nodes!\n"));
893                 return NULL;
894         }
895
896         // get a new node off the freelist
897         lp = GET_FIRST(&Nebl_free_list);
898         SDL_assert( lp != &Nebl_free_list );            // shouldn't have the dummy element
899
900         // remove trailp from the free list
901         list_remove( &Nebl_free_list, lp );
902         
903         // insert trailp onto the end of used list
904         list_append( &Nebl_used_list, lp );
905
906         // increment counter
907         Num_lnodes++;
908
909         lp->links[0] = NULL;
910         lp->links[1] = NULL;
911         lp->links[2] = NULL;    
912
913         // return the pointer
914         return lp;
915 }
916
917 // "delete" a lightning node
918 void nebl_delete(l_node *lp)
919 {
920         // remove objp from the used list
921         list_remove( &Nebl_used_list, lp );
922
923         // add objp to the end of the free
924         list_append( &Nebl_free_list, lp );
925
926         // decrement counter
927         Num_lnodes--;
928 }
929
930 // free a lightning bolt
931 void nebl_release(l_node *whee)
932 {
933         // if we're invalid
934         if(whee == NULL){
935                 return;
936         }
937
938         // release all of our children
939         if(whee->links[LINK_RIGHT] != NULL){
940                 nebl_release(whee->links[LINK_RIGHT]);
941         }       
942         if(whee->links[LINK_CHILD] != NULL){
943                 nebl_release(whee->links[LINK_CHILD]);
944         }       
945
946         // delete this node
947         nebl_delete(whee);
948 }
949
950 int nebl_gen(vector *left, vector *right, float depth, float max_depth, int child, l_node **l_left, l_node **l_right)
951 {
952         l_node *child_node = NULL;
953         float d = vm_vec_dist_quick( left, right );             
954
955         // if we've reached the critical point
956         if ( d < 0.30f || (depth > max_depth) ){
957                 // generate ne items
958                 l_node *new_left = nebl_new();
959                 if(new_left == NULL){
960                         return 0;
961                 }               
962                 new_left->links[0] = NULL; new_left->links[1] = NULL; new_left->links[2] = NULL;
963                 new_left->pos = vmd_zero_vector;
964                 l_node *new_right = nebl_new();
965                 if(new_right == NULL){
966                         nebl_delete(new_left);                  
967                         return 0;
968                 }               
969                 new_right->links[0] = NULL; new_right->links[1] = NULL; new_right->links[2] = NULL;
970                 new_right->pos = vmd_zero_vector;
971
972                 // left side
973                 new_left->pos = *left;          
974                 new_left->links[LINK_RIGHT] = new_right;                
975                 *l_left = new_left;
976                 
977                 // right side
978                 new_right->pos = *right;
979                 new_right->links[LINK_LEFT] = new_left;
980                 *l_right = new_right;
981
982                 // done
983                 return 1;
984         }  
985
986         // divide in half
987         vector tmp;
988         vm_vec_avg( &tmp, left, right );
989
990         // sometimes generate children
991         if(!child && (frand() <= Nebl_type->b_rand)){
992                 // get a point on the plane of the strike
993                 vector tmp2;
994                 vm_vec_random_in_circle(&tmp2, &Nebl_bolt_strike, &Nebl_bolt_dir, Nebl_bolt_len * Nebl_type->b_scale, 0);
995
996                 // maybe move away from the plane
997                 vector dir;
998                 vm_vec_sub(&dir, &tmp2, &tmp);          
999                 vm_vec_scale_add(&tmp2, &tmp, &dir, Nebl_type->b_shrink);
1000
1001                 // child
1002                 l_node *argh;           
1003                 if(!nebl_gen(&tmp, &tmp2, 0, 2, 1, &child_node, &argh)){
1004                         if(child_node != NULL){
1005                                 nebl_release(child_node);
1006                         }
1007                         return 0;
1008                 }
1009         }
1010         
1011         float scaler = 0.30f;
1012         tmp.xyz.x += (frand()-0.5f)*d*scaler;
1013         tmp.xyz.y += (frand()-0.5f)*d*scaler;
1014         tmp.xyz.z += (frand()-0.5f)*d*scaler;
1015
1016         // generate left half
1017         l_node *ll = NULL;
1018         l_node *lr = NULL;
1019         if(!nebl_gen( left, &tmp, depth+1, max_depth, child, &ll, &lr )){
1020                 if(child_node != NULL){
1021                         nebl_release(child_node);
1022                 }
1023                 if(ll != NULL){
1024                         nebl_release(ll);
1025                 }
1026                 return 0;
1027         }
1028
1029         // generate right half
1030         l_node *rl = NULL;
1031         l_node *rr = NULL;
1032         if(!nebl_gen( &tmp, right, depth+1, max_depth, child, &rl, &rr )){
1033                 if(child_node != NULL){
1034                         nebl_release(child_node);
1035                 }
1036                 if(ll != NULL){
1037                         nebl_release(ll);
1038                 }
1039                 if(rl != NULL){
1040                         nebl_release(rl);
1041                 }
1042                 return 0;
1043         }
1044         
1045         // splice the two together
1046         lr->links[LINK_RIGHT] = rl->links[LINK_RIGHT];
1047         lr->links[LINK_RIGHT]->links[LINK_LEFT] = lr;
1048         nebl_delete(rl);
1049
1050         // if we generated a child, stick him on
1051         if(child_node != NULL){
1052                 lr->links[LINK_CHILD] = child_node;
1053         }
1054
1055         // return these
1056         *l_left = ll;
1057         *l_right = rr;
1058
1059         return 1;
1060 }
1061
1062
1063 // output top and bottom vectors
1064 // fvec == forward vector (eye viewpoint basically. in world coords)
1065 // pos == world coordinate of the point we're calculating "around"
1066 // w == width of the diff between top and bottom around pos
1067 void nebl_calc_facing_pts_smart( vector *top, vector *bot, vector *fvec, vector *pos, float w, float z_add )
1068 {
1069         vector uvec, rvec;
1070         vector temp;    
1071
1072         temp = *pos;
1073
1074         vm_vec_sub( &rvec, &Eye_position, &temp );
1075         vm_vec_normalize( &rvec );      
1076
1077         vm_vec_crossprod(&uvec,fvec,&rvec);
1078         vm_vec_normalize(&uvec);
1079
1080         vm_vec_scale_add( top, &temp, &uvec, w/2.0f );
1081         vm_vec_scale_add( bot, &temp, &uvec, -w/2.0f ); 
1082         
1083         vm_vec_scale_add2( top, &rvec, z_add );
1084         vm_vec_scale_add2( bot, &rvec, z_add );
1085 }
1086
1087 // render a section of the bolt
1088 void nebl_render_section(bolt_type *bi, l_section *a, l_section *b)
1089 {               
1090         vertex v[4];
1091         vertex *verts[4] = {&v[0], &v[1], &v[2], &v[3]};
1092         int idx;
1093
1094         // Sets mode.  Returns previous mode.
1095         gr_zbuffer_set(GR_ZBUFF_FULL);  
1096
1097         // draw some stuff
1098         for(idx=0; idx<2; idx++){               
1099                 v[0] = a->vex[idx];             
1100                 v[0].u = 0.0f; v[0].v = 0.0f;
1101
1102                 v[1] = a->vex[idx+1];           
1103                 v[1].u = 1.0f; v[1].v = 0.0f;
1104
1105                 v[2] = b->vex[idx+1];           
1106                 v[2].u = 1.0f; v[2].v = 1.0f;
1107
1108                 v[3] = b->vex[idx];             
1109                 v[3].u = 0.0f; v[3].v = 1.0f;
1110
1111                 // draw
1112                 gr_set_bitmap(bi->texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, Nebl_alpha, -1, -1);
1113                 g3_draw_poly(4, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT);         
1114         }
1115
1116         // draw
1117         v[0] = a->vex[2];               
1118         v[0].u = 0.0f; v[0].v = 0.0f;
1119
1120         v[1] = a->vex[0];               
1121         v[1].u = 1.0f; v[1].v = 0.0f;
1122
1123         v[2] = b->vex[0];               
1124         v[2].u = 1.0f; v[2].v = 1.0f;
1125
1126         v[3] = b->vex[2];               
1127         v[3].u = 0.0f; v[3].v = 1.0f;
1128
1129         gr_set_bitmap(bi->texture, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, Nebl_alpha, -1, -1);
1130         g3_draw_poly(4, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT); 
1131
1132         // draw the glow beam   
1133         verts[0] = &a->glow_vex[0];
1134         verts[0]->v = 0.0f; verts[0]->u = 0.0f;
1135
1136         verts[1] = &a->glow_vex[1];
1137         verts[1]->v = 1.0f; verts[1]->u = 0.0f;
1138
1139         verts[2] = &b->glow_vex[1];
1140         verts[2]->v = 1.0f; verts[2]->u = 1.0f;
1141
1142         verts[3] = &b->glow_vex[0];
1143         verts[3]->v = 0.0f; verts[3]->u = 1.0f;
1144
1145         gr_set_bitmap(bi->glow, GR_ALPHABLEND_FILTER, GR_BITBLT_MODE_NORMAL, Nebl_glow_alpha, -1, -1);
1146         g3_draw_poly(4, verts, TMAP_FLAG_TEXTURED | TMAP_FLAG_CORRECT); 
1147 }
1148
1149 // generate a section
1150 void nebl_generate_section(bolt_type *bi, float width, l_node *a, l_node *b, l_section *c, l_section *cap, int pinch_a, int pinch_b)
1151 {
1152         vector dir;
1153         vector dir_normal;
1154         matrix m;
1155         int idx;        
1156         vector temp, pt;
1157         vector glow_a, glow_b;
1158
1159         // direction matrix
1160         vm_vec_sub(&dir, &a->pos, &b->pos);
1161         vm_vec_copy_normalize(&dir_normal, &dir);
1162         vm_vector_2_matrix(&m, &dir_normal, NULL, NULL);
1163
1164         // distance to player
1165         float bang_dist = vm_vec_dist_quick(&Eye_position, &a->pos);
1166         if(bang_dist < Nebl_bang){
1167                 Nebl_bang = bang_dist;
1168         }
1169
1170         // rotate the basic section into world  
1171         for(idx=0; idx<3; idx++){
1172                 // rotate to world              
1173                 if(pinch_a){                    
1174                         vm_vec_rotate(&pt, &Nebl_ring_pinched[idx], &m);
1175                 } else {
1176                         vm_vec_copy_scale(&temp, &Nebl_ring[idx], width);
1177                         vm_vec_rotate(&pt, &temp, &m);
1178                 }
1179                 vm_vec_add2(&pt, &a->pos);
1180                         
1181                 // transform
1182                 g3_rotate_vertex(&c->vex[idx], &pt);
1183                 g3_project_vertex(&c->vex[idx]);                
1184
1185                 // if first frame, keep track of the average screen pos
1186                 if((c->vex[idx].sx >= 0) && (c->vex[idx].sx < gr_screen.max_w) && (c->vex[idx].sy >= 0) && (c->vex[idx].sy < gr_screen.max_h)){
1187                         Nebl_flash_x += c->vex[idx].sx;
1188                         Nebl_flash_y += c->vex[idx].sy;
1189                         Nebl_flash_count++;
1190                 }
1191         }
1192         // calculate the glow points            
1193         nebl_calc_facing_pts_smart(&glow_a, &glow_b, &dir_normal, &a->pos, pinch_a ? 0.5f : width * 6.0f, Nebl_type->b_add);
1194         g3_rotate_vertex(&c->glow_vex[0], &glow_a);
1195         g3_project_vertex(&c->glow_vex[0]);
1196         g3_rotate_vertex(&c->glow_vex[1], &glow_b);
1197         g3_project_vertex(&c->glow_vex[1]);     
1198
1199         // maybe do a cap
1200         if(cap != NULL){                
1201                 // rotate the basic section into world
1202                 for(idx=0; idx<3; idx++){
1203                         // rotate to world              
1204                         if(pinch_b){
1205                                 vm_vec_rotate(&pt, &Nebl_ring_pinched[idx], &m);
1206                         } else {
1207                                 vm_vec_copy_scale(&temp, &Nebl_ring[idx], width);
1208                                 vm_vec_rotate(&pt, &temp, &m);          
1209                         }
1210                         vm_vec_add2(&pt, &b->pos);
1211                         
1212                         // transform
1213                         g3_rotate_vertex(&cap->vex[idx], &pt);
1214                         g3_project_vertex(&cap->vex[idx]);                      
1215
1216                         // if first frame, keep track of the average screen pos                 
1217                         if( (c->vex[idx].sx >= 0) && (c->vex[idx].sx < gr_screen.max_w) && (c->vex[idx].sy >= 0) && (c->vex[idx].sy < gr_screen.max_h)){
1218                                 Nebl_flash_x += c->vex[idx].sx;
1219                                 Nebl_flash_y += c->vex[idx].sy;
1220                                 Nebl_flash_count++;
1221                         }
1222                 }
1223                 
1224                 // calculate the glow points            
1225                 nebl_calc_facing_pts_smart(&glow_a, &glow_b, &dir_normal, &b->pos, pinch_b ? 0.5f : width * 6.0f, bi->b_add);
1226                 g3_rotate_vertex(&cap->glow_vex[0], &glow_a);
1227                 g3_project_vertex(&cap->glow_vex[0]);
1228                 g3_rotate_vertex(&cap->glow_vex[1], &glow_b);
1229                 g3_project_vertex(&cap->glow_vex[1]);
1230         }
1231 }
1232
1233 // render the bolt
1234 void nebl_render(bolt_type *bi, l_node *whee, float width, l_section *prev)
1235 {               
1236         l_section start;
1237         l_section end;
1238         l_section child_start;
1239
1240         // bad
1241         if(whee == NULL){
1242                 return;
1243         }
1244
1245         // if prev is NULL, we're just starting so we need our start point
1246         if(prev == NULL){
1247                 SDL_assert(whee->links[LINK_RIGHT] != NULL);
1248                 nebl_generate_section(bi, width, whee, whee->links[LINK_RIGHT], &start, NULL, 1, 0);
1249         } else {
1250                 start = *prev;
1251         }
1252         
1253         // if we have a child section   
1254         if(whee->links[LINK_CHILD]){            
1255                 // generate section
1256                 nebl_generate_section(bi, width * 0.5f, whee, whee->links[LINK_CHILD], &child_start, &end, 0, whee->links[LINK_CHILD]->links[LINK_RIGHT] == NULL ? 1 : 0);
1257
1258                 // render
1259                 nebl_render_section(bi, &child_start, &end);                    
1260
1261                 // maybe continue
1262                 if(whee->links[LINK_CHILD]->links[LINK_RIGHT] != NULL){
1263                         nebl_render(bi, whee->links[LINK_CHILD], width * 0.5f, &end);
1264                 }
1265         }       
1266                 
1267         // if the next section is an end section
1268         if(whee->links[LINK_RIGHT]->links[LINK_RIGHT] == NULL){
1269                 l_section temp;
1270
1271                 // generate section
1272                 nebl_generate_section(bi, width, whee, whee->links[LINK_RIGHT], &temp, &end, 0, 1);
1273
1274                 // render the section
1275                 nebl_render_section(bi, &start, &end);          
1276         }
1277         // a middle section
1278         else if(whee->links[LINK_RIGHT]->links[LINK_RIGHT] != NULL){
1279                 // generate section
1280                 nebl_generate_section(bi, width, whee->links[LINK_RIGHT], whee->links[LINK_RIGHT]->links[LINK_RIGHT], &end, NULL, 0, 0);
1281
1282                 // render the section
1283                 nebl_render_section(bi, &start, &end);
1284
1285                 // recurse through him
1286                 nebl_render(bi, whee->links[LINK_RIGHT], width, &end);
1287         }
1288 }
1289
1290 // given a valid, complete bolt, jitter him based upon his noise
1291 void nebl_jitter(l_bolt *b)
1292 {
1293         matrix m;
1294         vector temp;
1295         float length;
1296         l_node *moveup;
1297         bolt_type *bi = NULL;
1298
1299         // sanity
1300         if(b == NULL){
1301                 return;
1302         }
1303         if((b->type < 0) || ((b->type >= Num_bolt_types) && (b->type != DEBUG_BOLT)) ){
1304                 return;         
1305         }
1306         bi = &Bolt_types[(int)b->type];
1307
1308         // get the bolt direction
1309         vm_vec_sub(&temp, &b->strike, &b->start);
1310         length = vm_vec_normalize_quick(&temp);
1311         vm_vector_2_matrix(&m, &temp, NULL, NULL);
1312
1313         // jitter all nodes on the main trunk
1314         moveup = b->head;
1315         while(moveup != NULL){
1316                 temp = moveup->pos;
1317                 vm_vec_random_in_circle(&moveup->pos, &temp, &m, frand_range(0.0f, length * bi->noise), 0);
1318
1319                 // just on the main trunk
1320                 moveup = moveup->links[LINK_RIGHT];
1321         }       
1322 }
1323
1324 // return the index of a given bolt type by name
1325 int nebl_get_bolt_index(char *name)
1326 {
1327         int idx;
1328
1329         for(idx=0; idx<Num_bolt_types; idx++){
1330                 if(!strcmp(name, Bolt_types[idx].name)){
1331                         return idx;
1332                 }
1333         }
1334
1335         return -1;
1336 }
1337
1338 // return the index of a given storm type by name
1339 int nebl_get_storm_index(char *name)
1340 {
1341         int idx;
1342
1343         for(idx=0; idx<Num_bolt_types; idx++){
1344                 if(!strcmp(name, Storm_types[idx].name)){
1345                         return idx;
1346                 }
1347         }
1348
1349         return -1;
1350 }
1351