using System; using System.Collections; using UnityEngine; using UnityEngine.InputSystem; /// /// Reel-only fishing game manager. /// /// Removed from the old mixed version: /// - TimingGauge mode enum /// - Perfect / Good / Miss timing judgement /// - pointer rotation / success zone / round retry logic /// - submit action for the timing gauge /// /// Flow: /// FishingRodVRController detects bite -> StartFishing() /// -> player reels in -> CurrentLineLength reaches catchCompleteLineLength /// -> reward is rolled -> UI/inventory event updates -> bobber returns. /// public class FishingGameManager : MonoBehaviour { [Header("Auto Bind")] [Tooltip("현재 만든 Prefab 구조 기준으로 비어 있는 참조를 자동 연결합니다.")] [SerializeField] private bool autoBindMissingReferences = true; [Header("References")] [Tooltip("낚시 UI 전체 루트입니다. UI를 자동으로 켜고 끄고 싶을 때만 연결하세요.")] [SerializeField] private GameObject uiRoot; [SerializeField] private FishingGaugeUI ui; [SerializeField] private FishingRewardSystem rewardSystem; [SerializeField] private FishingHapticManager haptic; [SerializeField] private FishingRodVRController rodController; [SerializeField] private GameClear gameClear; [Header("Memory Piece Result Object")] [Tooltip("기억의 조각 획득 결과창이 뜰 때 플레이어 화면 앞에 생성할 오브젝트 프리팹입니다. StarPickup이 붙어 있어도 됩니다.")] [SerializeField] private GameObject memoryPieceResultPrefab; [Tooltip("씬에 미리 배치해 둔 기억의 조각 오브젝트입니다. 비워두면 Prefab을 생성합니다.")] [SerializeField] private GameObject memoryPieceResultSceneObject; [Tooltip("XR Origin의 Main Camera를 넣으세요. 비워두면 Camera.main을 자동으로 사용합니다.")] [SerializeField] private Transform memoryPiecePlayerHead; [SerializeField] private float memoryPieceResultDistance = 1.2f; [SerializeField] private float memoryPieceResultHeightOffset = -0.05f; [SerializeField] private float memoryPieceResultSideOffset = 0f; [SerializeField] private bool memoryPieceResultFollowPlayerHead = true; [SerializeField] private bool memoryPieceResultYawOnly = true; [Tooltip("켜면 오브젝트가 플레이어를 바라보게 합니다. StarPickup의 visualRoot가 자기 자신이면 회전 연출이 덮일 수 있으니 기본값은 Off입니다.")] [SerializeField] private bool memoryPieceResultFacePlayer = false; [Tooltip("0보다 크면 이 시간 뒤 기억의 조각 오브젝트를 숨깁니다. 결과창 자동 닫기 시간과 비슷하게 맞추세요.")] [SerializeField] private float memoryPieceResultShowTime = 3f; [SerializeField] private bool memoryPieceResultUseCustomScale = false; [SerializeField] private Vector3 memoryPieceResultCustomScale = Vector3.one; [Tooltip("켜면 StarPickup Trigger로 플레이어가 닿자마자 수집/Destroy되는 것을 막기 위해 Collider를 꺼둡니다.")] [SerializeField] private bool disableMemoryPieceResultColliders = true; [Tooltip("켜면 StarPickup의 floatMotion을 꺼서 카메라 앞 고정 위치와 충돌하지 않게 합니다. 회전은 유지됩니다.")] [SerializeField] private bool disableMemoryPieceResultFloatMotion = true; [SerializeField] private bool destroySpawnedMemoryPieceResultOnHide = true; [Header("Reel Fishing")] [Tooltip("현재 줄 길이가 이 값 이하가 되면 낚기 성공으로 처리합니다.")] [SerializeField] private float catchCompleteLineLength = 0.7f; [Tooltip("릴 낚시 시작 시 줄 길이가 성공 길이보다 너무 짧으면 이 거리만큼 최소 시작 길이를 보정합니다.")] [SerializeField] private float simpleReelMinimumPullDistance = 0.35f; [Tooltip("릴 낚기 성공 후 찌를 낚싯대 쪽 대기 위치로 회수합니다.")] [SerializeField] private bool returnBobberAfterCatch = true; [Tooltip("SimpleReel 모드에서는 StartFishing이 입질마다 호출됩니다. 켜면 첫 시작 때만 연못 상태를 초기화합니다.")] [SerializeField] private bool resetPondOnlyOnFirstStart = true; [Header("Reset Input")] [Tooltip("낚시 상태를 다시 시작할 컨트롤러 입력입니다. 필요 없으면 비워둬도 됩니다.")] [SerializeField] private InputActionReference resetAction; [Tooltip("씬에 Input Action Manager가 없거나 액션이 자동 활성화되지 않으면 켜두세요.")] [SerializeField] private bool enableInputActionsManually = true; [Header("Pond Cleanup Rules")] [Tooltip("연못을 맑게 만들기 위해 필요한 쓰레기 수입니다. 이제 쓰레기만 정화 아이템으로 카운트됩니다.")] [SerializeField] private int requiredCleanupItems = 3; [Tooltip("연못이 맑아진 뒤 다음 성공 낚시에서 기억의 조각을 확정으로 낚습니다.")] [SerializeField] private bool guaranteeMemoryPieceAfterCleaned = true; [Tooltip("StartFishing을 호출할 때 쓰레기 수거/연못 상태를 초기화합니다.")] [SerializeField] private bool resetPondStateOnStart = true; [Tooltip("낚시 세션이 진행 중일 때 StartFishing이 중복 호출되는 것을 막습니다.")] [SerializeField] private bool preventRestartWhileSessionRunning = true; [Header("Start / Final Result")] [Tooltip("VR 릴 낚시에서는 보통 꺼두세요. 입질이 왔을 때 FishingRodVRController가 StartFishing을 호출하는 구조를 추천합니다.")] [SerializeField] private bool startOnAwake = false; [Tooltip("최종 결과를 잠깐 보여준 뒤 uiRoot를 자동으로 끕니다. uiRoot가 비어 있으면 동작하지 않습니다.")] [SerializeField] private bool hideUIRootAfterFinalResult = false; [SerializeField] private float finalResultShowTime = 1.5f; [Header("Debug")] [SerializeField] private bool showDebugLog = true; private int cleanupItemCount; private int totalCaughtItems; // 임시 낚시 세션 카운트입니다. 영구 저장은 FishingInventoryBinder를 통해 FishingInventory에 연결하세요. private int sessionFishCount; private int sessionTrashCount; private int sessionMemoryPieceCount; private bool activeGame; private bool fishingSessionRunning; private bool pondCleaned; private bool memoryPieceCollected; private bool simpleReelCatchActive; private bool pondInitialized; private float simpleReelStartLineLength; private float simpleReelProgress; private bool resetActionWasEnabled; private Coroutine finalResultRoutine; private Coroutine memoryPieceResultRoutine; private GameObject currentMemoryPieceResultObject; private bool memoryPieceResultShowing; public bool IsActiveGame => activeGame; public bool IsFishingSessionRunning => fishingSessionRunning; public bool IsPondCleaned => pondCleaned; public bool IsMemoryPieceCollected => memoryPieceCollected; public int CleanupItemCount => cleanupItemCount; public int RequiredCleanupItems => requiredCleanupItems; public int TotalCaughtItems => totalCaughtItems; public int SessionFishCount => sessionFishCount; public int SessionTrashCount => sessionTrashCount; public int SessionMemoryPieceCount => sessionMemoryPieceCount; public bool IsSimpleReelCatchActive => simpleReelCatchActive; public float SimpleReelProgress => simpleReelProgress; public event Action ItemCaught; private void OnEnable() { RegisterInputAction(resetAction, OnResetAction, ref resetActionWasEnabled); } private void OnDisable() { UnregisterInputAction(resetAction, OnResetAction, resetActionWasEnabled); } private void Start() { if (autoBindMissingReferences) AutoBindMissingReferences(); ValidateRuntimeSettings(); if (startOnAwake) StartFishing(); else InitializeIdleUI(); } private void Update() { if (!activeGame) return; UpdateSimpleReelCatch(); } private void LateUpdate() { UpdateMemoryPieceResultFollow(); } private void OnValidate() { ValidateRuntimeSettings(); } [ContextMenu("Auto Bind Fishing References")] public void AutoBindMissingReferences() { Transform searchRoot = GetSearchRoot(); if (uiRoot == null) { Transform canvasTransform = FindTransformRecursive(searchRoot, "FishingCanvas"); if (canvasTransform != null) uiRoot = canvasTransform.gameObject; } if (ui == null) ui = searchRoot != null ? searchRoot.GetComponentInChildren(true) : GetComponentInChildren(true); if (rewardSystem == null) rewardSystem = searchRoot != null ? searchRoot.GetComponentInChildren(true) : GetComponentInChildren(true); if (haptic == null) haptic = searchRoot != null ? searchRoot.GetComponentInChildren(true) : GetComponentInChildren(true); if (rodController == null) rodController = searchRoot != null ? searchRoot.GetComponentInChildren(true) : GetComponentInChildren(true); if (gameClear == null) gameClear = searchRoot != null ? searchRoot.GetComponentInChildren(true) : GetComponentInChildren(true); if (memoryPieceResultSceneObject == null) { Transform memoryPieceResultTransform = FindTransformRecursive(searchRoot, "MemoryPieceResultObject"); if (memoryPieceResultTransform == null) memoryPieceResultTransform = FindTransformRecursive(searchRoot, "MemoryPieceScreenObject"); if (memoryPieceResultTransform == null) memoryPieceResultTransform = FindTransformRecursive(searchRoot, "MemoryPieceResultVisual"); if (memoryPieceResultTransform != null) memoryPieceResultSceneObject = memoryPieceResultTransform.gameObject; } } private Transform GetSearchRoot() { Transform current = transform; while (current.parent != null) current = current.parent; return current; } private Transform FindTransformRecursive(Transform current, string targetName) { if (current == null || string.IsNullOrEmpty(targetName)) return null; if (NormalizeName(current.name) == NormalizeName(targetName)) return current; for (int i = 0; i < current.childCount; i++) { Transform found = FindTransformRecursive(current.GetChild(i), targetName); if (found != null) return found; } return null; } private string NormalizeName(string value) { return value.Replace(" ", string.Empty) .Replace("_", string.Empty) .Replace("-", string.Empty) .ToLowerInvariant(); } private void RegisterInputAction(InputActionReference actionReference, System.Action callback, ref bool wasEnabled) { if (actionReference == null || actionReference.action == null) return; wasEnabled = actionReference.action.enabled; actionReference.action.performed += callback; if (enableInputActionsManually && !wasEnabled) actionReference.action.Enable(); } private void UnregisterInputAction(InputActionReference actionReference, System.Action callback, bool wasEnabled) { if (actionReference == null || actionReference.action == null) return; actionReference.action.performed -= callback; if (enableInputActionsManually && !wasEnabled) actionReference.action.Disable(); } private void ValidateRuntimeSettings() { requiredCleanupItems = Mathf.Max(1, requiredCleanupItems); catchCompleteLineLength = Mathf.Max(0.05f, catchCompleteLineLength); simpleReelMinimumPullDistance = Mathf.Max(0.01f, simpleReelMinimumPullDistance); finalResultShowTime = Mathf.Max(0f, finalResultShowTime); memoryPieceResultDistance = Mathf.Max(0.1f, memoryPieceResultDistance); memoryPieceResultShowTime = Mathf.Max(0f, memoryPieceResultShowTime); cleanupItemCount = Mathf.Max(0, cleanupItemCount); totalCaughtItems = Mathf.Max(0, totalCaughtItems); } private void InitializeIdleUI() { if (ui == null) return; ui.InitializeFishingUI(); ui.UpdateFishingProgress(cleanupItemCount, requiredCleanupItems, pondCleaned, memoryPieceCollected, totalCaughtItems); ui.UpdateInventoryUI(sessionFishCount, sessionTrashCount, sessionMemoryPieceCount); ui.SetSimpleReelUIVisible(false); ui.UpdateSimpleReelUI(0f, rodController != null ? rodController.CurrentLineLength : 0f, false); } public void StartFishing() { StartFishing(false); } public void StartFishing(bool forceRestart) { ValidateRuntimeSettings(); if (preventRestartWhileSessionRunning && fishingSessionRunning && !forceRestart) { if (showDebugLog) Debug.Log("낚시 세션이 이미 진행 중이라 StartFishing 호출을 무시했습니다.", this); return; } StopRunningRoutines(); if (uiRoot != null) uiRoot.SetActive(true); bool shouldResetPondState = forceRestart || resetPondStateOnStart; if (resetPondOnlyOnFirstStart) shouldResetPondState = forceRestart || (resetPondStateOnStart && !pondInitialized); if (shouldResetPondState) { ResetPondState(); pondInitialized = true; } fishingSessionRunning = true; if (ui != null) ui.InitializeFishingUI(); StartSimpleReelCatch(); if (showDebugLog) Debug.Log("릴 감기 낚시 시작", this); } public void StopFishing(bool hideUI = false) { StopRunningRoutines(); activeGame = false; fishingSessionRunning = false; simpleReelCatchActive = false; simpleReelProgress = 0f; if (ui != null) ui.SetSimpleReelUIVisible(false); if (hideUI && uiRoot != null) uiRoot.SetActive(false); } public void ResetFishing() { fishingSessionRunning = false; simpleReelCatchActive = false; pondInitialized = false; StartFishing(true); } public void ResetPondState() { cleanupItemCount = 0; totalCaughtItems = 0; sessionFishCount = 0; sessionTrashCount = 0; sessionMemoryPieceCount = 0; pondCleaned = false; memoryPieceCollected = false; simpleReelCatchActive = false; simpleReelProgress = 0f; simpleReelStartLineLength = 0f; HideMemoryPieceResultObject(); } private void StartSimpleReelCatch() { if (rodController == null && autoBindMissingReferences) AutoBindMissingReferences(); if (rodController == null) { Debug.LogWarning("[FishingGameManager] 릴 감기 낚시에는 FishingRodVRController 참조가 필요합니다.", this); activeGame = false; fishingSessionRunning = false; simpleReelCatchActive = false; return; } activeGame = true; simpleReelCatchActive = true; // 중요: 기존 코드에서는 simpleReelStartLineLength만 보정하고 실제 줄 길이는 그대로라서 // 찌가 대기 위치에 있으면 시작 즉시 성공할 수 있었습니다. // 릴 전용 버전에서는 실제 줄 길이도 최소 시작 길이로 맞춥니다. float minimumStartLength = catchCompleteLineLength + simpleReelMinimumPullDistance; if (rodController.CurrentLineLength < minimumStartLength) rodController.ForceSetReelLineLength(minimumStartLength); rodController.ForceMiniGameActiveState(); simpleReelStartLineLength = Mathf.Max(rodController.CurrentLineLength, minimumStartLength); simpleReelProgress = 0f; if (ui != null) { ui.SetSimpleReelUIVisible(true); ui.UpdateSimpleReelUI(simpleReelProgress, rodController.CurrentLineLength, rodController.IsReeling); ui.ShowPersistentResult("릴을 감아 끌어올려라!"); } UpdateUI(); } private void UpdateSimpleReelCatch() { if (!simpleReelCatchActive || rodController == null) return; float currentLineLength = rodController.CurrentLineLength; float totalPullDistance = Mathf.Max(0.001f, simpleReelStartLineLength - catchCompleteLineLength); float pulledDistance = simpleReelStartLineLength - currentLineLength; simpleReelProgress = Mathf.Clamp01(pulledDistance / totalPullDistance); if (ui != null) ui.UpdateSimpleReelUI(simpleReelProgress, currentLineLength, rodController.IsReeling); if (currentLineLength <= catchCompleteLineLength || simpleReelProgress >= 1f) { simpleReelCatchActive = false; activeGame = false; if (haptic != null) haptic.Perfect(); if (ui != null) { ui.UpdateSimpleReelUI(1f, currentLineLength, false); ui.ShowPersistentResult("낚았다!"); } CatchItemSuccess(); } } private void StopRunningRoutines() { if (finalResultRoutine != null) { StopCoroutine(finalResultRoutine); finalResultRoutine = null; } if (memoryPieceResultRoutine != null) { StopCoroutine(memoryPieceResultRoutine); memoryPieceResultRoutine = null; } HideMemoryPieceResultObject(); } private void CatchItemSuccess() { bool forceMemoryPiece = pondCleaned && guaranteeMemoryPieceAfterCleaned && !memoryPieceCollected; FishingRewardSystem.CatchResult catchResult; if (rewardSystem != null) catchResult = rewardSystem.RollCatch(pondCleaned, forceMemoryPiece); else catchResult = new FishingRewardSystem.CatchResult(FishingItemType.Fish, "물고기", false, false); ApplyCatchResult(catchResult); } private void ApplyCatchResult(FishingRewardSystem.CatchResult catchResult) { totalCaughtItems++; AddToSessionCounts(catchResult.ItemType); ItemCaught?.Invoke(catchResult.ItemType, 1); bool pondJustCleaned = false; string extraHint = string.Empty; if (catchResult.CountsAsCleanupItem) { cleanupItemCount = Mathf.Min(cleanupItemCount + 1, requiredCleanupItems); extraHint = $"연못 정화 {cleanupItemCount}/{requiredCleanupItems}"; if (!pondCleaned && cleanupItemCount >= requiredCleanupItems) { pondCleaned = true; pondJustCleaned = true; extraHint = "연못이 맑아졌다. 기억의 조각이 모습을 드러낸다."; } } if (catchResult.IsMemoryPiece) { memoryPieceCollected = true; extraHint = "잃어버린 기억의 일부다."; } UpdateUI(); if (ui != null) { ui.HighlightSlotForItem(catchResult.ItemType); if (!catchResult.IsMemoryPiece) ui.ShowCaughtItem(catchResult.ItemType, catchResult.DisplayName, catchResult.CountsAsCleanupItem, extraHint); if (pondJustCleaned) ui.ShowNotice("연못이 맑아졌다!\n기억의 조각이 모습을 드러냈다!"); } if (showDebugLog) Debug.Log($"{catchResult.DisplayName}을(를) 낚았다!", this); fishingSessionRunning = false; simpleReelCatchActive = false; activeGame = false; if (returnBobberAfterCatch && rodController != null) rodController.ReturnBobberToRest(); if (catchResult.IsMemoryPiece) FishingSuccess(); } private void AddToSessionCounts(FishingItemType itemType) { switch (itemType) { case FishingItemType.Fish: sessionFishCount++; break; case FishingItemType.Trash: sessionTrashCount++; break; case FishingItemType.MemoryPiece: sessionMemoryPieceCount++; break; } } private void UpdateUI() { if (ui == null) return; ui.SetSimpleReelUIVisible(activeGame || simpleReelCatchActive); ui.UpdateFishingProgress(cleanupItemCount, requiredCleanupItems, pondCleaned, memoryPieceCollected, totalCaughtItems); ui.UpdateInventoryUI(sessionFishCount, sessionTrashCount, sessionMemoryPieceCount); float currentLineLength = rodController != null ? rodController.CurrentLineLength : 0f; bool isReeling = rodController != null && rodController.IsReeling; ui.UpdateSimpleReelUI(simpleReelProgress, currentLineLength, isReeling); } private void FishingSuccess() { activeGame = false; fishingSessionRunning = false; simpleReelCatchActive = false; UpdateUI(); if (ui != null) ui.ShowFinalResult("기억의 조각 획득!\n기묘한 낚시터 클리어!"); ShowMemoryPieceResultObject(); if (gameClear != null) { gameClear.OnGameClear(); } else if (showDebugLog) { Debug.LogWarning("[FishingGameManager] GameClear가 연결되지 않아 NPC 이동/대화존 변경/문 선택지 세팅을 실행하지 못했습니다.", this); } if (showDebugLog) Debug.Log("기묘한 낚시터 클리어", this); BeginFinalResultRoutineIfNeeded(); } private void BeginFinalResultRoutineIfNeeded() { if (!hideUIRootAfterFinalResult || uiRoot == null) return; if (finalResultRoutine != null) StopCoroutine(finalResultRoutine); finalResultRoutine = StartCoroutine(HideUIRootAfterFinalResultRoutine()); } private IEnumerator HideUIRootAfterFinalResultRoutine() { yield return new WaitForSeconds(finalResultShowTime); if (uiRoot != null) uiRoot.SetActive(false); HideMemoryPieceResultObject(); finalResultRoutine = null; } private void ShowMemoryPieceResultObject() { EnsureMemoryPiecePlayerHead(); if (memoryPiecePlayerHead == null) { Debug.LogWarning("[FishingGameManager] Memory Piece Player Head가 없습니다. XR Origin의 Main Camera를 연결하세요.", this); return; } if (memoryPieceResultRoutine != null) { StopCoroutine(memoryPieceResultRoutine); memoryPieceResultRoutine = null; } if (currentMemoryPieceResultObject != null && currentMemoryPieceResultObject != memoryPieceResultSceneObject) { Destroy(currentMemoryPieceResultObject); currentMemoryPieceResultObject = null; } if (memoryPieceResultSceneObject != null) { currentMemoryPieceResultObject = memoryPieceResultSceneObject; } else if (memoryPieceResultPrefab != null) { currentMemoryPieceResultObject = Instantiate(memoryPieceResultPrefab); } else { if (showDebugLog) Debug.LogWarning("[FishingGameManager] Memory Piece Result Prefab 또는 Scene Object가 연결되지 않았습니다.", this); return; } currentMemoryPieceResultObject.SetActive(true); if (memoryPieceResultUseCustomScale) currentMemoryPieceResultObject.transform.localScale = memoryPieceResultCustomScale; PrepareMemoryPieceResultObject(currentMemoryPieceResultObject); PlaceMemoryPieceResultObjectInFrontOfPlayer(); memoryPieceResultShowing = true; if (memoryPieceResultShowTime > 0f) memoryPieceResultRoutine = StartCoroutine(HideMemoryPieceResultObjectAfterDelay()); } private void HideMemoryPieceResultObject() { memoryPieceResultShowing = false; if (memoryPieceResultRoutine != null) { StopCoroutine(memoryPieceResultRoutine); memoryPieceResultRoutine = null; } if (currentMemoryPieceResultObject == null) return; if (currentMemoryPieceResultObject == memoryPieceResultSceneObject) { currentMemoryPieceResultObject.SetActive(false); } else if (destroySpawnedMemoryPieceResultOnHide) { Destroy(currentMemoryPieceResultObject); } else { currentMemoryPieceResultObject.SetActive(false); } currentMemoryPieceResultObject = null; } private IEnumerator HideMemoryPieceResultObjectAfterDelay() { yield return new WaitForSeconds(memoryPieceResultShowTime); memoryPieceResultRoutine = null; HideMemoryPieceResultObject(); } private void UpdateMemoryPieceResultFollow() { if (!memoryPieceResultShowing || !memoryPieceResultFollowPlayerHead || currentMemoryPieceResultObject == null) return; PlaceMemoryPieceResultObjectInFrontOfPlayer(); } private void EnsureMemoryPiecePlayerHead() { if (memoryPiecePlayerHead != null) return; Camera mainCamera = Camera.main; if (mainCamera != null) memoryPiecePlayerHead = mainCamera.transform; } private void PlaceMemoryPieceResultObjectInFrontOfPlayer() { if (memoryPiecePlayerHead == null || currentMemoryPieceResultObject == null) return; Vector3 forward = memoryPiecePlayerHead.forward; Vector3 right = memoryPiecePlayerHead.right; if (memoryPieceResultYawOnly) { forward.y = 0f; if (forward.sqrMagnitude < 0.0001f) forward = currentMemoryPieceResultObject.transform.forward; forward.Normalize(); right = Vector3.Cross(Vector3.up, forward).normalized; } Vector3 targetPosition = memoryPiecePlayerHead.position + forward * memoryPieceResultDistance + Vector3.up * memoryPieceResultHeightOffset + right * memoryPieceResultSideOffset; currentMemoryPieceResultObject.transform.position = targetPosition; if (!memoryPieceResultFacePlayer) return; Vector3 lookDirection = memoryPiecePlayerHead.position - currentMemoryPieceResultObject.transform.position; if (memoryPieceResultYawOnly) lookDirection.y = 0f; if (lookDirection.sqrMagnitude > 0.0001f) currentMemoryPieceResultObject.transform.rotation = Quaternion.LookRotation(lookDirection.normalized, Vector3.up); } private void PrepareMemoryPieceResultObject(GameObject target) { if (target == null) return; if (disableMemoryPieceResultColliders) { Collider[] colliders = target.GetComponentsInChildren(true); for (int i = 0; i < colliders.Length; i++) colliders[i].enabled = false; } if (disableMemoryPieceResultFloatMotion) { StarPickup[] starPickups = target.GetComponentsInChildren(true); for (int i = 0; i < starPickups.Length; i++) starPickups[i].floatMotion = false; } } private void OnResetAction(InputAction.CallbackContext context) { ResetFishing(); } }