Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Explosion.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: Explos.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Explosion Sprite animation class
13 */
14 
15 #include "MemDebug.h"
16 #include "Explosion.h"
17 #include "QuantumFlash.h"
18 #include "Particles.h"
19 #include "Ship.h"
20 #include "Sim.h"
21 #include "CameraDirector.h"
22 #include "AudioConfig.h"
23 
24 #include "Light.h"
25 #include "Sprite.h"
26 #include "Solid.h"
27 #include "Bitmap.h"
28 #include "DataLoader.h"
29 #include "Game.h"
30 #include "Scene.h"
31 #include "ParseUtil.h"
32 
33 // +--------------------------------------------------------------------+
34 
35 const int MAX_EXPLOSION_TYPES = 32;
36 
37 static float lifetimes[MAX_EXPLOSION_TYPES];
38 static float scales[MAX_EXPLOSION_TYPES];
39 static Bitmap* bitmaps[MAX_EXPLOSION_TYPES];
40 static Bitmap* particle_bitmaps[MAX_EXPLOSION_TYPES];
41 static int part_frames[MAX_EXPLOSION_TYPES];
42 static int lengths[MAX_EXPLOSION_TYPES];
43 static float light_levels[MAX_EXPLOSION_TYPES];
44 static float light_decays[MAX_EXPLOSION_TYPES];
45 static Color light_colors[MAX_EXPLOSION_TYPES];
46 static int num_parts[MAX_EXPLOSION_TYPES];
47 static int part_types[MAX_EXPLOSION_TYPES];
48 static float part_speeds[MAX_EXPLOSION_TYPES];
49 static float part_drags[MAX_EXPLOSION_TYPES];
50 static float part_scales[MAX_EXPLOSION_TYPES];
51 static float part_blooms[MAX_EXPLOSION_TYPES];
52 static float part_rates[MAX_EXPLOSION_TYPES];
53 static float part_decays[MAX_EXPLOSION_TYPES];
54 static bool part_trails[MAX_EXPLOSION_TYPES];
55 static int part_alphas[MAX_EXPLOSION_TYPES];
56 static Sound* sounds[MAX_EXPLOSION_TYPES];
57 static bool recycles[MAX_EXPLOSION_TYPES];
58 
59 // +--------------------------------------------------------------------+
60 
61 Explosion::Explosion(int t, const Vec3& pos, const Vec3& vel,
62 float exp_scale, float part_scale,
63 SimRegion* rgn, SimObject* src)
64 : SimObject("Explosion", t), type(t), particles(0), source(src)
65 {
66  Observe(source);
67 
68  MoveTo(pos);
69  velocity = vel;
70  drag = 0.3f;
71  rep = 0;
72  light = 0;
73  life = 0;
74 
75  if (type == QUANTUM_FLASH) {
76  life = 1.1;
77 
78  QuantumFlash* q = new(__FILE__,__LINE__) QuantumFlash();
79  rep = q;
80 
81  light = new(__FILE__,__LINE__) Light(1e9, 0.66f);
82  light->SetColor(Color(180, 200, 255));
83  }
84 
85  else if (type >= 0 && type < MAX_EXPLOSION_TYPES) {
86  life = lifetimes[type];
87 
88  if (source) {
89  Matrix src_orient = source->Cam().Orientation();
90  src_orient.Transpose();
91  mount_rel = (pos - source->Location()) * src_orient;
92  }
93 
94  if (lengths[type] > 0) {
95  int repeat = (lengths[type] == 1);
96  Sprite* s = new(__FILE__,__LINE__) Sprite(bitmaps[type], lengths[type], repeat);
97  s->Scale(exp_scale * scales[type]);
98  s->SetAngle(PI * rand()/16384.0);
99  s->SetLuminous(true);
100  rep = s;
101  }
102 
103  if (light_levels[type] > 0) {
104  light = new(__FILE__,__LINE__) Light(light_levels[type], light_decays[type]);
105  light->SetColor(light_colors[type]);
106  }
107 
108  if (num_parts[type] > 0) {
109  particles = new(__FILE__,__LINE__) Particles(particle_bitmaps[type],
110  num_parts[type],
111  pos,
112  Vec3(0.0f, 0.0f, 0.0f),
113  part_speeds[type] * part_scale,
114  part_drags[type],
115  part_scales[type] * part_scale,
116  part_blooms[type] * part_scale,
117  part_decays[type],
118  part_rates[type],
119  recycles[type],
120  part_trails[type],
121  (rgn && rgn->IsAirSpace()),
122  part_alphas[type],
123  part_frames[type]);
124  }
125  }
126 
127  if (rep)
128  rep->MoveTo(pos);
129 
130  if (light)
131  light->MoveTo(pos);
132 }
133 
134 // +--------------------------------------------------------------------+
135 
137 {
139 }
140 
141 // +--------------------------------------------------------------------+
142 
143 bool
145 {
146  if (obj == source) {
147  source = 0;
148 
149  if (life < 0 || life > 4)
150  life = 4;
151 
152  if (particles)
154  }
155 
156  return SimObserver::Update(obj);
157 }
158 
159 const char*
161 {
162  static char name[128];
163  if (source)
164  sprintf_s(name, "Explosion(%s)", source->Name());
165  else
166  sprintf_s(name, "Explosion");
167  return name;
168 }
169 
170 // +--------------------------------------------------------------------+
171 
172 void
174 {
175  static int initialized = 0;
176  if (initialized) return;
177 
178  ZeroMemory(lifetimes, sizeof(lifetimes));
179  ZeroMemory(scales, sizeof(scales));
180  ZeroMemory(bitmaps, sizeof(bitmaps));
181  ZeroMemory(particle_bitmaps, sizeof(particle_bitmaps));
182  ZeroMemory(lengths, sizeof(lengths));
183  ZeroMemory(light_levels, sizeof(light_levels));
184  ZeroMemory(light_decays, sizeof(light_decays));
185  ZeroMemory(light_colors, sizeof(light_colors));
186  ZeroMemory(num_parts, sizeof(num_parts));
187  ZeroMemory(part_types, sizeof(part_types));
188  ZeroMemory(part_speeds, sizeof(part_speeds));
189  ZeroMemory(part_drags, sizeof(part_drags));
190  ZeroMemory(part_scales, sizeof(part_scales));
191  ZeroMemory(part_blooms, sizeof(part_blooms));
192  ZeroMemory(part_decays, sizeof(part_decays));
193  ZeroMemory(part_rates, sizeof(part_rates));
194  ZeroMemory(part_trails, sizeof(part_trails));
195  ZeroMemory(part_alphas, sizeof(part_alphas));
196  ZeroMemory(sounds, sizeof(sounds));
197  ZeroMemory(recycles, sizeof(recycles));
198 
199  const char* filename = "Explosions.def";
200  Print("Loading Explosion Defs '%s'\n", filename);
201 
202  // Load Design File:
203  DataLoader* loader = DataLoader::GetLoader();
204  BYTE* block;
205 
206  loader->SetDataPath("Explosions/");
207  int blocklen = loader->LoadBuffer(filename, block, true);
208  Parser parser(new(__FILE__,__LINE__) BlockReader((const char*) block, blocklen));
209  Term* term = parser.ParseTerm();
210 
211  if (!term) {
212  Print("ERROR: could not parse '%s'\n", filename);
213  exit(-3);
214  }
215  else {
216  TermText* file_type = term->isText();
217  if (!file_type || file_type->value() != "EXPLOSION") {
218  Print("ERROR: invalid explosion def file '%s'\n", filename);
219  exit(-4);
220  }
221  }
222 
223  do {
224  delete term;
225 
226  term = parser.ParseTerm();
227 
228  if (term) {
229  TermDef* def = term->isDef();
230  if (def) {
231  if (def->name()->value() == "explosion") {
232 
233  if (!def->term() || !def->term()->isStruct()) {
234  Print("WARNING: explosion structure missing in '%s'\n", filename);
235  }
236  else {
237  TermStruct* val = def->term()->isStruct();
238  int type = -1;
239  char type_name[32];
240  char bitmap[32];
241  char particle_bitmap[32];
242  char sound_file[32];
243  float lifetime = 0.0f;
244  float scale = 1.0f;
245  int length = 0;
246  float light_level = 0.0f;
247  float light_decay = 1.0f;
248  Color light_color;
249  int num_part = 0;
250  int part_type = 0;
251  float part_speed = 0.0f;
252  float part_drag = 1.0f;
253  float part_scale = 1.0f;
254  float part_bloom = 0.0f;
255  float part_decay = 100.0f;
256  float part_rate = 1.0f;
257  bool part_trail = true;
258  bool continuous = false;
259  int part_alpha = 4;
260  int part_nframes = 1;
261  float sound_min_dist = 1.0f;
262  float sound_max_dist = 1.0e5f;
263 
264  type_name[0] = 0;
265  bitmap[0] = 0;
266  particle_bitmap[0] = 0;
267  sound_file[0] = 0;
268 
269  for (int i = 0; i < val->elements()->size(); i++) {
270  TermDef* pdef = val->elements()->at(i)->isDef();
271  if (pdef) {
272 
273  if (pdef->name()->value() == "type") {
274  if (pdef->term()->isText()) {
275  GetDefText(type_name, pdef, filename);
276 
277  const char* names[15] = {
278  "SHIELD_FLASH",
279  "HULL_FLASH",
280  "BEAM_FLASH",
281  "SHOT_BLAST",
282  "HULL_BURST",
283  "HULL_FIRE",
284  "PLASMA_LEAK",
285  "SMOKE_TRAIL",
286  "SMALL_FIRE",
287  "SMALL_EXPLOSION",
288  "LARGE_EXPLOSION",
289  "LARGE_BURST",
290  "NUKE_EXPLOSION",
291  "QUANTUM_FLASH",
292  "HYPER_FLASH"
293  };
294 
295  for (int n = 0; n < 15; n++)
296  if (!_stricmp(type_name, names[n]))
297  type = n + 1;
298  }
299 
300  else if (pdef->term()->isNumber()) {
301  GetDefNumber(type, pdef, filename);
302 
303  if (type < 0 || type >= MAX_EXPLOSION_TYPES) {
304  ::Print("Warning - invalid explosion type %d ignored\n", type);
305  }
306  }
307 
308  else {
309  ::Print("Warning - weird explosion type:\n");
310  pdef->print();
311  }
312  }
313 
314  else if (pdef->name()->value() == "image" ||
315  pdef->name()->value() == "bitmap")
316  GetDefText(bitmap, pdef, filename);
317 
318  else if (pdef->name()->value() == "particles" ||
319  pdef->name()->value() == "particle_bitmap")
320  GetDefText(particle_bitmap, pdef, filename);
321 
322  else if (pdef->name()->value() == "sound")
323  GetDefText(sound_file, pdef, filename);
324 
325  else if (pdef->name()->value() == "lifetime")
326  GetDefNumber(lifetime, pdef, filename);
327 
328  else if (pdef->name()->value() == "scale")
329  GetDefNumber(scale, pdef, filename);
330 
331  else if (pdef->name()->value() == "length")
332  GetDefNumber(length, pdef, filename);
333 
334  else if (pdef->name()->value() == "light_level")
335  GetDefNumber(light_level, pdef, filename);
336 
337  else if (pdef->name()->value() == "light_decay")
338  GetDefNumber(light_decay, pdef, filename);
339 
340  else if (pdef->name()->value() == "light_color")
341  GetDefColor(light_color, pdef, filename);
342 
343  else if (pdef->name()->value() == "num_parts")
344  GetDefNumber(num_part, pdef, filename);
345 
346  else if (pdef->name()->value() == "part_frames")
347  GetDefNumber(part_nframes, pdef, filename);
348 
349  else if (pdef->name()->value() == "part_type")
350  GetDefNumber(part_type, pdef, filename);
351 
352  else if (pdef->name()->value() == "part_speed")
353  GetDefNumber(part_speed, pdef, filename);
354 
355  else if (pdef->name()->value() == "part_drag")
356  GetDefNumber(part_drag, pdef, filename);
357 
358  else if (pdef->name()->value() == "part_scale")
359  GetDefNumber(part_scale, pdef, filename);
360 
361  else if (pdef->name()->value() == "part_bloom")
362  GetDefNumber(part_bloom, pdef, filename);
363 
364  else if (pdef->name()->value() == "part_decay")
365  GetDefNumber(part_decay, pdef, filename);
366 
367  else if (pdef->name()->value() == "part_rate")
368  GetDefNumber(part_rate, pdef, filename);
369 
370  else if (pdef->name()->value() == "part_trail")
371  GetDefBool(part_trail, pdef, filename);
372 
373  else if (pdef->name()->value() == "part_alpha")
374  GetDefNumber(part_alpha, pdef, filename);
375 
376  else if (pdef->name()->value() == "continuous")
377  GetDefBool(continuous, pdef, filename);
378 
379  else if (pdef->name()->value() == "sound_min_dist")
380  GetDefNumber(sound_min_dist, pdef, filename);
381 
382  else if (pdef->name()->value() == "sound_max_dist")
383  GetDefNumber(sound_max_dist, pdef, filename);
384 
385  else {
386  Print("WARNING: parameter '%s' ignored in '%s'\n",
387  pdef->name()->value().data(), filename);
388  }
389  }
390  else {
391  Print("WARNING: term ignored in '%s'\n", filename);
392  val->elements()->at(i)->print();
393  }
394  }
395 
396  if (type >= 0 && type < MAX_EXPLOSION_TYPES) {
397  if (part_alpha > 2)
398  part_alpha = 4;
399 
400  lengths[type] = length;
401  lifetimes[type] = lifetime;
402  scales[type] = scale;
403  light_levels[type] = light_level;
404  light_decays[type] = light_decay;
405  light_colors[type] = light_color;
406  num_parts[type] = num_part;
407  part_types[type] = part_type;
408  part_speeds[type] = part_speed;
409  part_drags[type] = part_drag;
410  part_scales[type] = part_scale;
411  part_blooms[type] = part_bloom;
412  part_frames[type] = part_nframes;
413  part_decays[type] = part_decay;
414  part_rates[type] = part_rate;
415  part_trails[type] = part_trail;
416  part_alphas[type] = part_alpha;
417  recycles[type] = continuous;
418 
419  if (length > 0) {
420  bitmaps[type] = new(__FILE__,__LINE__) Bitmap[length];
421 
422  if (length > 1) {
423  for (int n = 0; n < length; n++) {
424  char img_name[64];
425  sprintf_s(img_name, "%s%02d.pcx", bitmap, n);
426  loader->LoadBitmap(img_name, bitmaps[type][n], Bitmap::BMP_TRANSLUCENT);
427  }
428  }
429 
430  else {
431  loader->LoadBitmap(bitmap, bitmaps[type][0], Bitmap::BMP_TRANSLUCENT);
432  }
433  }
434 
435  if (particle_bitmap[0]) {
436  particle_bitmaps[type] = new(__FILE__,__LINE__) Bitmap[part_nframes];
437 
438  if (part_nframes > 1) {
439  for (int i = 0; i < part_nframes; i++) {
440  char fname[64];
441  sprintf_s(fname, "%s%02d.pcx", particle_bitmap, i);
442  loader->LoadBitmap(fname, particle_bitmaps[type][i], Bitmap::BMP_TRANSLUCENT);
443  particle_bitmaps[type][i].MakeTexture();
444  }
445  }
446 
447  else {
448  loader->LoadBitmap(particle_bitmap, particle_bitmaps[type][0], Bitmap::BMP_TRANSLUCENT);
449  particle_bitmaps[type][0].MakeTexture();
450  }
451  }
452 
453  if (sound_file[0]) {
454  loader->SetDataPath("Sounds/");
455  loader->LoadSound(sound_file, sounds[type], Sound::LOCALIZED | Sound::LOC_3D);
456  loader->SetDataPath("Explosions/");
457 
458  if (sounds[type]) {
459  sounds[type]->SetMinDistance(sound_min_dist);
460  sounds[type]->SetMaxDistance(sound_max_dist);
461  }
462  }
463  }
464  }
465  }
466 
467  else
468  Print("WARNING: unknown definition '%s' in '%s'\n",
469  def->name()->value().data(), filename);
470  }
471  else {
472  Print("WARNING: term ignored in '%s'\n", filename);
473  term->print();
474  }
475  }
476  }
477  while (term);
478 
479  loader->ReleaseBuffer(block);
480  loader->SetDataPath(0);
481  initialized = 1;
482 }
483 
484 // +--------------------------------------------------------------------+
485 
486 void
488 {
489  for (int t = 0; t < MAX_EXPLOSION_TYPES; t++) {
490  if (lengths[t] && bitmaps[t]) {
491  for (int i = 0; i < lengths[t]; i++)
492  bitmaps[t][i].ClearImage();
493  delete [] bitmaps[t];
494  }
495 
496  if (particle_bitmaps[t]) {
497  for (int i = 0; i < part_frames[t]; i++)
498  particle_bitmaps[t][i].ClearImage();
499  delete [] particle_bitmaps[t];
500  }
501 
502  delete sounds[t];
503  }
504 }
505 
506 // +--------------------------------------------------------------------+
507 
508 void
509 Explosion::ExecFrame(double seconds)
510 {
511  if (source) {
512  const Matrix& orientation = source->Cam().Orientation();
513  MoveTo((mount_rel * orientation) + source->Location());
514 
515  if (rep) rep->Show();
516 
517  if (particles) particles->Show();
518 
519  if (source == Sim::GetSim()->GetPlayerShip()) {
520  Ship* ship = (Ship*) source;
522  !ship->IsDying()) {
523  if (rep) rep->Hide();
524  if (particles) particles->Hide();
525  }
526  }
527  }
528 
529  life -= seconds;
530 
531  if (rep) {
532  rep->MoveTo(Location());
533 
534  if (rep->Life() == 0) {
535  rep = 0; // about to be GC'd
536  }
537 
538  else if (rep->IsSprite()) {
539  Sprite* s = (Sprite*) rep;
540  s->SetAngle(s->Angle() + seconds * 0.5);
541  }
542 
543  else if (type == QUANTUM_FLASH) {
544  QuantumFlash* q = (QuantumFlash*) rep;
545  q->SetShade(q->Shade() - seconds);
546  }
547  }
548 
549  if (light) {
550  light->Update();
551 
552  if (light->Life() == 0)
553  light = 0; // about to be GC'd
554  }
555 
556  if (particles) {
558  particles->ExecFrame(seconds);
559  }
560 
561  if (source && source->Life() == 0)
562  life = 0;
563 }
564 
565 // +--------------------------------------------------------------------+
566 
567 void
569 {
570  bool filter = false;
571 
573  if (cam_dir && cam_dir->GetCamera()) {
574  if (Point(cam_dir->GetCamera()->Pos() - Location()).length() < 100)
575  filter = true;
576  }
577 
578  if (rep && !filter)
579  scene.AddGraphic(rep);
580 
581  if (light)
582  scene.AddLight(light);
583 
584  if (particles && !filter)
585  scene.AddGraphic(particles);
586 
587  if (sounds[obj_type]) {
588  Sound* sound = sounds[obj_type]->Duplicate();
589 
590  // fire and forget:
591  if (sound) {
592  sound->SetLocation(Location());
594  sound->Play();
595  }
596  }
597 
598  active = true;
599 }
600 
601 void
603 {
604  SimObject::Deactivate(scene);
605 
606  if (particles)
607  scene.DelGraphic(particles);
608 }
609 
610 // +--------------------------------------------------------------------+
611