motorvehicle.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WWPhys *
  23. * *
  24. * $Archive:: /Commando/Code/wwphys/motorvehicle.cpp $*
  25. * *
  26. * Author:: Greg Hjelstrom *
  27. * *
  28. * $Modtime:: 10/23/01 1:56p $*
  29. * *
  30. * $Revision:: 37 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "motorvehicle.h"
  36. #include "physcontrol.h"
  37. #include "persistfactory.h"
  38. #include "wwphysids.h"
  39. #include "wwhack.h"
  40. #include "wwprofile.h"
  41. #include "simplevec.h"
  42. #include "ode.h"
  43. #include "lookuptable.h"
  44. DECLARE_FORCE_LINK(motorvehicle);
  45. const float GEAR_SHIFT_DELAY = 1.0f;
  46. const float MIN_BRAKING_SPEED = 1.5f; // below this forward speed, we drive in reverse
  47. /***********************************************************************************************
  48. **
  49. ** MotorVehicleClass Implementation
  50. **
  51. ***********************************************************************************************/
  52. /*
  53. ** Chunk Ids used by MotorVehicleClass
  54. */
  55. enum
  56. {
  57. MOTO_CHUNK_RIGIDBODY = 0x01234500, // used to be derived from RigidBody
  58. MOTO_CHUNK_VARIABLES,
  59. MOTO_CHUNK_VEHICLEPHYS, // now derived from VehiclePhys
  60. OBSOLETE_MOTO_VARIABLE_CURENGINETORQUE = 0x00,
  61. MOTO_VARIABLE_ENGINEANGULARVELOCITY,
  62. MOTO_VARIABLE_CURRENTGEAR,
  63. MOTO_VARIABLE_SHIFTIMER,
  64. };
  65. MotorVehicleClass::MotorVehicleClass(void) :
  66. EngineAngularVelocity(0.0f),
  67. CurrentGear(0),
  68. ShiftTimer(0),
  69. AcceleratorFraction(0.0f),
  70. IsBraking(false)
  71. {
  72. }
  73. void MotorVehicleClass::Init(const MotorVehicleDefClass & def)
  74. {
  75. VehiclePhysClass::Init(def);
  76. }
  77. MotorVehicleClass::~MotorVehicleClass(void)
  78. {
  79. }
  80. void MotorVehicleClass::Timestep(float dt)
  81. {
  82. {
  83. WWPROFILE("MotorVehicle::Timestep");
  84. const MotorVehicleDefClass * def = Get_MotorVehicleDef();
  85. // Update the accelerator and braking state according to the current inputs
  86. AcceleratorFraction = 0.0f;
  87. IsBraking = false;
  88. if (Controller) {
  89. Vector3 objvel;
  90. Matrix3D::Inverse_Rotate_Vector(Get_Transform(),Velocity,&objvel);
  91. if ((Controller->Get_Move_Forward() < 0.0f) && (objvel.X > MIN_BRAKING_SPEED)) {
  92. IsBraking = true;
  93. } else if ((Controller->Get_Move_Forward() > 0) && (objvel.X < -MIN_BRAKING_SPEED)) {
  94. IsBraking = true;
  95. } else {
  96. AcceleratorFraction = Controller->Get_Move_Forward();
  97. }
  98. }
  99. // Engine simulation revvs up if the drive wheels are not in contact.
  100. if (!Drive_Wheels_In_Contact()) {
  101. EngineAngularVelocity += dt * Compute_Engine_Angular_Acceleration();
  102. }
  103. // Update our current gear if we are in contact with the ground
  104. if ((ShiftTimer <= 0.0f) && (Drive_Wheels_In_Contact() == true)) {
  105. // if we're near red-line and our shift timer has expired, shift up.
  106. // if we're at very low rpms, shift down.
  107. if ((EngineAngularVelocity > def->ShiftUpAvel) && (CurrentGear < def->GearCount)) {
  108. Shift_Up();
  109. } else if ((EngineAngularVelocity < def->ShiftDownAvel) && (CurrentGear > 0)) {
  110. Shift_Down();
  111. }
  112. } else if (ShiftTimer > 0.0f) {
  113. ShiftTimer -= dt;
  114. }
  115. }
  116. VehiclePhysClass::Timestep(dt);
  117. }
  118. /***********************************************************************************************
  119. **
  120. ** Engine Simulation code for MotorVehicleClass
  121. **
  122. ***********************************************************************************************/
  123. int MotorVehicleClass::Set_State(const StateVectorClass & new_state,int start_index)
  124. {
  125. // Whenever we get a new state from the integrator, make sure we update our
  126. // engine's angular velocity. This will ensure that the torque output from the
  127. // engine is in sync with the vehicle's motion. (even though we're not really
  128. // "simulating" the angular velocity of the engine...)
  129. start_index = VehiclePhysClass::Set_State(new_state,start_index);
  130. const MotorVehicleDefClass * def = Get_MotorVehicleDef();
  131. if (Drive_Wheels_In_Contact() == true) {
  132. float wheel_avel = Get_Ideal_Drive_Axle_Angular_Velocity();
  133. EngineAngularVelocity = wheel_avel * def->GearRatio[CurrentGear] * def->FinalDriveGearRatio;
  134. }
  135. return start_index;
  136. }
  137. float MotorVehicleClass::Get_Engine_Torque(void)
  138. {
  139. // Torque output by the engine depends on the torque curve, how much gas is being given, and
  140. // the engine's maximum torque. The maximum torque is used to scale the normalized engine
  141. // torque curve so that we can just re-use the same table for many vehicles.
  142. const MotorVehicleDefClass * def = Get_MotorVehicleDef();
  143. float normalized_torque = 0;
  144. if (def->EngineTorqueCurve != NULL) {
  145. normalized_torque = def->EngineTorqueCurve->Get_Value(WWMath::Fabs(EngineAngularVelocity));
  146. }
  147. return def->MaxEngineTorque * AcceleratorFraction * normalized_torque;
  148. }
  149. float MotorVehicleClass::Get_Axle_Angular_Velocity(void)
  150. {
  151. const MotorVehicleDefClass * def = Get_MotorVehicleDef();
  152. return EngineAngularVelocity / (def->GearRatio[CurrentGear] * def->FinalDriveGearRatio);
  153. }
  154. float MotorVehicleClass::Get_Axle_Torque(void)
  155. {
  156. const MotorVehicleDefClass * def = Get_MotorVehicleDef();
  157. return Get_Engine_Torque() * def->GearRatio[CurrentGear] * def->FinalDriveGearRatio;
  158. }
  159. float MotorVehicleClass::Get_Normalized_Engine_RPM(void)
  160. {
  161. return Get_Engine_RPM() / Get_MotorVehicleDef()->ShiftUpRpm;
  162. }
  163. float MotorVehicleClass::Get_Max_Engine_Torque(void)
  164. {
  165. return Get_MotorVehicleDef()->MaxEngineTorque;
  166. }
  167. float MotorVehicleClass::Compute_Engine_Angular_Acceleration(void)
  168. {
  169. const MotorVehicleDefClass * def = Get_MotorVehicleDef();
  170. return Get_Engine_Torque() / def->DriveTrainInertia;
  171. }
  172. void MotorVehicleClass::Shift_Up(void)
  173. {
  174. const MotorVehicleDefClass * def = Get_MotorVehicleDef();
  175. if (CurrentGear < def->GearCount-1) {
  176. CurrentGear++;
  177. ShiftTimer = GEAR_SHIFT_DELAY;
  178. }
  179. }
  180. void MotorVehicleClass::Shift_Down(void)
  181. {
  182. if (CurrentGear > 0) {
  183. CurrentGear--;
  184. ShiftTimer = GEAR_SHIFT_DELAY;
  185. }
  186. }
  187. /***********************************************************************************************
  188. **
  189. ** Save-Load for MotorVehicleClass
  190. ** Note: MotorVehicleClass contains pure virtuals so it does not instantiate a PersistFactory...
  191. **
  192. ***********************************************************************************************/
  193. bool MotorVehicleClass::Save (ChunkSaveClass &csave)
  194. {
  195. csave.Begin_Chunk(MOTO_CHUNK_VEHICLEPHYS);
  196. VehiclePhysClass::Save(csave);
  197. csave.End_Chunk();
  198. csave.Begin_Chunk(MOTO_CHUNK_VARIABLES);
  199. WRITE_MICRO_CHUNK(csave,MOTO_VARIABLE_ENGINEANGULARVELOCITY,EngineAngularVelocity);
  200. WRITE_MICRO_CHUNK(csave,MOTO_VARIABLE_CURRENTGEAR,CurrentGear);
  201. WRITE_MICRO_CHUNK(csave,MOTO_VARIABLE_SHIFTIMER,ShiftTimer);
  202. csave.End_Chunk();
  203. return true;
  204. }
  205. bool MotorVehicleClass::Load (ChunkLoadClass &cload)
  206. {
  207. while (cload.Open_Chunk()) {
  208. switch(cload.Cur_Chunk_ID())
  209. {
  210. case MOTO_CHUNK_RIGIDBODY: // used to be derived directly from RigidBody... Obsolete now
  211. RigidBodyClass::Load(cload);
  212. break;
  213. case MOTO_CHUNK_VEHICLEPHYS:
  214. VehiclePhysClass::Load(cload);
  215. break;
  216. case MOTO_CHUNK_VARIABLES:
  217. while (cload.Open_Micro_Chunk()) {
  218. switch(cload.Cur_Micro_Chunk_ID()) {
  219. READ_MICRO_CHUNK(cload,MOTO_VARIABLE_ENGINEANGULARVELOCITY,EngineAngularVelocity);
  220. READ_MICRO_CHUNK(cload,MOTO_VARIABLE_CURRENTGEAR,CurrentGear);
  221. READ_MICRO_CHUNK(cload,MOTO_VARIABLE_SHIFTIMER,ShiftTimer);
  222. }
  223. cload.Close_Micro_Chunk();
  224. }
  225. break;
  226. default:
  227. WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",cload.Cur_Chunk_ID(),__FILE__,__LINE__));
  228. break;
  229. }
  230. cload.Close_Chunk();
  231. }
  232. return true;
  233. }
  234. /***********************************************************************************************
  235. **
  236. ** MotorVehicleDefClass Implementation
  237. **
  238. ***********************************************************************************************/
  239. /*
  240. ** Declare a PersistFactory for MotorVehicleClasses
  241. */
  242. SimplePersistFactoryClass<MotorVehicleDefClass,PHYSICS_CHUNKID_MOTORVEHICLEDEF> _MotorVehicleDefFactory;
  243. /*
  244. ** Chunk ID's used by MotorVehicleDefClass
  245. */
  246. enum
  247. {
  248. MOTORVEHICLEDEF_CHUNK_RIGIDBODYDEF = 0x00516000, // (old parent class)
  249. MOTORVEHICLEDEF_CHUNK_VARIABLES,
  250. MOTORVEHICLEDEF_CHUNK_VEHICLEPHYSDEF, // (current parent class)
  251. MOTORVEHICLEDEF_VARIABLE_MAXENGINETORQUE = 0x00,
  252. MOTORVEHICLEDEF_VARIABLE_ENGINETORQUECURVEFILENAME,
  253. MOTORVEHICLEDEF_VARIABLE_GEARCOUNT,
  254. MOTORVEHICLEDEF_VARIABLE_GEARRATIO1,
  255. MOTORVEHICLEDEF_VARIABLE_GEARRATIO2,
  256. MOTORVEHICLEDEF_VARIABLE_GEARRATIO3,
  257. MOTORVEHICLEDEF_VARIABLE_GEARRATIO4,
  258. MOTORVEHICLEDEF_VARIABLE_GEARRATIO5,
  259. MOTORVEHICLEDEF_VARIABLE_GEARRATIO6,
  260. MOTORVEHICLEDEF_VARIABLE_FINALDRIVEGEARRATIO,
  261. OBSOLETE_MOTORVEHICLEDEF_VARIABLE_ENGINEINERTIA,
  262. OBSOLETE_MOTORVEHICLEDEF_VARIABLE_TRANSMISSIONINERTIA,
  263. OBSOLETE_MOTORVEHICLEDEF_VARIABLE_FINALDRIVEINERTIA,
  264. MOTORVEHICLEDEF_VARIABLE_SHIFTUPRPM,
  265. MOTORVEHICLEDEF_VARIABLE_SHIFTDOWNRPM,
  266. MOTORVEHICLEDEF_VARIABLE_DRIVETRAININERTIA,
  267. };
  268. MotorVehicleDefClass::MotorVehicleDefClass(void) :
  269. MaxEngineTorque(5.0f),
  270. EngineTorqueCurveFilename("Vehicles\\PhysicsTables\\DefaultEngineTorque.tbl"),
  271. EngineTorqueCurve(NULL),
  272. GearCount(4),
  273. FinalDriveGearRatio(2.92f),
  274. ShiftUpRpm(7000),
  275. ShiftDownRpm(2000),
  276. DriveTrainInertia(0.1f)
  277. {
  278. GearRatio[0] = 12.01f; // 1989 Ford Taurus gear ratios :-)
  279. GearRatio[1] = 7.82f;
  280. GearRatio[2] = 5.16f;
  281. GearRatio[3] = 3.81f;
  282. GearRatio[4] = 2.79f;
  283. GearRatio[5] = 1.0f;
  284. ShiftUpAvel = RPM_TO_RADS(ShiftUpRpm);
  285. ShiftDownAvel = RPM_TO_RADS(ShiftDownRpm);
  286. // make our parameters editable
  287. FLOAT_UNITS_PARAM(MotorVehicleDefClass, MaxEngineTorque, 0.01f, 100000.0f,"N*m");
  288. FILENAME_PARAM(MotorVehicleDefClass, EngineTorqueCurveFilename, "Table Files", ".tbl");
  289. INT_EDITABLE_PARAM(MotorVehicleDefClass,GearCount,1,6);
  290. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,GearRatio[0],1.0f,100.0f);
  291. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,GearRatio[1],1.0f,100.0f);
  292. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,GearRatio[2],1.0f,100.0f);
  293. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,GearRatio[3],1.0f,100.0f);
  294. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,GearRatio[4],1.0f,100.0f);
  295. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,GearRatio[5],1.0f,100.0f);
  296. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,FinalDriveGearRatio,0.0f,100.0f);
  297. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,DriveTrainInertia,0.001f,100000.0f);
  298. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,ShiftUpRpm,1.0f,100000.0f);
  299. FLOAT_EDITABLE_PARAM(MotorVehicleDefClass,ShiftDownRpm,1.0f,100000.0f);
  300. }
  301. MotorVehicleDefClass::~MotorVehicleDefClass(void)
  302. {
  303. REF_PTR_RELEASE(EngineTorqueCurve);
  304. }
  305. uint32 MotorVehicleDefClass::Get_Class_ID (void) const
  306. {
  307. return CLASSID_MOTORVEHICLEDEF;
  308. }
  309. const PersistFactoryClass & MotorVehicleDefClass::Get_Factory (void) const
  310. {
  311. return _MotorVehicleDefFactory;
  312. }
  313. bool MotorVehicleDefClass::Save(ChunkSaveClass &csave)
  314. {
  315. csave.Begin_Chunk(MOTORVEHICLEDEF_CHUNK_VEHICLEPHYSDEF);
  316. VehiclePhysDefClass::Save(csave);
  317. csave.End_Chunk();
  318. ShiftUpAvel = RPM_TO_RADS(ShiftUpRpm);
  319. ShiftDownAvel = RPM_TO_RADS(ShiftDownRpm);
  320. csave.Begin_Chunk(MOTORVEHICLEDEF_CHUNK_VARIABLES);
  321. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_MAXENGINETORQUE,MaxEngineTorque);
  322. WRITE_MICRO_CHUNK_WWSTRING(csave,MOTORVEHICLEDEF_VARIABLE_ENGINETORQUECURVEFILENAME,EngineTorqueCurveFilename);
  323. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_GEARCOUNT,GearCount);
  324. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_GEARRATIO1,GearRatio[0]);
  325. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_GEARRATIO2,GearRatio[1]);
  326. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_GEARRATIO3,GearRatio[2]);
  327. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_GEARRATIO4,GearRatio[3]);
  328. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_GEARRATIO5,GearRatio[4]);
  329. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_GEARRATIO6,GearRatio[5]);
  330. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_FINALDRIVEGEARRATIO,FinalDriveGearRatio);
  331. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_SHIFTUPRPM,ShiftUpRpm);
  332. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_SHIFTDOWNRPM,ShiftDownRpm);
  333. WRITE_MICRO_CHUNK(csave,MOTORVEHICLEDEF_VARIABLE_DRIVETRAININERTIA,DriveTrainInertia);
  334. csave.End_Chunk();
  335. return true;
  336. }
  337. bool MotorVehicleDefClass::Load(ChunkLoadClass &cload)
  338. {
  339. while (cload.Open_Chunk()) {
  340. switch(cload.Cur_Chunk_ID()) {
  341. case MOTORVEHICLEDEF_CHUNK_RIGIDBODYDEF: // old parent class
  342. RigidBodyDefClass::Load(cload);
  343. break;
  344. case MOTORVEHICLEDEF_CHUNK_VEHICLEPHYSDEF: // current parent class
  345. VehiclePhysDefClass::Load(cload);
  346. break;
  347. case MOTORVEHICLEDEF_CHUNK_VARIABLES:
  348. while (cload.Open_Micro_Chunk()) {
  349. switch(cload.Cur_Micro_Chunk_ID()) {
  350. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_MAXENGINETORQUE,MaxEngineTorque);
  351. READ_MICRO_CHUNK_WWSTRING(cload,MOTORVEHICLEDEF_VARIABLE_ENGINETORQUECURVEFILENAME,EngineTorqueCurveFilename);
  352. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_GEARCOUNT,GearCount);
  353. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_GEARRATIO1,GearRatio[0]);
  354. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_GEARRATIO2,GearRatio[1]);
  355. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_GEARRATIO3,GearRatio[2]);
  356. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_GEARRATIO4,GearRatio[3]);
  357. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_GEARRATIO5,GearRatio[4]);
  358. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_GEARRATIO6,GearRatio[5]);
  359. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_FINALDRIVEGEARRATIO,FinalDriveGearRatio);
  360. OBSOLETE_MICRO_CHUNK(OBSOLETE_MOTORVEHICLEDEF_VARIABLE_ENGINEINERTIA);
  361. OBSOLETE_MICRO_CHUNK(OBSOLETE_MOTORVEHICLEDEF_VARIABLE_TRANSMISSIONINERTIA);
  362. OBSOLETE_MICRO_CHUNK(OBSOLETE_MOTORVEHICLEDEF_VARIABLE_FINALDRIVEINERTIA);
  363. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_SHIFTUPRPM,ShiftUpRpm);
  364. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_SHIFTDOWNRPM,ShiftDownRpm);
  365. READ_MICRO_CHUNK(cload,MOTORVEHICLEDEF_VARIABLE_DRIVETRAININERTIA,DriveTrainInertia);
  366. }
  367. cload.Close_Micro_Chunk();
  368. }
  369. break;
  370. default:
  371. WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
  372. break;
  373. }
  374. cload.Close_Chunk();
  375. }
  376. ShiftUpAvel = RPM_TO_RADS(ShiftUpRpm);
  377. ShiftDownAvel = RPM_TO_RADS(ShiftDownRpm);
  378. REF_PTR_RELEASE(EngineTorqueCurve);
  379. if (!EngineTorqueCurveFilename.Is_Empty()) {
  380. // strip the path off the filename
  381. char * fname = strrchr(EngineTorqueCurveFilename,'\\');
  382. if (fname == NULL) {
  383. EngineTorqueCurve = LookupTableMgrClass::Get_Table(EngineTorqueCurveFilename);
  384. } else {
  385. EngineTorqueCurve = LookupTableMgrClass::Get_Table(fname + 1);
  386. }
  387. }
  388. if (EngineTorqueCurve == NULL) {
  389. WWDEBUG_SAY(("Missing EngineTorqueCurve Table file: %s\r\n",EngineTorqueCurveFilename));
  390. EngineTorqueCurve = LookupTableMgrClass::Get_Table("DefaultTable");
  391. }
  392. return true;
  393. }
  394. bool MotorVehicleDefClass::Is_Type(const char * type_name)
  395. {
  396. if (stricmp(type_name,MotorVehicleDefClass::Get_Type_Name()) == 0) {
  397. return true;
  398. } else {
  399. return VehiclePhysDefClass::Is_Type(type_name);
  400. }
  401. }