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
beam_generic.cpp
Go to the documentation of this file.
1 #include "vegastrike.h"
2 #include <vector>
3 #include "beam.h"
4 #include "unit_generic.h"
5 #include "audiolib.h"
6 #include "configxml.h"
7 #include "images.h"
8 #include "../gfx/camera.h"
9 
10 extern double interpolation_blend_factor;
11 extern bool AdjustMatrix( Matrix &mat, const Vector &velocity, Unit *target, float speed, bool lead, float cone );
12 
13 inline static float mysqr( float a )
14 {
15  return a*a;
16 }
17 
18 inline static float mymax( float a, float b )
19 {
20  return (a > b) ? a : b;
21 }
22 
23 inline static float mymin( float a, float b )
24 {
25  return (a < b) ? a : b;
26 }
27 
29 {
30  return refiretime;
31 }
32 
33 void Beam::SetPosition( const QVector &k )
34 {
35  local_transformation.position = k;
36 }
37 
38 void Beam::SetOrientation( const Vector &p, const Vector &q, const Vector &r )
39 {
40  local_transformation.orientation = Quaternion::from_vectors( p, q, r );
41 }
42 
43 void ScaleByAlpha( GFXColorVertex &vert, float alpha )
44 {
45  if (alpha < 1) {
46  vert.r *= alpha;
47  vert.g *= alpha;
48  vert.b *= alpha;
49  }
50 }
51 
52 void Beam::Init( const Transformation &trans, const weapon_info &cln, void *own, Unit *firer )
53 {
54  //Matrix m;
55  CollideInfo.object.b = NULL;
56  CollideInfo.type = LineCollide::BEAM;
57  //DO NOT DELETE - shared vlist
58  //if (vlist)
59  //delete vlist;
60  local_transformation = trans; //location on ship
61  //cumalative_transformation =trans;
62  //trans.to_matrix (cumalative_transformation_matrix);
63  speed = cln.Speed;
64  texturespeed = cln.PulseSpeed;
65  range = cln.Range;
66  radialspeed = cln.RadialSpeed;
67  thickness = cln.Radius;
68  stability = cln.Stability;
69  rangepenalty = cln.Longrange;
70  damagerate = cln.Damage;
71  phasedamage = cln.PhaseDamage;
72  texturestretch = cln.TextureStretch;
73  refiretime = 0;
74  refire = cln.Refire();
75  Col.r = cln.r;
76  Col.g = cln.g;
77  Col.b = cln.b;
78  Col.a = cln.a;
79  impact = ALIVE;
80  owner = own;
81  numframes = 0;
82  static int radslices = XMLSupport::parse_int( vs_config->getVariable( "graphics", "tractor.scoop_rad_slices", "10" ) )|1; //Must be odd
83  static int longslices = XMLSupport::parse_int( vs_config->getVariable( "graphics", "tractor.scoop_long_slices", "10" ) );
84  lastlength = 0;
85  curlength = SIMULATION_ATOM*speed;
86  lastthick = 0;
87  curthick = SIMULATION_ATOM*radialspeed;
88  if (curthick > thickness) //clamp to max thickness - needed for large simulation atoms
89  curthick = thickness;
90  static GFXVertexList *_vlist = 0;
91  if (!_vlist) {
92  int numvertex = float_to_int( mymax( 48, ( (4*radslices)+1 )*longslices*4 ) );
93  GFXColorVertex *beam = new GFXColorVertex[numvertex]; //regretably necessary: radslices and longslices come from the config file... so it's at runtime.
94  memset( beam, 0, sizeof (*beam)*numvertex );
95  _vlist = new GFXVertexList( GFXQUAD, numvertex, beam, numvertex, true ); //mutable color contained list
96  delete[] beam;
97  }
98  //Shared vlist - we recalculate it every time, so no loss
99  vlist = _vlist;
100 #ifdef PERBOLTSOUND
101  AUDStartPlaying( sound );
102 #endif
103 }
104 
105 //NOTE: The order of the quad's vertices IS important - it ensures symmetric interpolation.
106 #define V( xx, yy, zz, ss, tt, aa ) \
107  do { \
108  beam[a].x = xx; \
109  beam[a].y = yy; \
110  beam[a].z = zz; \
111  beam[a].s = ss; \
112  beam[a].t = tt; \
113  beam[a].r = this->Col.r*aa; \
114  beam[a].g = this->Col.g*aa; \
115  beam[a].b = this->Col.b*aa; \
116  beam[a].a = 1.0f; \
117  a++; \
118  } \
119  while (0)
120 
121 void Beam::RecalculateVertices( const Matrix &trans )
122 {
123  GFXColorVertex *beam = ( vlist->BeginMutate( 0 ) )->colors;
124  static float fadelocation = XMLSupport::parse_float( vs_config->getVariable( "graphics", "BeamFadeoutLength", ".8" ) );
125  static float hitfadelocation =
126  XMLSupport::parse_float( vs_config->getVariable( "graphics", "BeamFadeoutHitLength", ".95" ) );
127  static float scoopangle =
128  //In radians - the /2 is because of the way in which we check against the cone.
129  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.scoop_fov", "0.5" ) )/2;
130  static float scooptanangle = (float) tan( scoopangle );
131  static bool scoop = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "tractor.scoop", "true" ) );
132  static float scoopa =
133  XMLSupport::parse_float( vs_config->getVariable( "graphics", "tractor.scoop_alpha_multiplier", "2.5" ) );
134  static int radslices =
135  XMLSupport::parse_int( vs_config->getVariable( "graphics", "tractor.scoop_rad_slices", "10" ) )|1; //Must be odd
136  static int longslices =
137  XMLSupport::parse_int( vs_config->getVariable( "graphics", "tractor.scoop_long_slices", "10" ) );
138  const float fadeinlength = 4;
139  const bool tractor = (damagerate < 0 && phasedamage > 0);
140  const bool repulsor = (damagerate > 0 && phasedamage < 0);
141  float leftex = -texturespeed*(numframes*SIMULATION_ATOM+interpolation_blend_factor*SIMULATION_ATOM);
142  float righttex = leftex+texturestretch*curlength/curthick; //how long compared to how wide!
143  float len = (impact == ALIVE)
144  ? (curlength < range ? curlength-speed*SIMULATION_ATOM*(1-interpolation_blend_factor) : range)
145  : curlength;
146  float fadelen = (impact == ALIVE) ? len*fadelocation : len*hitfadelocation;
147  const bool doscoop = ( scoop && (tractor || repulsor) );
148  float fadetex = leftex+(righttex-leftex)*fadelocation;
149  const float touchtex = leftex-fadeinlength*.5*texturestretch;
150  float thick = curthick != thickness ? curthick-radialspeed*SIMULATION_ATOM
151  *(1-interpolation_blend_factor) : thickness;
152  float ethick = ( thick/( (thickness > 0) ? thickness : 1.0f ) )*(doscoop ? curlength*scooptanangle : 0);
153  const float invfadelen = thick*fadeinlength;
154  const float invfadealpha = mymax( 0.0f, mymin( 1.0f, 1.0f-mysqr( invfadelen/len ) ) );
155  const float fadealpha = mymax( 0.0f, mymin( 1.0f, 1.0f-mysqr( fadelen/len ) ) );
156  const float endalpha = 0.0f;
157  const float peralpha = doscoop ? 0.25f : 0.0f;
158  int a = 0;
159  if (doscoop) {
160  //Do the volumetric thingy
161  Vector r( _Universe->AccessCamera()->GetR() );
162  Vector x( trans.getP() ), y( trans.getQ() ), z( trans.getR() );
163  r.Normalize();
164  x.Normalize();
165  y.Normalize();
166  z.Normalize();
167  const float xyalpha = mymax( 0, fabs( z*r ) );
168  const float xzalpha = mymax( 0, fabs( y*r ) )*0.5f;
169  const float yzalpha = mymax( 0, fabs( x*r ) )*0.5f;
170  const float lislices = (longslices > 0) ? 1.0f/longslices : 0.0f;
171  const float rislices = (radslices > 0) ? 1.0f/radslices : 0.0f;
172  const float bxyalpha = xyalpha*lislices;
173  const float bxzalpha = xzalpha*rislices;
174  const float byzalpha = yzalpha*rislices;
175  const float zs = lislices*(fadelen-invfadelen);
176  const float ths = lislices*ethick*1.2f;
177  const float rim1 = (radslices-1)*rislices*2;
178  for (int i = 0; i < longslices; i++) {
179  float f = i*lislices;
180  float xa = mymax( 0, 1.0f-mysqr( f ) )*byzalpha*scoopa;
181  float ya = mymax( 0, 1.0f-mysqr( f ) )*bxzalpha*scoopa;
182  float za = mymax( 0, 1.0f-mysqr( f ) )*bxyalpha*scoopa;
183  float th = f*ethick+thick;
184  float z = i*zs+invfadelen;
185  if (za > 0.03) {
186  V( -th, +th, z, 0, 0.5f, za );
187  V( -th, -th, z, 0, 0.0f, za );
188  V( +th, -th, z, 1, 0.0f, za );
189  V( +th, +th, z, 1, 0.5f, za );
190  }
191  if (i > 1) {
192  if (ya > 0.03) {
193  for (int j = -radslices/2; j <= radslices/2; j++) {
194  float y = j*2*th*rislices;
195  float f = 1.0f-fabs( rim1*j*rislices );
196  float sf = sqrt( f );
197  float aa = ya*f;
198  if (aa > 0.03) {
199  V( -(th+ths)*sf, y, z+zs, 1, 0.50f, aa );
200  V( -(th-ths)*sf, y, z-zs, 0, 0.50f, aa );
201  V( 0, y, z-zs, 0, 0.75f, aa );
202  V( 0, y, z+zs, 1, 0.75f, aa );
203  V( 0, y, z+zs, 1, 0.75f, aa );
204  V( 0, y, z-zs, 0, 0.75f, aa );
205  V( +(th-ths)*sf, y, z-zs, 0, 1.00f, aa );
206  V( +(th+ths)*sf, y, z+zs, 1, 1.00f, aa );
207  }
208  }
209  }
210  if (xa > 0.03) {
211  for (int j = -radslices/2; j <= radslices/2; j++) {
212  float x = j*2*th*rislices;
213  float f = 1.0f-fabs( rim1*j*rislices );
214  float sf = sqrt( f );
215  float aa = xa*f;
216  if (aa > 0.03) {
217  V( x, -(th+ths)*sf, z+zs, 1, 0.50f, aa );
218  V( x, -(th-ths)*sf, z-zs, 0, 0.50f, aa );
219  V( x, 0, z-zs, 0, 0.75f, aa );
220  V( x, 0, z+zs, 1, 0.75f, aa );
221  V( x, 0, z+zs, 1, 0.75f, aa );
222  V( x, 0, z-zs, 0, 0.75f, aa );
223  V( x, +(th-ths)*sf, z-zs, 0, 1.00f, aa );
224  V( x, +(th+ths)*sf, z+zs, 1, 1.00f, aa );
225  }
226  }
227  }
228  }
229  }
230  } else {
231  //main section
232  V( 0, 0, invfadelen, leftex, 0.5f, invfadealpha );
233  V( 0, thick, invfadelen, leftex, 1, peralpha*invfadealpha );
234  V( 0, thick, fadelen, fadetex, 1, peralpha*fadealpha );
235  V( 0, 0, fadelen, fadetex, 0.5f, fadealpha );
236  V( 0, 0, invfadelen, leftex, 0.5f, invfadealpha );
237  V( 0, 0, fadelen, fadetex, 0.5f, fadealpha );
238  V( 0, -thick, fadelen, fadetex, 0, peralpha*fadealpha );
239  V( 0, -thick, invfadelen, leftex, 0, peralpha*invfadealpha );
240  //fade out
241  V( 0, 0, fadelen, fadetex, 0.5f, fadealpha );
242  V( 0, thick, fadelen, fadetex, 1, peralpha*fadealpha );
243  V( 0, thick, len, righttex, 1, peralpha*endalpha );
244  V( 0, 0, len, righttex, 0.5f, endalpha );
245  V( 0, 0, fadelen, fadetex, 0.5f, fadealpha );
246  V( 0, 0, len, righttex, 0.5f, endalpha );
247  V( 0, -thick, len, righttex, 0, peralpha*endalpha );
248  V( 0, -thick, fadelen, fadetex, 0, peralpha*fadealpha );
249  //fade in
250  V( 0, 0, invfadelen, leftex, 0.5f, invfadealpha );
251  V( 0, thick, invfadelen, leftex, 1, peralpha*invfadealpha );
252  V( 0, thick, 0, touchtex, 1, peralpha );
253  V( 0, 0, 0, touchtex, 0.5f, 1.0f );
254  V( 0, 0, invfadelen, leftex, 0.5f, invfadealpha );
255  V( 0, 0, 0, touchtex, 0.5f, 1.0f );
256  V( 0, -thick, 0, touchtex, 0, peralpha );
257  V( 0, -thick, invfadelen, leftex, 0, peralpha*invfadealpha );
258  //copy and rotate xy plane
259  for (int i = 0, upto = a; i < upto; i++, a++) {
260  beam[a] = beam[i];
261  float aux = beam[a].x;
262  beam[a].x = beam[a].y;
263  beam[a].y = aux;
264  }
265  }
266  vlist->EndMutate( a );
267 }
268 
269 #undef V
270 
271 void Beam::RemoveFromSystem( bool eradicate )
272 {}
273 
275  const Matrix &m,
276  Unit *targ,
277  float tracking_cone,
278  Unit *targetToCollideWith,
279  float HeatSink,
280  Unit *firer,
281  Unit *superunit )
282 {
283  curlength += SIMULATION_ATOM*speed;
284  if (curlength < 0)
285  curlength = 0;
286  if (curlength > range)
287  curlength = range;
288  if (curthick == 0) {
289  if (AUDIsPlaying( sound ) && refiretime >= SIMULATION_ATOM)
290  AUDStopPlaying( sound );
291  refiretime += SIMULATION_ATOM*HeatSink;
292  return;
293  }
294  if (stability && numframes*SIMULATION_ATOM > stability)
295  impact |= UNSTABLE;
296  numframes++;
297  Matrix cumulative_transformation_matrix;
298  Transformation cumulative_transformation = local_transformation;
299  cumulative_transformation.Compose( trans, m );
300  cumulative_transformation.to_matrix( cumulative_transformation_matrix );
301  bool possible = AdjustMatrix( cumulative_transformation_matrix, Vector( 0, 0, 0 ), targ, speed, false, tracking_cone );
302  static bool firemissingautotrackers =
303  XMLSupport::parse_bool( vs_config->getVariable( "physics", "fire_missing_autotrackers", "true" ) );
304  if (targ && possible == false && !firemissingautotrackers)
305  Destabilize();
306  //to help check for crashing.
307  center = cumulative_transformation.position;
308  direction = TransformNormal( cumulative_transformation_matrix, Vector( 0, 0, 1 ) );
309 #ifndef PERFRAMESOUND
310  AUDAdjustSound( sound, cumulative_transformation.position, speed*cumulative_transformation_matrix.getR() );
311 #endif
312  curthick += (impact&UNSTABLE) ? -radialspeed*SIMULATION_ATOM : radialspeed*SIMULATION_ATOM;
313  if (curthick > thickness)
314  curthick = thickness;
315  if (curthick <= 0) {
316  curthick = 0; //die die die
317 #ifdef BEAMCOLQ
318  RemoveFromSystem( false );
319 #endif
320  } else {
321  CollideHuge( CollideInfo, listen_to_owner ? targetToCollideWith : NULL, firer, superunit );
322  if ( !(curlength <= range && curlength > 0) ) {
323  //if curlength just happens to be nan --FIXME THIS MAKES NO SENSE AT ALL --chuck_starchaser
324  if (curlength > range)
325  curlength = range;
326  else
327  curlength = 0;
328  }
329  QVector tmpvec( center+direction.Cast().Scale( curlength ) );
330  QVector tmpMini = center.Min( tmpvec );
331  tmpvec = center.Max( tmpvec );
332 #ifdef BEAMCOLQ
333  if ( TableLocationChanged( CollideInfo, tmpMini, tmpvec ) || (curthick > 0 && CollideInfo.object.b == NULL) ) {
334  RemoveFromSystem( false );
335 #endif
336  CollideInfo.object.b = this;
337  CollideInfo.hhuge =
338  ( ( (CollideInfo.Maxi.i
339  -CollideInfo.Mini.i)
340  /coltableacc )
341  *( (CollideInfo.Maxi.j-CollideInfo.Mini.j)/coltableacc )*(CollideInfo.Maxi.k-CollideInfo.Mini.k)/coltableacc
342  > tablehuge );
343  CollideInfo.Mini = tmpMini;
344  CollideInfo.Maxi = tmpvec;
345 #ifdef BEAMCOLQ
346  AddCollideQueue( CollideInfo );
347  } else {
348  CollideInfo.Mini = tmpMini;
349  CollideInfo.Maxi = tmpvec;
350  }
351 #endif
352  }
353  //Check if collide...that'll change max beam length REAL quick
354 }
355 
356 extern Cargo * GetMasterPartList( const char* );
357 
358 bool Beam::Collide( Unit *target, Unit *firer, Unit *superunit )
359 {
360  if (this == NULL || target == NULL) {
361  VSFileSystem::vs_fprintf( stderr, "Recovering from nonfatal beam error when beam inactive\n" );
362  return false;
363  }
364  float distance;
365  Vector normal; //apply shields
366 
367  QVector direction( this->direction.Cast() );
368  QVector end( center+direction.Scale( curlength ) );
369  enum clsptr type = target->isUnit();
370  if (target == owner || type == NEBULAPTR || type == ASTEROIDPTR) {
371  static bool collideroids =
372  XMLSupport::parse_bool( vs_config->getVariable( "physics", "AsteroidWeaponCollision", "false" ) );
373  if ( type != ASTEROIDPTR || (!collideroids) )
374  return false;
375  }
376  static bool collidejump = XMLSupport::parse_bool( vs_config->getVariable( "physics", "JumpWeaponCollision", "false" ) );
377  if ( type == PLANETPTR && (!collidejump) && !target->GetDestinations().empty() )
378  return false;
379  //A bunch of needed config variables - its best to have them here, so that they're loaded the
380  //very first time Collide() is called. That way, we avoid hiccups.
381  static float nbig = XMLSupport::parse_float( vs_config->getVariable( "physics", "percent_to_tractor", ".1" ) );
382  int upgradesfaction = FactionUtil::GetUpgradeFaction();
383  static int cargofaction = FactionUtil::GetFactionIndex( "cargo" );
384  static bool c_fp = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.cargo.force_push", "true" ) );
385  static bool c_fi = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.cargo.force_in", "true" ) );
386  static bool u_fp = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.upgrade.force_push", "true" ) );
387  static bool u_fi = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.upgrade.force_in", "true" ) );
388  static bool f_fp = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.faction.force_push", "true" ) );
389  static bool f_fi = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.faction.force_in", "true" ) );
390  static bool d_fp = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.disabled.force_push", "true" ) );
391  static bool d_fi = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.disabled.force_in", "true" ) );
392  static bool o_fp = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.others.force_push", "false" ) );
393  static bool o_fi = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.others.force_in", "false" ) );
394  static bool scoop = XMLSupport::parse_bool( vs_config->getVariable( "physics", "tractor.scoop", "true" ) );
395  static float scoopangle = XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.scoop_angle", "0.5" ) ); //In radians
396  static float scoopcosangle = (float) cos( scoopangle );
397  static float maxrelspeed =
398  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.max_relative_speed", "150" ) );
399  static float c_lighting =
400  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.cargo.light_shields_on_push", "1" ) );
401  static float u_lighting =
402  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.upgrade.light_shields_on_push", "1" ) );
403  static float f_lighting =
404  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.faction.light_shields_on_push", "1" ) );
405  static float d_lighting =
406  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.disabled.light_shields_on_push", "0" ) );
407  static float o_lighting =
408  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.others.light_shields_on_push", "1" ) );
409  static float c_ors_m =
410  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.cargo.distance_own_rsize", "1.5" ) );
411  static float c_trs_m =
412  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.cargo.distance_tgt_rsize", "1.1" ) );
413  static float c_o = XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.cargo.distance", "0" ) );
414  static float u_ors_m =
415  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.ugprade.distance_own_rsize", "1.5" ) );
416  static float u_trs_m =
417  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.upgrade.distance_tgt_rsize", "1.1" ) );
418  static float u_o = XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.upgrade.distance", "0" ) );
419  static float f_ors_m =
420  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.faction.distance_own_rsize", "2.2" ) );
421  static float f_trs_m =
422  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.faction.distance_tgt_rsize", "2.2" ) );
423  static float f_o = XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.faction.distance", "0" ) );
424  static float o_ors_m =
425  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.others.distance_own_rsize", "1.1" ) );
426  static float o_trs_m =
427  XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.others.distance_tgt_rsize", "1.1" ) );
428  static float o_o = XMLSupport::parse_float( vs_config->getVariable( "physics", "tractor.others.distance", "0" ) );
429  bool tractor = (damagerate < 0 && phasedamage > 0);
430  bool repulsor = (damagerate > 0 && phasedamage < 0);
431  if ( scoop && (tractor || repulsor) ) {
432  QVector d2( target->Position()-center );
433  d2.Normalize();
434  float angle = this->direction*d2;
435  if (angle > scoopcosangle) {
436  end = center+d2*curlength;
437  direction = end-center;
438  direction.Normalize();
439  }
440  }
441  Unit *colidee;
442  if ( ( colidee = target->rayCollide( center, end, normal, distance ) ) ) {
443  if ( !( scoop && (tractor || repulsor) ) ){
444  this->curlength = distance;
445  }
446  float curlength = distance;
447  impact |= IMPACT;
448  GFXColor coltmp( Col );
449  float tmp = (curlength/range);
450  float appldam = (damagerate*SIMULATION_ATOM*curthick/thickness)*( (1-tmp)+tmp*rangepenalty );
451  float phasdam = (phasedamage*SIMULATION_ATOM*curthick/thickness)*( (1-tmp)+tmp*rangepenalty );
452  float owner_rsize = superunit->rSize();
453  int owner_faction = superunit->faction;
454  if (tractor || repulsor) {
455  bool fp = o_fp, fi = o_fi;
456  if (target->faction == owner_faction)
457  fp = f_fp, fi = f_fi;
458 
459  else if (target->faction == upgradesfaction)
460  fp = u_fp, fi = u_fi;
461 
462  else if (target->faction == cargofaction)
463  fp = c_fp, fi = c_fi;
464 
465  else if (target->getAIState() == NULL)
466  fp = d_fp, fi = d_fi;
467  //tractor/repulsor beam!
468  if ( fp || target->isTractorable( Unit::tractorPush ) ) {
469  float lighting = o_lighting;
470  if (target->faction == owner_faction)
471  lighting = f_lighting;
472 
473  else if (target->faction == upgradesfaction)
474  lighting = u_lighting;
475 
476  else if (target->faction == cargofaction)
477  lighting = c_lighting;
478 
479  else if (target->getAIState() == NULL)
480  lighting = d_lighting;
481  //Compute relative speed - if it's higher than the maximum, don't accelerate it anymore
482  //FIXME: Should predict the resulting velocity after applying the force,
483  //and adjust the force to match the maximum relative velocity - but the
484  //heterogeneous physics granularity makes it quite hard (it's not owr
485  //own priority the one counting, but the target's).
486  //The current hack - using the target's sim_atom_multiplier, only prevents
487  //aberrations from becoming obvious, but it's not entirely correct.
488  float relspeed = target->GetVelocity()*direction.Cast();
489  if (relspeed < maxrelspeed) {
490  //Modulate force on little mass objects, so they don't slingshot right past you
491  target->ApplyForce( direction
492  *( appldam
493  /sqrt( (target->sim_atom_multiplier
494  > 0) ? target->sim_atom_multiplier : 1.0 )*mymin( 1, target->GetMass() ) ) );
495  }
496  }
497  float ors_m = o_ors_m, trs_m = o_trs_m, ofs = o_o;
498  if (target->faction == owner_faction)
499  ors_m = f_ors_m, trs_m = f_trs_m, ofs = f_o;
500 
501  else if (target->faction == upgradesfaction)
502  ors_m = u_ors_m, trs_m = u_trs_m, ofs = u_o;
503 
504  else if (target->faction == cargofaction)
505  ors_m = c_ors_m, trs_m = c_trs_m, ofs = c_o;
506  if ( ( fi
507  || target->isTractorable( Unit::tractorIn ) )
508  && ( ( center-target->Position() ).Magnitude() < (ors_m*owner_rsize+trs_m*target->rSize()+ofs) ) ) {
509  Unit *un = superunit;
510  if ( target->faction == upgradesfaction || owner_rsize*nbig > target->rSize() ) {
511  //we have our man!
512  //lets add our cargo to him
513  Cargo *c = GetMasterPartList( target->name.get().c_str() );
514  Cargo tmp;
515  bool isnotcargo = (c == NULL);
516  if (!isnotcargo)
517  if (c->GetCategory().find( "upgrades" ) == 0)
518  isnotcargo = true;
519  //add upgrades as space junk
520  if (isnotcargo) {
521  c = &tmp;
522  tmp.content = "Space_Salvage";
523  tmp.category = "Uncategorized_Cargo";
524  static float spacejunk = parse_float( vs_config->getVariable( "cargo", "space_junk_price", "10" ) );
525  tmp.price = spacejunk;
526  tmp.quantity = 1;
527  tmp.mass = .001;
528  tmp.volume = 1;
529  if (target->faction != upgradesfaction) {
530  tmp.content = target->name;
531  tmp.category = "starships";
532  static float starshipprice =
533  XMLSupport::parse_float( vs_config->getVariable( "cargo", "junk_starship_price", "100000" ) );
534  static float starshipmass =
535  XMLSupport::parse_float( vs_config->getVariable( "cargo", "junk_starship_mass", "50" ) );
536  static float starshipvolume =
537  XMLSupport::parse_float( vs_config->getVariable( "cargo", "junk_starship_volume", "1500" ) );
538  tmp.price = starshipprice;
539  tmp.quantity = 1;
540  tmp.mass = starshipmass;
541  tmp.volume = starshipvolume;
542  }
543  }
544  if (c != NULL) {
545  Cargo adder = *c;
546  adder.quantity = 1;
547  if ( un->CanAddCargo( adder ) ) {
548  un->AddCargo( adder );
549  if ( _Universe->isPlayerStarship( un ) ) {
550  static int tractor_onboard =
551  AUDCreateSoundWAV( vs_config->getVariable( "unitaudio", "player_tractor_cargo",
552  "tractor_onboard.wav" ) );
553  AUDPlay( tractor_onboard, QVector( 0, 0, 0 ), Vector( 0, 0, 0 ), 1 );
554  } else {
555  Unit *tmp = _Universe->AccessCockpit()->GetParent();
556  if (tmp && tmp->owner == un) {
557  //Subunit of player (a turret)
558  static int tractor_onboard_fromturret =
559  AUDCreateSoundWAV( vs_config->getVariable( "unitaudio",
560  "player_tractor_cargo_fromturret",
561  "tractor_onboard.wav" ) );
562  AUDPlay( tractor_onboard_fromturret, QVector( 0, 0, 0 ), Vector( 0, 0, 0 ), 1 );
563  }
564  }
565  target->Kill();
566  }
567  }
568  }
569  }
570  } else {
571  target->ApplyDamage( center.Cast()+direction*curlength, normal, appldam, colidee, coltmp, owner, phasdam );
572  }
573  return true;
574  }
575  return false;
576 }
577