actionfishingnew.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. class FishingActionReceiveData : ActionReciveData
  2. {
  3. bool m_IsSurfaceSea;
  4. }
  5. class FishingActionData : ActionData
  6. {
  7. bool m_IsSurfaceSea;
  8. int m_FishingResult = -1; //use for hashed name?
  9. bool m_IsSignalActive = false;
  10. int m_SplashUniqueID = -1;
  11. ref CatchingContextFishingRodAction m_ContextData;
  12. void RollNextResultChance()
  13. {
  14. CAContinuousRepeatFishing component;
  15. Class.CastTo(component,m_ActionComponent);
  16. m_IsSignalActive = false; //redundant?
  17. if (m_ContextData.RollCatch())
  18. {
  19. RandomizeSignalValues();
  20. }
  21. else
  22. {
  23. component.SetNewSignalData(-1,-1);
  24. }
  25. }
  26. //signal methods
  27. protected void RandomizeSignalValues()
  28. {
  29. CAContinuousRepeatFishing component;
  30. Class.CastTo(component,m_ActionComponent);
  31. component.SetNewSignalData(m_ContextData.RandomizeSignalStartTime(),m_ContextData.RandomizeSignalDuration());
  32. }
  33. void AnimateRod(float phase, bool instant = false)
  34. {
  35. FishingRod_Base_New rod = FishingRod_Base_New.Cast(m_MainItem);
  36. rod.AnimateFishingRodEx(phase,instant);
  37. }
  38. //------------------------------------------------------------------
  39. //DEPRECATED
  40. //------------------------------------------------------------------
  41. const float FISHING_SUCCESS = 0.2;
  42. const float FISHING_BAIT_LOSS = 0.02;
  43. const float FISHING_HOOK_LOSS = 0.015;
  44. const float FISHING_DAMAGE = 1.5;
  45. const float FISHING_GARBAGE_CHANCE = 0.2;
  46. bool m_IsBaitAnEmptyHook;
  47. float m_RodQualityModifier = 0;
  48. ItemBase m_Bait;
  49. void InitBait(ItemBase item)
  50. {
  51. m_Bait = item;
  52. m_IsBaitAnEmptyHook = !m_Bait.ConfigIsExisting("hookType");
  53. }
  54. bool IsBaitEmptyHook()
  55. {
  56. return m_IsBaitAnEmptyHook;
  57. }
  58. }
  59. class ActionFishingNewCB : ActionContinuousBaseCB
  60. {
  61. FishingActionData m_ActionDataFishing;
  62. override void CreateActionComponent()
  63. {
  64. EnableStateChangeCallback();
  65. float cycleTime = UAFishingConstants.CYCLE_LENGTH_BASE; //redundant?
  66. if (Class.CastTo(m_ActionDataFishing,m_ActionData))
  67. {
  68. cycleTime = m_ActionDataFishing.m_ContextData.GetActionCycleTime();
  69. }
  70. m_ActionData.m_ActionComponent = new CAContinuousRepeatFishing(cycleTime);
  71. }
  72. override void InitActionComponent()
  73. {
  74. super.InitActionComponent();
  75. RegisterAnimationEvent("ParticleSplash", UAFishingConstants.EVENT_SPLASH_SIGNAL);
  76. RegisterAnimationEvent("EventFishPlacement", UAFishingConstants.EVENT_ANIMATE_ROD_CLOSE);
  77. }
  78. override void EndActionComponent()
  79. {
  80. bool animateRod = false;
  81. if (m_ActionDataFishing.m_State == UA_CANCEL)
  82. m_Canceled = true;
  83. if (m_ActionDataFishing.m_State == UA_FINISHED)
  84. {
  85. if (m_ActionDataFishing.m_FishingResult == 1)
  86. {
  87. SetCommand(DayZPlayerConstants.CMD_ACTIONINT_END);
  88. }
  89. else
  90. {
  91. SetCommand(DayZPlayerConstants.CMD_ACTIONINT_FINISH);
  92. animateRod = true;
  93. }
  94. }
  95. else
  96. {
  97. SetCommand(DayZPlayerConstants.CMD_ACTIONINT_INTERRUPT);
  98. animateRod = true;
  99. }
  100. animateRod |= m_Canceled;
  101. if (animateRod)
  102. {
  103. m_ActionDataFishing.AnimateRod(false,m_Canceled);
  104. }
  105. DestroySplashEffectSynced();
  106. }
  107. override void OnStateChange(int pOldState, int pCurrentState)
  108. {
  109. super.OnStateChange(pOldState,pCurrentState);
  110. if (pOldState == STATE_NONE && pCurrentState == STATE_LOOP_IN)
  111. {
  112. m_ActionDataFishing.AnimateRod(true);
  113. }
  114. }
  115. void ToggleFishBiting()
  116. {
  117. if (GetState() == STATE_LOOP_LOOP || GetState() == STATE_LOOP_LOOP2)
  118. SetCommand(DayZPlayerConstants.CMD_ACTIONINT_ACTIONLOOP);
  119. }
  120. //! Destroys the effecter, but lets the rest of the particle play out
  121. void DestroySplashEffectSynced()
  122. {
  123. if (GetGame().IsServer() && m_ActionDataFishing.m_SplashUniqueID >= 0)
  124. {
  125. SEffectManager.DestroyEffecterParticleServer(m_ActionDataFishing.m_SplashUniqueID);
  126. m_ActionDataFishing.m_SplashUniqueID = -1;
  127. }
  128. }
  129. //DEPRECATED
  130. ref array<string> m_JunkTypes = {};
  131. void HandleFishingResultSuccess();
  132. void HandleFishingResultFailure();
  133. };
  134. class ActionFishingNew: ActionContinuousBase
  135. {
  136. private const string ALLOWED_WATER_SURFACES = string.Format("%1|%2", UAWaterType.SEA, UAWaterType.FRESH);
  137. void ActionFishingNew()
  138. {
  139. m_CallbackClass = ActionFishingNewCB;
  140. m_SpecialtyWeight = UASoftSkillsWeight.PRECISE_MEDIUM;
  141. m_CommandUID = DayZPlayerConstants.CMD_ACTIONFB_FISHING;
  142. m_FullBody = true;
  143. m_StanceMask = DayZPlayerConstants.STANCEMASK_CROUCH;
  144. m_Text = "#start_fishing";
  145. }
  146. override void CreateConditionComponents()
  147. {
  148. m_ConditionItem = new CCINonRuined();
  149. m_ConditionTarget = new CCTWaterSurfaceEx(30, LIQUID_SALTWATER|LIQUID_FRESHWATER);
  150. }
  151. override bool HasTarget()
  152. {
  153. return true;
  154. }
  155. override bool HasAlternativeInterrupt()
  156. {
  157. return true;
  158. }
  159. override bool CanBeUsedInFreelook()
  160. {
  161. return false;
  162. }
  163. override bool ActionCondition(PlayerBase player, ActionTarget target, ItemBase item )
  164. {
  165. ItemBase hook;
  166. hook = ItemBase.Cast(item.FindAttachmentBySlotName("Hook"));
  167. return hook && !hook.IsRuined() && !hook.IsPendingDeletion();
  168. }
  169. override ActionData CreateActionData()
  170. {
  171. FishingActionData actionData = new FishingActionData();
  172. return actionData;
  173. }
  174. override bool SetupAction(PlayerBase player, ActionTarget target, ItemBase item, out ActionData action_data, Param extra_data = null)
  175. {
  176. if (super.SetupAction(player, target, item, action_data, extra_data))
  177. {
  178. FishingActionData data;
  179. if (Class.CastTo(data,action_data))
  180. {
  181. ComposeLocalContextData(data);
  182. return true;
  183. }
  184. }
  185. return false;
  186. }
  187. protected void ComposeLocalContextData(FishingActionData data)
  188. {
  189. #ifndef SERVER
  190. data.m_IsSurfaceSea = CheckForSea(data); //already synced from client by this point
  191. #endif
  192. Param2<EntityAI,bool> par = new Param2<EntityAI,bool>(data.m_MainItem,data.m_IsSurfaceSea);
  193. data.m_ContextData = new CatchingContextFishingRodAction(par);
  194. data.m_ContextData.GenerateResult(); //call only once
  195. #ifdef DEVELOPER
  196. data.m_ContextData.SetResultChanceOverride(data.m_Player.IsQuickFishing(),1.0); //active override sets chance to 100% for the action duration
  197. #endif
  198. }
  199. override void WriteToContext(ParamsWriteContext ctx, ActionData action_data)
  200. {
  201. super.WriteToContext(ctx, action_data);
  202. FishingActionData data
  203. if (Class.CastTo(data,action_data))
  204. {
  205. ctx.Write(data.m_IsSurfaceSea);
  206. }
  207. }
  208. override bool ReadFromContext(ParamsReadContext ctx, out ActionReciveData action_recive_data )
  209. {
  210. if (!action_recive_data)
  211. {
  212. action_recive_data = new FishingActionReceiveData;
  213. }
  214. super.ReadFromContext(ctx, action_recive_data);
  215. FishingActionReceiveData receiveDataFishing;
  216. if (Class.CastTo(receiveDataFishing,action_recive_data))
  217. {
  218. if (!ctx.Read(receiveDataFishing.m_IsSurfaceSea))
  219. return false;
  220. return true;
  221. }
  222. return false;
  223. }
  224. override void HandleReciveData(ActionReciveData action_recive_data, ActionData action_data)
  225. {
  226. super.HandleReciveData(action_recive_data, action_data);
  227. FishingActionReceiveData receiveDataFishing = FishingActionReceiveData.Cast(action_recive_data);
  228. FishingActionData fishingData = FishingActionData.Cast(action_data);
  229. fishingData.m_IsSurfaceSea = receiveDataFishing.m_IsSurfaceSea;
  230. }
  231. override protected void CreateAndSetupActionCallback(ActionData action_data)
  232. {
  233. super.CreateAndSetupActionCallback(action_data);
  234. FishingActionData data;
  235. if (Class.CastTo(data,action_data))
  236. {
  237. data.RollNextResultChance(); //performed here so that component exists
  238. }
  239. }
  240. override void OnAnimationEvent( ActionData action_data )
  241. {
  242. super.OnAnimationEvent(action_data);
  243. FishingActionData actionDataFishing = FishingActionData.Cast(action_data);
  244. switch (action_data.m_DelayedAnimationEventID)
  245. {
  246. case UAFishingConstants.EVENT_SPLASH_SIGNAL:
  247. PlaySplashEffectSynced(actionDataFishing);
  248. break;
  249. case UAFishingConstants.EVENT_ANIMATE_ROD_CLOSE:
  250. actionDataFishing.AnimateRod(false,false);
  251. break;
  252. }
  253. }
  254. override void OnUpdate(ActionData action_data)
  255. {
  256. super.OnUpdate(action_data);
  257. vector dir = vector.Direction(action_data.m_Player.GetPosition(), action_data.m_Target.GetCursorHitPos());
  258. dir[1] = 0;
  259. dir.Normalize();
  260. action_data.m_Player.AlignDirectionWS(dir);
  261. }
  262. void PlaySplashEffectSynced(FishingActionData actionDataFishing)
  263. {
  264. if (GetGame().IsServer())
  265. {
  266. int particleId = actionDataFishing.m_ContextData.GetResultParticleId();
  267. if (actionDataFishing.m_SplashUniqueID < 0)
  268. {
  269. actionDataFishing.m_SplashUniqueID = SEffectManager.CreateParticleServer(actionDataFishing.m_Target.GetCursorHitPos(), new ParticleEffecterParameters("ParticleEffecter", EffecterBase.NOT_DEFINED_LIFESPAN, particleId));
  270. }
  271. else
  272. {
  273. SEffectManager.ReinitParticleServer(actionDataFishing.m_SplashUniqueID, new ParticleEffecterParameters("ParticleEffecter", EffecterBase.NOT_DEFINED_LIFESPAN, particleId)); //reinit here, since particleId might differ
  274. SEffectManager.ReactivateParticleServer(actionDataFishing.m_SplashUniqueID);
  275. }
  276. }
  277. }
  278. protected bool CheckForSea(ActionData action_data)
  279. {
  280. bool ret = false;
  281. vector cursorPosition = action_data.m_Target.GetCursorHitPos();
  282. if (GetGame().SurfaceIsSea(cursorPosition[0], cursorPosition[2]))
  283. {
  284. ret = true;
  285. }
  286. return ret;
  287. }
  288. //------------------------------------------------------
  289. override void OnFinishProgress(ActionData action_data)
  290. {
  291. super.OnFinishProgress(action_data);
  292. FishingActionData data;
  293. if (Class.CastTo(data,action_data))
  294. {
  295. data.RollNextResultChance();
  296. }
  297. }
  298. override void OnEndInput(ActionData action_data)
  299. {
  300. ActionContinuousBaseCB callback;
  301. if (Class.CastTo(callback, action_data.m_Callback))
  302. {
  303. switch (callback.GetState())
  304. {
  305. case HumanCommandActionCallback.STATE_LOOP_ACTION:
  306. case HumanCommandActionCallback.STATE_LOOP_LOOP:
  307. case HumanCommandActionCallback.STATE_LOOP_LOOP2:
  308. FishingActionData data;
  309. if (Class.CastTo(data,action_data))
  310. {
  311. data.m_FishingResult = EvaluateFishingResult(action_data);
  312. if (data.m_FishingResult != -1)
  313. data.m_State = UA_FINISHED;
  314. }
  315. break;
  316. default:
  317. super.OnEndInput(action_data);
  318. callback.EndActionComponent(); //think about putting this everywhere, interrupts HumanCommandActionCallback.STATE_LOOP_IN neatly
  319. break;
  320. }
  321. }
  322. }
  323. override void OnEnd(ActionData action_data)
  324. {
  325. super.OnEnd(action_data);
  326. FishingActionData fad;
  327. if (Class.CastTo(fad,action_data))
  328. fad.AnimateRod(false,true); //just in case
  329. }
  330. //! Player input reaction evaluation
  331. int EvaluateFishingResult(ActionData action_data)
  332. {
  333. FishingActionData fad;
  334. if (Class.CastTo(fad,action_data))
  335. {
  336. //legacy stuff
  337. ActionFishingNewCB legacyCB = ActionFishingNewCB.Cast(fad.m_Callback);
  338. if (fad.m_IsSignalActive)//catch
  339. {
  340. fad.m_ContextData.OnBeforeSpawnSignalHit();
  341. if (!GetGame().IsMultiplayer() || GetGame().IsDedicatedServer())
  342. TrySpawnCatch(fad);
  343. fad.m_ContextData.OnAfterSpawnSignalHit();
  344. if (legacyCB)
  345. legacyCB.HandleFishingResultSuccess();
  346. EntityAI hookCheck = action_data.m_MainItem.FindAttachmentBySlotName("Hook");
  347. return hookCheck != null && !hookCheck.IsPendingDeletion(); //success animation only if hook loss didn't prevent catch (local)
  348. }
  349. else//fail
  350. {
  351. fad.m_ContextData.OnSignalMiss();
  352. if (legacyCB)
  353. legacyCB.HandleFishingResultFailure();
  354. return false;
  355. }
  356. }
  357. return -1;
  358. }
  359. //------------------------------------------------------
  360. void OnSignalStart(FishingActionData action_data)
  361. {
  362. action_data.m_IsSignalActive = true;
  363. ActionFishingNewCB fishingCB;
  364. if (Class.CastTo(fishingCB,action_data.m_Callback))
  365. fishingCB.ToggleFishBiting();
  366. }
  367. void OnSignalEnd(FishingActionData action_data)
  368. {
  369. action_data.m_IsSignalActive = false;
  370. ActionFishingNewCB fishingCB;
  371. if (Class.CastTo(fishingCB,action_data.m_Callback))
  372. fishingCB.ToggleFishBiting();
  373. action_data.m_ContextData.OnSignalPass();
  374. }
  375. protected EntityAI TrySpawnCatch(FishingActionData action_data)
  376. {
  377. vector spawnPos = vector.Direction(action_data.m_Player.GetPosition(),action_data.m_Target.GetCursorHitPos()); //direction first
  378. spawnPos = MiscGameplayFunctions.GetRandomizedPositionVerified(action_data.m_Player.GetPosition(),action_data.m_Player.GetPosition() + spawnPos * 0.1,0.15,action_data.m_Player);
  379. int idx;
  380. return action_data.m_ContextData.SpawnAndSetupCatch(idx,spawnPos);
  381. }
  382. }