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