dayzplayerimplementaiming.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. DayZPlayerImplement
  3. this file is implemenation of dayzPlayer in script
  4. - logic of movement
  5. - camera switching logic
  6. */
  7. enum eSwayStates
  8. {
  9. DEFAULT,
  10. HOLDBREATH_IN,
  11. HOLDBREATH_STABLE,
  12. HOLDBREATH_EXHAUSTED,
  13. MAX
  14. }
  15. class PlayerSwayConstants
  16. {
  17. static const float SWAY_MULTIPLIER_DEFAULT = 1.0;
  18. static const float SWAY_MULTIPLIER_STABLE = 0.05;
  19. static const float SWAY_MULTIPLIER_EXHAUSTED = 0.6;
  20. static const float SWAY_TIME_IN = 1.5;
  21. static const float SWAY_TIME_STABLE = 3.0;
  22. static const float SWAY_TIME_EXHAUSTED = 1.5;
  23. static const float SWAY_TIME_OUT = 0.5;
  24. static const float SWAY_ROLL = 3;
  25. static const float HOLD_BREATH_STAMINA_THRESHOLD = 0.5; //! at which point does the stabilization start to get affected
  26. }
  27. class DayZPlayerImplementAiming
  28. {
  29. //-------------------------------------------------------------
  30. //!
  31. //! This HeadingModel - Clamps heading
  32. //!
  33. protected const float SWAY_WEIGHT_SCALER = 1;//use this to scale the sway effect up/down
  34. protected float m_HorizontalNoise;
  35. protected float m_HorizontalTargetValue;
  36. protected float m_HorizontalNoiseVelocity[1] = {0};
  37. protected DayZPlayerImplement m_PlayerDpi;
  38. protected PlayerBase m_PlayerPb;
  39. protected float m_TotalTime;
  40. protected float m_ReferenceTime = 0;
  41. protected float m_StaminaPercentage; //! stamina percentage at hold breath start
  42. protected float m_HoldBreathSwayCoef = 1.0; //! proportionally shortens de/stabilization process and duration. Also affects stamina consumption (temporary!)
  43. protected float m_SwayStateStartTime;
  44. //protected float m_SwayStateStartTime[eSwayStates.MAX];
  45. protected float m_LastSwayMultiplier = PlayerSwayConstants.SWAY_MULTIPLIER_DEFAULT;
  46. protected float m_StateStartSwayMultiplier;
  47. protected float m_HorizontalNoiseXAxisOffset;
  48. protected float m_BreathingXAxisOffset;
  49. protected float m_BreathingYAxisOffset;
  50. protected bool m_HoldingBreathSet;
  51. protected bool m_AimNoiseAllowed = true;
  52. protected bool m_ProceduralRecoilEnabled = true;
  53. protected ref RecoilBase m_CurrentRecoil;
  54. protected int m_ShakeCount;
  55. protected float m_SwayWeight;
  56. protected float m_MaxVelocity;
  57. protected ref KuruShake m_KuruShake;
  58. protected float m_CamShakeX;
  59. protected float m_CamShakeY;
  60. protected vector m_SwayModifier = "1 1 1";//"max_speed_noise radius_noise overall_speed"
  61. protected int m_SwayState = -1;
  62. protected float m_StealthAimY_Last;
  63. protected float m_FilterVelocityStealthAimY[1] = {0};
  64. protected static float m_AimXClampRanges[] = { -180, -20, 90, 0, -50, 90, 180, -20, 90 };
  65. void DayZPlayerImplementAiming(DayZPlayerImplement player)
  66. {
  67. m_PlayerDpi = player;
  68. Class.CastTo(m_PlayerPb, player);
  69. UpdateSwayState(eSwayStates.DEFAULT);
  70. }
  71. void SetRecoil(Weapon_Base weapon)
  72. {
  73. if (m_ProceduralRecoilEnabled)
  74. {
  75. m_CurrentRecoil = weapon.SpawnRecoilObject();
  76. }
  77. }
  78. void RequestKuruShake(float amount)
  79. {
  80. if (!m_KuruShake)
  81. m_KuruShake = new KuruShake(m_PlayerPb, amount);
  82. }
  83. void OnRaiseBegin(DayZPlayerImplement player)
  84. {
  85. Weapon_Base weapon = Weapon_Base.Cast(player.GetHumanInventory().GetEntityInHands());
  86. if (weapon)
  87. {
  88. m_SwayModifier = weapon.GetPropertyModifierObject().m_SwayModifiers;
  89. }
  90. }
  91. void OnFinisherBegin(float currentAimY)
  92. {
  93. m_StealthAimY_Last = currentAimY;
  94. m_FilterVelocityStealthAimY[0] = 0;
  95. }
  96. void OnSwayStateChange(int state)
  97. {
  98. switch (state)
  99. {
  100. case eSwayStates.HOLDBREATH_EXHAUSTED:
  101. m_PlayerPb.OnHoldBreathExhausted();
  102. break;
  103. default:
  104. break;
  105. }
  106. }
  107. float GetSwayWeight()
  108. {
  109. return m_SwayWeight;
  110. }
  111. void SetAimNoiseAllowed(bool state)
  112. {
  113. m_AimNoiseAllowed = state;
  114. }
  115. bool IsAimNoiseAllowed()
  116. {
  117. return m_AimNoiseAllowed;
  118. }
  119. void SetProceduralRecoilEnabled(bool state)
  120. {
  121. m_ProceduralRecoilEnabled = state;
  122. }
  123. bool IsProceduralRecoilEnabled()
  124. {
  125. return m_ProceduralRecoilEnabled;
  126. }
  127. void SetCamShakeValues(float x_axis, float y_axis)
  128. {
  129. m_CamShakeX = x_axis;
  130. m_CamShakeY = y_axis;
  131. }
  132. bool ProcessStealthFilters(float pDt, SDayZPlayerAimingModel pModel)
  133. {
  134. m_StealthAimY_Last = Math.SmoothCD(m_StealthAimY_Last, 0, m_FilterVelocityStealthAimY, 0.3, 1000, pDt);
  135. pModel.m_fAimYMouseShift = -(pModel.m_fCurrentAimY - m_StealthAimY_Last);
  136. return true;
  137. }
  138. bool ProcessAimFilters(float pDt, SDayZPlayerAimingModel pModel, int stance_index)
  139. {
  140. float breathing_offset_x;
  141. float breathing_offset_y;
  142. float noise_offset_x;
  143. float noise_offset_y;
  144. float shake_offset_x;
  145. float shake_offset_y;
  146. float recoil_offset_mouse_x;
  147. float recoil_offset_mouse_y;
  148. float recoil_offset_hands_x;
  149. float recoil_offset_hands_y;
  150. float kuru_offset_x;
  151. float kuru_offset_y;
  152. float player_stamina = m_PlayerPb.GetStaminaHandler().GetSyncedStaminaNormalized();
  153. #ifdef DEVELOPER
  154. DbgPrintAimingImplement("Player: " + m_PlayerPb + " | ProcessAimFilters | timestamp: " + m_PlayerPb.GetSimulationTimeStamp());
  155. #endif
  156. //negates stamina effect during hold breath
  157. if (m_PlayerPb.IsHoldingBreath())
  158. {
  159. player_stamina = 1;
  160. }
  161. float speed = CalculateSpeedMultiplier(player_stamina);
  162. m_TotalTime += pDt * speed;
  163. if (m_PlayerPb.IsHoldingBreath() && !m_HoldingBreathSet)
  164. {
  165. m_ReferenceTime = m_TotalTime;
  166. m_StaminaPercentage = m_PlayerPb.GetStaminaHandler().GetSyncedStaminaNormalized();
  167. m_HoldBreathSwayCoef = Math.InverseLerp(0,PlayerSwayConstants.HOLD_BREATH_STAMINA_THRESHOLD,m_StaminaPercentage);
  168. m_HoldBreathSwayCoef = Math.Clamp(m_HoldBreathSwayCoef,0,1);
  169. m_HoldBreathSwayCoef = Math.Lerp(PlayerSwayConstants.HOLD_BREATH_STAMINA_THRESHOLD,1,m_HoldBreathSwayCoef);
  170. }
  171. else if (!m_PlayerPb.IsHoldingBreath() && m_HoldingBreathSet)
  172. {
  173. m_ReferenceTime = m_TotalTime;
  174. }
  175. float adjusted_sway_multiplier = CalculateSwayMultiplier();
  176. m_LastSwayMultiplier = adjusted_sway_multiplier;
  177. m_SwayWeight = CalculateWeight( stance_index, player_stamina, 0.5/*m_PlayerPb.m_CameraSwayModifier*/, m_PlayerPb.IsHoldingBreath()) * adjusted_sway_multiplier;
  178. //! get sway
  179. ApplyBreathingPattern(breathing_offset_x, breathing_offset_y, 3.0, m_TotalTime, m_SwayWeight);
  180. ApplyHorizontalNoise(noise_offset_x, noise_offset_y, 0.2, 0.5, 3.0 * m_SwayModifier[0], speed, 3 * m_SwayModifier[1], m_SwayWeight, pDt);
  181. int shake_level = m_PlayerPb.GetShakeLevel();
  182. if (shake_level != 0)
  183. {
  184. ApplyShakes(shake_offset_x, shake_offset_y, shake_level);
  185. }
  186. //! get recoil
  187. if (m_CurrentRecoil)
  188. {
  189. m_CurrentRecoil.Update(pModel, recoil_offset_mouse_x, recoil_offset_mouse_y, recoil_offset_hands_x, recoil_offset_hands_y, pDt);
  190. }
  191. if (m_KuruShake)
  192. {
  193. m_KuruShake.Update(pDt, kuru_offset_x, kuru_offset_y);
  194. }
  195. //! hands offset
  196. pModel.m_fAimXHandsOffset = breathing_offset_x + noise_offset_x + recoil_offset_hands_x + shake_offset_x + kuru_offset_x;
  197. pModel.m_fAimYHandsOffset = breathing_offset_y + noise_offset_y + recoil_offset_hands_y + shake_offset_y + kuru_offset_y;
  198. #ifdef DEVELOPER
  199. DbgPrintAimingImplement("breathing_offset_y: " + breathing_offset_y);
  200. DbgPrintAimingImplement("noise_offset_y: " + noise_offset_y);
  201. DbgPrintAimingImplement("recoil_offset_hands_y: " + recoil_offset_hands_y);
  202. DbgPrintAimingImplement("shake_offset_y: " + shake_offset_y);
  203. DbgPrintAimingImplement("kuru_offset_y: " + kuru_offset_y);
  204. DbgPrintAimingImplement("pModel.m_fAimYHandsOffset: " + pModel.m_fAimYHandsOffset);
  205. #endif
  206. //! cam offset
  207. pModel.m_fAimXCamOffset = -shake_offset_x - recoil_offset_hands_x - kuru_offset_x + m_CamShakeX;
  208. pModel.m_fAimYCamOffset = -shake_offset_y - recoil_offset_hands_y - kuru_offset_y + m_CamShakeY;
  209. #ifdef DEVELOPER
  210. DbgPrintAimingImplement("m_CamShakeY: " + m_CamShakeY);
  211. DbgPrintAimingImplement("pModel.m_fAimYCamOffset: " + pModel.m_fAimYCamOffset);
  212. #endif
  213. //! clamp aim ranges
  214. if (stance_index == DayZPlayerConstants.STANCEIDX_RAISEDPRONE)
  215. {
  216. float newVal = DayZPlayerUtils.LinearRangeClamp(pModel.m_fCurrentAimX, pModel.m_fCurrentAimY, m_AimXClampRanges);
  217. pModel.m_fAimYHandsOffset += newVal - pModel.m_fCurrentAimY;
  218. }
  219. float absAimY = Math.AbsFloat(pModel.m_fCurrentAimY);
  220. pModel.m_fAimYHandsOffset = Math.Clamp(pModel.m_fAimYHandsOffset,absAimY - 89.9,89.9 - absAimY); //'90' leads to rounding errors down the line
  221. if (m_PlayerDpi.IsInOptics() && m_KuruShake)
  222. {
  223. //TODO - do not offset mouse
  224. }
  225. //! mouse offset
  226. pModel.m_fAimXMouseShift = recoil_offset_mouse_x -kuru_offset_x / 10;
  227. pModel.m_fAimYMouseShift = recoil_offset_mouse_y + kuru_offset_y / 10;
  228. #ifdef DEVELOPER
  229. DbgPrintAimingImplement("recoil_offset_mouse_y: " + recoil_offset_mouse_y);
  230. DbgPrintAimingImplement("pModel.m_fAimYMouseShift: " + pModel.m_fAimYMouseShift);
  231. #endif
  232. if (m_PlayerPb.IsHoldingBreath() && !m_HoldingBreathSet)
  233. {
  234. m_HoldingBreathSet = true;
  235. m_HorizontalNoiseXAxisOffset = noise_offset_x;
  236. m_BreathingXAxisOffset = breathing_offset_x;
  237. m_BreathingYAxisOffset = breathing_offset_y;
  238. }
  239. else if (!m_PlayerPb.IsHoldingBreath() && m_HoldingBreathSet)
  240. {
  241. m_HoldingBreathSet = false;
  242. }
  243. if (!m_PlayerPb.IsHoldingBreath() && m_LastSwayMultiplier == PlayerSwayConstants.SWAY_MULTIPLIER_DEFAULT && m_HorizontalNoiseXAxisOffset != 0)
  244. {
  245. m_HorizontalNoiseXAxisOffset = 0;
  246. m_BreathingXAxisOffset = 0;
  247. m_BreathingYAxisOffset = 0;
  248. }
  249. if (m_PlayerPb.IsHoldingBreath())
  250. {
  251. m_PlayerPb.DepleteStaminaEx(EStaminaModifiers.HOLD_BREATH, pDt * speed, m_HoldBreathSwayCoef);
  252. }
  253. #ifdef DEVELOPER
  254. DbgPrintAimingImplement("----------------------------");
  255. #endif
  256. return true;
  257. }
  258. protected float CalculateSwayMultiplier()
  259. {
  260. float max;
  261. float time;
  262. float time_clamped;
  263. float ret;
  264. if (m_PlayerPb.IsHoldingBreath())
  265. {
  266. time = m_TotalTime - m_ReferenceTime;
  267. if (time < (PlayerSwayConstants.SWAY_TIME_IN * m_HoldBreathSwayCoef))
  268. {
  269. UpdateSwayState(eSwayStates.HOLDBREATH_IN);
  270. max = PlayerSwayConstants.SWAY_TIME_IN * m_HoldBreathSwayCoef;
  271. time_clamped = Math.Clamp((m_TotalTime - m_SwayStateStartTime),0,max);
  272. ret = Math.Lerp(m_LastSwayMultiplier,PlayerSwayConstants.SWAY_MULTIPLIER_STABLE,time_clamped/max);
  273. }
  274. else if (time >= (PlayerSwayConstants.SWAY_TIME_IN * m_HoldBreathSwayCoef) && time < (m_HoldBreathSwayCoef * (PlayerSwayConstants.SWAY_TIME_IN + PlayerSwayConstants.SWAY_TIME_STABLE)))
  275. {
  276. UpdateSwayState(eSwayStates.HOLDBREATH_STABLE);
  277. ret = PlayerSwayConstants.SWAY_MULTIPLIER_STABLE;
  278. }
  279. else
  280. {
  281. UpdateSwayState(eSwayStates.HOLDBREATH_EXHAUSTED);
  282. max = PlayerSwayConstants.SWAY_TIME_EXHAUSTED * m_HoldBreathSwayCoef;
  283. time_clamped = Math.Clamp((m_TotalTime - m_SwayStateStartTime),0,max);
  284. ret = Math.Lerp(PlayerSwayConstants.SWAY_MULTIPLIER_STABLE,PlayerSwayConstants.SWAY_MULTIPLIER_EXHAUSTED,(time_clamped/max));
  285. }
  286. }
  287. else
  288. {
  289. UpdateSwayState(eSwayStates.DEFAULT);
  290. max = PlayerSwayConstants.SWAY_TIME_OUT;
  291. time_clamped = Math.Clamp((m_TotalTime - m_SwayStateStartTime),0,max);
  292. ret = Math.Lerp(m_LastSwayMultiplier,1,time_clamped/max);
  293. }
  294. return ret;
  295. }
  296. float CalculateSpeedMultiplier(float stamina)
  297. {
  298. return (((1.0 - stamina) * 3.0) + 1.0) * m_SwayModifier[2]; // just 'm_SwayModifier[2]' for HoldBreath
  299. }
  300. protected bool UpdateSwayState(int state)
  301. {
  302. if (state != m_SwayState)
  303. {
  304. m_SwayState = state;
  305. m_SwayStateStartTime = m_TotalTime;
  306. m_StateStartSwayMultiplier = m_LastSwayMultiplier;
  307. OnSwayStateChange(state);
  308. return true;
  309. }
  310. return false;
  311. }
  312. int GetCurrentSwayState()
  313. {
  314. return m_SwayState;
  315. }
  316. protected void ApplyBreathingPattern(out float x_axis, out float y_axis, float pAmplitude, float pTotalTime, float weight)
  317. {
  318. float multiplier = Math.Lerp(PlayerSwayConstants.SWAY_MULTIPLIER_DEFAULT,0,m_LastSwayMultiplier); //TODO revise
  319. #ifdef DEVELOPER
  320. DbgPrintAimingImplement("m_LastSwayMultiplier: " + m_LastSwayMultiplier);
  321. DbgPrintAimingImplement("pAmplitude: " + pAmplitude);
  322. DbgPrintAimingImplement("pTotalTime: " + pTotalTime);
  323. DbgPrintAimingImplement("weight: " + weight);
  324. DbgPrintAimingImplement("multiplier: " + multiplier);
  325. #endif
  326. x_axis = (Math.Sin(pTotalTime) * pAmplitude / 4) * weight;
  327. y_axis = (Math.Sin((pTotalTime) * 0.8 + 0.6) * pAmplitude) * weight;
  328. #ifdef DEVELOPER
  329. DbgPrintAimingImplement("y_axis_midproduct: " + y_axis);
  330. #endif
  331. x_axis += m_BreathingXAxisOffset * multiplier;
  332. y_axis += m_BreathingYAxisOffset * multiplier;
  333. }
  334. protected void ApplyHorizontalNoise(out float x_axis, out float y_axis, float smooth_time,float max_velocity_low, float max_velocity_high, float velocity_modifier, float max_distance, float weight, float pDt)
  335. {
  336. if (Math.AbsFloat(m_HorizontalTargetValue - m_HorizontalNoise) < 0.01)
  337. {
  338. //acquire new target
  339. m_MaxVelocity = m_PlayerPb.GetRandomGeneratorSyncManager().GetRandomInRange(RandomGeneratorSyncUsage.RGSAimingModel, max_velocity_low, max_velocity_high);
  340. float r = m_PlayerPb.GetRandomGeneratorSyncManager().GetRandomInRange(RandomGeneratorSyncUsage.RGSAimingModel, 0, 1);
  341. m_HorizontalTargetValue = (r - 0.5) * 2 * max_distance;
  342. m_HorizontalNoiseVelocity[0] = 0;
  343. }
  344. m_HorizontalNoise = Math.SmoothCD(m_HorizontalNoise, m_HorizontalTargetValue, m_HorizontalNoiseVelocity, smooth_time, m_MaxVelocity * velocity_modifier, pDt);
  345. x_axis = m_HorizontalNoise * weight;
  346. float multiplier = Math.Lerp(PlayerSwayConstants.SWAY_MULTIPLIER_DEFAULT,0,m_LastSwayMultiplier); //TODO revise
  347. x_axis += m_HorizontalNoiseXAxisOffset * multiplier;
  348. }
  349. protected void ApplyShakes(out float x_axis, out float y_axis, int level)
  350. {
  351. float weight = level / PlayerBase.SHAKE_LEVEL_MAX;
  352. m_ShakeCount++;
  353. int shakes_threshold = Math.Round(m_PlayerPb.GetRandomGeneratorSyncManager().GetRandomInRange(RandomGeneratorSyncUsage.RGSAimingModel, 2, 4));
  354. if (m_ShakeCount > shakes_threshold)
  355. {
  356. m_ShakeCount = 0;
  357. float modifier = m_PlayerPb.GetRandomGeneratorSyncManager().GetRandomInRange(RandomGeneratorSyncUsage.RGSAimingModel, 0.45, 0.9);
  358. x_axis = modifier * weight * m_PlayerPb.GetRandomGeneratorSyncManager().GetRandomInRange(RandomGeneratorSyncUsage.RGSAimingModel, 0, 1);
  359. y_axis = modifier * weight * m_PlayerPb.GetRandomGeneratorSyncManager().GetRandomInRange(RandomGeneratorSyncUsage.RGSAimingModel, 0, 1);
  360. }
  361. }
  362. protected float CalculateWeight(int stance_index, float current_stamina, float camera_sway_modifier, bool holding_breath)
  363. {
  364. if (m_PlayerDpi.GetCommand_Move() && m_PlayerDpi.GetCommand_Move().IsInRoll())//when the player is rolling, set a constant and disregard everything else
  365. {
  366. return PlayerSwayConstants.SWAY_ROLL;
  367. }
  368. float stance_modifier;
  369. switch (stance_index)
  370. {
  371. case DayZPlayerConstants.STANCEIDX_RAISEDERECT:
  372. stance_modifier = 0.5;
  373. break;
  374. case DayZPlayerConstants.STANCEIDX_RAISEDCROUCH:
  375. stance_modifier = 0.75;
  376. break;
  377. case DayZPlayerConstants.STANCEIDX_RAISEDPRONE:
  378. stance_modifier = 0.925;
  379. break;
  380. default:
  381. stance_modifier = 0.75;
  382. //Debug.LogError("stance mask out of definition");
  383. break;
  384. }
  385. #ifdef DEVELOPER
  386. DbgPrintAimingImplement("current_stamina: " + current_stamina);
  387. DbgPrintAimingImplement("camera_sway_modifier: " + camera_sway_modifier);
  388. DbgPrintAimingImplement("holding_breath: " + holding_breath);
  389. #endif
  390. return (1 - stance_modifier) * m_AimNoiseAllowed * camera_sway_modifier * SWAY_WEIGHT_SCALER;
  391. }
  392. void DbgPrintAimingImplement(string val)
  393. {
  394. #ifdef DEVELOPER
  395. if (GetDayZGame().IsAimLogEnabled())
  396. Print("DayZPlayerImplementAiming | " + val);
  397. #endif
  398. }
  399. }