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