carscript.c 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835
  1. enum CarDoorState
  2. {
  3. DOORS_MISSING,
  4. DOORS_OPEN,
  5. DOORS_CLOSED
  6. }
  7. enum CarHeadlightBulbsState
  8. {
  9. NONE,
  10. LEFT,
  11. RIGHT,
  12. BOTH
  13. }
  14. enum CarRearLightType
  15. {
  16. NONE,
  17. BRAKES_ONLY,
  18. REVERSE_ONLY,
  19. BRAKES_AND_REVERSE
  20. }
  21. enum CarEngineSoundState
  22. {
  23. NONE,
  24. STARTING,
  25. START_OK,
  26. START_NO_FUEL,
  27. START_NO_BATTERY,
  28. START_NO_SPARKPLUG,
  29. STOP_OK,
  30. STOP_NO_FUEL
  31. }
  32. enum ECarHornState
  33. {
  34. OFF = 0,
  35. SHORT = 1,
  36. LONG = 2
  37. }
  38. #ifdef DIAG_DEVELOPER
  39. enum EVehicleDebugOutputType
  40. {
  41. NONE,
  42. DAMAGE_APPLIED = 1,
  43. DAMAGE_CONSIDERED = 2,
  44. CONTACT = 4
  45. //OTHER = 8
  46. //OTHER = 16
  47. }
  48. class CrashDebugData
  49. {
  50. static ref array<ref CrashDebugData> m_CrashData = new array<ref CrashDebugData>;
  51. static ref CrashDebugData m_CrashDataPoint;
  52. //data is recorded on server, upon request, sent to the client
  53. static void SendData(PlayerBase player)
  54. {
  55. /*
  56. m_CrashData.Clear();
  57. CrashDebugData fakeData = new CrashDebugData();
  58. fakeData.m_VehicleType = "FakeVehicle";
  59. m_CrashData.Insert(fakeData);
  60. */
  61. GetGame().RPCSingleParam(player, ERPCs.DIAG_VEHICLES_DUMP_CRASH_DATA_CONTENTS, new Param1<array<ref CrashDebugData>>(m_CrashData), true, player.GetIdentity());
  62. }
  63. //this is client requesting to dump the data it previously received from the server
  64. static void DumpDataArray(array<ref CrashDebugData> dataArray)
  65. {
  66. Print("Vehicle; DamageType; Damage; Zone; Momentum; Momentum Prev; Momentum Delta; Speedometer; SpeedWorld; SpeedWorld Prev; SpeedWorld Delta; Velocity; Velocity Prev; Velocity Dot; TimeStamp (ms); CrewDamageBase; ShockTemp; DMGHealth; DMGShock");
  67. foreach (CrashDebugData data:dataArray)
  68. {
  69. DumpData(data);
  70. }
  71. }
  72. static void DumpData(CrashDebugData data)
  73. {
  74. string output = data.m_VehicleType+";"+data.m_DamageType+";"+data.m_Damage+";"+data.m_Zone+";"+data.m_MomentumCurr+";"+data.m_MomentumPrev+";"+data.m_MomentumDelta+";"+data.m_Speedometer;
  75. output += ";"+data.m_SpeedWorld+";"+data.m_SpeedWorldPrev+";"+data.m_SpeedWorldDelta+";"+data.m_VelocityCur;
  76. output += ";"+data.m_VelocityPrev+";"+data.m_VelocityDot+";"+data.m_Time+";"+data.m_CrewDamageBase+";"+data.m_ShockTemp+";"+data.m_DMGHealth+";"+data.m_DMGShock;
  77. Print(output);
  78. }
  79. string m_VehicleType;
  80. string m_DamageType;
  81. float m_Damage;
  82. string m_Zone;
  83. float m_MomentumCurr;
  84. float m_MomentumPrev;
  85. float m_MomentumDelta;
  86. float m_Speedometer;
  87. float m_SpeedWorld;
  88. float m_SpeedWorldPrev;
  89. float m_SpeedWorldDelta;
  90. vector m_VelocityCur;
  91. vector m_VelocityPrev;
  92. float m_VelocityDot;
  93. float m_Time;
  94. float m_CrewDamageBase;
  95. float m_ShockTemp;
  96. float m_DMGHealth;
  97. float m_DMGShock;
  98. }
  99. #endif
  100. class CarContactData
  101. {
  102. vector localPos;
  103. IEntity other;
  104. float impulse;
  105. void CarContactData(vector _localPos, IEntity _other, float _impulse)
  106. {
  107. localPos = _localPos;
  108. other = _other;
  109. impulse = _impulse;
  110. }
  111. }
  112. typedef map<string, ref array<ref CarContactData>> CarContactCache
  113. #ifdef DEVELOPER
  114. CarScript _car;
  115. #endif
  116. /*!
  117. Base script class for all motorized wheeled vehicles.
  118. */
  119. class CarScript extends Car
  120. {
  121. #ifdef DIAG_DEVELOPER
  122. static EVehicleDebugOutputType DEBUG_OUTPUT_TYPE;
  123. bool m_ContactCalled;
  124. #endif
  125. static ref map<typename, ref TInputActionMap> m_CarTypeActionsMap = new map<typename, ref TInputActionMap>;
  126. TInputActionMap m_InputActionMap;
  127. bool m_ActionsInitialize;
  128. protected float m_MomentumPrevTick;
  129. protected vector m_VelocityPrevTick;
  130. ref CarContactCache m_ContactCache;
  131. protected float m_Time;
  132. static float DROWN_ENGINE_THRESHOLD = 0.5;
  133. static float DROWN_ENGINE_DAMAGE = 350.0;
  134. static const string MEMORY_POINT_NAME_CAR_HORN = "pos_carHorn";
  135. //! keeps ammount of each fluid
  136. protected float m_FuelAmmount;
  137. protected float m_CoolantAmmount;
  138. protected float m_OilAmmount;
  139. protected float m_BrakeAmmount;
  140. //!
  141. //protected float m_dmgContactCoef = 0.023;
  142. protected float m_dmgContactCoef = 0.058;
  143. protected float m_EnviroHeatComfortOverride;
  144. //!
  145. protected float m_DrownTime;
  146. static vector m_DrownEnginePos;
  147. //!
  148. protected float m_EngineHealth;
  149. protected float m_RadiatorHealth;
  150. protected float m_FuelTankHealth;
  151. protected float m_BatteryHealth;
  152. protected float m_PlugHealth;
  153. protected EntityAI m_Radiator;
  154. protected float m_BatteryConsume = 15; //Battery energy consumption upon engine start
  155. protected float m_BatteryContinuousConsume = 0.25; //Battery consumption with lights on and engine is off
  156. protected float m_BatteryRecharge = 0.15; //Battery recharge rate when engine is on
  157. private float m_BatteryTimer = 0; //Used to factor energy consumption / recharging
  158. private const float BATTERY_UPDATE_DELAY = 100;
  159. protected float m_BatteryEnergyStartMin = 5.0; // Minimal energy level of battery required for start
  160. //! Particles
  161. protected ref EffVehicleSmoke m_coolantFx;
  162. protected ref EffVehicleSmoke m_engineFx;
  163. protected ref EffVehicleSmoke m_exhaustFx;
  164. protected int m_enginePtcFx;
  165. protected int m_coolantPtcFx;
  166. protected int m_exhaustPtcFx;
  167. protected vector m_exhaustPtcPos;
  168. protected vector m_exhaustPtcDir;
  169. protected vector m_enginePtcPos;
  170. protected vector m_coolantPtcPos;
  171. protected vector m_enginePos;
  172. protected vector m_frontPos;
  173. protected vector m_backPos;
  174. protected vector m_side_1_1Pos;
  175. protected vector m_side_1_2Pos;
  176. protected vector m_side_2_1Pos;
  177. protected vector m_side_2_2Pos;
  178. //!Sounds
  179. string m_EngineStartOK = "";
  180. string m_EngineStartBattery = "";
  181. string m_EngineStartPlug = "";
  182. string m_EngineStartFuel = "";
  183. string m_EngineStopFuel = "";
  184. string m_CarDoorOpenSound = "";
  185. string m_CarDoorCloseSound = "";
  186. string m_CarSeatShiftInSound = "";
  187. string m_CarSeatShiftOutSound = "";
  188. string m_CarHornShortSoundName = "";
  189. string m_CarHornLongSoundName = "";
  190. ref EffectSound m_CrashSoundLight;
  191. ref EffectSound m_CrashSoundHeavy;
  192. ref EffectSound m_WindowSmall;
  193. ref EffectSound m_WindowLarge;
  194. private ref EffectSound m_PreStartSound;
  195. protected ref EffectSound m_CarHornSoundEffect;
  196. protected ref NoiseParams m_NoisePar;
  197. protected NoiseSystem m_NoiseSystem;
  198. protected bool m_PlayCrashSoundLight;
  199. protected bool m_PlayCrashSoundHeavy;
  200. protected bool m_HeadlightsOn;
  201. protected bool m_HeadlightsState;
  202. protected bool m_BrakesArePressed;
  203. protected bool m_RearLightType;
  204. protected bool m_ForceUpdateLights;
  205. protected bool m_EngineStarted;
  206. protected bool m_EngineDestroyed;
  207. protected int m_CarHornState;
  208. protected int m_CarEngineSoundState;
  209. protected int m_CarEngineLastSoundState;
  210. CarLightBase m_Headlight;
  211. CarRearLightBase m_RearLight;
  212. // Memory points
  213. static string m_ReverseLightPoint = "light_reverse";
  214. static string m_LeftHeadlightPoint = "light_left";
  215. static string m_RightHeadlightPoint = "light_right";
  216. static string m_LeftHeadlightTargetPoint = "light_left_dir";
  217. static string m_RightHeadlightTargetPoint = "light_right_dir";
  218. static string m_DrownEnginePoint = "drown_engine";
  219. // Model selection IDs for texture/material changes
  220. // If each car needs different IDs, then feel free to remove the 'static' flag and overwrite these numbers down the hierarchy
  221. static const int SELECTION_ID_FRONT_LIGHT_L = 0;
  222. static const int SELECTION_ID_FRONT_LIGHT_R = 1;
  223. static const int SELECTION_ID_BRAKE_LIGHT_L = 2;
  224. static const int SELECTION_ID_BRAKE_LIGHT_R = 3;
  225. static const int SELECTION_ID_REVERSE_LIGHT_L = 4;
  226. static const int SELECTION_ID_REVERSE_LIGHT_R = 5;
  227. static const int SELECTION_ID_TAIL_LIGHT_L = 6;
  228. static const int SELECTION_ID_TAIL_LIGHT_R = 7;
  229. static const int SELECTION_ID_DASHBOARD_LIGHT = 8;
  230. protected ref array<ref EffWheelSmoke> m_WheelSmokeFx;
  231. protected ref array<int> m_WheelSmokePtcFx;
  232. #ifdef DEVELOPER
  233. private const int DEBUG_MESSAGE_CLEAN_TIME_SECONDS = 10;
  234. private float m_DebugMessageCleanTime;
  235. private string m_DebugContactDamageMessage;
  236. #endif
  237. void CarScript()
  238. {
  239. #ifdef DEVELOPER
  240. _car = this;
  241. #endif
  242. SetEventMask(EntityEvent.POSTSIMULATE);
  243. SetEventMask(EntityEvent.POSTFRAME);
  244. m_ContactCache = new CarContactCache;
  245. m_Time = 0;
  246. // sets max health for all components at init
  247. m_EngineHealth = 1;
  248. m_FuelTankHealth = 1;
  249. m_RadiatorHealth = -1;
  250. m_BatteryHealth = -1;
  251. m_PlugHealth = -1;
  252. m_enginePtcFx = -1;
  253. m_coolantPtcFx = -1;
  254. m_exhaustPtcFx = -1;
  255. m_EnviroHeatComfortOverride = 0;
  256. m_PlayCrashSoundLight = false;
  257. m_PlayCrashSoundHeavy = false;
  258. m_CarHornState = ECarHornState.OFF;
  259. m_CarEngineSoundState = CarEngineSoundState.NONE;
  260. RegisterNetSyncVariableBool("m_HeadlightsOn");
  261. RegisterNetSyncVariableBool("m_BrakesArePressed");
  262. RegisterNetSyncVariableBool("m_ForceUpdateLights");
  263. RegisterNetSyncVariableBoolSignal("m_PlayCrashSoundLight");
  264. RegisterNetSyncVariableBoolSignal("m_PlayCrashSoundHeavy");
  265. RegisterNetSyncVariableInt("m_CarHornState", ECarHornState.OFF, ECarHornState.LONG);
  266. RegisterNetSyncVariableInt("m_CarEngineSoundState", CarEngineSoundState.NONE, CarEngineSoundState.STOP_NO_FUEL);
  267. if ( MemoryPointExists("ptcExhaust_end") )
  268. {
  269. m_exhaustPtcPos = GetMemoryPointPos("ptcExhaust_end");
  270. if ( MemoryPointExists("ptcExhaust_start") )
  271. {
  272. vector exhaustStart = GetMemoryPointPos("ptcExhaust_start");
  273. vector tempOri = vector.Direction( exhaustStart, m_exhaustPtcPos);
  274. m_exhaustPtcDir[0] = -tempOri[2];
  275. m_exhaustPtcDir[1] = tempOri[1];
  276. m_exhaustPtcDir[2] = tempOri[0];
  277. m_exhaustPtcDir = m_exhaustPtcDir.Normalized().VectorToAngles();
  278. }
  279. }
  280. else
  281. {
  282. m_exhaustPtcPos = "0 0 0";
  283. m_exhaustPtcDir = "1 1 1";
  284. }
  285. if ( MemoryPointExists("ptcEnginePos") )
  286. m_enginePtcPos = GetMemoryPointPos("ptcEnginePos");
  287. else
  288. m_enginePtcPos = "0 0 0";
  289. if ( MemoryPointExists("ptcCoolantPos") )
  290. m_coolantPtcPos = GetMemoryPointPos("ptcCoolantPos");
  291. else
  292. m_coolantPtcPos = "0 0 0";
  293. if ( MemoryPointExists("drown_engine") )
  294. m_DrownEnginePos = GetMemoryPointPos("drown_engine");
  295. else
  296. m_DrownEnginePos = "0 0 0";
  297. if ( MemoryPointExists("dmgZone_engine") )
  298. m_enginePos = GetMemoryPointPos("dmgZone_engine");
  299. else
  300. m_enginePos = "0 0 0";
  301. if ( MemoryPointExists("dmgZone_front") )
  302. m_frontPos = GetMemoryPointPos("dmgZone_front");
  303. else
  304. m_frontPos = "0 0 0";
  305. if ( MemoryPointExists("dmgZone_back") )
  306. m_backPos = GetMemoryPointPos("dmgZone_back");
  307. else
  308. m_backPos = "0 0 0";
  309. if ( MemoryPointExists("dmgZone_fender_1_1") )
  310. m_side_1_1Pos = GetMemoryPointPos("dmgZone_fender_1_1");
  311. else
  312. m_side_1_1Pos = "0 0 0";
  313. if ( MemoryPointExists("dmgZone_fender_1_2") )
  314. m_side_1_2Pos = GetMemoryPointPos("dmgZone_fender_1_2");
  315. else
  316. m_side_1_2Pos = "0 0 0";
  317. if ( MemoryPointExists("dmgZone_fender_2_1") )
  318. m_side_2_1Pos = GetMemoryPointPos("dmgZone_fender_2_1");
  319. else
  320. m_side_2_1Pos = "0 0 0";
  321. if ( MemoryPointExists("dmgZone_fender_2_2") )
  322. m_side_2_2Pos = GetMemoryPointPos("dmgZone_fender_2_2");
  323. else
  324. m_side_2_2Pos = "0 0 0";
  325. if (!GetGame().IsDedicatedServer())
  326. {
  327. m_WheelSmokeFx = new array<ref EffWheelSmoke>;
  328. m_WheelSmokeFx.Resize(WheelCount());
  329. m_WheelSmokePtcFx = new array<int>;
  330. m_WheelSmokePtcFx.Resize(WheelCount());
  331. for (int i = 0; i < m_WheelSmokePtcFx.Count(); i++)
  332. {
  333. m_WheelSmokePtcFx.Set(i, -1);
  334. }
  335. }
  336. }
  337. override void EEInit()
  338. {
  339. super.EEInit();
  340. if (GetGame().IsServer())
  341. {
  342. m_NoiseSystem = GetGame().GetNoiseSystem();
  343. if (m_NoiseSystem && !m_NoisePar)
  344. {
  345. m_NoisePar = new NoiseParams();
  346. m_NoisePar.LoadFromPath("cfgVehicles " + GetType() + " NoiseCarHorn");
  347. }
  348. }
  349. }
  350. #ifdef DIAG_DEVELOPER
  351. override void FixEntity()
  352. {
  353. if (GetGame().IsServer())
  354. {
  355. FillUpCarFluids();
  356. //server and single
  357. for (int i = 5; i > 0; i--)//there is a problem with wheels when performed only once, this solves it
  358. super.FixEntity();
  359. if (!GetGame().IsMultiplayer())
  360. {
  361. //single
  362. SEffectManager.DestroyEffect(m_engineFx);
  363. }
  364. }
  365. else
  366. {
  367. //MP client
  368. SEffectManager.DestroyEffect(m_engineFx);
  369. }
  370. }
  371. #endif
  372. override string GetVehicleType()
  373. {
  374. return "VehicleTypeCar";
  375. }
  376. vector GetEnginePosWS()
  377. {
  378. return ModelToWorld( m_DrownEnginePos );
  379. }
  380. vector GetCoolantPtcPosWS()
  381. {
  382. return ModelToWorld( m_coolantPtcPos );
  383. }
  384. vector GetEnginePointPosWS()
  385. {
  386. return ModelToWorld( m_enginePos );
  387. }
  388. vector GetFrontPointPosWS()
  389. {
  390. return ModelToWorld( m_frontPos );
  391. }
  392. vector GetBackPointPosWS()
  393. {
  394. return ModelToWorld( m_backPos );
  395. }
  396. vector Get_1_1PointPosWS()
  397. {
  398. return ModelToWorld( m_side_1_1Pos );
  399. }
  400. vector Get_1_2PointPosWS()
  401. {
  402. return ModelToWorld( m_side_1_2Pos );
  403. }
  404. vector Get_2_1PointPosWS()
  405. {
  406. return ModelToWorld( m_side_2_1Pos );
  407. }
  408. vector Get_2_2PointPosWS()
  409. {
  410. return ModelToWorld( m_side_2_2Pos );
  411. }
  412. override float GetLiquidThroughputCoef()
  413. {
  414. return LIQUID_THROUGHPUT_CAR_DEFAULT;
  415. }
  416. //here we should handle the damage dealt in OnContact event, but maybe we will react even in that event
  417. override void EEHitBy(TotalDamageResult damageResult, int damageType, EntityAI source, int component, string dmgZone, string ammo, vector modelPos, float speedCoef)
  418. {
  419. super.EEHitBy(damageResult, damageType, source, component, dmgZone, ammo, modelPos, speedCoef);
  420. ForceUpdateLightsStart();
  421. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(ForceUpdateLightsEnd, 100, false);
  422. }
  423. override void EEDelete(EntityAI parent)
  424. {
  425. #ifndef SERVER
  426. CleanupEffects();
  427. #endif
  428. }
  429. void ~CarScript()
  430. {
  431. #ifndef SERVER
  432. CleanupEffects();
  433. #endif
  434. }
  435. void CleanupEffects()
  436. {
  437. for (int i = 0; i < m_WheelSmokeFx.Count(); i++ )
  438. {
  439. Effect ps = m_WheelSmokeFx.Get(i);
  440. if (ps)
  441. {
  442. SEffectManager.DestroyEffect(ps);
  443. }
  444. }
  445. m_WheelSmokeFx.Clear();
  446. m_WheelSmokePtcFx.Clear();
  447. SEffectManager.DestroyEffect(m_coolantFx);
  448. SEffectManager.DestroyEffect(m_exhaustFx);
  449. SEffectManager.DestroyEffect(m_engineFx);
  450. if (m_Headlight)
  451. m_Headlight.Destroy();
  452. if (m_RearLight)
  453. m_RearLight.Destroy();
  454. SEffectManager.DestroyEffect(m_CrashSoundLight);
  455. SEffectManager.DestroyEffect(m_CrashSoundHeavy);
  456. SEffectManager.DestroyEffect(m_WindowSmall);
  457. SEffectManager.DestroyEffect(m_WindowLarge);
  458. CleanupSound(m_CarHornSoundEffect);
  459. }
  460. void CleanupSound(EffectSound sound)
  461. {
  462. SEffectManager.DestroyEffect(sound);
  463. }
  464. override void GetDebugActions(out TSelectableActionInfoArrayEx outputList)
  465. {
  466. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_HORN_START_SHORT, "Car Horn Start Short", FadeColors.LIGHT_GREY));
  467. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_HORN_START_LONG, "Car Horn Start Long", FadeColors.LIGHT_GREY));
  468. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_HORN_STOP, "Car Horn Stop", FadeColors.LIGHT_GREY));
  469. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "Car Fuel", FadeColors.RED));
  470. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_FUEL_FULL, "Full", FadeColors.LIGHT_GREY));
  471. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_FUEL_EMPTY, "Empty", FadeColors.LIGHT_GREY));
  472. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_FUEL_INCREASE, "10% increase", FadeColors.LIGHT_GREY));
  473. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_FUEL_DECREASE, "10% decrease", FadeColors.LIGHT_GREY));
  474. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  475. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "Car Cooler", FadeColors.RED));
  476. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_COOLANT_FULL, "Full", FadeColors.LIGHT_GREY));
  477. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_COOLANT_EMPTY, "Empty", FadeColors.LIGHT_GREY));
  478. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_COOLANT_INCREASE, "10% increase", FadeColors.LIGHT_GREY));
  479. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.CAR_COOLANT_DECREASE, "10% decrease", FadeColors.LIGHT_GREY));
  480. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  481. super.GetDebugActions(outputList);
  482. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
  483. outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.DELETE, "Delete", FadeColors.RED));
  484. }
  485. override bool OnAction(int action_id, Man player, ParamsReadContext ctx)
  486. {
  487. if (super.OnAction(action_id, player, ctx))
  488. return true;
  489. if (!GetGame().IsServer())
  490. {
  491. return false;
  492. }
  493. switch (action_id)
  494. {
  495. case EActions.CAR_HORN_START_SHORT:
  496. SetCarHornState(ECarHornState.SHORT);
  497. return true;
  498. case EActions.CAR_HORN_START_LONG:
  499. SetCarHornState(ECarHornState.LONG);
  500. return true;
  501. case EActions.CAR_HORN_STOP:
  502. SetCarHornState(ECarHornState.OFF);
  503. return true;
  504. case EActions.CAR_FUEL_FULL:
  505. Fill(CarFluid.FUEL, GetFluidCapacity(CarFluid.FUEL));
  506. return true;
  507. case EActions.CAR_FUEL_EMPTY:
  508. LeakAll(CarFluid.FUEL);
  509. return true;
  510. case EActions.CAR_FUEL_INCREASE:
  511. Fill(CarFluid.FUEL, GetFluidCapacity(CarFluid.FUEL) * 0.1);
  512. return true;
  513. case EActions.CAR_FUEL_DECREASE:
  514. Leak(CarFluid.FUEL, GetFluidCapacity(CarFluid.FUEL) * 0.1);
  515. return true;
  516. case EActions.CAR_COOLANT_FULL:
  517. Fill(CarFluid.COOLANT, GetFluidCapacity(CarFluid.COOLANT));
  518. return true;
  519. case EActions.CAR_COOLANT_EMPTY:
  520. LeakAll(CarFluid.COOLANT);
  521. return true;
  522. case EActions.CAR_COOLANT_INCREASE:
  523. Fill(CarFluid.COOLANT, GetFluidCapacity(CarFluid.COOLANT) * 0.1);
  524. return true;
  525. case EActions.CAR_COOLANT_DECREASE:
  526. Leak(CarFluid.COOLANT, GetFluidCapacity(CarFluid.COOLANT) * 0.1);
  527. return true;
  528. case EActions.DELETE:
  529. Delete();
  530. return true;
  531. }
  532. return false;
  533. }
  534. override void OnVariablesSynchronized()
  535. {
  536. super.OnVariablesSynchronized();
  537. if (GetCrashHeavySound())
  538. {
  539. PlayCrashHeavySound();
  540. }
  541. else if (GetCrashLightSound())
  542. {
  543. PlayCrashLightSound();
  544. }
  545. HandleCarHornSound(m_CarHornState);
  546. if (m_CarEngineSoundState != m_CarEngineLastSoundState)
  547. HandleEngineSound(m_CarEngineSoundState);
  548. UpdateLights();
  549. }
  550. void CreateCarDestroyedEffect()
  551. {
  552. if ( !SEffectManager.IsEffectExist( m_enginePtcFx ) && GetGame().GetWaterDepth( GetEnginePosWS() ) <= 0 )
  553. {
  554. m_engineFx = new EffEngineSmoke();
  555. m_engineFx.SetParticleStateHeavy();
  556. m_enginePtcFx = SEffectManager.PlayOnObject( m_engineFx, this, m_enginePtcPos, Vector(0,0,0));
  557. }
  558. }
  559. override void EEItemAttached(EntityAI item, string slot_name)
  560. {
  561. super.EEItemAttached(item, slot_name);
  562. switch (slot_name)
  563. {
  564. case "Reflector_1_1":
  565. if (GetGame().IsServer())
  566. {
  567. SetHealth("Reflector_1_1", "Health", item.GetHealth());
  568. }
  569. break;
  570. case "Reflector_2_1":
  571. if (GetGame().IsServer())
  572. {
  573. SetHealth("Reflector_2_1", "Health", item.GetHealth());
  574. }
  575. break;
  576. case "CarBattery":
  577. case "TruckBattery":
  578. if (GetGame().IsServer())
  579. {
  580. m_BatteryHealth = item.GetHealth01();
  581. }
  582. break;
  583. case "SparkPlug":
  584. case "GlowPlug":
  585. if (GetGame().IsServer())
  586. {
  587. m_PlugHealth = item.GetHealth01();
  588. }
  589. break;
  590. case "CarRadiator":
  591. if (GetGame().IsServer())
  592. {
  593. m_RadiatorHealth = item.GetHealth01();
  594. }
  595. m_Radiator = item;
  596. break;
  597. }
  598. if (GetGame().IsServer())
  599. {
  600. Synchronize();
  601. }
  602. UpdateHeadlightState();
  603. UpdateLights();
  604. }
  605. // Updates state of attached headlight bulbs for faster access
  606. void UpdateHeadlightState()
  607. {
  608. EntityAI bulb_L = FindAttachmentBySlotName("Reflector_1_1");
  609. EntityAI bulb_R = FindAttachmentBySlotName("Reflector_2_1");
  610. if (bulb_L && !bulb_L.IsRuined() && bulb_R && !bulb_R.IsRuined())
  611. {
  612. m_HeadlightsState = CarHeadlightBulbsState.BOTH;
  613. }
  614. else if (bulb_L && !bulb_L.IsRuined())
  615. {
  616. m_HeadlightsState = CarHeadlightBulbsState.LEFT;
  617. }
  618. else if (bulb_R && !bulb_R.IsRuined())
  619. {
  620. m_HeadlightsState = CarHeadlightBulbsState.RIGHT;
  621. }
  622. else if ((!bulb_L || bulb_L.IsRuined()) && (!bulb_R || bulb_R.IsRuined()))
  623. {
  624. m_HeadlightsState = CarHeadlightBulbsState.NONE;
  625. }
  626. }
  627. override void EEItemDetached(EntityAI item, string slot_name)
  628. {
  629. switch (slot_name)
  630. {
  631. case "CarBattery":
  632. case "TruckBattery":
  633. m_BatteryHealth = -1;
  634. if (GetGame().IsServer())
  635. {
  636. if (EngineIsOn())
  637. {
  638. EngineStop();
  639. }
  640. if (IsScriptedLightsOn())
  641. {
  642. ToggleHeadlights();
  643. }
  644. }
  645. break;
  646. case "SparkPlug":
  647. case "GlowPlug":
  648. m_PlugHealth = -1;
  649. if (GetGame().IsServer() && EngineIsOn())
  650. {
  651. EngineStop();
  652. }
  653. break;
  654. case "CarRadiator":
  655. m_Radiator = null;
  656. if (GetGame().IsServer())
  657. {
  658. LeakAll(CarFluid.COOLANT);
  659. if (m_DamageZoneMap.Contains("Radiator"))
  660. {
  661. SetHealth("Radiator", "Health", 0);
  662. }
  663. }
  664. break;
  665. }
  666. if (GetGame().IsServer())
  667. {
  668. Synchronize();
  669. }
  670. UpdateHeadlightState();
  671. UpdateLights();
  672. }
  673. override void OnAttachmentRuined(EntityAI attachment)
  674. {
  675. super.OnAttachmentRuined(attachment);
  676. UpdateHeadlightState();
  677. UpdateLights();
  678. }
  679. override bool CanReceiveAttachment(EntityAI attachment, int slotId)
  680. {
  681. if (!super.CanReceiveAttachment(attachment, slotId))
  682. return false;
  683. InventoryLocation attachmentInventoryLocation = new InventoryLocation();
  684. attachment.GetInventory().GetCurrentInventoryLocation(attachmentInventoryLocation);
  685. if (attachmentInventoryLocation.GetParent() == null)
  686. {
  687. return true;
  688. }
  689. if (attachment && attachment.Type().IsInherited(CarWheel))
  690. {
  691. string slotSelectionName;
  692. InventorySlots.GetSelectionForSlotId(slotId, slotSelectionName);
  693. switch (slotSelectionName)
  694. {
  695. case "wheel_spare_1":
  696. case "wheel_spare_2":
  697. return CanManipulateSpareWheel(slotSelectionName);
  698. break;
  699. }
  700. }
  701. return true;
  702. }
  703. override bool CanReleaseAttachment(EntityAI attachment)
  704. {
  705. if (!super.CanReleaseAttachment(attachment))
  706. {
  707. return false;
  708. }
  709. if (EngineIsOn() && IsMoving())
  710. {
  711. return false;
  712. }
  713. if (attachment && attachment.Type().IsInherited(CarWheel))
  714. {
  715. InventoryLocation attachmentInventoryLocation = new InventoryLocation();
  716. attachment.GetInventory().GetCurrentInventoryLocation(attachmentInventoryLocation);
  717. string slotSelectionName;
  718. InventorySlots.GetSelectionForSlotId(attachmentInventoryLocation.GetSlot(), slotSelectionName);
  719. switch (slotSelectionName)
  720. {
  721. case "wheel_spare_1":
  722. case "wheel_spare_2":
  723. return CanManipulateSpareWheel(slotSelectionName);
  724. break;
  725. }
  726. }
  727. return true;
  728. }
  729. protected bool CanManipulateSpareWheel(string slotSelectionName)
  730. {
  731. return false;
  732. }
  733. override void EOnPostSimulate(IEntity other, float timeSlice)
  734. {
  735. m_Time += timeSlice;
  736. if (GetGame().IsServer())
  737. {
  738. HandleByCrewMemberState(ECrewMemberState.UNCONSCIOUS);
  739. HandleByCrewMemberState(ECrewMemberState.DEAD);
  740. #ifdef DIAG_DEVELOPER
  741. if (DEBUG_OUTPUT_TYPE & EVehicleDebugOutputType.CONTACT)
  742. {
  743. if (m_ContactCalled)
  744. {
  745. Debug.Log("Momentum delta: " + (GetMomentum() - m_MomentumPrevTick));
  746. Debug.Log("--------------------------------------------------------------------");
  747. m_ContactCalled = false;
  748. }
  749. }
  750. #endif
  751. CheckContactCache();
  752. m_VelocityPrevTick = GetVelocity(this);
  753. m_MomentumPrevTick = GetMomentum();
  754. #ifdef DEVELOPER
  755. m_DebugMessageCleanTime += timeSlice;
  756. if (m_DebugMessageCleanTime >= DEBUG_MESSAGE_CLEAN_TIME_SECONDS)
  757. {
  758. m_DebugMessageCleanTime = 0;
  759. m_DebugContactDamageMessage = "";
  760. }
  761. #endif
  762. }
  763. if ( m_Time >= GameConstants.CARS_FLUIDS_TICK )
  764. {
  765. m_Time = 0;
  766. CarPartsHealthCheck();
  767. //First of all check if the car should stop the engine
  768. if (GetGame().IsServer() && EngineIsOn())
  769. {
  770. if ( GetFluidFraction(CarFluid.FUEL) <= 0 || m_EngineHealth <= 0 )
  771. EngineStop();
  772. CheckVitalItem(IsVitalCarBattery(), "CarBattery");
  773. CheckVitalItem(IsVitalTruckBattery(), "TruckBattery");
  774. CheckVitalItem(IsVitalSparkPlug(), "SparkPlug");
  775. CheckVitalItem(IsVitalGlowPlug(), "GlowPlug");
  776. }
  777. if (GetGame().IsServer())
  778. {
  779. if (IsVitalFuelTank())
  780. {
  781. if (m_FuelTankHealth == GameConstants.DAMAGE_RUINED_VALUE && m_EngineHealth > GameConstants.DAMAGE_RUINED_VALUE)
  782. {
  783. SetHealth("Engine", "Health", GameConstants.DAMAGE_RUINED_VALUE);
  784. }
  785. }
  786. }
  787. //! actions runned when the engine on
  788. if ( EngineIsOn() )
  789. {
  790. if ( GetGame().IsServer() )
  791. {
  792. float dmg;
  793. if ( EngineGetRPM() >= EngineGetRPMRedline() )
  794. {
  795. if (EngineGetRPM() > EngineGetRPMMax())
  796. AddHealth( "Engine", "Health", -GetMaxHealth("Engine", "") * 0.05 ); //CAR_RPM_DMG
  797. dmg = EngineGetRPM() * 0.001 * Math.RandomFloat( 0.02, 1.0 ); //CARS_TICK_DMG_MIN; //CARS_TICK_DMG_MAX
  798. ProcessDirectDamage(DamageType.CUSTOM, null, "Engine", "EnviroDmg", vector.Zero, dmg);
  799. SetEngineZoneReceivedHit(true);
  800. }
  801. else
  802. {
  803. SetEngineZoneReceivedHit(false);
  804. }
  805. //! leaking of coolant from radiator when damaged
  806. if ( IsVitalRadiator() )
  807. {
  808. if ( GetFluidFraction(CarFluid.COOLANT) > 0 && m_RadiatorHealth < 0.5 ) //CARS_LEAK_THRESHOLD
  809. LeakFluid( CarFluid.COOLANT );
  810. }
  811. if ( GetFluidFraction(CarFluid.FUEL) > 0 && m_FuelTankHealth < GameConstants.DAMAGE_DAMAGED_VALUE )
  812. LeakFluid( CarFluid.FUEL );
  813. if ( GetFluidFraction(CarFluid.BRAKE) > 0 && m_EngineHealth < GameConstants.DAMAGE_DAMAGED_VALUE )
  814. LeakFluid( CarFluid.BRAKE );
  815. if ( GetFluidFraction(CarFluid.OIL) > 0 && m_EngineHealth < GameConstants.DAMAGE_DAMAGED_VALUE )
  816. LeakFluid( CarFluid.OIL );
  817. if ( m_EngineHealth < 0.25 )
  818. LeakFluid( CarFluid.OIL );
  819. if ( IsVitalRadiator() )
  820. {
  821. if ( GetFluidFraction( CarFluid.COOLANT ) < 0.5 && GetFluidFraction( CarFluid.COOLANT ) >= 0 )
  822. {
  823. dmg = ( 1 - GetFluidFraction(CarFluid.COOLANT) ) * Math.RandomFloat( 0.02, 10.00 ); //CARS_DMG_TICK_MIN_COOLANT; //CARS_DMG_TICK_MAX_COOLANT
  824. AddHealth( "Engine", "Health", -dmg );
  825. SetEngineZoneReceivedHit(true);
  826. }
  827. }
  828. }
  829. //FX only on Client and in Single
  830. if (!GetGame().IsDedicatedServer())
  831. {
  832. if (!SEffectManager.IsEffectExist(m_exhaustPtcFx))
  833. {
  834. m_exhaustFx = new EffExhaustSmoke();
  835. m_exhaustPtcFx = SEffectManager.PlayOnObject( m_exhaustFx, this, m_exhaustPtcPos, m_exhaustPtcDir );
  836. m_exhaustFx.SetParticleStateLight();
  837. }
  838. if (IsVitalRadiator() && GetFluidFraction(CarFluid.COOLANT) < 0.5)
  839. {
  840. if (!SEffectManager.IsEffectExist(m_coolantPtcFx))
  841. {
  842. m_coolantFx = new EffCoolantSteam();
  843. m_coolantPtcFx = SEffectManager.PlayOnObject(m_coolantFx, this, m_coolantPtcPos, vector.Zero);
  844. }
  845. if (m_coolantFx)
  846. {
  847. if (GetFluidFraction(CarFluid.COOLANT) > 0)
  848. m_coolantFx.SetParticleStateLight();
  849. else
  850. m_coolantFx.SetParticleStateHeavy();
  851. }
  852. }
  853. else
  854. {
  855. if (SEffectManager.IsEffectExist(m_coolantPtcFx))
  856. SEffectManager.Stop(m_coolantPtcFx);
  857. }
  858. }
  859. }
  860. else
  861. {
  862. //FX only on Client and in Single
  863. if ( !GetGame().IsDedicatedServer() )
  864. {
  865. if (SEffectManager.IsEffectExist(m_exhaustPtcFx))
  866. {
  867. SEffectManager.Stop(m_exhaustPtcFx);
  868. m_exhaustPtcFx = -1;
  869. }
  870. if (SEffectManager.IsEffectExist(m_coolantPtcFx))
  871. {
  872. SEffectManager.Stop(m_coolantPtcFx);
  873. m_coolantPtcFx = -1;
  874. }
  875. }
  876. }
  877. }
  878. //FX only on Client and in Single
  879. if ( !GetGame().IsDedicatedServer() )
  880. {
  881. float carSpeed = GetVelocity(this).Length();
  882. for (int i = 0; i < WheelCount(); i++)
  883. {
  884. EffWheelSmoke eff = m_WheelSmokeFx.Get(i);
  885. int ptrEff = m_WheelSmokePtcFx.Get(i);
  886. bool haveParticle = false;
  887. if (WheelHasContact(i))
  888. {
  889. CarWheel wheel = CarWheel.Cast(WheelGetEntity(i));
  890. float wheelSpeed = WheelGetAngularVelocity(i) * wheel.GetRadius();
  891. vector wheelPos = WheelGetContactPosition(i);
  892. vector wheelVel = dBodyGetVelocityAt(this, wheelPos);
  893. vector transform[3];
  894. transform[2] = WheelGetDirection(i);
  895. transform[1] = vector.Up;
  896. transform[0] = transform[2] * transform[1];
  897. wheelVel = wheelVel.InvMultiply3(transform);
  898. float bodySpeed = wheelVel[2];
  899. bool applyEffect = false;
  900. if ((wheelSpeed > 0 && bodySpeed > 0) || (wheelSpeed < 0 && bodySpeed < 0))
  901. {
  902. applyEffect = Math.AbsFloat(wheelSpeed) > Math.AbsFloat(bodySpeed) + EffWheelSmoke.WHEEL_SMOKE_THRESHOLD;
  903. }
  904. else
  905. {
  906. applyEffect = Math.AbsFloat(wheelSpeed) > EffWheelSmoke.WHEEL_SMOKE_THRESHOLD;
  907. }
  908. if (applyEffect)
  909. {
  910. haveParticle = true;
  911. string surface;
  912. GetGame().SurfaceGetType(wheelPos[0], wheelPos[2], surface);
  913. wheelPos = WorldToModel(wheelPos);
  914. if (!SEffectManager.IsEffectExist(ptrEff))
  915. {
  916. eff = new EffWheelSmoke();
  917. eff.SetSurface(surface);
  918. ptrEff = SEffectManager.PlayOnObject(eff, this, wheelPos, "0 1 -1");
  919. eff.SetCurrentLocalPosition(wheelPos);
  920. m_WheelSmokeFx.Set(i, eff);
  921. m_WheelSmokePtcFx.Set(i, ptrEff);
  922. }
  923. else
  924. {
  925. if (!eff.IsPlaying())
  926. eff.Start();
  927. eff.SetSurface(surface);
  928. eff.SetCurrentLocalPosition(wheelPos);
  929. }
  930. }
  931. }
  932. if (!haveParticle)
  933. {
  934. if (eff && eff.IsPlaying())
  935. eff.Stop();
  936. }
  937. }
  938. }
  939. //}
  940. }
  941. void OnBrakesPressed()
  942. {
  943. UpdateLights();
  944. }
  945. void OnBrakesReleased()
  946. {
  947. UpdateLights();
  948. }
  949. // Server side event for jump out processing
  950. void OnVehicleJumpOutServer(GetOutTransportActionData gotActionData)
  951. {
  952. PlayerBase player = gotActionData.m_Player;
  953. array<ClothingBase> equippedClothes = new array<ClothingBase>;
  954. equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("LEGS")));
  955. equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("BACK")));
  956. equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("VEST")));
  957. equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("HeadGear")));
  958. equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("Mask")));
  959. equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("BODY")));
  960. equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("FEET")));
  961. equippedClothes.Insert(ClothingBase.Cast(player.GetItemOnSlot("GLOVES")));
  962. // -----------------------------------------------
  963. float shockTaken = (gotActionData.m_Speed * gotActionData.m_Speed) / ActionGetOutTransport.DMG_FACTOR;
  964. //Lower shock taken if player uses a helmet
  965. ItemBase headGear = ClothingBase.Cast(player.GetItemOnHead());
  966. HelmetBase helmet;
  967. if (Class.CastTo(helmet, headGear))
  968. shockTaken *= 0.5;
  969. // -----------------------------------------------
  970. int randNum; //value used for probability evaluation
  971. randNum = Math.RandomInt(0, 100);
  972. if (gotActionData.m_Speed < ActionGetOutTransport.LOW_SPEED_VALUE)
  973. {
  974. if (randNum < 20)
  975. player.GiveShock(-shockTaken); //To inflict shock, a negative value must be passed
  976. randNum = Math.RandomIntInclusive(0, PlayerBase.m_BleedingSourcesLow.Count() - 1);
  977. player.m_BleedingManagerServer.AttemptAddBleedingSourceBySelection(PlayerBase.m_BleedingSourcesLow[randNum]);
  978. }
  979. else if (gotActionData.m_Speed >= ActionGetOutTransport.LOW_SPEED_VALUE && gotActionData.m_Speed < ActionGetOutTransport.HIGH_SPEED_VALUE)
  980. {
  981. if (randNum < 50)
  982. player.GiveShock(-shockTaken);
  983. randNum = Math.RandomInt(0, PlayerBase.m_BleedingSourcesUp.Count() - 1);
  984. player.m_BleedingManagerServer.AttemptAddBleedingSourceBySelection(PlayerBase.m_BleedingSourcesUp[randNum]);
  985. }
  986. else if (gotActionData.m_Speed >= ActionGetOutTransport.HIGH_SPEED_VALUE)
  987. {
  988. if (!headGear)
  989. player.m_BleedingManagerServer.AttemptAddBleedingSourceBySelection("Head");
  990. if (randNum < 75)
  991. player.GiveShock(-shockTaken);
  992. }
  993. float dmgTaken = (gotActionData.m_Speed * gotActionData.m_Speed) / ActionGetOutTransport.SHOCK_FACTOR;
  994. //Damage all currently equipped clothes
  995. foreach (ClothingBase cloth : equippedClothes)
  996. {
  997. //If no item is equipped on slot, slot is ignored
  998. if (cloth == null)
  999. continue;
  1000. cloth.DecreaseHealth(dmgTaken, false);
  1001. }
  1002. vector posMS = gotActionData.m_Player.WorldToModel(gotActionData.m_Player.GetPosition());
  1003. gotActionData.m_Player.DamageAllLegs(dmgTaken); //Additionnal leg specific damage dealing
  1004. float healthCoef = Math.InverseLerp(ActionGetOutTransport.HEALTH_LOW_SPEED_VALUE, ActionGetOutTransport.HEALTH_HIGH_SPEED_VALUE, gotActionData.m_Speed);
  1005. healthCoef = Math.Clamp(healthCoef, 0.0, 1.0);
  1006. gotActionData.m_Player.ProcessDirectDamage(DamageType.CUSTOM, gotActionData.m_Player, "", "FallDamageHealth", posMS, healthCoef);
  1007. }
  1008. override void OnUpdate( float dt )
  1009. {
  1010. if ( GetGame().IsServer() )
  1011. {
  1012. ItemBase battery = GetBattery();
  1013. if ( battery )
  1014. {
  1015. if ( EngineIsOn() )
  1016. {
  1017. m_BatteryTimer += dt;
  1018. if ( m_BatteryTimer >= BATTERY_UPDATE_DELAY )
  1019. {
  1020. battery.GetCompEM().ConsumeEnergy(GetBatteryRechargeRate() * m_BatteryTimer);
  1021. m_BatteryTimer = 0;
  1022. }
  1023. }
  1024. else if ( !EngineIsOn() && IsScriptedLightsOn() )
  1025. {
  1026. m_BatteryTimer += dt;
  1027. if ( m_BatteryTimer >= BATTERY_UPDATE_DELAY )
  1028. {
  1029. battery.GetCompEM().ConsumeEnergy(GetBatteryRuntimeConsumption() * m_BatteryTimer);
  1030. m_BatteryTimer = 0;
  1031. if ( battery.GetCompEM().GetEnergy() <= 0 )
  1032. {
  1033. ToggleHeadlights();
  1034. }
  1035. }
  1036. }
  1037. }
  1038. if ( GetGame().GetWaterDepth( GetEnginePosWS() ) > 0 )
  1039. {
  1040. m_DrownTime += dt;
  1041. if ( m_DrownTime > DROWN_ENGINE_THRESHOLD )
  1042. {
  1043. // *dt to get damage per second
  1044. AddHealth( "Engine", "Health", -DROWN_ENGINE_DAMAGE * dt);
  1045. SetEngineZoneReceivedHit(true);
  1046. }
  1047. }
  1048. else
  1049. {
  1050. m_DrownTime = 0;
  1051. }
  1052. }
  1053. // For visualisation of brake lights for all players
  1054. float brake_coef = GetBrake();
  1055. if ( brake_coef > 0 )
  1056. {
  1057. if ( !m_BrakesArePressed )
  1058. {
  1059. m_BrakesArePressed = true;
  1060. SetSynchDirty();
  1061. OnBrakesPressed();
  1062. }
  1063. }
  1064. else
  1065. {
  1066. if ( m_BrakesArePressed )
  1067. {
  1068. m_BrakesArePressed = false;
  1069. SetSynchDirty();
  1070. OnBrakesReleased();
  1071. }
  1072. }
  1073. if ( (!GetGame().IsDedicatedServer()) && m_ForceUpdateLights )
  1074. {
  1075. UpdateLights();
  1076. m_ForceUpdateLights = false;
  1077. }
  1078. }
  1079. override void EEKilled(Object killer)
  1080. {
  1081. super.EEKilled(killer);
  1082. m_EngineDestroyed = true;
  1083. }
  1084. //! WARNING: Can be called very frequently in one frame, use with caution
  1085. override void OnContact( string zoneName, vector localPos, IEntity other, Contact data )
  1086. {
  1087. if (GetGame().IsServer())
  1088. {
  1089. #ifdef DIAG_DEVELOPER
  1090. m_ContactCalled = true;
  1091. if (DEBUG_OUTPUT_TYPE & EVehicleDebugOutputType.CONTACT)
  1092. {
  1093. string output = "Zone: " + zoneName + " | Impulse:" + data.Impulse;
  1094. Debug.Log(output);
  1095. }
  1096. #endif
  1097. if (m_ContactCache.Count() == 0)
  1098. {
  1099. array<ref CarContactData> ccd = new array<ref CarContactData>;
  1100. m_ContactCache.Insert(zoneName, ccd);
  1101. float momentumDelta = GetMomentum() - m_MomentumPrevTick;
  1102. float dot = vector.Dot(m_VelocityPrevTick.Normalized(), GetVelocity(this).Normalized());
  1103. if (dot < 0)
  1104. {
  1105. momentumDelta = m_MomentumPrevTick;
  1106. }
  1107. ccd.Insert(new CarContactData(localPos, other, momentumDelta));
  1108. }
  1109. }
  1110. }
  1111. //! Responsible for damaging the car according to contact events from OnContact
  1112. void CheckContactCache()
  1113. {
  1114. int contactZonesCount = m_ContactCache.Count();
  1115. if (contactZonesCount == 0)
  1116. return;
  1117. for (int i = 0; i < contactZonesCount; ++i)
  1118. {
  1119. string zoneName = m_ContactCache.GetKey(i);
  1120. array<ref CarContactData> data = m_ContactCache[zoneName];
  1121. float dmg = Math.AbsInt(data[0].impulse * m_dmgContactCoef);
  1122. float crewDmgBase = Math.AbsInt((data[0].impulse / dBodyGetMass(this)) * 1000 * m_dmgContactCoef);// calculates damage as if the object's weight was 1000kg instead of its actual weight
  1123. #ifdef DIAG_DEVELOPER
  1124. CrashDebugData.m_CrashDataPoint = new CrashDebugData();
  1125. CrashDebugData.m_CrashDataPoint.m_VehicleType = GetDisplayName();
  1126. CrashDebugData.m_CrashDataPoint.m_Damage = dmg;
  1127. CrashDebugData.m_CrashDataPoint.m_Zone = zoneName;
  1128. CrashDebugData.m_CrashDataPoint.m_MomentumCurr = GetMomentum();
  1129. CrashDebugData.m_CrashDataPoint.m_MomentumPrev = m_MomentumPrevTick;
  1130. CrashDebugData.m_CrashDataPoint.m_MomentumDelta = data[0].impulse;
  1131. CrashDebugData.m_CrashDataPoint.m_SpeedWorld = GetVelocity(this).Length() * 3.6;
  1132. CrashDebugData.m_CrashDataPoint.m_SpeedWorldPrev = m_VelocityPrevTick.Length() * 3.6;
  1133. CrashDebugData.m_CrashDataPoint.m_SpeedWorldDelta = (m_VelocityPrevTick.Length() - GetVelocity(this).Length()) * 3.6;
  1134. CrashDebugData.m_CrashDataPoint.m_VelocityCur = GetVelocity(this);
  1135. CrashDebugData.m_CrashDataPoint.m_VelocityPrev = m_VelocityPrevTick;
  1136. CrashDebugData.m_CrashDataPoint.m_VelocityDot = vector.Dot(m_VelocityPrevTick.Normalized(), GetVelocity(this).Normalized());
  1137. CrashDebugData.m_CrashDataPoint.m_Time = GetGame().GetTime();
  1138. if (DEBUG_OUTPUT_TYPE & EVehicleDebugOutputType.DAMAGE_CONSIDERED)
  1139. {
  1140. Debug.Log("--------------------------------------------------");
  1141. Debug.Log("Vehicle:" + GetDisplayName());
  1142. Debug.Log("DMG: " + dmg);
  1143. Debug.Log("zoneName : "+ zoneName);
  1144. Debug.Log("momentumCurr : "+ GetMomentum());
  1145. Debug.Log("momentumPrev : "+ m_MomentumPrevTick);
  1146. Debug.Log("momentumDelta : "+ data[0].impulse);
  1147. Debug.Log("speed(km/h): "+ GetVelocity(this).Length() * 3.6);
  1148. Debug.Log("speedPrev(km/h): "+ m_VelocityPrevTick.Length() * 3.6);
  1149. Debug.Log("speedDelta(km/h) : "+ (m_VelocityPrevTick.Length() - GetVelocity(this).Length()) * 3.6);
  1150. Debug.Log("velocityCur.): "+ GetVelocity(this));
  1151. Debug.Log("velocityPrev.): "+ m_VelocityPrevTick);
  1152. Debug.Log("velocityDot): "+ vector.Dot(m_VelocityPrevTick.Normalized(), GetVelocity(this).Normalized()));
  1153. Debug.Log("GetGame().GetTime(): "+ GetGame().GetTime());
  1154. Debug.Log("--------------------------------------------------");
  1155. }
  1156. #endif
  1157. if ( dmg < GameConstants.CARS_CONTACT_DMG_MIN )
  1158. continue;
  1159. int pddfFlags;
  1160. #ifdef DIAG_DEVELOPER
  1161. CrashDebugData.m_CrashData.Insert(CrashDebugData.m_CrashDataPoint);
  1162. CrashDebugData.m_CrashDataPoint.m_Speedometer = GetSpeedometer();
  1163. //Print("Crash data recorded");
  1164. #endif
  1165. if (dmg < GameConstants.CARS_CONTACT_DMG_THRESHOLD)
  1166. {
  1167. #ifdef DIAG_DEVELOPER
  1168. CrashDebugData.m_CrashDataPoint.m_DamageType = "Small";
  1169. if (DEBUG_OUTPUT_TYPE & EVehicleDebugOutputType.DAMAGE_APPLIED)
  1170. Debug.Log(string.Format("[Vehiles:Damage]:: DMG %1 to the %2 zone is SMALL (threshold: %3), SPEEDOMETER: %4, TIME: %5", dmg, zoneName, GameConstants.CARS_CONTACT_DMG_MIN, GetSpeedometer(), GetGame().GetTime() ));
  1171. #endif
  1172. SynchCrashLightSound(true);
  1173. pddfFlags = ProcessDirectDamageFlags.NO_TRANSFER;
  1174. }
  1175. else
  1176. {
  1177. #ifdef DIAG_DEVELOPER
  1178. CrashDebugData.m_CrashDataPoint.m_DamageType = "Big";
  1179. if (DEBUG_OUTPUT_TYPE & EVehicleDebugOutputType.DAMAGE_APPLIED)
  1180. Debug.Log(string.Format("[Vehiles:Damage]:: DMG %1 to the %2 zone is BIG (threshold: %3), SPEED: %4, TIME: %5", dmg, zoneName, GameConstants.CARS_CONTACT_DMG_THRESHOLD, GetSpeedometer(), GetGame().GetTime() ));
  1181. #endif
  1182. DamageCrew(crewDmgBase);
  1183. SynchCrashHeavySound(true);
  1184. pddfFlags = 0;
  1185. }
  1186. #ifdef DEVELOPER
  1187. m_DebugContactDamageMessage += string.Format("%1: %2\n", zoneName, dmg);
  1188. #endif
  1189. ProcessDirectDamage(DT_CUSTOM, null, zoneName, "EnviroDmg", "0 0 0", dmg, pddfFlags);
  1190. //if (data[0].impulse > TRESHOLD)
  1191. //{
  1192. /* Object targetEntity = Object.Cast(data[0].other);
  1193. if (targetEntity && targetEntity.IsTree())
  1194. {
  1195. SEffectManager.CreateParticleServer(targetEntity.GetPosition(), new TreeEffecterParameters("TreeEffecter", 1.0, 0.1));
  1196. }*/
  1197. //}
  1198. }
  1199. UpdateHeadlightState();
  1200. UpdateLights();
  1201. m_ContactCache.Clear();
  1202. }
  1203. //! Responsible for damaging crew in a car crash
  1204. void DamageCrew(float dmg)
  1205. {
  1206. for ( int c = 0; c < CrewSize(); ++c )
  1207. {
  1208. Human crew = CrewMember( c );
  1209. if ( !crew )
  1210. continue;
  1211. PlayerBase player;
  1212. if ( Class.CastTo(player, crew ) )
  1213. {
  1214. if ( dmg > GameConstants.CARS_CONTACT_DMG_KILLCREW )
  1215. {
  1216. #ifdef DIAG_DEVELOPER
  1217. CrashDebugData.m_CrashDataPoint.m_CrewDamageBase = dmg;
  1218. CrashDebugData.m_CrashDataPoint.m_DMGHealth = -100;
  1219. if (DEBUG_OUTPUT_TYPE & EVehicleDebugOutputType.DAMAGE_APPLIED)
  1220. {
  1221. Debug.Log("--------------------------------------------------");
  1222. Debug.Log("Killing the player");
  1223. Debug.Log("Crew DMG Base: " + dmg);
  1224. Debug.Log("--------------------------------------------------");
  1225. }
  1226. #endif
  1227. player.SetHealth(0.0);
  1228. }
  1229. else
  1230. {
  1231. float shockTemp = Math.InverseLerp(GameConstants.CARS_CONTACT_DMG_THRESHOLD, GameConstants.CARS_CONTACT_DMG_KILLCREW, dmg);
  1232. shockTemp = Math.Clamp(shockTemp,0,1);
  1233. float shock = Math.Lerp( 50, 150, shockTemp );
  1234. float hp = Math.Lerp( 2, 100, shockTemp );
  1235. #ifdef DIAG_DEVELOPER
  1236. CrashDebugData.m_CrashDataPoint.m_CrewDamageBase = dmg;
  1237. CrashDebugData.m_CrashDataPoint.m_ShockTemp = shockTemp;
  1238. CrashDebugData.m_CrashDataPoint.m_DMGHealth = hp;
  1239. CrashDebugData.m_CrashDataPoint.m_DMGShock = shock;
  1240. if (DEBUG_OUTPUT_TYPE & EVehicleDebugOutputType.DAMAGE_APPLIED)
  1241. {
  1242. Debug.Log("--------------------------------------------------");
  1243. Debug.Log("Crew DMG Base: " + dmg);
  1244. Debug.Log("Crew shockTemp: " + shockTemp);
  1245. Debug.Log("Crew DMG Health: " + hp);
  1246. Debug.Log("Crew DMG Shock: " + shock);
  1247. Debug.Log("--------------------------------------------------");
  1248. }
  1249. #endif
  1250. player.AddHealth("", "Shock", -shock );
  1251. player.AddHealth("", "Health", -hp );
  1252. }
  1253. }
  1254. }
  1255. }
  1256. /*!
  1257. Gets called every sound simulation step.
  1258. In this callback, user can modify behaviour of sound controllers
  1259. The higher the return value is the more muted sound is.
  1260. */
  1261. override float OnSound( CarSoundCtrl ctrl, float oldValue )
  1262. {
  1263. switch (ctrl)
  1264. {
  1265. case CarSoundCtrl.ENGINE:
  1266. if (!m_EngineStarted)
  1267. {
  1268. return 0.0;
  1269. }
  1270. break;
  1271. }
  1272. return oldValue;
  1273. }
  1274. override void OnAnimationPhaseStarted(string animSource, float phase)
  1275. {
  1276. #ifndef SERVER
  1277. HandleDoorsSound(animSource, phase);
  1278. HandleSeatAdjustmentSound(animSource, phase);
  1279. #endif
  1280. }
  1281. protected void HandleDoorsSound(string animSource, float phase)
  1282. {
  1283. switch (animSource)
  1284. {
  1285. case "doorsdriver":
  1286. case "doorscodriver":
  1287. case "doorscargo1":
  1288. case "doorscargo2":
  1289. case "doorshood":
  1290. case "doorstrunk":
  1291. EffectSound sound;
  1292. if (phase == 0)
  1293. sound = SEffectManager.PlaySound(m_CarDoorOpenSound, GetPosition());
  1294. else
  1295. sound = SEffectManager.PlaySound(m_CarDoorCloseSound, GetPosition());
  1296. if (sound)
  1297. sound.SetAutodestroy(true);
  1298. break;
  1299. }
  1300. }
  1301. protected void HandleSeatAdjustmentSound(string animSource, float phase)
  1302. {
  1303. switch (animSource)
  1304. {
  1305. case "seatdriver":
  1306. case "seatcodriver":
  1307. EffectSound sound;
  1308. if (phase == 0)
  1309. sound = SEffectManager.PlaySound(m_CarSeatShiftInSound, GetPosition());
  1310. else
  1311. sound = SEffectManager.PlaySound(m_CarSeatShiftOutSound, GetPosition());
  1312. if (sound)
  1313. sound.SetAutodestroy(true);
  1314. break;
  1315. }
  1316. }
  1317. protected void HandleCarHornSound(ECarHornState pState)
  1318. {
  1319. switch (pState)
  1320. {
  1321. case ECarHornState.SHORT:
  1322. PlaySoundSet(m_CarHornSoundEffect, m_CarHornShortSoundName, 0, 0, false);
  1323. break;
  1324. case ECarHornState.LONG:
  1325. PlaySoundSet(m_CarHornSoundEffect, m_CarHornLongSoundName, 0, 0, true);
  1326. break;
  1327. default:
  1328. CleanupSound(m_CarHornSoundEffect);
  1329. break;
  1330. }
  1331. }
  1332. void HandleEngineSound(CarEngineSoundState state)
  1333. {
  1334. #ifndef SERVER
  1335. PlayerBase player = null;
  1336. EffectSound sound = null;
  1337. WaveKind waveKind = WaveKind.WAVEEFFECT;
  1338. m_CarEngineLastSoundState = state;
  1339. switch (state)
  1340. {
  1341. case CarEngineSoundState.STARTING:
  1342. m_PreStartSound = SEffectManager.PlaySound("Offroad_02_Starting_SoundSet", ModelToWorld(GetEnginePos()));
  1343. m_PreStartSound.SetSoundFadeOut(0.15);
  1344. break;
  1345. case CarEngineSoundState.START_OK:
  1346. // play different sound based on selected camera
  1347. if (Class.CastTo(player, CrewMember(0)))
  1348. {
  1349. if (!player.IsCameraInsideVehicle())
  1350. {
  1351. waveKind = WaveKind.WAVEEFFECTEX;
  1352. }
  1353. sound = SEffectManager.CreateSound(m_EngineStartOK, ModelToWorld(GetEnginePos()));
  1354. if (sound)
  1355. {
  1356. sound.SetSoundWaveKind(waveKind);
  1357. sound.SoundPlay();
  1358. sound.SetAutodestroy(true);
  1359. }
  1360. }
  1361. //! postpone the engine sound played from c++ on soundcontroller (via OnSound override)
  1362. GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(SetEngineStarted, 1000, false, true);
  1363. break;
  1364. case CarEngineSoundState.START_NO_FUEL:
  1365. sound = SEffectManager.PlaySound("offroad_engine_failed_start_fuel_SoundSet", ModelToWorld(GetEnginePos()));
  1366. sound.SetAutodestroy(true);
  1367. break;
  1368. case CarEngineSoundState.START_NO_BATTERY:
  1369. sound = SEffectManager.PlaySound("offroad_engine_failed_start_battery_SoundSet", ModelToWorld(GetEnginePos()));
  1370. sound.SetAutodestroy(true);
  1371. break;
  1372. case CarEngineSoundState.START_NO_SPARKPLUG:
  1373. sound = SEffectManager.PlaySound("offroad_engine_failed_start_sparkplugs_SoundSet", ModelToWorld(GetEnginePos()));
  1374. sound.SetAutodestroy(true);
  1375. break;
  1376. case CarEngineSoundState.STOP_OK:
  1377. case CarEngineSoundState.STOP_NO_FUEL:
  1378. // play different sound based on selected camera
  1379. if (Class.CastTo(player, CrewMember(0)))
  1380. {
  1381. if (!player.IsCameraInsideVehicle())
  1382. {
  1383. waveKind = WaveKind.WAVEEFFECTEX;
  1384. }
  1385. sound = SEffectManager.CreateSound(m_EngineStopFuel, ModelToWorld(GetEnginePos()));
  1386. if (sound)
  1387. {
  1388. sound.SetSoundWaveKind(waveKind);
  1389. sound.SoundPlay();
  1390. sound.SetAutodestroy(true);
  1391. }
  1392. }
  1393. SetEngineStarted(false);
  1394. break;
  1395. default:
  1396. break;
  1397. }
  1398. #endif
  1399. }
  1400. override void HandleByCrewMemberState(ECrewMemberState state)
  1401. {
  1402. switch (state)
  1403. {
  1404. case ECrewMemberState.UNCONSCIOUS:
  1405. foreach (int unconsciousCrewMemberIndex : m_UnconsciousCrewMemberIndices)
  1406. {
  1407. if (unconsciousCrewMemberIndex == DayZPlayerConstants.VEHICLESEAT_DRIVER)
  1408. {
  1409. EngineStop();
  1410. SetBrake(0.5);
  1411. }
  1412. m_UnconsciousCrewMemberIndices.RemoveItem(unconsciousCrewMemberIndex);
  1413. }
  1414. break
  1415. case ECrewMemberState.DEAD:
  1416. foreach (int deadCrewMemberIndex : m_DeadCrewMemberIndices)
  1417. {
  1418. if (deadCrewMemberIndex == DayZPlayerConstants.VEHICLESEAT_DRIVER)
  1419. {
  1420. EngineStop();
  1421. SetBrake(0.5);
  1422. }
  1423. m_DeadCrewMemberIndices.RemoveItem(deadCrewMemberIndex);
  1424. }
  1425. break
  1426. }
  1427. }
  1428. //! DEPRECATED
  1429. float GetEnviroHeatComfortOverride();
  1430. /*!
  1431. Gets called everytime when the specified vehicle's fluid
  1432. changes its current value eg. when vehicle is consuming fuel.
  1433. This callback is called on server.
  1434. */
  1435. override void OnFluidChanged(CarFluid fluid, float newValue, float oldValue)
  1436. {
  1437. switch ( fluid )
  1438. {
  1439. case CarFluid.FUEL:
  1440. m_FuelAmmount = newValue;
  1441. break;
  1442. case CarFluid.OIL:
  1443. m_OilAmmount = newValue;
  1444. break;
  1445. case CarFluid.BRAKE:
  1446. m_BrakeAmmount = newValue;
  1447. break;
  1448. case CarFluid.COOLANT:
  1449. m_CoolantAmmount = newValue;
  1450. break;
  1451. }
  1452. }
  1453. /*!
  1454. Gets called everytime the game wants to start the engine.
  1455. This callback is called on server only.
  1456. \return true if the engine can start, false otherwise.
  1457. */
  1458. override bool OnBeforeEngineStart()
  1459. {
  1460. EntityAI item = null;
  1461. if (GetFluidFraction(CarFluid.FUEL) <= 0)
  1462. {
  1463. SetCarEngineSoundState(CarEngineSoundState.START_NO_FUEL);
  1464. return false;
  1465. }
  1466. if (IsVitalCarBattery() || IsVitalTruckBattery())
  1467. {
  1468. item = GetBattery();
  1469. if (!item || (item && (item.IsRuined() || item.GetCompEM().GetEnergy() < m_BatteryEnergyStartMin)))
  1470. {
  1471. SetCarEngineSoundState(CarEngineSoundState.START_NO_BATTERY);
  1472. return false;
  1473. }
  1474. }
  1475. if (IsVitalSparkPlug())
  1476. {
  1477. item = FindAttachmentBySlotName("SparkPlug");
  1478. if (!item || (item && item.IsRuined()))
  1479. {
  1480. SetCarEngineSoundState(CarEngineSoundState.START_NO_SPARKPLUG);
  1481. return false;
  1482. }
  1483. }
  1484. if (IsVitalGlowPlug())
  1485. {
  1486. item = FindAttachmentBySlotName("GlowPlug");
  1487. if (!item || (item && item.IsRuined()))
  1488. {
  1489. SetCarEngineSoundState(CarEngineSoundState.START_NO_SPARKPLUG);
  1490. return false;
  1491. }
  1492. }
  1493. SetCarEngineSoundState(CarEngineSoundState.STARTING);
  1494. return true;
  1495. }
  1496. override void OnGearChanged(int newGear, int oldGear)
  1497. {
  1498. //Debug.Log(string.Format("OnGearChanged newGear=%1,oldGear=%2", newGear, oldGear));
  1499. UpdateLights(newGear);
  1500. }
  1501. //! Gets called everytime the engine starts.
  1502. override void OnEngineStart()
  1503. {
  1504. ItemBase battery = GetBattery();
  1505. if (GetGame().IsServer() && battery)
  1506. {
  1507. battery.GetCompEM().ConsumeEnergy(GetBatteryConsumption());
  1508. }
  1509. UpdateLights();
  1510. HandleEngineSound(CarEngineSoundState.START_OK);
  1511. }
  1512. //! Gets called everytime the engine stops.
  1513. override void OnEngineStop()
  1514. {
  1515. UpdateLights();
  1516. HandleEngineSound(CarEngineSoundState.STOP_OK);
  1517. SetEngineZoneReceivedHit(false);
  1518. }
  1519. /*!
  1520. DEPRECATED Gets called everytime the game wants to switch the lights.
  1521. \return true when lights can be switched, false otherwise.
  1522. */
  1523. bool OnBeforeSwitchLights( bool toOn )
  1524. {
  1525. return true;
  1526. }
  1527. //! Propper way to get if light is swiched on. Use instead of IsLightsOn().
  1528. bool IsScriptedLightsOn()
  1529. {
  1530. return m_HeadlightsOn;
  1531. }
  1532. //! Switches headlights on/off, including the illumination of the control panel and synchronizes this change to all clients.
  1533. void ToggleHeadlights()
  1534. {
  1535. m_HeadlightsOn = !m_HeadlightsOn;
  1536. SetSynchDirty();
  1537. }
  1538. void UpdateLights(int new_gear = -1)
  1539. {
  1540. #ifndef SERVER
  1541. UpdateLightsClient(new_gear);
  1542. #endif
  1543. UpdateLightsServer(new_gear);
  1544. }
  1545. void UpdateLightsClient(int newGear = -1)
  1546. {
  1547. int gear;
  1548. if (newGear == -1)
  1549. {
  1550. gear = GetGear();
  1551. }
  1552. else
  1553. {
  1554. gear = newGear;
  1555. }
  1556. if (m_HeadlightsOn)
  1557. {
  1558. if (!m_Headlight && m_HeadlightsState != CarHeadlightBulbsState.NONE)
  1559. {
  1560. m_Headlight = CreateFrontLight();
  1561. }
  1562. if (m_Headlight)
  1563. {
  1564. switch (m_HeadlightsState)
  1565. {
  1566. case CarHeadlightBulbsState.LEFT:
  1567. m_Headlight.AttachOnMemoryPoint(this, m_LeftHeadlightPoint, m_LeftHeadlightTargetPoint);
  1568. m_Headlight.SegregateLight();
  1569. break;
  1570. case CarHeadlightBulbsState.RIGHT:
  1571. m_Headlight.AttachOnMemoryPoint(this, m_RightHeadlightPoint, m_RightHeadlightTargetPoint);
  1572. m_Headlight.SegregateLight();
  1573. break;
  1574. case CarHeadlightBulbsState.BOTH:
  1575. vector local_pos_left = GetMemoryPointPos(m_LeftHeadlightPoint);
  1576. vector local_pos_right = GetMemoryPointPos(m_RightHeadlightPoint);
  1577. vector local_pos_middle = (local_pos_left + local_pos_right) * 0.5;
  1578. m_Headlight.AttachOnObject(this, local_pos_middle);
  1579. m_Headlight.AggregateLight();
  1580. break;
  1581. default:
  1582. m_Headlight.FadeOut();
  1583. m_Headlight = null;
  1584. }
  1585. }
  1586. }
  1587. else
  1588. {
  1589. if (m_Headlight)
  1590. {
  1591. m_Headlight.FadeOut();
  1592. m_Headlight = null;
  1593. }
  1594. }
  1595. // brakes & reverse
  1596. switch (gear)
  1597. {
  1598. case CarGear.REVERSE:
  1599. case CarAutomaticGearboxMode.R:
  1600. if (m_BrakesArePressed)
  1601. m_RearLightType = CarRearLightType.BRAKES_AND_REVERSE;
  1602. else
  1603. m_RearLightType = CarRearLightType.REVERSE_ONLY;
  1604. break;
  1605. default:
  1606. if (m_BrakesArePressed)
  1607. m_RearLightType = CarRearLightType.BRAKES_ONLY;
  1608. else
  1609. m_RearLightType = CarRearLightType.NONE;
  1610. }
  1611. //Debug.Log(string.Format("m_BrakesArePressed=%1, m_RearLightType=%2", m_BrakesArePressed.ToString(), EnumTools.EnumToString(CarRearLightType, m_RearLightType)));
  1612. if (!m_RearLight && m_RearLightType != CarRearLightType.NONE && m_HeadlightsState != CarHeadlightBulbsState.NONE)
  1613. {
  1614. if (EngineIsOn() || m_RearLightType == CarRearLightType.BRAKES_ONLY || m_RearLightType == CarRearLightType.BRAKES_AND_REVERSE)
  1615. {
  1616. m_RearLight = CreateRearLight();
  1617. vector localPos = GetMemoryPointPos(m_ReverseLightPoint);
  1618. m_RearLight.AttachOnObject(this, localPos, "180 0 0");
  1619. }
  1620. }
  1621. // rear lights
  1622. if (m_RearLight && m_RearLightType != CarRearLightType.NONE && m_HeadlightsState != CarHeadlightBulbsState.NONE)
  1623. {
  1624. switch (m_RearLightType)
  1625. {
  1626. case CarRearLightType.BRAKES_ONLY:
  1627. BrakesRearLight();
  1628. break;
  1629. case CarRearLightType.REVERSE_ONLY:
  1630. if (EngineIsOn())
  1631. ReverseRearLight();
  1632. else
  1633. NoRearLight();
  1634. break;
  1635. case CarRearLightType.BRAKES_AND_REVERSE:
  1636. if (EngineIsOn())
  1637. BrakeAndReverseRearLight();
  1638. else
  1639. BrakesRearLight();
  1640. break;
  1641. default:
  1642. NoRearLight();
  1643. }
  1644. }
  1645. else
  1646. {
  1647. if (m_RearLight)
  1648. {
  1649. NoRearLight();
  1650. }
  1651. }
  1652. }
  1653. void UpdateLightsServer(int newGear = -1)
  1654. {
  1655. int gear;
  1656. if (newGear == -1)
  1657. {
  1658. gear = GetGear();
  1659. if (GearboxGetType() == CarGearboxType.AUTOMATIC)
  1660. {
  1661. gear = GearboxGetMode();
  1662. }
  1663. }
  1664. else
  1665. {
  1666. gear = newGear;
  1667. }
  1668. if (m_HeadlightsOn)
  1669. {
  1670. DashboardShineOn();
  1671. TailLightsShineOn();
  1672. switch (m_HeadlightsState)
  1673. {
  1674. case CarHeadlightBulbsState.LEFT:
  1675. LeftFrontLightShineOn();
  1676. RightFrontLightShineOff();
  1677. break;
  1678. case CarHeadlightBulbsState.RIGHT:
  1679. LeftFrontLightShineOff();
  1680. RightFrontLightShineOn();
  1681. break;
  1682. case CarHeadlightBulbsState.BOTH:
  1683. LeftFrontLightShineOn();
  1684. RightFrontLightShineOn();
  1685. break;
  1686. default:
  1687. LeftFrontLightShineOff();
  1688. RightFrontLightShineOff();
  1689. }
  1690. //Debug.Log(string.Format("m_HeadlightsOn=%1, m_HeadlightsState=%2", m_HeadlightsOn.ToString(), EnumTools.EnumToString(CarHeadlightBulbsState, m_HeadlightsState)));
  1691. }
  1692. else
  1693. {
  1694. TailLightsShineOff();
  1695. DashboardShineOff();
  1696. LeftFrontLightShineOff();
  1697. RightFrontLightShineOff();
  1698. }
  1699. // brakes & reverse
  1700. switch (gear)
  1701. {
  1702. case CarGear.REVERSE:
  1703. case CarAutomaticGearboxMode.R:
  1704. if (m_BrakesArePressed)
  1705. m_RearLightType = CarRearLightType.BRAKES_AND_REVERSE;
  1706. else
  1707. m_RearLightType = CarRearLightType.REVERSE_ONLY;
  1708. break;
  1709. default:
  1710. if (m_BrakesArePressed)
  1711. m_RearLightType = CarRearLightType.BRAKES_ONLY;
  1712. else
  1713. m_RearLightType = CarRearLightType.NONE;
  1714. }
  1715. //Debug.Log(string.Format("m_BrakesArePressed=%1, m_RearLightType=%2", m_BrakesArePressed.ToString(), EnumTools.EnumToString(CarRearLightType, m_RearLightType)));
  1716. // rear lights
  1717. if (m_RearLightType != CarRearLightType.NONE && m_HeadlightsState != CarHeadlightBulbsState.NONE)
  1718. {
  1719. switch (m_RearLightType)
  1720. {
  1721. case CarRearLightType.BRAKES_ONLY:
  1722. ReverseLightsShineOff();
  1723. BrakeLightsShineOn();
  1724. break;
  1725. case CarRearLightType.REVERSE_ONLY:
  1726. if (EngineIsOn())
  1727. {
  1728. ReverseLightsShineOn();
  1729. BrakeLightsShineOff();
  1730. }
  1731. else
  1732. {
  1733. ReverseLightsShineOff();
  1734. BrakeLightsShineOff();
  1735. }
  1736. break;
  1737. case CarRearLightType.BRAKES_AND_REVERSE:
  1738. if (EngineIsOn())
  1739. {
  1740. BrakeLightsShineOn();
  1741. ReverseLightsShineOn();
  1742. }
  1743. else
  1744. {
  1745. ReverseLightsShineOff();
  1746. BrakeLightsShineOn();
  1747. }
  1748. break;
  1749. default:
  1750. ReverseLightsShineOff();
  1751. BrakeLightsShineOff();
  1752. }
  1753. }
  1754. else
  1755. {
  1756. ReverseLightsShineOff();
  1757. BrakeLightsShineOff();
  1758. }
  1759. }
  1760. protected void BrakesRearLight()
  1761. {
  1762. m_RearLight.SetAsSegregatedBrakeLight();
  1763. }
  1764. protected void ReverseRearLight()
  1765. {
  1766. m_RearLight.SetAsSegregatedReverseLight();
  1767. }
  1768. protected void BrakeAndReverseRearLight()
  1769. {
  1770. m_RearLight.AggregateLight();
  1771. m_RearLight.SetFadeOutTime(1);
  1772. }
  1773. protected void NoRearLight()
  1774. {
  1775. m_RearLight.FadeOut();
  1776. m_RearLight = null;
  1777. }
  1778. protected void LeftFrontLightShineOn()
  1779. {
  1780. string material = ConfigGetString("frontReflectorMatOn");
  1781. if (material)
  1782. {
  1783. SetObjectMaterial(SELECTION_ID_FRONT_LIGHT_L, material);
  1784. }
  1785. }
  1786. protected void RightFrontLightShineOn()
  1787. {
  1788. string material = ConfigGetString("frontReflectorMatOn");
  1789. if (material)
  1790. {
  1791. SetObjectMaterial(SELECTION_ID_FRONT_LIGHT_R, material);
  1792. }
  1793. }
  1794. protected void LeftFrontLightShineOff()
  1795. {
  1796. string material = ConfigGetString("frontReflectorMatOff");
  1797. if (material)
  1798. {
  1799. SetObjectMaterial(SELECTION_ID_FRONT_LIGHT_L, material);
  1800. }
  1801. }
  1802. protected void RightFrontLightShineOff()
  1803. {
  1804. string material = ConfigGetString("frontReflectorMatOff");
  1805. if (material)
  1806. {
  1807. SetObjectMaterial(SELECTION_ID_FRONT_LIGHT_R, material);
  1808. }
  1809. }
  1810. protected void ReverseLightsShineOn()
  1811. {
  1812. string material = ConfigGetString("ReverseReflectorMatOn");
  1813. if (material)
  1814. {
  1815. SetObjectMaterial(SELECTION_ID_REVERSE_LIGHT_L, material);
  1816. SetObjectMaterial(SELECTION_ID_REVERSE_LIGHT_R, material);
  1817. }
  1818. }
  1819. protected void ReverseLightsShineOff()
  1820. {
  1821. string material = ConfigGetString("ReverseReflectorMatOff");
  1822. if (material)
  1823. {
  1824. SetObjectMaterial(SELECTION_ID_REVERSE_LIGHT_L, material);
  1825. SetObjectMaterial(SELECTION_ID_REVERSE_LIGHT_R, material);
  1826. }
  1827. }
  1828. protected void BrakeLightsShineOn()
  1829. {
  1830. string material = ConfigGetString("brakeReflectorMatOn");
  1831. if (material)
  1832. {
  1833. SetObjectMaterial(SELECTION_ID_BRAKE_LIGHT_L, material);
  1834. SetObjectMaterial(SELECTION_ID_BRAKE_LIGHT_R, material);
  1835. }
  1836. }
  1837. protected void BrakeLightsShineOff()
  1838. {
  1839. string material = ConfigGetString("brakeReflectorMatOff");
  1840. if (material)
  1841. {
  1842. SetObjectMaterial(SELECTION_ID_BRAKE_LIGHT_L, material);
  1843. SetObjectMaterial(SELECTION_ID_BRAKE_LIGHT_R, material);
  1844. }
  1845. }
  1846. protected void TailLightsShineOn()
  1847. {
  1848. string material = ConfigGetString("TailReflectorMatOn");
  1849. string materialOff = ConfigGetString("TailReflectorMatOff");
  1850. if (material && materialOff)
  1851. {
  1852. if (m_HeadlightsState == CarHeadlightBulbsState.LEFT)
  1853. {
  1854. SetObjectMaterial(SELECTION_ID_TAIL_LIGHT_L, material);
  1855. SetObjectMaterial(SELECTION_ID_TAIL_LIGHT_R, materialOff);
  1856. }
  1857. else if (m_HeadlightsState == CarHeadlightBulbsState.RIGHT)
  1858. {
  1859. SetObjectMaterial(SELECTION_ID_TAIL_LIGHT_L, materialOff);
  1860. SetObjectMaterial(SELECTION_ID_TAIL_LIGHT_R, material);
  1861. }
  1862. else if (m_HeadlightsState == CarHeadlightBulbsState.BOTH)
  1863. {
  1864. SetObjectMaterial(SELECTION_ID_TAIL_LIGHT_L, material);
  1865. SetObjectMaterial(SELECTION_ID_TAIL_LIGHT_R, material);
  1866. }
  1867. }
  1868. }
  1869. protected void TailLightsShineOff()
  1870. {
  1871. string material = ConfigGetString("TailReflectorMatOff");
  1872. if (material)
  1873. {
  1874. SetObjectMaterial(SELECTION_ID_TAIL_LIGHT_L, material);
  1875. SetObjectMaterial(SELECTION_ID_TAIL_LIGHT_R, material);
  1876. }
  1877. }
  1878. protected void DashboardShineOn()
  1879. {
  1880. string material = ConfigGetString("dashboardMatOn");
  1881. if (material)
  1882. {
  1883. SetObjectMaterial(SELECTION_ID_DASHBOARD_LIGHT, material);
  1884. }
  1885. }
  1886. protected void DashboardShineOff()
  1887. {
  1888. string material = ConfigGetString("dashboardMatOff");
  1889. if (material)
  1890. {
  1891. SetObjectMaterial(SELECTION_ID_DASHBOARD_LIGHT, material);
  1892. }
  1893. }
  1894. // Override this for a car-specific light type
  1895. protected CarRearLightBase CreateRearLight()
  1896. {
  1897. return CarRearLightBase.Cast(ScriptedLightBase.CreateLight(OffroadHatchbackFrontLight));
  1898. }
  1899. // Override this for a car-specific light type
  1900. protected CarLightBase CreateFrontLight()
  1901. {
  1902. return CarLightBase.Cast(ScriptedLightBase.CreateLight(OffroadHatchbackFrontLight));
  1903. }
  1904. protected void CheckVitalItem( bool isVital, string itemName )
  1905. {
  1906. if ( !isVital )
  1907. return;
  1908. EntityAI item = FindAttachmentBySlotName(itemName);
  1909. if ( !item )
  1910. EngineStop();
  1911. else if ( item.IsRuined() )
  1912. EngineStop();
  1913. }
  1914. protected void LeakFluid(CarFluid fluid)
  1915. {
  1916. float ammount = 0;
  1917. switch (fluid)
  1918. {
  1919. case CarFluid.COOLANT:
  1920. ammount = (1- m_RadiatorHealth) * Math.RandomFloat(0.02, 0.05);//CARS_LEAK_TICK_MIN; CARS_LEAK_TICK_MAX
  1921. Leak(fluid, ammount);
  1922. break;
  1923. case CarFluid.OIL:
  1924. ammount = ( 1 - m_EngineHealth ) * Math.RandomFloat(0.02, 1.0);//CARS_LEAK_OIL_MIN; CARS_LEAK_OIL_MAX
  1925. Leak(fluid, ammount);
  1926. break;
  1927. case CarFluid.FUEL:
  1928. ammount = ( 1 - m_FuelTankHealth ) * Math.RandomFloat(0.02, 0.05);//CARS_LEAK_TICK_MIN; CARS_LEAK_TICK_MAX
  1929. Leak(fluid, ammount);
  1930. break;
  1931. }
  1932. }
  1933. protected void CarPartsHealthCheck()
  1934. {
  1935. if (GetGame().IsServer())
  1936. {
  1937. if (HasRadiator())
  1938. {
  1939. m_RadiatorHealth = GetRadiator().GetHealth01("", "");
  1940. }
  1941. else
  1942. {
  1943. m_RadiatorHealth = 0;
  1944. }
  1945. m_EngineHealth = GetHealth01("Engine", "");
  1946. m_FuelTankHealth = GetHealth01("FuelTank", "");
  1947. }
  1948. }
  1949. bool GetCrashLightSound()
  1950. {
  1951. return m_PlayCrashSoundLight;
  1952. }
  1953. void SynchCrashLightSound(bool play)
  1954. {
  1955. if (m_PlayCrashSoundLight != play)
  1956. {
  1957. m_PlayCrashSoundLight = play;
  1958. SetSynchDirty();
  1959. }
  1960. }
  1961. void PlayCrashLightSound()
  1962. {
  1963. PlaySoundEx("offroad_hit_light_SoundSet", m_CrashSoundLight, m_PlayCrashSoundLight);
  1964. }
  1965. bool GetCrashHeavySound()
  1966. {
  1967. return m_PlayCrashSoundHeavy;
  1968. }
  1969. void SynchCrashHeavySound(bool play)
  1970. {
  1971. if (m_PlayCrashSoundHeavy != play)
  1972. {
  1973. m_PlayCrashSoundHeavy = play;
  1974. SetSynchDirty();
  1975. }
  1976. }
  1977. void PlayCrashHeavySound()
  1978. {
  1979. PlaySoundEx("offroad_hit_heavy_SoundSet", m_CrashSoundHeavy, m_PlayCrashSoundHeavy);
  1980. }
  1981. void PlaySoundEx(string soundset, EffectSound sound, out bool soundbool)
  1982. {
  1983. #ifndef SERVER
  1984. if (!sound)
  1985. {
  1986. sound = SEffectManager.PlaySoundCachedParams(soundset, GetPosition());
  1987. if( sound )
  1988. {
  1989. sound.SetAutodestroy(true);
  1990. }
  1991. }
  1992. else
  1993. {
  1994. if (!sound.IsSoundPlaying())
  1995. {
  1996. sound.SetPosition(GetPosition());
  1997. sound.SoundPlay();
  1998. }
  1999. }
  2000. soundbool = false;
  2001. #endif
  2002. }
  2003. void PlaySound(string soundset, ref EffectSound sound, out bool soundbool)
  2004. {
  2005. PlaySoundEx(soundset, sound, soundbool);
  2006. }
  2007. string GetAnimSourceFromSelection( string selection )
  2008. {
  2009. return "";
  2010. }
  2011. string GetDoorConditionPointFromSelection( string selection )
  2012. {
  2013. switch( selection )
  2014. {
  2015. case "seat_driver":
  2016. return "seat_con_1_1";
  2017. break;
  2018. case "seat_codriver":
  2019. return "seat_con_2_1";
  2020. break;
  2021. case "seat_cargo1":
  2022. return "seat_con_1_2";
  2023. break;
  2024. case "seat_cargo2":
  2025. return "seat_con_2_2";
  2026. break;
  2027. }
  2028. return "";
  2029. }
  2030. string GetDoorSelectionNameFromSeatPos(int posIdx)
  2031. {
  2032. return "";
  2033. }
  2034. string GetDoorInvSlotNameFromSeatPos(int posIdx)
  2035. {
  2036. return "";
  2037. }
  2038. int GetCrewIndex( string selection )
  2039. {
  2040. return -1;
  2041. }
  2042. override bool CanReachSeatFromDoors( string pSeatSelection, vector pFromPos, float pDistance = 1.0 )
  2043. {
  2044. string conPointName = GetDoorConditionPointFromSelection(pSeatSelection);
  2045. if (conPointName.Length() > 0)
  2046. {
  2047. if ( MemoryPointExists(conPointName) )
  2048. {
  2049. vector conPointMS = GetMemoryPointPos(conPointName);
  2050. vector conPointWS = ModelToWorld(conPointMS);
  2051. //! skip the height for now
  2052. conPointWS[1] = 0;
  2053. pFromPos[1] = 0;
  2054. if (vector.Distance(pFromPos, conPointWS) <= pDistance)
  2055. {
  2056. return true;
  2057. }
  2058. }
  2059. }
  2060. return false;
  2061. }
  2062. bool IsVitalCarBattery()
  2063. {
  2064. return true;
  2065. }
  2066. bool IsVitalTruckBattery()
  2067. {
  2068. return true;
  2069. }
  2070. bool IsVitalGlowPlug()
  2071. {
  2072. return true;
  2073. }
  2074. bool IsVitalEngineBelt()
  2075. {
  2076. return true;
  2077. }
  2078. bool IsVitalRadiator()
  2079. {
  2080. return true;
  2081. }
  2082. bool IsVitalFuelTank()
  2083. {
  2084. return true;
  2085. }
  2086. bool HasRadiator()
  2087. {
  2088. return m_Radiator != null;
  2089. }
  2090. EntityAI GetRadiator()
  2091. {
  2092. return m_Radiator;
  2093. }
  2094. bool IsMoving()
  2095. {
  2096. return GetSpeedometerAbsolute() > 3.5;
  2097. }
  2098. bool IsHandbrakeActive()
  2099. {
  2100. return GetHandbrake() > 0.0;
  2101. }
  2102. //! camera type
  2103. override int Get3rdPersonCameraType()
  2104. {
  2105. return DayZPlayerCameras.DAYZCAMERA_3RD_VEHICLE;
  2106. }
  2107. void SetEngineStarted(bool started)
  2108. {
  2109. m_EngineStarted = started;
  2110. }
  2111. int GetCarDoorsState(string slotType)
  2112. {
  2113. return -1;
  2114. }
  2115. CarDoorState TranslateAnimationPhaseToCarDoorState(string animation)
  2116. {
  2117. if (GetAnimationPhase(animation) > 0.5)
  2118. {
  2119. return CarDoorState.DOORS_OPEN;
  2120. }
  2121. else
  2122. {
  2123. return CarDoorState.DOORS_CLOSED;
  2124. }
  2125. }
  2126. string GetActionCompNameCoolant()
  2127. {
  2128. return "radiator";
  2129. }
  2130. float GetActionDistanceCoolant()
  2131. {
  2132. return 2.0;
  2133. }
  2134. string GetActionCompNameOil()
  2135. {
  2136. return "carradiator";
  2137. }
  2138. float GetActionDistanceOil()
  2139. {
  2140. return 2.0;
  2141. }
  2142. string GetActionCompNameBrakes()
  2143. {
  2144. return "carradiator";
  2145. }
  2146. float GetActionDistanceBrakes()
  2147. {
  2148. return 2.0;
  2149. }
  2150. override bool CanPutIntoHands(EntityAI parent)
  2151. {
  2152. return false;
  2153. }
  2154. void InitializeActions()
  2155. {
  2156. m_InputActionMap = m_CarTypeActionsMap.Get( this.Type() );
  2157. if (!m_InputActionMap)
  2158. {
  2159. TInputActionMap iam = new TInputActionMap;
  2160. m_InputActionMap = iam;
  2161. SetActions();
  2162. m_CarTypeActionsMap.Insert(this.Type(), m_InputActionMap);
  2163. }
  2164. }
  2165. override void GetActions(typename action_input_type, out array<ActionBase_Basic> actions)
  2166. {
  2167. if (!m_ActionsInitialize)
  2168. {
  2169. m_ActionsInitialize = true;
  2170. InitializeActions();
  2171. }
  2172. actions = m_InputActionMap.Get(action_input_type);
  2173. }
  2174. void SetActions()
  2175. {
  2176. AddAction(ActionOpenCarDoorsOutside);
  2177. AddAction(ActionCloseCarDoorsOutside);
  2178. AddAction(ActionGetInTransport);
  2179. AddAction(ActionSwitchLights);
  2180. AddAction(ActionCarHornShort);
  2181. AddAction(ActionCarHornLong);
  2182. AddAction(ActionPushCar);
  2183. }
  2184. void AddAction(typename actionName)
  2185. {
  2186. ActionBase action = ActionManagerBase.GetAction(actionName);
  2187. if (!action)
  2188. {
  2189. Debug.LogError("Action " + actionName + " dosn't exist!");
  2190. return;
  2191. }
  2192. typename ai = action.GetInputType();
  2193. if (!ai)
  2194. {
  2195. m_ActionsInitialize = false;
  2196. return;
  2197. }
  2198. array<ActionBase_Basic> action_array = m_InputActionMap.Get(ai);
  2199. if (!action_array)
  2200. {
  2201. action_array = new array<ActionBase_Basic>;
  2202. m_InputActionMap.Insert(ai, action_array);
  2203. }
  2204. if ( LogManager.IsActionLogEnable() )
  2205. {
  2206. Debug.ActionLog(action.ToString() + " -> " + ai, this.ToString() , "n/a", "Add action" );
  2207. }
  2208. action_array.Insert(action);
  2209. }
  2210. void RemoveAction(typename actionName)
  2211. {
  2212. PlayerBase player = PlayerBase.Cast(GetGame().GetPlayer());
  2213. ActionBase action = player.GetActionManager().GetAction(actionName);
  2214. typename ai = action.GetInputType();
  2215. array<ActionBase_Basic> action_array = m_InputActionMap.Get(ai);
  2216. if (action_array)
  2217. {
  2218. action_array.RemoveItem(action);
  2219. }
  2220. }
  2221. override bool IsInventoryVisible()
  2222. {
  2223. return ( GetGame().GetPlayer() && ( !GetGame().GetPlayer().GetCommand_Vehicle() || GetGame().GetPlayer().GetCommand_Vehicle().GetTransport() == this ) );
  2224. }
  2225. override void EEHealthLevelChanged(int oldLevel, int newLevel, string zone)
  2226. {
  2227. super.EEHealthLevelChanged(oldLevel,newLevel,zone);
  2228. if (newLevel == GameConstants.STATE_RUINED && oldLevel != newLevel)
  2229. {
  2230. bool dummy;
  2231. switch ( zone )
  2232. {
  2233. case "WindowLR":
  2234. case "WindowRR":
  2235. if (m_Initialized)
  2236. {
  2237. PlaySoundEx("offroad_hit_window_small_SoundSet", m_WindowSmall, dummy);
  2238. }
  2239. break;
  2240. case "WindowFront":
  2241. case "WindowBack":
  2242. case "WindowFrontLeft":
  2243. case "WindowFrontRight":
  2244. if (m_Initialized)
  2245. {
  2246. PlaySoundEx("offroad_hit_window_large_SoundSet", m_WindowLarge, dummy);
  2247. }
  2248. break;
  2249. case "Engine":
  2250. #ifndef SERVER
  2251. CreateCarDestroyedEffect();
  2252. #endif
  2253. break;
  2254. }
  2255. }
  2256. }
  2257. override void EEOnCECreate()
  2258. {
  2259. float maxVolume = GetFluidCapacity( CarFluid.FUEL );
  2260. float amount = Math.RandomFloat(0.0, maxVolume * 0.35 );
  2261. Fill( CarFluid.FUEL, amount );
  2262. }
  2263. /*override void EOnPostFrame(IEntity other, int extra)
  2264. {
  2265. //Prepared for fix particle simulation when player is not in vehicle
  2266. }*/
  2267. void ForceUpdateLightsStart()
  2268. {
  2269. if (!m_ForceUpdateLights)
  2270. {
  2271. m_ForceUpdateLights = true;
  2272. SetSynchDirty();
  2273. }
  2274. }
  2275. void ForceUpdateLightsEnd()
  2276. {
  2277. if (m_ForceUpdateLights)
  2278. {
  2279. m_ForceUpdateLights = false;
  2280. SetSynchDirty();
  2281. }
  2282. }
  2283. //Get the engine start battery consumption
  2284. float GetBatteryConsumption()
  2285. {
  2286. return m_BatteryConsume;
  2287. }
  2288. float GetBatteryRuntimeConsumption()
  2289. {
  2290. return m_BatteryContinuousConsume;
  2291. }
  2292. float GetBatteryRechargeRate()
  2293. {
  2294. return -m_BatteryRecharge;
  2295. }
  2296. ItemBase GetBattery()
  2297. {
  2298. if (IsVitalCarBattery())
  2299. {
  2300. return ItemBase.Cast(FindAttachmentBySlotName("CarBattery"));
  2301. }
  2302. else if (IsVitalTruckBattery())
  2303. {
  2304. return ItemBase.Cast(FindAttachmentBySlotName("TruckBattery"));
  2305. }
  2306. return null;
  2307. }
  2308. void SetCarHornState(int pState)
  2309. {
  2310. m_CarHornState = pState;
  2311. SetSynchDirty();
  2312. if (GetGame().IsServer())
  2313. {
  2314. GenerateCarHornAINoise(pState);
  2315. }
  2316. }
  2317. // Only used for sound states which happen before engine start
  2318. void SetCarEngineSoundState(CarEngineSoundState pState)
  2319. {
  2320. m_CarEngineSoundState = pState;
  2321. SetSynchDirty();
  2322. }
  2323. protected void GenerateCarHornAINoise(int pState)
  2324. {
  2325. if (pState != ECarHornState.OFF)
  2326. {
  2327. if (m_NoiseSystem && m_NoisePar)
  2328. {
  2329. float noiseMultiplier = 1.0;
  2330. if (pState == ECarHornState.LONG)
  2331. noiseMultiplier = 2.0;
  2332. noiseMultiplier *= NoiseAIEvaluate.GetNoiseReduction(GetGame().GetWeather());
  2333. m_NoiseSystem.AddNoiseTarget(GetPosition(), 5, m_NoisePar, noiseMultiplier);
  2334. }
  2335. }
  2336. }
  2337. override vector GetDefaultHitPosition()
  2338. {
  2339. return vector.Zero;
  2340. }
  2341. float GetPushForceCoefficientMultiplier()
  2342. {
  2343. return 1.0;
  2344. }
  2345. #ifdef DEVELOPER
  2346. override protected string GetDebugText()
  2347. {
  2348. string debug_output = super.GetDebugText();
  2349. if (GetGame().IsServer())
  2350. {
  2351. debug_output += m_DebugContactDamageMessage + "\n";
  2352. }
  2353. debug_output += "Entity momentum: " + GetMomentum();
  2354. return debug_output;
  2355. }
  2356. #endif
  2357. protected void SpawnUniversalParts()
  2358. {
  2359. GetInventory().CreateInInventory("HeadlightH7");
  2360. GetInventory().CreateInInventory("HeadlightH7");
  2361. GetInventory().CreateInInventory("HeadlightH7");
  2362. GetInventory().CreateInInventory("HeadlightH7");
  2363. if (IsVitalCarBattery())
  2364. {
  2365. GetInventory().CreateInInventory("CarBattery");
  2366. GetInventory().CreateInInventory("CarBattery");
  2367. }
  2368. if (IsVitalTruckBattery())
  2369. {
  2370. GetInventory().CreateInInventory("TruckBattery");
  2371. GetInventory().CreateInInventory("TruckBattery");
  2372. }
  2373. if (IsVitalRadiator())
  2374. {
  2375. GetInventory().CreateInInventory("CarRadiator");
  2376. GetInventory().CreateInInventory("CarRadiator");
  2377. }
  2378. if (IsVitalSparkPlug())
  2379. {
  2380. GetInventory().CreateInInventory("SparkPlug");
  2381. GetInventory().CreateInInventory("SparkPlug");
  2382. }
  2383. if (IsVitalGlowPlug())
  2384. {
  2385. GetInventory().CreateInInventory("GlowPlug");
  2386. GetInventory().CreateInInventory("GlowPlug");
  2387. }
  2388. }
  2389. protected void SpawnAdditionalItems()
  2390. {
  2391. GetInventory().CreateInInventory("Wrench");
  2392. GetInventory().CreateInInventory("LugWrench");
  2393. GetInventory().CreateInInventory("Screwdriver");
  2394. GetInventory().CreateInInventory("EpoxyPutty");
  2395. GetInventory().CreateInInventory("CanisterGasoline");
  2396. EntityAI ent;
  2397. ItemBase container;
  2398. ent = GetInventory().CreateInInventory("CanisterGasoline");
  2399. if (Class.CastTo(container, ent))
  2400. {
  2401. container.SetLiquidType(LIQUID_WATER, true);
  2402. }
  2403. ent = GetInventory().CreateInInventory("Blowtorch");
  2404. if (ent)
  2405. {
  2406. ent.GetInventory().CreateInInventory("LargeGasCanister");
  2407. }
  2408. ent = GetInventory().CreateInInventory("Blowtorch");
  2409. if (ent)
  2410. {
  2411. ent.GetInventory().CreateInInventory("LargeGasCanister");
  2412. }
  2413. }
  2414. protected void FillUpCarFluids()
  2415. {
  2416. Fill(CarFluid.FUEL, 200.0);
  2417. Fill(CarFluid.COOLANT, 200.0);
  2418. Fill(CarFluid.OIL, 200.0);
  2419. }
  2420. }