FS2_Open
Open source remastering of the Freespace 2 engine
fireballs.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "asteroid/asteroid.h"
13 #include "cmdline/cmdline.h"
14 #include "fireball/fireballs.h"
15 #include "gamesnd/gamesnd.h"
16 #include "graphics/tmapper.h"
17 #include "localization/localize.h"
18 #include "model/model.h"
19 #include "object/object.h"
20 #include "parse/parselo.h"
21 #include "render/3d.h"
22 #include "ship/ship.h"
23 
24 #include <stdlib.h>
25 
26 
27 // make use of the LOD checker for tbl/tbm parsing (from weapons.cpp)
29 
30 static SCP_vector<color> LOD_color;
31 
34 
35 #define WARPHOLE_GROW_TIME (2.35f) // time for warphole to reach max size (also time to shrink to nothing once it begins to shrink)
36 
37 #define MAX_FIREBALL_LOD 4
38 
39 #define MAX_FIREBALLS 200
40 
41 #define MAX_WARP_LOD 0
42 
44 
46 
48 
49 int Num_fireballs = 0;
51 
53 
56 
57 #define FB_INDEX(fb) (fb-Fireballs)
58 
63 {
64  int sound_index;
65  float range_multiplier = 1.0f;
66  object *fireball_objp;
67 
68  Assert((fb != NULL) && (fb->objnum >= 0));
69  if((fb == NULL) || (fb->objnum < 0)){
70  return;
71  }
72  fireball_objp = &Objects[fb->objnum];
73 
74  sound_index = SND_WARP_IN;
75 
76  if(fb->warp_open_sound_index > -1) {
77  sound_index = fb->warp_open_sound_index;
78  } else if ((ship_class >= 0) && (ship_class < static_cast<int>(Ship_info.size()))) {
79  if ( Ship_info[ship_class].flags & SIF_HUGE_SHIP ) {
80  sound_index = SND_CAPITAL_WARP_IN;
82  } else if ( Ship_info[ship_class].flags & SIF_BIG_SHIP ) {
83  range_multiplier = 6.0f;
85  }
86  }
87 
88  snd_play_3d(&Snds[sound_index], &fireball_objp->pos, &Eye_position, fireball_objp->radius, NULL, 0, 1.0f, SND_PRIORITY_DOUBLE_INSTANCE, NULL, range_multiplier); // play warp sound effect
89 }
90 
95 {
96  int sound_index;
97 
98  object *fireball_objp;
99 
100  fireball_objp = &Objects[fb->objnum];
101 
102  sound_index = SND_WARP_OUT;
103 
104  if ( fb->warp_close_sound_index > -1 ) {
105  sound_index = fb->warp_close_sound_index;
106  } else if ( fb->flags & FBF_WARP_CAPITAL_SIZE ) {
107  sound_index = SND_CAPITAL_WARP_OUT;
108  } else {
109  return;
110  }
111 
112  snd_play_3d(&Snds[sound_index], &fireball_objp->pos, &Eye_position, fireball_objp->radius); // play warp sound effect
113 }
114 
118 static void fireball_set_default_color(int idx)
119 {
120  Assert( (idx >= 0) && (idx < MAX_FIREBALL_TYPES) );
121 
122  switch (idx)
123  {
127  case FIREBALL_ASTEROID:
128  Fireball_info[idx].exp_color[0] = 1.0f;
129  Fireball_info[idx].exp_color[1] = 0.5f;
130  Fireball_info[idx].exp_color[2] = 0.125f;
131  break;
132 
133  case FIREBALL_WARP:
134  Fireball_info[idx].exp_color[0] = 0.75f;
135  Fireball_info[idx].exp_color[1] = 0.75f;
136  Fireball_info[idx].exp_color[2] = 1.0f;
137  break;
138 
139 
140  case FIREBALL_KNOSSOS:
141  Fireball_info[idx].exp_color[0] = 0.75f;
142  Fireball_info[idx].exp_color[1] = 1.0f;
143  Fireball_info[idx].exp_color[2] = 0.75f;
144  break;
145 
146  default:
147  Fireball_info[idx].exp_color[0] = 1.0f;
148  Fireball_info[idx].exp_color[1] = 1.0f;
149  Fireball_info[idx].exp_color[2] = 1.0f;
150  break;
151  }
152 }
153 
159 void parse_fireball_tbl(const char *filename)
160 {
161  lod_checker lod_check;
162  color fb_color;
163 
164  try
165  {
166  read_file_text(filename, CF_TYPE_TABLES);
167  reset_parse();
168 
169  required_string("#Start");
170 
171  while (required_string_either("#End", "$Name:")) {
172  memset(&lod_check, 0, sizeof(lod_checker));
173 
174  // base filename
175  required_string("$Name:");
177 
178  lod_check.override = -1;
179 
180  // these entries should only be in TBMs, and it has to include at least one
181  if (Parsing_modular_table) {
182  if (optional_string("+Explosion_Medium")) {
184  }
185  else if (optional_string("+Warp_Effect")) {
186  lod_check.override = FIREBALL_WARP;
187  }
188  else if (optional_string("+Knossos_Effect")) {
189  lod_check.override = FIREBALL_KNOSSOS;
190  }
191  else if (optional_string("+Asteroid")) {
192  lod_check.override = FIREBALL_ASTEROID;
193  }
194  else if (optional_string("+Explosion_Large1")) {
196  }
197  else if (optional_string("+Explosion_Large2")){
199  }
200  else {
201  required_string("+Custom_Fireball");
202  stuff_int(&lod_check.override);
203  }
204  }
205 
206  lod_check.num_lods = 1;
207 
208  // Do we have an LOD num
209  if (optional_string("$LOD:")) {
210  stuff_int(&lod_check.num_lods);
211  }
212 
213  if (lod_check.num_lods > MAX_FIREBALL_LOD) {
214  lod_check.num_lods = MAX_FIREBALL_LOD;
215  }
216 
217  // check for particular lighting color
218  if (optional_string("$Light color:")) {
219  int r, g, b;
220 
221  stuff_int(&r);
222  stuff_int(&g);
223  stuff_int(&b);
224 
225  CLAMP(r, 0, 255);
226  CLAMP(g, 0, 255);
227  CLAMP(b, 0, 255);
228 
229  gr_init_color(&fb_color, r, g, b);
230  }
231  else {
232  // to keep things simple, we just use 0 alpha to indicate that a default value should be used
233  memset(&fb_color, 0, sizeof(color));
234  }
235 
236  // we may use one filename for multiple entries so we'll have to handle dupes post parse
237  LOD_checker.push_back(lod_check);
238  LOD_color.push_back(fb_color);
239  }
240 
241  required_string("#End");
242  }
243  catch (const parse::ParseException& e)
244  {
245  mprintf(("TABLES: Unable to parse '%s'! Error message = %s.\n", filename, e.what()));
246  return;
247  }
248 }
249 
251 {
252  int i = 0, j;
254 
255  memset( &Fireball_info, 0, sizeof(fireball_info) * MAX_FIREBALL_TYPES );
256 
257 
258  parse_fireball_tbl("fireball.tbl");
259 
260  // look for any modular tables
262 
263  // we've got our list so pass it off for final checking and loading.
264  // we assume that entries in fireball.tbl are in the correct order
265  for (lod = LOD_checker.begin(); lod != LOD_checker.end(); ++lod) {
266  if ( (i < MAX_FIREBALL_TYPES) && (lod->override < 0) ) {
267  strcpy_s( Fireball_info[i].lod[0].filename, lod->filename );
268  Fireball_info[i].lod_count = lod->num_lods;
270 
271  if (LOD_color[i].alpha == 255) {
272  Fireball_info[i].exp_color[0] = (LOD_color[i].red / 255.0f);
273  Fireball_info[i].exp_color[1] = (LOD_color[i].green / 255.0f);
274  Fireball_info[i].exp_color[2] = (LOD_color[i].blue / 255.0f);
275  } else {
276  fireball_set_default_color(i);
277  }
278  }
279  i++;
280  }
281 
282  // having to do this twice is less than optimal, but less error prone too.
283  // this handles (and should only have to handle) TBM related entries
284  i = 0;
285  for (lod = LOD_checker.begin(); lod != LOD_checker.end(); ++lod) {
286  // try entry replacement
287  if ( (lod->override >= 0) && (lod->override < Num_fireball_types) ) {
288  strcpy_s( Fireball_info[lod->override].lod[0].filename, lod->filename );
289  Fireball_info[lod->override].lod_count = lod->num_lods;
290 
291  if (LOD_color[i].alpha == 255) {
292  Fireball_info[lod->override].exp_color[0] = (LOD_color[i].red / 255.0f);
293  Fireball_info[lod->override].exp_color[1] = (LOD_color[i].green / 255.0f);
294  Fireball_info[lod->override].exp_color[2] = (LOD_color[i].blue / 255.0f);
295  } else {
296  fireball_set_default_color(lod->override);
297  }
298  }
299  }
300 
301  // fill in extra LOD filenames
302  for (i = 0; i < Num_fireball_types; i++) {
303  for (j = 1; j < Fireball_info[i].lod_count; j++) {
304  sprintf( Fireball_info[i].lod[j].filename, "%s_%d", Fireball_info[i].lod[0].filename, j);
305  }
306  }
307 
308  // done
309  LOD_checker.clear();
310 }
311 
312 
314 {
315  int i, idx;
316  fireball_info *fd;
317 
318  for ( i = 0; i < Num_fireball_types; i++ ) {
319  fd = &Fireball_info[i];
320 
321  for(idx=0; idx<fd->lod_count; idx++){
322  // we won't use a warp effect lod greater than MAX_WARP_LOD so don't load it either
323  if ( (i == FIREBALL_WARP) && (idx > MAX_WARP_LOD) )
324  continue;
325 
326  fd->lod[idx].bitmap_id = bm_load_animation( fd->lod[idx].filename, &fd->lod[idx].num_frames, &fd->lod[idx].fps, NULL, 1 );
327  if ( fd->lod[idx].bitmap_id < 0 ) {
328  Error(LOCATION, "Could not load %s anim file\n", fd->lod[idx].filename);
329  }
330  }
331  }
332 
333  if ( Warp_glow_bitmap == -1 ) {
334  Warp_glow_bitmap = bm_load( NOX("warpglow01") );
335  }
336  if ( Warp_ball_bitmap == -1 ) {
337  Warp_ball_bitmap = bm_load( NOX("warpball01") );
338  }
339 }
340 
341 // This will get called at the start of each level.
343 {
344  int i;
345 
346  if ( !fireballs_inited ) {
347  fireballs_inited = 1;
348 
349  // Do all the processing that happens only once
352  }
353 
354  // Reset everything between levels
355  Num_fireballs = 0;
356  for (i=0; i<MAX_FIREBALLS; i++ ) {
357  Fireballs[i].objnum = -1;
358  }
359 
360  // Goober5000 - reset Knossos warp flag
362 
363  mprintf(("Loading warp model\n"));
364  Warp_model = -1;
365 
366  // Goober5000 - check for existence of file before trying to load it
367  if (cf_exists_full("warp.pof", CF_TYPE_MODELS))
368  {
369  Warp_model = model_load("warp.pof", 0, NULL, 0);
370  }
371 
372  mprintf((" %d\n", Warp_model));
373 }
374 
375 MONITOR( NumFireballsRend )
376 
378 {
379  int num;
380  vertex p;
381  fireball *fb;
382 
383  MONITOR_INC( NumFireballsRend, 1 );
384 
385  memset(&p, 0, sizeof(p));
386 
387  num = obj->instance;
388  fb = &Fireballs[num];
389 
390  if ( Fireballs[num].current_bitmap < 0 )
391  return;
392 
393  // turn off fogging
395  gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
396  }
397 
398  if(Cmdline_nohtl) {
399  g3_rotate_vertex(&p, &obj->pos );
400  }else{
401  g3_transfer_vertex(&p, &obj->pos);
402  }
403 
404  switch( fb->fireball_render_type ) {
405 
408  Fireballs[num].current_bitmap,
410  &p,
411  fb->orient,
412  obj->radius
413  );
414  break;
415 
417  // Make the big explosions rotate with the viewer.
419  Fireballs[num].current_bitmap,
421  &p,
422  (i2fl(fb->orient)*PI)/180.0f,
423  obj->radius
424  );
425  break;
426 
427  case FIREBALL_WARP_EFFECT: {
428 
429  float percent_life = fb->time_elapsed / fb->total_time;
430 
431  float rad;
432 
433  // Code to make effect grow/shrink.
434  float t = fb->time_elapsed;
435 
436  if ( t < WARPHOLE_GROW_TIME ) {
437  rad = (float)pow(t/WARPHOLE_GROW_TIME,0.4f)*obj->radius;
438  } else if ( t < fb->total_time - WARPHOLE_GROW_TIME ) {
439  rad = obj->radius;
440  } else {
441  rad = (float)pow((fb->total_time - t)/WARPHOLE_GROW_TIME,0.4f)*obj->radius;
442  }
443 
444  warpin_render(obj, &obj->orient, &obj->pos, Fireballs[num].current_bitmap, rad, percent_life, obj->radius, (Fireballs[num].flags & FBF_WARP_3D) );
445  }
446  break;
447 
448 
449  default:
450  Int3();
451  }
452 }
453 
458 void fireball_delete( object * obj )
459 {
460  int num;
461  fireball *fb;
462 
463  num = obj->instance;
464  fb = &Fireballs[num];
465 
466  Assert( fb->objnum == OBJ_INDEX(obj));
467 
468  Fireballs[num].objnum = -1;
469  Num_fireballs--;
470  Assert( Num_fireballs >= 0 );
471 }
472 
477 {
478  fireball *fb;
479  int i;
480 
481  for ( i = 0; i < MAX_FIREBALLS; i++ ) {
482  fb = &Fireballs[i];
483  if ( fb->objnum != -1 ) {
484  obj_delete(fb->objnum);
485  }
486  }
487 }
488 
490 {
491  int framenum;
492  fireball *fb;
493  fireball_info *fd;
494  fireball_lod *fl;
495 
496  fb = &Fireballs[num];
497  fd = &Fireball_info[Fireballs[num].fireball_info_index];
498 
499  // valid lod?
500  fl = NULL;
501  if((fb->lod >= 0) && (fb->lod < fd->lod_count)){
502  fl = &Fireball_info[Fireballs[num].fireball_info_index].lod[fb->lod];
503  }
504  if(fl == NULL){
505  // argh
506  return;
507  }
508 
510  float total_time = i2fl(fl->num_frames) / fl->fps; // in seconds
511 
512  framenum = fl2i(fb->time_elapsed * fl->num_frames / total_time + 0.5);
513 
514  if ( framenum < 0 ) framenum = 0;
515 
516  framenum = framenum % fl->num_frames;
517 
518  if ( fb->orient ) {
519  // warp out effect plays backwards
520  framenum = fl->num_frames-framenum-1;
521  fb->current_bitmap = fl->bitmap_id + framenum;
522  } else {
523  fb->current_bitmap = fl->bitmap_id + framenum;
524  }
525  } else {
526 
527  framenum = fl2i(fb->time_elapsed / fb->total_time * fl->num_frames + 0.5);
528 
529  // ensure we don't go past the number of frames of animation
530  if ( framenum > (fl->num_frames-1) ) {
531  framenum = (fl->num_frames-1);
533  }
534 
535  if ( framenum < 0 ) framenum = 0;
536  fb->current_bitmap = fl->bitmap_id + framenum;
537  }
538 }
539 
541 {
542  // return 1;
543  int num, objnum;
544  fireball *fb;
545 
546  num = obj->instance;
547  objnum = OBJ_INDEX(obj);
548  Assert( Fireballs[num].objnum == objnum );
549 
550  fb = &Fireballs[num];
551 
553  return 1;
554 
555  if ( !(fb->fireball_render_type == FIREBALL_WARP_EFFECT) ) {
556  if ( !(obj->flags & OF_WAS_RENDERED)) {
557  return 1;
558  }
559  }
560 
561  return 0;
562 }
563 
564 
572 {
573  fireball *fb;
574  int i;
575 
576  int oldest_objnum = -1, oldest_slotnum = -1;
577  float lifeleft, oldest_lifeleft = 0.0f;
578 
579  for ( i = 0; i < MAX_FIREBALLS; i++ ) {
580  fb = &Fireballs[i];
581 
582  // only remove the ones that aren't warp effects
583  if ( (fb->objnum >= 0) && fireball_is_perishable(&Objects[fb->objnum]) ) {
584 
585  lifeleft = fb->total_time - fb->time_elapsed;
586  if ( (oldest_objnum < 0) || (lifeleft < oldest_lifeleft) ) {
587  oldest_slotnum = i;
588  oldest_lifeleft = lifeleft;
589  oldest_objnum = fb->objnum;
590  }
591  break;
592  }
593  }
594 
595  if ( oldest_objnum > -1 ) {
596  obj_delete(oldest_objnum);
597  }
598  return oldest_slotnum;
599 }
600 
601 int fireball_is_warp(object * obj)
602 {
603  int num, objnum;
604  fireball *fb;
605 
606  num = obj->instance;
607  objnum = OBJ_INDEX(obj);
608  Assert( Fireballs[num].objnum == objnum );
609 
610  fb = &Fireballs[num];
611 
613  return 1;
614 
615  return 0;
616 }
617 
618 // maybe play sound effect for warp hole closing
620 {
621  float life_left;
622 
623  // If not a warphole fireball, do a quick out
625  return;
626  }
627 
628  // If the warhole close sound has been played, don't play it again!
629  if ( fb->flags & FBF_WARP_CLOSE_SOUND_PLAYED ) {
630  return;
631  }
632 
633  life_left = fb->total_time - fb->time_elapsed;
634 
635  if ( life_left < WARPHOLE_GROW_TIME ) {
638  }
639 }
640 
641 MONITOR( NumFireballs )
642 
644 {
645  int num, objnum;
646  fireball *fb;
647 
648  MONITOR_INC( NumFireballs, 1 );
649 
650  num = obj->instance;
651  objnum = OBJ_INDEX(obj);
652  Assert( Fireballs[num].objnum == objnum );
653 
654  fb = &Fireballs[num];
655 
656  fb->time_elapsed += frame_time;
657  if ( fb->time_elapsed > fb->total_time ) {
658  obj->flags |= OF_SHOULD_BE_DEAD;
659  }
660 
662 
664 }
665 
669 float fireball_lifeleft( object *obj )
670 {
671  int num, objnum;
672  fireball *fb;
673 
674  num = obj->instance;
675  objnum = OBJ_INDEX(obj);
676  Assert( Fireballs[num].objnum == objnum );
677 
678  fb = &Fireballs[num];
679 
680  return fb->total_time - fb->time_elapsed;
681 }
682 
687 {
688  int num, objnum;
689  fireball *fb;
690 
691  num = obj->instance;
692  objnum = OBJ_INDEX(obj);
693  Assert( Fireballs[num].objnum == objnum );
694 
695  fb = &Fireballs[num];
696 
697  float p = (fb->total_time - fb->time_elapsed) / fb->total_time;
698  if (p < 0)p=0.0f;
699  return p;
700 }
701 
706 {
707  vertex v;
708  int x, y, w, h, bm_size;
709  int must_stop = 0;
710  int ret_lod = 1;
711  int behind = 0;
712 
713  // bogus
714  if(fd == NULL){
715  return 1;
716  }
717 
718  // start the frame
719  extern int G3_count;
720 
721  if(!G3_count){
722  g3_start_frame(1);
723  must_stop = 1;
724  }
726 
727  // get extents of the rotated bitmap
728  g3_rotate_vertex(&v, pos);
729 
730  // if vertex is behind, find size if in front, then drop down 1 LOD
731  if (v.codes & CC_BEHIND) {
732  float dist = vm_vec_dist_quick(&Eye_position, pos);
733  vec3d temp;
734 
735  behind = 1;
736  vm_vec_scale_add(&temp, &Eye_position, &Eye_matrix.vec.fvec, dist);
737  g3_rotate_vertex(&v, &temp);
738 
739  // if still behind, bail and go with default
740  if (v.codes & CC_BEHIND) {
741  behind = 0;
742  }
743  }
744 
745  if(!g3_get_bitmap_dims(fd->lod[0].bitmap_id, &v, size, &x, &y, &w, &h, &bm_size)) {
746  if (Detail.hardware_textures == 4) {
747  // straight LOD
748  if(w <= bm_size/8){
749  ret_lod = 3;
750  } else if(w <= bm_size/2){
751  ret_lod = 2;
752  } else if(w <= (1.56*bm_size)){
753  ret_lod = 1;
754  } else {
755  ret_lod = 0;
756  }
757  } else {
758  // less aggressive LOD for lower detail settings
759  if(w <= bm_size/8){
760  ret_lod = 3;
761  } else if(w <= bm_size/3){
762  ret_lod = 2;
763  } else if(w <= (1.2*bm_size)){
764  ret_lod = 1;
765  } else {
766  ret_lod = 0;
767  }
768  }
769  }
770 
771  // if it's behind, bump up LOD by 1
772  if (behind) {
773  ret_lod++;
774  }
775 
776  // end the frame
777  if(must_stop){
778  g3_end_frame();
779  }
780 
781  // return the best lod
782  return MIN(ret_lod, fd->lod_count - 1);
783 }
784 
788 int fireball_create( vec3d * pos, int fireball_type, int render_type, int parent_obj, float size, int reverse, vec3d *velocity, float warp_lifetime, int ship_class, matrix *orient_override, int low_res, int extra_flags, int warp_open_sound, int warp_close_sound)
789 {
790  int n, objnum, fb_lod;
791  object *obj;
792  fireball *fb;
793  fireball_info *fd;
794  fireball_lod *fl;
795 
796  Assert( fireball_type > -1 );
797  Assert( fireball_type < Num_fireball_types );
798 
799  fd = &Fireball_info[fireball_type];
800 
801  // check to make sure this fireball type exists
802  if (!fd->lod_count)
803  return -1;
804 
806  if ( !((fireball_type == FIREBALL_WARP) || (fireball_type == FIREBALL_KNOSSOS)) ) {
807  return -1;
808  }
809  }
810 
811  if ( (Num_fireballs >= MAX_FIREBALLS) || (Num_objects >= MAX_OBJECTS) ) {
812 
813  // out of slots, so free one up.
814  n = fireball_free_one();
815  if ( n < 0 ) {
816  return -1;
817  }
818  } else {
819  for ( n = 0; n < MAX_FIREBALLS; n++ ) {
820  if ( Fireballs[n].objnum < 0 ) {
821  break;
822  }
823  }
824  Assert( n != MAX_FIREBALLS );
825  }
826 
827  fb = &Fireballs[n];
828 
829  // get an lod to use
830  fb_lod = fireball_get_lod(pos, fd, size);
831 
832  // change lod if low res is desired
833  if (low_res) {
834  fb_lod++;
835  fb_lod = MIN(fb_lod, fd->lod_count - 1);
836  }
837 
838  // if this is a warpout fireball, never go higher than LOD 1
839  if(fireball_type == FIREBALL_WARP){
840  fb_lod = MAX_WARP_LOD;
841  }
842  fl = &fd->lod[fb_lod];
843 
844  fb->lod = (char)fb_lod;
845 
846  fb->flags = extra_flags;
847  fb->warp_open_sound_index = warp_open_sound;
848  fb->warp_close_sound_index = warp_close_sound;
849 
850  matrix orient;
851  if(orient_override != NULL){
852  orient = *orient_override;
853  } else {
854  if ( parent_obj < 0 ) {
855  orient = vmd_identity_matrix;
856  } else {
857  orient = Objects[parent_obj].orient;
858  }
859  }
860 
861  objnum = obj_create(OBJ_FIREBALL, parent_obj, n, &orient, pos, size, OF_RENDERS);
862 
863  if (objnum < 0) {
864  Int3(); // Get John, we ran out of objects for fireballs
865  return objnum;
866  }
867 
868  obj = &Objects[objnum];
869 
870  fb->fireball_info_index = fireball_type;
871  fb->fireball_render_type = render_type;
872  fb->time_elapsed = 0.0f;
873  fb->objnum = objnum;
874  fb->current_bitmap = -1;
875 
876  switch( fb->fireball_render_type ) {
877 
879  fb->orient = (myrand()>>8) & 7; // 0 - 7
880  break;
881 
883  fb->orient = (myrand()>>8) % 360; // 0 - 359
884  break;
885 
887  // Play sound effect for warp hole opening up
888  fireball_play_warphole_open_sound(ship_class, fb);
889 
890  // warp in type
891  if (reverse) {
892  fb->orient = 1;
893  // if warp out, then reverse the orientation
894  vm_vec_scale( &obj->orient.vec.fvec, -1.0f ); // Reverse the forward vector
895  vm_vec_scale( &obj->orient.vec.rvec, -1.0f ); // Reverse the right vector
896  } else {
897  fb->orient = 0;
898  }
899  break;
900 
901  default:
902  Int3();
903  break;
904  }
905 
907  Assert( warp_lifetime >= 4.0f ); // Warp lifetime must be at least 4 seconds!
908  if ( warp_lifetime < 4.0f )
909  warp_lifetime = 4.0f;
910  fb->total_time = warp_lifetime; // in seconds
911  } else {
912  fb->total_time = i2fl(fl->num_frames) / fl->fps; // in seconds
913  }
914 
916 
917  if ( velocity ) {
918  // Make the explosion move at a constant velocity.
919  obj->flags |= OF_PHYSICS;
920  obj->phys_info.mass = 1.0f;
921  obj->phys_info.side_slip_time_const = 0.0f;
922  obj->phys_info.rotdamp = 0.0f;
923  obj->phys_info.vel = *velocity;
924  obj->phys_info.max_vel = *velocity;
925  obj->phys_info.desired_vel = *velocity;
926  obj->phys_info.speed = vm_vec_mag(velocity);
928  }
929 
930  Num_fireballs++;
931  return objnum;
932 }
933 
938 {
939  if ( !fireballs_inited )
940  return;
941 
943 }
944 
946 {
947  int i, idx;
948  fireball_info *fd;
949 
950  for ( i = 0; i < Num_fireball_types; i++ ) {
951  if((i < NUM_DEFAULT_FIREBALLS) || fireball_used[i]){
952  fd = &Fireball_info[i];
953 
954  // if this is a Knossos ani, only load if Knossos_warp_ani_used is true
955  if ( (i == FIREBALL_KNOSSOS) && !Knossos_warp_ani_used)
956  continue;
957 
958  for(idx=0; idx<fd->lod_count; idx++) {
959  // we won't use a warp effect lod greater than MAX_WARP_LOD so don't load it either
960  if ( (i == FIREBALL_WARP) && (idx > MAX_WARP_LOD) )
961  continue;
962 
963  bm_page_in_texture( fd->lod[idx].bitmap_id, fd->lod[idx].num_frames );
964  }
965  }
966  }
967 
970 }
971 
972 void fireball_get_color(int idx, float *red, float *green, float *blue)
973 {
974  Assert( red && blue && green );
975 
976  if ( (idx < 0) || (idx >= Num_fireball_types) ) {
977  Int3();
978 
979  *red = 1.0f;
980  *green = 1.0f;
981  *blue = 1.0f;
982 
983  return;
984  }
985 
986  fireball_info *fbi = &Fireball_info[idx];
987 
988  *red = fbi->exp_color[0];
989  *green = fbi->exp_color[1];
990  *blue = fbi->exp_color[2];
991 }
992 
994 {
995  Assert( sip != NULL );
996 
997  int index = -1;
998  int ship_fireballs = (int)sip->explosion_bitmap_anims.size();
999  int objecttype_fireballs = -1;
1000 
1001  if (sip->class_type >= 0) {
1002  objecttype_fireballs = (int)Ship_types[sip->class_type].explosion_bitmap_anims.size();
1003  }
1004 
1005  if(ship_fireballs > 0){
1006  index = sip->explosion_bitmap_anims[rand()%ship_fireballs];
1007  } else if(objecttype_fireballs > 0){
1008  index = Ship_types[sip->class_type].explosion_bitmap_anims[rand()%objecttype_fireballs];
1009  }
1010 
1011  return index;
1012 }
1013 
1015 {
1016  Assert( aip != NULL );
1017 
1018  if (aip->explosion_bitmap_anims.empty())
1019  return -1;
1020 
1021  int index = -1;
1022  int roid_fireballs = (int)aip->explosion_bitmap_anims.size();
1023 
1024  if (roid_fireballs > 0) {
1025  index = aip->explosion_bitmap_anims[rand()%roid_fireballs];
1026  }
1027 
1028  return index;
1029 }
1030 
1032 {
1033  int num, objnum;
1034  fireball *fb;
1035 
1036  num = obj->instance;
1037  objnum = OBJ_INDEX(obj);
1038  Assertion( Fireballs[num].objnum == objnum, "Basic sanity check. Fireballs[num].objnum (%d) should == objnum (%d)", Fireballs[num].objnum, objnum );
1039 
1040  fb = &Fireballs[num];
1041 
1042  float t = fb->time_elapsed;
1043  float rad;
1044 
1045  if ( t < WARPHOLE_GROW_TIME ) {
1046  rad = (float)pow(t/WARPHOLE_GROW_TIME,0.4f);
1047  } else if ( t < fb->total_time - WARPHOLE_GROW_TIME ) {
1048  rad = 1;
1049  } else {
1050  rad = (float)pow((fb->total_time - t)/WARPHOLE_GROW_TIME,0.4f);
1051  }
1052  return rad;
1053 }
1054 
1055 void fireball_render(object* obj, draw_list *scene)
1056 {
1057  int num;
1058  vertex p;
1059  fireball *fb;
1060 
1061  MONITOR_INC( NumFireballsRend, 1 );
1062 
1063  num = obj->instance;
1064  fb = &Fireballs[num];
1065 
1066  if ( Fireballs[num].current_bitmap < 0 )
1067  return;
1068 
1069  if ( Cmdline_nohtl ) {
1070  g3_rotate_vertex(&p, &obj->pos );
1071  } else {
1072  g3_transfer_vertex(&p, &obj->pos);
1073  }
1074 
1075  switch ( fb->fireball_render_type ) {
1076 
1079  Fireballs[num].current_bitmap,
1081  &p,
1082  fb->orient,
1083  obj->radius
1084  );
1085  }
1086  break;
1087 
1088  case FIREBALL_LARGE_EXPLOSION: {
1089  // Make the big explosions rotate with the viewer.
1091  Fireballs[num].current_bitmap,
1093  &p,
1094  (i2fl(fb->orient)*PI)/180.0f,
1095  obj->radius
1096  );
1097  }
1098  break;
1099 
1100  case FIREBALL_WARP_EFFECT: {
1101  float percent_life = fb->time_elapsed / fb->total_time;
1102 
1103  float rad;
1104 
1105  // Code to make effect grow/shrink.
1106  float t = fb->time_elapsed;
1107 
1108  if ( t < WARPHOLE_GROW_TIME ) {
1109  rad = (float)pow(t/WARPHOLE_GROW_TIME,0.4f)*obj->radius;
1110  } else if ( t < fb->total_time - WARPHOLE_GROW_TIME ) {
1111  rad = obj->radius;
1112  } else {
1113  rad = (float)pow((fb->total_time - t)/WARPHOLE_GROW_TIME,0.4f)*obj->radius;
1114  }
1115 
1116  warpin_queue_render(scene, obj, &obj->orient, &obj->pos, Fireballs[num].current_bitmap, rad, percent_life, obj->radius, (Fireballs[num].flags & FBF_WARP_3D) );
1117  }
1118  break;
1119 
1120 
1121  default:
1122  Int3();
1123  }
1124 }
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
#define FIREBALL_EXPLOSION_LARGE2
Definition: fireballs.h:33
int i
Definition: multi_pxo.cpp:466
int fireball_info_index
Definition: fireballs.h:66
int bitmap_id
Definition: fireballs.h:46
#define MIN(a, b)
Definition: pstypes.h:296
int objnum
Definition: fireballs.h:65
#define TMAP_FLAG_SOFT_QUAD
Definition: tmapper.h:79
#define OBJ_FIREBALL
Definition: object.h:34
GLfloat GLfloat GLfloat GLfloat h
Definition: Glext.h:7280
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
#define MISSION_FLAG_FULLNEB
Definition: missionparse.h:70
int fireball_asteroid_explosion_type(asteroid_info *aip)
Definition: fireballs.cpp:1014
int fireball_free_one()
Definition: fireballs.cpp:571
#define DETAIL_FLAG_FIREBALLS
Definition: systemvars.h:115
SCP_vector< lod_checker > LOD_checker
Definition: weapons.cpp:103
warp hole opening up for departing (Same as warp in for now)
Definition: gamesnd.h:114
SCP_vector< game_snd > Snds
Definition: gamesnd.cpp:19
int orient
Definition: fireballs.h:69
float vm_vec_mag(const vec3d *v)
Definition: vecmat.cpp:325
int num_frames
Definition: fireballs.h:47
#define FIREBALL_LARGE_EXPLOSION
Definition: fireballs.h:24
int Warp_model
Definition: fireballs.cpp:32
vec3d desired_vel
Definition: physics.h:70
GLuint index
Definition: Glext.h:5608
physics_info phys_info
Definition: object.h:157
int Warp_ball_bitmap
Definition: fireballs.cpp:55
ubyte g3_transfer_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:84
int class_type
Definition: ship.h:1167
#define OF_WAS_RENDERED
Definition: object.h:113
void fireball_parse_tbl()
Definition: fireballs.cpp:250
#define MAX_FIREBALL_LOD
Definition: fireballs.cpp:37
Assert(pm!=NULL)
Definition: pstypes.h:88
#define mprintf(args)
Definition: pstypes.h:238
int Num_fireball_types
Definition: fireballs.cpp:50
float side_slip_time_const
Definition: physics.h:44
#define OF_RENDERS
Definition: object.h:103
float time_elapsed
Definition: fireballs.h:72
Definition: 2d.h:95
matrix Eye_matrix
Definition: 3dsetup.cpp:26
char filename[MAX_FILENAME_LEN]
Definition: pstypes.h:408
#define TMAP_HTL_3D_UNLIT
Definition: tmapper.h:63
vec3d max_vel
Definition: physics.h:49
GLclampf f
Definition: Glext.h:7097
#define MAX_OBJECTS
Definition: globals.h:83
int fireball_render_type
Definition: fireballs.h:67
void fireball_init()
Definition: fireballs.cpp:342
#define Assertion(expr, msg,...)
Definition: clang.h:41
float Eye_fov
Definition: 3dsetup.cpp:28
int fireball_used[MAX_FIREBALL_TYPES]
Definition: fireballs.cpp:47
void fireball_play_warphole_close_sound(fireball *fb)
Definition: fireballs.cpp:94
int Knossos_warp_ani_used
Definition: fireballs.cpp:33
#define FIREBALL_EXPLOSION_LARGE1
Definition: fireballs.h:32
hull_check orient
Definition: lua.cpp:5049
int batch_add_bitmap_rotated(int texture, int tmap_flags, vertex *pnt, float angle, float rad, float alpha, float depth)
Definition: grbatch.cpp:793
int warp_open_sound_index
Definition: fireballs.h:74
GLsizeiptr size
Definition: Glext.h:5496
#define Int3()
Definition: pstypes.h:292
vec3d max_rotvel
Definition: physics.h:52
void fireball_set_framenum(int num)
Definition: fireballs.cpp:489
int required_string_either(char *str1, char *str2)
Checks for one of two required strings.
Definition: parselo.cpp:673
vec3d pos
Definition: object.h:152
#define MAX_FIREBALL_TYPES
Definition: fireballs.h:35
int flags
Definition: fireballs.h:70
char filename[MAX_FILENAME_LEN]
Definition: fireballs.h:45
int warp_close_sound_index
Definition: fireballs.h:75
int bm_load_animation(const char *real_filename, int *nframes, int *fps, int *keyframe, int can_drop_frames, int dir_type)
Loads a bitmap sequance so we can draw with it.
Definition: bmpman.cpp:1420
#define CLAMP(x, min, max)
Definition: pstypes.h:488
#define FBF_WARP_3D
Definition: fireballs.h:61
#define SND_PRIORITY_DOUBLE_INSTANCE
Definition: sound.h:28
void fireballs_page_in()
Definition: fireballs.cpp:945
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
int fireball_is_warp(object *obj)
Definition: fireballs.cpp:601
int instance
Definition: object.h:150
#define FIREBALL_MEDIUM_EXPLOSION
Definition: fireballs.h:23
#define MAX_FIREBALLS
Definition: fireballs.cpp:39
int Cmdline_nohtl
Definition: cmdline.cpp:438
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
#define NUM_DEFAULT_FIREBALLS
Definition: fireballs.h:36
#define SIF_BIG_SHIP
Definition: ship.h:944
struct matrix::@228::@230 vec
GLboolean GLboolean g
Definition: Glext.h:5781
void vm_vec_scale(vec3d *dest, float s)
Definition: vecmat.cpp:248
detail_levels Detail
Definition: systemvars.cpp:478
float rotdamp
Definition: physics.h:43
GLclampf GLclampf blue
Definition: Glext.h:5177
int fireball_ship_explosion_type(ship_info *sip)
Definition: fireballs.cpp:993
int cf_exists_full(const char *filename, int dir_type)
Definition: cfile.cpp:527
int obj_create(ubyte type, int parent_obj, int instance, matrix *orient, vec3d *pos, float radius, uint flags)
Definition: object.cpp:467
void fireball_get_color(int idx, float *red, float *green, float *blue)
Definition: fireballs.cpp:972
void g3_set_view_matrix(const vec3d *view_pos, const matrix *view_matrix, float zoom)
Definition: 3dsetup.cpp:152
char * filename
float speed
Definition: physics.h:79
int snd_play_3d(game_snd *gs, vec3d *source_pos, vec3d *listen_pos, float radius, vec3d *source_vel, int looping, float vol_scale, int priority, vec3d *sound_fvec, float range_factor, int force, bool is_ambient)
Definition: sound.cpp:594
void stuff_string(char *outstr, int type, int len, char *terminators)
Definition: parselo.cpp:1189
#define w(p)
Definition: modelsinc.h:68
#define CF_TYPE_TABLES
Definition: cfile.h:50
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
void warpin_render(object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, int warp_3d=0)
void warpin_queue_render(draw_list *scene, object *obj, matrix *orient, vec3d *pos, int texture_bitmap_num, float radius, float life_percent, float max_radius, int warp_3d)
float total_time
Definition: fireballs.h:73
int Num_objects
Definition: object.cpp:68
ubyte g3_rotate_vertex(vertex *dest, const vec3d *src)
Definition: 3dmath.cpp:97
int override
Definition: pstypes.h:410
int hardware_textures
Definition: systemvars.h:169
int required_string(const char *pstr)
Definition: parselo.cpp:468
int optional_string(const char *pstr)
Definition: parselo.cpp:539
float fireball_lifeleft(object *obj)
Definition: fireballs.cpp:669
#define MONITOR(function_name)
Definition: pstypes.h:454
float fireball_lifeleft_percent(object *obj)
Definition: fireballs.cpp:686
fireball_lod lod[4]
Definition: fireballs.h:54
int model_load(char *filename, int n_subsystems, model_subsystem *subsystems, int ferror=1, int duplicate=0)
Definition: modelread.cpp:2573
void read_file_text(const char *filename, int mode, char *processed_text, char *raw_text)
Definition: parselo.cpp:1995
bool Parsing_modular_table
Definition: parselo.cpp:34
int idx
Definition: multiui.cpp:761
#define FIREBALL_WARP
Definition: fireballs.h:29
GLdouble GLdouble t
Definition: Glext.h:5329
GLclampf green
Definition: Glext.h:5177
warp hole opening up for arriving
Definition: gamesnd.h:113
float exp_color[3]
Definition: fireballs.h:53
GLint GLint GLint GLint GLint x
Definition: Glext.h:5182
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
GLclampd n
Definition: Glext.h:7286
#define MONITOR_INC(function_name, inc)
Definition: pstypes.h:457
int fireball_is_perishable(object *obj)
Definition: fireballs.cpp:540
#define vm_vec_zero(v)
Definition: vecmat.h:37
void fireball_play_warphole_open_sound(int ship_class, fireball *fb)
Definition: fireballs.cpp:62
#define OBJ_INDEX(objp)
Definition: object.h:235
int g3_get_bitmap_dims(int bitmap, vertex *pos, float radius, int *x, int *y, int *w, int *h, int *size)
Definition: 3ddraw.cpp:740
void fireball_load_data()
Definition: fireballs.cpp:313
matrix orient
Definition: object.h:153
#define NOX(s)
Definition: pstypes.h:473
#define WARPHOLE_GROW_TIME
Definition: fireballs.cpp:35
char lod
Definition: fireballs.h:71
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
void fireball_render(object *obj, draw_list *scene)
Definition: fireballs.cpp:1055
GLbitfield flags
Definition: Glext.h:6722
#define SIF_HUGE_SHIP
Definition: ship.h:945
typedef void(APIENTRY *PFNGLARRAYELEMENTEXTPROC)(GLint i)
void reset_parse(char *text)
Definition: parselo.cpp:3305
int fireballs_inited
Definition: fireballs.cpp:52
vec3d vel
Definition: physics.h:77
vec3d Eye_position
Definition: 3dsetup.cpp:27
int bm_load(const char *real_filename)
Loads a bitmap so we can draw with it later.
Definition: bmpman.cpp:1119
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
void stuff_int(int *i)
Definition: parselo.cpp:2372
__inline void gr_fog_set(int fog_mode, int r, int g, int b, float fog_near=-1.0f, float fog_far=-1.0f)
Definition: 2d.h:833
uint Game_detail_flags
Definition: systemvars.cpp:52
#define CC_BEHIND
Definition: 3d.h:31
void fireball_close()
Definition: fireballs.cpp:937
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
GLuint GLuint num
Definition: Glext.h:9089
void obj_delete(int objnum)
Definition: object.cpp:522
float frame_time
Definition: multi.cpp:1426
float vm_vec_dist_quick(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:417
void fireball_delete(object *obj)
Definition: fireballs.cpp:458
SCP_vector< int > explosion_bitmap_anims
Definition: asteroid.h:74
int current_bitmap
Definition: fireballs.h:68
#define fl2i(fl)
Definition: floating.h:33
void fireball_maybe_play_warp_close_sound(fireball *fb)
Definition: fireballs.cpp:619
void bm_page_in_texture(int bitmapnum, int nframes)
Marks a texture as being used for this level.
Definition: bmpman.cpp:2462
int batch_add_bitmap(int texture, int tmap_flags, vertex *pnt, int orient, float rad, float alpha, float depth)
Definition: grbatch.cpp:724
#define g3_end_frame()
Definition: 3d.h:49
void parse_fireball_tbl(const char *filename)
Definition: fireballs.cpp:159
fireball Fireballs[MAX_FIREBALLS]
Definition: fireballs.cpp:43
#define FBF_WARP_CLOSE_SOUND_PLAYED
Definition: fireballs.h:58
#define FBF_WARP_CRUISER_SIZE
Definition: fireballs.h:60
#define OF_PHYSICS
Definition: object.h:105
GLfloat GLfloat p
Definition: Glext.h:8373
#define MAX_WARP_LOD
Definition: fireballs.cpp:41
capital warp hole closing
Definition: gamesnd.h:138
#define F_NAME
Definition: parselo.h:34
int num_lods
Definition: pstypes.h:409
SCP_vector< ship_info > Ship_info
Definition: ship.cpp:164
#define LOCATION
Definition: pstypes.h:245
#define TMAP_FLAG_TEXTURED
Definition: tmapper.h:36
float fireball_wormhole_intensity(object *obj)
Definition: fireballs.cpp:1031
#define OF_SHOULD_BE_DEAD
Definition: object.h:106
void fireball_render_DEPRECATED(object *obj)
Definition: fireballs.cpp:377
#define PI
Definition: pstypes.h:303
hull_check pos
Definition: lua.cpp:5050
GLsizei GLsizei GLuint * obj
Definition: Glext.h:5619
int Num_fireballs
Definition: fireballs.cpp:49
#define i2fl(i)
Definition: floating.h:32
int Warp_glow_bitmap
Definition: fireballs.cpp:54
fireball_info Fireball_info[MAX_FIREBALL_TYPES]
Definition: fireballs.cpp:45
int parse_modular_table(const char *name_check, void(*parse_callback)(const char *filename), int path_type, int sort_type)
Definition: parselo.cpp:4205
#define FIREBALL_KNOSSOS
Definition: fireballs.h:30
void fireball_delete_all()
Definition: fireballs.cpp:476
int temp
Definition: lua.cpp:4996
capital warp hole opening
Definition: gamesnd.h:137
#define FBF_WARP_CAPITAL_SIZE
Definition: fireballs.h:59
#define FIREBALL_ASTEROID
Definition: fireballs.h:31
int G3_count
Definition: 3dsetup.cpp:59
SCP_vector< int > explosion_bitmap_anims
Definition: ship.h:1247
float mass
Definition: physics.h:39
#define FIREBALL_EXPLOSION_MEDIUM
Definition: fireballs.h:28
ubyte codes
Definition: pstypes.h:177
uint flags
Definition: object.h:151
float radius
Definition: object.h:154
mission The_mission
#define FIREBALL_WARP_EFFECT
Definition: fireballs.h:25
GLint lod
Definition: Glext.h:7352
GLclampf GLclampf GLclampf alpha
Definition: Glext.h:5177
int fireball_get_lod(vec3d *pos, fireball_info *fd, float size)
Definition: fireballs.cpp:705
const GLdouble * v
Definition: Glext.h:5322
void gr_init_color(color *c, int r, int g, int b)
Definition: 2d.cpp:1155
matrix vmd_identity_matrix
Definition: vecmat.cpp:28
void fireball_process_post(object *obj, float frame_time)
Definition: fireballs.cpp:643
#define CF_TYPE_MODELS
Definition: cfile.h:49
#define fl(p)
Definition: modelsinc.h:71
int myrand()
Definition: systemvars.cpp:102
SCP_vector< ship_type_info > Ship_types
Definition: ship.cpp:168
GLint y
Definition: Gl.h:1505
#define g3_start_frame(zbuffer_flag)
Definition: 3d.h:39
int fireball_create(vec3d *pos, int fireball_type, int render_type, int parent_obj, float size, int reverse, vec3d *velocity, float warp_lifetime, int ship_class, matrix *orient_override, int low_res, int extra_flags, int warp_open_sound, int warp_close_sound)
Definition: fireballs.cpp:788
#define GR_FOGMODE_NONE
Definition: 2d.h:355
#define strcpy_s(...)
Definition: safe_strings.h:67