worlddata.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. //! Keeps information about currently loaded world, like temperature
  2. class WorldData
  3. {
  4. const float SPAWN_CHANCE_CHOLERA_DEF = 50;
  5. const float COLD_AREA_TOOL_DMG_MODIF_DEF = 1;
  6. //! directly accesible (defined/overriden in Init())
  7. float m_TemperaturePerHeightReductionModifier; //! amount of °C reduced for each 100 meteres of height above water level
  8. float m_CloudsTemperatureEffectModifier; //! how many % of environment temperature can be lowered by clouds
  9. float m_TemperatureInsideBuildingsModifier;
  10. float m_WaterContactTemperatureModifier;
  11. protected float SUDDENCHANGE_TIME_MULTIPLIER = 0.2;
  12. protected float SUDDENCHANGE_LENGTH_MULTIPLIER = 0.4;
  13. protected float WIND_MAGNITUDE_TIME_MULTIPLIER = 0.1;
  14. protected float WIND_DIRECTION_TIME_MULTIPLIER = 0.05;
  15. protected Weather m_Weather;
  16. protected float m_EnvironmentTemperature;
  17. protected bool m_EnTempUpdated;
  18. protected float m_Timer;
  19. protected float m_MaxTemps[12];
  20. protected float m_MinTemps[12];
  21. protected float m_Sunrise_Jan;
  22. protected float m_Sunset_Jan;
  23. protected float m_Sunrise_Jul;
  24. protected float m_Sunset_Jul;
  25. protected ref array<vector> m_FiringPos; // Where we should fire from. On Init set the relevant data
  26. protected bool m_Pollution;
  27. protected ref CatchYieldBank m_YieldBank;
  28. protected ref WorldDataWeatherSettings m_WeatherDefaultSettings;
  29. protected ref WorldDataLiquidSettings m_LiquidSettings;
  30. protected ref TStringArray m_DefaultPlayerRestrictedAreas;
  31. //! weather related
  32. protected int m_BadWeatherChance;
  33. protected int m_ClearWeatherChance;
  34. protected bool m_IsSuddenChange;
  35. protected float m_WorldWindCoef;
  36. protected float m_UniversalTemperatureSourceCapModifier;
  37. //used at next weather calculation
  38. protected int m_SameWeatherCnt = 0;
  39. protected int m_StepValue = 5;
  40. protected int m_Chance = 50;
  41. protected int m_ChoosenWeather = 1;
  42. protected int m_LastWeather = 0;
  43. void WorldData()
  44. {
  45. Init();
  46. CreateYieldBank();
  47. InitYieldBank();
  48. UpdateBaseEnvTemperature(0);
  49. }
  50. void Init()
  51. {
  52. SetupWeatherSettings();
  53. SetupLiquidTemperatures();
  54. m_EnTempUpdated = false;
  55. m_Weather = g_Game.GetWeather();
  56. m_EnvironmentTemperature = 12.0;
  57. m_Timer = 0.0;
  58. m_Sunrise_Jan = 8.54;
  59. m_Sunset_Jan = 15.52;
  60. m_Sunrise_Jul = 3.26;
  61. m_Sunset_Jul = 20.73;
  62. m_MaxTemps = {3,5,7,14,19,24,26,25,21,16,10,5};
  63. m_MinTemps = {-3,-2,0,4,9,14,18,17,12,7,4,0};
  64. m_Pollution = EPollution.NONE;
  65. m_WorldWindCoef = 0.5;
  66. m_UniversalTemperatureSourceCapModifier = 0.0;
  67. m_TemperaturePerHeightReductionModifier = 0.02;
  68. m_CloudsTemperatureEffectModifier = 3.0;
  69. m_TemperatureInsideBuildingsModifier = 1.0;
  70. m_WaterContactTemperatureModifier = 20.0;
  71. m_ClearWeatherChance = m_WeatherDefaultSettings.m_ClearWeatherChance;
  72. m_BadWeatherChance = m_WeatherDefaultSettings.m_BadWeatherChance;
  73. m_DefaultPlayerRestrictedAreas = {};
  74. }
  75. float GetApproxSunriseTime( float monthday )
  76. {
  77. if ( monthday <= 8.0 )
  78. return ( ( m_Sunrise_Jan - m_Sunrise_Jul ) / ( 8 - 1 ) ) * ( 1 - monthday ) + m_Sunrise_Jan;
  79. else
  80. return ( ( ( monthday - 8 ) * ( m_Sunrise_Jan - m_Sunrise_Jul ) ) / ( 13 - 8 ) ) + m_Sunrise_Jul;
  81. }
  82. float GetApproxSunsetTime( float monthday )
  83. {
  84. if ( monthday <= 8.0 )
  85. return ( ( m_Sunset_Jan - m_Sunset_Jul ) / (8 - 1) ) * ( 1 - monthday ) + m_Sunset_Jan;
  86. else
  87. return ( ( ( monthday - 8 ) * ( m_Sunset_Jan - m_Sunset_Jul ) ) / ( 13 - 8 ) ) + m_Sunset_Jul;
  88. }
  89. int GetDaytime()
  90. {
  91. int year, month, day, hour, minute;
  92. GetGame().GetWorld().GetDate(year, month, day, hour, minute);
  93. float sunriseTimeStart = g_Game.GetMission().GetWorldData().GetApproxSunriseTime(month);
  94. float sunsetTimeStart = g_Game.GetMission().GetWorldData().GetApproxSunsetTime(month);
  95. if (hour >= sunriseTimeStart && hour < (sunriseTimeStart + 2))
  96. return WorldDataDaytime.DAWN;
  97. else if (hour >= (sunriseTimeStart + 2) && hour < sunsetTimeStart)
  98. return WorldDataDaytime.DAY;
  99. else if (hour >= sunsetTimeStart && hour < (sunsetTimeStart + 2))
  100. return WorldDataDaytime.DUSK;
  101. return WorldDataDaytime.NIGHT;
  102. }
  103. protected float CalcBaseEnvironmentTemperature( float monthday, float daytime )
  104. {
  105. float approxSunrise = GetApproxSunriseTime( monthday );
  106. float approxSunset = GetApproxSunsetTime( monthday );
  107. float dayLight = approxSunset - approxSunrise;
  108. float nightTime = 24.0 - dayLight;
  109. int tempArrayIndex = Math.Floor(monthday) - 1;
  110. int tempArrayIndexToLerp = tempArrayIndex + 1;
  111. if ( tempArrayIndexToLerp >= 12 )
  112. tempArrayIndexToLerp = 0;
  113. float tempArrayLerp = monthday - Math.Floor(monthday);
  114. float minTempA = m_MinTemps[tempArrayIndex];
  115. float minTempB = m_MinTemps[tempArrayIndexToLerp];
  116. float maxTempA = m_MaxTemps[tempArrayIndex];
  117. float maxTempB = m_MaxTemps[tempArrayIndexToLerp];
  118. float eveningMinA = minTempA + ( 0.5 * Math.AbsFloat( minTempA - maxTempA ) );
  119. float eveningMinB = minTempB + ( 0.5 * Math.AbsFloat( minTempB - maxTempB ) );
  120. if ( ( daytime >= approxSunrise ) && ( daytime <= approxSunset ) ) {
  121. if ( daytime <= ( approxSunrise + ( dayLight * 0.75 ) ) )
  122. return Math.Lerp(
  123. Math.Lerp( minTempA, minTempB, tempArrayLerp ),
  124. Math.Lerp( maxTempA, maxTempB, tempArrayLerp ),
  125. ( ( daytime - approxSunrise ) / ( dayLight * 0.75 ) ) );
  126. else
  127. return Math.Lerp(
  128. Math.Lerp( maxTempA, maxTempB, tempArrayLerp ),
  129. Math.Lerp( eveningMinA, eveningMinB, tempArrayLerp ),
  130. ( ( ( daytime - approxSunrise ) - ( dayLight * 0.75 ) ) / ( dayLight - ( dayLight * 0.75 ) ) ) );
  131. } else {
  132. if ( ( daytime > approxSunset ) && ( daytime < 24 ) )
  133. return Math.Lerp(
  134. Math.Lerp( eveningMinA, eveningMinB, tempArrayLerp ),
  135. Math.Lerp( minTempA, minTempB, tempArrayLerp ),
  136. ( ( daytime - approxSunset ) / ( 24 - approxSunset ) ) / 2.0 );
  137. else
  138. return Math.Lerp(
  139. Math.Lerp( eveningMinA, eveningMinB, tempArrayLerp ),
  140. Math.Lerp( minTempA, minTempB, tempArrayLerp ),
  141. ( ( ( daytime + ( 24 - approxSunset ) ) / nightTime ) / 2.0 ) + 0.5 );
  142. }
  143. }
  144. void UpdateBaseEnvTemperature(float timeslice)
  145. {
  146. m_Timer += timeslice;
  147. if (m_Timer > 30 || !m_EnTempUpdated)
  148. {
  149. int year, month, day, hour, minute;
  150. GetGame().GetWorld().GetDate( year, month, day, hour, minute );
  151. m_EnvironmentTemperature = CalcBaseEnvironmentTemperature( month + ( day / 32.0 ), hour + ( minute / 60.0 ) );
  152. m_Timer = 0;
  153. if (!m_EnTempUpdated)
  154. m_EnTempUpdated = true;
  155. }
  156. }
  157. /*!
  158. \brief Updates *local* weather effects.
  159. \param weather Weather instance
  160. \param timeslice Time delta since last update
  161. */
  162. void UpdateWeatherEffects( Weather weather, float timeslice )
  163. {
  164. float snowflakeScale = ComputeSnowflakeScale( weather );
  165. weather.SetSnowflakeScale( snowflakeScale );
  166. }
  167. /*!
  168. \brief Returns the desired snowflake scale based on weather simulation state.
  169. \param weather Weather instance
  170. */
  171. float ComputeSnowflakeScale( Weather weather )
  172. {
  173. float overcast01 = Math.Clamp( Math.InverseLerp( 0.4, 1.0, weather.GetOvercast().GetActual() ), 0.0, 1.0 ); // remap range to <0.4, 1.0> snowfall overcast threshold
  174. float wind01 = weather.GetWindSpeed() / weather.GetWindMaximumSpeed();
  175. float overcastScale = Math.Lerp( 0.50, 1.25, overcast01 );
  176. float windScale = Math.Lerp( 1.25, 1.00, wind01 );
  177. return Math.Clamp( overcastScale * windScale, 0.50, 1.25 );
  178. }
  179. // getter for the new base enviro temperature
  180. float GetBaseEnvTemperature()
  181. {
  182. return m_EnvironmentTemperature;
  183. }
  184. float GetBaseEnvTemperatureAtObject(notnull Object object)
  185. {
  186. return GetBaseEnvTemperatureAtPosition(object.GetPosition());
  187. }
  188. float GetBaseEnvTemperatureAtPosition(vector pos)
  189. {
  190. float terrainHeight = pos[1];
  191. float heightCorrection = Math.Max(0, (terrainHeight * m_TemperaturePerHeightReductionModifier));
  192. return m_EnvironmentTemperature - heightCorrection;
  193. }
  194. float GetBaseEnvTemperatureExact(int month, int day, int hour, int minute)
  195. {
  196. return CalcBaseEnvironmentTemperature( month + ( day / 32.0 ), hour + ( minute / 60.0 ) );
  197. }
  198. float GetLiquidTypeEnviroTemperature(int liquidType)
  199. {
  200. if (m_LiquidSettings.m_Temperatures.Count() > 0 && m_LiquidSettings.m_Temperatures.Contains(liquidType) != INDEX_NOT_FOUND)
  201. return m_LiquidSettings.m_Temperatures.Get(liquidType);
  202. #ifdef DEVELOPER
  203. ErrorEx("Undefined enviro temperature for liquid type: " + liquidType);
  204. #endif
  205. return m_EnvironmentTemperature;
  206. }
  207. bool WeatherOnBeforeChange( EWeatherPhenomenon type, float actual, float change, float time )
  208. {
  209. // default behaviour is same like setting MissionWeather (in Weather) to true
  210. return false;
  211. }
  212. // Used to return the artillery firing positions
  213. array<vector> GetArtyFiringPos()
  214. {
  215. return m_FiringPos;
  216. }
  217. // Returns chance percentage for selected agent to spawn, used with spawned loot
  218. float GetAgentSpawnChance(eAgents agent)
  219. {
  220. if (agent == eAgents.CHOLERA)
  221. return SPAWN_CHANCE_CHOLERA_DEF;
  222. return 0;
  223. }
  224. // Returns modifier which is added to the tool damage logic when player is in cold area
  225. float GetColdAreaToolDamageModifier()
  226. {
  227. return COLD_AREA_TOOL_DMG_MODIF_DEF;
  228. }
  229. // debug
  230. void BaseTempDebug(int month, int day)
  231. {
  232. Print("--------------------");
  233. for ( int i = 0; i < 24; i++ )
  234. {
  235. for ( int j = 0; j < 6; j++ )
  236. {
  237. int minute = ( j * 10 );
  238. Print(string.Format( "%1:%2 %3", i, minute, GetBaseEnvTemperatureExact( month, day, i, minute ) ) );
  239. }
  240. }
  241. }
  242. int GetPollution()
  243. {
  244. return m_Pollution;
  245. }
  246. float GetWindCoef()
  247. {
  248. return m_WorldWindCoef;
  249. }
  250. float GetUniversalTemperatureSourceCapModifier()
  251. {
  252. return m_UniversalTemperatureSourceCapModifier;
  253. }
  254. /*!
  255. \brief Return actual temperature of environment based on provided parameters
  256. \param object Reference to object that is used mainly for sea height related calculation
  257. \param properties Flag made of EEnvironmentTemperatureComponent which will influence the resulting value of temperature based on combination of the parts
  258. */
  259. float GetTemperature(Object object, EEnvironmentTemperatureComponent properties = EEnvironmentTemperatureComponent.BASE)
  260. {
  261. // EEnvironmentTemperatureComponent.BASE only
  262. float temperature = GetBaseEnvTemperature();
  263. if (object && properties & EEnvironmentTemperatureComponent.ALTITUDE)
  264. temperature = GetBaseEnvTemperatureAtObject(object);
  265. if (properties & EEnvironmentTemperatureComponent.OVERCAST)
  266. temperature += m_Weather.GetOvercast().GetActual() * m_CloudsTemperatureEffectModifier;
  267. if (properties & EEnvironmentTemperatureComponent.WIND)
  268. temperature += WindEffectTemperatureValue(temperature);
  269. if (properties & EEnvironmentTemperatureComponent.FOG)
  270. temperature += m_Weather.GetFog().GetActual() * GameConstants.ENVIRO_FOG_TEMP_EFFECT;
  271. return temperature;
  272. }
  273. /*!
  274. \brief Return value of queried EEnvironmentTemperatureComponent which can be used in future calculation(s)
  275. \param temperature Base temperature which will be used in component calculation (currently WIND only)
  276. \param properties Flag made of EEnvironmentTemperatureComponent which will influence the resulting value of temperature based on combination of the parts
  277. */
  278. float GetTemperatureComponentValue(float temperatureIn, EEnvironmentTemperatureComponent properties = 0)
  279. {
  280. float temperatureOut = 0.0;
  281. if ((properties & EEnvironmentTemperatureComponent.OVERCAST) == EEnvironmentTemperatureComponent.OVERCAST)
  282. temperatureOut = m_Weather.GetOvercast().GetActual() * m_CloudsTemperatureEffectModifier;
  283. else if ((properties & EEnvironmentTemperatureComponent.WIND) == EEnvironmentTemperatureComponent.WIND)
  284. temperatureOut = WindEffectTemperatureValue(temperatureIn);
  285. else if ((properties & EEnvironmentTemperatureComponent.FOG) == EEnvironmentTemperatureComponent.FOG)
  286. temperatureOut = m_Weather.GetFog().GetActual() * GameConstants.ENVIRO_FOG_TEMP_EFFECT;
  287. else
  288. {
  289. Debug.Log(string.Format("Only OVERCAST, WIND and FOG parameters are supported"));
  290. }
  291. return temperatureOut;
  292. }
  293. protected float WindEffectTemperatureValue(float temperatureInput)
  294. {
  295. float temperatureOutput = 0.0;
  296. temperatureOutput = (temperatureInput - GameConstants.ENVIRO_WIND_CHILL_LIMIT) / (GameConstants.ENVIRO_WIND_EFFECT_SLOPE - GameConstants.ENVIRO_WIND_CHILL_LIMIT);
  297. temperatureOutput = temperatureOutput * m_Weather.GetWindMagnitude().GetActual() * GetWindCoef();
  298. return -temperatureOutput;
  299. }
  300. protected void CalculateWind(int newWeather, bool suddenChange, out float magnitude, out float direction);
  301. protected void CalculateVolFog(float lerpValue, float windMagnitude, float changeTime);
  302. protected void CreateYieldBank()
  303. {
  304. m_YieldBank = new CatchYieldBank();
  305. }
  306. //! override this to properly register world-specific yields
  307. protected void InitYieldBank()
  308. {
  309. GetDayZGame().GetYieldDataInitInvoker().Invoke(m_YieldBank); //injects defaults from 4_World and above
  310. }
  311. protected void SetupWeatherSettings()
  312. {
  313. m_WeatherDefaultSettings = new WorldDataWeatherSettings();
  314. }
  315. protected void SetupLiquidTemperatures()
  316. {
  317. m_LiquidSettings = new WorldDataLiquidSettings();
  318. m_LiquidSettings.m_Temperatures[LIQUID_SALTWATER] = 23.0;
  319. m_LiquidSettings.m_Temperatures[LIQUID_WATER] = 15.0;
  320. m_LiquidSettings.m_Temperatures[LIQUID_STILLWATER] = 15.0;
  321. m_LiquidSettings.m_Temperatures[LIQUID_RIVERWATER] = 15.0;
  322. m_LiquidSettings.m_Temperatures[LIQUID_FRESHWATER] = 15.0;
  323. m_LiquidSettings.m_Temperatures[LIQUID_CLEANWATER] = 10.0;
  324. m_LiquidSettings.m_Temperatures[LIQUID_SNOW] = -5.0;
  325. }
  326. CatchYieldBank GetCatchYieldBank()
  327. {
  328. return m_YieldBank;
  329. }
  330. TStringArray GetDefaultPRAPaths()
  331. {
  332. return m_DefaultPlayerRestrictedAreas;
  333. }
  334. //!
  335. //! DEPRECATED
  336. //!
  337. protected float m_DayTemperature = 10; // legacy, no longer used
  338. protected float m_NightTemperature = 6; // legacy, no longer used
  339. float GetDayTemperature()
  340. {
  341. return m_DayTemperature;
  342. }
  343. float GetNightTemperature()
  344. {
  345. return m_NightTemperature;
  346. }
  347. }
  348. class WorldDataWeatherConstants
  349. {
  350. const int CLEAR_WEATHER = 1;
  351. const int CLOUDY_WEATHER = 2;
  352. const int BAD_WEATHER = 3;
  353. }
  354. class WorldDataWeatherSettings
  355. {
  356. int m_OvercastMinTime = 600;
  357. int m_OvercastMaxTime = 900;
  358. int m_OvercastMinLength = 600;
  359. int m_OvercastMaxLength = 900;
  360. float m_RainThreshold = 0.6;
  361. int m_RainTimeMin = 60;
  362. int m_RainTimeMax = 120;
  363. int m_RainLengthMin = 60;
  364. int m_RainLengthMax = 120;
  365. float m_StormThreshold = 0.85;
  366. float m_ThundersnowThreshold = 0.98;
  367. float m_SnowfallThreshold = 0.3;
  368. int m_SnowfallTimeMin = 60;
  369. int m_SnowfallTimeMax = 120;
  370. int m_SnowfallLengthMin = 150;
  371. int m_SnowfallLengthMax = 300;
  372. int m_GlobalSuddenChance = 95;
  373. int m_ClearWeatherChance = 30;
  374. int m_BadWeatherChance = 80;
  375. int m_BadWeatherSuddenChance = 95;
  376. int m_FoggyMorningHeigthBiasLowLimit = 155;
  377. int m_DefaultHeigthBias = 170;
  378. int m_CalmAfterStormTimeMin = 480;
  379. int m_CalmAfterStormTimeMax = 600;
  380. }
  381. class WorldDataLiquidSettings
  382. {
  383. ref map<int, float> m_Temperatures = new map<int, float>();
  384. }
  385. class WorldDataDaytime
  386. {
  387. static int ANY = -1;
  388. static int NIGHT = 0;
  389. static int DAY = 1;
  390. static int DUSK = 2;
  391. static int DAWN = 3;
  392. static string ToString(int value)
  393. {
  394. switch (value)
  395. {
  396. case NIGHT:
  397. return "NIGHT";
  398. case DAY:
  399. return "DAY";
  400. case DUSK:
  401. return "DUSK";
  402. case DAWN:
  403. return "DAWN";
  404. }
  405. return "ANYTIME";
  406. }
  407. }