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