Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Drive.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: Drive.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Weapon class
13 */
14 
15 #include "MemDebug.h"
16 #include "Drive.h"
17 #include "Power.h"
18 #include "Ship.h"
19 #include "Sim.h"
20 #include "DriveSprite.h"
21 #include "CameraDirector.h"
22 #include "AudioConfig.h"
23 
24 #include "Light.h"
25 #include "Bitmap.h"
26 #include "Sound.h"
27 #include "DataLoader.h"
28 #include "Bolt.h"
29 #include "Solid.h"
30 #include "Game.h"
31 
32 // +--------------------------------------------------------------------+
33 
34 static int drive_value[] = {
35  1, 1, 1, 1, 1, 1, 1, 1
36 };
37 
38 static float drive_light[] = {
39  10.0f, 100.0f, 5.0f, 1.0e3f, 100.0f, 10.0f, 0.0f, 0.0f
40 };
41 
42 Bitmap* drive_flare_bitmap[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
43 Bitmap* drive_trail_bitmap[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
44 Bitmap* drive_glow_bitmap[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
45 
46 static Sound* sound_resource[3] = { 0, 0, 0 };
47 
48 #define CLAMP(x, a, b) if (x < (a)) x = (a); else if (x > (b)) x = (b);
49 
50 // +----------------------------------------------------------------------+
51 
52 DrivePort::DrivePort(const Point& l, float s)
53 : loc(l), flare(0), trail(0), scale(s)
54 { }
55 
57 {
60 }
61 
62 // +----------------------------------------------------------------------+
63 
64 Drive::Drive(SUBTYPE drive_type, float max_thrust, float max_aug, bool show)
65 : System(DRIVE, drive_type, "Drive", drive_value[drive_type],
66 max_thrust*2, max_thrust*2, max_thrust*2),
67 thrust(max_thrust), augmenter(max_aug), scale(0.0f),
68 throttle(0.0f), augmenter_throttle(0.0f), intensity(0.0f),
69 sound(0), burner_sound(0), show_trail(show)
70 {
72 
73  switch (drive_type) {
74  default:
75  case PLASMA: name = Game::GetText("sys.drive.plasma"); break;
76  case FUSION: name = Game::GetText("sys.drive.fusion"); break;
77  case GREEN: name = Game::GetText("sys.drive.green"); break;
78  case RED: name = Game::GetText("sys.drive.red"); break;
79  case BLUE: name = Game::GetText("sys.drive.blue"); break;
80  case YELLOW: name = Game::GetText("sys.drive.yellow"); break;
81  case STEALTH: name = Game::GetText("sys.drive.stealth"); break;
82  }
83 
84  abrv = Game::GetText("sys.drive.abrv");
85 
86  emcon_power[0] = 0;
87  emcon_power[1] = 50;
88  emcon_power[2] = 100;
89 }
90 
91 // +----------------------------------------------------------------------+
92 
94 : System(d), thrust(d.thrust), augmenter(d.augmenter), scale(d.scale),
95 throttle(0.0f), augmenter_throttle(0.0f), intensity(0.0f),
96 sound(0), burner_sound(0), show_trail(d.show_trail)
97 {
99 
100  Mount(d);
101 
102  if (subtype != Drive::STEALTH) {
103  for (int i = 0; i < d.ports.size(); i++) {
104  DrivePort* p = d.ports[i];
105  CreatePort(p->loc, p->scale);
106  }
107  }
108 }
109 
110 // +--------------------------------------------------------------------+
111 
113 {
114  if (sound) {
115  sound->Stop();
116  sound->Release();
117  sound = 0;
118  }
119 
120  if (burner_sound) {
121  burner_sound->Stop();
123  burner_sound = 0;
124  }
125 
126  ports.destroy();
127 }
128 
129 // +--------------------------------------------------------------------+
130 
131 void
133 {
134  static int initialized = 0;
135  if (initialized) return;
136 
137  DataLoader* loader = DataLoader::GetLoader();
138  loader->SetDataPath("Drive/");
139  loader->LoadTexture("Drive0.pcx", drive_flare_bitmap[0], Bitmap::BMP_TRANSLUCENT);
140  loader->LoadTexture("Drive1.pcx", drive_flare_bitmap[1], Bitmap::BMP_TRANSLUCENT);
141  loader->LoadTexture("Drive2.pcx", drive_flare_bitmap[2], Bitmap::BMP_TRANSLUCENT);
142  loader->LoadTexture("Drive3.pcx", drive_flare_bitmap[3], Bitmap::BMP_TRANSLUCENT);
143  loader->LoadTexture("Drive4.pcx", drive_flare_bitmap[4], Bitmap::BMP_TRANSLUCENT);
144  loader->LoadTexture("Drive5.pcx", drive_flare_bitmap[5], Bitmap::BMP_TRANSLUCENT);
145 
146  loader->LoadTexture("Trail0.pcx", drive_trail_bitmap[0], Bitmap::BMP_TRANSLUCENT);
147  loader->LoadTexture("Trail1.pcx", drive_trail_bitmap[1], Bitmap::BMP_TRANSLUCENT);
148  loader->LoadTexture("Trail2.pcx", drive_trail_bitmap[2], Bitmap::BMP_TRANSLUCENT);
149  loader->LoadTexture("Trail3.pcx", drive_trail_bitmap[3], Bitmap::BMP_TRANSLUCENT);
150  loader->LoadTexture("Trail4.pcx", drive_trail_bitmap[4], Bitmap::BMP_TRANSLUCENT);
151  loader->LoadTexture("Trail5.pcx", drive_trail_bitmap[5], Bitmap::BMP_TRANSLUCENT);
152 
153  loader->LoadTexture("Glow0.pcx", drive_glow_bitmap[0], Bitmap::BMP_TRANSLUCENT);
154  loader->LoadTexture("Glow1.pcx", drive_glow_bitmap[1], Bitmap::BMP_TRANSLUCENT);
155  loader->LoadTexture("Glow2.pcx", drive_glow_bitmap[2], Bitmap::BMP_TRANSLUCENT);
156  loader->LoadTexture("Glow3.pcx", drive_glow_bitmap[3], Bitmap::BMP_TRANSLUCENT);
157  loader->LoadTexture("Glow4.pcx", drive_glow_bitmap[4], Bitmap::BMP_TRANSLUCENT);
158  loader->LoadTexture("Glow5.pcx", drive_glow_bitmap[5], Bitmap::BMP_TRANSLUCENT);
159 
160  const int SOUND_FLAGS = Sound::LOCALIZED |
161  Sound::LOC_3D |
162  Sound::LOOP |
164 
165  loader->SetDataPath("Sounds/");
166  loader->LoadSound("engine.wav", sound_resource[0], SOUND_FLAGS);
167  loader->LoadSound("burner2.wav", sound_resource[1], SOUND_FLAGS);
168  loader->LoadSound("rumble.wav", sound_resource[2], SOUND_FLAGS);
169  loader->SetDataPath(0);
170 
171  if (sound_resource[0])
172  sound_resource[0]->SetMaxDistance(30.0e3f);
173 
174  if (sound_resource[1])
175  sound_resource[1]->SetMaxDistance(30.0e3f);
176 
177  if (sound_resource[2])
178  sound_resource[2]->SetMaxDistance(50.0e3f);
179 
180  initialized = 1;
181 }
182 
183 // +--------------------------------------------------------------------+
184 
185 void
187 {
188  for (int i = 0; i < 3; i++) {
189  delete sound_resource[i];
190  sound_resource[i] = 0;
191  }
192 }
193 
194 // +--------------------------------------------------------------------+
195 
196 void
198 {
199 }
200 
201 // +--------------------------------------------------------------------+
202 
203 void
204 Drive::AddPort(const Point& loc, float flare_scale)
205 {
206  if (flare_scale == 0) flare_scale = scale;
207  DrivePort* port = new(__FILE__,__LINE__) DrivePort(loc, flare_scale);
208  ports.append(port);
209 }
210 
211 // +--------------------------------------------------------------------+
212 
213 void
214 Drive::CreatePort(const Point& loc, float flare_scale)
215 {
216  Bitmap* flare_bmp = drive_flare_bitmap[subtype];
217  Bitmap* trail_bmp = drive_trail_bitmap[subtype];
218  Bitmap* glow_bmp = 0;
219 
220  if (flare_scale <= 0)
221  flare_scale = scale;
222 
223  if (augmenter <= 0)
224  glow_bmp = drive_glow_bitmap[subtype];
225 
226  if (subtype != Drive::STEALTH && flare_scale > 0) {
227  DrivePort* port = new(__FILE__,__LINE__) DrivePort(loc, flare_scale);
228 
229  if (flare_bmp) {
230  DriveSprite* flare_rep = new(__FILE__,__LINE__) DriveSprite(flare_bmp, glow_bmp);
231  flare_rep->Scale(flare_scale * 1.5);
232  flare_rep->SetShade(0);
233  port->flare = flare_rep;
234  }
235 
236  if (trail_bmp && show_trail) {
237  Bolt* trail_rep = new(__FILE__,__LINE__) Bolt(flare_scale * 30, flare_scale * 8, trail_bmp, true);
238  port->trail = trail_rep;
239  }
240 
241  ports.append(port);
242  }
243 }
244 
245 // +--------------------------------------------------------------------+
246 
247 void
249 {
250  System::Orient(rep);
251 
252  const Matrix& orientation = rep->Cam().Orientation();
253  Point ship_loc = rep->Location();
254 
255  for (int i = 0; i < ports.size(); i++) {
256  DrivePort* p = ports[i];
257 
258  Point projector = (p->loc * orientation) + ship_loc;
259 
260  if (p->flare) {
261  p->flare->MoveTo(projector);
262  p->flare->SetFront(rep->Cam().vpn() * -10 * p->scale);
263  }
264 
265  if (p->trail) {
266  if (intensity > 0.5) {
267  double len = -60 * p->scale * intensity;
268 
269  if (augmenter > 0 && augmenter_throttle > 0)
270  len += len * augmenter_throttle;
271 
272  p->trail->Show();
273  p->trail->SetEndPoints(projector, projector + rep->Cam().vpn() * len);
274  }
275  else {
276  p->trail->Hide();
277  }
278  }
279  }
280 }
281 
282 // +--------------------------------------------------------------------+
283 
284 static double drive_seconds=0;
285 
286 void
287 Drive::SetThrottle(double t, bool aug)
288 {
289  double spool = 1.2 * drive_seconds;
290  double throttle_request = t / 100;
291 
292  if (throttle < throttle_request) {
293  if (throttle_request-throttle < spool) {
294  throttle = (float) throttle_request;
295  }
296  else {
297  throttle += (float) spool;
298  }
299  }
300 
301  else if (throttle > throttle_request) {
302  if (throttle - throttle_request < spool) {
303  throttle = (float) throttle_request;
304  }
305  else {
306  throttle -= (float) spool;
307  }
308  }
309 
310  if (throttle < 0.5)
311  aug = false;
312 
313  if (aug && augmenter_throttle < 1) {
314  augmenter_throttle += (float) spool;
315 
316  if (augmenter_throttle > 1)
317  augmenter_throttle = 1.0f;
318  }
319  else if (!aug && augmenter_throttle > 0) {
320  augmenter_throttle -= (float) spool;
321 
322  if (augmenter_throttle < 0)
323  augmenter_throttle = 0.0f;
324  }
325 }
326 
327 // +----------------------------------------------------------------------+
328 
329 double
330 Drive::GetRequest(double seconds) const
331 {
332  if (!power_on) return 0;
333 
334  double t_factor = max(throttle + 0.5 * augmenter_throttle, 0.3);
335 
336  return t_factor * power_level * sink_rate * seconds;
337 }
338 
339 bool
341 {
342  return augmenter > 0 &&
343  augmenter_throttle > 0.05 &&
344  IsPowerOn() &&
345  status > CRITICAL;
346 }
347 
348 // +--------------------------------------------------------------------+
349 
350 int
352 {
353  return ports.size();
354 }
355 
357 Drive::GetFlare(int port) const
358 {
359  if (port >= 0 && port < ports.size()) {
360  return ports[port]->flare;
361  }
362 
363  return 0;
364 }
365 
366 Bolt*
367 Drive::GetTrail(int port) const
368 {
369  if (port >= 0 && port < ports.size()) {
370  return ports[port]->trail;
371  }
372 
373  return 0;
374 }
375 
376 // +--------------------------------------------------------------------+
377 
378 float
379 Drive::Thrust(double seconds)
380 {
381  drive_seconds = seconds;
382 
383  float eff = (energy/capacity) * availability * 100.0f;
384  float output = throttle * thrust * eff;
385  bool aug_on = IsAugmenterOn();
386 
387  if (aug_on) {
388  output += augmenter * augmenter_throttle * eff;
389 
390  // augmenter burns extra fuel:
392  reac->SetCapacity(reac->GetCapacity() - (0.1 * drive_seconds));
393  }
394 
395  energy = 0.0f;
396 
397  if (output < 0 || GetPowerLevel() < 0.01)
398  output = 0.0f;
399 
400  int vol = -10000;
401  int vol_aug = -10000;
402  double fraction = output / thrust;
403 
404  for (int i = 0; i < ports.size(); i++) {
405  DrivePort* p = ports[i];
406 
407  if (p->flare) {
408  if (i == 0) {
409  if (fraction > 0)
410  intensity += (float) seconds;
411  else
412  intensity -= (float) seconds;
413 
414  // capture volume based on actual output:
415  CLAMP(intensity, 0.0f, 1.0f);
416 
417  if (intensity > 0.25) {
418  vol = (int) ((intensity - 1.0) * 10000.0);
419  CLAMP(vol, -10000, -1500);
420 
421  if (aug_on && intensity > 0.5) {
422  vol_aug = (int) ((5 * augmenter_throttle - 1.0) * 10000.0);
423  CLAMP(vol_aug, -10000, -1000);
424  }
425  }
426  }
427 
428  p->flare->SetShade(intensity);
429  }
430 
431  if (p->trail) {
432  p->trail->SetShade(intensity);
433  }
434  }
435 
437 
438  // no sound when paused!
439  if (!Game::Paused() && subtype != STEALTH && cam_dir && cam_dir->GetCamera()) {
440  if (ship && ship->GetRegion() == Sim::GetSim()->GetActiveRegion()) {
441  if (!sound) {
442  int sound_index = 0;
443  if (thrust > 100)
444  sound_index = 2;
445 
446  if (sound_resource[sound_index])
447  sound = sound_resource[sound_index]->Duplicate();
448  }
449 
450  if (aug_on && !burner_sound) {
451  if (sound_resource[1])
452  burner_sound = sound_resource[1]->Duplicate();
453  }
454 
455  Point cam_loc = cam_dir->GetCamera()->Pos();
456  double dist = (ship->Location() - cam_loc).length();
457 
458  if (sound && dist < sound->GetMaxDistance()) {
459  long max_vol = AudioConfig::EfxVolume();
460 
461  if (vol > max_vol)
462  vol = max_vol;
463 
464  if (sound) {
466  sound->SetVolume(vol);
467  sound->Play();
468  }
469 
470  if (burner_sound) {
471  if (vol_aug > max_vol)
472  vol_aug = max_vol;
473 
475  burner_sound->SetVolume(vol_aug);
476  burner_sound->Play();
477  }
478  }
479  else {
480  if (sound && sound->IsPlaying())
481  sound->Stop();
482 
484  burner_sound->Stop();
485  }
486  }
487  else {
488  if (sound && sound->IsPlaying())
489  sound->Stop();
490 
492  burner_sound->Stop();
493  }
494  }
495 
496  return output;
497 }