environment.c 56 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735
  1. enum EEnvironmentHeatcomfortBehaviorCategory
  2. {
  3. DEFAULT,
  4. CAR_ENGINE_ON
  5. }
  6. class EnvironmentSnapshotData
  7. {
  8. float m_TargetHeatComfort = 0.0;
  9. }
  10. class Environment
  11. {
  12. const float RAIN_LIMIT_LOW = 0.05;
  13. protected const float SNOWFALL_LIMIT_LOW = 0.5;
  14. protected const float SNOWFALL_WIND_COMBINED_THRESHOLD = 1.3;
  15. const float WATER_LEVEL_HIGH = 1.5;
  16. const float WATER_LEVEL_MID = 1.2;
  17. const float WATER_LEVEL_LOW = 0.5;
  18. const float WATER_LEVEL_NONE = 0.15;
  19. protected float m_WetDryTick; //ticks passed since last clothing wetting or drying
  20. protected float m_ItemsWetnessMax; //! keeps wetness of most wet item in player's possesion
  21. protected float m_RoofCheckTimer; // keeps info about tick time
  22. //player
  23. protected PlayerBase m_Player;
  24. protected float m_PlayerHeightPos; // y position of player above water level (meters)
  25. protected float m_PlayerSpeed; // 1-3 speed of player movement
  26. protected float m_PlayerTemperature; //34-44
  27. protected float m_PlayerHeat; //3-9 heatcomfort generated by entites movement
  28. protected float m_HeatComfort; //! player's heatcomfort (buffered, stored in player stats)
  29. protected float m_TargetHeatComfort; //! target value of heatcomfort (non-buffered)
  30. //environment
  31. protected float m_Rain = 0; // 0-1 amount of rain
  32. protected float m_Snowfall = 0; // 0-1 amount of rain
  33. protected float m_Wind = 0; // strength of wind
  34. protected float m_Fog = 0; // 0-1 how foggy it is
  35. protected float m_DayOrNight = 0; // 0-1 day(0) or night(1)
  36. protected float m_Clouds = 0; // 0-1 how cloudy it is
  37. protected float m_EnvironmentTemperature; //temperature of environment player is in
  38. protected float m_Time = 0;
  39. protected string m_SurfaceType;
  40. protected int m_LiquidType;
  41. //item temperatures
  42. protected float m_ItemTemperatureCoef;
  43. //
  44. protected float m_WaterLevel;
  45. protected bool m_IsUnderRoof;
  46. private bool m_IsUnderRoofBuilding;
  47. protected bool m_IsInWater;
  48. protected bool m_IsTempSet;
  49. //
  50. protected float m_HeatBufferTimer; //! reused as state toggle
  51. protected ref array<int> m_SlotIdsComplete;
  52. protected ref array<int> m_SlotIdsUpper;
  53. protected ref array<int> m_SlotIdsBottom;
  54. protected ref array<int> m_SlotIdsLower;
  55. protected ref array<int> m_HeadParts;
  56. protected ref array<int> m_BodyParts;
  57. protected ref array<int> m_FeetParts;
  58. protected ref WorldData m_WorldData;
  59. protected bool m_HasTemperatureSources;
  60. protected float m_UTSAverageTemperature;
  61. protected ref array<UTemperatureSource> m_UTemperatureSources;
  62. protected ref SimpleMovingAverage<float> m_UTSAverageTemperatureBuffer;
  63. protected ref SimpleMovingAverage<float> m_AverageHeatComfortBuffer;
  64. protected int m_HeatComfortBehaviorCategory;
  65. protected ref EnvironmentSnapshotData m_EnvironmentSnapshot; //! used for calculations before the data modification
  66. private bool m_Initialized;
  67. #ifdef DIAG_DEVELOPER
  68. bool m_Debug = false;
  69. bool m_DebugLogDryWet = false;
  70. bool m_DebugLogItemHeat = false;
  71. #endif
  72. void Environment(PlayerBase pPlayer)
  73. {
  74. m_Player = pPlayer;
  75. }
  76. void Init()
  77. {
  78. m_PlayerSpeed = 0.0;
  79. m_WetDryTick = 0.0;
  80. m_RoofCheckTimer = 0.0;
  81. m_WaterLevel = 0.0;
  82. m_HeatComfort = m_Player.GetStatHeatComfort().Get();
  83. m_WorldData = g_Game.GetMission().GetWorldData();
  84. m_EnvironmentTemperature = m_WorldData.GetBaseEnvTemperatureAtObject(m_Player);
  85. m_IsUnderRoof = false;
  86. m_IsInWater = false;
  87. m_SurfaceType = "cp_dirt";
  88. m_HeatBufferTimer = 0.0;
  89. m_UTSAverageTemperature = 0.0;
  90. m_UTemperatureSources = new array<UTemperatureSource>();
  91. m_UTSAverageTemperatureBuffer = new SimpleMovingAverage<float>(10, 0.0);
  92. m_AverageHeatComfortBuffer = new SimpleMovingAverage<float>(20, m_HeatComfort);
  93. //! whole body slots
  94. m_SlotIdsComplete = new array<int>();
  95. m_SlotIdsComplete = {
  96. InventorySlots.HEADGEAR,
  97. InventorySlots.MASK,
  98. InventorySlots.EYEWEAR,
  99. InventorySlots.GLOVES,
  100. InventorySlots.ARMBAND,
  101. InventorySlots.BODY,
  102. InventorySlots.HIPS,
  103. InventorySlots.VEST,
  104. InventorySlots.BACK,
  105. InventorySlots.LEGS,
  106. InventorySlots.FEET
  107. };
  108. //! upper body part slots
  109. m_SlotIdsUpper = new array<int>();
  110. m_SlotIdsUpper = {
  111. InventorySlots.GLOVES,
  112. InventorySlots.ARMBAND,
  113. InventorySlots.BODY,
  114. InventorySlots.HIPS,
  115. InventorySlots.VEST,
  116. InventorySlots.BACK,
  117. InventorySlots.LEGS,
  118. InventorySlots.FEET
  119. };
  120. //! bottom body part slots
  121. m_SlotIdsBottom = new array<int>();
  122. m_SlotIdsBottom = {
  123. InventorySlots.HIPS,
  124. InventorySlots.LEGS,
  125. InventorySlots.FEET
  126. };
  127. //! lower body part slots
  128. m_SlotIdsLower = new array<int>();
  129. m_SlotIdsLower = {
  130. InventorySlots.FEET,
  131. };
  132. //! --------------------------
  133. //! heat comfort related slots
  134. m_HeadParts = new array<int>();
  135. m_HeadParts = {
  136. InventorySlots.HEADGEAR,
  137. InventorySlots.MASK,
  138. };
  139. m_BodyParts = new array<int>();
  140. m_BodyParts = {
  141. InventorySlots.GLOVES,
  142. InventorySlots.HIPS,
  143. InventorySlots.BODY,
  144. InventorySlots.BACK,
  145. InventorySlots.VEST,
  146. InventorySlots.MELEE,
  147. InventorySlots.SHOULDER
  148. };
  149. m_FeetParts = new array<int>();
  150. m_FeetParts = {
  151. InventorySlots.LEGS,
  152. InventorySlots.FEET,
  153. };
  154. m_HeatComfortBehaviorCategory = EEnvironmentHeatcomfortBehaviorCategory.DEFAULT;
  155. SetEnvironmentSnapshotData();
  156. m_Initialized = true;
  157. }
  158. // Calculates heatisolation of clothing, process its wetness, collects heat from heated items and calculates player's heat comfort
  159. void Update(float pDelta)
  160. {
  161. if (m_Player && m_Initialized)
  162. {
  163. m_RoofCheckTimer += pDelta;
  164. //! check if player is under roof (only if the Building check is false)
  165. if ( m_RoofCheckTimer >= GameConstants.ENVIRO_TICK_ROOF_RC_CHECK )
  166. {
  167. if ( !IsInsideBuilding() )
  168. CheckUnderRoof();
  169. m_RoofCheckTimer = 0;
  170. }
  171. m_Time += pDelta;
  172. if (m_Time >= GameConstants.ENVIRO_TICK_RATE)
  173. {
  174. m_Time = 0;
  175. m_WetDryTick++; // Sets whether it is time to add wetness to items and clothing
  176. //! Updates data
  177. CheckWaterContact(m_WaterLevel);
  178. CollectAndSetPlayerData();
  179. CollectAndSetEnvironmentData();
  180. GatherTemperatureSources();
  181. ProcessTemperatureSources();
  182. //! Process temperatures
  183. ProcessItemsTemperature(m_HeadParts);
  184. ProcessItemsTemperature(m_BodyParts);
  185. ProcessItemsTemperature(m_FeetParts);
  186. ProcessItemsInHandsTemperature();
  187. //! heat comfort calculation
  188. if (DetermineHeatcomfortBehavior())
  189. SetHeatcomfortDirectly();
  190. else
  191. ProcessHeatComfort();
  192. //! Process item wetness/dryness
  193. if (m_WetDryTick >= GameConstants.ENVIRO_TICKS_TO_WETNESS_CALCULATION)
  194. {
  195. if (IsWaterContact())
  196. {
  197. ProcessWetnessByWaterLevel(m_WaterLevel);
  198. }
  199. else if ((IsRaining() || (IsSnowing() && MiscGameplayFunctions.GetCombinedSnowfallWindValue() > SNOWFALL_WIND_COMBINED_THRESHOLD)) && !IsInsideBuilding() && !IsUnderRoof() && !IsInsideVehicle())
  200. {
  201. ProcessItemsWetness(m_SlotIdsComplete);
  202. }
  203. else
  204. {
  205. ProcessItemsDryness();
  206. }
  207. //! setting of wetness/dryiness of player
  208. if ((m_ItemsWetnessMax < GameConstants.STATE_WET) && (m_Player.GetStatWet().Get() == 1))
  209. {
  210. m_Player.GetStatWet().Set(0);
  211. }
  212. else if ((m_ItemsWetnessMax >= GameConstants.STATE_WET) && (m_Player.GetStatWet().Get() == 0))
  213. {
  214. m_Player.GetStatWet().Set(1);
  215. }
  216. m_WetDryTick = 0;
  217. m_ItemsWetnessMax = 0; //! reset item wetness counter;
  218. }
  219. }
  220. }
  221. }
  222. bool IsTemperatureSet()
  223. {
  224. return m_IsTempSet;
  225. }
  226. //! Returns heat player generated based on player's movement speed (for now)
  227. protected float GetPlayerHeat()
  228. {
  229. float heat = m_PlayerSpeed * GameConstants.ENVIRO_DEFAULT_ENTITY_HEAT;
  230. return heat;
  231. }
  232. bool IsUnderRoof()
  233. {
  234. return m_IsUnderRoof;
  235. }
  236. protected bool IsWaterContact()
  237. {
  238. return m_IsInWater;
  239. }
  240. bool IsInsideBuilding()
  241. {
  242. return m_Player && m_Player.IsSoundInsideBuilding();
  243. }
  244. protected bool IsInsideVehicle()
  245. {
  246. return m_Player && m_Player.IsInVehicle();
  247. }
  248. private bool IsUnderRoofBuilding()
  249. {
  250. return m_IsUnderRoofBuilding;
  251. }
  252. protected bool IsRaining()
  253. {
  254. return m_Rain > RAIN_LIMIT_LOW;
  255. }
  256. protected bool IsSnowing()
  257. {
  258. return m_Snowfall > SNOWFALL_LIMIT_LOW;
  259. }
  260. protected bool DetermineHeatcomfortBehavior()
  261. {
  262. if (IsInsideVehicle())
  263. {
  264. CarScript car = CarScript.Cast(m_Player.GetParent());
  265. if (car && car.EngineIsOn())
  266. {
  267. m_HeatComfortBehaviorCategory = EEnvironmentHeatcomfortBehaviorCategory.CAR_ENGINE_ON;
  268. return true;
  269. }
  270. }
  271. m_HeatComfortBehaviorCategory = EEnvironmentHeatcomfortBehaviorCategory.DEFAULT;
  272. return false;
  273. }
  274. //! Checks whether Player is sheltered
  275. protected void CheckUnderRoof()
  276. {
  277. // if inside vehicle return immediatelly
  278. if (IsInsideVehicle())
  279. {
  280. m_IsUnderRoof = false;
  281. m_IsUnderRoofBuilding = false;
  282. return;
  283. }
  284. float hitFraction;
  285. vector hitPosition, hitNormal;
  286. vector from = m_Player.GetPosition();
  287. vector to = from + "0 25 0";
  288. Object hitObject;
  289. PhxInteractionLayers collisionLayerMask = PhxInteractionLayers.ITEM_LARGE|PhxInteractionLayers.BUILDING|PhxInteractionLayers.VEHICLE;
  290. m_IsUnderRoof = DayZPhysics.RayCastBullet(from, to, collisionLayerMask, null, hitObject, hitPosition, hitNormal, hitFraction);
  291. m_IsUnderRoofBuilding = hitObject && hitObject.IsInherited(House);
  292. }
  293. protected void CheckWaterContact(out float pWaterLevel)
  294. {
  295. string surfType;
  296. int liquidType;
  297. m_IsInWater = false;
  298. if (m_Player.IsSwimming())
  299. {
  300. g_Game.SurfaceUnderObjectByBoneCorrectedLiquid(m_Player, SurfaceAnimationBone.RightFrontLimb, surfType, liquidType);
  301. m_SurfaceType = surfType;
  302. m_LiquidType = liquidType;
  303. m_IsInWater = true;
  304. m_Player.SetInWater(m_IsInWater);
  305. HumanMovementState hms = new HumanMovementState();
  306. m_Player.GetMovementState(hms);
  307. pWaterLevel = WATER_LEVEL_MID;
  308. if (hms.m_iMovement >= DayZPlayerConstants.MOVEMENTIDX_WALK)
  309. pWaterLevel = WATER_LEVEL_HIGH;
  310. return;
  311. }
  312. //! no valid surface under character
  313. if (IsUnderRoofBuilding())
  314. {
  315. m_IsInWater = false;
  316. return;
  317. }
  318. string impact;
  319. g_Game.SurfaceUnderObjectExCorrectedLiquid(m_Player, surfType, impact, liquidType);
  320. switch (liquidType)
  321. {
  322. case LIQUID_SALTWATER:
  323. case LIQUID_WATER:
  324. case LIQUID_RIVERWATER:
  325. case LIQUID_FRESHWATER:
  326. case LIQUID_STILLWATER:
  327. case LIQUID_HOTWATER:
  328. pWaterLevel = m_Player.GetCurrentWaterLevel();
  329. m_IsInWater = true;
  330. break;
  331. }
  332. //! sync info about water contact to player
  333. m_Player.SetInWater(m_IsInWater);
  334. //! update active surface
  335. m_SurfaceType = surfType;
  336. m_LiquidType = liquidType;
  337. }
  338. float GetWindModifierPerSurface()
  339. {
  340. if (IsUnderRoofBuilding())
  341. return 0.0;
  342. return g_Game.ConfigGetFloat("CfgSurfaces " + m_SurfaceType + " windModifier");
  343. }
  344. float GetTemperature()
  345. {
  346. return m_EnvironmentTemperature;
  347. }
  348. float GetTargetHeatComfort()
  349. {
  350. return m_TargetHeatComfort;
  351. }
  352. // Calculates and return temperature of environment
  353. protected float GetEnvironmentTemperature()
  354. {
  355. float temperature;
  356. temperature = m_WorldData.GetBaseEnvTemperatureAtObject(m_Player);
  357. temperature += m_Clouds * m_WorldData.m_CloudsTemperatureEffectModifier;
  358. if (IsWaterContact())
  359. {
  360. float waterBodyTemperature = m_WorldData.GetLiquidTypeEnviroTemperature(m_LiquidType);
  361. temperature = waterBodyTemperature - m_WorldData.m_WaterContactTemperatureModifier;
  362. return temperature;
  363. }
  364. if (IsInsideBuilding() || m_IsUnderRoofBuilding)
  365. {
  366. temperature += m_WorldData.m_TemperatureInsideBuildingsModifier;
  367. }
  368. else if (IsInsideVehicle())
  369. {
  370. temperature += Math.AbsFloat(temperature * GameConstants.ENVIRO_TEMPERATURE_INSIDE_VEHICLE_COEF);
  371. return temperature;
  372. }
  373. else if (IsUnderRoof() && !m_IsUnderRoofBuilding)
  374. {
  375. temperature += m_Fog * GameConstants.ENVIRO_FOG_TEMP_EFFECT;
  376. temperature += WindEffectTemperatureValue(temperature) * GetWindModifierPerSurface() * GameConstants.ENVIRO_TEMPERATURE_UNDERROOF_COEF;
  377. }
  378. else
  379. {
  380. temperature += m_Fog * GameConstants.ENVIRO_FOG_TEMP_EFFECT;
  381. temperature += WindEffectTemperatureValue(temperature) * GetWindModifierPerSurface();
  382. }
  383. // incorporate temperature from temperature sources (buffer)
  384. if (Math.AbsFloat(m_UTSAverageTemperature) > 0.0 && m_UTSAverageTemperature > temperature)
  385. temperature = m_UTSAverageTemperature;
  386. return temperature;
  387. }
  388. // Calculates wet/drying delta based on player's location and weather
  389. float GetWetDelta()
  390. {
  391. float wetDelta = 0;
  392. if ( IsWaterContact() )
  393. {
  394. //! player is getting wet by movement/swimming in water (+differentiate wetDelta by water level)
  395. if (m_WaterLevel >= WATER_LEVEL_HIGH)
  396. {
  397. wetDelta = 1;
  398. }
  399. else if (m_WaterLevel >= WATER_LEVEL_MID && m_WaterLevel < WATER_LEVEL_HIGH)
  400. {
  401. wetDelta = 0.66;
  402. }
  403. else if (m_WaterLevel >= WATER_LEVEL_LOW && m_WaterLevel < WATER_LEVEL_MID)
  404. {
  405. wetDelta = 0.66;
  406. }
  407. else if (m_WaterLevel >= WATER_LEVEL_NONE && m_WaterLevel < WATER_LEVEL_LOW)
  408. {
  409. wetDelta = 0.33;
  410. }
  411. }
  412. else if (!IsInsideBuilding() && !IsUnderRoof() && !IsInsideVehicle())
  413. {
  414. if (IsRaining())
  415. wetDelta = GameConstants.ENVIRO_WET_INCREMENT * GameConstants.ENVIRO_TICKS_TO_WETNESS_CALCULATION * (m_Rain) * (1 + (GameConstants.ENVIRO_WIND_EFFECT * m_Wind));
  416. if (IsSnowing() && MiscGameplayFunctions.GetCombinedSnowfallWindValue() > SNOWFALL_WIND_COMBINED_THRESHOLD)
  417. wetDelta = GameConstants.ENVIRO_WET_INCREMENT * GameConstants.ENVIRO_TICKS_TO_WETNESS_CALCULATION * (m_Snowfall - SNOWFALL_LIMIT_LOW) * GameConstants.ENVIRO_SNOW_WET_COEF * (1 + (GameConstants.ENVIRO_WIND_EFFECT * m_Wind));
  418. }
  419. else
  420. {
  421. //! player is drying
  422. float tempEffect = Math.Max(m_PlayerHeat + GetEnvironmentTemperature(), 1.0);
  423. float weatherEffect = ((1 - (m_Fog * GameConstants.ENVIRO_FOG_DRY_EFFECT))) * (1 - (m_Clouds * GameConstants.ENVIRO_CLOUD_DRY_EFFECT));
  424. if (weatherEffect <= 0)
  425. {
  426. weatherEffect = 1.0;
  427. }
  428. wetDelta = -(GameConstants.ENVIRO_DRY_INCREMENT * weatherEffect * tempEffect);
  429. if (!IsInsideBuilding())
  430. {
  431. wetDelta *= 1 + (GameConstants.ENVIRO_WIND_EFFECT * m_Wind);
  432. }
  433. }
  434. return wetDelta;
  435. }
  436. // EXPOSURE
  437. // Each tick updates current entity member variables
  438. protected void CollectAndSetPlayerData()
  439. {
  440. vector playerPos = m_Player.GetPosition();
  441. m_PlayerHeightPos = playerPos[1];
  442. HumanCommandMove hcm = m_Player.GetCommand_Move();
  443. if (hcm)
  444. {
  445. m_PlayerSpeed = hcm.GetCurrentMovementSpeed();
  446. }
  447. m_PlayerHeat = GetPlayerHeat();
  448. }
  449. // Each tick updates current environment member variables
  450. protected void CollectAndSetEnvironmentData()
  451. {
  452. Weather weather = g_Game.GetWeather();
  453. m_Rain = weather.GetRain().GetActual();
  454. m_Snowfall = weather.GetSnowfall().GetActual();
  455. m_DayOrNight = g_Game.GetMission().GetWorldData().GetDaytime();
  456. m_Fog = weather.GetFog().GetActual();
  457. m_Clouds = weather.GetOvercast().GetActual();
  458. m_Wind = g_Game.GetWeather().GetWindMagnitude().GetActual();
  459. SetEnvironmentTemperature();
  460. SetAreaGenericColdness();
  461. }
  462. void SetEnvironmentTemperature()
  463. {
  464. m_IsTempSet = true;
  465. m_EnvironmentTemperature = GetEnvironmentTemperature();
  466. }
  467. //! Determines whether player is in cold area which restricts use of some actions (digging)
  468. void SetAreaGenericColdness()
  469. {
  470. float heigthCorrectedTemp = m_WorldData.GetBaseEnvTemperatureAtObject(m_Player);
  471. m_Player.SetInColdArea(heigthCorrectedTemp <= GameConstants.COLD_AREA_TEMPERATURE_THRESHOLD);
  472. }
  473. protected float WindEffectTemperatureValue(float temperatureInput)
  474. {
  475. float output = 0.0;
  476. output = (temperatureInput - GameConstants.ENVIRO_WIND_CHILL_LIMIT) / (GameConstants.ENVIRO_WIND_EFFECT_SLOPE - GameConstants.ENVIRO_WIND_CHILL_LIMIT);
  477. output = output * m_Wind * m_WorldData.GetWindCoef();
  478. return -output;
  479. }
  480. //! process attachments by water depth
  481. protected void ProcessWetnessByWaterLevel(float pWaterLevel)
  482. {
  483. if (pWaterLevel >= WATER_LEVEL_HIGH)
  484. ProcessItemsWetness(m_SlotIdsComplete);
  485. else if (pWaterLevel >= WATER_LEVEL_MID && pWaterLevel < WATER_LEVEL_HIGH)
  486. ProcessItemsWetness(m_SlotIdsUpper);
  487. else if (pWaterLevel >= WATER_LEVEL_LOW && pWaterLevel < WATER_LEVEL_MID)
  488. ProcessItemsWetness(m_SlotIdsBottom);
  489. else if (pWaterLevel >= WATER_LEVEL_NONE && pWaterLevel < WATER_LEVEL_LOW)
  490. ProcessItemsWetness(m_SlotIdsLower);
  491. }
  492. // Wets or dry items once in given time
  493. protected void ProcessItemsWetness(array<int> pSlotIds)
  494. {
  495. EntityAI attachment;
  496. int playerAttachmentCount = m_Player.GetInventory().AttachmentCount();
  497. LogDryWetProcess(string.Format("Environment :: ProcessItemsWetness (update interval=%1s)", GameConstants.ENVIRO_TICK_RATE));
  498. for (int attIdx = 0; attIdx < playerAttachmentCount; ++attIdx)
  499. {
  500. attachment = m_Player.GetInventory().GetAttachmentFromIndex(attIdx);
  501. if (attachment.IsItemBase())
  502. {
  503. int attachmentSlotsCount = attachment.GetInventory().GetSlotIdCount();
  504. for (int attachmentSlotId = 0; attachmentSlotId < attachmentSlotsCount; ++attachmentSlotId)
  505. {
  506. int attachmentSlot = attachment.GetInventory().GetSlotId(attachmentSlotId);
  507. for (int i = 0; i < pSlotIds.Count(); ++i)
  508. {
  509. if (attachmentSlot == pSlotIds.Get(i))
  510. {
  511. ApplyWetnessToItem(ItemBase.Cast(attachment));
  512. break;
  513. }
  514. }
  515. }
  516. }
  517. }
  518. if (m_Player.GetItemInHands())
  519. ApplyWetnessToItem(m_Player.GetItemInHands());
  520. LogDryWetProcess("==========");
  521. }
  522. protected void ProcessItemsDryness()
  523. {
  524. EntityAI attachment;
  525. ItemBase item;
  526. int attCount = m_Player.GetInventory().AttachmentCount();
  527. LogDryWetProcess(string.Format("Environment :: ProcessItemsDryness (update interval=%1s)", GameConstants.ENVIRO_TICK_RATE));
  528. EnvironmentDrynessData drynessData = new EnvironmentDrynessData();
  529. drynessData.m_UseTemperatureSources = m_HasTemperatureSources;
  530. if (m_HasTemperatureSources)
  531. {
  532. float distance = vector.Distance(m_UTemperatureSources[0].GetPosition(), m_Player.GetPosition());
  533. distance = Math.Max(distance, 0.1);
  534. drynessData.m_TemperatureSourceDistance = distance;
  535. LogDryWetProcess(string.Format("distance to heatsource: %1 m", distance));
  536. }
  537. for (int attIdx = 0; attIdx < attCount; ++attIdx)
  538. {
  539. attachment = m_Player.GetInventory().GetAttachmentFromIndex(attIdx);
  540. if (attachment && attachment.IsItemBase())
  541. {
  542. item = ItemBase.Cast(attachment);
  543. if (item)
  544. ApplyDrynessToItemEx(item, drynessData);
  545. }
  546. }
  547. if (m_Player.GetItemInHands())
  548. {
  549. ApplyDrynessToItemEx(m_Player.GetItemInHands(), drynessData);
  550. }
  551. LogDryWetProcess("==========");
  552. }
  553. protected void ApplyWetnessToItem(ItemBase pItem)
  554. {
  555. if (pItem)
  556. {
  557. ItemBase parentItem;
  558. bool isParentWet = false;
  559. bool parentContainsLiquid = false;
  560. InventoryLocation iLoc = new InventoryLocation();
  561. if (pItem.GetInventory().GetCurrentInventoryLocation(iLoc))
  562. {
  563. EntityAI parent = iLoc.GetParent();
  564. if (parent)
  565. {
  566. parentItem = ItemBase.Cast(parent);
  567. if (parentItem)
  568. {
  569. if (parentItem.GetWet() >= GameConstants.STATE_SOAKING_WET)
  570. isParentWet = true;
  571. if ((parentItem.GetLiquidType() != 0) && (parentItem.GetQuantity() > 0))
  572. parentContainsLiquid = true;
  573. }
  574. else
  575. isParentWet = true;
  576. if ((pItem.GetWet() > m_ItemsWetnessMax) && (parent == m_Player))
  577. m_ItemsWetnessMax = pItem.GetWet();
  578. }
  579. }
  580. if (isParentWet || parentContainsLiquid)
  581. {
  582. float soakingCoef = 0;
  583. if (parentContainsLiquid)
  584. {
  585. soakingCoef = pItem.GetSoakingIncrement("parentWithLiquid");
  586. LogDryWetProcess(string.Format("%1 (soak coef=%2/s, current wetness=%3) [parent contains liquid]", pItem.GetDisplayName(), soakingCoef / GameConstants.ENVIRO_TICK_RATE, pItem.GetWet()), parentItem != null);
  587. }
  588. else if (isParentWet && parentItem)
  589. {
  590. if (pItem.GetWet() < parentItem.GetWet())
  591. {
  592. soakingCoef = pItem.GetSoakingIncrement("wetParent");
  593. LogDryWetProcess(string.Format("%1 (soak coef=%2/s, current wetness=%3) [parent wet]", pItem.GetDisplayName(), soakingCoef / GameConstants.ENVIRO_TICK_RATE, pItem.GetWet()), parentItem != null);
  594. }
  595. }
  596. else
  597. {
  598. soakingCoef = GetWetDelta();
  599. LogDryWetProcess(string.Format("%1 (soak coef=%2/s, current wetness=%3) [normal]", pItem.GetDisplayName(), soakingCoef / GameConstants.ENVIRO_TICK_RATE, pItem.GetWet()), parentItem != null);
  600. }
  601. pItem.AddWet(soakingCoef);
  602. if (pItem.GetInventory().GetCargo())
  603. {
  604. int inItemCount = pItem.GetInventory().GetCargo().GetItemCount();
  605. for (int i = 0; i < inItemCount; ++i)
  606. {
  607. ItemBase inItem;
  608. if (Class.CastTo(inItem, pItem.GetInventory().GetCargo().GetItem(i)))
  609. ApplyWetnessToItem(inItem);
  610. }
  611. }
  612. int attCount = pItem.GetInventory().AttachmentCount();
  613. if (attCount > 0)
  614. {
  615. for (int attIdx = 0; attIdx < attCount; ++attIdx)
  616. {
  617. EntityAI attachment = pItem.GetInventory().GetAttachmentFromIndex(attIdx);
  618. ItemBase itemAtt = ItemBase.Cast(attachment);
  619. if (itemAtt)
  620. ApplyWetnessToItem(itemAtt);
  621. }
  622. }
  623. }
  624. }
  625. }
  626. protected void ApplyDrynessToItem(ItemBase pItem)
  627. {
  628. EnvironmentDrynessData drynessData = new EnvironmentDrynessData();
  629. ApplyDrynessToItemEx(pItem, drynessData);
  630. }
  631. protected void ApplyDrynessToItemEx(ItemBase pItem, EnvironmentDrynessData pDrynessData)
  632. {
  633. if (pItem)
  634. {
  635. float dryingIncrement = pItem.GetDryingIncrement("player");
  636. if (pDrynessData.m_UseTemperatureSources)
  637. dryingIncrement = pItem.GetDryingIncrement("playerHeatSource");
  638. ItemBase parentItem;
  639. bool isParentWet = false;
  640. bool parentContainsLiquid = false;
  641. InventoryLocation iLoc = new InventoryLocation();
  642. if (pItem.GetInventory().GetCurrentInventoryLocation(iLoc))
  643. {
  644. EntityAI parent = iLoc.GetParent();
  645. if (parent)
  646. {
  647. parentItem = ItemBase.Cast(parent);
  648. if (parentItem)
  649. {
  650. if (parentItem.GetWet() >= GameConstants.STATE_SOAKING_WET)
  651. isParentWet = true;
  652. if ((parentItem.GetLiquidType() != 0) && (parentItem.GetQuantity() > 0))
  653. parentContainsLiquid = true;
  654. }
  655. if ((pItem.GetWet() > m_ItemsWetnessMax) && (parent == m_Player))
  656. m_ItemsWetnessMax = pItem.GetWet();
  657. }
  658. }
  659. float dryingCoef = 0;
  660. if (!isParentWet && !parentContainsLiquid)
  661. {
  662. dryingCoef = (-1 * GameConstants.ENVIRO_TICK_RATE * dryingIncrement) / pDrynessData.m_TemperatureSourceDistance;
  663. if (pItem.GetWet() >= GameConstants.STATE_DAMP)
  664. {
  665. LogDryWetProcess(string.Format("%1 (dry coef=%2/s, current wetness=%3) [normal]", pItem.GetDisplayName(), dryingCoef / GameConstants.ENVIRO_TICK_RATE, pItem.GetWet()), parentItem != null);
  666. pItem.AddWet(dryingCoef);
  667. }
  668. if (pItem.GetInventory().GetCargo())
  669. {
  670. int inItemCount = pItem.GetInventory().GetCargo().GetItemCount();
  671. for (int i = 0; i < inItemCount; ++i)
  672. {
  673. ItemBase inItem;
  674. if (Class.CastTo(inItem, pItem.GetInventory().GetCargo().GetItem(i)))
  675. ApplyDrynessToItemEx(inItem, pDrynessData);
  676. }
  677. }
  678. int attCount = pItem.GetInventory().AttachmentCount();
  679. if (attCount > 0)
  680. {
  681. for (int attIdx = 0; attIdx < attCount; ++attIdx)
  682. {
  683. EntityAI attachment = pItem.GetInventory().GetAttachmentFromIndex(attIdx);
  684. ItemBase itemAtt;
  685. if (ItemBase.CastTo(itemAtt, attachment))
  686. ApplyDrynessToItemEx(itemAtt, pDrynessData);
  687. }
  688. }
  689. }
  690. if (parentContainsLiquid)
  691. {
  692. //! adds wetness to item inside parent item containing liquid
  693. dryingCoef = (GameConstants.ENVIRO_TICK_RATE * pItem.GetSoakingIncrement("parentWithLiquid")) / pDrynessData.m_TemperatureSourceDistance;
  694. LogDryWetProcess(string.Format("%1 (dry coef=%2/s, current wetness=%3) [parent contains liquid]", pItem.GetDisplayName(), dryingCoef / GameConstants.ENVIRO_TICK_RATE, pItem.GetWet()), parentItem != null);
  695. pItem.AddWet(dryingCoef);
  696. }
  697. if (isParentWet)
  698. {
  699. if (pItem.GetWet() < parentItem.GetWet())
  700. {
  701. //! adds wetness to item inside wet parent item
  702. dryingCoef = (GameConstants.ENVIRO_TICK_RATE * pItem.GetSoakingIncrement("wetParent")) / pDrynessData.m_TemperatureSourceDistance;
  703. LogDryWetProcess(string.Format("%1 (dry coef=%2/s, current wetness=%3) [parent wet]", pItem.GetDisplayName(), dryingCoef / GameConstants.ENVIRO_TICK_RATE, pItem.GetWet()), parentItem != null);
  704. pItem.AddWet(dryingCoef);
  705. }
  706. }
  707. }
  708. }
  709. // HEAT COMFORT
  710. //! Calculates and process player's heatcomfort related to body parts
  711. protected void ProcessHeatComfort()
  712. {
  713. float hcPenaltyTotal //! Heat Comfort Penalty
  714. // NEW body parts => splitted
  715. float hcBodyPartTotal, hcBodyPart;
  716. float hBodyPartTotal, hBodyPart;
  717. float heatComfortSum = 0.0;
  718. float heatItems = 0.0;
  719. LogItemHeat("====================");
  720. BodyPartHeatProperties(InventorySlots.HEADGEAR, GameConstants.ENVIRO_HEATCOMFORT_HEADGEAR_WEIGHT, hcBodyPart, hBodyPart);
  721. hcBodyPartTotal += hcBodyPart; hBodyPartTotal += hBodyPart;
  722. BodyPartHeatProperties(InventorySlots.MASK, GameConstants.ENVIRO_HEATCOMFORT_MASK_WEIGHT, hcBodyPart, hBodyPart);
  723. hcBodyPartTotal += hcBodyPart; hBodyPartTotal += hBodyPart;
  724. BodyPartHeatProperties(InventorySlots.VEST, GameConstants.ENVIRO_HEATCOMFORT_VEST_WEIGHT, hcBodyPart, hBodyPart);
  725. hcBodyPartTotal += hcBodyPart; hBodyPartTotal += hBodyPart;
  726. BodyPartHeatProperties(InventorySlots.BODY, GameConstants.ENVIRO_HEATCOMFORT_BODY_WEIGHT, hcBodyPart, hBodyPart);
  727. hcBodyPartTotal += hcBodyPart; hBodyPartTotal += hBodyPart;
  728. BodyPartHeatProperties(InventorySlots.BACK, GameConstants.ENVIRO_HEATCOMFORT_BACK_WEIGHT, hcBodyPart, hBodyPart);
  729. hcBodyPartTotal += hcBodyPart; hBodyPartTotal += hBodyPart;
  730. BodyPartHeatProperties(InventorySlots.GLOVES, GameConstants.ENVIRO_HEATCOMFORT_GLOVES_WEIGHT, hcBodyPart, hBodyPart);
  731. hcBodyPartTotal += hcBodyPart; hBodyPartTotal += hBodyPart;
  732. BodyPartHeatProperties(InventorySlots.LEGS, GameConstants.ENVIRO_HEATCOMFORT_LEGS_WEIGHT, hcBodyPart, hBodyPart);
  733. hcBodyPartTotal += hcBodyPart; hBodyPartTotal += hBodyPart;
  734. BodyPartHeatProperties(InventorySlots.FEET, GameConstants.ENVIRO_HEATCOMFORT_FEET_WEIGHT, hcBodyPart, hBodyPart);
  735. hcBodyPartTotal += hcBodyPart; hBodyPartTotal += hBodyPart;
  736. BodyPartHeatProperties(InventorySlots.HIPS, GameConstants.ENVIRO_HEATCOMFORT_HIPS_WEIGHT, hcBodyPart, hBodyPart);
  737. hcBodyPartTotal += hcBodyPart; hBodyPartTotal += hBodyPart;
  738. hcPenaltyTotal += NakedBodyPartHeatComfortPenalty(InventorySlots.HEADGEAR, GameConstants.ENVIRO_HEATCOMFORT_HEADGEAR_WEIGHT);
  739. hcPenaltyTotal += NakedBodyPartHeatComfortPenalty(InventorySlots.MASK, GameConstants.ENVIRO_HEATCOMFORT_MASK_WEIGHT);
  740. hcPenaltyTotal += NakedBodyPartHeatComfortPenalty(InventorySlots.BODY, GameConstants.ENVIRO_HEATCOMFORT_BODY_WEIGHT);
  741. hcPenaltyTotal += NakedBodyPartHeatComfortPenalty(InventorySlots.GLOVES, GameConstants.ENVIRO_HEATCOMFORT_GLOVES_WEIGHT);
  742. hcPenaltyTotal += NakedBodyPartHeatComfortPenalty(InventorySlots.LEGS, GameConstants.ENVIRO_HEATCOMFORT_LEGS_WEIGHT);
  743. hcPenaltyTotal += NakedBodyPartHeatComfortPenalty(InventorySlots.FEET, GameConstants.ENVIRO_HEATCOMFORT_FEET_WEIGHT);
  744. heatItems = hBodyPartTotal;
  745. heatComfortSum = hcBodyPartTotal;
  746. heatComfortSum += hcPenaltyTotal; //! heatcomfort body parts penalties
  747. {
  748. float stomachContentTemperature = m_Player.GetStomach().GetStomachTemperature();
  749. if (!IsNeutralTemperature(stomachContentTemperature))
  750. {
  751. stomachContentTemperature = m_Player.GetStomach().GetStomachTemperature() * GameConstants.ENVIRO_STOMACH_WEIGHT;
  752. stomachContentTemperature = Math.Clamp(stomachContentTemperature, -GameConstants.ENVIRO_STOMACH_WEIGHT, GameConstants.ENVIRO_STOMACH_WEIGHT);
  753. heatComfortSum += stomachContentTemperature;
  754. }
  755. }
  756. float targetHeatComfort = (heatComfortSum + heatItems + (GetPlayerHeat() / 100)) + EnvTempToCoef(m_EnvironmentTemperature);
  757. SetEnvironmentSnapshotData();
  758. ProcessHeatBuffer(hcBodyPartTotal);
  759. if (m_Player.GetModifiersManager().IsModifierActive(eModifiers.MDF_HEATBUFFER))
  760. targetHeatComfort = Math.Clamp(targetHeatComfort, 0.0, m_Player.GetStatHeatComfort().GetMax());
  761. else
  762. targetHeatComfort = Math.Clamp(targetHeatComfort, m_Player.GetStatHeatComfort().GetMin(), m_Player.GetStatHeatComfort().GetMax());
  763. targetHeatComfort = Math.Round(targetHeatComfort * 100) * 0.01;
  764. float dynamicHeatComfort;
  765. {
  766. float direction = 1.0;
  767. if (targetHeatComfort < 0.0)
  768. direction = -1.0;
  769. if (Math.AbsFloat(targetHeatComfort - m_HeatComfort) <= GameConstants.ENVIRO_HEATCOMFORT_MAX_STEP_SIZE)
  770. dynamicHeatComfort = m_AverageHeatComfortBuffer.Add(targetHeatComfort);
  771. else
  772. dynamicHeatComfort = m_AverageHeatComfortBuffer.Add((Math.AbsFloat(targetHeatComfort) - GameConstants.ENVIRO_HEATCOMFORT_MAX_STEP_SIZE) * direction);
  773. }
  774. dynamicHeatComfort = Math.Round(dynamicHeatComfort * 100) * 0.01;
  775. m_HeatComfort = dynamicHeatComfort;
  776. SetTargetHeatComfort(targetHeatComfort);
  777. m_Player.GetStatHeatComfort().Set(m_HeatComfort);
  778. }
  779. protected void SetTargetHeatComfort(float value)
  780. {
  781. m_TargetHeatComfort = value;
  782. }
  783. protected void SetHeatcomfortDirectly()
  784. {
  785. if (m_HeatComfortBehaviorCategory == EEnvironmentHeatcomfortBehaviorCategory.CAR_ENGINE_ON)
  786. {
  787. float targetHeatComfort = 0.0;
  788. float dynamicHeatComfort = m_AverageHeatComfortBuffer.Add(targetHeatComfort);
  789. m_HeatComfort = dynamicHeatComfort;
  790. SetTargetHeatComfort(0.0);
  791. m_Player.GetStatHeatComfort().Set(dynamicHeatComfort);
  792. }
  793. }
  794. protected void ProcessHeatBuffer(float heatComfortCloths)
  795. {
  796. if (m_HeatComfortBehaviorCategory == EEnvironmentHeatcomfortBehaviorCategory.DEFAULT)
  797. {
  798. float applicableHeatbuffer = GetApplicableHeatbuffer();
  799. float originalTargetHeatcomfortMultiplier = 1.0;
  800. //! dynamic HB cap based on actual heatcomfort (from cloths)
  801. float heatBufferCap = Math.InverseLerp(0.0, GameConstants.ENVIRO_HEATCOMFORT_WEIGHT_SUMMARY, heatComfortCloths);
  802. float heatBufferMax = GameConstants.ENVIRO_PLAYER_HEATBUFFER_CAPACITY_MIN + heatBufferCap * (1 - GameConstants.ENVIRO_PLAYER_HEATBUFFER_CAPACITY_MIN);
  803. m_Player.SetHeatBufferDynamicMax(heatBufferMax);
  804. float increaseRate = 0.0;
  805. float decreaseRate = 0.0;
  806. if (m_EnvironmentSnapshot)
  807. {
  808. increaseRate = GameConstants.ENVIRO_PLAYER_HEATBUFFER_INCREASE / (heatBufferMax * (( -GameConstants.ENVIRO_PLAYER_HEATBUFFER_TEMP_AFFECT * m_EnvironmentSnapshot.m_TargetHeatComfort ) + 1 ));
  809. decreaseRate = GameConstants.ENVIRO_PLAYER_HEATBUFFER_DECREASE / (heatBufferMax * (( GameConstants.ENVIRO_PLAYER_HEATBUFFER_TEMP_AFFECT * m_EnvironmentSnapshot.m_TargetHeatComfort ) + 1 ));
  810. if (m_IsInWater)
  811. decreaseRate *= GameConstants.ENVIRO_PLAYER_HEATBUFFER_WATEREFFECT * m_WaterLevel;
  812. }
  813. if (!m_HasTemperatureSources)
  814. {
  815. if (m_Player.GetModifiersManager().IsModifierActive(eModifiers.MDF_HEATBUFFER))
  816. {
  817. if (m_HeatBufferTimer >= 1.0)
  818. m_Player.GetStatHeatBuffer().Add(-decreaseRate);
  819. else
  820. m_HeatBufferTimer = 1.0;
  821. }
  822. else
  823. {
  824. m_HeatBufferTimer = 0.0;
  825. if (applicableHeatbuffer > 0.0)
  826. m_Player.GetStatHeatBuffer().Add(-decreaseRate);
  827. else if (applicableHeatbuffer != 0.0 && !m_Player.GetModifiersManager().IsModifierActive(eModifiers.MDF_HEATBUFFER))
  828. m_Player.GetStatHeatBuffer().Set(0.0);
  829. }
  830. }
  831. else
  832. {
  833. if (m_HeatComfort > PlayerConstants.THRESHOLD_HEAT_COMFORT_MINUS_WARNING && m_UTSAverageTemperature > 0) // m_UTSAverageTemperature can be negative
  834. {
  835. if (applicableHeatbuffer < heatBufferMax)
  836. m_Player.GetStatHeatBuffer().Add(increaseRate);
  837. }
  838. else if (applicableHeatbuffer > 0.0)
  839. m_Player.GetStatHeatBuffer().Add(-decreaseRate);
  840. else if (applicableHeatbuffer != 0.0 && !m_Player.GetModifiersManager().IsModifierActive(eModifiers.MDF_HEATBUFFER))
  841. m_Player.GetStatHeatBuffer().Set(0.0);
  842. m_HeatBufferTimer = 0.0;
  843. }
  844. }
  845. }
  846. protected float GetApplicableHeatbuffer()
  847. {
  848. float applicableHeatbuffer = Math.Round((m_Player.GetStatHeatBuffer().Get() / m_Player.GetStatHeatBuffer().GetMax()) * 1000) * 0.001;
  849. return applicableHeatbuffer;
  850. }
  851. //! go through all items in player's possession cool/warm them to neutral temperature
  852. protected void ProcessItemsTemperature(array<int> pBodyPartIds)
  853. {
  854. EntityAI attachment;
  855. ItemBase item;
  856. // TODO:
  857. // * based on water level - change the target temperature and speed exchange while swimming
  858. int attCount = m_Player.GetInventory().AttachmentCount();
  859. for (int attIdx = 0; attIdx < attCount; ++attIdx)
  860. {
  861. attachment = m_Player.GetInventory().GetAttachmentFromIndex(attIdx);
  862. item = ItemBase.Cast(attachment);
  863. int attachmentSlot = attachment.GetInventory().GetSlotId(0);
  864. //! go through all body parts we've defined for that zone (ex.: head, body, feet)
  865. for (int i = 0; i < pBodyPartIds.Count(); ++i)
  866. {
  867. if (attachmentSlot == pBodyPartIds[i])
  868. {
  869. float heatPermCoef = item.GetHeatPermeabilityCoef();
  870. //first handle the item itself, if necessary
  871. if (item.CanHaveTemperature() && !item.IsSelfAdjustingTemperature())
  872. SetProcessedItemTemperature(item,heatPermCoef);
  873. ProcessItemHierarchyRecursive(item,heatPermCoef);
  874. }
  875. }
  876. }
  877. }
  878. protected void ProcessItemsInHandsTemperature()
  879. {
  880. ItemBase item = m_Player.GetItemInHands();
  881. if (item)
  882. {
  883. float heatPermCoef = item.GetHeatPermeabilityCoef();
  884. //first handle the item itself, if necessary
  885. if (item.CanHaveTemperature() && !item.IsSelfAdjustingTemperature())
  886. SetProcessedItemTemperature(item,heatPermCoef);
  887. ProcessItemHierarchyRecursive(item,heatPermCoef);
  888. }
  889. }
  890. protected void ProcessItemHierarchyRecursive(ItemBase item, float heatPermeabilityCoef = 1.0)
  891. {
  892. float heatPermCoef = heatPermeabilityCoef;
  893. // go through any attachments and cargo, recursive
  894. int inventoryAttCount = item.GetInventory().AttachmentCount();
  895. if (inventoryAttCount > 0)
  896. {
  897. ItemBase attachmentItem;
  898. for (int inAttIdx = 0; inAttIdx < inventoryAttCount; ++inAttIdx)
  899. {
  900. if (Class.CastTo(attachmentItem,item.GetInventory().GetAttachmentFromIndex(inAttIdx)))
  901. {
  902. heatPermCoef = heatPermeabilityCoef;
  903. heatPermCoef *= attachmentItem.GetHeatPermeabilityCoef();
  904. if (attachmentItem.CanHaveTemperature() && !attachmentItem.IsSelfAdjustingTemperature())
  905. {
  906. SetProcessedItemTemperature(attachmentItem,heatPermCoef);
  907. }
  908. ProcessItemHierarchyRecursive(attachmentItem,heatPermCoef);
  909. }
  910. }
  911. }
  912. if (item.GetInventory().GetCargo())
  913. {
  914. int inventoryItemCount = item.GetInventory().GetCargo().GetItemCount();
  915. if (inventoryItemCount > 0)
  916. {
  917. ItemBase inventoryItem;
  918. for (int j = 0; j < inventoryItemCount; ++j)
  919. {
  920. if (Class.CastTo(inventoryItem,item.GetInventory().GetCargo().GetItem(j)))
  921. {
  922. heatPermCoef = heatPermeabilityCoef;
  923. heatPermCoef *= inventoryItem.GetHeatPermeabilityCoef();
  924. if (inventoryItem.CanHaveTemperature() && !inventoryItem.IsSelfAdjustingTemperature())
  925. {
  926. SetProcessedItemTemperature(inventoryItem,heatPermCoef);
  927. }
  928. ProcessItemHierarchyRecursive(inventoryItem,heatPermCoef);
  929. }
  930. }
  931. }
  932. }
  933. }
  934. protected void SetProcessedItemTemperature(ItemBase item, float heatPermeabilityCoef = 1.0)
  935. {
  936. if (item.GetTemperature() != GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_MIDDLE)
  937. item.SetTemperatureEx(new TemperatureDataInterpolated(GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_MIDDLE,ETemperatureAccessTypes.ACCESS_INVENTORY,GameConstants.ENVIRO_TICK_RATE,m_ItemTemperatureCoef,heatPermeabilityCoef));
  938. }
  939. protected float EnvTempToCoef(float pTemp)
  940. {
  941. return (pTemp - GameConstants.ENVIRO_PLAYER_COMFORT_TEMP) / GameConstants.ENVIRO_TEMP_EFFECT_ON_PLAYER;
  942. }
  943. //! returns enhanced heat comfort for given body part
  944. protected void BodyPartHeatProperties(int pBodyPartId, float pCoef, out float pHeatComfort, out float pHeat)
  945. {
  946. pHeatComfort = 0;
  947. pHeat = 0;
  948. int attCount = m_Player.GetInventory().AttachmentCount();
  949. for (int attIdx = 0; attIdx < attCount; ++attIdx)
  950. {
  951. EntityAI attachment = m_Player.GetInventory().GetAttachmentFromIndex(attIdx);
  952. if (attachment.IsClothing())
  953. {
  954. ItemBase item = ItemBase.Cast(attachment);
  955. int attachmentSlot = attachment.GetInventory().GetSlotId(0);
  956. if (attachmentSlot == pBodyPartId)
  957. {
  958. LogItemHeat(string.Format("BodyPartHeatProperties (%1)", EnumTools.EnumToString(InventorySlots, pBodyPartId)));
  959. float itemHeatcomfort = 0;
  960. float itemTemperature = 0;
  961. // go through any attachments and cargo (only current level, ignore nested containers - they isolate)
  962. int inventoryAttCount = item.GetInventory().AttachmentCount();
  963. if (inventoryAttCount > 0)
  964. {
  965. LogItemHeat(string.Format("attachments:"), false);
  966. for (int inAttIdx = 0; inAttIdx < inventoryAttCount; ++inAttIdx)
  967. {
  968. EntityAI inAttachment = item.GetInventory().GetAttachmentFromIndex(inAttIdx);
  969. ItemBase attachmentItem = ItemBase.Cast(inAttachment);
  970. if (attachmentItem && attachmentItem.CanHaveTemperature())
  971. {
  972. itemTemperature = attachmentItem.GetTemperature();
  973. if (itemTemperature < GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT || itemTemperature > GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT)
  974. {
  975. itemHeatcomfort = NormalizedTemperature(itemTemperature) * attachmentItem.GetQuantityNormalizedScripted() * attachmentItem.GetTemperaturePerQuantityWeight();
  976. LogItemHeat(string.Format("%1: temperature=%2 heat=%3", attachmentItem, itemTemperature, pHeat), true);
  977. pHeat += itemHeatcomfort;
  978. }
  979. }
  980. }
  981. }
  982. if (item.GetInventory().GetCargo())
  983. {
  984. int inventoryItemCount = item.GetInventory().GetCargo().GetItemCount();
  985. if (inventoryItemCount > 0)
  986. {
  987. LogItemHeat(string.Format("cargo:"), false);
  988. for (int j = 0; j < inventoryItemCount; ++j)
  989. {
  990. ItemBase inventoryItem = ItemBase.Cast(item.GetInventory().GetCargo().GetItem(j));
  991. if (inventoryItem && inventoryItem.CanHaveTemperature())
  992. {
  993. itemTemperature = inventoryItem.GetTemperature();
  994. if (itemTemperature < GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT || itemTemperature > GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT)
  995. {
  996. itemHeatcomfort = NormalizedTemperature(itemTemperature) * inventoryItem.GetQuantityNormalizedScripted() * inventoryItem.GetTemperaturePerQuantityWeight();
  997. LogItemHeat(string.Format("%1: temperature=%2 heat=%3", inventoryItem, itemTemperature, itemHeatcomfort), true);
  998. pHeat += itemHeatcomfort;
  999. }
  1000. }
  1001. }
  1002. }
  1003. }
  1004. pHeatComfort = MiscGameplayFunctions.GetCurrentItemHeatIsolation(item) * pCoef;
  1005. LogItemHeat(string.Format("overall heat from items=%1 (coef applied)", pHeat));
  1006. LogItemHeat("");
  1007. break;
  1008. }
  1009. }
  1010. }
  1011. }
  1012. protected float NakedBodyPartHeatComfortPenalty(int pBodyPartSlotId, float pCoef)
  1013. {
  1014. float penalty = 0.0;
  1015. if (!IsInsideBuilding() && !IsUnderRoof() && !IsInsideVehicle() && !IsWaterContact())
  1016. {
  1017. if (m_Rain > GameConstants.ENVIRO_NAKED_BODY_PENALTY_RAIN_MIN_VALUE || m_Snowfall > GameConstants.ENVIRO_NAKED_BODY_PENALTY_SNOWFALL_MIN_VALUE)
  1018. {
  1019. penalty += GameConstants.ENVIRO_ISOLATION_WETFACTOR_DRENCHED;
  1020. penalty *= pCoef;
  1021. }
  1022. }
  1023. return penalty;
  1024. }
  1025. protected void GatherTemperatureSources()
  1026. {
  1027. m_UTemperatureSources.Clear();
  1028. array<Object> nearestObjects = new array<Object>();
  1029. GetGame().GetObjectsAtPosition(m_Player.GetPosition(), GameConstants.ENVIRO_TEMP_SOURCES_LOOKUP_RADIUS, nearestObjects, null);
  1030. foreach (Object nearestObject : nearestObjects)
  1031. {
  1032. EntityAI ent = EntityAI.Cast(nearestObject);
  1033. if (ent && ent.IsUniversalTemperatureSource() && ent != m_Player)
  1034. {
  1035. //! next temp source is too far
  1036. if (vector.DistanceSq(m_Player.GetPosition(), ent.GetPosition()) > Math.SqrFloat(ent.GetUniversalTemperatureSource().GetMaxRange()))
  1037. continue;
  1038. //! skip - this TS is not affecting player entities
  1039. if (ent.GetUniversalTemperatureSource().GetLambda().AffectsPlayer())
  1040. m_UTemperatureSources.Insert(ent.GetUniversalTemperatureSource());
  1041. }
  1042. }
  1043. if (m_Player.GetItemInHands() && m_Player.GetItemInHands().IsUniversalTemperatureSource())
  1044. m_UTemperatureSources.Insert(m_Player.GetItemInHands().GetUniversalTemperatureSource());
  1045. }
  1046. protected void SetItemHeatingCoef(float val)
  1047. {
  1048. m_ItemTemperatureCoef = val;
  1049. }
  1050. protected void ProcessTemperatureSources()
  1051. {
  1052. int UTScount = m_UTemperatureSources.Count();
  1053. if (UTScount == 0)
  1054. {
  1055. m_HasTemperatureSources = false;
  1056. OnTemperatureSourcesLeft();
  1057. m_UTSAverageTemperatureBuffer.Add(0.0);
  1058. m_UTSAverageTemperature = 0.0;
  1059. SetItemHeatingCoef(GameConstants.TEMP_COEF_INVENTORY);
  1060. return;
  1061. }
  1062. array<float> utsTemperatures = new array<float>();
  1063. // get temperature from the source (based on distance), save it for min/max filtering
  1064. float itemCoefAverage = 0.0;
  1065. foreach (UTemperatureSource tempSource : m_UTemperatureSources)
  1066. {
  1067. utsTemperatures.Insert(CalcTemperatureFromTemperatureSource(tempSource));
  1068. itemCoefAverage += tempSource.GetTemperatureItemCoef();
  1069. }
  1070. itemCoefAverage /= UTScount;
  1071. SetItemHeatingCoef(itemCoefAverage);
  1072. float min = MiscGameplayFunctions.GetMinValue(utsTemperatures);
  1073. float max = MiscGameplayFunctions.GetMaxValue(utsTemperatures);
  1074. if (max > 0 && min < 0)
  1075. {
  1076. //! adds average of 2 most significat sources to buffer
  1077. m_UTSAverageTemperature = m_UTSAverageTemperatureBuffer.Add((max + min) * 0.5);
  1078. }
  1079. else
  1080. {
  1081. m_UTSAverageTemperature = m_UTSAverageTemperatureBuffer.Add(max);
  1082. }
  1083. if (m_HasTemperatureSources == false)
  1084. OnTemperatureSourcesEnter();
  1085. m_HasTemperatureSources = true;
  1086. }
  1087. protected void OnTemperatureSourcesEnter();
  1088. protected void OnTemperatureSourcesLeft();
  1089. protected void SetEnvironmentSnapshotData()
  1090. {
  1091. EnvironmentSnapshotData data = new EnvironmentSnapshotData();
  1092. data.m_TargetHeatComfort = m_TargetHeatComfort;
  1093. m_EnvironmentSnapshot = data;
  1094. }
  1095. float GetUniversalSourcesTemperageAverage()
  1096. {
  1097. return m_UTSAverageTemperature;
  1098. }
  1099. float CalcTemperatureFromTemperatureSource(notnull UTemperatureSource uts)
  1100. {
  1101. float distance = vector.Distance(m_Player.GetPosition(), uts.GetPosition());
  1102. distance = Math.Max(distance, 0.1); //min distance cannot be 0 (division by zero)
  1103. float temperature = 0;
  1104. //! heat transfer through air to player (env temperature)
  1105. if (distance > uts.GetFullRange())
  1106. {
  1107. float distFactor = Math.InverseLerp(uts.GetMaxRange(), uts.GetFullRange(), distance);
  1108. temperature = uts.GetTemperatureCap() * distFactor;
  1109. }
  1110. else
  1111. {
  1112. temperature = uts.GetTemperatureCap();
  1113. }
  1114. return temperature;
  1115. }
  1116. //! debug
  1117. #ifdef DIAG_DEVELOPER
  1118. EnvDebugData GetEnvDebugData()
  1119. {
  1120. EnvDebugData data = new EnvDebugData();
  1121. data.Synch(this, m_Player);
  1122. return data;
  1123. }
  1124. void ShowEnvDebugPlayerInfo(bool enabled)
  1125. {
  1126. EnvDebugData data = GetEnvDebugData();
  1127. DisplayEnvDebugPlayerInfo(enabled, data);
  1128. }
  1129. static void DisplayEnvDebugPlayerInfo(bool enabled, EnvDebugData data)
  1130. {
  1131. int windowPosX = 10;
  1132. int windowPosY = 200;
  1133. Object obj;
  1134. DbgUI.Begin("Player stats", windowPosX, windowPosY);
  1135. if ( enabled )
  1136. {
  1137. DbgUI.Text(string.Format("Heat comfort(target): %1", data.m_PlayerData.m_HeatComfortTarget));
  1138. DbgUI.Text(string.Format("Heat comfort(dynamic): %1", data.m_PlayerData.m_HeatComfortDynamic));
  1139. DbgUI.Text(string.Format("Inside: %1 (%2)", data.m_PlayerData.m_Inside, data.m_PlayerData.m_Surface));
  1140. DbgUI.Text(string.Format("Under roof: %1 (%2)", data.m_PlayerData.m_UnderRoof, data.m_PlayerData.m_UnderRoofTimer));
  1141. if ( data.m_PlayerData.m_WaterLevel > 0 )
  1142. {
  1143. DbgUI.Text(string.Format("Water Level: %1", data.m_PlayerData.m_WaterLevel));
  1144. }
  1145. }
  1146. DbgUI.End();
  1147. DbgUI.Begin("Weather stats:", windowPosX, windowPosY + 200);
  1148. if ( enabled )
  1149. {
  1150. DbgUI.Text(string.Format("Env temperature (base): %1", data.m_MiscData.m_TemperatureBase));
  1151. DbgUI.Text(string.Format("Env temperature (height corrected): %1", data.m_MiscData.m_HeightCorrectedTemperature));
  1152. DbgUI.Text(string.Format("Env temperature (modfied): %1", data.m_MiscData.m_TemperatureModified));
  1153. DbgUI.Text(string.Format("Wind magnitude(surface mult): %1 (x%2)", data.m_WeatherData.m_Wind, data.m_WeatherData.m_WindModifier));
  1154. DbgUI.Text(string.Format("Rain: %1", data.m_WeatherData.m_Rain));
  1155. DbgUI.Text(string.Format("Snow: %1", data.m_WeatherData.m_Snowfall));
  1156. DbgUI.Text(string.Format("Datetime: %1", WorldDataDaytime.ToString(g_Game.GetMission().GetWorldData().GetDaytime())));
  1157. DbgUI.Text(string.Format("Fog: %1", data.m_WeatherData.m_Fog));
  1158. DbgUI.Text(string.Format("Clouds: %1", data.m_WeatherData.m_Clouds));
  1159. DbgUI.Text(string.Format("Wet delta: %1", data.m_MiscData.m_WetDelta));
  1160. }
  1161. DbgUI.End();
  1162. }
  1163. void FillDebugWeatherData(EnvDebugWeatherData data)
  1164. {
  1165. data.m_Wind = m_Wind;
  1166. data.m_WindModifier = GetWindModifierPerSurface();
  1167. data.m_Rain = m_Rain;
  1168. data.m_Snowfall = m_Snowfall;
  1169. data.m_Fog = m_Fog;
  1170. data.m_Clouds = m_Clouds;
  1171. }
  1172. #endif
  1173. string GetDebugMessage()
  1174. {
  1175. string message;
  1176. message += "Player stats";
  1177. message += "\nHeat comfort(target): " + GetTargetHeatComfort().ToString();
  1178. message += "\nHeat comfort(dynamic): " + m_HeatComfort.ToString();
  1179. int liquidType;
  1180. string impact, surfaceType;
  1181. g_Game.SurfaceUnderObjectExCorrectedLiquid(m_Player, surfaceType, impact, liquidType);
  1182. message += "\nInside: " + IsInsideBuilding().ToString();
  1183. message += "\nSurface: " + surfaceType;
  1184. message += "\nLiquid: " + liquidType;
  1185. message += "\nUnder roof: " + m_IsUnderRoof.ToString() + " (" + GetNextRoofCheck() + ")";
  1186. if (IsWaterContact() && m_WaterLevel > WATER_LEVEL_NONE)
  1187. {
  1188. message += "\nWater Level: " + m_WaterLevel;
  1189. }
  1190. message += "\n\nWeather stats";
  1191. message += "\nEnv temperature (base): " + m_WorldData.GetBaseEnvTemperature().ToString();
  1192. message += "\nEnv temperature (height corrected): " + m_WorldData.GetBaseEnvTemperatureAtObject(m_Player);
  1193. message += "\nEnv temperature (modified): " + m_EnvironmentTemperature.ToString();
  1194. message += "\nWind: " + m_Wind.ToString() + " (x" + GetWindModifierPerSurface() + ")";
  1195. message += "\nRain: " + m_Rain.ToString();
  1196. message += "\nSnow: " + m_Snowfall.ToString();
  1197. message += "\nDatetime: " + WorldDataDaytime.ToString(m_DayOrNight);
  1198. message += "\nFog: " + m_Fog.ToString();
  1199. message += "\nClouds: " + m_Clouds.ToString();
  1200. message += "\nWet delta: " + GetWetDelta().ToString();
  1201. return message;
  1202. }
  1203. int GetNextRoofCheck()
  1204. {
  1205. return (GameConstants.ENVIRO_TICK_ROOF_RC_CHECK - m_RoofCheckTimer) + 1;
  1206. }
  1207. float GetWaterLevel()
  1208. {
  1209. if (IsWaterContact() && m_WaterLevel > WATER_LEVEL_NONE)
  1210. {
  1211. return m_WaterLevel;
  1212. }
  1213. return 0.0;
  1214. }
  1215. private bool IsNeutralTemperature(float temperature, float lowerLimit = GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT, float upperLimit = GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT)
  1216. {
  1217. if (temperature >= lowerLimit && temperature <= upperLimit)
  1218. return true;
  1219. return false;
  1220. }
  1221. private float NormalizedTemperature(float temperature, float lowerLimit = GameConstants.ENVIRO_LOW_TEMP_LIMIT, float upperLimit = GameConstants.ENVIRO_HIGH_TEMP_LIMIT)
  1222. {
  1223. if (temperature >= GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT && temperature <= GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT)
  1224. return 0.0;
  1225. if (temperature < GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT)
  1226. return Math.Clamp(Math.InverseLerp(lowerLimit, GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT, temperature), -1.0, -0.1);
  1227. if (temperature > GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT)
  1228. return Math.Clamp(Math.InverseLerp(GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT, upperLimit, temperature), 0.1, 1.0);
  1229. // neutral zone
  1230. return 0.0;
  1231. }
  1232. private void LogDryWetProcess(string message, bool indented = false)
  1233. {
  1234. #ifdef DIAG_DEVELOPER
  1235. if (m_DebugLogDryWet)
  1236. {
  1237. string indentation = "";
  1238. if (indented)
  1239. indentation = "|--";
  1240. Debug.Log(string.Format("%1 %2", indentation, message));
  1241. }
  1242. #endif
  1243. }
  1244. private void LogItemHeat(string message, bool indented = false)
  1245. {
  1246. #ifdef DIAG_DEVELOPER
  1247. if (m_DebugLogItemHeat)
  1248. {
  1249. string indentation = "";
  1250. if (indented)
  1251. indentation = "|--";
  1252. Debug.Log(string.Format("%1 %2", indentation, message));
  1253. }
  1254. #endif
  1255. }
  1256. //! DEPRECATED
  1257. protected float m_HeatSourceTemp;
  1258. protected ref SimpleMovingAverage<float> m_WindAverageBuffer;
  1259. void Init(PlayerBase pPlayer)
  1260. {
  1261. Init();
  1262. }
  1263. protected bool OverridenHeatComfort(out float value);
  1264. void AddToEnvironmentTemperature(float pTemperature);
  1265. protected void ProcessItemsHeat()
  1266. {
  1267. // for backward combatibility only
  1268. ProcessHeatComfort();
  1269. }
  1270. protected void ProcessWetnessByRain()
  1271. {
  1272. ProcessItemsWetness(m_SlotIdsComplete);
  1273. }
  1274. // Returns amount of deg C air temperature should be lowered by, based on player's height above water level
  1275. float GetTemperatureHeightCorrection()
  1276. {
  1277. float temperature_reduction = Math.Max(0, (m_PlayerHeightPos * m_WorldData.m_TemperaturePerHeightReductionModifier));
  1278. return temperature_reduction;
  1279. }
  1280. //! returns weighted avg heat comfort for bodypart
  1281. protected void BodyPartHeatProperties(array<int> pBodyPartIds, float pCoef, out float pHeatComfort, out float pHeat)
  1282. {
  1283. pHeatComfort = 0;
  1284. pHeat = 0;
  1285. if (pBodyPartIds.Count() > 0)
  1286. {
  1287. LogItemHeat(string.Format("BodyPartHeatProperties (%1)", EnumTools.EnumToString(InventorySlots, pBodyPartIds[0])));
  1288. int attCount = m_Player.GetInventory().AttachmentCount();
  1289. for (int attIdx = 0; attIdx < attCount; ++attIdx)
  1290. {
  1291. EntityAI attachment = m_Player.GetInventory().GetAttachmentFromIndex(attIdx);
  1292. if (attachment.IsClothing())
  1293. {
  1294. ItemBase item = ItemBase.Cast(attachment);
  1295. int attachmentSlot = attachment.GetInventory().GetSlotId(0);
  1296. //! go through all body parts we've defined for that zone (ex.: head, body, feet)
  1297. for (int i = 0; i < pBodyPartIds.Count(); ++i)
  1298. {
  1299. if (attachmentSlot == pBodyPartIds[i])
  1300. {
  1301. float heatIsoMult = 1.0;
  1302. if (attachmentSlot == InventorySlots.BACK)
  1303. heatIsoMult = GameConstants.ENVIRO_HEATISOLATION_BACK_WEIGHT;
  1304. else if (attachmentSlot == InventorySlots.VEST)
  1305. heatIsoMult = GameConstants.ENVIRO_HEATISOLATION_VEST_WEIGHT;
  1306. pHeatComfort += heatIsoMult * MiscGameplayFunctions.GetCurrentItemHeatIsolation(item);
  1307. float itemHeatcomfort = 0;
  1308. float itemTemperature = 0;
  1309. // go through any attachments and cargo (only current level, ignore nested containers - they isolate)
  1310. int inventoryAttCount = item.GetInventory().AttachmentCount();
  1311. if (inventoryAttCount > 0)
  1312. {
  1313. LogItemHeat(string.Format("attachments:"), false);
  1314. for (int inAttIdx = 0; inAttIdx < inventoryAttCount; ++inAttIdx)
  1315. {
  1316. EntityAI inAttachment = item.GetInventory().GetAttachmentFromIndex(inAttIdx);
  1317. ItemBase attachmentItem = ItemBase.Cast(inAttachment);
  1318. if (attachmentItem && attachmentItem.CanHaveTemperature())
  1319. {
  1320. itemTemperature = attachmentItem.GetTemperature();
  1321. if (itemTemperature < GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT || itemTemperature > GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT)
  1322. {
  1323. itemHeatcomfort = NormalizedTemperature(itemTemperature) * attachmentItem.GetQuantityNormalizedScripted() * attachmentItem.GetTemperaturePerQuantityWeight();
  1324. LogItemHeat(string.Format("%1: temperature=%2 heat=%3", attachmentItem, itemTemperature, pHeat), true);
  1325. pHeat += itemHeatcomfort;
  1326. }
  1327. }
  1328. }
  1329. }
  1330. if (item.GetInventory().GetCargo())
  1331. {
  1332. int inventoryItemCount = item.GetInventory().GetCargo().GetItemCount();
  1333. if (inventoryItemCount > 0)
  1334. {
  1335. LogItemHeat(string.Format("cargo:"), false);
  1336. for (int j = 0; j < inventoryItemCount; ++j)
  1337. {
  1338. ItemBase inventoryItem = ItemBase.Cast(item.GetInventory().GetCargo().GetItem(j));
  1339. if (inventoryItem && inventoryItem.CanHaveTemperature())
  1340. {
  1341. itemTemperature = inventoryItem.GetTemperature();
  1342. if (itemTemperature < GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT || itemTemperature > GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT)
  1343. {
  1344. itemHeatcomfort = NormalizedTemperature(itemTemperature) * inventoryItem.GetQuantityNormalizedScripted() * inventoryItem.GetTemperaturePerQuantityWeight();
  1345. LogItemHeat(string.Format("%1: temperature=%2 heat=%3", inventoryItem, itemTemperature, itemHeatcomfort), true);
  1346. pHeat += itemHeatcomfort;
  1347. }
  1348. }
  1349. }
  1350. }
  1351. }
  1352. }
  1353. }
  1354. }
  1355. }
  1356. pHeatComfort += (pHeatComfort / pBodyPartIds.Count()) * pCoef;
  1357. LogItemHeat(string.Format("overall heat from items=%1 (coef applied)", pHeat));
  1358. LogItemHeat("");
  1359. }
  1360. }
  1361. float GetDayOrNight()
  1362. {
  1363. return m_DayOrNight;
  1364. }
  1365. }
  1366. class EnvironmentDrynessData
  1367. {
  1368. bool m_UseTemperatureSources = false;
  1369. float m_TemperatureSourceDistance = 1.0;
  1370. }
  1371. #ifdef DIAG_DEVELOPER
  1372. class EnvDebugPlayerData : Param
  1373. {
  1374. float m_HeatComfortDynamic;
  1375. float m_HeatComfortTarget;
  1376. bool m_Inside;
  1377. string m_Surface;
  1378. bool m_UnderRoof;
  1379. int m_UnderRoofTimer;
  1380. float m_WaterLevel;
  1381. void Synch(Environment env, PlayerBase player)
  1382. {
  1383. m_HeatComfortTarget = env.GetTargetHeatComfort();
  1384. m_HeatComfortDynamic = player.GetStatHeatComfort().Get();
  1385. m_Inside = env.IsInsideBuilding();
  1386. m_Surface = player.GetSurfaceType();
  1387. m_UnderRoof = env.IsUnderRoof();
  1388. m_UnderRoofTimer = env.GetNextRoofCheck();
  1389. m_WaterLevel = env.GetWaterLevel();
  1390. }
  1391. override bool Serialize(Serializer ctx)
  1392. {
  1393. return (
  1394. ctx.Write(m_HeatComfortTarget) && ctx.Write(m_HeatComfortDynamic) && ctx.Write(m_Inside) && ctx.Write(m_Surface) && ctx.Write(m_UnderRoof) && ctx.Write(m_UnderRoofTimer) && ctx.Write(m_WaterLevel));
  1395. }
  1396. override bool Deserializer(Serializer ctx)
  1397. {
  1398. return ctx.Write(m_HeatComfortTarget) && ctx.Read(m_HeatComfortDynamic) && ctx.Read(m_Inside) && ctx.Read(m_Surface) && ctx.Read(m_UnderRoof) && ctx.Read(m_UnderRoofTimer) && ctx.Read(m_WaterLevel);
  1399. }
  1400. }
  1401. class EnvDebugMiscData : Param
  1402. {
  1403. float m_TemperatureBase;
  1404. float m_TemperatureModified;
  1405. float m_HeightCorrectedTemperature;
  1406. float m_WetDelta;
  1407. void Synch(Environment env)
  1408. {
  1409. m_TemperatureBase = g_Game.GetMission().GetWorldData().GetBaseEnvTemperature();
  1410. m_TemperatureModified = env.GetTemperature();
  1411. m_HeightCorrectedTemperature = m_TemperatureBase - env.GetTemperatureHeightCorrection();
  1412. m_WetDelta = env.GetWetDelta();
  1413. }
  1414. override bool Serialize(Serializer ctx)
  1415. {
  1416. return ctx.Write(m_TemperatureBase) && ctx.Write(m_TemperatureModified) && ctx.Write(m_HeightCorrectedTemperature) && ctx.Write(m_WetDelta);
  1417. }
  1418. override bool Deserializer(Serializer ctx)
  1419. {
  1420. return ctx.Read(m_TemperatureBase) && ctx.Read(m_TemperatureModified) && ctx.Read(m_HeightCorrectedTemperature) && ctx.Read(m_WetDelta);
  1421. }
  1422. }
  1423. class EnvDebugWeatherData : Param
  1424. {
  1425. float m_Wind;
  1426. float m_WindModifier;
  1427. float m_Rain;
  1428. float m_Snowfall;
  1429. float m_Fog;
  1430. float m_Clouds;
  1431. void Synch(Environment env)
  1432. {
  1433. env.FillDebugWeatherData(this);
  1434. }
  1435. override bool Serialize(Serializer ctx)
  1436. {
  1437. return ctx.Write(m_Wind) && ctx.Write(m_WindModifier) && ctx.Write(m_Rain) && ctx.Write(m_Snowfall) && ctx.Write(m_Fog) && ctx.Write(m_Clouds);
  1438. }
  1439. override bool Deserializer(Serializer ctx)
  1440. {
  1441. return ctx.Read(m_Wind) && ctx.Read(m_WindModifier) && ctx.Read(m_Rain) && ctx.Read(m_Snowfall) && ctx.Read(m_Fog) && ctx.Read(m_Clouds);
  1442. }
  1443. }
  1444. class EnvDebugData : Param
  1445. {
  1446. ref EnvDebugPlayerData m_PlayerData = new EnvDebugPlayerData();
  1447. ref EnvDebugMiscData m_MiscData = new EnvDebugMiscData();
  1448. ref EnvDebugWeatherData m_WeatherData = new EnvDebugWeatherData();
  1449. void Synch(Environment env, PlayerBase player)
  1450. {
  1451. m_PlayerData.Synch(env, player);
  1452. m_MiscData.Synch(env);
  1453. m_WeatherData.Synch(env);
  1454. }
  1455. override bool Serialize(Serializer ctx)
  1456. {
  1457. return m_PlayerData.Serialize(ctx) && m_MiscData.Serialize(ctx) && m_WeatherData.Serialize(ctx);
  1458. }
  1459. override bool Deserializer(Serializer ctx)
  1460. {
  1461. return m_PlayerData.Deserializer(ctx) && m_MiscData.Deserializer(ctx) && m_WeatherData.Deserializer(ctx);
  1462. }
  1463. }
  1464. #endif