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