rangefinder.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. class Rangefinder extends PoweredOptic_Base
  2. {
  3. static const float RANGEFINDER_MAX_DISTANCE = 913.4856; //TODO adjust maximal distance to match real life rangefinder
  4. protected ref Timer m_Timer;
  5. protected Widget m_Root;
  6. protected TextWidget m_RangeText;
  7. protected string m_LayoutPath;
  8. void Rangefinder()
  9. {
  10. InitRangeFinderData();
  11. }
  12. void ~Rangefinder()
  13. {
  14. m_IsActionActive = false;
  15. }
  16. protected void InitRangeFinderData()
  17. {
  18. string path = "cfgVehicles " + GetType();
  19. if (GetGame().ConfigIsExisting(path))
  20. {
  21. string layout;
  22. if (GetGame().ConfigIsExisting(path + " rangeFinderLayout"))
  23. {
  24. GetGame().ConfigGetText(path + " rangeFinderLayout", layout);
  25. }
  26. if (layout != "" && layout.Length() > 0)
  27. {
  28. m_LayoutPath = layout;
  29. }
  30. else
  31. {
  32. m_LayoutPath = "gui/layouts/gameplay/rangefinder_hud.layout";
  33. }
  34. }
  35. }
  36. // How frequently the measurement should be taken
  37. float GetMeasurementUpdateInterval()
  38. {
  39. return 0.5;
  40. }
  41. override void OnWorkStart()
  42. {
  43. if (GetGame().IsServer() && !m_IsActionActive) // incorrectly synchronized state from EM
  44. StopWorkServer();
  45. if( !GetGame().IsDedicatedServer())
  46. {
  47. PlayerBase player_this = PlayerBase.Cast( GetGame().GetPlayer() );
  48. PlayerBase player_owner = PlayerBase.Cast( GetHierarchyRootPlayer() );
  49. if ( player_this == player_owner )
  50. {
  51. StartPeriodicMeasurement();
  52. }
  53. }
  54. }
  55. override void OnWorkStop()
  56. {
  57. if( !GetGame().IsDedicatedServer())
  58. {
  59. PlayerBase player_this = PlayerBase.Cast( GetGame().GetPlayer() );
  60. PlayerBase player_owner = PlayerBase.Cast( GetHierarchyRootPlayer() );
  61. if ( player_this == player_owner )
  62. {
  63. StopPeriodicMeasurement();
  64. }
  65. }
  66. }
  67. void StartPeriodicMeasurement()
  68. {
  69. if( !m_Timer )
  70. {
  71. m_Timer = new Timer( CALL_CATEGORY_GAMEPLAY );
  72. }
  73. m_Root = GetGame().GetWorkspace().CreateWidgets( m_LayoutPath );
  74. // Either use root as text widget directly or find the text as children, arbitrary layout is supported now.
  75. m_RangeText = TextWidget.Cast(m_Root);
  76. if (!m_RangeText)
  77. m_RangeText = TextWidget.Cast(m_Root.FindAnyWidget("RangeText"));
  78. m_Timer.Run( GetMeasurementUpdateInterval(), this, "DoMeasurement", null, true );
  79. }
  80. void StopPeriodicMeasurement()
  81. {
  82. if( m_Timer )
  83. {
  84. m_Timer.Stop();
  85. }
  86. if (m_Root)
  87. {
  88. delete m_Root;
  89. }
  90. }
  91. protected void SetDistanceText(TextWidget text, float dist)
  92. {
  93. dist = Math.Round(dist);
  94. if (dist < RANGEFINDER_MAX_DISTANCE)
  95. {
  96. if( dist < 10 )
  97. text.SetText( "00" + dist.ToString() );
  98. else if( dist < 100 )
  99. text.SetText( "0" + dist.ToString() );
  100. else
  101. text.SetText( dist.ToString() );
  102. }
  103. else
  104. {
  105. SetInvalidText(text);
  106. }
  107. }
  108. protected void SetInvalidText(TextWidget text)
  109. {
  110. text.SetText( "---" );
  111. }
  112. // Measures the distance and returns result in formated string
  113. void DoMeasurement()
  114. {
  115. PlayerBase player = GetPlayer();
  116. if ( player )
  117. {
  118. vector from = GetGame().GetCurrentCameraPosition();
  119. vector fromDirection = GetGame().GetCurrentCameraDirection();
  120. vector to = from + (fromDirection * RANGEFINDER_MAX_DISTANCE);
  121. vector contact_pos;
  122. vector contact_dir;
  123. int contactComponent;
  124. bool hit = DayZPhysics.RaycastRV( from, to, contact_pos, contact_dir, contactComponent, NULL , NULL, player, false, false, ObjIntersectIFire);
  125. // (a)
  126. // from -> --- <- horizEnd
  127. // (h) \ |
  128. // to -> \|
  129. // Generate result
  130. float h = vector.Distance( from, contact_pos );
  131. if (hit)
  132. SetDistanceText( m_RangeText, h );
  133. else
  134. SetInvalidText( m_RangeText );
  135. // Horizontal distance
  136. TextWidget angleText = TextWidget.Cast(m_Root.FindAnyWidget("AngleText"));
  137. TextWidget horizText = TextWidget.Cast(m_Root.FindAnyWidget("RangeHDText"));
  138. vector horizontalTo = Vector( contact_pos[0], from[1], contact_pos[2] );
  139. float a = vector.Distance( from, horizontalTo );
  140. // Angle between horizontal and actual line
  141. float heightDiff = contact_pos[1] - from[1];
  142. float angle = Math.Atan( heightDiff / a ) * Math.RAD2DEG;
  143. angle = Math.Round(angle);
  144. if (angleText)
  145. {
  146. if (hit)
  147. angleText.SetText(string.Format("%1", angle));
  148. else
  149. SetInvalidText( angleText );
  150. }
  151. if (horizText)
  152. {
  153. if (hit)
  154. SetDistanceText( horizText, a );
  155. else
  156. SetInvalidText( horizText );
  157. }
  158. }
  159. }
  160. override void SetActions()
  161. {
  162. super.SetActions();
  163. RemoveAction(ActionViewOptics);
  164. AddAction(ActionViewBinoculars);
  165. }
  166. override void OnDebugSpawn()
  167. {
  168. GetInventory().CreateInInventory( "Battery9V" );
  169. }
  170. }