Files
2026-03-04 10:03:45 +08:00

643 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using UFS2.Gameplay;
using UFS2.ScriptableObjects;
using UnityEngine;
public class FishFightState : IState
{
private static float takeTimeAmount = 5f;
private static float spitOutBaitTimeThresholdWhenNoTension = 15f;
private FishEntity entity;
private FHook bait;
private FLure lure;
private FRod rod;
private float takeTime;
private float baitTakeAttempts;
private bool isStrikeEnter;
private bool isSpitoutBite;
private float lastTimeWhenTensionApplied;
private float wigglingTimer;
private float wigglingAmount;
private bool wigglingActive;
private bool wigglingCooldown;
private Vector3 moveDirection;
private float changeTime;
private LayerMask obstacleMask = LayerMask.GetMask("Default", "Terrain", "UnderwaterObject", "Bridges");
private float yankTimer;
private int yankCount;
private bool yankCooldown;
private Rigidbody defaultBaitBody;
private Rigidbody defaultLurebody;
private bool isTimerCanChange => changeTime < Time.time;
private bool isInWater
{
get
{
if (GameWaterSystem.IsPositionUnderWater(entity.transform.position + Vector3.up * 0.25f))
{
return GameWaterSystem.IsPositionUnderWater(entity.JointAnchor.position);
}
return false;
}
}
private float velocityLimit => entity.MoveSpeed / entity.Physics.Rbody.drag;
public static event Action OnEnter;
public static event Action OnExit;
public static event Action OnFishCanTake;
public static event Action OnFishStrikeEnter;
public static event Action OnFishYank;
public FishFightState(FishEntity entity)
{
this.entity = entity;
}
private void ConnectFishToLine(Rigidbody rb)
{
entity.Physics.Rbody.mass = 15f;
entity.SetCurrentFishInFight(rod);
Rigidbody endLineRigidbody = rod.fishingLine.currentLineHandler.EndLineRigidbody;
entity.Physics.AttachFishToBody(endLineRigidbody, entity.GetJointAnchorPositionScaled);
}
public void Enter()
{
FishFightState.OnEnter?.Invoke();
bait = null;
lure = null;
rod = null;
FHook component2;
if (entity.LureTarget.TryGetComponent<FLure>(out var component))
{
lure = component;
rod = component.currentRod;
ConnectFishToLine(component.rigidbody);
SettingLure(component, isJoinedToFish: true);
}
else if (entity.LureTarget.TryGetComponent<FHook>(out component2))
{
bait = component2;
rod = component2.currentRod;
ConnectFishToLine(component2.rigidbody);
SettingBait(component2, isJoinedToFish: true);
}
takeTime = Time.time + takeTimeAmount;
if ((bool)bait)
{
takeTime += 3.5f;
}
baitTakeAttempts = 3f;
isStrikeEnter = false;
isSpitoutBite = false;
lastTimeWhenTensionApplied = Time.time;
moveDirection = entity.transform.forward;
changeTime = Time.time;
entity.MoveSpeed = entity.Data.MoveMaxSpeed;
entity.Target = null;
SetCollidersTrigger(value: false);
entity.SetAIEnabled(value: false);
entity.ResetRotate();
entity.Physics.ResetTail();
entity.WeightTugging = FScriptsHandler.Instance.fishFightData.GetTuggingForceActiveFight(entity);
entity.FightTime = 0f;
entity.Stamina01 = 1f;
yankTimer = Time.time;
yankCount = 0;
yankCooldown = false;
if (Singleton<SaveDataManager>.Instance.SettingsData.IsControllerVibrationEnabled)
{
GameManager.Instance.ControllerVibrate(0.5f, 1);
}
}
public void Execute()
{
if (entity.IsCatched)
{
return;
}
SpitOutHandler();
if (isSpitoutBite)
{
return;
}
VelocityLimitHandler();
EnterStrike();
if ((bool)lure)
{
lure.transform.position = entity.JointAnchor.position;
}
if ((bool)bait)
{
bait.transform.position = entity.JointAnchor.position;
}
if ((bool)lure)
{
FightBehaviourHandler();
}
if (!bait)
{
return;
}
if (!entity.IsHooked)
{
if (entity.Data.BehaviourType == FishBehaviourType.ActivePredator || entity.Data.BehaviourType == FishBehaviourType.PassivePredator)
{
FightBehaviourHandler();
}
else
{
BaitBehaviourHandler();
}
}
else
{
FightBehaviourHandler();
}
}
public void Exit()
{
if ((bool)lure)
{
SettingLure(lure, isJoinedToFish: false);
}
if ((bool)bait)
{
SettingBait(bait, isJoinedToFish: false);
}
FishFightState.OnExit?.Invoke();
Rigidbody rbody = entity.Physics.Rbody;
rbody.mass = 1f;
rbody.useGravity = true;
rbody.angularDrag = 1f;
rbody.drag = 1f;
entity.Physics.ResetTail();
entity.Physics.VelocityLimit = -1f;
entity.SetAnimatorFloat("AngularVelocityY", 0f);
entity.SetAnimatorFloat("speed", 0f);
entity.SetAnimatorBool("jump", b: false);
entity.SetIKAndAnimatorLayers(0f);
entity.IsHooked = false;
entity.LastCatchTime = Time.time;
if ((bool)rod && (bool)rod.fishingLine)
{
rod.fishingLine.CurrentLineTension = 0f;
}
}
private void SpitOutHandler()
{
if (isSpitoutBite)
{
return;
}
if (!entity.IsCanFight)
{
SpitOutBait();
}
else if (entity.IsHooked && lastTimeWhenTensionApplied + spitOutBaitTimeThresholdWhenNoTension < Time.time)
{
SpitOutBait();
}
else
{
if (entity.IsHooked || !(takeTime < Time.time))
{
return;
}
if ((bool)bait && baitTakeAttempts > 0f)
{
FishFightState.OnFishCanTake?.Invoke();
baitTakeAttempts -= 1f;
takeTime += 2f;
Vector3[] array = new Vector3[3]
{
-entity.LureTarget.up,
entity.LureTarget.right,
-entity.LureTarget.right
};
Vector3 direction = array[UnityEngine.Random.Range(0, array.Length)];
entity.Physics.MoveInDirection(direction, 10f, 15f, Time.deltaTime, ForceMode.Impulse);
if (baitTakeAttempts <= 0f)
{
SpitOutBait();
}
}
if ((bool)lure)
{
SpitOutBait();
}
}
}
private void VelocityLimitHandler()
{
entity.Physics.VelocityLimit = velocityLimit;
if (!(entity.Data.Weight > 100f))
{
return;
}
if (yankCooldown)
{
if (Time.time > yankTimer)
{
yankCooldown = false;
}
}
else if (entity.Physics.Rbody.velocity.magnitude > velocityLimit * 2.5f)
{
yankCount++;
yankTimer = Time.time + 2f;
yankCooldown = true;
if (yankCount >= 3)
{
rod.CutLine(destroyBaits: true);
FishFightState.OnFishYank?.Invoke();
}
}
}
private void SpitOutBait()
{
entity.SpitOutBait();
SetCollidersTrigger(value: true);
if (!entity.IsCatched && Singleton<SaveDataManager>.Instance.SettingsData.IsControllerVibrationEnabled)
{
GameManager.Instance.ControllerVibrate(0.5f, 1);
}
isSpitoutBite = true;
}
private void EnterStrike()
{
if (entity.IsHooked && !isStrikeEnter)
{
isStrikeEnter = true;
FishFightState.OnFishStrikeEnter?.Invoke();
}
}
private void StaminaHandler()
{
entity.Stamina01 = 1f - Mathf.Clamp01(entity.FightTime / FScriptsHandler.Instance.fishFightData.GetFightTime(entity));
float tuggingForceActiveFight = FScriptsHandler.Instance.fishFightData.GetTuggingForceActiveFight(entity);
float tuggingForceWeakFight = FScriptsHandler.Instance.fishFightData.GetTuggingForceWeakFight(entity);
float tuggingForceExhausted = FScriptsHandler.Instance.fishFightData.GetTuggingForceExhausted(entity);
entity.WeightTugging = Mathf.Lerp(tuggingForceWeakFight, tuggingForceActiveFight, entity.Stamina01);
if (entity.Stamina01 <= 0f)
{
entity.WeightTugging = tuggingForceExhausted;
entity.WeightTugging = Mathf.Min(entity.WeightTugging, 90f);
}
}
private void DirectionChangeHandler()
{
bool directionChangeNeeded;
bool escapeFound;
Vector3 alleyEscapeDirection = GetAlleyEscapeDirection(out directionChangeNeeded, out escapeFound);
if (!isInWater || directionChangeNeeded)
{
changeTime = Mathf.Min(changeTime, Time.time + 0.2f);
}
if (!isTimerCanChange)
{
return;
}
if (!isInWater && !directionChangeNeeded)
{
ChangeTime(0.5f, 1f);
moveDirection = Vector3.down;
return;
}
if (directionChangeNeeded)
{
ChangeTime();
moveDirection = alleyEscapeDirection;
return;
}
ChangeTime();
Transform transform = FScriptsHandler.Instance.m_PlayerMain.transform;
Vector3 forward = transform.forward;
Vector3 right = transform.right;
Vector3 up = transform.up;
float num = Vector3.Distance(transform.position, entity.transform.position);
List<Vector3> list = new List<Vector3>
{
right + -forward,
-right + -forward,
forward,
right + forward,
-right + forward,
right,
-right
};
if (num > 6f)
{
list.Add(up + forward);
list.Add(-up + forward);
}
int index = UnityEngine.Random.Range(0, list.Count);
moveDirection = list[index];
}
private void HandleLine()
{
_ = FScriptsHandler.Instance.m_PlayerMain;
FFishingLine fishingLine = rod.fishingLine;
float reelingDrag = rod.currentReel.reelingDrag;
float linePullingForce = rod.currentReel.LinePullingForce;
entity.Physics.SetJointDistance(fishingLine.currentLineHandler.ObiLineOut);
fishingLine.CurrentLineTension = fishingLine.GetTension(entity.WeightTugging) * 2f;
if (fishingLine.CurrentLineTension > 0f)
{
lastTimeWhenTensionApplied = Time.time;
if (reelingDrag < 1f && fishingLine.CurrentLineTension > linePullingForce)
{
float num = Mathf.Clamp01((fishingLine.CurrentLineTension - linePullingForce) / 10f);
float amount = entity.MoveSpeed * Time.deltaTime * num;
fishingLine.currentLineHandler.SetRopeLenght(amount, rod);
}
}
}
private void HandleFishAnimator(bool jaw = false)
{
if (wigglingCooldown)
{
if (Time.time > wigglingTimer)
{
wigglingActive = false;
wigglingCooldown = false;
}
}
else if (wigglingActive)
{
if (Time.time > wigglingTimer)
{
wigglingActive = false;
wigglingCooldown = true;
wigglingTimer = Time.time + 3f;
}
}
else if (!isInWater || entity.Physics.IsJointTension)
{
wigglingActive = true;
wigglingCooldown = false;
wigglingTimer = Time.time + 1f;
}
wigglingAmount = Mathf.MoveTowards(wigglingAmount, wigglingActive ? (entity.GetMoveSpeedAnimation() * 1.7f) : entity.GetMoveSpeedAnimation(), Time.deltaTime * 4f);
entity.SetAnimatorFloat("AngularVelocityY", 0f);
entity.SetAnimatorFloat("speed", wigglingAmount);
entity.SetAnimatorBool("jump", !isInWater);
entity.SetAnimatorBool("jaw", jaw);
}
private void BaitBehaviourHandler()
{
StaminaHandler();
moveDirection = entity.LureTarget.forward;
float moveSpeed = Mathf.MoveTowards(entity.MoveSpeed, entity.MoveSpeed * 0.4f, Time.deltaTime);
float rotationSpeed = 3f;
entity.MoveSpeed = moveSpeed;
entity.Physics.MoveInDirection(moveDirection, entity.MoveSpeed, rotationSpeed, Time.deltaTime);
HandleLine();
HandleFishAnimator(jaw: true);
}
private void FightBehaviourHandler()
{
entity.FightTime += Time.deltaTime;
StaminaHandler();
DirectionChangeHandler();
float moveSpeed = Mathf.Lerp(entity.Data.MoveSpeed * 0.7f, entity.Data.MoveMaxSpeed, entity.Stamina01);
if (entity.Stamina01 <= 0f)
{
moveSpeed = entity.Data.MoveSpeed * 0.3f;
}
float rotationSpeed = 3f;
entity.MoveSpeed = moveSpeed;
entity.Physics.MoveInDirection(moveDirection, entity.MoveSpeed, rotationSpeed, Time.deltaTime);
HandleLine();
HandleFishAnimator();
if (rod.fishingLine.linelenghtDiferent > 0.8f && Singleton<SaveDataManager>.Instance.SettingsData.IsControllerVibrationEnabled)
{
GameManager.Instance.ControllerVibrate(0.5f, 1);
}
}
private Vector3 GetAlleyEscapeDirection(out bool directionChangeNeeded, out bool escapeFound)
{
Vector3 result = Vector3.zero;
directionChangeNeeded = true;
escapeFound = false;
Vector3 right = entity.transform.right;
Vector3 up = entity.transform.up;
Vector3 forward = entity.transform.forward;
List<Vector3> dirList = new List<Vector3>
{
forward,
(up + forward).normalized,
(-up + forward).normalized,
(right + forward).normalized,
(-right + forward).normalized
};
bool flag = false;
Vector3 hitNormal = Vector3.zero;
Vector3 hitPoint = Vector3.zero;
foreach (Vector3 item in dirList)
{
if (RaycastForObstacles(item, out hitNormal, out hitPoint))
{
flag = true;
break;
}
}
Vector3 directionOppositeObstacle;
Vector3 perpendicular;
if (flag)
{
directionChangeNeeded = true;
directionOppositeObstacle = (entity.transform.position - hitPoint).normalized;
Vector3 lhs = ((Mathf.Abs(Vector3.Dot(directionOppositeObstacle, Vector3.up)) < 0.99f) ? Vector3.up : Vector3.right);
Vector3 hitNormal2 = Vector3.Cross(lhs, directionOppositeObstacle);
perpendicular = hitNormal2.normalized;
dirList.Clear();
dirList.Add(directionOppositeObstacle);
AddDirectionsAround(30f);
AddDirectionsAround(70f);
dirList.Sort(delegate(Vector3 a, Vector3 b)
{
float value = Vector3.Dot(forward, a);
return Vector3.Dot(forward, b).CompareTo(value);
});
foreach (Vector3 item2 in dirList)
{
if (!RaycastForObstacles(item2, out hitNormal2, out var _))
{
result = item2;
directionChangeNeeded = true;
escapeFound = true;
break;
}
}
}
else
{
result = forward;
directionChangeNeeded = false;
escapeFound = true;
}
if (!escapeFound)
{
Debug.Log("Fish fight rotation return zero");
}
return result;
void AddDirectionsAround(float angle)
{
for (int i = 0; i < 4; i++)
{
Vector3 vector = directionOppositeObstacle;
vector = Quaternion.AngleAxis(angle, perpendicular) * vector;
vector = Quaternion.AngleAxis(90f * (float)i, directionOppositeObstacle) * vector;
vector.Normalize();
dirList.Add(vector);
}
}
}
private void SetCollidersTrigger(bool value)
{
Collider[] componentsInChildren = entity.GetComponentsInChildren<Collider>();
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].isTrigger = value;
}
}
private void ChangeTime(float min = 3f, float max = 7f)
{
changeTime = Time.time + UnityEngine.Random.Range(min, max);
}
private bool RaycastForObstacles(Vector3 direction, out Vector3 hitNormal, out Vector3 hitPoint, float originBackwardOffset = 0.2f)
{
Vector3 origin = -direction * originBackwardOffset + entity.transform.position;
float maxDistance = Vector3.Distance(entity.JointAnchor.position, entity.transform.position) + originBackwardOffset + 0.5f;
RaycastHit hitInfo;
bool num = Physics.Raycast(origin, direction, out hitInfo, maxDistance, obstacleMask);
if (num)
{
hitNormal = hitInfo.normal;
hitPoint = hitInfo.point;
return num;
}
hitNormal = Vector3.zero;
hitPoint = Vector3.zero;
return num;
}
private void SettingBait(FHook bait, bool isJoinedToFish)
{
Rigidbody rigidbody = bait?.currentRod?.fishingLine?.currentLineHandler?.EndLineRigidbody;
if (isJoinedToFish)
{
defaultBaitBody = bait.CfgJoint.connectedBody;
bait.HideRenderer();
bait.rigidbody.rotation = entity.JointAnchor.rotation;
bait.CfgJoint.connectedBody.velocity = entity.Physics.Rbody.velocity;
bait.CfgJoint.connectedBody = null;
bait.GetComponent<Collider>().enabled = false;
bait.Rigidbody.isKinematic = true;
bait.CfgJoint.enableCollision = false;
bait.CfgJoint.autoConfigureConnectedAnchor = false;
bait.CfgJoint.connectedAnchor = entity.GetJointAnchorPositionScaled;
if ((bool)rigidbody)
{
rigidbody.useGravity = false;
}
}
else
{
bait.ShowRenderer();
bait.CfgJoint.connectedBody = defaultBaitBody;
bait.GetComponent<Collider>().enabled = true;
bait.Rigidbody.isKinematic = false;
bait.CfgJoint.enableCollision = true;
bait.CfgJoint.autoConfigureConnectedAnchor = false;
bait.CfgJoint.connectedAnchor = Vector3.zero;
if ((bool)defaultBaitBody)
{
bait.transform.position = defaultBaitBody.position;
}
if ((bool)rigidbody)
{
rigidbody.useGravity = true;
}
}
}
private void SettingLure(FLure lure, bool isJoinedToFish)
{
Rigidbody endLineRigidbody = lure.currentRod.fishingLine.currentLineHandler.EndLineRigidbody;
if (isJoinedToFish)
{
defaultLurebody = lure.CfgJoint.connectedBody;
lure.HideRenderer();
lure.CfgJoint.connectedBody.velocity = entity.Physics.Rbody.velocity;
lure.rigidbody.rotation = entity.JointAnchor.rotation;
lure.CfgJoint.connectedBody = null;
lure.GetComponent<Collider>().enabled = false;
lure.rigidbody.isKinematic = true;
lure.CfgJoint.enableCollision = false;
lure.CfgJoint.autoConfigureConnectedAnchor = false;
lure.CfgJoint.connectedAnchor = entity.GetJointAnchorPositionScaled;
endLineRigidbody.useGravity = false;
}
else
{
lure.ShowRenderer();
lure.CfgJoint.connectedBody = defaultLurebody;
lure.GetComponent<Collider>().enabled = true;
lure.rigidbody.isKinematic = false;
lure.CfgJoint.enableCollision = true;
lure.CfgJoint.autoConfigureConnectedAnchor = false;
lure.CfgJoint.connectedAnchor = Vector3.zero;
lure.transform.position = defaultLurebody.position;
endLineRigidbody.useGravity = true;
}
}
}