Rise
The Vieneo Province
propulsion.cpp
Go to the documentation of this file.
1 #include "propulsion.h"
2 
3 #include "Viewscreen.h"
4 #include "../MathUtilities.h"
5 
6 #include <fcntl.h> // For _O_RDWR, _O_BINARY, _O_RDONLY, O_TEXT
7 #include <sys/stat.h> // For _S_IWRITE, _S_IREAD
8 #include "../Dialogs/InformationDialog.h"
9 
11 {
12  viewscreen = ptr;
13  logger = ptr->logger;
14 
15  logger->Log("propulsion::ctor");
16 
17  gndcontactG = 0.0f;
18  halfsec = 0.0f;
19  oldmsl = f_MSL;
20  oldagl = f_AGL;
21  ambtype1 = PlotType::NotZoned;
22  ambtype2 = -1;
23  oldvol = 1.0f;
24  chip = -1;
25  tach = 0.0f;
26  actual = centerC;
27  trendup = false;
28  intensity = 0.0f;
29  windgust = centerC;
30  olddesiredvsi = 0.0f;
31  oldpitch = 0.0f;
32  oldcorrection = 0.0f;
33  rougfric = 0.0f;
34  f_netupdate = 0.0f;
35 
36  oldOdoPosition = centerC; // flag to initialize for odometer tracking
37  oldOdoReference = 0; // will be initialized with above
38 
39  msg[0] = 0;
40  for (int i = 0; i < MAX_ENGINES; i++)
41  {
42  ThrustReverserOutput[i] = 0.0f;
43  EngineThrustOutput[i] = 0.0f;
44  }
45 }
46 
47 float propulsion::CalculateLiftCoefficient(AirfoilType type, float aoaRad, float CLDelta)
48 {
49  if (type == AirfoilType::Asymm)
50  {
51  if (fabsf(aoaRad) < 0.2618f)
52  return aoaRad / 0.2618f * 1.575f + 0.35f + CLDelta;
53  }
54  else if (type == AirfoilType::Symm)
55  {
56  if (fabsf(aoaRad) < 0.2094395102f)
57  return aoaRad / 0.2094395102f * 1.2f + CLDelta;
58  }
59 
60  return 0.0f; // stalled
61 
62  //float x = D3DXToDegree(aoa);
63  //if (x < -8.25f || x > 11.25f)
64  // return 0.0f; // stalled
65 
67  //float y = -0.01904908f + 0.1058976f*x + powf(0.009139439f*x, 2.0f) - powf(0.0002088268f*x, 3.0f) - powf(0.00006616284f*x, 4.0f);
68  //return y * 1.4f + flapsDelta;
69 }
70 
71 float propulsion::CalculateDragCoefficient(AirfoilType type, float aoa, float CDDelta)
72 {
73  //if (type == AirfoilType::Asymm)
74  //{
76  float x = fmodf(fabsf(D3DXToDegree(aoa)), 180.0f);
77  float y = powf((sinf((x - 1.5708f) * .018f) * 0.5f + 0.5f), 4.8f) * 1.37f - 0.02f;
78  return min(1.35f, y + CDDelta);
79  //}
80  //else
81  //{
82  // return 0.0f;
83  //}
84 }
85 
86 void propulsion::GetFrictionCoefficients(const unsigned char type, float* rollingResistance, float* roughness)
87 {
88  switch (type)
89  {
90  case 0: *rollingResistance += 0.149252459f; *roughness += 0.140034499f; break;
91  case 1: *rollingResistance += 3.0f; break;
92  case 2: *rollingResistance += 0.155294699f; *roughness += 0.110395962f; break;
93  case 3: *rollingResistance += 0.19890972f; *roughness += 0.075400626f; break;
94  case 4: *rollingResistance += 0.3f; *roughness += 0.279197232f; break;
95  case 5: *rollingResistance += 0.188024219f; *roughness += 0.16794517f; break;
96  case 6: *rollingResistance += 0.142987307f; *roughness += 0.036592876f; break;
97  case 7: *rollingResistance += 0.164080576f; *roughness += 0.041991001f; break;
98  case 8: *rollingResistance += 0.137754924f; *roughness += 0.089029615f; break;
99  case 9: *rollingResistance += 0.252407802f; *roughness += 0.250432014f; break;
100  case 10: *rollingResistance += 0.031694275f; *roughness += 0.010107074f; break;
101  case 11: *rollingResistance += 0.117426575f; *roughness += 0.110174209f; break;
102  case 12: *rollingResistance += 0.143053466f; *roughness += 0.089767837f; break;
103  case 13: *rollingResistance += 0.095765193f; *roughness += 0.018145682f; break;
104  case 14: *rollingResistance += 0.18167668f; *roughness += 0.059555865f; break;
105  case 15: *rollingResistance += 0.090375496f; *roughness += 0.039227343f; break;
106  case 16: *rollingResistance += 0.0462223f; *roughness += 0.004436346f; break;
107  case 17: *rollingResistance += 0.139361155f; *roughness += 0.109465749f; break;
108  case 18: *rollingResistance += 0.243311063f; *roughness += 0.189429028f; break;
109  case 19: *rollingResistance += 0.244358393f; *roughness += 0.214655836f; break;
110  case 20: *rollingResistance += 0.110182991f; *roughness += 0.023593817f; break;
111  case 21: *rollingResistance += 0.172887321f; *roughness += 0.092974959f; break;
112  case 22: *rollingResistance += 0.251099364f; *roughness += 0.204277683f; break;
113  case 23: *rollingResistance += 0.153308566f; *roughness += 0.124721617f; break;
114  case 24: *rollingResistance += 0.014f; *roughness += 0.002153018f; break;
115  case 25: *rollingResistance += 0.18702122f; *roughness += 0.04422358f; break;
116  case 26: *rollingResistance += 0.142394658f; *roughness += 0.069383043f; break;
117  case 27: *rollingResistance += 0.188285943f; *roughness += 0.127695657f; break;
118  case 28: *rollingResistance += 0.065420895f; *roughness += 0.026730762f; break;
119  case 29: *rollingResistance += 0.152859968f; *roughness += 0.100728901f; break;
120  case 30: *rollingResistance += 0.240485841f; *roughness += 0.211254006f; break;
121  case 31: *rollingResistance += 0.080389436f; *roughness += 0.01810045f; break;
122  }
123 }
124 
125 void propulsion::Update(float fElapsedTime)
126 {
127  logger->AddToCallStack("propulsion::Update");
128 
129  D3DXQUATERNION quaternionTemp;
130  D3DXMATRIX matrixInverse, matrixTemp;
131  D3DXVECTOR3 result, cross;
132  float f_temp;
133 
134  // reset
136 
137  const float iceLoad = 8.0f * ourcockpit.i12WingAreaOneSideSqFt * 2.0f * iceAccumulationMm / 25.4f; // 8 pounds per square ft of wing per inch (25.4 mm) of thickness
138  totalWeightLbs = ourcockpit.emptyWeightLbs + fuel + payload + iceLoad; // in pounds
140  {
141  logger->Log("weightC was calculated to be below the ourcockpit.emptyweight!", Logger::Level::Error);
143  }
144 
145  viewscreen->AssertTelemetry("Propulsion::Update1", 0);
146 
147  // for our speed relative to ground for cloud fog effects
148  D3DXVec3Subtract(&locvelcomp, &playerships[0].velocity, &playerships[0].barycentric);
149 
150 
151  // TURN TURN TURN -------------------------------------------------------------------------------
153  {
154  D3DXQuaternionRotationYawPitchRoll(&quaternionTemp, playerships[0].yaw * fElapsedTime, playerships[0].pitch * fElapsedTime, playerships[0].roll * fElapsedTime);
155  D3DXQuaternionMultiply(&playerships[0].orientation, &playerships[0].orientation, &quaternionTemp);
156  }
157 
158  D3DXQuaternionNormalize(&playerships[0].orientation, &playerships[0].orientation);
159  D3DXMatrixRotationQuaternion(&matrixInverse, &playerships[0].orientation);
160  D3DXMatrixInverse(&playerships[0].matrixWorld, nullptr, &matrixInverse);
161  // TURN TURN TURN -------------------------------------------------------------------------------
162 
163 
165  {
166 #pragma region debug
167  if (matrixInverse._11 > 1000.0f || matrixInverse._11 < -1000.0f || _isnan(matrixInverse._11) || isinf(matrixInverse._11) ||
168  matrixInverse._12 > 1000.0f || matrixInverse._12 < -1000.0f || _isnan(matrixInverse._12) || isinf(matrixInverse._12) ||
169  matrixInverse._13 > 1000.0f || matrixInverse._13 < -1000.0f || _isnan(matrixInverse._13) || isinf(matrixInverse._13) ||
170  matrixInverse._14 > 1000.0f || matrixInverse._14 < -1000.0f || _isnan(matrixInverse._14) || isinf(matrixInverse._14))
171  {
172  sprintf_s(msg, sizeof(msg), "Trapped a violation after world matrix calculation...");
173  logger->Log(msg, Logger::Level::Error);
174  }
175  if (matrixInverse._21 > 1000.0f || matrixInverse._21 < -1000.0f || _isnan(matrixInverse._21) || isinf(matrixInverse._21) ||
176  matrixInverse._22 > 1000.0f || matrixInverse._22 < -1000.0f || _isnan(matrixInverse._22) || isinf(matrixInverse._22) ||
177  matrixInverse._23 > 1000.0f || matrixInverse._23 < -1000.0f || _isnan(matrixInverse._23) || isinf(matrixInverse._23) ||
178  matrixInverse._24 > 1000.0f || matrixInverse._24 < -1000.0f || _isnan(matrixInverse._24) || isinf(matrixInverse._24))
179  {
180  sprintf_s(msg, sizeof(msg), "Trapped a violation after world matrix calculation...");
181  logger->Log(msg, Logger::Level::Error);
182  }
183  if (matrixInverse._31 > 1000.0f || matrixInverse._31 < -1000.0f || _isnan(matrixInverse._31) || isinf(matrixInverse._31) ||
184  matrixInverse._32 > 1000.0f || matrixInverse._32 < -1000.0f || _isnan(matrixInverse._32) || isinf(matrixInverse._32) ||
185  matrixInverse._33 > 1000.0f || matrixInverse._33 < -1000.0f || _isnan(matrixInverse._33) || isinf(matrixInverse._33) ||
186  matrixInverse._34 > 1000.0f || matrixInverse._34 < -1000.0f || _isnan(matrixInverse._34) || isinf(matrixInverse._34))
187  {
188  sprintf_s(msg, sizeof(msg), "Trapped a violation after world matrix calculation...");
189  logger->Log(msg, Logger::Level::Error);
190  }
191  if (matrixInverse._41 > 1000.0f || matrixInverse._41 < -1000.0f || _isnan(matrixInverse._41) || isinf(matrixInverse._41) ||
192  matrixInverse._42 > 1000.0f || matrixInverse._42 < -1000.0f || _isnan(matrixInverse._42) || isinf(matrixInverse._42) ||
193  matrixInverse._43 > 1000.0f || matrixInverse._43 < -1000.0f || _isnan(matrixInverse._43) || isinf(matrixInverse._43) ||
194  matrixInverse._44 > 1000.0f || matrixInverse._44 < -1000.0f || _isnan(matrixInverse._44) || isinf(matrixInverse._44))
195  {
196  sprintf_s(msg, sizeof(msg), "Trapped a violation after world matrix calculation...");
197  logger->Log(msg, Logger::Level::Error);
198  }
199 #pragma endregion
200  }
201 
202  // Velocity must save after turning
203  // &velocity is now our ship-axis-oriented velocity
204  D3DXVec3TransformNormal(&velocity, &playerships[0].velocity, &matrixInverse);
205 
206  D3DXVECTOR3 Tdockingvel;
207  if (playerships[0].reference >= REF_INANOTHER)
208  D3DXVec3TransformNormal(&Tdockingvel, &playerships[0].dockingvel, &matrixInverse);
209 
211  {
212  // Acceleration twice per second?, must be compared after turning
213  halfsec += fElapsedTime;
214  if (halfsec > 0.5f && f_MSL != -1.0f)
215  {
216  // for VSI
217  const float oldgroundspeed = groundSpeedKms;
220  result = oldvelocity - playerships[0].barycentric; // in km/s
221  f_temp = D3DXVec3Length(&result);
223  if (f_temp > 0.0f)
224  grounditerate = (sqrtf(f_temp) - oldgroundspeed) * 0.5f;
225  else
226  grounditerate = -oldgroundspeed * 0.5f;
227 
228  oldmsl = f_MSL;
229  oldagl = f_AGL;
230 
232 
233  halfsec = 0.0f;
234  }
235 
236  groundSpeedKms += grounditerate * fElapsedTime;
238 
239 
240  logger->AddToCallStack("EnvironmentalSounds");
241 
242 #pragma region Environmental Sound Effects (like waves and extractors)
244  {
245  PlotType newambtype;
246  char newambtype2;
247  float newvolume;
248 
249  result = playerships[0].position;
250  // mining, farming, and industrial for now
251  if ((gridarray[31][31].type == PlotType::UserMining || gridarray[31][31].type == PlotType::UserFarming || gridarray[31][31].type == PlotType::DeoisIndustrial)
252  && gridarray[31][31].powered)
253  newambtype = gridarray[31][31].type;
254  else
255  newambtype = PlotType::NotZoned;
256  if ((gridarray[31][31].pri_transition != 0 || gridarray[31][31].sec_transition != 0) &&
257  (gridarray[31][31].pri_landform == 1 || gridarray[31][31].sec_landform == 1 || gridarray[31][31].ter_landform == 1))
258  newambtype2 = 6; // beach
259  else
260  newambtype2 = 0;
261 
262  result += (gridarray[31][31].position + gridarray[32][32].position) * 0.5f; // center
263  f_temp = D3DXVec3Length(&result);
264  // sprintf_s(msg, sizeof(msg), "Mine: %.3f km away", f_temp);
265  // _write(logfile, msg, strlen(msg));
266  if (f_temp < 1.0f) // 1km away
267  {
268  newvolume = powf(f_temp, 2.0f); // 0 close 1 far away
269  newvolume = 1.0f - newvolume;
270  newvolume *= staticDensity;
271  newvolume *= viewscreen->gameclass->sound->GetAttenuation(false);
272  }
273  else
274  newvolume = 0.0f;
275 
276  if (newambtype != ambtype1 || newambtype2 != ambtype2 || newvolume != oldvol)
277  {
278  if (newambtype == PlotType::UserMining)
279  viewscreen->gameclass->sound->PlayEx(SOUND_MINING, true, newvolume);
280  else
282  if (newambtype == PlotType::UserFarming) // farm
283  viewscreen->gameclass->sound->PlayEx(SOUND_FARMING, true, newvolume);
284  else
286  if (newambtype == PlotType::DeoisIndustrial)
287  viewscreen->gameclass->sound->PlayEx(SOUND_INDUSTRIAL, true, newvolume);
288  else
290  if (newambtype2 == 6)
291  viewscreen->gameclass->sound->PlayEx(SOUND_SHORE, true, newvolume);
292  else
294 
295  ambtype1 = newambtype;
296  ambtype2 = newambtype2;
297  oldvol = newvolume;
298  }
299  }
300 #pragma endregion
301 
302 
303  logger->AddToCallStack("StraightAheadVector");
304 
305  // Straight ahead vector
306  result.x = 0.0f; result.y = 0.0f; result.z = -1.0f; // local
307  D3DXVec3TransformNormal(&viewscreen->headlightvec, &result, &playerships[0].matrixWorld); // Find straight ahead vector, world coord
308 
309  D3DXVECTOR4 result4;
310  result4.x = viewscreen->headlightvec.x; result4.y = viewscreen->headlightvec.y; result4.z = viewscreen->headlightvec.z;
311  if (playerships[0].headlight && ourcockpit.power > 0.5f)
312  result4.w = 1.0f;
313  else
314  result4.w = 0.0f;
315  logger->AddToCallStack("SettingSpotDir");
316  if (_isnan(result4.x) || _isnan(result4.y) || _isnan(result4.z) || isinf(result4.x) || isinf(result4.y) || isinf(result4.z))
317  logger->Log("Ha! It was the SettingSpotDir with NAN values!", Logger::Level::Error);
318  else
319  {
320  try
321  {
322  HRESULT hr;
323  V(viewscreen->gameclass->graphics->g_pEffect->SetVector("SpotDir", &result4));
324  }
325  catch (...)
326  {
327  logger->Log("Exception thrown on ID3DXEffect->SetVector", Logger::Level::Error);
329  logger->Log("-- viewscreen->gameclass->graphics->g_pEffect is not null", Logger::Level::Error);
330  else
331  logger->Log("-- viewscreen->gameclass->graphics->g_pEffect IS NULL", Logger::Level::Error);
332  sprintf_s(msg, sizeof(msg), "-- result4 %f %f %f %f", result4.x, result4.y, result4.z, result4.w);
333  logger->Log(msg, Logger::Level::Error);
334  }
335 
336  logger->AddToCallStack("Calc for SetLight(1)");
337 
338  D3DXVec3TransformNormal(&result, &ourcockpit.headlight, &playerships[0].matrixWorld); // Find straight ahead vector
339  viewscreen->headlight.Position = -result;
340  viewscreen->headlight.Direction = viewscreen->headlightvec; // Headlight shines dead ahead, world coord
341  if (playerships[0].headlight)
342  {
343  logger->AddToCallStack("SetLight(1)");
345  DXUTGetD3D9Device()->SetLight(1, &viewscreen->headlight);
346  }
347  }
348 
349  } // flightfreeze
350 
351 
352  // so we moved some stuff out like weather, temperature and wind speed
353 
354  logger->AddToCallStack("GroundVecPropulsion");
355 
356  D3DXVECTOR3 groundvec, barycentric;
357  // Need to convert barycentric velocity to ship oriented axis velocity
358  D3DXVec3TransformCoord(&barycentric, &playerships[0].barycentric, &matrixInverse);
359  // Adjust the ship oriented axis velocity by the barycentric ship oriented axis velocity
360  D3DXVec3Subtract(&groundvec, &barycentric, &velocity);
361 
362 #pragma region debug
363  if (groundvec.x > 100.0f || groundvec.x < -100.0f || _isnan(groundvec.x) || isinf(groundvec.x) ||
364  groundvec.y>100.0f || groundvec.y < -100.0f || _isnan(groundvec.y) || isinf(groundvec.y) ||
365  groundvec.z>100.0f || groundvec.z < -100.0f || _isnan(groundvec.z) || isinf(groundvec.z) ||
366  _isnan(barycentric.x) || _isnan(barycentric.y) || _isnan(barycentric.z) ||
367  isinf(barycentric.x) || isinf(barycentric.y) || isinf(barycentric.z))
368  {
369  sprintf_s(msg, sizeof(msg), "\tbarycentric I: %f", barycentric.x);
370  logger->Log(msg, Logger::Level::Debug);
371  sprintf_s(msg, sizeof(msg), "\tbarycentric J: %f", barycentric.y);
372  logger->Log(msg, Logger::Level::Debug);
373  sprintf_s(msg, sizeof(msg), "\tbarycentric K: %f", barycentric.z);
374  logger->Log(msg, Logger::Level::Debug);
375  sprintf_s(msg, sizeof(msg), "\tvelocity I: %f", velocity.x);
376  logger->Log(msg, Logger::Level::Debug);
377  sprintf_s(msg, sizeof(msg), "\tvelocity J: %f", velocity.y);
378  logger->Log(msg, Logger::Level::Debug);
379  sprintf_s(msg, sizeof(msg), "\tvelocity K: %f", velocity.z);
380  logger->Log(msg, Logger::Level::Debug);
381  sprintf_s(msg, sizeof(msg), "\tour barycentric I: %f", playerships[0].barycentric.x);
382  logger->Log(msg, Logger::Level::Debug);
383  sprintf_s(msg, sizeof(msg), "\tour barycentric J: %f", playerships[0].barycentric.y);
384  logger->Log(msg, Logger::Level::Debug);
385  sprintf_s(msg, sizeof(msg), "\tour barycentric K: %f", playerships[0].barycentric.z);
386  logger->Log(msg, Logger::Level::Debug);
387  sprintf_s(msg, sizeof(msg), "Trapped a violation after groundvec calculation...");
388  logger->Log(msg, Logger::Level::Fatal);
389  }
390 #pragma endregion
391 
392 
393  logger->AddToCallStack("WindDirection");
394 
395  D3DXVECTOR3 windDirectionOnly;
396  D3DXVECTOR3 negPosNormal = -viewscreen->posnorml;
397  D3DXMatrixRotationAxis(&matrixTemp, &negPosNormal, viewscreen->ptrWeather->GetWindDirectionRadians());
398  D3DXVec3TransformNormal(&windDirectionOnly, &viewscreen->compassnorth, &matrixTemp);
399 
400  // this is a vector that is why we are modulating with wind dir
401  windVectorTrueKms = viewscreen->ptrWeather->GetWindspeedKms() * windDirectionOnly;
402 
403  if (windVectorTrueKms.x > 100.0f || windVectorTrueKms.x < -100.0f || _isnan(windVectorTrueKms.x) || isinf(windVectorTrueKms.x) ||
404  windVectorTrueKms.y > 100.0f || windVectorTrueKms.y < -100.0f || _isnan(windVectorTrueKms.y) || isinf(windVectorTrueKms.y) ||
405  windVectorTrueKms.z > 100.0f || windVectorTrueKms.z < -100.0f || _isnan(windVectorTrueKms.z) || isinf(windVectorTrueKms.z))
406  {
407  sprintf_s(msg, sizeof(msg), "Trapped a violation when windspeed was calculated...");
408  logger->Log(msg, Logger::Level::Error);
409  sprintf_s(msg, sizeof(msg), "\twindspeed: %f", viewscreen->ptrWeather->GetWindspeedKms());
410  logger->Log(msg, Logger::Level::Error);
411  sprintf_s(msg, sizeof(msg), "\tturbulence: %f", viewscreen->ptrWeather->GetTurbulence());
412  logger->Log(msg, Logger::Level::Error);
413  sprintf_s(msg, sizeof(msg), "\twinddir I: %f", windDirectionOnly.x);
414  logger->Log(msg, Logger::Level::Error);
415  sprintf_s(msg, sizeof(msg), "\twinddir J: %f", windDirectionOnly.y);
416  logger->Log(msg, Logger::Level::Error);
417  sprintf_s(msg, sizeof(msg), "\twinddir K: %f", windDirectionOnly.z);
418  logger->Log(msg, Logger::Level::Error);
419  }
420 
421 #ifdef _DEBUG
422  //viewscreen->ptrWeather->turbulence = 1.0f;
423  //viewscreen->ptrWeather->windspeed = 0.041f; // half full
424  //if (viewscreen->gameclass->GUI->IsAdmin)
425  // viewscreen->ptrWeather->turbulence = 1.0f;
426 #endif
427 
428  if (playerships[0].reference != REF_BUILDING && playerships[0].reference != REF_SIMBAY && playerships[0].reference != REF_INANOTHER)
429  {
430  if (f_MSL != -1.0f) // Hold off until altitude is calculated
431  {
432  // as of 5/23/2018 we take into account density adjustment based on temperature too! this is really called "delta"
433  staticDensity = expf(-fabsf(f_MSL) / ScaleHeightC) * 288.15f / (viewscreen->ptrWeather->GetTemperatureCelsius() + 273.15f);
434  }
435  else
436  {
437  staticDensity = 1.0f;
438  }
439  }
440  else
441  {
442  staticDensity = 1.0f;
443  }
444 
445 
446  // @bug https://jira.risetvp.com/view.php?id=1727
447  float machWaveEffect;
448  if (mach <= 1.0f)
449  machWaveEffect = powf(mach, 12.622f);
450  else
451  machWaveEffect = 1.0f / ((powf(mach + 0.169f, 2.0f) - 1.0f) * 2.73f);
453 
454 
455  logger->AddToCallStack("MoreWindTurbulenceCrap");
456 
457  // turbulence 2.0 ... we are doing aeroelastic approach still but should result in upwards of 0.6 G
458  // severe (1) changes 8 times per second ... none (0) is never or 0 per second ... at .5 it is every 2 seconds
459  // actually this is probably in part based on speed?
460  // because on the ground a gust is considered a 3 second ... so say 500 knots would be 0.125 seconds, 0 knots is 3 seconds
461  if (viewscreen->ptrWeather->GetTurbulence() > 0)
462  {
463  const float penetrationSpeed = D3DXVec3Length(&relativeWindTrueKms);
464  const float turbChange = 0.125f / powf(viewscreen->ptrWeather->GetTurbulence(), 2.0f) + 2.875f - 2.875f * sqrtf(min(penetrationSpeed, 0.05f) / 0.05f);
465  if (intensity == 0.0f && rand() % max(1, static_cast<int>(60.0f * fElapsedTime * turbChange * 10.0f)) == 0)
466  {
467  trendup = true;
468  // lerp between OLD gust and NEW gust so we can get rid of the 10.0 above and keep us around .6 G +/-
469  windgust.x = -1.0f + RandomFloat() * 2.0f;
470  windgust.y = -1.0f + RandomFloat() * 2.0f;
471  windgust.z = -1.0f + RandomFloat() * 2.0f;
472  D3DXVec3Normalize(&windgust, &windgust);
473  D3DXVec3Lerp(&windgust, &windDirectionOnly, &windgust, viewscreen->ptrWeather->GetTurbulence());
474  D3DXVec3Normalize(&windgust, &windgust);
475  windgust *= 0.5f * 0.0302222f * viewscreen->ptrWeather->GetTurbulence() * RandomFloat();// *viewscreen->ptrWeather->windspeed / 0.08277758256f;
476 
477  // so new direction of gust in 3 dimensions from our current direction
478 
479  // but if on ground then we don't get from above and below so much
480  // groundeffect
481  // slewing of that direction randomly based on severity
482  // intensity of gust
483  }
484 
485  // until 6/5/2019 this section wasn't working at all because rate was always 0!
486  if (trendup)
487  {
488  // so at 1 we want .3 and at 0 we want 9999
489  // (1-turbulence)
490  intensity += fElapsedTime / turbChange * 0.5f;
491  if (intensity > 1.0f)
492  {
493  intensity = 1.0f;
494  trendup = false;
495  }
496  }
497  else
498  {
499  intensity -= fElapsedTime / turbChange * 0.5f;
500  if (intensity < 0.0f)
501  intensity = 0.0f;
502  }
503 
504  // lerp wind to direction/magnitude of nominal value
506  if (windVectorTrueKms.x > 100.0f || windVectorTrueKms.x < -100.0f || _isnan(windVectorTrueKms.x) || isinf(windVectorTrueKms.x) ||
507  windVectorTrueKms.y > 100.0f || windVectorTrueKms.y < -100.0f || _isnan(windVectorTrueKms.y) || isinf(windVectorTrueKms.y) ||
508  windVectorTrueKms.z > 100.0f || windVectorTrueKms.z < -100.0f || _isnan(windVectorTrueKms.z) || isinf(windVectorTrueKms.z))
509  {
510  sprintf_s(msg, sizeof(msg), "Trapped a violation after windspeed added gust factor...");
511  logger->Log(msg, Logger::Level::Error);
512  sprintf_s(msg, sizeof(msg), "\twindgust I: %f", windgust.x);
513  logger->Log(msg, Logger::Level::Error);
514  sprintf_s(msg, sizeof(msg), "\twindgust J: %f", windgust.y);
515  logger->Log(msg, Logger::Level::Error);
516  sprintf_s(msg, sizeof(msg), "\twindgust K: %f", windgust.z);
517  logger->Log(msg, Logger::Level::Error);
518  sprintf_s(msg, sizeof(msg), "\tintensity: %f", intensity);
519  logger->Log(msg, Logger::Level::Error);
520  }
521  }
523 
524  D3DXVECTOR3 localWindVector;
525  D3DXVec3TransformCoord(&localWindVector, &windVectorTrueKms, &matrixInverse); // makes it ship oriented
526 
527 #pragma region debug
528  if (localWindVector.x > 100.0f || localWindVector.x < -100.0f || _isnan(localWindVector.x) || isinf(localWindVector.x) ||
529  localWindVector.y > 100.0f || localWindVector.y < -100.0f || _isnan(localWindVector.y) || isinf(localWindVector.y) ||
530  localWindVector.z > 100.0f || localWindVector.z < -100.0f || _isnan(localWindVector.z) || isinf(localWindVector.z))
531  {
532  sprintf_s(msg, sizeof(msg), "Trapped a violation after windspeed transformed by inverse matrix...");
533  logger->Log(msg, Logger::Level::Error);
534  }
535 #pragma endregion
536 
537  logger->AddToCallStack("RelativeWindCalculation");
538 
539  relativeWindTrueKms = groundvec + localWindVector;
540 
541 #pragma region debug
542  if (relativeWindTrueKms.x > 100.0f || relativeWindTrueKms.x < -100.0f || _isnan(relativeWindTrueKms.x) || isinf(relativeWindTrueKms.x) ||
543  relativeWindTrueKms.y > 100.0f || relativeWindTrueKms.y < -100.0f || _isnan(relativeWindTrueKms.y) || isinf(relativeWindTrueKms.y) ||
544  relativeWindTrueKms.z > 100.0f || relativeWindTrueKms.z < -100.0f || _isnan(relativeWindTrueKms.z) || isinf(relativeWindTrueKms.z))
545  {
546  sprintf_s(msg, sizeof(msg), "Trapped a violation after wind calculation...");
547  logger->Log(msg, Logger::Level::Error);
548  sprintf_s(msg, sizeof(msg), "\tdensity: %f", staticDensity);
549  logger->Log(msg, Logger::Level::Error);
550  sprintf_s(msg, sizeof(msg), "\tgroundvec I: %f", groundvec.x);
551  logger->Log(msg, Logger::Level::Error);
552  sprintf_s(msg, sizeof(msg), "\tgroundvec J: %f", groundvec.y);
553  logger->Log(msg, Logger::Level::Error);
554  sprintf_s(msg, sizeof(msg), "\tgroundvec K: %f", groundvec.z);
555  logger->Log(msg, Logger::Level::Error);
556  sprintf_s(msg, sizeof(msg), "\tlocalWindVector I: %f", localWindVector.x);
557  logger->Log(msg, Logger::Level::Error);
558  sprintf_s(msg, sizeof(msg), "\tlocalWindVector J: %f", localWindVector.y);
559  logger->Log(msg, Logger::Level::Error);
560  sprintf_s(msg, sizeof(msg), "\tlocalWindVector K: %f", localWindVector.z);
561  logger->Log(msg, Logger::Level::Fatal);
562  deathinhibit = 15.0f;
563  dead = 8; // vessel has a problem
564  return;
565  }
566 #pragma endregion
567 
569 
570  logger->AddToCallStack("PropulsionSection");
571 
572  // Propulsion section ---------------------------------------------------------------------------
573  if (playerships[0].reference != REF_BUILDING && playerships[0].reference != REF_SIMBAY)
574  {
575  D3DXVECTOR3 relativel;
576 
577  logger->AddToCallStack("CurrentRelativeVelocity");
578 
579  // Current relative velocity
580  if (viewscreen->gameclass->bus->AFCS.TvmOn) // Target velocity match
581  {
582  if (viewscreen->gameclass->bus->targetC == -1) // User waypoint, ground reference
583  {
584  relativel = playerships[0].barycentric;
585  }
586  else if (viewscreen->gameclass->bus->targetC >= 0) // ship in contact list
587  {
590  if (network_objects.reference == REF_INANOTHER && network_objects.inarray == 0)
591  viewscreen->gameclass->LostScannerTarget("Propulsion");
592  else if (network_objects.reference < REF_INANOTHER)
593  relativel = network_objects.velocity;
594  else
595  relativel = network_objects.dockingvel;
596  }
597  else if (viewscreen->gameclass->bus->targetC < -1) // Docks
598  {
599  if (playerships[0].reference < REF_INANOTHER)
600  // have bill try this
601  // holding ??? relativel=allobjects[-targetC-2].velocity-playerships[0].barycentric;
602  relativel = allobjects[-viewscreen->gameclass->bus->targetC - 2].velocity;//-playerships[0].barycentric;
603  else
604  relativel = centerC; // 0
605  }
606  }
607  else if (viewscreen->gameclass->bus->AFCS.DorOn) // DOR vector match, always in ref<0
608  {
609  D3DXMATRIX dor;
610  D3DXVECTOR3 location, tempvelocity;
611  D3DXVec3Normalize(&location, &playerships[0].position); // Turn into a vector
612  D3DXVec3Normalize(&tempvelocity, &playerships[0].velocity); // Turn into a vector
613  const float radius = D3DXVec3Length(&playerships[0].position) / radiusC; // Radii from CM, could be stolen from earlier
614  D3DXVec3Cross(&cross, &location, &tempvelocity); // Find perpendicular vector
615  const float angle = D3DXVec3Dot(&location, &tempvelocity); // Find our trajectory to the surface
616  if (angle >= 1.0f)
617  f_temp = -D3DX_HALFPI;
618  else if (angle <= -1.0f)
619  f_temp = -D3DX_PI;
620  else
621  f_temp = -acosf(angle) - D3DX_HALFPI;
622  D3DXMatrixRotationAxis(&dor, &cross, f_temp); // Set up a matrix
623  D3DXVec3TransformCoord(&relativel, &tempvelocity, &dor); // Use DOR to fix trajectory
624  D3DXVec3Normalize(&relativel, &relativel); // Make it into a vector
625  D3DXVec3Scale(&relativel, &relativel, -sqrtf(gravityC * radiusC / radius));
626  }
627  else
628  {
629  relativel = playerships[0].velocity; // this is handled like DOR, always in ref<0
630  }
631 
632  logger->AddToCallStack("CurrentLocalVelocity");
633 
634  // Current local velocity
636  {
637  if (playerships[0].reference >= REF_INANOTHER)
638  D3DXVec3Subtract(&localvel, &playerships[0].dockingvel, &relativel);
639  else
640  D3DXVec3Subtract(&localvel, &playerships[0].velocity, &relativel);
641  }
642  else
643  {
644  D3DXVec3Subtract(&localvel, &playerships[0].velocity, &relativel);
645  }
646 
647  // Convert to relative velocities in x, y, z
648  D3DXVec3TransformNormal(&localvel, &localvel, &matrixInverse);
650 
651  logger->AddToCallStack("EngineCriticalAltitude");
652 
653  float engineCriticalAltitudeMod = 1.0f;
655  {
656  // 1 - (31 - 6) / 45
657  engineCriticalAltitudeMod = 1.0f - (f_MSL - ourcockpit.engineCriticalAltitude) / ourcockpit.serviceCeilingKm;
658  if (engineCriticalAltitudeMod < 0.0f)
659  engineCriticalAltitudeMod = 0.0f;
660  }
661 
662  logger->AddToCallStack("EngineOutput");
663 
664  // Logic for the tail engine that we have no discreet control over
665  if (ourcockpit.engines == 3)
667 
668  float antiIceEffectiveness = 0.0f;
670  antiIceEffectiveness = static_cast<float>(ourcockpit.vdat.antiIce) / 127.0f;
671 
672  // Calculate output of each engine
673  float zThrustAvgPercent = 0.0f, zThrustAcceleration = 0.0f, zThrustAcceleration4FF = 0.0f, rcsThrustYPR = 0.0f;
674  for (int i = 0; i < ourcockpit.engines; i++)
675  {
676  // Adjust velocity (fire mains)
678  {
679  // distance velocity acceleration jerk
680  // distance velocity acceleration
681  // a = 2 * (Δd - v_i * Δt) / Δt²,
682  // jerk = 2 * (Δv - acceleration * Δt) / Δt²
683  f_temp = viewscreen->gameclass->bus->AFCS.DesiredClosingSpeed - localvel.z; // difference in zvelocity
685  //float timeToChange = fabsf(f_temp / currentThrust);
687  f_temp = 2.0f * (f_temp - currentThrust * ourcockpit.spoolTime * 0.5f) / powf(ourcockpit.spoolTime * 0.5f, 2.0f);
689  if (f_temp > 0)
690  {
691  // desired is 1.0kms and we are at 0.9kms = 0.1kms² / 0.0338f for the A-4 is 2.958579881656805 or 100%
692  // it takes him ourcockpit.spoolTime 16.9 seconds to adjust 100% of the thrust
693  // so we have a target velocity
696  }
697  else
698  {
702  }
703  }
704 
705  // Reversers
707  {
708  ThrustReverserOutput[i] += fElapsedTime * 0.5f; // 2 seconds
709  if (ThrustReverserOutput[i] > 1.0f)
710  ThrustReverserOutput[i] = 1.0f;
711  }
712  else
713  {
714  ThrustReverserOutput[i] -= fElapsedTime * 0.5f; // 2 seconds
715  if (ThrustReverserOutput[i] < 0.0f)
716  ThrustReverserOutput[i] = 0.0f;
717  }
718 
719  f_temp = viewscreen->gameclass->bus->EngineThrustLever[i];
720 
721  // for CAS to watch
722  if (viewscreen->gameclass->bus->EngineThrustCommand[i] > f_temp)
723  {
724  if (ourcockpit.spoolTime > 0)
726  else
727  viewscreen->gameclass->bus->EngineThrustCommand[i] -= 0.02f * fElapsedTime;
728 
729  if (viewscreen->gameclass->bus->EngineThrustCommand[i] < f_temp)
731  }
732  else if (viewscreen->gameclass->bus->EngineThrustCommand[i] < f_temp)
733  {
734  if (ourcockpit.spoolTime > 0)
736  else
737  viewscreen->gameclass->bus->EngineThrustCommand[i] += 0.02f * fElapsedTime;
738  if (viewscreen->gameclass->bus->EngineThrustCommand[i] > f_temp)
740  }
741 
742  // also need to adjust based on ourcockpit.power, before engine thrust output because we actually stop FCU from working
743  f_temp *= ourcockpit.power;
744 
745  // for fuel flow (before damage and engine critical altitude)
746  if (ourcockpit.engines)
747  zThrustAcceleration4FF += ourcockpit.fwdthrustlimit * f_temp / static_cast<float>(ourcockpit.engines);
748  else
749  logger->Log("Yup, this was it... divide by zero error on ourcockpit.engines #1", Logger::Level::Debug);
750 
751  // we need to kill percent thrust based on damage on engines, before engine thrust output because this is what we want to base alert on!
752  if (i == 0)
753  {
754  const float leftHealth = ourcockpit.vdat.leftengine > -1 ? static_cast<float>(ourcockpit.vdat.leftengine) / 127.0f : 0;
755  f_temp *= leftHealth;
756  }
757  else if ((i == 1 && ourcockpit.engines == 2) || (i == 2 && ourcockpit.engines == 3))
758  {
759  const float rightHealth = ourcockpit.vdat.rightengine > -1 ? static_cast<float>(ourcockpit.vdat.rightengine) / 127.0f : 0;
760  f_temp *= rightHealth;
761  }
762  else if (i == 1 && ourcockpit.engines == 3)
763  {
764  const float centerHealth = ourcockpit.vdat.clengine > -1 ? static_cast<float>(ourcockpit.vdat.clengine) / 127.0f : 0;
765  f_temp *= centerHealth;
766  }
767 
768  // smoothly seek the desired output
769  if (viewscreen->gameclass->bus->EngineThrustOutput[i] > f_temp)
770  {
771  if (ourcockpit.spoolTime > 0)
773  else
774  viewscreen->gameclass->bus->EngineThrustOutput[i] -= 0.02f * fElapsedTime;
775 
776  if (viewscreen->gameclass->bus->EngineThrustOutput[i] < f_temp)
778  }
779  else if (viewscreen->gameclass->bus->EngineThrustOutput[i] < f_temp)
780  {
781  if (ourcockpit.spoolTime > 0)
783  else
784  viewscreen->gameclass->bus->EngineThrustOutput[i] += 0.02f * fElapsedTime;
785  if (viewscreen->gameclass->bus->EngineThrustOutput[i] > f_temp)
787  }
788 
789  // this is the end of what is now displayed for the engine output and what the ENG FAIL message will be cued by
790  // can no longer use f_temp
791 
792  // average for transmitting
793  zThrustAvgPercent += viewscreen->gameclass->bus->EngineThrustOutput[i] * Lerp(1, -1, ThrustReverserOutput[i]);
794 
795  // reverser 0-1 means lerp between fwdthrustlimit and revthrustlimit
796  if (ourcockpit.engines)
797  {
799  if (_isnan(zThrustAcceleration) || isinf(zThrustAcceleration))
800  {
801  logger->Log("Yup, this was it...", Logger::Level::Debug);
802  sprintf_s(msg, sizeof(msg), "\tourcockpit.fwdthrustlimit: %f", ourcockpit.fwdthrustlimit);
803  logger->Log(msg, Logger::Level::Debug);
804  sprintf_s(msg, sizeof(msg), "\tourcockpit.revthrustlimit: %f", ourcockpit.revthrustlimit);
805  logger->Log(msg, Logger::Level::Debug);
806  sprintf_s(msg, sizeof(msg), "\tThrustReverserOutput[%i]: %f", i, ThrustReverserOutput[i]);
807  logger->Log(msg, Logger::Level::Debug);
808  sprintf_s(msg, sizeof(msg), "\tEngineThrustOutput[%i]: %f", i, viewscreen->gameclass->bus->EngineThrustOutput[i]);
809  logger->Log(msg, Logger::Level::Debug);
810  zThrustAcceleration = 0.0f;
811  }
812  }
813 
814  // Main engine sound
816  {
817  int soundEnum = 0;
818  float pan = 0.0f;
819  if (i == 0)
820  {
821  pan = -1.0f;
822  soundEnum = SOUND_COCKPITENGINELEFT;
823  }
824  else if ((i == 1 && ourcockpit.engines == 2) || (i == 3 && ourcockpit.engines == 3))
825  {
826  pan = 1.0f;
827  soundEnum = SOUND_COCKPITENGINERIGHT;
828  }
829  else if (i == 2 && ourcockpit.engines == 3)
830  {
831  pan = 0.0f;
832  soundEnum = SOUND_COCKPITENGINECENTER;
833  }
834 
836  if (soundEnum)
837  {
838  if (ourcockpit.texturelib != VehicleType::T27)
839  {
840  const float vol = sqrtf(viewscreen->gameclass->bus->EngineThrustOutput[i]) * engineCriticalAltitudeMod;
841  viewscreen->gameclass->sound->PlayEx(soundEnum, true, vol * viewscreen->gameclass->sound->GetAttenuation(true), 0.2f + 0.8f * viewscreen->gameclass->bus->EngineThrustOutput[i], pan);
842  }
843  else // Mammoth
844  {
845  const float vol = ourcockpit.power * (sqrtf(viewscreen->gameclass->bus->EngineThrustOutput[i]) * 0.4f + 0.6f);
847  }
848  }
849  }
850  }
851  if (ourcockpit.engines)
852  zThrustAvgPercent /= static_cast<float>(ourcockpit.engines);
853 
854  // also need to affect based on engine critical altitude, normal and expected loss of power
855  zThrustAcceleration *= engineCriticalAltitudeMod;
856 
857  // also need to affect based on vacuum efficiency, normal and expected loss of power
858  zThrustAcceleration *= Lerp(1.0f, ourcockpit.engineEfficiencyAtSeaLevelScalar, staticDensity);
859 
860  // Anti-ice, normal and expected loss of power
862  {
863  zThrustAcceleration -= 0.05f * ourcockpit.fwdthrustlimit * antiIceEffectiveness;
864  if (zThrustAcceleration < 0.0f)
865  zThrustAcceleration = 0.0f;
866  }
867 
869  {
870  viewscreen->rcsThrustRequestX -= localvel.x; // difference in xvelocity
871  viewscreen->rcsThrustRequestY -= localvel.y; // difference in yvelocity
872  }
873 
874 
875  if (playerships[0].docked)
877 
878 
879  static float rcsThrustOutputX = 0.0f, rcsThrustOutputY = 0.0f, rcsThrustOutputZ = 0.0f;
880  rcsThrustOutputX += (viewscreen->rcsThrustRequestX - rcsThrustOutputX) * fElapsedTime;
881  rcsThrustOutputY += (viewscreen->rcsThrustRequestY - rcsThrustOutputY) * fElapsedTime;
882  rcsThrustOutputZ += (viewscreen->rcsThrustRequestZ - rcsThrustOutputZ) * fElapsedTime;
883  viewscreen->rcsThrustOutputX = rcsThrustOutputX;
884  viewscreen->rcsThrustOutputY = rcsThrustOutputY;
885  viewscreen->rcsThrustOutputZ = rcsThrustOutputZ;
886 
887 
889  return;
890 
891 
892  if (ourcockpit.power < 1.0f) // this is a good save-all, loses containment or some BS like that
893  {
897  }
898 
899  // Result of all thrust inputs
908 
909 
910  // how much we are actually thrusting ... will be adjusted by weight and friction an everything else
911  const auto tx = static_cast<char>(viewscreen->rcsThrustOutputX / ourcockpit.fwdthrustlimit * 127.0f);
912  const auto ty = static_cast<char>(viewscreen->rcsThrustOutputY / ourcockpit.fwdthrustlimit * 127.0f);
913  const auto tz = static_cast<char>(Clamp(viewscreen->rcsThrustOutputZ / ourcockpit.fwdthrustlimit + zThrustAvgPercent, -1, 1) * 127.0f);
914  // not sure if we should be doing this as 0-100% thrust or in meters per second
915  // doppler sound should be based on weight of vehicle times thrust output over max?
916 
917 
918  // adjust for engine critical altitude
919  viewscreen->rcsThrustOutputX *= engineCriticalAltitudeMod;
920  viewscreen->rcsThrustOutputY *= engineCriticalAltitudeMod;
921  viewscreen->rcsThrustOutputZ *= engineCriticalAltitudeMod;
922 
923 
924  // Adjust for ground effect?
925  const float tempagl = (f_AGL - citystuff.elevation) * 1000.0f; // km to m
926  float groundeffect = 1.0f;
927  if (!ourcockpit.gndvehicle && tempagl <= ourcockpit.wingspanM && ourcockpit.wingspanM > 0.0f && tempagl >= 0.0f)
928  {
929  // 1.0f-1.5f times (0-50% increase) when one wingspan to 0.0f AGL
930  groundeffect = 1.5f - powf(tempagl / ourcockpit.wingspanM, 2.0f) * 0.5f;
931  viewscreen->rcsThrustOutputY *= groundeffect;
932  }
933 
934 
935  logger->AddToCallStack("PropulsionForGroundVehicle");
936 
937  if (ourcockpit.gndvehicle) // ground vehicle
938  {
939  float ratio = 999.0f;
940  if (ourcockpit.gearshift == -1) // rev
941  ratio = ourcockpit.ratios[0];
942  else if (ourcockpit.gearshift > 0)
944 
945  float pedal = Clamp(viewscreen->gameclass->bus->EngineThrustLever[0], 0.1f, 1.0f); // idle
946 
947  // 0001252: Speed limiters for ground vehicles over 11 MT MTOW
949  {
950  // we are going 94.5 and limit is 105 .. buffer = 10.5
951  // we are going 105 and limit is 105 .. buffer = 0
952  const float buffer = max(ourcockpit.speedLimiterKph * 1.05f - ourcockpit.tirespeedKph, 0);
953  pedal *= buffer / (ourcockpit.speedLimiterKph * 0.05f);
954  }
955 
956  pedal *= ourcockpit.power;
957  if (_isnan(pedal) || isinf(pedal))
958  {
959  logger->Log("Pedal died", Logger::Level::Fatal);
960  }
961 
962  // Effect on fuel
963  const float oldFuel = fuel;
964  fuel -= pedal * ourcockpit.ffmax * fElapsedTime;
965  if (oldFuel > ourcockpit.fuelmax * 0.5f && fuel <= ourcockpit.fuelmax * 0.25f)
967  viewscreen->gameclass->bus->FuelFlowKgh = pedal * ourcockpit.ffmax * 3600.0f / Kg2Lbs;
968  deathfuel -= pedal * ourcockpit.ffmax * fElapsedTime;
969  if (fuel < 0.0f)
970  pedal = fuel = 0.0f;
971  if (deathfuel < 0.0f)
972  deathfuel = 0.0f;
973 
974  ourcockpit.clutchhold -= fElapsedTime * 0.1f;
975  if (ourcockpit.clutchhold < 0.0f)
976  ourcockpit.clutchhold = 0.0f;
977 
978  // temp += desiredrpm
979  // temp -= (ias+beltdrivenfanrpm)*density+ambientrad
980 
981  const float desired = pedal;
982 
983  D3DXVec3TransformNormal(&result, &locvelcomp, &matrixInverse);
984  // so this is fwd/rev in rotation of tire but ground speed
985  const float speedometerKph = result.z * 60.0f * 60.0f; // kph, + is fwd, - is rev
986  float nettorque = 0.0f;
987  float clutch = 1.0f - ourcockpit.clutchhold;
988  if (ourcockpit.gearshift > 0 || ourcockpit.gearshift == -1) // is the transmission engaged
989  {
990  // this is what limits the top speed
991  const float actualTach = ourcockpit.tirespeedKph / ratio / 77.7f * clutch;
992  // 109.435392*.71/77.69*x=1
993 
994  if (_isnan(actualTach) || isinf(actualTach))
995  {
996  logger->Log("actual tach died", Logger::Level::Fatal);
997  }
998 
999  float gauge;
1000  // so if we are 0.1 and driving at 0.5 that is 0.4 which is greater than desired
1001  if (desired < actualTach || ourcockpit.gearshift == 0 || ourcockpit.gearshift == -2)
1002  gauge = actualTach;
1003  else
1004  gauge = (desired + actualTach + actualTach + actualTach) * 0.25f;
1005 
1006 
1007  gauge = Clamp(gauge, 0.0f, 1.0f);
1008 
1009 
1010  // keep the engine from dieing
1011  if (gauge < 0.1f && pedal>0.0f)
1012  {
1013  clutch = 1.0f - gauge / 0.1f;
1014  gauge = 0.1f;
1015  }
1016 
1017 
1018  // assuming we are on the ground, torque adds to tire speed
1019  // so torque is current tach*pedal/(weightC/ourcockpit.emptyweight)
1020  // the closer tach is to say 0.733 (5500) so tach-0.733 is 0 or less than .1 or
1021  // ok .733-.733 is 0, 1-.733 is .26, 0-.733 is -.733 or .733 fabsf(tach-peaktach)
1022  // 1-0=1 1-.26=.74 1-.733=.267
1023  // so 1.0f-fabsf(tach-peaktach), clamp to .1 and 1.0
1024  // if (ourcockpit.tach>ourcockpit.peaktach)
1025  // baseonpeak=
1026  float baseonpeak = 1.0f - fabsf(gauge - 0.733f); // peak hp for mack is 1800 rpm
1027  if (baseonpeak > 1.0f)
1028  baseonpeak = 1.0f;
1029  else if (baseonpeak < 0.0f)
1030  baseonpeak = 0.0f;
1031  // 3.9m/s at gross
1032  const float torque = baseonpeak / ratio * ourcockpit.fwdthrustlimit * pedal * clutch;
1033  // engine power is based on RPM and gas and sent to the wheels by ratio
1034  // wheels like the mack do 3.23 meters per rotation, 5.55 is rear axel
1035  // torque is actual force the engine produces
1036  // now you can't go faster than when the ground speed equals the drive train speed
1037  // so if drivetrain is 10 and and groundspeed is 10 then zoutput is 1
1038  // if drivetrain is 0 and groundspeed is 10 then zoutput is 0
1039  // if drivetrain is 10 and groundspeed is 0 then zoutput is 999999
1040 
1041  // if drivetrain=20kph and groundspeed=20kph then effective=1
1042  // if drivetrain=20kph and groundspeed=0kph then effective=0
1043  float effective = desired - actualTach; // 1-0=1, 0-1=0 .5-.5=0 .6-.5=.1
1044  if (effective > 1.0f)
1045  effective = 1.0f;
1046  // else if (effective<-1.0f)
1047  // effective=-1.0f;
1048  // if (groundspeed<0.0f)
1049  // effective=-effective;
1050  /* if (drivetrain>groundspeed && groundspeed>=0.0f)
1051  effective=1.0f-groundspeed/drivetrain;
1052  else
1053  effective=0.0f;
1054  */
1055  // float easeofdeltatire=fabsf(ratio)/2.0f;
1056  // tirespeed equals groundspeed
1057  if (playerships[0].reference == REF_ONGROUND) // on surface
1058  {
1059  /* if (groundspeed>(realtach*ratio*272.4f))
1060  {
1061  float speeddiff=speedometer-(realtach*ratio*272.4f+torque); // 12-11 is 1
1062  float Gtokph=gndcontactG*60.0f*60.0f*gravityC;
1063  if (speeddiff>Gtokph)
1064  speeddiff=Gtokph;
1065  else if (speeddiff<(-Gtokph))
1066  speeddiff=-Gtokph; // the rest is sliding
1067  float oldtirespeed=ourcockpit.tirespeed;
1068  ourcockpit.tirespeed=realtach*ratio*272.4f+speeddiff*easeofdeltatire; // add 1
1069  zthrustoutput-=speeddiff*(1.0f-easeofdeltatire)/60.0f/60.0f; // kph to km/s
1070  }
1071  */ // limit to 1G, else destroy transmission, engine, squeal tires
1072  nettorque = Clamp(torque * effective, -gravityC, gravityC);
1073  ourcockpit.tirespeedKph = speedometerKph;//realtach*ratio*272.4f+speeddiff*easeofdeltatire; // add 1
1074 
1075 #ifdef chipbin
1076  if (game->advanceframe)
1077  {
1078  if (chip == -1)
1079  _sopen_s(&chip, "chip.bin", _O_WRONLY | O_TEXT | _O_CREAT | O_TRUNC, _SH_DENYWR, _S_IWRITE);
1080  char chipmsg[9999];
1081  sprintf_s(chipmsg, sizeof(chipmsg), "(g/s %5.1f kph)(gear %+i/%4.2f)(pedal %2.1f/fz%.3f)(actual %2.1f/%4.0f RPM)(gauge %2.1f/%4.0f RPM/peak %2.1f)(torque %+.4f net %.4f (%2.1f))\n",
1082  speedometer, ourcockpit.gearshift, ratio, desired, game->gameclass->bus->EngineThrustLever[0], actualTach, actualTach * 7500.0f, gauge, gauge * 7500.0f, baseonpeak,
1083  torque, nettorque, effective);
1084  _lseek(chip, 0L, SEEK_SET);
1085  _write(chip, chipmsg, strlen(chipmsg));
1086  }
1087 #endif
1088  }
1089  else
1090  {
1091  ourcockpit.tirespeedKph += torque * effective;//realtach*ratio*272.4f+speeddiff*easeofdeltatire; // add 1
1092  // ourcockpit.tirespeed=ourcockpit.tach*ratio*272.4f+torque*easeofdeltatire; // add 1
1093  }
1094 
1095  ourcockpit.tach = gauge;
1096  }
1097  else
1098  {
1099  if (playerships[0].reference == REF_ONGROUND) // on surface
1100  ourcockpit.tirespeedKph = speedometerKph; // neutral, is same as groundspeed
1102  //else
1103  // ourcockpit.tirespeed -= ourcockpit.tirespeed*fElapsedTime;
1104 
1105 
1106  ourcockpit.tach = Lerp(desired, ourcockpit.tach - ourcockpit.tach * fElapsedTime, ourcockpit.clutchhold);
1107  //if (ourcockpit.clutchhold == 0.0f)
1108  // ourcockpit.tach = desired; // when not shifting we are in neutral, etc
1109  //else
1110  // ourcockpit.tach -= ourcockpit.tach*fElapsedTime; // when shifting, let off gas
1111  }
1112 
1113 
1114  tach += (ourcockpit.tach - tach) * fElapsedTime * 3.0f;
1115 
1116  if (ourcockpit.power > 0.25f)
1117  {
1118  if (playerships[0].type != VehicleType::T120 && playerships[0].type != VehicleType::T121)
1119  viewscreen->gameclass->sound->PlayEx(SOUND_COCKPITENGINECENTER, true, (0.2f + tach * 0.8f) * viewscreen->gameclass->sound->GetAttenuation(true), 0.2f + 2.0f * tach);
1120  else
1121  viewscreen->gameclass->sound->PlayEx(SOUND_COCKPITENGINECENTER, true, (0.3f + tach * 0.7f) * viewscreen->gameclass->sound->GetAttenuation(true), 0.2f + 2.0f * tach);
1122  }
1123  else
1124  {
1125  if (playerships[0].type != VehicleType::T120 && playerships[0].type != VehicleType::T121)
1127  else
1129  }
1130 
1131  actual.x = 0.0f;
1132  actual.y = 0.0f;
1133  // Effectiveness of thrust
1134  if (ourcockpit.gndvehicle &&
1135  (playerships[0].reference != REF_ONGROUND || // wheels must be on ground
1136  fabsf(levelerroll) > 0.9f || // rolled more than 60 deg
1137  levelerpitch > 0.001f)) // drive wheels are off ground, FWD vs RWD?
1138  actual.z = 0.0f;
1139  else
1140  actual.z = nettorque;
1141  }
1142  else
1143  {
1146  actual.z = viewscreen->rcsThrustOutputZ + zThrustAcceleration;
1147  }
1148 
1149  logger->AddToCallStack("EffectivenessOfThrust");
1150 
1151 
1152  result.x = actual.x * fElapsedTime; result.y = actual.y * fElapsedTime; result.z = actual.z * fElapsedTime;
1153 
1154 
1155 
1156 #pragma region debug
1157  if (result.x > 100.0f || result.x < -100.0f || _isnan(result.x) || isinf(result.x) ||
1158  result.y > 100.0f || result.y < -100.0f || _isnan(result.y) || isinf(result.y) ||
1159  result.z > 100.0f || result.z < -100.0f || _isnan(result.z) || isinf(result.z))
1160  {
1161  sprintf_s(msg, sizeof(msg), "\tET: %f", fElapsedTime);
1162  logger->Log(msg, Logger::Level::Debug);
1163  sprintf_s(msg, sizeof(msg), "\tactual I: %f", actual.x);
1164  logger->Log(msg, Logger::Level::Debug);
1165  sprintf_s(msg, sizeof(msg), "\tactual J: %f", actual.y);
1166  logger->Log(msg, Logger::Level::Debug);
1167  sprintf_s(msg, sizeof(msg), "\tactual K: %f", actual.z);
1168  logger->Log(msg, Logger::Level::Debug);
1169  sprintf_s(msg, sizeof(msg), "\tresult I: %f", result.x);
1170  logger->Log(msg, Logger::Level::Debug);
1171  sprintf_s(msg, sizeof(msg), "\tresult J: %f", result.y);
1172  logger->Log(msg, Logger::Level::Debug);
1173  sprintf_s(msg, sizeof(msg), "\tresult K: %f", result.z);
1174  logger->Log(msg, Logger::Level::Debug);
1175  sprintf_s(msg, sizeof(msg), "\tgndvehicle: %i", ourcockpit.gndvehicle);
1176  logger->Log(msg, Logger::Level::Debug);
1177  sprintf_s(msg, sizeof(msg), "\trcsThrustOutputZ: %f", viewscreen->rcsThrustOutputZ);
1178  logger->Log(msg, Logger::Level::Debug);
1179  sprintf_s(msg, sizeof(msg), "\tzThrustAcceleration: %f", zThrustAcceleration);
1180  logger->Log(msg, Logger::Level::Debug);
1181  sprintf_s(msg, sizeof(msg), "Trapped a violation after xy thrust spoolup...");
1182  logger->Log(msg, Logger::Level::Fatal);
1183  }
1184 #pragma endregion
1185 
1186  D3DXVec3Scale(&result, &result, ourcockpit.maxGrossLbs / totalWeightLbs); // bias the BOW so at gross this is 0.625
1187 
1188 #pragma region debug
1189  if (result.x > 100.0f || result.x < -100.0f || _isnan(result.x) || isinf(result.x) ||
1190  result.y > 100.0f || result.y < -100.0f || _isnan(result.y) || isinf(result.y) ||
1191  result.z > 100.0f || result.z < -100.0f || _isnan(result.z) || isinf(result.z))
1192  {
1193  sprintf_s(msg, sizeof(msg), "\tET: %f", fElapsedTime);
1194  logger->Log(msg, Logger::Level::Warn);
1195  sprintf_s(msg, sizeof(msg), "\tourcockpit.maxgross: %f", ourcockpit.maxGrossLbs);
1196  logger->Log(msg, Logger::Level::Warn);
1197  sprintf_s(msg, sizeof(msg), "\tourcockpit.emptyweight: %f", ourcockpit.emptyWeightLbs);
1198  logger->Log(msg, Logger::Level::Warn);
1199  sprintf_s(msg, sizeof(msg), "\tfuel: %f", fuel);
1200  logger->Log(msg, Logger::Level::Warn);
1201  sprintf_s(msg, sizeof(msg), "\tpayload: %f", payload);
1202  logger->Log(msg, Logger::Level::Warn);
1203  sprintf_s(msg, sizeof(msg), "\tweightC: %f", totalWeightLbs);
1204  logger->Log(msg, Logger::Level::Warn);
1205  sprintf_s(msg, sizeof(msg), "\tresult I: %f", result.x);
1206  logger->Log(msg, Logger::Level::Warn);
1207  sprintf_s(msg, sizeof(msg), "\tresult J: %f", result.y);
1208  logger->Log(msg, Logger::Level::Warn);
1209  sprintf_s(msg, sizeof(msg), "\tresult K: %f", result.z);
1210  logger->Log(msg, Logger::Level::Warn);
1211  sprintf_s(msg, sizeof(msg), "Trapped a violation after weight adjustment spoolup...");
1212  logger->Log(msg, Logger::Level::Fatal);
1213  }
1214 #pragma endregion
1215  sprintf_s(msg, sizeof(msg), "X%7.3f Y%7.3f Z%7.3f thrust", result.x * oneOvergForceKmSSC / fElapsedTime, result.y * oneOvergForceKmSSC / fElapsedTime, result.z * oneOvergForceKmSSC / fElapsedTime);
1216  viewscreen->sofTracking.emplace_back(msg);
1217 
1218  sumofforces += result; // thrust
1219 
1220 #pragma region debug
1221  if (sumofforces.x > 100.0f || sumofforces.x < -100.0f || _isnan(sumofforces.x) || isinf(sumofforces.x) ||
1222  sumofforces.y > 100.0f || sumofforces.y < -100.0f || _isnan(sumofforces.y) || isinf(sumofforces.y) ||
1223  sumofforces.z > 100.0f || sumofforces.z < -100.0f || _isnan(sumofforces.z) || isinf(sumofforces.z))
1224  {
1225  sprintf_s(msg, sizeof(msg), "\tET: %f", fElapsedTime);
1226  logger->Log(msg, Logger::Level::Warn);
1227  sprintf_s(msg, sizeof(msg), "\tsumofforces I: %f", sumofforces.x);
1228  logger->Log(msg, Logger::Level::Warn);
1229  sprintf_s(msg, sizeof(msg), "\tsumofforces J: %f", sumofforces.y);
1230  logger->Log(msg, Logger::Level::Warn);
1231  sprintf_s(msg, sizeof(msg), "\tsumofforces K: %f", sumofforces.z);
1232  logger->Log(msg, Logger::Level::Warn);
1233  sprintf_s(msg, sizeof(msg), "\tresult I: %f", result.x);
1234  logger->Log(msg, Logger::Level::Warn);
1235  sprintf_s(msg, sizeof(msg), "\tresult J: %f", result.y);
1236  logger->Log(msg, Logger::Level::Warn);
1237  sprintf_s(msg, sizeof(msg), "\tresult K: %f", result.z);
1238  logger->Log(msg, Logger::Level::Warn);
1240  sprintf_s(msg, sizeof(msg), "Trapped a violation after thrust adjusted...");
1241  logger->Log(msg, Logger::Level::Fatal);
1242  }
1243 #pragma endregion
1244 
1245 
1246 
1247  logger->AddToCallStack("AtmosphericPhysics");
1248 
1249 #pragma region Atmospheric Physics
1250  // Atmospheric functions ************************************************************************
1251  // YAW DAMPER EMPLOYED
1252  // Only question right now are movement of the Cp
1253  // Also whether or not fuselage should block lift when in a slip/skid situation
1254  // AOA increases by atanf( (2.0f*sinf(D3DX_PI-roll))/(1.0f-2.0f*cosf(D3DX_PI-roll)) ) w/ deflect
1255 
1256  if (playerships[0].reference != REF_INANOTHER)
1257  {
1258  if (f_MSL != -1.0f) // Hold off until altitude is calculated
1259  {
1260  float S, tempaoa;
1261  float tempDragTail = 0.0f;
1262 
1263 
1264  // wind sensors
1265  static float fullsec = 0.0f;
1266  fullsec += fElapsedTime;
1267  if (fullsec > 1.0f)
1268  {
1269  viewscreen->gameclass->bus->WindSpeedMs = D3DXVec3Length(&windVectorTrueKms) * 1000.0f;
1272  fullsec = 0.0f;
1273  }
1274 
1275 
1276  // air density sensor (static pressure sensor)
1278 
1279  // Solve for forward dynamic pressure
1280  qz = dynamicDensity * rhoOver2SlugsCuFt2 * powf(relativeWindTrueKms.z * 3280.8f, 2.0f);
1283 
1284 
1285  // just the forward part, used for st. elmos, possibly fan cooled engines, and IAS bus value below
1286  const float ias = max(-relativeWindTrueKms.z, 0) * staticDensity;
1287  // ias sensor, cannot sense backwards (ram air sensor)
1289 
1290  const float tas = D3DXVec3Length(&relativeWindTrueKms); // any direction for mach and heating? and ice ... km/s
1291  const float qxyz = dynamicDensity * rhoOver2SlugsCuFt2 * powf(tas * 3280.8f, 2.0f);
1292 
1293 
1294  // oat sensor (static air temperature sensor)
1296  // tas calculation is based on indicated airspeed and density, that is all we have
1299  else
1301 
1302  const float outsideAirTemperatureKelvin = ZeroCelsiusToKelvin + viewscreen->ptrWeather->GetTemperatureCelsius();
1303  viewscreen->gameclass->bus->OutsideAirTemperatureKelvin = outsideAirTemperatureKelvin;
1304 
1305  // angular velocity sensor?
1306  viewscreen->gameclass->bus->LinearVelocityKms = D3DXVec3Length(&playerships[0].velocity);
1307 
1308 
1309  const float molarMass = 0.9914103f + 29.5230397f / (1.0f + powf(max(f_MSL, 0) / 378.4386f, 1.425581f)); // 29 at sea level, 18 at 300km
1310  const float molarMassMod = 29.0f / molarMass; // 1 at sea level, 1.61 at 300km
1311  speedOfSoundKms = sqrtf(adiabaticIndex * gasConstantm2s2K * outsideAirTemperatureKelvin * molarMassMod) * 0.001f;
1312  if (_isnan(speedOfSoundKms) || isinf(speedOfSoundKms))
1313  {
1314  sprintf_s(msg, 160, "speedOfSoundKms was NAN, OAT %.3f MMM %.3f", outsideAirTemperatureKelvin, molarMassMod);
1316  speedOfSoundKms = 0.343f;
1317  }
1319 
1320  mach = tas / speedOfSoundKms; // real mach the airframe sees
1321  if (viewscreen->gameclass->bus->PressureAltitudeKm < 100.0f) // Karman line
1323  else
1325 
1326 
1327  tatCelsius = viewscreen->ptrWeather->GetTemperatureCelsius() + outsideAirTemperatureKelvin * (adiabaticIndex - 1.0f) * 0.5f * mach * mach;
1328  // tat calculation
1331 
1332 
1333 
1334 #pragma region Thermodynamics
1336  const float airframeTempKelvin = ZeroCelsiusToKelvin + airframeTempCelsius;
1337  // result is in Watts, convert to Celsius heat units (IT) per second * 0.000526565066841
1341  // we use SAT because it is a relatively small amount of air that is increased temp compared to the surrounding environment
1342  // tried using heat coefficient but it is not 0-1 ... so it exploded the server! .001 for emissivity seems right for some reason
1343  float radiationRate = 0.001f * 0.000000056703f * (powf(outsideAirTemperatureKelvin, 4.0f) - powf(airframeTempKelvin, 4.0f)) * (ourcockpit.i12WingAreaOneSideSqFt * 4.0f * 0.092903f) * 0.000526565066841f;
1344  // tried modulating outsideAirTemperatureKelvin with density but even at 300 meters it was 90% which was 30 degrees below SAT... so I put it back
1345  // now we just don't let it heat up the ship when in thermosphere
1346  if (radiationRate > 0)
1347  radiationRate = 0;
1349  convectionRate = (tatCelsius - airframeTempCelsius) * ourcockpit.f20FrontBackDragCoeff * 0.00004f * qxyz; // f20 is 2.56 .. doubled from 0.000018 to 0.00004 on 6/2/2019
1351  float outsideConductionRate = (tatCelsius - airframeTempCelsius) * ourcockpit.f20FrontBackDragCoeff * 0.000008f * dynamicDensity;
1352  if (playerships[0].baydoor) outsideConductionRate *= 1.2f; // 0000983: Heat managment
1353 
1355  {
1356  static int tempDumpFile = -1;
1357  if (tempDumpFile == -1)
1358  _sopen_s(&tempDumpFile, "tempdata.log", _O_RDWR | _O_CREAT | _O_TRUNC | _O_TEXT | _O_SEQUENTIAL, SH_DENYWR, S_IWRITE);
1359  if (halfsec == 0.0f)
1360  {
1361  char msg1[999];
1362  sprintf_s(msg1, 999, "Alt: %.1f D: %.3f M: %.3f Q: %.3f SAT: %.1f AFT: %.1f TAT: %.1f Q*TAT: %.0f Rad/s: %.6f Cnv/s: %.6f OCnd/s: %.6f\n",
1365  _write(tempDumpFile, msg1, strlen(msg1));
1366  }
1367  }
1368 
1369  airframeTempCelsius += ourcockpit.exteriorInsulationHeatTransferCoefficient * (convectionRate + radiationRate + outsideConductionRate) * fElapsedTime;
1370  if (airframeTempCelsius < -273.15f) airframeTempCelsius = -273.15f;
1371  if (airframeTempCelsius > 3276.7f) airframeTempCelsius = 3276.7f; // we use short*10 for data transfer
1372 
1373  // airframe temp sensor
1381 
1382  if (airframeTempCelsius > 350.0f && ourcockpit.vdat.leftwing > 0 && ourcockpit.vdat.rightwing > 0)
1383  {
1384  // 350 is published limit ... stay there for a minute and get rid of 120 ... getting rid of 2 per second
1385  static bool favorLeft = rand() % 2 == 0;
1386  static float leftWing = 0.0f;
1387  static float rightWing = 0.0f;
1388  leftWing += powf(airframeTempCelsius / 525.0f, 8.0f) * RandomFloat() * (favorLeft ? 4.0f : 3.0f) * fElapsedTime;
1389  rightWing += powf(airframeTempCelsius / 525.0f, 8.0f) * RandomFloat() * (favorLeft ? 3.0f : 4.0f) * fElapsedTime;
1390  if (leftWing >= 1.0f)
1391  {
1392  if (leftWing > ourcockpit.vdat.leftwing)
1393  {
1395  ourcockpit.vdat.leftwing = 0;
1396  favorLeft = rand() % 2 == 0;
1397  }
1398  else
1399  {
1400  ourcockpit.vdat.leftwing -= (char)leftWing;
1402  if (rand() % 32) viewscreen->gameclass->bus->ComponentRcsRollFail = true;
1403  if (rand() % 32) viewscreen->gameclass->bus->ComponentFcsRollFail = true;
1404  }
1405  ourcockpit.vdatChanged = true;
1406  leftWing = 0;
1407  }
1408  if (rightWing >= 1.0f)
1409  {
1410  if (rightWing > ourcockpit.vdat.rightwing)
1411  {
1413  ourcockpit.vdat.rightwing = 0;
1414  favorLeft = rand() % 2 == 0;
1415  }
1416  else
1417  {
1418  ourcockpit.vdat.rightwing -= (char)rightWing;
1420  if (rand() % 32) viewscreen->gameclass->bus->ComponentRcsRollFail = true;
1421  if (rand() % 32) viewscreen->gameclass->bus->ComponentFcsRollFail = true;
1422  }
1423  ourcockpit.vdatChanged = true;
1424  rightWing = 0;
1425  }
1426  }
1427 #pragma endregion
1428 
1429 
1430 
1431 #pragma region Icing
1432  float cloudSeverity = 0.0f;
1433  if (f_ACL < 0.150f && f_BCL < 0.150f) // ACL is above upper cloud level, BCL is below cloud bases
1434  {
1435  // Icing can be most intense near the cloud tops, where the amount of liquid water is often greatest.
1437  // if we are at 0 BCL that means we are at base, BCL is -cloudThickness at top
1438  cloudSeverity = fabsf(f_BCL) / viewscreen->ptrWeather->cloudThickness; // 0-1 from bottom to top
1439  cloudSeverity *= 0.285714f; // 0 to .285714 which is turbidity of 6 (ensures minimum in clouds)
1440  }
1441  // this will be 0-1 based on turbidity of 6 to 14
1442  const float dropSeverity = max((viewscreen->ptrWeather->GetTurbidity() - 2.0f) / 14.0f - 0.285714f, 0.0f) * 1.4f; // 0-1
1443  // inverse of turbulence is what dictates how cold our droplets can be
1445  const float waterFreezesAt = -35.0f * sqrtf(1.0f - viewscreen->ptrWeather->GetTurbulence());
1446 
1447  // 107 is from the FCOM 14-10-2
1448  // if temp is -5 we can only heat to 102, if temp is 10 we can only heat to 107 ... so it is 107-ambient ... 107 means 0 added, 106 means 1 added, -5 means
1449  const float ductTempCelsius = fabsf(zThrustAvgPercent) > 0 ? (viewscreen->gameclass->bus->AntiIce ? 107.0f * antiIceEffectiveness : 0) : 0;
1450  const float riseAvailable = min(ductTempCelsius - airframeTempCelsius, 107.0f); // 107 minus 0 is 107 ... 107 minus -5 is 107 ... -5 minus -5 is 0
1451  const float leadingEdgeTempCelsius = airframeTempCelsius + max(0.0f, riseAvailable);
1452 
1453  // SAT is at or above waterFreezesAt and AFT is below freezing
1454  // OAT is 0 to -15 and in clouds or below 0 in rain
1456  float temperatureSeverity = 0.0f;
1457  if (viewscreen->ptrWeather->GetTemperatureCelsius() >= waterFreezesAt)
1458  temperatureSeverity = min(1.0f, -min(0.0f, leadingEdgeTempCelsius + viewscreen->ptrWeather->GetTemperatureCelsius()) / 70.0f);
1459  const float iceIntensity = min(dropSeverity + cloudSeverity, 1.0f) * temperatureSeverity; // temp differential, clouds, precipitation ... highest at top of clouds
1460  const float iceAccretion = tas / 16.0f * fElapsedTime * 25.0f * iceIntensity; // aka 25 mm in 16 km
1461  if (iceAccretion > 0)
1462  {
1464  viewscreen->gameclass->bus->IceDetectorMm += iceAccretion;
1465  iceAccumulationMm += iceAccretion;
1466  }
1467  // *** now sublimate, melt, and de-ice and cycle probe!!
1468  // melt is based on AFT ... sublimate is probably speed based? deice adds to melt
1469  const float sublimation = 1.143f / 135.224f * fElapsedTime; // it is a rate slightly below trace icing .. 1.143 mm per 16 km at 230 knots? that is every 135.224 seconds
1470  viewscreen->gameclass->bus->IceDetectorMm -= sublimation;
1471  iceAccumulationMm -= sublimation;
1472  // icing systems only work up to heavy icing which is .72 inches (18.288 mm) per 16 km at 230 knots
1473  // 70 degrees based on pitot heat temperature (electric)
1474  const float probeHeaterCelsius = (viewscreen->gameclass->bus->IceDetectorHeat ? 70 : viewscreen->ptrWeather->GetTemperatureCelsius());
1475  const float probeRiseAvailable = min(probeHeaterCelsius - viewscreen->ptrWeather->GetTemperatureCelsius(), 70);
1476  const float probeTempCelsius = viewscreen->ptrWeather->GetTemperatureCelsius() + max(0, probeRiseAvailable);
1477 
1478  float melt = probeTempCelsius / 70.0f * 18.288f / 135.224f * fElapsedTime;
1479  if (melt > 0)
1481  // can't comment this out because of the sublimation above
1484  if (leadingEdgeTempCelsius > 0)
1485  {
1486  melt = leadingEdgeTempCelsius / 107.0f * 18.288f / 135.224f * fElapsedTime;
1487  iceAccumulationMm -= melt;
1488  }
1490  // *** disrupt airflow
1491  // 1/2 of an inch (12.7mm) reduces lift by 50% and increases drag 50%
1492  // #40 grit (0.425 mm) can reduce lift by 30% ... 12.7 is 50% reduction
1493  // reduce lift by up to 30% ... large horn ice accumulation is 40-50% reduction
1494  // increase drag to 40% (large horn ice can do 80-200%)
1495  // clamp to .5 on the low end because we have no evidence that it ever drops below 50%
1496  const float liftIceMod = max(0.5f, 1.0f - 0.003f * powf(iceAccumulationMm, 2.0f)); // 1-0 ... @ref not curvefit but fn=1-.003*x^2 on fooplot.com ..
1497  const float dragIceMod = 1.0f + 0.14f * powf(iceAccumulationMm, 0.5f); // 1-2 ... @ref not curvefit but fn=1+.14*x^.5 on fooplot.com .. 204 mm is 300% drag!
1499  {
1500  static int iceDumpFile = -1;
1501  if (iceDumpFile == -1)
1502  _sopen_s(&iceDumpFile, "icedata.log", _O_RDWR | _O_CREAT | _O_TRUNC | _O_TEXT | _O_SEQUENTIAL, SH_DENYWR, S_IWRITE);
1503  if (halfsec == 0.0f)
1504  {
1505  char msg1[999];
1506  sprintf_s(msg1, 999, "MSL: %.3f TAS: %.3f DSV: %.1f TSV: %.1f CSV: %.1f THK: %.1f SAT: %+.1f AFT: %+.1f INT: %.1f ACC: %.3f I/D: %.1f (%i) A/F: %.1f SUB: %.1f LET: %.1f (%i) LFT: %.1f DRG: %.1f\n",
1507  f_MSL, tas, dropSeverity, temperatureSeverity, cloudSeverity, viewscreen->ptrWeather->cloudThickness, viewscreen->ptrWeather->GetTemperatureCelsius(), airframeTempCelsius, iceIntensity, iceAccretion, // adding
1509  sublimation, leadingEdgeTempCelsius, viewscreen->gameclass->bus->AntiIce ? 1 : 0, liftIceMod, dragIceMod); // removing
1510  _write(iceDumpFile, msg1, strlen(msg1));
1511  }
1512  }
1513 #pragma endregion
1514 
1515 
1516  // St. Elmo's Fire
1517  const float charge = viewscreen->ptrWeather->GetTurbulence() * cloudSeverity * ias / 0.09f; // 175 kts
1518  if (charge > 0.05f) // disappated by static wicks
1519  staticBuildup += charge * fElapsedTime;
1520 
1521 
1522  // deflect is 0-30° to 220 m/s
1523  if (ourcockpit.Vs2 && g_bAugment && playerships[0].reference != REF_ONGROUND && ourcockpit.vdat.thrustaug > 0)
1524  {
1525  // 77 - 67 (10) / 33.5 = 0.2985074626865672 (0.7)
1526  f_temp = Clamp((viewscreen->gameclass->bus->IndicatedAirspeedKms - ourcockpit.Vs2) / (ourcockpit.Vs2 * 0.5f), 0, 1); // 0.078 is 2.0*Vs1-0.078f, 100% at 78 or less, 0% at 85
1527 
1528  // so this way it is 77 / 67 which is 1 (0) @todo once we get the freaking vehicles to fly like real aircraft we can use this one?
1529  //f_temp = Clamp(viewscreen->gameclass->bus->IndicatedAirspeedKms / ourcockpit.Vs2, 0, 1); // 0.078 is 2.0*Vs1-0.078f, 100% at 78 or less, 0% at 85
1530 
1531  f_augment = sqrtf(1.0f - f_temp); // didn't used to be exponential
1532  f_augment *= static_cast<float>(ourcockpit.vdat.thrustaug) / 127.0f;
1533  }
1534  else
1535  f_augment = 0.0f;
1536 
1537 
1538  float f_deflect; // % to deflect based on velocity, 0% to 0.078f, 100% at 0.078f to 25% at 0.176f
1539  if (ourcockpit.gndvehicle)
1540  f_deflect = 1.0f;
1541  else if (viewscreen->gameclass->bus->IndicatedAirspeedKms > ourcockpit.Vs1) // stall
1542  {
1543  f_deflect = (viewscreen->gameclass->bus->IndicatedAirspeedKms - ourcockpit.Vs1) / (ourcockpit.VcMSL - ourcockpit.Vs1); // 0.173 is Vc at MSL
1544  if (f_deflect > 1.0f)
1545  f_deflect = 1.0f;
1546  // 0 at stall to 1 above stall to 0.75 at full speed
1547  f_deflect = sqrtf(1.0f - f_deflect);
1548  if (f_deflect < 0.25f)
1549  f_deflect = 0.25f;
1550  }
1551  else
1552  f_deflect = 1.0f;
1553 
1554 
1555  // AUTOFLYTE SYSTEM ---------------------------------------
1556  // vertical modes
1557  if (viewscreen->gameclass->bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::VerticalMode_TakeOff)
1558  {
1559  // evaluate engines running
1562  if (ourcockpit.vdat.leftengine >= 64)
1563  viewscreen->gameclass->bus->AFCS.DesiredPitchRadians += D3DXToRadian(5.0f);
1564  if (ourcockpit.vdat.clengine >= 64)
1565  viewscreen->gameclass->bus->AFCS.DesiredPitchRadians += D3DXToRadian(5.0f);
1566  if (ourcockpit.vdat.rightengine >= 64)
1567  viewscreen->gameclass->bus->AFCS.DesiredPitchRadians += D3DXToRadian(5.0f);
1568  }
1569 
1570  Swaypoint currentWaypoint = Swaypoint();
1571  if (viewscreen->gameclass->bus->WPtargetC >= 0 && viewscreen->gameclass->bus->WPtargetC < static_cast<long>(viewscreen->gameclass->bus->waypoint.size()))
1572  currentWaypoint = viewscreen->gameclass->bus->waypoint.at(viewscreen->gameclass->bus->WPtargetC);
1573 
1574  if (viewscreen->gameclass->bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::GlideSlope)
1575  {
1576  // check distance
1577  if (viewscreen->gameclass->bus->WPtargetC < 0 || viewscreen->gameclass->bus->WPtargetC >= static_cast<long>(viewscreen->gameclass->bus->waypoint.size()))
1578  throw std::exception("Trying to use a waypoint that doesn't exist in collection for G/S!");
1579 
1580  result = -viewscreen->position - currentWaypoint.location; // this is now the runway threshold waypoint
1581  float dme = D3DXVec3Length(&result);
1582  viewscreen->gameclass->bus->AFCS.DesiredAltitudeKm = 0.8f * dme / 12.4824f; // AGL along localizer path
1583  viewscreen->gameclass->bus->AFCS.DesiredAltitudeKm -= (f_AGL - viewscreen->gameclass->bus->AFCS.DesiredAltitudeKm) * 1.25f; // to get target agl
1584  viewscreen->verticaltime = 4.0f;
1585  viewscreen->gameclass->bus->GlideslopeDeviationRadians = atanf(f_AGL / dme) - D3DXToRadian(3.0f);
1586  }
1587  else
1588  {
1590  }
1591  if (viewscreen->gameclass->bus->AFCS.CurrentVerticalMode >= Bus::Afcs::VerticalModes::AltitudeAgl) // agl or G/S
1592  {
1594  if (f_AGL > 10.0f)
1595  {
1597  }
1598  else
1599  {
1600  viewscreen->gameclass->bus->AFCS.DesiredVsiKms = viewscreen->gameclass->bus->AFCS.DesiredAltitudeKm - f_AGL; // 10% of altitude 1000 fpm we stop 100 short so (tgt-cur)*0.1
1601  if ((fabsf(olddesiredvsi) > 0.300 && fabsf(viewscreen->gameclass->bus->AFCS.DesiredVsiKms) <= 0.300) ||
1602  (fabsf(olddesiredvsi) < 0.060 && fabsf(viewscreen->gameclass->bus->AFCS.DesiredVsiKms) >= 0.060))
1603  {
1604  if (ourcockpit.power > 0.5f)
1605  {
1606  if (viewscreen->gameclass->bus->AFCS.CurrentVerticalMode != Bus::Afcs::VerticalModes::GlideSlope)
1608  }
1609  }
1612  // limit +/- 6000 fpm (30.5 m/s)
1613  if (viewscreen->gameclass->bus->AFCS.DesiredVsiKms > 0.0305f)
1614  viewscreen->gameclass->bus->AFCS.DesiredVsiKms = 0.0305f;
1615  else if (viewscreen->gameclass->bus->AFCS.DesiredVsiKms < -0.0305f)
1616  viewscreen->gameclass->bus->AFCS.DesiredVsiKms = -0.0305f;
1617 
1618  // sprintf_s(msg, 99, "\t AGL\tcur %.3f ", f_AGL);
1619  // _write(logfile, msg, strlen(msg));
1620  }
1621  }
1622  if (viewscreen->gameclass->bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::AltitudeMsl)
1623  {
1624  viewscreen->gameclass->bus->AFCS.DesiredVsiKms = viewscreen->gameclass->bus->AFCS.DesiredAltitudeKm - f_MSL; // 10% of altitude 1000 fpm we stop 100 short so (tgt-cur)*0.1
1625  if ((fabsf(olddesiredvsi) > 0.300f && fabsf(viewscreen->gameclass->bus->AFCS.DesiredVsiKms) <= 0.300f) ||
1626  (fabsf(olddesiredvsi) < 0.060f && fabsf(viewscreen->gameclass->bus->AFCS.DesiredVsiKms) >= 0.060f))
1627  {
1628  if (ourcockpit.power > 0.5f)
1629  {
1631  }
1632  }
1634  viewscreen->gameclass->bus->AFCS.DesiredVsiKms *= 0.2f / ourcockpit.appitagr; // 100 meters we will do 10 m/s to get there
1635  // so T-1 with 2 is .1 but E-10 with 3.5 is .05
1636  // limit +/- 6000 fpm (30.5 m/s)
1637  if (viewscreen->gameclass->bus->AFCS.DesiredVsiKms > 0.0305f)
1638  viewscreen->gameclass->bus->AFCS.DesiredVsiKms = 0.0305f;
1639  else if (viewscreen->gameclass->bus->AFCS.DesiredVsiKms < -0.0305f)
1640  viewscreen->gameclass->bus->AFCS.DesiredVsiKms = -0.0305f;
1641  // desiredvsi*=0.012695510867357302457850903920374;
1642  // sprintf_s(msg, 99, "\t MSL\tcur %.3f", f_MSL);
1643  // _write(logfile, msg, strlen(msg));
1644  }
1645  if (viewscreen->gameclass->bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::SpeedPitch)
1646  {
1647  // 0.090 - 0.080 is +0.010 is 1 deg so *100
1649  const float targetpitch = viewscreen->gameclass->bus->PitchAttitudeRadians + deltaias * 3.0f; // was 10
1650  float diff = targetpitch - viewscreen->gameclass->bus->AFCS.DesiredPitchRadians;
1651  if (diff > 0.052359877559829887307710723054658f) // 3 degrees per second
1652  diff = 0.052359877559829887307710723054658f;
1653  else if (diff < -0.052359877559829887307710723054658f)
1654  diff = -0.052359877559829887307710723054658f;
1655  viewscreen->gameclass->bus->AFCS.DesiredPitchRadians += diff * fElapsedTime; // 0.1-0.01=0.09
1656  // deg limit
1657  if (viewscreen->gameclass->bus->AFCS.DesiredPitchRadians > 0.34906585039886591538473815369772f) // nose up 20
1658  viewscreen->gameclass->bus->AFCS.DesiredPitchRadians = 0.34906585039886591538473815369772f;
1659  else if (viewscreen->gameclass->bus->AFCS.DesiredPitchRadians < -0.26179938779914943653855361527329f) // nose down 15
1660  viewscreen->gameclass->bus->AFCS.DesiredPitchRadians = -0.26179938779914943653855361527329f;
1661  // sprintf_s(msg, 99, "\t VSI\tcur %.3f tgt %.3f", vsi, desiredvsi);
1662  // _write(logfile, msg, strlen(msg));
1663  }
1664  if (viewscreen->gameclass->bus->AFCS.CurrentVerticalMode == Bus::Afcs::VerticalModes::VerticalSpeed ||
1665  viewscreen->gameclass->bus->AFCS.CurrentVerticalMode > Bus::Afcs::VerticalModes::SpeedPitch)
1666  {
1667  // 0.020 - 0.010 is +0.010 is 1 deg so *100
1669  const float targetpitch = viewscreen->gameclass->bus->PitchAttitudeRadians + deltavsi * 3.0f; // was 10
1670  // targetpitch+=fabsf(horizonroll)*0.3f;
1671  float diff = targetpitch - viewscreen->gameclass->bus->AFCS.DesiredPitchRadians;
1672  if (diff > 0.052359877559829887307710723054658f) // 3 degrees per second
1673  diff = 0.052359877559829887307710723054658f;
1674  else if (diff < -0.052359877559829887307710723054658f)
1675  diff = -0.052359877559829887307710723054658f;
1676  viewscreen->gameclass->bus->AFCS.DesiredPitchRadians += diff * fElapsedTime; // 0.1-0.01=0.09
1677  // deg limit
1678  if (viewscreen->gameclass->bus->AFCS.DesiredPitchRadians > 0.34906585039886591538473815369772f) // nose up 20
1679  viewscreen->gameclass->bus->AFCS.DesiredPitchRadians = 0.34906585039886591538473815369772f;
1680  else if (viewscreen->gameclass->bus->AFCS.DesiredPitchRadians < -0.26179938779914943653855361527329f) // nose down 15
1681  viewscreen->gameclass->bus->AFCS.DesiredPitchRadians = -0.26179938779914943653855361527329f;
1682  // sprintf_s(msg, 99, "\t VSI\tcur %.3f tgt %.3f", vsi, desiredvsi);
1683  // _write(logfile, msg, strlen(msg));
1684  }
1686  {
1687  float deltapitch;
1688  if (fabsf(viewscreen->gameclass->bus->RollAttitudeRadians) < D3DX_PI) // unusual attitudes
1689  deltapitch = viewscreen->gameclass->bus->AFCS.DesiredPitchRadians - viewscreen->gameclass->bus->PitchAttitudeRadians;//-playerships[0].pitch;
1690  else
1691  deltapitch = -viewscreen->gameclass->bus->AFCS.DesiredPitchRadians - viewscreen->gameclass->bus->PitchAttitudeRadians;//-playerships[0].pitch;
1692  deltapitch += sinf(fabsf(viewscreen->gameclass->bus->RollAttitudeRadians)) * 0.10472f; // at 30 degrees which is 0.5 we need +3 deg
1693 
1694  // 10 deg, we do max of 3 deg per sec
1695  float desiredrate = Clamp(deltapitch * 0.3f, -0.05236f, 0.05236f);
1696 
1697 
1698  // float authority=fabsf(playerships[0].pitch/0.052359877559829887307710723054658f);
1699  // if (authority>10.0f) // 3 deg/sec==1.0f
1700  // authority=10.0f;
1701  // else if (authority<0.1f)
1702  // authority=0.1f;
1703  // desiredrate*=1.0f/authority;
1704 
1705 
1706  // we want to effect a change on the pitch of a certain number of deg/s/s so we look at how much it did
1707  // from one frame to another and magnify the effect
1708  const float effectivechange = oldpitch - playerships[0].pitch;
1709  float magnify = 1.0f;
1711  magnify = fabsf(oldcorrection - effectivechange) / fabsf(oldcorrection) + 1.0f;
1712  // magnify*=magnify; // 4
1713  if (magnify > 10.0f)
1714  magnify = 10.0f;
1715  else if (magnify < 0.1f)
1716  magnify = 0.1f;
1717 
1718  desiredrate *= magnify;
1719  // follow a running magnify average
1720  // static float magavg=200.0f;
1721  // magavg*=0.995f; // was 100, now 99
1722  // magavg+=magnify; // now 10 again
1723  /* char msg[999];
1724  sprintf_s( msg, 999, "AF* current %.1f requested %.1f magnify %.1f desiredrate %.1f/s",
1725  D3DXToDegree(horizonpitch), D3DXToDegree(desiredpitch), magnify, D3DXToDegree(desiredrate) );
1726  _write(logfile, msg, strlen(msg));
1727  */
1728 
1729  oldpitch = playerships[0].pitch; // save for next time where it should have been
1730  oldcorrection = (desiredrate - playerships[0].pitch) * ourcockpit.appitagr; // was fixed 2.0 agressiveness until 5/26/2019
1731  oldcorrection = Clamp(oldcorrection, -0.5236f, 0.5236f); // 30 degrees
1732  oldcorrection *= fElapsedTime;
1734 
1735  float transfer = viewscreen->pitchInput * ourcockpit.pitchLimitRadians * 0.01f * fElapsedTime * ourcockpit.appitagr; // will be there in less than 60 sec times pitch agressivness
1736  // if transfer>xx // trim runaway sound?
1737  viewscreen->gameclass->bus->PitchTrimScalar += transfer / trimlimiterC; // +1
1738  if (viewscreen->gameclass->bus->PitchTrimScalar > 1.0f) // 16° and 15°
1739  {
1740  transfer -= trimlimiterC * (viewscreen->gameclass->bus->PitchTrimScalar - 1.0f); // 1.1 - 1.0 is .1
1742  }
1743  else if (viewscreen->gameclass->bus->PitchTrimScalar < -1.0f) // -16 < -15 // transfer -1
1744  {
1745  transfer += trimlimiterC * (viewscreen->gameclass->bus->PitchTrimScalar + 1.0f);
1747  }
1748  viewscreen->pitchInput -= transfer;
1749 
1750  viewscreen->pitchInput = Clamp(viewscreen->pitchInput, -1.0f, 1.0f);
1751 
1752 
1753  // send alarm
1754  if (fabsf(viewscreen->pitchInput) > 0.9f && ourcockpit.power > 0.5f)
1756 
1757  // we want pitch to be 0 when desiredpitch==horizonpitch, 3deg/sec when desiredpitch is 10 off
1758  // sprintf_s(msg, 99, "\tPITCH\ttgt %.3f - cur %.3f = dlt %.3f (sat rat %.3f) - cur %.3f = trm %.3f", D3DXToDegree(desiredpitch), D3DXToDegree(horizonpitch), D3DXToDegree(deltapitch), desiredrate, playerships[0].pitch, trim);
1759  // _write(logfile, msg, strlen(msg));
1760  }
1761 
1762  //viewscreen->gameclass->bus->Debug1Vec3.x = currentWaypoint.id;
1763  //viewscreen->gameclass->bus->Debug1Vec3.y = -1;
1764  //viewscreen->gameclass->bus->Debug1Vec3.z = -1;
1765  //viewscreen->gameclass->bus->Debug2Vec3.x = -1; // for course diff
1766 
1767  if (viewscreen->gameclass->bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Navigation ||
1768  viewscreen->gameclass->bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Localizer)
1769  {
1770  if (viewscreen->gameclass->bus->WPtargetC < 0 || viewscreen->gameclass->bus->WPtargetC >= static_cast<long>(viewscreen->gameclass->bus->waypoint.size()))
1771  throw std::exception("Trying to use a waypoint that doesn't exist in collection for NAV/LOC!");
1772  result = -viewscreen->position - currentWaypoint.location;
1773  const float dist = D3DXVec3Length(&result) - f_MSL;
1774  //viewscreen->gameclass->bus->Debug1Vec3.z = dist;
1775  // check to see if close enough to go to LOC mode
1776  if (viewscreen->gameclass->bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Navigation &&
1777  (viewscreen->gameclass->bus->WPtargetC < 0 || viewscreen->gameclass->bus->WPtargetC >= static_cast<long>(viewscreen->gameclass->bus->waypoint.size())))
1778  throw std::exception("Trying to use a waypoint that doesn't exist in collection for LOC!");
1779 
1780  if (viewscreen->gameclass->bus->AFCS.CurrentLateralMode == Bus::Afcs::LateralModes::Navigation && currentWaypoint.type == 1) // NAV mode and FAF waypoint
1781  {
1782  viewscreen->gameclass->bus->AFCS.StandbyLateralMode = Bus::Afcs::LateralModes::Localizer;
1783  viewscreen->gameclass->bus->AFCS.StandbyVerticalMode = Bus::Afcs::VerticalModes::GlideSlope;
1784  Swaypoint runwayWaypoint = Swaypoint();
1785  const short runwayIndex = viewscreen->ptrWaypoints->FindByUniqueId(currentWaypoint.pairedwith);
1786  if (runwayIndex)
1787  runwayWaypoint = viewscreen->gameclass->bus->waypoint.at(runwayIndex);
1788  //viewscreen->gameclass->bus->Debug1Vec3.y = runwayWaypoint.id;
1789 
1790  float hdgdiff = fabsf(viewscreen->insttrk - runwayWaypoint.heading);
1791  // 360-0 is 360, 0-360 is 360 359-2
1792  if (hdgdiff > 180.0f)
1793  hdgdiff -= 360.0f;
1794  //viewscreen->gameclass->bus->Debug2Vec3.x = hdgdiff;
1795  // check distance and bearing difference and sequencer
1796  if (dist < 0.5f && fabsf(hdgdiff) < 30.0f && runwayIndex) // .5km capture tolerance within 30 deg of course and found runway TDZ waypoint
1797  {
1798  logger->Log("###CAPTURE!!");
1799  viewscreen->gameclass->bus->AFCS.CurrentLateralMode = Bus::Afcs::LateralModes::Localizer;
1800  viewscreen->gameclass->bus->AFCS.CurrentVerticalMode = Bus::Afcs::VerticalModes::GlideSlope;
1801  viewscreen->gameclass->bus->AFCS.DesiredCourseRadians = D3DXToRadian(runwayWaypoint.heading); // inbound course
1802  viewscreen->gameclass->bus->WPtargetC = runwayIndex;
1803  if (viewscreen->gameclass->bus->WPtargetC < 0 || viewscreen->gameclass->bus->WPtargetC >= static_cast<long>(viewscreen->gameclass->bus->waypoint.size()))
1804  {
1805  char msg[99];
1806  sprintf_s(msg, 99, "Found the problem WPtargetC %i because of runwayIndex!", viewscreen->gameclass->bus->WPtargetC);
1807  logger->Log(msg, Logger::Level::Error);
1809  }
1810  }
1811  }
1812  else
1813  {
1814  viewscreen->gameclass->bus->AFCS.StandbyLateralMode = Bus::Afcs::LateralModes::LateralMode_Off;
1815  viewscreen->gameclass->bus->AFCS.StandbyVerticalMode = Bus::Afcs::VerticalModes::VerticalMode_Off;
1816  }
1817 
1818 
1819  //LOOK HERE, we were 352.7 he was bear 17.3 so course is 10
1820 
1821  // start with desiredcrs given
1822  // heading to object
1823  float hdg2obj = viewscreen->insthdgDegrees + bear; // 020+020 is 040
1824  if (hdg2obj > 360.0f)
1825  hdg2obj -= 360.0f;
1826  else if (hdg2obj <= 0.0f)
1827  hdg2obj += 360.0f;
1828  // difference between them should be 0
1829  // this is where we need to look for flyover vs. flyby
1830  // https://jira.risetvp.com/view.php?id=456
1831  float correct = hdg2obj - D3DXToDegree(viewscreen->gameclass->bus->AFCS.DesiredCourseRadians); // 020-350 is -330
1832  if (correct > 180.0f) // 359
1833  correct -= 360.0f; // to fix case of 359-0 is 359 instead of -1
1834  else if (correct < -180.0f)
1835  correct += 360.0f;
1836  if (correct > 90.0f) // 179
1837  correct = 180.0f - correct; // 1 to the right
1838  else if (correct < -90.0f) // -179
1839  correct = -180.0f - correct;
1840  correct *= 2.0f;
1841  if (correct > 45.0f)
1842  correct = 45.0f;
1843  else if (correct < -45.0f)
1844  correct = -45.0f;
1845  if (dist < 4.0f)
1846  correct *= dist * 0.25f;
1847 
1848  // if insttrk is 320 and we are 330 then we need to pretend we are +10
1849  float trkadj = viewscreen->insthdgDegrees - viewscreen->insttrk; // +10
1850  if (trkadj > 360.0f)
1851  trkadj -= 360.0f;
1852  else if (trkadj <= 0.0f)
1853  trkadj += 360.0f;
1854 
1858  else if (viewscreen->gameclass->bus->AFCS.DesiredHeadingRadians <= 0.0f)
1860  }
1861  else
1862  {
1863  viewscreen->gameclass->bus->AFCS.StandbyLateralMode = Bus::Afcs::LateralModes::LateralMode_Off;
1864  viewscreen->gameclass->bus->AFCS.StandbyVerticalMode = Bus::Afcs::VerticalModes::VerticalMode_Off;
1865  }
1866 
1867  if (viewscreen->gameclass->bus->AFCS.CurrentLateralMode >= Bus::Afcs::LateralModes::Heading)
1868  {
1869  float desiredrollDegrees = D3DXToDegree(viewscreen->gameclass->bus->AFCS.DesiredHeadingRadians) - viewscreen->insthdgDegrees; // we were 030 and selected 360, that is 330 greater than 180
1870  if (desiredrollDegrees < -180.0f)
1871  desiredrollDegrees = 360.0f + desiredrollDegrees;
1872  else if (desiredrollDegrees > 180.0f) // more than 180 to right
1873  desiredrollDegrees = desiredrollDegrees - 360.0f;
1874  viewscreen->gameclass->bus->AFCS.DesiredRollRadians = D3DXToRadian(desiredrollDegrees); // aggressive A-4 is 1.0f // 30 bank is 10 deg
1875  if (viewscreen->gameclass->bus->AFCS.DesiredRollRadians > 0.523599f)
1877  else if (viewscreen->gameclass->bus->AFCS.DesiredRollRadians < -0.523599f)
1878  viewscreen->gameclass->bus->AFCS.DesiredRollRadians = -0.523599f; // limit to 30 deg of bank
1879  // sprintf_s(msg, 99, "\thdg\ttgt %.3f - cur %.3f = dlt %.3f (clamped %.3f)", desiredhdg, insthdg, desiredhdg-insthdg, D3DXToDegree(desiredroll));
1880  // _write(logfile, msg, strlen(msg));
1881  }
1882  if (viewscreen->gameclass->bus->AFCS.CurrentLateralMode && viewscreen->gameclass->bus->AFCS.AutopilotEngaged) // roll mode is lateralmode==1, this also covers TO/TO at -1
1883  {
1884  // we want 30 deg bank, we are at 0 deg bank so that is 30deg
1885  const float deltaroll = viewscreen->gameclass->bus->AFCS.DesiredRollRadians - viewscreen->gameclass->bus->RollAttitudeRadians;//-D3DXToDegree(playerships[0].roll); // degrees, can be up to 60 usually 30
1886  // desiredrate is 10deg/s
1887  float desiredrate = deltaroll * 0.3f; // 10 deg/s for 30 deg
1888  // desiredrate=D3DXToRadian(desiredrate); everything is in rads
1889  // we want 10 deg per sec max
1890  if (desiredrate > 0.17453292519943295769236907684886f)
1891  desiredrate = 0.17453292519943295769236907684886f;
1892  else if (desiredrate < -0.17453292519943295769236907684886f)
1893  desiredrate = -0.17453292519943295769236907684886f;
1894  // we want roll to be 0 when desiredroll==horizonroll, 10deg/sec when desiredpitch is 30 off
1895  // so we want to increase/decrease the rate
1896  const float ratediff = desiredrate - playerships[0].roll; // we want 10deg per sec, we have 0deg per sec
1897  // so ratediff=10deg/sec, 0 deg/sec is centered, 10deg/sec is full right
1898  float oldcorrection = (ratediff * 3.0f - viewscreen->rollInput) * ourcockpit.aprolagr; // agressiveness, A-4 is 1.0f
1899  if (oldcorrection > 0.523599f)
1900  oldcorrection = 0.523599f;
1901  else if (oldcorrection < -0.523599f)
1902  oldcorrection = -0.523599f; // limit to 30 deg of bank
1903  viewscreen->rollInput += oldcorrection * fElapsedTime;
1904  viewscreen->rollInput = Clamp(viewscreen->rollInput, -1.0f, 1.0f);
1905 
1906  /* char msg[999];
1907  sprintf_s(msg, "desired %.1f° - horizon %.1f° = delta %.1f° *0.3= ratechange %frad - currate %frad = ratediff %frad >>> rolladj %frad/s",
1908  desiredroll, horizonroll, deltaroll, desiredrate, playerships[0].roll, ratediff, ratediff*3.0f-roll);
1909  _write(logfile, msg, strlen(msg));
1910  */
1911  // sprintf_s(msg, 99, "\tROLL\ttgt %.3f - cur %.3f = dlt %.3f (rad %.3f - cur %.3f = trm %.3f)",
1912  // D3DXToDegree(desiredroll), D3DXToDegree(horizonroll), D3DXToDegree(deltaroll), desiredrate, playerships[0].roll, roll);
1913  // _write(logfile, msg, strlen(msg));
1914  }
1915 
1916  if (initFromDeflect)
1917  {
1918  viewscreen->rollInput = playerships[0].rolldeflect / f_deflect;
1919  viewscreen->yawInput = playerships[0].yawdeflect / f_deflect;
1920  if (ourcockpit.pitchLimitRadians != 0)
1922  else
1923  viewscreen->pitchInput = playerships[0].pitchdeflect / f_deflect;
1924  initFromDeflect = false;
1925  }
1926  else
1927  {
1928  playerships[0].rolldeflect = viewscreen->rollInput * f_deflect; // Percent of available AOA deflection
1929  playerships[0].yawdeflect = viewscreen->yawInput * f_deflect;
1930  if (ourcockpit.pitchLimitRadians != 0)
1931  {
1933  playerships[0].pitchdeflect = Clamp(playerships[0].pitchdeflect, -1.0f, 1.0f);
1934  }
1935  else
1936  playerships[0].pitchdeflect = 0.0f;
1937  }
1938 
1940 
1941 
1942 
1943 #pragma region debug
1944  if (playerships[0].pitchdeflect > 1.0f || playerships[0].pitchdeflect < -1.0f || _isnan(playerships[0].pitchdeflect) || isinf(playerships[0].pitchdeflect) ||
1945  playerships[0].rolldeflect > 1.0f || playerships[0].rolldeflect < -1.0f || _isnan(playerships[0].rolldeflect) || isinf(playerships[0].rolldeflect) ||
1946  playerships[0].yawdeflect > 1.0f || playerships[0].yawdeflect < -1.0f || _isnan(playerships[0].yawdeflect) || isinf(playerships[0].yawdeflect))
1947  {
1948  sprintf_s(msg, sizeof(msg), "\tPitch: %f (%f, %f)", playerships[0].pitchdeflect, viewscreen->pitchInput, viewscreen->gameclass->bus->PitchTrimScalar);
1949  logger->Log(msg, Logger::Level::Warn);
1950  sprintf_s(msg, sizeof(msg), "\tRoll: %f (%f)", playerships[0].rolldeflect, viewscreen->rollInput);
1951  logger->Log(msg, Logger::Level::Warn);
1952  sprintf_s(msg, sizeof(msg), "\tYaw: %f (%f)", playerships[0].yawdeflect, viewscreen->yawInput);
1953  logger->Log(msg, Logger::Level::Warn);
1954  sprintf_s(msg, sizeof(msg), "\tf_deflect: %f", f_deflect);
1955  logger->Log(msg, Logger::Level::Warn);
1956  sprintf_s(msg, sizeof(msg), "Trapped a violation computing propulsion...");
1957  logger->Log(msg, Logger::Level::Fatal);
1958  }
1959 #pragma endregion
1960 
1961 
1962 
1963  // RCS pitch roll and yaw
1964  float rollThrustTotal = (-playerships[0].roll / 0.523599f + viewscreen->rollInput) * f_augment * ourcockpit.power * 10.0f; // roll rad/s
1965  float yawThrust = (playerships[0].yaw / 0.523599f + viewscreen->yawInput) * f_augment * ourcockpit.power * 10.0f;
1966  float pitchThrust = (-playerships[0].pitch / 0.523599f + viewscreen->pitchInput) * f_augment * ourcockpit.power * 10.0f;
1967 
1968  rollThrustTotal = Clamp(rollThrustTotal, -1.0, 1.0f) * 870.0f * 60.0f; // 870 pounds, * 40 because shuttle is too slow!?
1969  // to keep it simple we will say that postive values for both left and right mean positive roll right...
1970  // if one wing is missing then it will still roll right at half the torque (should actually be less?) but also translate
1971  const float rollRightThrustLeftSide = rollThrustTotal * max(0, static_cast<float>(ourcockpit.vdat.leftwing)) / 127.0f;
1972  const float rollRightThrustRightSide = rollThrustTotal * max(0, static_cast<float>(ourcockpit.vdat.rightwing)) / 127.0f;
1973 
1974  yawThrust = Clamp(yawThrust, -1.0f, 1.0f) * 870.0f * 200.0f; // 870 pounds, *100 because shuttle is too slow!?
1975  pitchThrust = Clamp(pitchThrust, -1.0f, 1.0f) * 870.0f * 134.0f; // 870 pounds, *67 because shuttle is too slow!?
1976 
1977  rcsThrustYPR = (fabsf(rollRightThrustLeftSide + rollRightThrustRightSide) + fabsf(yawThrust) + fabsf(pitchThrust)) / totalWeightLbs * gForceKmSSC;
1978 
1979 
1980 
1981 
1982  if (relativeWindTrueKms.z != 0)
1983  aoaRad = atanf(-relativeWindTrueKms.y / relativeWindTrueKms.z); // stick shaker and display value
1984  else
1985  aoaRad = D3DX_HALFPI; // stalled
1987  // stall warning is 1 degree before critical angle (hard-coded for all vehicles) and IAS of >20m/s and not WOW
1988  if ((viewscreen->gameclass->bus->AngleOfAttackRadians + 0.0174533f) > 0.2618f &&
1990  playerships[0].reference != REF_ONGROUND)
1991  {
1992  Command command;
1993  command.name = "AuralStall";
1994  viewscreen->gameclass->bus->AddCommand(command, true);
1995  }
1997  {
1998  Command command;
1999  command.name = "AuralOverspeed";
2000  viewscreen->gameclass->bus->AddCommand(command, true);
2001  }
2002 
2003 
2005  const float flapTemp = ourcockpit.flapExtent * ourcockpit.flapMaxDegrees / 45.0f * (ourcockpit.flapAreaModTE * max(0, static_cast<float>(ourcockpit.vdat.flapsTE)) / 127.0f + ourcockpit.flapAreaModLE * max(0, static_cast<float>(ourcockpit.vdat.flapsLE)) / 127.0f);
2006  const float flapCLDelta = MaxCLDelta * flapTemp;
2007  const float flapCDDelta = MaxCDDelta * flapTemp; // can't be negative deflection so no need to ABS
2008 
2009 
2010  // Relative wind for the wings based on roll rate and yaw rate (unverified)
2011  // what would these be, wing roll arm?
2012  const float velinc1 = ourcockpit.b12WingRollArmM * playerships[0].roll * 0.001f; // km in a second for the arc
2013  const float velinc2 = ourcockpit.c9WingYawArmM * playerships[0].yaw * 0.001f; // km in a second for the arc
2014 
2015  // Right wing (AOA changes with current roll and yaw rates)
2016  f_temp = relativeWindTrueKms.z - velinc2; // apparent wind velocity (could include pitch too?)
2017  float tempq = dynamicDensity * rhoOver2SlugsCuFt2 * powf(f_temp * 3280.8f, 2.0f);
2018 
2019  float tempLiftWingRight = 0.0f; float tempDragWingRight = 0.0f;
2020  if (ourcockpit.vdat.rightwing > 0 && f_temp != 0.0f)
2021  {
2022  // aileron needs to be baked into CLDelta and CDDelta like flaps
2023  const float aileronTemp = playerships[0].rolldeflect * (ourcockpit.aileronAreaMod * max(0, static_cast<float>(ourcockpit.vdat.rightaileron)) / 127.0f);
2024  const float aileronCLDelta = MaxCLDelta * aileronTemp;
2025  const float aileronCDDelta = MaxCDDelta * fabsf(aileronTemp);
2026 
2027  // Surface area I12 each wing ft² (this is effective vertical area translated to the CG)
2029  tempaoa = atanf((-relativeWindTrueKms.y - velinc1) / f_temp) + ourcockpit.aoiWingRad; // roll+right produces - wind on y
2030  const float Cl = CalculateLiftCoefficient(AirfoilType::Asymm, tempaoa, flapCLDelta - aileronCLDelta);
2031  tempLiftWingRight = Cl * tempq * S * static_cast<float>(ourcockpit.vdat.rightwing) / 127.0f * liftIceMod;
2032  const float Cd = CalculateDragCoefficient(AirfoilType::Asymm, tempaoa, flapCDDelta - aileronCDDelta);
2033  tempDragWingRight = Cd * tempq * S * static_cast<float>(ourcockpit.vdat.rightwing) / 127.0f * dragIceMod;
2034  }
2035 
2036  // Left wing (AOA changes with current roll and yaw rates)
2037  f_temp = relativeWindTrueKms.z + velinc2; // apparent wind velocity (could include pitch too?)
2038  tempq = dynamicDensity * rhoOver2SlugsCuFt2 * powf(f_temp * 3280.8f, 2.0f); // convert to ft/s from km/s
2039 
2040  float tempLiftWingLeft = 0.0f; float tempDragWingLeft = 0.0f;
2041  if (ourcockpit.vdat.leftwing > 0 && f_temp != 0.0f)
2042  {
2043  // aileron needs to be baked into CLDelta and CDDelta like flaps
2044  const float aileronTemp = playerships[0].rolldeflect * (ourcockpit.aileronAreaMod * max(0, static_cast<float>(ourcockpit.vdat.leftaileron)) / 127.0f);
2045  const float aileronCLDelta = MaxCLDelta * aileronTemp;
2046  const float aileronCDDelta = MaxCDDelta * fabsf(aileronTemp);
2047 
2048  // Surface area I12 each wing ft² (this is effective vertical area translated to the CG)
2050  tempaoa = atanf((-relativeWindTrueKms.y + velinc1) / f_temp) + ourcockpit.aoiWingRad; // roll+right produces + wind on y
2051  const float Cl = CalculateLiftCoefficient(AirfoilType::Asymm, tempaoa, flapCLDelta + aileronCLDelta);
2052  tempLiftWingLeft = Cl * tempq * S * static_cast<float>(ourcockpit.vdat.leftwing) / 127.0f * liftIceMod;
2053  const float Cd = CalculateDragCoefficient(AirfoilType::Asymm, tempaoa, flapCDDelta + aileronCDDelta);
2054  tempDragWingLeft = Cd * tempq * S * static_cast<float>(ourcockpit.vdat.leftwing) / 127.0f * dragIceMod;
2055  }
2056 
2057  // Where they are equal, we get vertical lift (smaller of the two is the vertical rise)
2058  // Perpendicular to roll and pitch, but not quite over CG (95.7% effective)
2059  f_temp = (tempLiftWingRight + tempLiftWingLeft + rollRightThrustLeftSide - rollRightThrustRightSide) * gForceKmSSC / totalWeightLbs * fElapsedTime; // negative is going up
2060  f_temp *= groundeffect;
2061 
2062  sprintf_s(msg, sizeof(msg), "X%7.3f Y%7.3f Z%7.3f wing lift", 0.0f, f_temp * oneOvergForceKmSSC / fElapsedTime, 0.0f);
2063  viewscreen->sofTracking.emplace_back(msg);
2064 
2065  sumofforces.y += f_temp; // lift
2066 
2067 #pragma region debug
2068  if (sumofforces.x > 100.0f || sumofforces.x < -100.0f || _isnan(sumofforces.x) || isinf(sumofforces.x) ||
2069  sumofforces.y > 100.0f || sumofforces.y < -100.0f || _isnan(sumofforces.y) || isinf(sumofforces.y) ||
2070  sumofforces.z > 100.0f || sumofforces.z < -100.0f || _isnan(sumofforces.z) || isinf(sumofforces.z))
2071  {
2072  sprintf_s(msg, sizeof(msg), "\tET: %f", fElapsedTime);
2073  logger->Log(msg, Logger::Level::Debug);
2074  sprintf_s(msg, sizeof(msg), "\tsumofforces I: %f", sumofforces.x);
2075  logger->Log(msg, Logger::Level::Debug);
2076  sprintf_s(msg, sizeof(msg), "\tsumofforces J: %f", sumofforces.y);
2077  logger->Log(msg, Logger::Level::Debug);
2078  sprintf_s(msg, sizeof(msg), "\tsumofforces K: %f", sumofforces.z);
2079  logger->Log(msg, Logger::Level::Debug);
2080  sprintf_s(msg, sizeof(msg), "\tlift2: %f", f_temp);
2081  logger->Log(msg, Logger::Level::Debug);
2082  sprintf_s(msg, sizeof(msg), "\ttotalWeightLbs: %f", totalWeightLbs);
2083  logger->Log(msg, Logger::Level::Debug);
2084  sprintf_s(msg, sizeof(msg), "\ttempLiftWingRight: %f", tempLiftWingRight);
2085  logger->Log(msg, Logger::Level::Debug);
2086  sprintf_s(msg, sizeof(msg), "\ttempLiftWingLeft: %f", tempLiftWingLeft);
2087  logger->Log(msg, Logger::Level::Debug);
2088  sprintf_s(msg, sizeof(msg), "\trollRightThrustLeftSide: %f", rollRightThrustLeftSide);
2089  logger->Log(msg, Logger::Level::Debug);
2090  sprintf_s(msg, sizeof(msg), "\trollRightThrustRightSide: %f", rollRightThrustRightSide);
2091  logger->Log(msg, Logger::Level::Debug);
2092  sprintf_s(msg, sizeof(msg), "\tgroundeffect: %f", groundeffect);
2093  logger->Log(msg, Logger::Level::Debug);
2095  sprintf_s(msg, sizeof(msg), "Trapped a violation after lift2 application...");
2096  logger->Log(msg, Logger::Level::Fatal);
2097  }
2098 #pragma endregion
2099 
2100 
2101  float momentp = -ourcockpit.b15WingPitchArmM * (tempLiftWingRight + tempLiftWingLeft); // B15 lb-m the wing, applied aft of CG nose up is +, nose down is - (verified)
2102 
2103  // But the difference causes rolling moment on the wing arm
2104  // B12 rolling moment in lb-m (verified)
2105  // wingspan in meters is total width... must be halved
2106  float momentr = ourcockpit.b12WingRollArmM * (tempLiftWingLeft - tempLiftWingRight) + ourcockpit.wingspanM * 0.5f * (rollRightThrustLeftSide + rollRightThrustRightSide);
2107 
2108  // arm in m gives us velocity times roll rate to get average velocity ***
2109  // Rolling drag, using weighted arm in ft (arm²) to find average velocity in ft, then square
2110  f_temp = powf(ourcockpit.e65wase61 * 3.2808f * playerships[0].roll, 2.0f); // E63 ft/s
2111  // Multiplied pounds of drag the surface area corrected for Cd max, to ft², rho/2, at arm (m)
2112  if (playerships[0].roll > 0.0f)
2113  momentr -= ourcockpit.d65wasd61 * f_temp * dynamicDensity; // D63
2114  else
2115  momentr += ourcockpit.d65wasd61 * f_temp * dynamicDensity; // D63
2116 
2117  rollAccelerationSnapshot = momentr / (ourcockpit.momentr * totalWeightLbs) * fElapsedTime;
2118  // Left wing more lift rolls right, convert to angular velocity by dividing by MI about Z
2119  //if (!ourcockpit.gndvehicle) // to test for bill, shouldn't need to exclude
2120  playerships[0].roll += rollAccelerationSnapshot; // (verified intertial) 107.901512
2121 
2122 
2123  // Longitudinal pitching moment -------------------------------------------------------------
2124  // up is +, down is -
2125  float tempLiftElevator = 0.0f;
2126  if (ourcockpit.vdat.htail > 0)
2127  {
2128  // Determine Cl's for Htail
2129  tempaoa = -aoaRad + 0.03f; // Add AOI (negative is nose down VERIFIED) .03 = 1.72 degrees
2131 
2132  // aileron needs to be baked into CLDelta and CDDelta like flaps
2133  const float elevatorTemp = playerships[0].pitchdeflect * (ourcockpit.elevatorAreaMod * max(0, static_cast<float>(ourcockpit.vdat.elevator)) / 127.0f);
2134  const float elevatorCLDelta = MaxCLDelta * elevatorTemp;
2135  const float elevatorCDDelta = MaxCDDelta * fabsf(elevatorTemp);
2136 
2137  const float Cl = CalculateLiftCoefficient(AirfoilType::Symm, tempaoa, elevatorCLDelta);
2138  tempLiftElevator = Cl * qz * S * max(0, static_cast<float>(ourcockpit.vdat.htail)) / 127.0f * liftIceMod; // qz figured in vertical translation area
2139  const float Cd = CalculateDragCoefficient(AirfoilType::Symm, tempaoa, elevatorCDDelta);
2140  tempDragTail += Cd * qz * S * max(0, static_cast<float>(ourcockpit.vdat.htail)) / 127.0f * dragIceMod; // qz figured in vertical translation area
2141  if (_isnan(tempDragTail) || isinf(tempDragTail))
2142  {
2143  sprintf_s(msg, sizeof(msg), "Going to crap out on air friction tempDragHTail!");
2144  logger->Log(msg, Logger::Level::Error);
2145  tempDragTail = 0;
2146  sprintf_s(msg, sizeof(msg), "Cd: %f", Cd);
2147  logger->Log(msg, Logger::Level::Debug);
2148  sprintf_s(msg, sizeof(msg), "qz: %f", qz);
2149  logger->Log(msg, Logger::Level::Debug);
2150  sprintf_s(msg, sizeof(msg), "S: %f", S);
2151  logger->Log(msg, Logger::Level::Debug);
2152  sprintf_s(msg, sizeof(msg), "ourcockpit.vdat.htail: %i", ourcockpit.vdat.htail);
2153  logger->Log(msg, Logger::Level::Debug);
2154  sprintf_s(msg, sizeof(msg), "dragIceMod: %f", dragIceMod);
2155  logger->Log(msg, Logger::Level::Debug);
2156  }
2157  }
2158 
2159  // Convert to torque at arm (variable with Cp)
2160  // positive value pushes down (nose up), negative value pulls up (nose down) (lb-m)
2161  momentp += fabsf(ourcockpit.b6DistanceToHTailM) * tempLiftElevator + ourcockpit.rcsYParmM * pitchThrust; // B6 (verified)
2162  f_temp = tempLiftElevator * gForceKmSSC / totalWeightLbs * fElapsedTime; // negative is going up
2163 
2164  sprintf_s(msg, sizeof(msg), "X%7.3f Y%7.3f Z%7.3f htail lift", 0.0f, f_temp * oneOvergForceKmSSC / fElapsedTime, 0.0f);
2165  viewscreen->sofTracking.emplace_back(msg);
2166 
2167  sumofforces.y += f_temp; // lift
2168 
2169 #pragma region debug
2170  if (sumofforces.x > 100.0f || sumofforces.x < -100.0f || _isnan(sumofforces.x) || isinf(sumofforces.x) ||
2171  sumofforces.y > 100.0f || sumofforces.y < -100.0f || _isnan(sumofforces.y) || isinf(sumofforces.y) ||
2172  sumofforces.z > 100.0f || sumofforces.z < -100.0f || _isnan(sumofforces.z) || isinf(sumofforces.z))
2173  {
2174  sprintf_s(msg, sizeof(msg), "\tET: %f", fElapsedTime);
2175  logger->Log(msg, Logger::Level::Warn);
2176  sprintf_s(msg, sizeof(msg), "\tsumofforces I: %f", sumofforces.x);
2177  logger->Log(msg, Logger::Level::Warn);
2178  sprintf_s(msg, sizeof(msg), "\tsumofforces J: %f", sumofforces.y);
2179  logger->Log(msg, Logger::Level::Warn);
2180  sprintf_s(msg, sizeof(msg), "\tsumofforces K: %f", sumofforces.z);
2181  logger->Log(msg, Logger::Level::Warn);
2182  sprintf_s(msg, sizeof(msg), "\tlift: %f", f_temp);
2183  logger->Log(msg, Logger::Level::Warn);
2185  sprintf_s(msg, sizeof(msg), "Trapped a violation after lift application...");
2186  logger->Log(msg, Logger::Level::Fatal);
2187  }
2188 #pragma endregion
2189 
2190  // Weathervaning tendency
2191  f_temp = powf(relativeWindTrueKms.y * 3280.8f, 2.0f);
2192  if (relativeWindTrueKms.y > 0.0f)
2193  f_temp = -f_temp;
2194  // Pitching drag, using arm in ft to find average velocity in ft/s
2195  // if (playerships[0].pitch<0.0f)
2196  // f_temp+=powf(ourcockpit.b6*3.2808f*playerships[0].pitch, 2.0f);
2197  // else
2198  // f_temp-=powf(ourcockpit.b6*3.2808f*playerships[0].pitch, 2.0f);
2199  // Multiplied pounds of drag the surface area corrected for Cd max, to ft², rho/2, at arm (m)
2200  if (ourcockpit.vdat.htail > 0)
2201  momentp += (ourcockpit.i66wasi62 + ourcockpit.k66wask62 * static_cast<float>(ourcockpit.vdat.htail) / 127.0f) * f_temp * dynamicDensity; // lbs at m
2202  else
2203  momentp += ourcockpit.i66wasi62 * f_temp * dynamicDensity; // lbs at m
2204 
2205  // pounds at meters business is accelleration km/s so convert to pounds of force
2206  momentp += ourcockpit.l48AverageEnginePitchArmM * ourcockpit.maxGrossLbs * zThrustAcceleration * oneOvergForceKmSSC;
2207 
2208 
2209  // Convert to angular velocity by dividing by inertial moment about X axis
2210 
2211  pitchAccelerationSnapshot = momentp / (ourcockpit.momentp * totalWeightLbs) * fElapsedTime;
2212  playerships[0].pitch += pitchAccelerationSnapshot; // (verified inertial) 154.817291
2213 
2214 
2215  // Longitudinal pitching moment -------------------------------------------------------------
2216 
2217 
2218 #pragma region Directional Moment
2219  float tempLiftRudder = 0.0f;
2220  if (ourcockpit.vdat.vtail > 0)
2221  {
2222  // AOA plus rate of turn adds relative wind plus deflection changes camber
2223  if (relativeWindTrueKms.z != 0.0f)
2224  tempaoa = atanf(relativeWindTrueKms.x / relativeWindTrueKms.z);
2225  else
2226  tempaoa = D3DX_HALFPI; // Stalled
2227  if (viewscreen->gameclass->bus->YawDamperStatus && ourcockpit.vdat.yawdamper)
2229  else
2231  const float yawDeflect = viewscreen->gameclass->bus->YawDamperCommand + playerships[0].yawdeflect;
2232  S = ourcockpit.d17VTailWithRudderSqFt; // I9 Surface area in ft² of the HCl tail including rudder area
2233  const float rudderDelta = yawDeflect * ourcockpit.h9RudderSqFt / S / 0.25f * static_cast<float>(max(0, ourcockpit.vdat.rudder)) / 127.0f;
2234  const float Cl = CalculateLiftCoefficient(AirfoilType::Symm, tempaoa, rudderDelta * MaxCLDelta);
2235  tempLiftRudder = Cl * qz * S * static_cast<float>(ourcockpit.vdat.vtail) / 127.0f * liftIceMod; // qz figured in vertical translation area
2236  const float Cd = CalculateDragCoefficient(AirfoilType::Symm, tempaoa, rudderDelta * MaxCDDelta);
2237  tempDragTail += Cd * qz * S * static_cast<float>(ourcockpit.vdat.vtail) / 127.0f * dragIceMod; // qz figured in vertical translation area
2238  if (_isnan(tempDragTail) || isinf(tempDragTail))
2239  {
2240  sprintf_s(msg, sizeof(msg), "Going to crap out on air friction tempDragVTail!");
2241  logger->Log(msg, Logger::Level::Error);
2242  tempDragTail = 0;
2243  sprintf_s(msg, sizeof(msg), "Cd: %f", Cd);
2244  logger->Log(msg, Logger::Level::Debug);
2245  sprintf_s(msg, sizeof(msg), "qz: %f", qz);
2246  logger->Log(msg, Logger::Level::Debug);
2247  sprintf_s(msg, sizeof(msg), "S: %f", S);
2248  logger->Log(msg, Logger::Level::Debug);
2249  sprintf_s(msg, sizeof(msg), "ourcockpit.vdat.vtail: %i", ourcockpit.vdat.vtail);
2250  logger->Log(msg, Logger::Level::Debug);
2251  sprintf_s(msg, sizeof(msg), "dragIceMod: %f", dragIceMod);
2252  logger->Log(msg, Logger::Level::Debug);
2253  }
2254  }
2255  else
2257 
2258 
2259  float momenty = ourcockpit.b9DistanceToVTailM * tempLiftRudder + ourcockpit.rcsYParmM * yawThrust; // B9 verified DV (m)
2260  momenty += ourcockpit.c9WingYawArmM * (tempDragWingRight - tempDragWingLeft); // adverse yaw
2261 
2262 
2263  // asymmetric thrust
2264  if (ourcockpit.engines > 1)
2265  {
2266  // Convert to torque at arm (variable with Cp)
2267  // Add difference of the two engines (lb-m)
2268  float business = 0.0f;
2270  if (ourcockpit.engines == 2)
2271  {
2273  }
2274  else if (ourcockpit.engines == 3)
2275  {
2277  }
2278  // pounds at meters business is accelleration km/s so convert to pounds of force
2279 
2281  }
2282 
2283 
2284  // Weathervaning tendency weathervane
2285  f_temp = powf(relativeWindTrueKms.x * 3280.8f, 2.0f);
2286  if (relativeWindTrueKms.x > 0.0f)
2287  f_temp = -f_temp;
2288  // Pitching drag, using arm in ft to find average velocity in ft/s
2289  // if (playerships[0].pitch<0.0f)
2290  // f_temp+=powf(ourcockpit.b6*3.2808f*playerships[0].pitch, 2.0f);
2291  // else
2292  // f_temp-=powf(ourcockpit.b6*3.2808f*playerships[0].pitch, 2.0f);
2293  // Multiplied pounds of drag the surface area corrected for Cd max, to ft², rho/2, at arm (m)
2294  if (ourcockpit.vdat.vtail > 0)
2295  momenty += (ourcockpit.i65wasi61 + ourcockpit.k65wask61 * static_cast<float>(ourcockpit.vdat.vtail) / 127.0f) * f_temp * dynamicDensity; // lbs at m
2296  else
2297  momenty += ourcockpit.i65wasi61 * f_temp * dynamicDensity; // lbs at m
2298 
2299 
2300  yawAccelerationSnapshot = momenty / (ourcockpit.momenty * totalWeightLbs) * fElapsedTime;
2301  // Convert to angular velocity by dividing by inertial moment about Y axis
2302  if (playerships[0].reference != REF_ONGROUND)
2303  {
2304  playerships[0].yaw -= yawAccelerationSnapshot; // (verified inertial) 246.996033
2305  //logger->Log("Not steering1");
2306  }
2307  else
2308  {
2309  // wheels must be on ground
2311  fabsf(levelerroll) <= 0.9f && // can't be rolled more than 60 deg
2312  levelerpitch <= 0.1f) // steering wheels must be on ground
2313  {
2314  // this is force that will make the nose tire turn one way or the other
2315  // the *10 is how easily (lower = harder) to move the steering, more wheels makes it harder
2316  const float tireTurnForce = yawAccelerationSnapshot * groundvec.z / ourcockpit.steerTires * 200.0f;
2317 
2319  // made the ground velocity fabs
2320  const float tireStraightenForce = copysignf(sqrtf(fabsf(viewscreen->yawInput)), viewscreen->yawInput) * -fabsf(groundvec.z) * ourcockpit.steerTires;
2321 
2322  viewscreen->yawInput -= tireTurnForce;
2323 
2324  // so for C-2 to work right we have to do 10% of this force
2325  // for T-1 to work right we need 100%
2326 
2327  const float oldYawInput = viewscreen->yawInput;
2328  viewscreen->yawInput += tireStraightenForce;
2329  if ((viewscreen->yawInput > 0 && oldYawInput < 0) ||
2330  (viewscreen->yawInput < 0 && oldYawInput > 0))
2331  viewscreen->yawInput = 0;
2332 
2333  viewscreen->yawInput = Clamp(viewscreen->yawInput, -1.0f, 1.0f);
2334 
2336 
2337 
2338  // This is ground speed until wind is factored in
2339  viewscreen->gameclass->bus->DebugFloat3 = D3DXToDegree(f_temp);
2340  viewscreen->gameclass->bus->DebugFloat4 = tireTurnForce;
2341  viewscreen->gameclass->bus->DebugFloat5 = tireStraightenForce;
2343 
2344 
2345  // yaw input is radians ...
2346  playerships[0].yaw = f_temp * groundvec.z / ourcockpit.noseWheelToCgKm * 1.57f * 0.1f;
2347  }
2349  logger->Log("Not steering2");
2350  }
2351 
2352 #pragma endregion
2353 
2354 
2355 
2356 
2357 
2358 
2359  // normal velocity changes
2360 
2361  // Atmospheric drag in pounds (once multiplied by Cx which equates to Cd, q at MSL, and S)
2362  // Convert to thrust
2364  // Then fix for fraction of second
2365  f_temp *= fElapsedTime;
2366 
2367 
2368  result = centerC;
2369  // damage to tail, wings should increase the drag by 33% from 127 to 64 then taper to 0
2370  // ****@@@@****@@@@***
2371  if (relativeWindTrueKms.z > 0.0f) // Frontal
2372  {
2373  result.z += ourcockpit.f20FrontBackDragCoeff * f_temp * powf(relativeWindTrueKms.z * 3280.8f, 2.0f);
2374  result.z += ourcockpit.f25 * ourcockpit.gearextent * f_temp * powf(relativeWindTrueKms.z * 3280.8f, 2.0f);
2375  result.z += (tempDragWingRight + tempDragWingLeft + tempDragTail) * fElapsedTime * gForceKmSSC / totalWeightLbs;
2376  }
2377  else // Rear
2378  {
2379  result.z -= ourcockpit.f20FrontBackDragCoeff * f_temp * powf(relativeWindTrueKms.z * 3280.8f, 2.0f);
2380  result.z -= ourcockpit.f25 * ourcockpit.gearextent * f_temp * powf(relativeWindTrueKms.z * 3280.8f, 2.0f);
2381  result.z -= (tempDragWingRight + tempDragWingLeft + tempDragTail) * fElapsedTime * gForceKmSSC / totalWeightLbs;
2382  }
2383  if (_isnan(result.z) || isinf(result.z))
2384  {
2385  sprintf_s(msg, sizeof(msg), "Going to crap out on air friction result.z!");
2386  logger->Log(msg, Logger::Level::Error);
2387  result.z = 0;
2388  sprintf_s(msg, sizeof(msg), "f_temp: %f", f_temp);
2389  logger->Log(msg, Logger::Level::Debug);
2390  sprintf_s(msg, sizeof(msg), "relativeWindTrueKms.z: %f", relativeWindTrueKms.z);
2391  logger->Log(msg, Logger::Level::Debug);
2392  sprintf_s(msg, sizeof(msg), "ourcockpit.f20FrontBackDragCoeff: %f", ourcockpit.f20FrontBackDragCoeff);
2393  logger->Log(msg, Logger::Level::Debug);
2394  sprintf_s(msg, sizeof(msg), "ourcockpit.f25: %f", ourcockpit.f25);
2395  logger->Log(msg, Logger::Level::Debug);
2396  sprintf_s(msg, sizeof(msg), "ourcockpit.gearextent: %f", ourcockpit.gearextent);
2397  logger->Log(msg, Logger::Level::Debug);
2398  sprintf_s(msg, sizeof(msg), "tempDragWingRight: %f", tempDragWingRight);
2399  logger->Log(msg, Logger::Level::Debug);
2400  sprintf_s(msg, sizeof(msg), "tempDragWingLeft: %f", tempDragWingLeft);
2401  logger->Log(msg, Logger::Level::Debug);
2402  sprintf_s(msg, sizeof(msg), "tempDragTail: %f", tempDragTail);
2403  logger->Log(msg, Logger::Level::Debug);
2404  sprintf_s(msg, sizeof(msg), "totalWeightLbs: %f", totalWeightLbs);
2405  logger->Log(msg, Logger::Level::Debug);
2406  sprintf_s(msg, sizeof(msg), "fElapsedTime: %f", fElapsedTime);
2407  logger->Log(msg, Logger::Level::Debug);
2408  }
2409 
2410  if (relativeWindTrueKms.y > 0.0f) // Lower F27
2411  result.y += ourcockpit.f27 * f_temp * powf(relativeWindTrueKms.y * 3280.8f, 2.0f);
2412  else // Upper F28
2413  result.y -= ourcockpit.f27 * f_temp * powf(relativeWindTrueKms.y * 3280.8f, 2.0f);
2414  if (relativeWindTrueKms.x > 0.0f) // Sideways left F29
2415  {
2416  result.x += ourcockpit.f28 * f_temp * powf(relativeWindTrueKms.x * 3280.8f, 2.0f);
2417  // should include gear extended case someday
2418  }
2419  else // Sideways right F29
2420  {
2421  result.x -= ourcockpit.f28 * f_temp * powf(relativeWindTrueKms.x * 3280.8f, 2.0f);
2422  // should include gear extended case someday
2423  }
2424 
2425  if (result.x > 100.0f || result.x < -100.0f || _isnan(result.x) || isinf(result.x) ||
2426  result.y > 100.0f || result.y < -100.0f || _isnan(result.y) || isinf(result.y) ||
2427  result.z > 100.0f || result.z < -100.0f || _isnan(result.z) || isinf(result.z))
2428  {
2429  sprintf_s(msg, sizeof(msg), "ET: %f", fElapsedTime);
2430  logger->Log(msg, Logger::Level::Warn);
2431  sprintf_s(msg, sizeof(msg), "Result I: %f", result.x);
2432  logger->Log(msg, Logger::Level::Debug);
2433  sprintf_s(msg, sizeof(msg), "Result J: %f", result.y);
2434  logger->Log(msg, Logger::Level::Debug);
2435  sprintf_s(msg, sizeof(msg), "Result K: %f", result.z);
2436  logger->Log(msg, Logger::Level::Debug);
2437  sprintf_s(msg, sizeof(msg), "Relative I: %f", relativeWindTrueKms.x);
2438  logger->Log(msg, Logger::Level::Debug);
2439  sprintf_s(msg, sizeof(msg), "Relative J: %f", relativeWindTrueKms.y);
2440  logger->Log(msg, Logger::Level::Debug);
2441  sprintf_s(msg, sizeof(msg), "Relative K: %f", relativeWindTrueKms.z);
2442  logger->Log(msg, Logger::Level::Debug);
2443  sprintf_s(msg, sizeof(msg), "Weight: %f", totalWeightLbs);
2444  logger->Log(msg, Logger::Level::Warn);
2445  sprintf_s(msg, sizeof(msg), "Density: %f", staticDensity);
2446  logger->Log(msg, Logger::Level::Warn);
2447  sprintf_s(msg, sizeof(msg), "f_temp: %f", f_temp);
2448  logger->Log(msg, Logger::Level::Debug);
2449  sprintf_s(msg, sizeof(msg), "Empty Weight: %f", ourcockpit.emptyWeightLbs);
2450  logger->Log(msg, Logger::Level::Warn);
2451  sprintf_s(msg, sizeof(msg), "Trapped a violation after air friction...");
2452  logger->Log(msg, Logger::Level::Fatal);
2453  }
2454  else
2455  {
2456  sprintf_s(msg, sizeof(msg), "X%7.3f Y%7.3f Z%7.3f air friction", result.x * oneOvergForceKmSSC / fElapsedTime, result.y * oneOvergForceKmSSC / fElapsedTime, result.z * oneOvergForceKmSSC / fElapsedTime);
2457  viewscreen->sofTracking.emplace_back(msg);
2458  sumofforces += result; // drag from air friction
2459  }
2460 
2461 
2462 
2463 
2464  // Velocity local to ship orientation section -----------------------------------------------
2465 
2466  } // MSL=-1 contained in identity because altitude is not yet determined
2467  else
2468  speedOfSoundKms = 0.343f;
2469  }
2470  else
2471  {
2472  speedOfSoundKms = 0.343f;
2473  }
2474  // Atmospheric functions ************************************************************************
2475 #pragma endregion
2476 
2477 
2478  logger->AddToCallStack("SumOfForcesInAnotherVessel");
2479 
2480  if (playerships[0].reference == REF_INANOTHER)
2481  {
2482  sumofforces.x += playerships[playerships[0].inarray].acc.x * gForceKmSSC * fElapsedTime;
2483  sumofforces.y += playerships[playerships[0].inarray].acc.y * gForceKmSSC * fElapsedTime;
2484  sumofforces.z += playerships[playerships[0].inarray].acc.z * gForceKmSSC * fElapsedTime;
2485  sprintf_s(msg, sizeof(msg), "X%7.3f Y%7.3f Z%7.3f parent",
2486  playerships[playerships[0].inarray].acc.x,
2489  viewscreen->sofTracking.emplace_back(msg);
2490  }
2491  else
2492  {
2493 #pragma region debug
2494  // ok, this is the exciting part... need to add sumofforces to velocity
2495  if (sumofforces.x > 100.0f || sumofforces.x < -100.0f || _isnan(sumofforces.x) || isinf(sumofforces.x) ||
2496  sumofforces.y > 100.0f || sumofforces.y < -100.0f || _isnan(sumofforces.y) || isinf(sumofforces.y) ||
2497  sumofforces.z > 100.0f || sumofforces.z < -100.0f || _isnan(sumofforces.z) || isinf(sumofforces.z))
2498  {
2499  sprintf_s(msg, sizeof(msg), "ET: %f", fElapsedTime);
2500  logger->Log(msg, Logger::Level::Warn);
2501  sprintf_s(msg, sizeof(msg), "sumofforces I: %f", sumofforces.x);
2502  logger->Log(msg, Logger::Level::Warn);
2503  sprintf_s(msg, sizeof(msg), "sumofforces J: %f", sumofforces.y);
2504  logger->Log(msg, Logger::Level::Warn);
2505  sprintf_s(msg, sizeof(msg), "sumofforces K: %f", sumofforces.z);
2506  logger->Log(msg, Logger::Level::Warn);
2507  sprintf_s(msg, sizeof(msg), "velocity I: %f", velocity.x);
2508  logger->Log(msg, Logger::Level::Warn);
2509  sprintf_s(msg, sizeof(msg), "velocity J: %f", velocity.y);
2510  logger->Log(msg, Logger::Level::Warn);
2511  sprintf_s(msg, sizeof(msg), "velocity K: %f", velocity.z);
2512  logger->Log(msg, Logger::Level::Warn);
2514  sprintf_s(msg, sizeof(msg), "Trapped a violation before sumofforces application...");
2515  logger->Log(msg, Logger::Level::Fatal);
2516  }
2517 #pragma endregion
2518 
2519  velocity += sumofforces;
2520 
2521  // put velocity back into universe terms, keep sumofforces in local terms
2522  D3DXVec3TransformNormal(&playerships[0].velocity, &velocity, &playerships[0].matrixWorld); // Velocity local back to ship orientation
2523  if (playerships[0].reference >= REF_DOCKCPOC)
2524  {
2525  Tdockingvel += sumofforces;
2526  D3DXVec3TransformNormal(&playerships[0].dockingvel, &Tdockingvel, &playerships[0].matrixWorld); // Velocity local to ship orientation Tdockingvel.z+=f_temp*fElapsedTime;
2527  }
2528 
2529  if (playerships[0].velocity.x > 100.0f || playerships[0].velocity.x < -100.0f || _isnan(playerships[0].velocity.x) || isinf(playerships[0].velocity.x) ||
2530  playerships[0].velocity.y > 100.0f || playerships[0].velocity.y < -100.0f || _isnan(playerships[0].velocity.y) || isinf(playerships[0].velocity.y) ||
2531  playerships[0].velocity.z > 100.0f || playerships[0].velocity.z < -100.0f || _isnan(playerships[0].velocity.z) || isinf(playerships[0].velocity.z))
2532  {
2533  sprintf_s(msg, sizeof(msg), "ET: %f", fElapsedTime);
2534  logger->Log(msg, Logger::Level::Warn);
2535  sprintf_s(msg, sizeof(msg), "universe I: %f", playerships[0].velocity.x);
2536  logger->Log(msg, Logger::Level::Warn);
2537  sprintf_s(msg, sizeof(msg), "universe J: %f", playerships[0].velocity.y);
2538  logger->Log(msg, Logger::Level::Warn);
2539  sprintf_s(msg, sizeof(msg), "universe K: %f", playerships[0].velocity.z);
2540  logger->Log(msg, Logger::Level::Warn);
2541  sprintf_s(msg, sizeof(msg), "local I: %f", velocity.x);
2542  logger->Log(msg, Logger::Level::Warn);
2543  sprintf_s(msg, sizeof(msg), "local J: %f", velocity.y);
2544  logger->Log(msg, Logger::Level::Warn);
2545  sprintf_s(msg, sizeof(msg), "local K: %f", velocity.z);
2546  logger->Log(msg, Logger::Level::Warn);
2547  sprintf_s(msg, sizeof(msg), "Trapped a violation after putting velocity in universe terms...");
2548  logger->Log(msg, Logger::Level::Fatal);
2549  }
2550 
2551 
2552  // Handle on the ground stuff
2553  if (playerships[0].reference == REF_ONGROUND)
2554  {
2555  // Determine whether our acceleration vector takes us up or down
2556  D3DXVECTOR3 sumOfForcesNormal;
2557  D3DXVec3Normalize(&sumOfForcesNormal, &sumofforces);
2558 
2559  D3DXVECTOR3 loclev;
2560  D3DXVec3TransformNormal(&loclev, &leveler, &matrixInverse);
2561 
2562  // char msg[99];
2563  // sprintf_s(msg, sizeof(msg), "on ground, loclev %+.3f %+.3f %+.3f normsum %+.3f %+.3f %+.3f", loclev.x, loclev.y, loclev.z, normsum.x, normsum.y, normsum.z );
2564  // _write(logfile, msg, strlen(msg));
2565 
2566  // portion of our thrust that is in direction of gravity
2567  D3DXVECTOR3 locgrav;
2568  D3DXVec3Normalize(&locgrav, &gravityacc);
2569 
2570  const float cmDot = D3DXVec3Dot(&locgrav, &sumOfForcesNormal);
2571  //game->gameclass->bus->DebugFloat = cmDot;
2572  if (cmDot > 0.0f) // 1.0f means that overall acceleration is away from Vieneo CM
2573  {
2574  //if (D3DXVec3Length(&gravport) > 0.0f) // km/s/s at sea level
2575  playerships[0].reference = REF_APNMODE;
2576 
2577  touchdownG = 0.0f; // reset
2578  }
2579 
2580  D3DXVECTOR3 locvel = velocity - barycentric;
2581  D3DXVec3Normalize(&cross, &locvel);
2582  const float f_temp2 = D3DXVec3Dot(&cross, &loclev);
2583 
2584  D3DXVECTOR3 gravport; // has to be done BEFORE we block the force down with the terrain plate
2585  gravport.x = sumofforces.x * locgrav.x;
2586  gravport.y = sumofforces.y * locgrav.y;
2587  gravport.z = sumofforces.z * locgrav.z;
2588 
2589  // Portion that is perpendicular to the terrain plate
2590  cross.x = 0.0f;// locvel.x*fabsf(loclev.x);
2591  cross.y = locvel.y * fabsf(loclev.y);
2592  cross.z = 0.0f;// locvel.z*fabsf(loclev.z);
2593 
2594  if (f_temp2 < 0.0f) // into the ground
2595  {
2596  sprintf_s(msg, sizeof(msg), "X%7.3f Y%7.3f Z%7.3f touchdown", -cross.x * oneOvergForceKmSSC / fElapsedTime, -cross.y * oneOvergForceKmSSC / fElapsedTime, -cross.z * oneOvergForceKmSSC / fElapsedTime);
2597  viewscreen->sofTracking.emplace_back(msg);
2598 
2599  locvel -= cross;
2600  sumofforces -= cross; // in m/s
2601 
2602  // need to research how shocks actually work
2603  float shock = -cross.y / fElapsedTime;
2604  if (shock > gravityC)
2605  {
2606  shock -= gravityC; // might be 0-50m/s above 1G
2607 
2608  // 10fps or 3m/s touchdown is some kind of FAA standard
2609 
2610  // .011 max
2611  float absorb = ourcockpit.strutabsorb;
2612  if (!ourcockpit.gndvehicle)
2613  absorb *= ourcockpit.gearextent;
2614 
2615  if (absorb > (shock * fElapsedTime))
2616  absorb = shock * fElapsedTime;
2617 
2618  sprintf_s(msg, sizeof(msg), "X%7.3f Y%7.3f Z%7.3f struts", 0.0f, -absorb * oneOvergForceKmSSC / fElapsedTime, 0.0f);
2619  viewscreen->sofTracking.emplace_back(msg);
2620 
2621  sumofforces.y -= absorb;
2622 
2623  if (fabsf(cross.y) >= 0.001f)
2624  {
2625  sprintf_s(msg, sizeof(msg), "*** TD force was %.3f/f (%.3f/s), absorbed %.3f/f (%.3f/s)", -cross.y, -cross.y / fElapsedTime, absorb, absorb / fElapsedTime);
2626  logger->Log(msg);
2627  }
2628  }
2629 
2630  D3DXVec3TransformNormal(&cross, &cross, &playerships[0].matrixWorld);
2631  D3DXVec3Subtract(&playerships[0].velocity, &playerships[0].velocity, &cross);
2632  }
2633 
2634 
2635 
2636 
2637 #pragma region Ground Friction
2638  // Ground friction and vector
2639  if (_isnan(locvel.x) || _isnan(locvel.y) || _isnan(locvel.z) ||
2640  isinf(locvel.x) || isinf(locvel.y) || isinf(locvel.z))
2641  {
2642  logger->Log("Skipping ground friction, locvel had NAN components!", Logger::Level::Debug);
2643  }
2644  else
2645  {
2646  D3DXVECTOR3 newlocvel = cross = locvel;
2647 
2648  // Downward force
2649  if (cmDot < 0.0f)
2650  gndcontactG = D3DXVec3Length(&gravport) / fElapsedTime / gravityC; // convert to G's (1 is G)
2651  else
2652  gndcontactG = 0.0f;
2653 
2654  //game->gameclass->bus->Debug1Vec3.x = gndcontactG;
2655  //game->gameclass->bus->Debug1Vec3.y = 0;
2656  //game->gameclass->bus->Debug1Vec3.z = 0;
2657 
2658  float rollingResistance, roughness, slideFrictionKineticCoeff;
2659  if (g_bRoad)
2660  {
2661  if (viewscreen->ptrWeather->GetTurbidity() > 5.0f) // wet cheat
2662  {
2663  rollingResistance = 0.017f;
2664  slideFrictionKineticCoeff = 0.7f;
2665  roughness = 0.005f;
2666  }
2667  else
2668  {
2669  rollingResistance = 0.014f;
2670  slideFrictionKineticCoeff = 1.0f;
2671  roughness = 0.001f;
2672  }
2673  }
2674  else
2675  {
2676  slideFrictionKineticCoeff = 0.6f; // gravel/sand ... dirt is 0.65 so...
2677  rollingResistance = roughness = 0.0f;
2678  // static/rolling friction varies on ground type
2679  GetFrictionCoefficients(gridarray[31][31].pri_landform, &rollingResistance, &roughness);
2680  if (gridarray[31][31].pri_transition)
2681  {
2682  GetFrictionCoefficients(gridarray[31][31].sec_landform, &rollingResistance, &roughness);
2683  if (gridarray[31][31].sec_transition)
2684  {
2685  GetFrictionCoefficients(gridarray[31][31].ter_landform, &rollingResistance, &roughness);
2686  rollingResistance /= 3.0f; // to average
2687  roughness /= 3.0f; // to average
2688  }
2689  else
2690  {
2691  rollingResistance *= 0.5f; // to average
2692  roughness *= 0.5f; // to average
2693  }
2694  }
2695 
2696  rollingResistance *= 0.1f;
2697  roughness *= 0.1f;
2698  }
2699 
2700  rollingResistance *= 75.0f; // was 100 but Bill is complaining
2701  roughness *= 75.0f;
2702 
2703  if (_isnan(rollingResistance) || isinf(rollingResistance))
2704  {
2705  rollingResistance = 0.0f;
2706  logger->Log("rollingResistance was NAN", Logger::Error);
2707  }
2708  if (_isnan(roughness) || isinf(roughness))
2709  {
2710  roughness = 0.0f;
2711  logger->Log("roughness was NAN", Logger::Error);
2712  }
2713 
2714  // roughness would vary citystuff.elevation and randomize range of friction
2715  static float targetRoughness = roughness;
2716  float diff = targetRoughness - rougfric;
2717  if (fabsf(diff) < 0.0001f)
2718  {
2719  targetRoughness = RandomFloat() * roughness * 2.0f;
2720  diff = targetRoughness - rougfric;
2721  }
2722  if (_isnan(targetRoughness) || isinf(targetRoughness))
2723  {
2724  targetRoughness = 0.0f;
2725  logger->Log("targetRoughness was NAN", Logger::Error);
2726  }
2727  if (_isnan(diff) || isinf(diff))
2728  {
2729  diff = 0.0f;
2730  logger->Log("diff was NAN", Logger::Error);
2731  }
2732 
2733  if (_isnan(rougfric) || isinf(rougfric) || fabsf(rougfric) > 1000000.0f)
2734  {
2735  sprintf_s(msg, sizeof(msg), "groundSpeedKms: %f", groundSpeedKms);
2736  logger->Log(msg, Logger::Level::Debug);
2737  sprintf_s(msg, sizeof(msg), "diff: %f", diff);
2738  logger->Log(msg, Logger::Level::Debug);
2739  sprintf_s(msg, sizeof(msg), "fElapsedTime: %f", fElapsedTime);
2740  logger->Log(msg, Logger::Level::Debug);
2741  sprintf_s(msg, sizeof(msg), "rougfric was %f before +=", rougfric);
2742  logger->Log(msg, Logger::Level::Error);
2743  rougfric = 0.0f;
2744  }
2745  rougfric += diff * fElapsedTime * groundSpeedKms * 300.0f; // 0.033 is 120kph
2746  if (_isnan(rougfric) || isinf(rougfric) || fabsf(rougfric) > 1000000.0f)
2747  {
2748  sprintf_s(msg, sizeof(msg), "groundSpeedKms: %f", groundSpeedKms);
2749  logger->Log(msg, Logger::Level::Debug);
2750  sprintf_s(msg, sizeof(msg), "diff: %f", diff);
2751  logger->Log(msg, Logger::Level::Debug);
2752  sprintf_s(msg, sizeof(msg), "fElapsedTime: %f", fElapsedTime);
2753  logger->Log(msg, Logger::Level::Debug);
2754  sprintf_s(msg, sizeof(msg), "rougfric was %f after +=", rougfric);
2755  logger->Log(msg, Logger::Level::Error);
2756  rougfric = 0.0f;
2757  }
2758  if (_isnan(fElapsedTime) || isinf(fElapsedTime))
2759  {
2760  fElapsedTime = 0.0f;
2761  logger->Log("fElapsedTime was NAN", Logger::Error);
2762  }
2763  if (_isnan(groundSpeedKms) || isinf(groundSpeedKms))
2764  {
2765  groundSpeedKms = 0.0f;
2766  logger->Log("groundSpeedKms was NAN", Logger::Error);
2767  }
2768 
2769  //sprintf_s(msg, 160, "FRICTION Target %.3f Current %.3f G/S %.3f Elapsed %.3f",
2770  // targetRoughness, rougfric, groundSpeedKms, fElapsedTime);
2771  //logger->Log(msg);
2772 
2773 
2775  float slidingFriction;
2776  if (fabsf(newlocvel.z) < FLT_EPSILON)
2777  slidingFriction = (slideFrictionKineticCoeff * 1.428571f + rougfric) * gndcontactG * 0.001f * totalWeightLbs * Kg2Lbs * fElapsedTime; // bill's frict from jeep was about twice as long of a roll
2778  else
2779  slidingFriction = (slideFrictionKineticCoeff + rougfric) * gndcontactG * 0.001f * totalWeightLbs * Kg2Lbs * fElapsedTime; // bill's frict from jeep was about twice as long of a roll
2780  const float rollfric = (rollingResistance + rougfric) * gndcontactG * 0.001f * fElapsedTime;
2781  // http://en.wikipedia.org/wiki/Rolling_resistance
2782  // http://en.wikipedia.org/wiki/Sliding_friction
2783  // Factors affecting sliding friction include weight (normal force) and surface roughness.
2784  // However surface area does not affect sliding friction.
2785  // float slidfric=f_frict*gndcontactG*weightC*fElapsedTime;
2786 
2787  if (_isnan(slidingFriction) || isinf(slidingFriction))
2788  {
2789  sprintf_s(msg, sizeof(msg), "slideFrictionKineticCoeff: %f", slideFrictionKineticCoeff);
2790  logger->Log(msg, Logger::Level::Debug);
2791  sprintf_s(msg, sizeof(msg), "rougfric: %f", rougfric);
2792  logger->Log(msg, Logger::Level::Debug);
2793  sprintf_s(msg, sizeof(msg), "gndcontactG: %f", gndcontactG);
2794  logger->Log(msg, Logger::Level::Debug);
2795  sprintf_s(msg, sizeof(msg), "totalWeightLbs: %f", totalWeightLbs);
2796  logger->Log(msg, Logger::Level::Debug);
2797  sprintf_s(msg, sizeof(msg), "fElapsedTime: %f", fElapsedTime);
2798  logger->Log(msg, Logger::Level::Debug);
2799  sprintf_s(msg, sizeof(msg), "groundSpeedKms: %f", groundSpeedKms);
2800  logger->Log(msg, Logger::Level::Debug);
2801  sprintf_s(msg, sizeof(msg), "Trapped a violation with sliding friction...");
2802  logger->Log(msg, Logger::Level::Error);
2803 
2804  slidingFriction = 0.0f;
2805  }
2806 
2807  bool skid = false;
2808  if (slidingFriction > (gravityC * fElapsedTime))
2809  {
2810  slidingFriction = gravityC * fElapsedTime;
2811  skid = true;
2812  }
2813  else if (slidingFriction < -(gravityC * fElapsedTime))
2814  {
2815  slidingFriction = -gravityC * fElapsedTime;
2816  skid = true;
2817  }
2818 
2819 
2820 
2821  // UP AND DOWN if bumper is against a cliff
2822  //{
2823  // if (newlocvel.y > 0.0f)
2824  // {
2825  // newlocvel.y -= slidfric;
2826  // if (newlocvel.y < 0.0f)
2827  // newlocvel.y = 0.0f;
2828  // }
2829  // else if (newlocvel.y < 0.0f)
2830  // {
2831  // newlocvel.y += slidfric;
2832  // if (newlocvel.y > 0.0f)
2833  // newlocvel.y = 0.0f;
2834  // }
2835  //}
2836 
2837  // SIDE TO SIDE
2838  if (skid && fabsf(newlocvel.x) > 0.001f && ourcockpit.wheeled)
2839  viewscreen->gameclass->sound->PlayEx(SOUND_TIRESKID, false, viewscreen->gameclass->sound->GetAttenuation(true), 1, newlocvel.x > 0 ? 1.0f : -1.0f);
2840  if (newlocvel.x > 0.0f)
2841  {
2842  newlocvel.x -= slidingFriction;
2843  if (newlocvel.x < 0.0f)
2844  newlocvel.x = 0.0f;
2845  }
2846  else if (newlocvel.x < 0.0f)
2847  {
2848  newlocvel.x += slidingFriction;
2849  if (newlocvel.x > 0.0f)
2850  newlocvel.x = 0.0f;
2851  }
2852 
2853  // FRONT TO BACK
2854  float dynamicMod = 0.0f;
2855  float effectiveLeftBrake, effectiveRightBrake;
2857  effectiveLeftBrake = effectiveRightBrake = 0.5f * static_cast<float>(ourcockpit.vdat.parkingBrake) / 127.0f;
2858  else
2859  {
2860  effectiveLeftBrake = viewscreen->gameclass->bus->LeftBrake;
2861  effectiveRightBrake = viewscreen->gameclass->bus->RightBrake;
2862  if (ourcockpit.gndvehicle)
2863  {
2864  bool brakelight = viewscreen->gameclass->bus->LeftBrake > 0.0f || viewscreen->gameclass->bus->RightBrake > 0.0f;
2865  if (brakelight != playerships[0].brakelight)
2866  {
2867  playerships[0].brakelight = brakelight;
2869  }
2870  }
2871  }
2873  if (ourcockpit.gndvehicle && ourcockpit.gearshift == -2) // in park
2874  effectiveLeftBrake = effectiveRightBrake = 1.0f; // in park override
2875  effectiveLeftBrake *= 0.270453f; // 3.048f / gravityC;
2876  effectiveRightBrake *= 0.270453f; // 3.048f / gravityC;
2877  effectiveLeftBrake *= static_cast<float>(ourcockpit.vdat.leftBrake) / 127.0f;
2878  effectiveRightBrake *= static_cast<float>(ourcockpit.vdat.rightBrake) / 127.0f;
2879 
2881  dynamicMod += 1.0f - ourcockpit.gearextent; // no gear
2883  dynamicMod += 1.0f; // no wheels
2884  else if (fabsf(levelerroll) >= 0.5f || fabsf(levelerpitch) >= 0.5f) // 30 degrees left or right, up or down
2885  {
2887  dynamicMod += 1.0f; // wing strike or tail strike or upside down
2888  }
2889  if (dynamicMod > 1.0f) dynamicMod = 1.0f;
2890 
2891 #ifdef frictionLoggingC
2892  static int tempDumpFile1 = -1;
2893  if (tempDumpFile1 == -1)
2894  _sopen_s(&tempDumpFile1, "friction.log", _O_RDWR | _O_CREAT | _O_TRUNC | _O_TEXT | _O_SEQUENTIAL, SH_DENYWR, S_IWRITE);
2895 #endif
2896 
2897  // has rolling reduction for wheels not in park and with travel direction
2899  {
2900  if (newlocvel.z > 0.0f)
2901  {
2902  newlocvel.z -= rollfric;
2903  if (newlocvel.z < 0.0f)
2904  newlocvel.z = 0.0f;
2905  }
2906  else if (newlocvel.z < 0.0f)
2907  {
2908  newlocvel.z += rollfric;
2909  if (newlocvel.z > 0.0f)
2910  newlocvel.z = 0.0f;
2911  }
2912  // weight and time factored in already to dynafric
2913 #ifdef frictionLoggingC
2914  if (rollfric != 0.0f)
2915  {
2916  char msg[999];
2917  sprintf_s(msg, 999, "%8.3f rol GV%i GR%+i WH%i GE%.1f LB%.1f RB%.1f RFI%.6f RFS%.3f RFG%.3f V%.3f G%.1f R%.1f P%.1f\n",
2918  DXUTGetTime(), ourcockpit.gndvehicle ? 1 : 0, ourcockpit.gearshift, ourcockpit.wheeled ? 1 : 0, ourcockpit.gearextent, viewscreen->gameclass->bus->LeftBrake, viewscreen->gameclass->bus->RightBrake, rollfric, rollfric / fElapsedTime, rollfric / fElapsedTime * oneOvergForceKmSSC, newlocvel.z, gndcontactG, levelerroll, levelerpitch);
2919  _write(tempDumpFile1, msg, strlen(msg));
2920  }
2921 #endif
2922  }
2923 
2924  if (dynamicMod > 0.0f || max(effectiveLeftBrake, effectiveRightBrake) > 0.0f)
2925  {
2926  f_temp = slidingFriction * max(dynamicMod, max(effectiveLeftBrake, effectiveRightBrake));
2927 
2928  if (newlocvel.z > 0.0f)
2929  {
2930  newlocvel.z -= f_temp;
2931  if (newlocvel.z < 0.0f)
2932  newlocvel.z = 0.0f;
2933  }
2934  else if (newlocvel.z < 0.0f)
2935  {
2936  newlocvel.z += f_temp;
2937  if (newlocvel.z > 0.0f)
2938  newlocvel.z = 0.0f;
2939  }
2940 #ifdef frictionLoggingC
2941  if (f_temp != 0.0f)
2942  {
2943  char msg[999];
2944  sprintf_s(msg, 999, "%8.3f BRK GV%i GR%+i WH%i GE%.1f LB%.1f RB%.1f SFI%.6f SFS%.3f SFG%.3f V%.3f G%.1f R%.1f P%.1f AVG%.3f\n",
2945  DXUTGetTime(), ourcockpit.gndvehicle ? 1 : 0, ourcockpit.gearshift, ourcockpit.wheeled ? 1 : 0, ourcockpit.gearextent, g_fBrakingLeft, g_fBrakingRight, f_temp, f_temp / fElapsedTime, f_temp / fElapsedTime * oneOvergForceKmSSC, newlocvel.z, gndcontactG, levelerroll, levelerpitch, slidfric / fElapsedTime * oneOvergForceKmSSC);
2946  _write(tempDumpFile1, msg, strlen(msg));
2947  }
2948 #endif
2949  }
2950 
2951  cross -= newlocvel;
2952 
2953  sprintf_s(msg, sizeof(msg), "X%7.3f Y%7.3f Z%7.3f ground friction", -cross.x * oneOvergForceKmSSC / fElapsedTime, -cross.y * oneOvergForceKmSSC / fElapsedTime, -cross.z * oneOvergForceKmSSC / fElapsedTime);
2954  viewscreen->sofTracking.emplace_back(msg);
2955 
2956  sumofforces -= cross; // rolling and sliding friction
2957 
2958 
2959  // so we have a ground noise based on rollfriction
2960  // we have a loop and stop based on slidfric
2961 
2962  static bool groundscrapeloop = false;
2963  const float scrapevel = sqrtf(newlocvel.x * newlocvel.x + newlocvel.z * newlocvel.z);
2964  const float scrapevol = min(1.0f, scrapevel / 0.01f * gndcontactG);
2965  const float rollvol = min(1.0f, fabsf(newlocvel.z) / 0.026f); // 60mph
2966  if (scrapevol > 0.0f)
2967  {
2968  viewscreen->gameclass->sound->PlayEx(SOUND_GROUNDSCRAPELOOP, true, dynamicMod * scrapevol * viewscreen->gameclass->sound->GetAttenuation(true));
2969  groundscrapeloop = true;
2970  }
2971  else if (groundscrapeloop)
2972  {
2973  if (scrapevel > 0.01f)
2976  groundscrapeloop = false;
2977  }
2979  {
2981  }
2982 
2983 
2984  D3DXVec3TransformNormal(&cross, &cross, &playerships[0].matrixWorld);
2985  D3DXVec3Subtract(&playerships[0].velocity, &playerships[0].velocity, &cross);
2986 
2987 
2988  if (sumofforces.x > 100.0f || sumofforces.x < -100.0f || _isnan(sumofforces.x) || isinf(sumofforces.x) ||
2989  sumofforces.y > 100.0f || sumofforces.y < -100.0f || _isnan(sumofforces.y) || isinf(sumofforces.y) ||
2990  sumofforces.z > 100.0f || sumofforces.z < -100.0f || _isnan(sumofforces.z) || isinf(sumofforces.z))
2991  {
2992  sprintf_s(msg, sizeof(msg), "ET: %f", fElapsedTime);
2993  logger->Log(msg, Logger::Level::Debug);
2994  sprintf_s(msg, sizeof(msg), "Groundspeed: %f", groundSpeedKms);
2995  logger->Log(msg, Logger::Level::Debug);
2996  sprintf_s(msg, sizeof(msg), "sumofforces I: %f", sumofforces.x);
2997  logger->Log(msg, Logger::Level::Debug);
2998  sprintf_s(msg, sizeof(msg), "sumofforces J: %f", sumofforces.y);
2999  logger->Log(msg, Logger::Level::Debug);
3000  sprintf_s(msg, sizeof(msg), "sumofforces K: %f", sumofforces.z);
3001  logger->Log(msg, Logger::Level::Debug);
3002  sprintf_s(msg, sizeof(msg), "cross I: %f", cross.x);
3003  logger->Log(msg, Logger::Level::Debug);
3004  sprintf_s(msg, sizeof(msg), "cross J: %f", cross.y);
3005  logger->Log(msg, Logger::Level::Debug);
3006  sprintf_s(msg, sizeof(msg), "cross K: %f", cross.z);
3007  logger->Log(msg, Logger::Level::Debug);
3008  sprintf_s(msg, sizeof(msg), "newlocvel I: %f", newlocvel.x);
3009  logger->Log(msg, Logger::Level::Debug);
3010  sprintf_s(msg, sizeof(msg), "newlocvel J: %f", newlocvel.y);
3011  logger->Log(msg, Logger::Level::Debug);
3012  sprintf_s(msg, sizeof(msg), "newlocvel K: %f", newlocvel.z);
3013  logger->Log(msg, Logger::Level::Debug);
3014  sprintf_s(msg, sizeof(msg), "slidingFriction: %f", slidingFriction);
3015  logger->Log(msg, Logger::Level::Debug);
3016  sprintf_s(msg, sizeof(msg), "rollfric: %f", rollfric);
3017  logger->Log(msg, Logger::Level::Debug);
3018  sprintf_s(msg, sizeof(msg), "rollingResistance: %f", rollingResistance);
3019  logger->Log(msg, Logger::Level::Debug);
3020  sprintf_s(msg, sizeof(msg), "rougfric: %f", rougfric);
3021  logger->Log(msg, Logger::Level::Debug);
3023  sprintf_s(msg, sizeof(msg), "Trapped a violation with ground friction...");
3024  logger->Log(msg, Logger::Level::Fatal);
3025  }
3026  }
3027 #pragma endregion
3028  }
3029  else
3030  {
3031  //logger->Log("FRICTION Doesn't think he is on the ground!");
3034  }
3035 
3036 
3037  if (playerships[0].reference < REF_INANOTHER)
3038  {
3039  sprintf_s(msg, sizeof(msg), "X%7.3f Y%7.3f Z%7.3f gravity2", gravityacc.x * oneOvergForceKmSSC / fElapsedTime, gravityacc.y * oneOvergForceKmSSC / fElapsedTime, gravityacc.z * oneOvergForceKmSSC / fElapsedTime);
3040  viewscreen->sofTracking.emplace_back(msg);
3041 
3042  sumofforces += gravityacc;//f_temp; // gravity affects vehicles and occupant individually
3043  }
3044  }
3045 
3046 #pragma region debug
3047  if (sumofforces.x > 100.0f || sumofforces.x < -100.0f || _isnan(sumofforces.x) || isinf(sumofforces.x) ||
3048  sumofforces.y > 100.0f || sumofforces.y < -100.0f || _isnan(sumofforces.y) || isinf(sumofforces.y) ||
3049  sumofforces.z > 100.0f || sumofforces.z < -100.0f || _isnan(sumofforces.z) || isinf(sumofforces.z))
3050  {
3051  sprintf_s(msg, sizeof(msg), "ET: %f", fElapsedTime);
3052  logger->Log(msg, Logger::Level::Warn);
3053  sprintf_s(msg, sizeof(msg), "sumofforces I: %f", sumofforces.x);
3054  logger->Log(msg, Logger::Level::Warn);
3055  sprintf_s(msg, sizeof(msg), "sumofforces J: %f", sumofforces.y);
3056  logger->Log(msg, Logger::Level::Warn);
3057  sprintf_s(msg, sizeof(msg), "sumofforces K: %f", sumofforces.z);
3058  logger->Log(msg, Logger::Level::Warn);
3059  sprintf_s(msg, sizeof(msg), "gravityacc I: %f", gravityacc.x);
3060  logger->Log(msg, Logger::Level::Warn);
3061  sprintf_s(msg, sizeof(msg), "gravityacc J: %f", gravityacc.y);
3062  logger->Log(msg, Logger::Level::Warn);
3063  sprintf_s(msg, sizeof(msg), "gravityacc K: %f", gravityacc.z);
3064  logger->Log(msg, Logger::Level::Warn);
3066  sprintf_s(msg, sizeof(msg), "Trapped a violation after gravityacc application...");
3067  logger->Log(msg, Logger::Level::Fatal);
3068  }
3069 #pragma endregion
3070 
3071  logger->AddToCallStack("SendTelemetryUpstream");
3072 
3073  f_netupdate += fElapsedTime;
3074  if (f_netupdate >= 0.25f) // 4 times a second
3075  {
3076  f_netupdate = 0.0f;
3077  if (playerships[0].simulator)
3078  {
3079  }
3080  else if (playerships[0].reference == REF_INANOTHER || playerships[0].reference == REF_BUILDING || playerships[0].reference == REF_SIMBAY)
3081  {
3082  //SClientPacket ourpacket; // NOLINT
3083  //ourpacket.type = 6; // character movement
3084  //ourpacket.f_x = viewscreen->gameclass->GUI->player[ourcockpit.ourplyrC].startx;
3085  //ourpacket.f_y = viewscreen->gameclass->GUI->player[ourcockpit.ourplyrC].starty;
3086  //ourpacket.f_z = viewscreen->gameclass->GUI->player[ourcockpit.ourplyrC].hdg;
3087  //ourpacket.f_w = 0.0f; // static_cast<float>(viewscreen->gameclass->GUI->player[ourcockpit.ourplyrC].ani);
3088  //viewscreen->gameclass->networking->SendToServer(&ourpacket, sizeof(SClientPacket), true);
3089  }
3090  else
3091  {
3092  SClientPacketNew outpacket;
3093  outpacket.reference = playerships[0].reference; // local reference system
3094 
3095  // for odometer
3096  if (oldOdoPosition == centerC)
3097  {
3100  }
3101 
3102  if (outpacket.reference < REF_INANOTHER)
3103  {
3104  outpacket.velocity = playerships[0].velocity;
3105  outpacket.position = playerships[0].position;
3106  if (outpacket.reference == oldOdoReference && outpacket.reference == REF_ONGROUND && ourcockpit.gndvehicle)
3107  {
3108  result = outpacket.position - oldOdoPosition;
3109  ourcockpit.usage += D3DXVec3Length(&result);
3110  }
3111  }
3112  else
3113  {
3114  outpacket.velocity = playerships[0].dockingvel;
3115  outpacket.position = playerships[0].dockoffset;
3116  }
3117 
3118  oldOdoPosition = outpacket.position;
3119  oldOdoReference = outpacket.reference;
3120 
3121  outpacket.fuel = static_cast<unsigned short>(fuel);
3122  outpacket.orientation = playerships[0].orientation;
3123  outpacket.pitch1 = static_cast<short>(playerships[0].pitch / rotlimitC * 32767.0f);
3124  outpacket.roll1 = static_cast<short>(playerships[0].roll / rotlimitC * 32767.0f);
3125  outpacket.yaw1 = static_cast<short>(playerships[0].yaw / rotlimitC * 32767.0f);
3126  const float ai = sumofforces.x * oneOvergForceKmSSC / fElapsedTime;
3127  outpacket.ai = static_cast<short>(ai / MaxAcceleration * 32767.0f);
3128  const float aj = sumofforces.y * oneOvergForceKmSSC / fElapsedTime;
3129  outpacket.aj = static_cast<short>(aj / MaxAcceleration * 32767.0f);
3130  const float ak = sumofforces.z * oneOvergForceKmSSC / fElapsedTime;
3131  outpacket.ak = static_cast<short>(ak / MaxAcceleration * 32767.0f);
3132  outpacket.tx = tx; // -127 to 127
3133  outpacket.ty = ty; // -127 to 127
3134  outpacket.tz = tz; // -127 to 127
3135  outpacket.pitchdeflect = static_cast<char>(playerships[0].pitchdeflect * 127.0f); // percent*127
3136  outpacket.rolldeflect = static_cast<char>(playerships[0].rolldeflect * 127.0f);
3137  outpacket.yawdeflect = static_cast<char>(playerships[0].yawdeflect * 127.0f);
3138  outpacket.airframeTemp = static_cast<short>(airframeTempCelsius * 10.0f);
3139  outpacket.iceAccumulationMm = static_cast<unsigned char>(iceAccumulationMm);
3140  outpacket.pitchTrim = static_cast<short>(viewscreen->gameclass->bus->PitchTrimScalar * 32767.0f);
3141  if (!viewscreen->AssertTelemetry("Propulsion::Update2", 0)) return;
3142 
3144  }
3145 
3146  discordHeartbeat++;
3147  if (discordHeartbeat == 60) // one update every 15 seconds
3148  {
3149  discordHeartbeat = 0;
3151  }
3152  }
3153 
3154 
3155 
3156 
3157  logger->AddToCallStack("EffectOnFuel");
3158 
3159  // Effect on fuel
3160  if (!ourcockpit.gndvehicle)
3161  {
3162  ourcockpit.currentFuelFlowPoundsPerSecond = (fabsf(viewscreen->rcsThrustOutputX) + fabsf(viewscreen->rcsThrustOutputY) + fabsf(viewscreen->rcsThrustOutputZ) + fabsf(zThrustAcceleration4FF) + rcsThrustYPR) * ourcockpit.ffmax;
3163  const int dockArray = playerships[0].reference - REF_DOCKCPOC;
3164  if (!playerships[0].docked || (dockArray >= 0 && dockArray < maxdockC && !allobjects[dockArray].powered))
3165  ourcockpit.currentFuelFlowPoundsPerSecond += ourcockpit.ffidle * ourcockpit.power; // plus idle fuel while powered up
3169  if (fuel < 0.0f)
3170  fuel = 0.0f;
3171  if (deathfuel < 0.0f)
3172  deathfuel = 0.0f;
3173  }
3174 
3175 
3177 
3178 
3179  logger->AddToCallStack("ThrustSounds");
3180 
3181 #pragma region Thrust Sounds
3182  const float pan = -viewscreen->rcsThrustOutputX;
3183  float volume = fabsf(viewscreen->rcsThrustOutputX);
3184  float maxVolume = ourcockpit.lrtranslimit;
3185 
3186  volume += fabsf(viewscreen->rcsThrustOutputY);
3187  maxVolume += max(ourcockpit.uptranslimit, ourcockpit.dntranslimit);
3188 
3189  volume += fabsf(viewscreen->rcsThrustOutputZ);
3190  maxVolume += 0.002f;
3191 
3192  if (volume == 0.0f)
3194  else
3195  viewscreen->gameclass->sound->PlayEx(SOUND_THRUST, true, Clamp(volume / maxVolume * 3.0f * viewscreen->gameclass->sound->GetAttenuation(true), 0, 1), 1, Clamp(pan / volume, -1, 1), false);
3196 #pragma endregion
3197 
3198 
3199 
3200  viewscreen->AssertTelemetry("Propulsion::Update3", 0);
3201 
3202 
3203  // Propulsion section -----------------------------------------------------------------------
3204 }
3205  else
3206  speedOfSoundKms = 0.343f;
3207 
3208 
3209  logger->AddToCallStack("DamageControl");
3210 
3211  // damage control
3212  if (ourcockpit.vdatChanged)
3213  {
3214  ourcockpit.vdatTime += fElapsedTime;
3215  if (ourcockpit.vdatTime > 5.0f) // wait 5 seconds
3216  {
3217  ourcockpit.vdatChanged = false;
3218  ourcockpit.vdatTime = 0.0f;
3219 
3220  if (!playerships[0].simulator)
3221  {
3222  logger->Log("Sent damage control!");
3223 
3224  SPacketBig outpacket; // NOLINT
3225  outpacket.type = 11; // damage control
3226  outpacket.vdat = ourcockpit.vdat;
3227  outpacket.ship = ourcockpit.hitpoints;
3228  outpacket.array = 0; // unused
3229  outpacket.inarray = 0; // unused
3230  outpacket.vehicleId = playerships[0].vehicleId;
3231  viewscreen->gameclass->networking->SendToServer(&outpacket, sizeof(SPacketBig), true);
3232  }
3233  }
3234  }
3235  else
3236  {
3237  ourcockpit.vdatTime = 0.0f;
3238  }
3239 
3240 
3241  logger->AddToCallStack("Propulsion::Update End");
3242 }
3243 
3244 /*
3245 D3DXVECTOR3 propulsion::EvaluateRotationalForces()
3246 {
3247 
3248  // so wings currently only care about Y load
3249  // they should fly off if roll or yaw is too high ...
3250  ourcockpit.c9WingYawArmM;
3251  ourcockpit.b12WingRollArmM;
3252  // but then what the hell is the ultimate limit for this?
3253 
3254 
3255  // tail should care about Z only probably?
3256  ourcockpit.b6DistanceToHTailM;
3257  ourcockpit.b9DistanceToVTailM;
3258  // geez, I thought I had something here with the american airbus 300 but that is shear bending and torsion https://lessonslearned.faa.gov/American587/AAR0404.pdf
3259  Table 6. A300-600 Design Limit Loads for the A300-600 and A310-300 and the 1986
3260  Full-Scale Certification Test Loads
3261  Load type
3262  A300-600 design limit loads A310-300 design limit loads A310-300 full-scale certification test loads
3263  Shear (in N) -215,800 -223,390 -424,440
3264  Bending moment (in Nm) 861,650 883,300 1,677,700
3265  Torsion (in Nm) 152,680 161,000 340,720
3266 
3267 
3268  // Passed structural limitation rot/s
3269  if (viewscreen->advanceframe && (playerships[0].yaw > rotlimitC || playerships[0].yaw < -rotlimitC))
3270  {
3271  viewscreen->causechain = 2; // rotation
3272  if (ourcockpit.vdat.vtail > 0)
3273  {
3274  char damage = (char)(rand() % ourcockpit.vdat.vtail + 1); // thanks canary
3275  ourcockpit.vdat.vtail -= damage;
3276  ourcockpit.vdatChanged = true;
3277  if (damage > 32)
3278  {
3279  if (rand() < 16384)
3280  viewscreen->gameclass->sound->Play(SOUND_TDEATH1);
3281  else
3282  viewscreen->gameclass->sound->Play(SOUND_TDEATH2);
3283  }
3284  }
3285  if (ourcockpit.vdat.htail > 0)
3286  {
3287  char damage = (char)(rand() % ourcockpit.vdat.htail + 1); // thanks canary
3288  ourcockpit.vdat.htail -= damage;
3289  ourcockpit.vdatChanged = true;
3290  if (damage > 32)
3291  {
3292  if (rand() < 16384)
3293  viewscreen->gameclass->sound->Play(SOUND_TDEATH1);
3294  else
3295  viewscreen->gameclass->sound->Play(SOUND_TDEATH2);
3296  }
3297  }
3298  }
3299 
3300  // Passed structural limitation rot/s
3301  if (viewscreen->advanceframe && (playerships[0].roll > rotlimitC || playerships[0].roll < -rotlimitC))
3302  {
3303  viewscreen->causechain = 2; // rotation
3304  if (ourcockpit.vdat.leftwing > 0)
3305  {
3306  char damage = (char)(rand() % ourcockpit.vdat.leftwing + 1); // thanks canary 1-254 is 2 to 255 or 1 to 254
3307  ourcockpit.vdat.leftwing -= damage;
3308  ourcockpit.vdatChanged = true;
3309  if (damage > 32)
3310  {
3311  viewscreen->gameclass->sound->Play(SOUND_ODEATH1);
3312  }
3313  }
3314  if (ourcockpit.vdat.rightwing > 0)
3315  {
3316  char damage = (char)(rand() % ourcockpit.vdat.rightwing + 1); // thanks canary
3317  ourcockpit.vdat.rightwing -= damage;
3318  ourcockpit.vdatChanged = true;
3319  if (damage > 32)
3320  {
3321  viewscreen->gameclass->sound->Play(SOUND_ODEATH2);
3322  }
3323  }
3324  }
3325 
3326  // Passed structural limitation rot/s
3327  if (viewscreen->advanceframe && (playerships[0].pitch > rotlimitC || playerships[0].pitch < -rotlimitC))
3328  {
3329  viewscreen->causechain = 2; // rotation
3330  if (ourcockpit.vdat.htail > 0)
3331  {
3332  char damage = (char)(rand() % ourcockpit.vdat.htail + 1); // thanks canary
3333  ourcockpit.vdat.htail -= damage;
3334  ourcockpit.vdatChanged = true;
3335  if (damage > 32)
3336  {
3337  if (rand() < 16384)
3338  viewscreen->gameclass->sound->Play(SOUND_TDEATH1);
3339  else
3340  viewscreen->gameclass->sound->Play(SOUND_TDEATH2);
3341  }
3342  }
3343  }
3344 }
3345 */
3346 
3347 float propulsion::GetTach() const
3348 {
3349  return tach;
3350 }
3351 
3353 {
3355 }
3356 
3358 {
3359  return D3DXVec3Length(&actual);
3360 }
#define radiusC
Definition: globals.h:88
float Mach
Definition: Bus.h:356
float Vne
Definition: globals.h:636
float EngineThrustOutput[MAX_ENGINES]
Definition: propulsion.h:55
float ratios[8]
Definition: globals.h:653
float tat_mod_qz_x
Definition: propulsion.h:82
Scockpit ourcockpit
Definition: globals.cpp:176
#define oneOvergForceKmSSC
Definition: globals.h:91
float yawInput
Definition: Viewscreen.h:237
float rollAccelerationSnapshot
Definition: propulsion.h:83
float PitchTrimScalar
Definition: Bus.h:316
void DumpSofTracking()
bool AntiIce
Definition: Bus.h:296
float intensity
Definition: propulsion.h:45
float oldmsl
Definition: propulsion.h:37
#define MAX_ENGINES
Definition: Bus.h:14
float staticDensity
Definition: propulsion.h:84
D3DXVECTOR3 dockingvel
Definition: globals.h:540
bool g_bAugment
Definition: globals.cpp:63
ID3DXEffect * g_pEffect
Definition: Graphics.h:30
float f_netupdate
Definition: propulsion.h:51
float tach
Definition: globals.h:651
D3DXVECTOR3 acc
Definition: globals.h:542
float aileronAreaMod
Definition: globals.h:696
float power
Definition: globals.h:608
float yawdeflect
Definition: globals.h:562
float aoiWingRad
Definition: globals.h:683
float fuel
Definition: globals.cpp:143
float DesiredVsiKms
Definition: Bus.h:113
#define MaxCDDelta
Definition: propulsion.h:15
struct Bus::Afcs AFCS
float RightBrake
Definition: Bus.h:289
float SpeedOfSoundKms
Definition: Bus.h:357
D3DXVECTOR3 gravityacc
Definition: globals.cpp:100
D3DXVECTOR3 posnorml
Definition: Viewscreen.h:248
float gndcontactG
Definition: propulsion.h:36
D3DXVECTOR3 position
Definition: Viewscreen.h:247
float e65wase61
Definition: globals.h:635
float TvmCurrentClosingSpeed
Definition: Bus.h:128
float GetWindDirectionRadians() const
Definition: weather.cpp:921
char ambtype2
Definition: propulsion.h:39
D3DXVECTOR3 position
Definition: globals.h:549
#define gasConstantm2s2K
Definition: globals.h:82
float touchdownG
Definition: globals.cpp:69
float payload
Definition: globals.cpp:145
GameClass * gameclass
Definition: Viewscreen.h:292
#define gForceKmSSC
Definition: globals.h:90
float airframeTempCelsius
Definition: propulsion.h:76
float rougfric
Definition: propulsion.h:50
float dynamicDensity
Definition: propulsion.h:85
float k65wask61
Definition: globals.h:635
float i65wasi61
Definition: globals.h:635
float DynamicPressure
Definition: Bus.h:354
D3DXQUATERNION orientation
Definition: globals.h:558
float tirespeedKph
Definition: globals.h:651
void Update(float fElapsedTime)
Definition: propulsion.cpp:125
D3DXVECTOR3 compassnorth
Definition: Viewscreen.h:43
enum Bus::Afcs::LateralModes CurrentLateralMode
void SendToServer(void *pData, DWORD dwSize, bool bGuaranteed, PacketOrdering order=ORDERING_NONE) const
Definition: Networking.cpp:59
bool g_bRoad
Definition: globals.cpp:20
float serviceCeilingKm
Definition: globals.h:631
float i48CriticalEngineYawArmM
Definition: globals.h:639
float b15WingPitchArmM
Definition: globals.h:634
int flapMaxDegrees
Definition: globals.h:692
bool wheeled
Definition: globals.h:605
float i12WingAreaOneSideSqFt
Definition: globals.h:633
float oldcorrection
Definition: propulsion.h:49
float GetTach() const
float groundclose
Definition: globals.cpp:39
InformationDialog * informationDialog
Definition: gui.h:789
Logger * logger
Definition: propulsion.h:34
void Reset()
unsigned short vehicleId
Definition: globals.h:570
D3DXVECTOR3 position
Definition: globals.h:280
float c9WingYawArmM
Definition: globals.h:634
float yawAccelerationSnapshot
Definition: propulsion.h:83
s_network_objects playerships[MAX_SCAN]
Definition: globals.cpp:174
waypoints * ptrWaypoints
Definition: Viewscreen.h:290
float cloudThickness
Definition: weather.h:81
float d16HTailWithElevatorSqFt
Definition: globals.h:634
short texturelib
Definition: globals.h:612
float f25
Definition: globals.h:633
float mach
Definition: propulsion.h:78
float flapAreaModLE
Definition: globals.h:693
bool DorOn
Definition: Bus.h:130
D3DXVECTOR3 velocity
Definition: globals.h:500
float WindDirectionDegrees
Definition: Bus.h:229
float VerticalSpeedKms
Definition: Bus.h:351
float rollInput
Definition: Viewscreen.h:237
static float CalculateLiftCoefficient(AirfoilType type, float aoaRad, float CLDelta)
Definition: propulsion.cpp:47
bool ComponentRcsRollFail
Definition: Bus.h:382
float aoaRad
Definition: globals.cpp:33
float RollAttitudeRadians
Definition: Bus.h:37
float DebugFloat6
Definition: Bus.h:413
float Vs1
Definition: globals.h:636
float momentr
Definition: globals.h:632
#define ScaleHeightC
Definition: globals.h:84
float DesiredCourseRadians
Definition: Bus.h:115
float machAngleDragScalar
Definition: globals.h:713
float IceDetectorMm
Definition: Bus.h:275
float pitchAccelerationSnapshot
Definition: propulsion.h:83
float olddesiredvsi
Definition: propulsion.h:47
float deathfuel
Definition: globals.cpp:144
float rcsThrustRequestY
Definition: Viewscreen.h:239
static void GetFrictionCoefficients(unsigned char type, float *rollingResistance, float *roughness)
Definition: propulsion.cpp:86
s_city_stuff citystuff
Definition: globals.cpp:172
float f_ACL
Definition: globals.cpp:16
void AddCommand(Command command, bool onlyOne)
Definition: Bus.cpp:3
float oldagl
Definition: propulsion.h:37
char msg[160]
Definition: propulsion.h:61
float levelerpitch
Definition: globals.cpp:12
float ffmax
Definition: globals.h:637
float b9DistanceToVTailM
Definition: globals.h:634
short scanslot[MAX_SCAN]
Definition: Viewscreen.h:276
float f27
Definition: globals.h:633
weather * ptrWeather
Definition: Viewscreen.h:287
void SendEvent(EventType eventType, float extent=0.0f) const
Definition: Networking.cpp:111
float AngleOfAttackRadians
Definition: Bus.h:152
float GlideslopeDeviationRadians
Definition: Bus.h:136
float DesiredRollRadians
Definition: Bus.h:116
float PressureAltitudeKm
Definition: Bus.h:25
float rcsThrustOutputX
Definition: Viewscreen.h:238
float DesiredIasKms
Definition: Bus.h:120
bool ComponentFcsRollFail
Definition: Bus.h:383
float steerLimitRadian
Definition: globals.h:641
float f28
Definition: globals.h:633
float wingspanM
Definition: globals.h:635
D3DXVECTOR3 relativeWindTrueKms
Definition: propulsion.h:65
float VcMSL
Definition: globals.h:636
PlotType type
Definition: globals.h:282
D3DXVECTOR3 actual
Definition: propulsion.h:43
D3DXVECTOR3 locvelcomp
Definition: globals.cpp:99
float DebugFloat5
Definition: Bus.h:412
bool advanceframe
Definition: Viewscreen.h:240
DiscordRPC * discord
Definition: GameClass.h:115
float d17VTailWithRudderSqFt
Definition: globals.h:633
float engineCriticalAltitude
Definition: globals.h:690
std::string name
Definition: Command.h:11
float fuelmax
Definition: globals.h:637
float DesiredClosingSpeed
Definition: Bus.h:127
bool trendup
Definition: propulsion.h:44
bool ThrustReverserCommand[MAX_ENGINES]
Definition: Bus.h:61
#define gravityC
Definition: globals.h:89
#define Kg2Lbs
Definition: globals.h:31
#define adiabaticIndex
Definition: globals.h:81
float speedLimiterKph
Definition: globals.h:712
float ThrustReverserOutput[MAX_ENGINES]
Definition: propulsion.h:54
char oldOdoReference
Definition: propulsion.h:59
#define rhoOver2SlugsCuFt2
Definition: globals.h:79
float h9RudderSqFt
Definition: globals.h:633
void LostScannerTarget(const char *msg) const
Definition: GameClass.cpp:2191
float d65wasd61
Definition: globals.h:635
float momentp
Definition: globals.h:632
float spoolTime
Definition: globals.h:610
float DesiredPitchRadians
Definition: Bus.h:117
float flapExtent
Definition: globals.h:655
s_universe_object allobjects[maxstarC]
Definition: globals.cpp:170
float GetWindspeedKms() const
Definition: weather.cpp:905
float elevation
Definition: globals.h:517
float GetTemperatureCelsius() const
Definition: weather.cpp:937
bool IsAdmin
Definition: gui.h:777
D3DXVECTOR3 leveler
Definition: globals.cpp:8
bool AssertTelemetry(const char *location, short id)
Definition: framemove.cpp:7
float IndicatedAirspeedKms
Definition: Bus.h:27
float rolldeflect
Definition: globals.h:562
float AirDensityScalar
Definition: Bus.h:353
float WindUpdraftMs
Definition: Bus.h:231
Networking * networking
Definition: GameClass.h:107
bool PopUpHelp(short helpId, bool allowDismiss=true, bool isLearnMore=false)
float WindSpeedMs
Definition: Bus.h:230
float f_MSL
Definition: globals.cpp:36
void PrecipWindSoundBarrier(D3DXVECTOR3 relativewind, float elapsedTime)
Definition: Sound.cpp:1764
float DebugFloat3
Definition: Bus.h:410
D3DXVECTOR3 sumofforces
Definition: globals.cpp:103
float f_augment
Definition: globals.cpp:34
float Clamp(float val, float min, float max)
Definition: MathUtilities.h:3
std::vector< std::string > sofTracking
Definition: Viewscreen.h:51
float bear
Definition: globals.cpp:58
bool vdatChanged
Definition: globals.h:670
float LinearVelocityKms
Definition: Bus.h:355
float appitagr
Definition: globals.h:638
float rcsThrustOutputY
Definition: Viewscreen.h:238
bool FlightFreeze
Definition: Bus.h:374
char engines
Definition: globals.h:627
float qz
Definition: propulsion.h:80
float AirframeTemperatureCelsius
Definition: Bus.h:69
float k66wask62
Definition: globals.h:635
float pitchInput
Definition: Viewscreen.h:237
float engineEfficiencyAtSeaLevelScalar
Definition: globals.h:715
float verticaltime
Definition: Viewscreen.h:243
bool initFromDeflect
Definition: propulsion.h:72
PlotType ambtype1
Definition: propulsion.h:38
float EngineThrustOutput[MAX_ENGINES]
Definition: Bus.h:43
float exteriorInsulationHeatTransferCoefficient
https://en.wikipedia.org/wiki/List_of_thermal_conductivities
Definition: globals.h:706
float halfsec
Definition: propulsion.h:36
Definition: Command.h:5
short targetC
Definition: Bus.h:378
float noseWheelToCgKm
Definition: globals.h:640
float pitchdeflect
Definition: globals.h:562
float EngineThrustCommand[MAX_ENGINES]
Definition: Bus.h:267
enum Bus::Afcs::VerticalModes CurrentVerticalMode
Graphics * graphics
Definition: GameClass.h:109
float uptranslimit
Definition: globals.h:610
float oldvol
Definition: propulsion.h:40
float lrtranslimit
Definition: globals.h:610
D3DXVECTOR3 velocity
Definition: globals.cpp:9
float l48AverageEnginePitchArmM
Definition: globals.h:691
const D3DXVECTOR3 centerC
D3DXVECTOR3 velocity
Definition: globals.h:540
Sound * sound
Definition: GameClass.h:108
float i66wasi62
Definition: globals.h:635
float b6DistanceToHTailM
Definition: globals.h:634
D3DXMATRIX matrixWorld
Definition: globals.h:555
static float CalculateDragCoefficient(AirfoilType type, float aoa, float CDDelta)
Definition: propulsion.cpp:71
float GetAttenuation(bool applyDensity) const
Definition: Sound.cpp:1062
D3DXVECTOR3 headlightvec
Definition: Viewscreen.h:230
D3DXVECTOR3 windgust
Definition: propulsion.h:46
void Log(const char *msg, Level level=Info, int errorCode=0)
Definition: Logger.cpp:11
float rcsThrustOutputZ
Definition: Viewscreen.h:238
enum Bus::Afcs::VerticalModes StandbyVerticalMode
float DesiredAltitudeKm
Definition: Bus.h:118
unsigned char hitpoints
Definition: globals.h:663
Viewscreen * viewscreen
Definition: propulsion.h:33
float gearextent
Definition: globals.h:621
float PitchTrimSurfacePositionDegrees
Definition: Bus.h:53
float staticBuildup
Definition: propulsion.h:75
float rcsThrustRequestX
Definition: Viewscreen.h:239
float tatCelsius
Definition: propulsion.h:79
D3DXVECTOR3 headlight
Definition: globals.h:613
float levelerroll
Definition: globals.cpp:13
D3DXVECTOR3 oldvelocity
Definition: globals.cpp:102
bool TvmOn
Definition: Bus.h:126
#define MaxAcceleration
Definition: globals.h:34
float deathinhibit
Definition: globals.cpp:51
float aprolagr
Definition: globals.h:638
#define maxdockC
Definition: globals.h:25
float maxGrossLbs
Definition: globals.h:630
float Play(int soundEnum)
Definition: Sound.cpp:577
float totalWeightLbs
Definition: propulsion.h:73
float YawDamperCommand
Definition: Bus.h:336
bool YawDamperStatus
Definition: Bus.h:333
float f_BCL
Definition: globals.cpp:17
float elevatorAreaMod
Definition: globals.h:697
float Vs2
Definition: globals.h:636
float tach
Definition: propulsion.h:42
char discordHeartbeat
Definition: propulsion.h:52
float DesiredHeadingRadians
Definition: Bus.h:114
D3DXVECTOR3 windVectorTrueKms
Definition: propulsion.h:64
float strutabsorb
Definition: globals.h:621
float OutsideAirTemperatureKelvin
Definition: Bus.h:67
float Lerp(float val1, float val2, float lerp)
Definition: MathUtilities.h:12
#define maxDragIncreaseApproachingMachC
Definition: propulsion.h:22
HMI * GUI
Definition: GameClass.h:110
D3DLIGHT9 headlight
Definition: Viewscreen.h:217
float groundSpeedKms
Definition: globals.cpp:38
void SendTelemetry(SClientPacketNew *pData) const
Definition: Networking.cpp:83
float GroundSpeedKms
Definition: Bus.h:156
float revthrustlimit
Definition: globals.h:610
char dead
Definition: globals.cpp:49
float currentFuelFlowPoundsPerSecond
Definition: globals.h:648
void UpdateTelemetry()
Definition: DiscordRPC.cpp:54
#define trimlimiterC
Definition: globals.h:33
LOCALGRID2 gridarray[64][64]
Definition: globals.cpp:153
float rcsYParmM
Definition: globals.h:635
void LostVerticalTarget() const
Definition: GameClass.cpp:2222
float TotalAirTemperatureCelsius
Definition: Bus.h:68
std::vector< Swaypoint > waypoint
Definition: Bus.h:391
bool AutopilotEngaged
Definition: Bus.h:74
float GetTurbulence() const
Definition: weather.cpp:929
float oldpitch
Definition: propulsion.h:48
float usage
Definition: globals.h:645
float GetTotalThrust() const
void Stop(int soundEnum)
Definition: Sound.cpp:1946
short FindByUniqueId(int id) const
Definition: waypoints.cpp:163
D3DXVECTOR3 barycentric
Definition: globals.h:540
float vdatTime
Definition: globals.h:671
float momenty
Definition: globals.h:632
float rcsThrustRequestZ
Definition: Viewscreen.h:239
float DebugTurbulence
Definition: Bus.h:421
float speedOfSoundKms
Definition: propulsion.h:74
void PlayEx(int soundEnum, bool loop, float volume=1.0f, float frequencyMod=1.0f, float pan=0.0f, bool restart=true)
Definition: Sound.cpp:606
bool parkingBrake
Definition: globals.h:685
enum Bus::Afcs::LateralModes StandbyLateralMode
float LeftBrake
Definition: Bus.h:289
bool gndvehicle
Definition: globals.h:604
float GetTurbidity() const
Definition: weather.cpp:913
int WPtargetC
Definition: Bus.h:390
void AddToCallStack(const char *msg)
Definition: Logger.cpp:86
Bus * bus
Definition: GameClass.h:112
float clutchhold
Definition: globals.h:651
float pitchLimitRadians
Definition: globals.h:711
float fwdthrustlimit
Definition: globals.h:610
float insthdgDegrees
Definition: Viewscreen.h:234
float ffidle
Definition: globals.h:637
float f20FrontBackDragCoeff
Definition: globals.h:633
char gearshift
Definition: globals.h:652
float dntranslimit
Definition: globals.h:610
D3DXVECTOR3 localvel
Definition: propulsion.h:63
bool IceDetectorHeat
Definition: Bus.h:276
float RandomFloat()
Definition: MathUtilities.h:98
float emptyWeightLbs
Definition: globals.h:629
Logger * logger
Definition: Viewscreen.h:293
float flapAreaModTE
Definition: globals.h:694
float b12WingRollArmM
Definition: globals.h:634
float grounditerate
Definition: globals.cpp:40
float DebugFloat4
Definition: Bus.h:411
float convectionRate
Definition: propulsion.h:81
char steerTires
Definition: globals.h:625
#define MaxCLDelta
Definition: propulsion.h:14
float insttrk
Definition: Viewscreen.h:234
D3DXVECTOR3 oldOdoPosition
Definition: propulsion.h:58
float StaticAirTemperatureCelsius
Definition: Bus.h:66
float PitchAttitudeRadians
Definition: Bus.h:36
float FuelFlowKgh
Definition: Bus.h:363
D3DXVECTOR3 dockoffset
Definition: globals.h:549
float f_AGL
Definition: globals.cpp:14
float EngineThrustLever[MAX_ENGINES]
Definition: Bus.h:264
SVesselDC vdat
Definition: globals.h:669
#define ZeroCelsiusToKelvin
Definition: globals.h:32
propulsion(Viewscreen *ptr)
Definition: propulsion.cpp:10
float iceAccumulationMm
Definition: propulsion.h:77
float TrueAirspeedKms
Definition: Bus.h:348