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