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_damage.h
Go to the documentation of this file.
1 #ifndef __UNIT_DAMAGE_CPP__
2 #define __UNIT_DAMAGE_CPP__
3 #include <string>
4 #include <vector>
5 #include "unit.h"
6 #include "unit_factory.h"
7 #include "ai/order.h"
8 #include "gfx/animation.h"
9 #include "gfx/mesh.h"
10 #include "gfx/halo.h"
11 #include "vegastrike.h"
12 #include "unit_collide.h"
13 #include <float.h>
14 #include "audiolib.h"
15 #include "images.h"
16 #include "beam.h"
17 #include "config_xml.h"
18 #include "vs_globals.h"
19 #include "xml_support.h"
20 #include "savegame.h"
21 #include "gfx/cockpit.h"
22 #include "cmd/script/mission.h"
23 #include "missile.h"
24 #include "cmd/ai/communication.h"
25 #include "cmd/script/flightgroup.h"
26 #include "music.h"
27 #include "faction_generic.h"
28 #include "universe_util.h"
29 #include "csv.h"
30 #include "unit_csv.h"
31 #include "base.h"
32 
33 extern unsigned int apply_float_to_unsigned_int( float tmp ); //Short fix
34 extern vector< Mesh* >MakeMesh( unsigned int mysize );
35 
36 template < class UnitType >
38 {
39  static bool split_subunits = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "split_dead_subunits", "true" ) );
40  if (split_subunits)
41  for (un_iter su = this->getSubUnits(); *su; ++su)
42  (*su)->Split( level );
43  static float debrismassmult = XMLSupport::parse_float( vs_config->getVariable( "physics", "debris_mass", ".00001" ) );
44  Vector PlaneNorm;
45  for (int i = 0; i < nummesh();) {
46  if (this->meshdata[i]) {
47  if (this->meshdata[i]->getBlendDst() == ONE) {
48  delete this->meshdata[i];
49  this->meshdata.erase( this->meshdata.begin()+i );
50  } else {i++; }} else {this->meshdata.erase( this->meshdata.begin()+i ); }}
51  int nm = this->nummesh();
52  string fac = FactionUtil::GetFaction( this->faction );
53 
54  CSVRow unit_stats( LookupUnitRow( this->name, fac ) );
55  unsigned int num_chunks = unit_stats.success() ? atoi( unit_stats["Num_Chunks"].c_str() ) : 0;
56  if (nm <= 0 && num_chunks == 0)
57  return;
58  vector< Mesh* >old = this->meshdata;
59  Mesh *shield = old.back();
60  old.pop_back();
61 
62  vector< unsigned int >meshsizes;
63  if ( num_chunks && unit_stats.success() ) {
64  size_t i;
65  vector< Mesh* >nw;
66  unsigned int which_chunk = rand()%num_chunks;
67  string chunkname = UniverseUtil::LookupUnitStat( this->name, fac, "Chunk_"+XMLSupport::tostring( which_chunk ) );
68  string dir = UniverseUtil::LookupUnitStat( this->name, fac, "Directory" );
69  VSFileSystem::current_path.push_back( unit_stats.getRoot() );
70  VSFileSystem::current_subdirectory.push_back( "/"+dir );
72  float randomstartframe = 0;
73  float randomstartseconds = 0;
74  string scalestr = UniverseUtil::LookupUnitStat( this->name, fac, "Unit_Scale" );
75  int scale = atoi( scalestr.c_str() );
76  if (scale == 0) scale = 1;
77  AddMeshes( nw, randomstartframe, randomstartseconds, scale, chunkname, this->faction,
78  this->getFlightgroup(), &meshsizes );
79  VSFileSystem::current_type.pop_back();
81  VSFileSystem::current_path.pop_back();
82  for (i = 0; i < old.size(); ++i)
83  delete old[i];
84  old.clear();
85  old = nw;
86  } else {
87  for (int split = 0; split < level; split++) {
88  vector< Mesh* >nw;
89  size_t oldsize = old.size();
90  for (size_t i = 0; i < oldsize; i++) {
91  PlaneNorm.Set( rand()-RAND_MAX/2, rand()-RAND_MAX/2, rand()-RAND_MAX/2+.5 );
92  PlaneNorm.Normalize();
93  nw.push_back( NULL );
94  nw.push_back( NULL );
95  old[i]->Fork( nw[nw.size()-2], nw.back(), PlaneNorm.i, PlaneNorm.j, PlaneNorm.k,
96  -PlaneNorm.Dot( old[i]->Position() ) ); //splits somehow right down the middle.
97  delete old[i];
98  old[i] = NULL;
99  if (nw[nw.size()-2] == NULL) {
100  nw[nw.size()-2] = nw.back();
101  nw.pop_back();
102  }
103  if (nw.back() == NULL)
104  nw.pop_back();
105  }
106  old = nw;
107  }
108  meshsizes.reserve( old.size() );
109  for (size_t i = 0; i < old.size(); ++i)
110  meshsizes.push_back( 1 );
111  }
112  old.push_back( NULL ); //push back shield
113  if (shield)
114  delete shield;
115  nm = old.size()-1;
116  unsigned int k = 0;
117  vector< Mesh* >tempmeshes;
118  for (vector<Mesh *>::size_type i=0;i<meshsizes.size();i++) {
119  Unit *splitsub;
120  tempmeshes.clear();
121  tempmeshes.reserve( meshsizes[i] );
122  for (unsigned int j = 0; j < meshsizes[i] && k < old.size(); ++j, ++k)
123  tempmeshes.push_back( old[k] );
124  this->SubUnits.prepend( splitsub = UnitFactory::createUnit( tempmeshes, true, this->faction ) );
125  splitsub->hull = 1000;
126  splitsub->name = "debris";
127  splitsub->Mass = debrismassmult*splitsub->Mass/level;
128  splitsub->pImage->timeexplode = .1;
129  if (splitsub->meshdata[0]) {
130  Vector loc = splitsub->meshdata[0]->Position();
131  static float explosion_force = XMLSupport::parse_float( vs_config->getVariable( "graphics", "explosionforce", ".5" ) ); //10 seconds for auto to kick in;
132  float locm = loc.Magnitude();
133  if (locm < .0001)
134  locm = 1;
135  splitsub->ApplyForce( splitsub->meshdata[0]->rSize()*explosion_force*10*splitsub->GetMass()*loc/locm );
136  loc.Set( rand(), rand(), rand()+.1 );
137  loc.Normalize();
138  static float explosion_torque =
139  XMLSupport::parse_float( vs_config->getVariable( "graphics", "explosiontorque", ".001" ) ); //10 seconds for auto to kick in;
140  splitsub->ApplyLocalTorque( loc*splitsub->GetMoment()*explosion_torque*( 1+rand()%(int) ( 1+this->rSize() ) ) );
141  }
142  }
143  old.clear();
144  this->meshdata.clear();
145  this->meshdata.push_back( NULL ); //the shield
146  this->Mass *= debrismassmult;
147 }
148 
149 extern float rand01();
150 
151 template < class UnitType >
153 {
154  if ( !_Universe->isPlayerStarship( this ) ) {
155  static bool ai_sound = XMLSupport::parse_bool( vs_config->getVariable( "audio", "ai_sound", "true" ) );
156  if ( AUDIsPlaying( this->sound->armor ) )
157  AUDStopPlaying( this->sound->armor );
158  if (ai_sound)
159  AUDPlay( this->sound->armor, this->ToWorldCoordinates(
160  pnt ).Cast()+this->cumulative_transformation.position, this->Velocity, 1 );
161  } else {
162  static int playerarmorsound =
163  AUDCreateSoundWAV( vs_config->getVariable( "unitaudio", "player_armor_hit", "bigarmor.wav" ) );
164  int sound = playerarmorsound != -1 ? playerarmorsound : this->sound->armor;
165  if ( AUDIsPlaying( sound ) )
166  AUDStopPlaying( sound );
167  AUDPlay( sound, this->ToWorldCoordinates(
168  pnt ).Cast()+this->cumulative_transformation.position, this->Velocity, 1 );
169  }
170 }
171 
172 template < class UnitType >
174 {
175  if ( !_Universe->isPlayerStarship( this ) ) {
176  static bool ai_sound = XMLSupport::parse_bool( vs_config->getVariable( "audio", "ai_sound", "true" ) );
177  if ( AUDIsPlaying( this->sound->hull ) )
178  AUDStopPlaying( this->sound->hull );
179  if (ai_sound)
180  AUDPlay( this->sound->hull, this->ToWorldCoordinates(
181  pnt ).Cast()+this->cumulative_transformation.position, this->Velocity, 1 );
182  } else {
183  static int playerhullsound = AUDCreateSoundWAV( vs_config->getVariable( "unitaudio", "player_hull_hit", "bigarmor.wav" ) );
184  int sound = playerhullsound != -1 ? playerhullsound : this->sound->hull;
185  if ( AUDIsPlaying( sound ) )
186  AUDStopPlaying( sound );
187  AUDPlay( sound, this->ToWorldCoordinates(
188  pnt ).Cast()+this->cumulative_transformation.position, this->Velocity, 1 );
189  }
190 }
191 
192 template < class UnitType >
193 float GameUnit< UnitType >::DealDamageToShield( const Vector &pnt, float &damage )
194 {
195  float percent = UnitType::DealDamageToShield( pnt, damage );
196  if ( !_Universe->isPlayerStarship( this ) ) {
197  static bool ai_sound = XMLSupport::parse_bool( vs_config->getVariable( "audio", "ai_sound", "true" ) );
198  if (percent) {
199  if ( AUDIsPlaying( this->sound->shield ) )
200  AUDStopPlaying( this->sound->shield );
201  if (ai_sound)
202  AUDPlay( this->sound->shield, this->ToWorldCoordinates(
203  pnt ).Cast()+this->cumulative_transformation.position, this->Velocity, 1 );
204  }
205  } else {
206  static int playerhullsound =
207  AUDCreateSoundWAV( vs_config->getVariable( "unitaudio", "player_shield_hit", "shieldhit.wav" ) );
208  int sound = playerhullsound != -1 ? playerhullsound : this->sound->hull;
209  if (percent) {
210  if ( AUDIsPlaying( sound ) )
211  AUDStopPlaying( sound );
212  AUDPlay( sound, this->ToWorldCoordinates(
213  pnt ).Cast()+this->cumulative_transformation.position, this->Velocity, 1 );
214  }
215  }
216  return percent;
217 }
218 
219 extern Animation * GetVolatileAni( unsigned int );
220 extern unsigned int AddAnimation( const QVector&, const float, bool, const string&, float percentgrow );
221 
222 extern Animation * getRandomCachedAni();
223 extern string getRandomCachedAniString();
224 extern void disableSubUnits( Unit *un );
225 
226 template < class UnitType >
227 bool GameUnit< UnitType >::Explode( bool drawit, float timeit )
228 {
229  if (this->pImage->pExplosion == NULL && this->pImage->timeexplode == 0) {
230  //no explosion in unit data file && explosions haven't started yet
231 
232  //notify the director that a ship got destroyed
234  disableSubUnits( this );
235  this->pImage->timeexplode = 0;
236  static string expani = vs_config->getVariable( "graphics", "explosion_animation", "explosion_orange.ani" );
237 
238  string bleh = this->pImage->explosion_type;
239  if ( bleh.empty() )
241  if ( bleh.empty() ) {
242  static Animation cache( expani.c_str(), false, .1, BILINEAR, false );
243  bleh = getRandomCachedAniString();
244  if (bleh.size() == 0)
245  bleh = expani;
246  }
247  static bool explosion_face_player =
248  XMLSupport::parse_bool( vs_config->getVariable( "graphics", "explosion_face_player", "true" ) );
249  this->pImage->pExplosion = new Animation( bleh.c_str(), explosion_face_player, .1, BILINEAR, true );
250  this->pImage->pExplosion->SetDimensions( this->ExplosionRadius(), this->ExplosionRadius() );
251  Vector p, q, r;
252  this->GetOrientation( p, q, r );
253  this->pImage->pExplosion->SetOrientation( p, q, r );
254  if (this->isUnit() != MISSILEPTR) {
255  static float expdamagecenter =
256  XMLSupport::parse_float( vs_config->getVariable( "physics", "explosion_damage_center", "1" ) );
257  static float damageedge =
258  XMLSupport::parse_float( vs_config->getVariable( "graphics", "explosion_damage_edge", ".125" ) );
259  _Universe->activeStarSystem()->AddMissileToQueue( new MissileEffect( this->Position().Cast(), this->MaxShieldVal(),
260  0, this->ExplosionRadius()*expdamagecenter,
261  this->ExplosionRadius()*expdamagecenter
262  *damageedge, NULL ) );
263  }
264  QVector exploc = this->cumulative_transformation.position;
265  bool sub = this->isSubUnit();
266  Unit *un = NULL;
267  if (!sub)
268  if (( un = _Universe->AccessCockpit( 0 )->GetParent() )) {
269  static float explosion_closeness =
270  XMLSupport::parse_float( vs_config->getVariable( "audio", "explosion_closeness", ".8" ) );
271  exploc = un->Position()*explosion_closeness+exploc*(1-explosion_closeness);
272  }
273  AUDPlay( this->sound->explode, exploc, this->Velocity, 1 );
274  if (!sub) {
275  un = _Universe->AccessCockpit()->GetParent();
276  if (this->isUnit() == UNITPTR) {
277  static float percentage_shock =
278  XMLSupport::parse_float( vs_config->getVariable( "graphics", "percent_shockwave", ".5" ) );
279  if ( rand() < RAND_MAX*percentage_shock && ( !this->isSubUnit() ) ) {
280  static float shockwavegrowth =
281  XMLSupport::parse_float( vs_config->getVariable( "graphics", "shockwave_growth", "1.05" ) );
282  static string shockani( vs_config->getVariable( "graphics", "shockwave_animation", "explosion_wave.ani" ) );
283 
284  static Animation *__shock__ani = new Animation( shockani.c_str(), true, .1, MIPMAP, false );
285  __shock__ani->SetFaceCam( false );
286  unsigned int which = AddAnimation( this->Position(),
287  this->ExplosionRadius(), true, shockani, shockwavegrowth );
288  Animation *ani = GetVolatileAni( which );
289  if (ani) {
290  ani->SetFaceCam( false );
291  Vector p, q, r;
292  this->GetOrientation( p, q, r );
293  int tmp = rand();
294  if (tmp < RAND_MAX/24)
295  ani->SetOrientation( Vector( 0, 0, 1 ), Vector( 1, 0, 0 ), Vector( 0, 1, 0 ) );
296  else if (tmp < RAND_MAX/16)
297  ani->SetOrientation( Vector( 0, 1, 0 ), Vector( 0, 0, 1 ), Vector( 1, 0, 0 ) );
298  else if (tmp < RAND_MAX/8)
299  ani->SetOrientation( Vector( 1, 0, 0 ), Vector( 0, 1, 0 ), Vector( 0, 0, 1 ) );
300  else
301  ani->SetOrientation( p, q, r );
302  }
303  }
304  if (un) {
305  int upgradesfaction = FactionUtil::GetUpgradeFaction();
306  static float badrel =
307  XMLSupport::parse_float( vs_config->getVariable( "sound", "loss_relationship", "-.1" ) );
308  static float goodrel =
309  XMLSupport::parse_float( vs_config->getVariable( "sound", "victory_relationship", ".5" ) );
310  static float timelapse =
311  XMLSupport::parse_float( vs_config->getVariable( "sound", "time_between_music", "180" ) );
312  float rel = un->getRelation( this );
314  static float lasttime = 0;
315  float newtime = getNewTime();
316  if ( newtime-lasttime > timelapse
317  || (_Universe->isPlayerStarship( this ) && this->isUnit() != MISSILEPTR && this->faction
318  != upgradesfaction) ) {
319  //No victory for missiles or spawned explosions
320  if (rel > goodrel) {
321  lasttime = newtime;
323  } else if (rel < badrel) {
324  lasttime = newtime;
326  }
327  }
328  }
329  }
330  }
331  }
332  }
333  static float timebeforeexplodedone = XMLSupport::parse_float( vs_config->getVariable( "physics", "debris_time", "500" ) );
334  bool timealldone =
335  ( this->pImage->timeexplode > timebeforeexplodedone || this->isUnit() == MISSILEPTR
336  || _Universe->AccessCockpit()->GetParent() == this || this->SubUnits.empty() );
337  if (this->pImage->pExplosion) {
338  this->pImage->timeexplode += timeit;
339  this->pImage->pExplosion->SetPosition( this->Position() );
340  Vector p, q, r;
341  this->GetOrientation( p, q, r );
342  this->pImage->pExplosion->SetOrientation( p, q, r );
343  if (this->pImage->pExplosion->Done() && timealldone) {
344  delete this->pImage->pExplosion;
345  this->pImage->pExplosion = NULL;
346  }
347  if (drawit && this->pImage->pExplosion)
348  this->pImage->pExplosion->Draw(); //puts on draw queue... please don't delete
349  }
350  bool alldone = this->pImage->pExplosion ? !this->pImage->pExplosion->Done() : false;
351  if ( !this->SubUnits.empty() ) {
352  Unit *su;
353  for (un_iter ui = this->getSubUnits(); (su = *ui); ++ui) {
354  bool temp = su->Explode( drawit, timeit );
356  alldone |= temp;
357  }
358  }
359  static float phatloot = XMLSupport::parse_float( vs_config->getVariable( "physics", "eject_cargo_on_blowup", "0" ) );
360  if ( (phatloot > 0) && (this->numCargo() > 0) ) {
361  size_t dropcount = (size_t) floor( this->numCargo()/phatloot )+1;
362  if ( dropcount > this->numCargo() ) dropcount = this->numCargo();
363  for (size_t i = 0; i < dropcount; i++)
364  this->EjectCargo( this->numCargo()-1 ); //Ejecting the last one is somewhat faster
365  }
366  return alldone || (!timealldone);
367 }
368 
369 #endif
370