carscript.c 75 KB

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