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
unit.cpp
Go to the documentation of this file.
1 /*
2  * Vega Strike
3  * Copyright (C) 2001-2002 Daniel Horn
4  *
5  * http://vegastrike.sourceforge.net/
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 #include "unit.h"
22 #include "vsfilesystem.h"
23 #include "vs_globals.h"
24 #include "file_main.h"
25 #include "gfx/halo.h"
26 #include "gfx/halo_system.h"
27 #include "gfx/quaternion.h"
28 #include "gfx/matrix.h"
29 #include "gfx/technique.h"
30 
31 #include "unit_factory.h"
32 
33 #include "gfx/sprite.h"
34 #include "lin_time.h"
35 
36 #include "gfx/vsbox.h"
37 #include "bolt.h"
38 #include "gfx/lerp.h"
39 #include "audiolib.h"
40 #include "gfx/cockpit.h"
41 #include "config_xml.h"
42 #include "images.h"
43 #include "main_loop.h"
44 #include "script/mission.h"
45 #include "script/flightgroup.h"
46 #include "savegame.h"
47 #include "xml_serializer.h"
48 #include "python/python_class.h"
49 #include "cmd/ai/missionscript.h"
50 #include "gfx/particle.h"
51 #include "cmd/ai/aggressive.h"
52 #include "cmd/base.h"
53 #include "gfx/point_to_cam.h"
54 
55 #include "base_util.h"
56 #include "unit_jump.h"
57 #include "unit_customize.h"
58 #include "unit_damage.h"
59 #include "unit_physics.h"
60 #include "unit_click.h"
61 
62 using std::vector;
63 using std::string;
64 using std::map;
65 
66 //if the PQR of the unit may be variable...for radius size computation
67 //#define VARIABLE_LENGTH_PQR
68 
69 //#define DESTRUCTDEBUG
70 #include "beam.h"
71 #include "python/init.h"
72 #include "unit_const_cache.h"
73 extern double interpolation_blend_factor;
75 extern bool cam_setup_phase;
76 
77 /**** MOVED FROM BASE_INTERFACE.CPP ****/
78 extern string getCargoUnitName( const char *name );
79 
80 template < class UnitType >GameUnit< UnitType >::GameUnit( int ) : sparkle_accum( 0 )
81  , phalos( new HaloSystem() )
82 {
83  this->Unit::Init();
84 }
85 
86 template < class UnitType >GameUnit< UnitType >::GameUnit( std::vector< Mesh* > &meshes, bool SubU, int fact ) :
87  UnitType( meshes, SubU, fact )
88  , sparkle_accum( 0 )
89  , phalos( new HaloSystem() )
90 {}
91 
92 template < class UnitType >GameUnit< UnitType >::GameUnit( const char *filename,
93  bool SubU,
94  int faction,
95  std::string unitModifications,
96  Flightgroup *flightgrp,
97  int fg_subnumber,
98  string *netxml ) : sparkle_accum( 0 )
99  , phalos( new HaloSystem() )
100 {
101  Unit::Init( filename, SubU, faction, unitModifications, flightgrp, fg_subnumber, netxml );
102 }
103 
104 template < class UnitType >GameUnit< UnitType >::~GameUnit()
105 {
106  for (unsigned int meshcount = 0; meshcount < this->meshdata.size(); meshcount++)
107  if (this->meshdata[meshcount])
108  delete this->meshdata[meshcount];
109  this->meshdata.clear();
110  //delete phalos;
111 }
112 
113 template < class UnitType >
115 {
116  return ( (int) this->meshdata.size() )-1;
117 }
118 
119 template < class UnitType >
121 {
122  string basename = ( ::getCargoUnitName( baseun->getFullname().c_str() ) );
123  if (baseun->isUnit() != PLANETPTR)
124  basename = baseun->name;
125  BaseUtil::LoadBaseInterfaceAtDock( basename, baseun, this );
126 }
127 
128 #define PARANOIA .4
129 
130 inline static float perspectiveFactor( float d )
131 {
132  if (d > 0)
134  else
135  return 1.0f;
136 }
137 
138 template < class UnitType >
140 {
141  return this->pImage->pHudImage;
142 }
143 
144 template < class UnitType >
145 void GameUnit< UnitType >::addHalo( const char *filename,
146  const QVector &loc,
147  const Vector &size,
148  const GFXColor &col,
149  std::string halo_type,
150  float halo_speed )
151 {
152  phalos->AddHalo( filename, loc, size, col, halo_type, halo_speed );
153 }
154 
155 template < class UnitType >
156 void GameUnit< UnitType >::Cloak( bool engage )
157 {
158  if (Network != NULL && !SERVER) {
159  int which = UnitUtil::isPlayerStarship( this );
160  if (which >= 0)
161  Network[which].sendCloak( engage );
162  else
163  UnitType::Cloak( engage ); //client side unit
164  } else {
165  UnitType::Cloak( engage ); //client side unit
166  }
167 }
168 
169 template < class UnitType >
170 bool GameUnit< UnitType >::queryFrustum( double frustum[6][4] ) const
171 {
172  int i;
173 #ifdef VARIABLE_LENGTH_PQR
174  Vector TargetPoint( cumulative_transformation_matrix[0],
175  cumulative_transformation_matrix[1],
176  cumulative_transformation_matrix[2] );
177  float SizeScaleFactor = sqrtf( TargetPoint.Dot( TargetPoint ) );
178 #else
179  Vector TargetPoint;
180 #endif
181  for (i = 0; i < nummesh(); i++) {
182  TargetPoint = Transform( this->cumulative_transformation_matrix, this->meshdata[i]->Position() );
183  if ( GFXSphereInFrustum( frustum,
184  TargetPoint,
185  this->meshdata[i]->rSize()
186 #ifdef VARIABLE_LENGTH_PQR
187  *SizeScaleFactor
188 #endif
189  ) )
190  return true;
191  }
192  const Unit *un;
193  for (un_fkiter iter = this->SubUnits.constFastIterator(); (un = *iter); ++iter)
194  if ( ( (GameUnit< UnitType >*)un )->queryFrustum( frustum ) )
195  return true;
196  return false;
197 }
198 
199 template < class UnitType >
201 {
202  Matrix m;
203  Matrix ctm = this->cumulative_transformation_matrix;
204  Vector q( ctm.getQ() );
205  Vector r( ctm.getR() );
206  Vector tmp;
207  CrossProduct( r, q, tmp );
208  _Universe->AccessCamera( whichcam )->SetOrientation( tmp, q, r );
209 
210  _Universe->AccessCamera( whichcam )->SetPosition( Transform( ctm,
211  this->pImage->CockpitCenter.Cast() ),
212  this->GetWarpVelocity(), this->GetAngularVelocity(), this->GetAcceleration() );
213 }
214 
215 extern bool flickerDamage( Unit *un, float hullpercent );
216 extern int cloakVal( int cloakint, int cloakminint, int cloakrateint, bool cloakglass ); //short fix?
217 
218 template < class UnitType >
219 void GameUnit< UnitType >::DrawNow( const Matrix &mato, float lod )
220 {
221  static const void *rootunit = NULL;
222  if (rootunit == NULL) rootunit = (const void*) this;
223  float damagelevel = 1.0;
224  unsigned char chardamage = 0;
225  if (this->hull < this->maxhull) {
226  damagelevel = this->hull/this->maxhull;
227  chardamage = ( 255-(unsigned char) (damagelevel*255) );
228  }
229 #ifdef VARIABLE_LENGTH_PQR
230  const float vlpqrScaleFactor = SizeScaleFactor;
231 #else
232  const float vlpqrScaleFactor = 1.f;
233 #endif
234  unsigned int i;
235  Matrix mat( mato );
236  if (this->graphicOptions.FaceCamera) {
237  Vector p, q, r;
238  QVector pos( mato.p );
239  float wid, hei;
240  CalculateOrientation( pos, p, q, r, wid, hei, 0, false, &mat );
241  pos = mato.p;
242  VectorAndPositionToMatrix( mat, p, q, r, pos );
243  }
244  int cloak = this->cloaking;
245  if (this->cloaking > this->cloakmin)
246  cloak = cloakVal( cloak, this->cloakmin, this->pImage->cloakrate, this->pImage->cloakglass );
247  for (i = 0; (int) i < this->nummesh(); i++) {
248  //NOTE LESS THAN OR EQUALS...to cover shield mesh
249  if (this->meshdata[i] == NULL)
250  continue;
251  QVector TransformedPosition = Transform( mat,
252  this->meshdata[i]->Position().Cast() );
253  float d = GFXSphereInFrustum( TransformedPosition, this->meshdata[i]->clipRadialSize()*vlpqrScaleFactor );
254  if (d) //d can be used for level of detail
255  //this->meshdata[i]->DrawNow(lod,false,mat,cloak);//cloakign and nebula
256  this->meshdata[i]->Draw( lod, mat, d, cloak );
257  }
258  Unit *un;
259  for (un_kiter iter = this->SubUnits.constIterator(); (un = *iter); ++iter) {
260  Matrix temp;
261  un->curr_physical_state.to_matrix( temp );
262  Matrix submat;
263  MultMatrix( submat, mat, temp );
264  (un)->DrawNow( submat, lod );
265  }
266  float haloalpha = 1;
267  if (cloak >= 0)
268  haloalpha = ( (float) cloak )/2147483647;
269 #ifdef CAR_SIM
270  Vector Scale( 1, pImage->ecm, computer.set_speed );
271 #else
272  float cmas = this->computer.max_ab_speed()*this->computer.max_ab_speed();
273  if (cmas == 0)
274  cmas = 1;
275  Vector Scale( 1, 1, 1 ); //Now, HaloSystem handles that
276 #endif
277  int nummounts = this->GetNumMounts();
278  for (i = 0; (int) i < nummounts; i++) {
279  static bool draw_mounts = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "draw_weapons", "false" ) );
280  Mount *mahnt = &this->mounts[i];
281  if (draw_mounts)
282  if (mahnt->xyscale != 0 && mahnt->zscale != 0) {
283  Mesh *gun = mahnt->type->gun;
284  if (gun && mahnt->status != Mount::UNCHOSEN) {
285  Transformation mountLocation( mahnt->GetMountOrientation(), mahnt->GetMountLocation().Cast() );
286  mountLocation.Compose( Transformation::from_matrix( mat ), this->WarpMatrix( mat ) );
287  Matrix mmat;
288  mountLocation.to_matrix( mmat );
289  if (GFXSphereInFrustum( mountLocation.position, gun->rSize()*vlpqrScaleFactor ) > 0) {
290  float d = ( mountLocation.position-_Universe->AccessCamera()->GetPosition() ).Magnitude();
291  float lod = gun->rSize()*g_game.detaillevel*perspectiveFactor(
292  (d-gun->rSize() < g_game.znear) ? g_game.znear : d-gun->rSize() );
293  ScaleMatrix( mmat, Vector( mahnt->xyscale, mahnt->xyscale, mahnt->zscale ) );
294  gun->setCurrentFrame( this->mounts[i].ComputeAnimatedFrame( gun ) );
295  gun->Draw( lod, mmat, d, cloak,
296  (_Universe->AccessCamera()->GetNebula() == this->nebula && this->nebula != NULL) ? -1 : 0,
297  chardamage,
298  true ); //cloakign and nebula
299  if (mahnt->type->gun1) {
300  gun = mahnt->type->gun1;
301  gun->setCurrentFrame( this->mounts[i].ComputeAnimatedFrame( gun ) );
302  gun->Draw( lod, mmat, d, cloak,
303  (_Universe->AccessCamera()->GetNebula() == this->nebula && this->nebula
304  != NULL) ? -1 : 0,
305  chardamage, true ); //cloakign and nebula
306  }
307  }
308  }
309  }
310  }
311  Vector accel = this->GetAcceleration();
312  float maxaccel = this->GetMaxAccelerationInDirectionOf( mat.getR(), true );
313  Vector velocity = this->GetVelocity();
314  if ( phalos->ShouldDraw( mat, velocity, accel, maxaccel,
315  cmas ) && !( this->docked&(UnitType::DOCKED|UnitType::DOCKED_INSIDE) ) )
316  phalos->Draw( mat, Scale, cloak, 0, this->GetHullPercent(), velocity, accel, maxaccel, cmas, this->faction );
317  if (rootunit == (const void*) this) {
320  rootunit = NULL;
321  }
322 }
323 
324 template < class UnitType >
326 {
327  DrawNow( identity_matrix, 1000000000 );
328 }
329 
330 extern double calc_blend_factor( double frac, int priority, int when_it_will_be_simulated, int cur_simulation_frame );
331 
332 template < class UnitType >
333 void GameUnit< UnitType >::Draw( const Transformation &parent, const Matrix &parentMatrix )
334 {
335  //Quick shortcut for camera setup phase
336  bool myparent = ( this == _Universe->AccessCockpit()->GetParent() );
337 
338 #ifdef VARIABLE_LENGTH_PQR
339  const float vlpqrScaleFactor = SizeScaleFactor;
340 #else
341  const float vlpqrScaleFactor = 1.f;
342 #endif
343 
344  Matrix *ctm;
345  Matrix invview;
346  Transformation *ct;
347 
348  this->cumulative_transformation = linear_interpolate( this->prev_physical_state,
349  this->curr_physical_state,
351  this->cumulative_transformation.Compose( parent, parentMatrix );
352  this->cumulative_transformation.to_matrix( this->cumulative_transformation_matrix );
353 
354  ctm = &this->cumulative_transformation_matrix;
355  ct = &this->cumulative_transformation;
356  if (this->graphicOptions.FaceCamera == 1) {
357  Vector p, q, r;
358  QVector pos( ctm->p );
359  float wid, hei;
360  float magr = parentMatrix.getR().Magnitude();
361  float magp = parentMatrix.getP().Magnitude();
362  float magq = parentMatrix.getQ().Magnitude();
363  CalculateOrientation( pos, p, q, r, wid, hei, 0, false, ctm );
364  VectorAndPositionToMatrix( invview, p*magp, q*magq, r*magr, ctm->p );
365  ctm = &invview;
366  }
367 
368 #ifdef PERFRAMESOUND
369  AUDAdjustSound( sound.engine, cumulative_transformation.position, GetVelocity() );
370 #endif
371 
372  int cloak = this->cloaking;
373  if (this->cloaking > this->cloakmin) {
374  cloak = (int) (this->cloaking-interpolation_blend_factor*this->pImage->cloakrate*SIMULATION_ATOM);
375  cloak = cloakVal( cloak, this->cloakmin, this->pImage->cloakrate, this->pImage->cloakglass );
376  }
377 
378  unsigned int i;
379  if ( (this->hull < 0) && (!cam_setup_phase) )
380  Explode( true, GetElapsedTime() );
381 
382  float damagelevel = 1.0f;
383  unsigned char chardamage = 0;
384  if (this->hull < this->maxhull && !cam_setup_phase) {
385  damagelevel = this->hull/this->maxhull;
386  chardamage = ( 255-(unsigned char) (damagelevel*255) );
387  }
388 
389  bool On_Screen = false;
390  if ( ( !(this->invisible&UnitType::INVISUNIT) ) && ( ( !(this->invisible&UnitType::INVISCAMERA) ) || (!myparent) ) ) {
391  if (!cam_setup_phase) {
392  Camera *camera = _Universe->AccessCamera();
393  QVector camerapos = camera->GetPosition();
394 
395  float minmeshradius =
396  ( camera->GetVelocity().Magnitude()+this->Velocity.Magnitude() )*SIMULATION_ATOM;
397 
398  unsigned int numKeyFrames = this->graphicOptions.NumAnimationPoints;
399  for (i = 0; i < this->meshdata.size(); i++) {
400  //NOTE LESS THAN OR EQUALS...to cover shield mesh
401  if (this->meshdata[i] == NULL)
402  continue;
403  if ( (int) i == this->nummesh() && (this->meshdata[i]->numFX() == 0 || this->hull < 0) )
404  continue;
405  if (this->meshdata[i]->getBlendDst() == ONE) {
406  if ( (this->invisible&UnitType::INVISGLOW) != 0 )
407  continue;
408  if (damagelevel < .9)
409  if ( flickerDamage( this, damagelevel ) )
410  continue;
411  }
412  QVector TransformedPosition = Transform( *ctm, this->meshdata[i]->Position().Cast() );
413 
414  double d = GFXSphereInFrustum( TransformedPosition,
415  minmeshradius+this->meshdata[i]->clipRadialSize()*vlpqrScaleFactor );
416  if (d) {
417  //d can be used for level of detail shit
418  d = ( TransformedPosition-camerapos ).Magnitude();
419  double rd = d-this->meshdata[i]->rSize();
420  double pixradius = this->meshdata[i]->rSize()*perspectiveFactor(
421  (rd < g_game.znear) ? g_game.znear : rd );
422  double lod = pixradius*g_game.detaillevel;
423  if (lod >= 0.5 && pixradius >= 2.5) {
424  //if the radius is at least half a pixel at detail 1 (equivalent to pixradius >= 0.5 / detail)
425  float currentFrame = this->meshdata[i]->getCurrentFrame();
426  this->meshdata[i]->Draw( lod, this->WarpMatrix( *ctm ), d,
427  i == this->meshdata.size()-1 ? -1 : cloak,
428  (camera->GetNebula() == this->nebula && this->nebula != NULL) ? -1 : 0,
429  chardamage ); //cloakign and nebula
430  On_Screen = true;
431  unsigned int numAnimFrames = 0;
432  static const string default_animation;
433  if ( this->meshdata[i]->getFramesPerSecond()
434  && ( numAnimFrames = this->meshdata[i]->getNumAnimationFrames( default_animation ) ) ) {
435  float currentprogress = floor(
436  this->meshdata[i]->getCurrentFrame()*numKeyFrames/(float) numAnimFrames );
437  if (numKeyFrames
438  && floor( currentFrame*numKeyFrames/(float) numAnimFrames ) != currentprogress)
439  {
440  this->graphicOptions.Animating = 0;
441  this->meshdata[i]->setCurrentFrame( .1+currentprogress*numAnimFrames/(float) numKeyFrames );
442  } else if (!this->graphicOptions.Animating) {
443  this->meshdata[i]->setCurrentFrame( currentFrame ); //dont' budge
444  }
445  }
446  }
447  }
448  }
449  }
450  {
451  Unit *un;
452  double backup = interpolation_blend_factor;
453  int cur_sim_frame = _Universe->activeStarSystem()->getCurrentSimFrame();
454  for (un_kiter iter = this->SubUnits.constIterator(); (un = *iter); ++iter) {
455  float backup = SIMULATION_ATOM;
456  if (this->sim_atom_multiplier && un->sim_atom_multiplier)
457  SIMULATION_ATOM = SIMULATION_ATOM*un->sim_atom_multiplier/this->sim_atom_multiplier;
460  un->cur_sim_queue_slot,
461  cur_sim_frame );
462  (un)->Draw( *ct, *ctm );
463 
464  SIMULATION_ATOM = backup;
465  }
467  }
468  } else {
470  //UpdateHudMatrix();
471  }
472  /***DEBUGGING cosAngleFromMountTo
473  * UnitCollection *dL = _Universe->activeStarSystem()->getUnitList();
474  * UnitCollection::UnitIterator *tmpiter = dL->createIterator();
475  * GameUnit<UnitType> * curun;
476  * while (curun = tmpiter->current()) {
477  * if (curun->selected) {
478  * float tmpdis;
479  * float tmpf = cosAngleFromMountTo (curun, tmpdis);
480  * VSFileSystem::vs_fprintf (stderr,"%s: <%f d: %f\n", curun->name.c_str(), tmpf, tmpdis);
481  *
482  * }
483  * tmpiter->advance();
484  * }
485  * delete tmpiter;
486  **/
487  if (cam_setup_phase) return;
488  int nummounts = this->GetNumMounts();
489  for (i = 0; (int) i < nummounts; i++) {
490  static bool draw_mounts = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "draw_weapons", "false" ) );
491  Mount *mahnt = &this->mounts[i];
492  if (draw_mounts && On_Screen)
493  if (mahnt->xyscale != 0 && mahnt->zscale != 0) {
494  Mesh *gun = mahnt->type->gun;
495  if (gun && mahnt->status != Mount::UNCHOSEN) {
496  Transformation mountLocation( mahnt->GetMountOrientation(), mahnt->GetMountLocation().Cast() );
497  mountLocation.Compose( *ct, this->WarpMatrix( *ctm ) );
498  Matrix mat;
499  mountLocation.to_matrix( mat );
500  if (GFXSphereInFrustum( mountLocation.position, gun->rSize()*vlpqrScaleFactor ) > 0) {
501  float d = ( mountLocation.position-_Universe->AccessCamera()->GetPosition() ).Magnitude();
502  float lod = gun->rSize()*g_game.detaillevel*perspectiveFactor(
503  (d-gun->rSize() < g_game.znear) ? g_game.znear : d-gun->rSize() );
504  ScaleMatrix( mat, Vector( mahnt->xyscale, mahnt->xyscale, mahnt->zscale ) );
505  gun->setCurrentFrame( this->mounts[i].ComputeAnimatedFrame( gun ) );
506  gun->Draw( lod, mat, d, cloak,
507  (_Universe->AccessCamera()->GetNebula() == this->nebula && this->nebula != NULL) ? -1 : 0,
508  chardamage,
509  true ); //cloakign and nebula
510  if (mahnt->type->gun1) {
511  gun = mahnt->type->gun1;
512  gun->setCurrentFrame( this->mounts[i].ComputeAnimatedFrame( gun ) );
513  gun->Draw( lod, mat, d, cloak,
514  (_Universe->AccessCamera()->GetNebula() == this->nebula && this->nebula
515  != NULL) ? -1 : 0,
516  chardamage, true ); //cloakign and nebula
517  }
518  }
519  }
520  }
521  if (this->mounts[i].type->type == weapon_info::BEAM)
522  if (this->mounts[i].ref.gun)
523  this->mounts[i].ref.gun->Draw( *ct, this->WarpMatrix( *ctm ),
524  ( (this->mounts[i].size&weapon_info::AUTOTRACKING)
525  && (this->mounts[i].time_to_lock <= 0)
526  && (this->computer.radar.trackingactive) ) ? Unit::Target() : NULL,
527  this->computer.radar.trackingcone );
528  }
529  float haloalpha = 1;
530  if (cloak >= 0)
531  haloalpha = ( (float) cloak )/2147483647;
532  if ( On_Screen && (phalos->NumHalos() > 0) && !( this->docked&(UnitType::DOCKED|UnitType::DOCKED_INSIDE) ) ) {
533  Vector accel = this->GetAcceleration();
534  float maxaccel = this->GetMaxAccelerationInDirectionOf( this->WarpMatrix( *ctm ).getR(), true );
535  Vector velocity = this->GetVelocity();
536 
537 #ifdef CAR_SIM
538  Vector Scale( 1, pImage->ecm, computer.set_speed );
539 #else
540  float cmas = this->computer.max_ab_speed()*this->computer.max_ab_speed();
541  if (cmas == 0)
542  cmas = 1;
543  Vector Scale( 1, 1, 1 ); //Now, HaloSystem handles that
544 #endif
545  //WARNING: cmas is not a valid maximum speed for the upcoming multi-direction thrusters,
546  //nor is maxaccel. Instead, each halo should have its own limits specified in units.csv
547  if ( phalos->ShouldDraw( this->WarpMatrix( *ctm ), velocity, accel, maxaccel, cmas ) )
548  phalos->Draw( this->WarpMatrix( *ctm ), Scale, cloak,
549  (_Universe->AccessCamera()->GetNebula() == this->nebula && this->nebula != NULL) ? -1 : 0,
550  this->GetHull() > 0 ? damagelevel : 1.0, velocity, accel, maxaccel, cmas, this->faction );
551  }
552  if ( On_Screen && !UnitType::graphicOptions.NoDamageParticles
553  && !( this->docked&(UnitType::DOCKED|UnitType::DOCKED_INSIDE) ) ) {
554  int numm = this->nummesh();
555  if (damagelevel < .99 && numm > 0 && this->GetHull() > 0) {
556  unsigned int switcher = (damagelevel > .8) ? 1
557  : (damagelevel > .6) ? 2 : (damagelevel > .4) ? 3 : (damagelevel > .2) ? 4 : 5;
558  static float sparklerate = XMLSupport::parse_float( vs_config->getVariable( "graphics", "sparklerate", "5" ) );
559  sparkle_accum += GetElapsedTime()*sparklerate;
560  int spawn = (int) (sparkle_accum);
561  sparkle_accum -= spawn;
562  while (spawn-- > 0) {
563  switch (switcher)
564  {
565  case 5:
566  LaunchOneParticle( *ctm, this->GetVelocity(), ( (long) this )+165, this, damagelevel, this->faction );
567  case 4:
568  LaunchOneParticle( *ctm, this->GetVelocity(), ( (long) this )+47, this, damagelevel, this->faction );
569  case 3:
570  LaunchOneParticle( *ctm, this->GetVelocity(), ( (long) this )+61, this, damagelevel, this->faction );
571  case 2:
572  LaunchOneParticle( *ctm, this->GetVelocity(), ( (long) this )+65537, this, damagelevel, this->faction );
573  default:
574  LaunchOneParticle( *ctm, this->GetVelocity(), ( (long) this )+257, this, damagelevel, this->faction );
575  }
576  }
577  }
578  }
579 }
580 
581 template < class UnitType >
583 {
584  Draw( quat, identity_matrix );
585 }
586 
587 template < class UnitType >
589 {
591 }
592 
593 
594 static float parseFloat( const std::string &s )
595 {
596  if ( s.empty() ) {
597  VSFileSystem::vs_dprintf(1, "WARNING: invalid float: %s\n", s.c_str());
598  return 0.f;
599  } else {
600  return XMLSupport::parse_floatf( s );
601  }
602 }
603 
604 static void parseFloat4( const std::string &s, float value[4] )
605 {
606  string::size_type ini = 0, end;
607  int i = 0;
608  while (i < 4 && ini != string::npos) {
609  value[i++] = parseFloat( s.substr( ini, end = s.find_first_of( ',', ini ) ) );
610  ini = ( (end == string::npos) ? end : (end+1) );
611  }
612  if (i >= 4 && ini != string::npos)
613  VSFileSystem::vs_dprintf(1, "WARNING: invalid float4: %s\n", s.c_str());
614  while (i < 4)
615  value[i++] = 0;
616 }
617 
618 template < class UnitType >
619 void GameUnit< UnitType >::applyTechniqueOverrides(const map<string, string> &overrides)
620 {
621  for (vector<Mesh*>::iterator mesh = this->meshdata.begin(); mesh != this->meshdata.end(); ++mesh) {
622  if (*mesh != NULL) {
623  // First check to see if the technique holds any parameter being overridden
624  TechniquePtr technique = (*mesh)->getTechnique();
625  if (technique.get() != NULL) {
626  bool doOverride = false;
627  for (int passno = 0; !doOverride && passno < technique->getNumPasses(); ++passno) {
628  const Technique::Pass &pass = technique->getPass(passno);
629  for (size_t paramno = 0; !doOverride && paramno < pass.getNumShaderParams(); ++paramno) {
630  if (overrides.count(pass.getShaderParam(paramno).name) > 0)
631  doOverride = true;
632  }
633  }
634 
635  if (doOverride) {
636  // Prepare a new technique with the overrides
637  // (make sure the technique has been compiled though -
638  // parameter values don't really need recompilation)
639  TechniquePtr newtechnique = TechniquePtr(new Technique(*technique));
640  for (int passno = 0; passno < technique->getNumPasses(); ++passno) {
641  Technique::Pass &pass = technique->getPass(passno);
642  for (size_t paramno = 0; paramno < pass.getNumShaderParams(); ++paramno) {
643  Technique::Pass::ShaderParam &param = pass.getShaderParam(paramno);
644  map<string, string>::const_iterator override = overrides.find(param.name);
645  if (override != overrides.end())
646  parseFloat4(override->second, param.value);
647  }
648  }
649 
650  (*mesh)->setTechnique(newtechnique);
651  }
652  }
653  }
654  }
655 }
656 
657 template < class UnitType >
659 {
660  static float cutoff =
661  XMLSupport::parse_float( vs_config->getVariable( "graphics", "warp_stretch_cutoff",
662  "50000" ) )*XMLSupport::parse_float(
663  vs_config->getVariable( "physics", "game_speed", "1" ) );
664  static float cutoffcutoff = cutoff*cutoff;
665  static bool only_stretch_in_warp =
666  XMLSupport::parse_bool( vs_config->getVariable( "graphics", "only_stretch_in_warp", "true" ) );
667  if ( this->GetWarpVelocity().MagnitudeSquared() < cutoffcutoff
668  || (only_stretch_in_warp && this->graphicOptions.InWarp == 0) ) {
669  return ctm;
670  } else {
671  Matrix k( ctm );
672 
673  float speed = this->GetWarpVelocity().Magnitude();
674  static float maxregion0stretch =
675  XMLSupport::parse_float( vs_config->getVariable( "graphics", "warp_stretch_region0_max", "1" ) );
676 
677  static float maxstretch = XMLSupport::parse_float( vs_config->getVariable( "graphics", "warp_stretch_max", "4" ) );
678  static float maxspeed =
679  XMLSupport::parse_float( vs_config->getVariable( "graphics", "warp_stretch_max_speed",
680  "1000000" ) )
681  *XMLSupport::parse_float( vs_config->getVariable( "physics", "game_speed", "1" ) );
682  static float maxregion0speed =
683  XMLSupport::parse_float( vs_config->getVariable( "graphics", "warp_stretch_max_region0_speed",
684  "100000" ) )
685  *XMLSupport::parse_float( vs_config->getVariable( "physics", "game_speed", "1" ) );
686  float stretchregion0length = maxregion0stretch*(speed-cutoff)/(maxregion0speed-cutoff);
687  float stretchlength =
688  (maxstretch
689  -maxregion0stretch)*(speed-maxregion0speed)/(maxspeed-maxregion0speed+.06125)+maxregion0stretch;
690  if (stretchlength > maxstretch)
691  stretchlength = maxstretch;
692  if (stretchregion0length > maxregion0stretch)
693  stretchregion0length = maxregion0stretch;
694  ScaleMatrix( k, Vector( 1, 1, 1+(speed > maxregion0speed ? stretchlength : stretchregion0length) ) );
695  return k;
696  }
697 }
698 
699 using Orders::FireAt;
700 
701 #if 0
702 template < class UnitType >
704 {
705  for (int i = 0; i < numhalos; i++)
706  //float x,y;
707  //halos[i]->GetDimensions (x,y); //halos[i]->SetDimensions (x/(1024),y/(1024));
708  halos[i]->Draw( cumulative_transformation, cumulative_transformation_matrix, 0 );
709 }
710 template < class UnitType >
712 {
713  for (int i = 0; i < numhalos; i++) {
714  //float x,y;
715  //halos[i]->GetDimensions (x,y);
716  //halos[i]->SetDimensions (x*(1024),y*(1024));
717  }
718 }
719 #endif
720 
722 //explicit instantiations, added by chuck_starchaser:
723 
724 
725  #include "cmd/asteroid_generic.h"
726 template class GameUnit< Asteroid >;
727 
728  #include "cmd/building_generic.h"
729 template class GameUnit< Building >;
730 
731  #include "cmd/planet_generic.h"
732 template class GameUnit< Planet >;
733 
734  #include "cmd/unit_generic.h"
735 template class GameUnit< Unit >;
736 
737  #include "cmd/missile_generic.h"
738 template class GameUnit< Missile >;
739 
740  #include "cmd/nebula.h"
741 template class GameUnit< Nebula >;
742 
743  #include "cmd/enhancement.h"
744 template class GameUnit< Enhancement >;
745