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