Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Shot.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright (C) 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: Shot.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Laser and Missile class
13 */
14 
15 #include "MemDebug.h"
16 #include "Shot.h"
17 #include "Weapon.h"
18 #include "DriveSprite.h"
19 #include "SeekerAI.h"
20 #include "Sim.h"
21 #include "Ship.h"
22 #include "Trail.h"
23 #include "Random.h"
24 #include "AudioConfig.h"
25 #include "TerrainRegion.h"
26 #include "Terrain.h"
27 
28 #include "Game.h"
29 #include "Bolt.h"
30 #include "Sprite.h"
31 #include "Solid.h"
32 #include "Light.h"
33 #include "Bitmap.h"
34 #include "DataLoader.h"
35 #include "Sound.h"
36 
37 // +--------------------------------------------------------------------+
38 
39 Shot::Shot(const Point& pos, const Camera& shot_cam, WeaponDesign* dsn, const Ship* ship)
40 : first_frame(true), owner(ship), flash(0), flare(0), trail(0), sound(0), eta(0),
41 charge(1.0f), design(dsn), offset(1.0e5f), altitude_agl(-1.0e6f), hit_target(false)
42 {
44  type = design->type;
46  beam = design->beam;
48  armed = false;
49 
50  radius = 10.0f;
51 
52  if (primary || design->decoy_type || !design->guided) {
53  straight = true;
54  armed = true;
55  }
56 
57  cam.Clone(shot_cam);
58 
59  life = design->life;
60  velocity = cam.vpn() * (double) design->speed;
61 
62  MoveTo(pos);
63 
64  if (beam)
65  origin = pos + (shot_cam.vpn() * -design->length);
66 
67  switch (design->graphic_type) {
68  case Graphic::BOLT: {
69  Bolt* s = new(__FILE__,__LINE__) Bolt(design->length, design->width, design->shot_img, 1);
70  s->SetDirection(cam.vpn());
71  rep = s;
72  }
73  break;
74 
75  case Graphic::SPRITE: {
76  Sprite* s = 0;
77 
78  if (design->animation)
79  s = new(__FILE__,__LINE__) DriveSprite(design->animation, design->anim_length);
80  else
81  s = new(__FILE__,__LINE__) DriveSprite(design->shot_img);
82 
83  s->Scale((double) design->scale);
84  rep = s;
85  }
86  break;
87 
88  case Graphic::SOLID: {
89  Solid* s = new(__FILE__,__LINE__) Solid;
91  rep = s;
92 
93  radius = rep->Radius();
94  }
95  break;
96  }
97 
98  if (rep)
99  rep->MoveTo(pos);
100 
101  light = 0;
102 
103  if (design->light > 0) {
104  light = new(__FILE__,__LINE__) Light(design->light);
106  }
107 
108  mass = design->mass;
109  drag = design->drag;
110  thrust = 0.0f;
111 
115 
116  SetAngularRates((float) design->roll_rate, (float) design->pitch_rate, (float) design->yaw_rate);
117 
118  if (design->flash_img != 0) {
119  flash = new(__FILE__,__LINE__) Sprite(design->flash_img);
120  flash->Scale((double) design->flash_scale);
121  flash->MoveTo(pos - cam.vpn() * design->length);
122  flash->SetLuminous(true);
123  }
124 
125  if (design->flare_img != 0) {
126  flare = new(__FILE__,__LINE__) DriveSprite(design->flare_img);
127  flare->Scale((double) design->flare_scale);
128  flare->MoveTo(pos);
129  }
130 
131  if (owner) {
132  iff_code = (BYTE) owner->GetIFF();
133  Observe((SimObject*) owner);
134  }
135 
136  sprintf_s(name, "Shot(%s)", design->name.data());
137 }
138 
139 // +--------------------------------------------------------------------+
140 
142 {
146 
147  if (sound) {
148  sound->Stop();
149  sound->Release();
150  }
151 }
152 
153 // +--------------------------------------------------------------------+
154 
155 const char*
157 {
158  return design->name;
159 }
160 
161 // +--------------------------------------------------------------------+
162 
163 void
165 {
166  charge = c;
167 
168  // trim beam life to amount of energy available:
169  if (beam)
171 }
172 
173 void
174 Shot::SetFuse(double seconds)
175 {
176  if (seconds > 0 && !beam)
177  life = seconds;
178 }
179 
180 // +--------------------------------------------------------------------+
181 
182 void
184 {
185  if (dir && !primary) {
186  SeekerAI* seeker = (SeekerAI*) dir;
187  SimObject* old_target = seeker->GetTarget();
188 
189  if (old_target->Type()==SimObject::SIM_SHIP) {
190  Ship* tgt_ship = (Ship*) old_target;
191  tgt_ship->DropThreat(this);
192  }
193  }
194 
195  delete dir;
196  dir = 0;
197 
198  if (target) {
199  SeekerAI* seeker = new(__FILE__,__LINE__) SeekerAI(this);
200  seeker->SetTarget(target, sub);
201  seeker->SetPursuit(design->guided);
202  seeker->SetDelay(1);
203 
204  dir = seeker;
205 
206  if (!primary && target->Type()==SimObject::SIM_SHIP) {
207  Ship* tgt_ship = (Ship*) target;
208  tgt_ship->AddThreat(this);
209  }
210  }
211 }
212 
213 bool
215 {
216  return tgt && (GetTarget() == tgt);
217 }
218 
219 SimObject*
221 {
222  if (dir) {
223  SeekerAI* seeker = (SeekerAI*) dir;
224 
225  if (seeker->GetDelay() <= 0)
226  return seeker->GetTarget();
227  }
228 
229  return 0;
230 }
231 
232 bool
234 {
235  return design && design->flak;
236 }
237 
238 // +--------------------------------------------------------------------+
239 
240 bool
242 {
243  if (o) {
244  if (o->Type() == SIM_SHIP) {
245  Ship* s = (Ship*) o;
246 
247  if (s->IsRogue())
248  return true;
249 
250  if (s->GetIFF() > 0 && s->GetIFF() != GetIFF())
251  return true;
252  }
253 
254  else if (o->Type() == SIM_SHOT || o->Type() == SIM_DRONE) {
255  Shot* s = (Shot*) o;
256 
257  if (s->GetIFF() > 0 && s->GetIFF() != GetIFF())
258  return true;
259  }
260  }
261 
262  return false;
263 }
264 
265 // +--------------------------------------------------------------------+
266 
267 void
268 Shot::ExecFrame(double seconds)
269 {
270  altitude_agl = -1.0e6f;
271 
272  // add random flickering effect:
273  double flicker = 0.75 + (double) rand() / 8e4;
274  if (flicker > 1) flicker = 1;
275 
276  if (flare) {
277  flare->SetShade(flicker);
278  }
279  else if (beam) {
280  Bolt* blob = (Bolt*) rep;
281  blob->SetShade(flicker);
282  offset -= (float) (seconds * 10);
283  }
284 
285  if (Game::Paused())
286  return;
287 
288  if (beam) {
289  if (!first_frame) {
290  if (life > 0) {
291  life -= seconds;
292 
293  if (life < 0)
294  life = 0;
295  }
296  }
297  }
298  else {
299  origin = Location();
300 
301  if (!first_frame)
302  Physical::ExecFrame(seconds);
303  else
305 
306  double len = design->length;
307  if (len < 50) len = 50;
308 
309  if (!trail && life > 0 && design->life - life > 0.2) {
310  if (design->trail.length()) {
311  trail = new(__FILE__,__LINE__) Trail(design->trail_img, design->trail_length);
312 
313  if (design->trail_width > 0)
315 
316  if (design->trail_dim > 0)
318 
319  trail->AddPoint(Location() + Heading() * -100);
320 
321  Scene* scene = 0;
322 
323  if (rep)
324  scene = rep->GetScene();
325 
326  if (scene)
327  scene->AddGraphic(trail);
328  }
329  }
330 
331  if (trail)
332  trail->AddPoint(Location());
333 
334  if (!armed) {
335  SeekerAI* seeker = (SeekerAI*) dir;
336 
337  if (seeker && seeker->GetDelay() <= 0)
338  armed = true;
339  }
340 
341  // handle submunitions:
342  else if (design->det_range > 0 && design->det_count > 0) {
343  if (dir && !primary) {
344  SeekerAI* seeker = (SeekerAI*) dir;
345  SimObject* target = seeker->GetTarget();
346 
347  if (target) {
348  double range = Point(Location() - target->Location()).length();
349 
350  if (range < design->det_range) {
351  life = 0;
352 
353  Sim* sim = Sim::GetSim();
355 
356  if (sim && child_design) {
357  double spread = design->det_spread;
358 
359  Camera aim_cam;
360  aim_cam.Clone(Cam());
361  aim_cam.LookAt(target->Location());
362 
363  for (int i = 0; i < design->det_count; i++) {
364  Shot* child = sim->CreateShot(Location(), aim_cam, child_design,
365  owner, owner->GetRegion());
366 
367  child->SetCharge(child_design->charge);
368 
369  if (child_design->guided)
370  child->SeekTarget(target, seeker->GetSubTarget());
371 
372  if (child_design->beam)
373  child->SetBeamPoints(Location(), target->Location());
374 
375  if (i) aim_cam.LookAt(target->Location());
376  aim_cam.Pitch(Random(-spread, spread));
377  aim_cam.Yaw(Random(-spread, spread));
378  }
379  }
380  }
381  }
382  }
383  }
384 
385  if (flash && !first_frame)
387 
388  if (thrust < design->thrust)
389  thrust += (float) (seconds * 5.0e3);
390  else
391  thrust = design->thrust;
392  }
393 
394  first_frame = 0;
395 
396  if (flare)
397  flare->MoveTo(Location());
398 }
399 
400 // +--------------------------------------------------------------------+
401 
402 void
404 {
405  if (armed && !primary) {
406  armed = false;
407  delete dir;
408  dir = 0;
409  }
410 }
411 
412 void
414 {
415  life = 0;
416 }
417 
418 // +--------------------------------------------------------------------+
419 
420 void
421 Shot::SetBeamPoints(const Point& from, const Point& to)
422 {
423  if (beam) {
424  MoveTo(to);
425  origin = from;
426 
427  if (sound) {
428  sound->SetLocation(from);
429  }
430 
431  if (rep) {
432  Bolt* s = (Bolt*) rep;
433  s->SetEndPoints(from, to);
434 
435  double len = Point(to - from).length() / 500;
436  s->SetTextureOffset(offset, offset + len);
437  }
438  }
439 
440  if (flash) {
441  flash->MoveTo(origin);
442  }
443 }
444 
445 // +--------------------------------------------------------------------+
446 
447 double
449 {
450  return Location().y;
451 }
452 
453 double
455 {
456  if (altitude_agl < -1000) {
457  Shot* pThis = (Shot*) this; // cast-away const
458  Point loc = Location();
459  Terrain* terrain = region->GetTerrain();
460 
461  if (terrain)
462  pThis->altitude_agl = (float) (loc.y - terrain->Height(loc.x, loc.z));
463 
464  else
465  pThis->altitude_agl = (float) loc.y;
466 
467  if (!_finite(altitude_agl)) {
468  pThis->altitude_agl = 0.0f;
469  }
470  }
471 
472  return altitude_agl;
473 }
474 
475 // +--------------------------------------------------------------------+
476 
477 void
479 {
480 }
481 
482 // +--------------------------------------------------------------------+
483 
484 void
486 {
487 }
488 
489 // +--------------------------------------------------------------------+
490 
491 double
493 {
494  double damage = 0;
495 
496  // beam damage based on length:
497  if (beam) {
498  double fade = 1;
499 
500  if (design) {
501  // linear fade with distance:
502  double len = Point(origin - Location()).length();
503 
504  if (len > design->min_range)
505  fade = (design->length - len) / (design->length - design->min_range);
506  }
507 
508  damage = base_damage * charge * fade * Game::FrameTime();
509  }
510 
511  // energy wep damage based on time:
512  else if (primary) {
513  damage = base_damage * charge * life;
514  }
515 
516  // missile damage is constant:
517  else {
518  damage = base_damage * charge;
519  }
520 
521  return damage;
522 }
523 
524 double
526 {
527  if (design)
528  return design->length;
529 
530  return 500;
531 }
532 
533 // +--------------------------------------------------------------------+
534 
535 void
537 {
538  SimObject::Activate(scene);
539 
540  if (trail)
541  scene.AddGraphic(trail);
542 
543  if (flash)
544  scene.AddGraphic(flash);
545 
546  if (flare)
547  scene.AddGraphic(flare);
548 
549  if (first_frame) {
550  if (design->sound_resource) {
552 
553  if (sound) {
554  long max_vol = AudioConfig::EfxVolume();
555  long volume = -1000;
556 
557  if (volume > max_vol)
558  volume = max_vol;
559 
560  if (beam) {
562  sound->SetVolume(volume);
563  sound->Play();
564  }
565  else {
567  sound->SetVolume(volume);
568  sound->Play();
569  sound = 0; // fire and forget:
570  }
571  }
572  }
573  }
574 }
575 
576 // +--------------------------------------------------------------------+
577 
578 void
580 {
581  SimObject::Deactivate(scene);
582 
583  if (trail)
584  scene.DelGraphic(trail);
585 
586  if (flash)
587  scene.DelGraphic(flash);
588 
589  if (flare)
590  scene.DelGraphic(flare);
591 }
592 
593 // +--------------------------------------------------------------------+
594 
595 int
597 {
598  return iff_code;
599 }
600 
601 // +--------------------------------------------------------------------+
602 
603 Color
605 {
606  return Ship::IFFColor(GetIFF());
607 }
608 
609 // +--------------------------------------------------------------------+
610 
611 const char*
613 {
614  return name;
615 }
616 
617 // +--------------------------------------------------------------------+
618 
619 bool
621 {
622  if (obj == (SimObject*) owner)
623  owner = 0;
624 
625  return SimObserver::Update(obj);
626 }