Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mount.cpp
Go to the documentation of this file.
1 #include "unit_generic.h"
2 #include "missile_generic.h"
3 #include "beam.h"
4 #include "bolt.h"
5 #include "weapon_xml.h"
6 #include "audiolib.h"
7 #include "unit_factory.h"
8 #include "ai/order.h"
9 #include "ai/fireall.h"
10 #include "ai/script.h"
11 #include "ai/navigation.h"
12 #include "ai/flybywire.h"
13 #include "configxml.h"
14 #include "gfx/cockpit_generic.h"
15 #include "force_feedback.h"
16 #include "networking/netclient.h"
17 #include "ai/aggressive.h"
18 #include "lin_time.h"
19 #include "vsfilesystem.h"
20 
21 extern char SERVER;
22 extern bool isMissile( const weapon_info* );
24 {
25  static weapon_info wi( weapon_info::BEAM );
26  functionality = 1;
27  maxfunctionality = 1;
28  type = &wi;
31  ammo = -1;
32  status = UNCHOSEN;
34  sound = -1;
36  static float xyscalestat = XMLSupport::parse_float( vs_config->getVariable( "graphics", "weapon_xyscale", "1" ) );
37 
38  static float zscalestat = XMLSupport::parse_float( vs_config->getVariable( "graphics", "weapon_zscale", "1" ) );
39  xyscale = xyscalestat;
40  zscale = zscalestat;
41  serial = 0;
42 }
43 extern double interpolation_blend_factor;
44 void DestroyMount( Mount *mount )
45 {
46  mount->UnFire();
47  AUDStopPlaying( mount->sound );
48  mount->status = Mount::DESTROYED;
49 }
51 {
52  if (type->type == weapon_info::BEAM) {
53  if (ref.gun) {
54  if ( ref.gun->Ready() )
56  else
57  return getNewTime()*gun->getFramesPerSecond();
58  } else {
59  return 0;
60  }
61  } else {
62  if ( ref.refire < type->Refire() )
63  return getNewTime()*gun->getFramesPerSecond();
64  else
66  }
67 }
68 Mount::Mount( const string &filename, int am, int vol, float xyscale, float zscale, float func, float maxfunc,
69  bool banked ) : bank( banked )
70 {
71  //short fix
72  functionality = func;
73  maxfunctionality = maxfunc;
74  static weapon_info wi( weapon_info::BEAM );
76  static float xyscalestat = XMLSupport::parse_float( vs_config->getVariable( "graphics", "weapon_xyscale", "1" ) );
77 
78  static float zscalestat = XMLSupport::parse_float( vs_config->getVariable( "graphics", "weapon_zscale", "1" ) );
79  if (xyscale == -1)
80  xyscale = xyscalestat;
81  if (zscale == -1)
82  zscale = zscalestat;
83  this->zscale = zscale;
84  this->xyscale = xyscale;
85  serial = 0;
86  ammo = am;
87  sound = -1;
88  type = &wi;
89  this->volume = vol;
90  ref.gun = NULL;
91  status = (UNCHOSEN);
93  weapon_info *temp = getTemplate( filename );
94  if (temp == NULL) {
95  status = UNCHOSEN;
96  time_to_lock = 0;
97  } else {
98  type = temp;
99  status = ACTIVE;
100  time_to_lock = temp->LockTime;
101  if (type->type != weapon_info::BEAM)
102  ref.refire = type->Refire();
103  }
104 }
105 
106 extern bool AdjustMatrix( Matrix &mat, const Vector &velocity, Unit *target, float speed, bool lead, float cone );
107 void AdjustMatrixToTrackTarget( Matrix &mat, const Vector &velocity, Unit *target, float speed, bool lead, float cone )
108 {
109  AdjustMatrix( mat, velocity, target, speed, lead, cone );
110 }
111 
113 {
114  processed = UNFIRED;
115  if (status != ACTIVE || ref.gun == NULL || type->type != weapon_info::BEAM)
116  return;
117  ref.gun->Destabilize();
118 }
119 
120 void Mount::ReplaceMounts( Unit *un, const Mount *other )
121 {
122  int thisvol = volume; //short fix
123  int thissize = size; //short fix
124  float xyscale = this->xyscale;
125  float zscale = this->zscale;
126  bool thisbank = this->bank;
127  Quaternion q = this->GetMountOrientation();
128  Vector v = this->GetMountLocation();
129  *this = *other;
130  this->size = thissize;
131  volume = thisvol;
132  this->SetMountPosition( v );
133  this->SetMountOrientation( q );
134  this->xyscale = xyscale;
135  this->zscale = zscale;
136  this->bank = thisbank;
137  ref.gun = NULL;
138  if (type->type != weapon_info::BEAM)
139  ref.refire = type->Refire();
140  this->ReplaceSound();
141  if (other->ammo == -1)
142  ammo = -1;
143  else if (other->ammo != -1 && ammo == -1)
144  ammo = 0; //zero ammo if other was not zero earlier.
145  un->setAverageGunSpeed();
146 }
147 double Mount::Percentage( const Mount *newammo ) const
148 {
149  float percentage = 1./1024;
150  int thingstocompare = 0;
151  if (status == UNCHOSEN || status == DESTROYED)
152  return percentage;
153  if (newammo->ammo == -1) {
154  if (ammo != -1) {
155  thingstocompare++;
156  } else {
157  if (newammo->type->Range == type->Range && newammo->type->Damage == type->Damage && newammo->type->PhaseDamage
158  == type->PhaseDamage)
159  return 1;
160  if (newammo->type->weapon_name == type->weapon_name)
161  return 1;
162  }
163  } else if (newammo->ammo > 0) {
164  percentage += .25;
165  thingstocompare++;
166  if (ammo > 0) {
167  if (newammo->type->Range == type->Range && newammo->type->Damage == type->Damage && newammo->type->PhaseDamage
168  == type->PhaseDamage)
169  return 1;
170  if (newammo->type->weapon_name == type->weapon_name)
171  return 1;
172  }
173  }
174  if (newammo->type->Range) {
175  if (type->Range > newammo->type->Range) percentage += .25;
176  thingstocompare++;
177  }
178  if (newammo->type->Damage+100*newammo->type->PhaseDamage) {
179  if (type->Damage+100*type->PhaseDamage > newammo->type->Damage+100*newammo->type->PhaseDamage) percentage += .75;
180  thingstocompare++;
181  }
182  if (thingstocompare)
183  return percentage/thingstocompare;
184  else
185  return 1./1024;
186 }
187 extern void GetMadAt( Unit *un, Unit *parent, int numhits = 0 );
188 
189 //bool returns whether to refund the cost of firing
191  const Transformation &Cumulative,
192  const Matrix &m,
193  const Vector &velocity,
194  void *owner,
195  Unit *target,
196  signed char autotrack,
197  float trackingcone,
198  CollideMap::iterator hint[] )
199 {
200  using namespace VSFileSystem;
201  if (time_to_lock > 0)
202  target = NULL;
203  static bool lock_disrupted_by_false_fire =
204  XMLSupport::parse_bool( vs_config->getVariable( "physics", "out_of_arc_fire_disrupts_lock", "false" ) );
205  if (lock_disrupted_by_false_fire)
207  if (processed == FIRED) {
208  if ( type->type == weapon_info::BEAM || isMissile( type ) )
209  //Missiles and beams set to processed.
211  else if (ref.refire < type->Refire() || type->EnergyRate > caller->energy)
212  //Wait until refire has expired and reactor has produced enough energy for the next bolt.
213  return true; //Not ready to refire yet. But don't stop firing.
214 
215  Unit *temp;
216  Transformation tmp( orient, pos.Cast() );
217  tmp.Compose( Cumulative, m );
218  Matrix mat;
219  tmp.to_matrix( mat );
220  mat.p = Transform( mat, ( type->offset+Vector( 0, 0, zscale ) ).Cast() );
221  static bool firemissingautotrackers =
222  XMLSupport::parse_bool( vs_config->getVariable( "physics", "fire_missing_autotrackers", "true" ) );
223  if (autotrack && NULL != target) {
224  if ( !AdjustMatrix( mat, velocity, target, type->Speed, autotrack >= 2, trackingcone ) )
225  if (!firemissingautotrackers)
226  return false;
227  } else if (this->size&weapon_info::AUTOTRACKING) {
228  if (!firemissingautotrackers)
229  return false;
230  }
231  if (type->type != weapon_info::BEAM) {
232  ref.refire = 0;
233  if (ammo > 0)
234  ammo--;
235  } else {
236  static bool reduce_beam_ammo = XMLSupport::parse_bool( vs_config->getVariable( "physics", "reduce_beam_ammo", "0" ) );
237  if (ammo > 0 && reduce_beam_ammo)
238  ammo--;
239  }
241  switch (type->type)
242  {
244  break;
245  case weapon_info::BEAM:
246  if (ref.gun)
247  ref.gun->Init( Transformation( orient, pos.Cast() ), *type, owner, caller );
248  break;
249  case weapon_info::BOLT:
250  case weapon_info::BALL:
251  caller->energy -= type->EnergyRate;
252  hint[Unit::UNIT_BOLT] = Bolt( type, mat, velocity, owner, hint[Unit::UNIT_BOLT] ).location; //FIXME turrets won't work! Velocity
253 
254  break;
256  if (Network == NULL || SERVER) {
257  //Server will create a networked unit, and send it over to the client.
258  static bool match_speed_with_target =
259  XMLSupport::parse_float( vs_config->getVariable( "physics", "match_speed_with_target", "true" ) );
260  string skript = /*string("ai/script/")+*/ type->file+string( ".xai" );
261  VSError err = LookForFile( skript, AiFile );
262  if (err <= Ok) {
264  type->file.c_str(), caller->faction, "", type->Damage, type->PhaseDamage, type->Range/type->Speed,
265  type->Radius, type->RadialSpeed, type->PulseSpeed /*detonation_radius*/, this->serial );
266  if (!match_speed_with_target) {
267  temp->GetComputerData().max_combat_speed = type->Speed+velocity.Magnitude();
268  temp->GetComputerData().max_combat_ab_speed = type->Speed+velocity.Magnitude();
269  }
270  } else {
271  Flightgroup *testfg = caller->getFlightgroup();
272  if (testfg == NULL) {
273  static Flightgroup bas;
274  bas.name = "Base";
275  testfg = &bas;
276  }
277  if (testfg->name == "Base") {
278  int fgsnumber = 0;
279  Flightgroup *fg = Flightgroup::newFlightgroup( "Base_Patrol",
280  type->file,
282  "deafult",
283  1,
284  1,
285  "",
286  "",
287  mission );
288  if (fg != NULL) {
289  fg->target.SetUnit( caller->Target() );
290  fg->directive = "a";
291  fg->name = "Base_Patrol"; //this fixes base-spawned fighters becoming navpoints, which happens sometimes
292 
293  fgsnumber = fg->nr_ships;
294  fg->nr_ships = 1;
295  fg->nr_ships_left = 1;
296  }
298  type->file.c_str(), false, caller->faction, "", fg, fgsnumber, NULL, this->serial );
299  } else {
300  Flightgroup *fg = caller->getFlightgroup();
301  int fgsnumber = 0;
302  if (fg != NULL) {
303  fgsnumber = fg->nr_ships;
304  fg->nr_ships++;
305  fg->nr_ships_left++;
306  }
308  type->file.c_str(), false, caller->faction, "", fg, fgsnumber, NULL, this->serial );
309  }
310  }
311  Vector adder = Vector( mat.r[6], mat.r[7], mat.r[8] )*type->Speed;
312  temp->SetVelocity( caller->GetVelocity()+adder );
313 
314  //Affect the stored mount serial to the new missile
315  temp->SetSerial( this->serial );
316 
317  VSFileSystem::vs_dprintf( 3, "Creating missile with SERIAL ID %d\n", this->serial );
318 
319  this->serial = 0;
320  if (target && target != owner) {
321  temp->Target( target );
322  temp->TargetTurret( target );
323  if (err <= Ok) {
324  temp->EnqueueAI( new AIScript( (type->file+".xai").c_str() ) );
325  temp->EnqueueAI( new Orders::FireAllYouGot );
326  if (match_speed_with_target)
327  temp->GetComputerData().velocity_ref.SetUnit( target );
328  } else {
329  temp->EnqueueAI( new Orders::AggressiveAI( "default.agg.xml" ) );
330  temp->SetTurretAI();
331  temp->TurretFAW(); //turrets are for DEFENSE damnit!
332  temp->owner = caller; //spawned wingmen act as cargo (owned) wingmen, not as hired wingmen
333  float relat;
334  relat = caller->getRelation( target );
335  if (caller->isSubUnit() && relat >= 0) {
336  relat = -1;
337  temp->owner = caller->owner;
338  }
339  if (relat < 0) {
340  int i = 0;
341  while (relat < temp->getRelation( target ) && i++ < 100)
342  GetMadAt( target, temp, 2 );
343  }
344  //pissed off getMadAt(target, 10); // how do I cause an attack here?
345  }
346  } else {
347  temp->EnqueueAI( new Orders::MatchLinearVelocity( Vector( 0, 0, 100000 ), true, false ) );
348  temp->EnqueueAI( new Orders::FireAllYouGot );
349  }
350  temp->SetOwner( (Unit*) owner );
351  temp->Velocity = velocity+adder;
354  _Universe->activeStarSystem()->AddUnit( temp );
356  for (unsigned int locind = 0; locind < Unit::NUM_COLLIDE_MAPS; ++locind)
357  if ( !is_null( temp->location[locind] ) )
358  hint[locind] = temp->location[locind];
359  }
360  break;
361  }
362  static bool use_separate_sound =
363  XMLSupport::parse_bool( vs_config->getVariable( "audio", "high_quality_weapon", "true" ) );
364  static bool ai_use_separate_sound =
365  XMLSupport::parse_bool( vs_config->getVariable( "audio", "ai_high_quality_weapon", "false" ) );
366  static bool ai_sound = XMLSupport::parse_bool( vs_config->getVariable( "audio", "ai_sound", "true" ) );
367  Cockpit *cp;
368  bool ips = ( ( cp = _Universe->isPlayerStarshipVoid( owner ) ) != NULL );
369  double distancesqr = ( tmp.position-AUDListenerLocation() ).MagnitudeSquared();
370  static double maxdistancesqr =
371  XMLSupport::parse_float( vs_config->getVariable( "audio", "max_range_to_hear_weapon_fire",
372  "100000" ) )
373  *XMLSupport::parse_float( vs_config->getVariable( "audio", "max_range_to_hear_weapon_fire", "100000" ) );
374  static float weapon_gain =
375  XMLSupport::parse_float( vs_config->getVariable( "audio", "weapon_gain", ".25" ) );
376  static float exterior_weapon_gain =
377  XMLSupport::parse_float( vs_config->getVariable( "audio", "exterior_weapon_gain", ".35" ) );
378  static float min_weapon_sound_refire =
379  XMLSupport::parse_float( vs_config->getVariable( "audio", "min_weapon_sound_refire", ".2" ) );
380  float curtime = realTime();
381  bool tooquick = ((curtime - last_sound_refire_time) < min_weapon_sound_refire);
382  if (!tooquick) {
383  last_sound_refire_time = curtime;
384 
385  QVector sound_pos;
386  Vector sound_vel;
387  float sound_gain;
388 
389  if (ips && cp != NULL && cp->GetView() <= CP_RIGHT) {
390  sound_pos = QVector(0, 0, 0);
391  sound_vel = Vector(0, 0, 0);
392  sound_gain = weapon_gain;
393  } else {
394  sound_pos = tmp.position;
395  sound_vel = velocity;
396  sound_gain = exterior_weapon_gain;
397  }
398 
399  if ( ( ( (!use_separate_sound)
400  || type->type == weapon_info::BEAM )
401  || ( (!ai_use_separate_sound) && !ips ) ) && (isMissile( type ) == false) ) {
402  if ( ai_sound || (ips && type->type == weapon_info::BEAM) ) {
403  if ( !AUDIsPlaying( sound ) ) {
404  AUDPlay( sound, sound_pos, sound_vel, sound_gain );
405  } else {
406  if (distancesqr < maxdistancesqr) {
407  if (type->type == weapon_info::BEAM) {
408  // Beams don't re-start, they keep playing
409  AUDAdjustSound( sound, sound_pos, sound_vel );
410  AUDSoundGain( sound, sound_gain );
411  } else {
412  // Other kinds of weapons just re-play the sound
414  AUDPlay( sound, sound_pos, sound_vel, sound_gain );
415  }
416  } else {
418  }
419  }
420  }
421  } else if ( (ai_sound || ips) && distancesqr < maxdistancesqr ) {
422  int snd = AUDCreateSound( sound, false );
423  AUDPlay( sound, sound_pos, sound_vel, sound_gain );
424  AUDDeleteSound( snd );
425  }
426  }
427  return true;
428  }
429  return true;
430 }
431 bool Mount::NextMountCloser( Mount *nextmount, Unit *firer )
432 {
433  Unit *target;
434  if ( nextmount && ( target = firer->Target() ) ) {
435  Matrix mat;
436  nextmount->orient.to_matrix( mat );
437  Vector nextR = mat.getR();
438  this->orient.to_matrix( mat );
439  Vector diff = firer->LocalCoordinates( target );
440  Vector nextmountnorm = diff-nextmount->pos;
441  nextmountnorm.Normalize();
442  Vector thismountnorm = diff-this->pos;
443  thismountnorm.Normalize();
444  return nextR.Dot( nextmountnorm ) > mat.getR().Dot( thismountnorm );
445  }
446  return false;
447 }
448 bool Mount::Fire( Unit *firer, void *owner, bool Missile, bool listen_to_owner )
449 {
450  if (ammo == 0)
451  processed = UNFIRED;
452  if (processed == FIRED || status != ACTIVE || ( Missile != ( isMissile( type ) ) ) || ammo == 0)
453  return false;
454  if (type->type == weapon_info::BEAM) {
455  bool fireit = ref.gun == NULL;
456  if (!fireit)
457  fireit = ref.gun->Ready();
458  else
459  ref.gun = new Beam( Transformation( orient, pos.Cast() ), *type, owner, firer, sound );
460  if (fireit) {
461  ref.gun->ListenToOwner( listen_to_owner );
462  processed = FIRED;
463  }
464  return true;
465  } else if ( ref.refire >= type->Refire() ) {
466  processed = FIRED;
467  if ( owner == _Universe->AccessCockpit()->GetParent() )
469  ;
470 
471  return true;
472  }
473  return false;
474 }
476 {
477  //Stop Playing SOund?? No, that's done in the beam, must not be aligned
478  if (processed == UNFIRED)
479  if ( AUDIsPlaying( sound ) )
481 }
482 
484 {
485  sound = AUDCreateSound( sound, false ); //copy constructor basically
486 }
487