1187 lines
28 KiB
C#
1187 lines
28 KiB
C#
using System;
|
|
using Lean.Pool;
|
|
using Obvious.Soap;
|
|
using Photon.Pun;
|
|
using QFSW.QC;
|
|
using RootMotion.FinalIK;
|
|
using ShiningGames.UFS2;
|
|
using Sirenix.Utilities;
|
|
using UFS2.ScriptableObjects;
|
|
using UnityEngine;
|
|
|
|
namespace UFS2.Gameplay
|
|
{
|
|
public class FishEntity : FishFSM
|
|
{
|
|
private static FishEntity _CurrentFishInFight;
|
|
|
|
private static FishEntity _CurrentFishInAttack;
|
|
|
|
[Command("FishStaminaMod", "default 1", Platform.AllPlatforms, MonoTargetType.Single)]
|
|
public static float StaminaModifier = 1f;
|
|
|
|
[Command("FishSpeedMod", "default 1", Platform.AllPlatforms, MonoTargetType.Single)]
|
|
public static float GlobalSpeedModifier = 1f;
|
|
|
|
[SerializeField]
|
|
private Vector3Variable player_CurrentPosition;
|
|
|
|
[SerializeField]
|
|
private FishData _Data;
|
|
|
|
[SerializeField]
|
|
private Transform _JointAnchor;
|
|
|
|
private float _Weight;
|
|
|
|
private FishPhysics _Physics;
|
|
|
|
private FishScanner _FishScanner;
|
|
|
|
private Animator _Animator;
|
|
|
|
private LocalAvoidance _AI;
|
|
|
|
private CCDIK _IK;
|
|
|
|
public FishTargetArea CurrentArea;
|
|
|
|
private LODGroup lodGroup;
|
|
|
|
private Material[][] rendererMaterialsOriginal;
|
|
|
|
private Material[][] rendererMaterialsEagle;
|
|
|
|
public Transform LureTarget;
|
|
|
|
public Transform networkedTarget;
|
|
|
|
public FRod rod;
|
|
|
|
public float WeightTugging;
|
|
|
|
public float FightTime;
|
|
|
|
public float Stamina01;
|
|
|
|
public bool IsCatched;
|
|
|
|
private bool _IsCulled = true;
|
|
|
|
private bool _IsHooked;
|
|
|
|
private float lastCatchTime;
|
|
|
|
private float lastServerRequestTime;
|
|
|
|
private float nextCatchDelayInterval = 15f;
|
|
|
|
private bool _IsAtracted;
|
|
|
|
private bool _IsScarred;
|
|
|
|
public bool IsInDistanceToLure;
|
|
|
|
public bool IsInDistanceToBait;
|
|
|
|
public static FishEntity CurrentFishInFight
|
|
{
|
|
get
|
|
{
|
|
return _CurrentFishInFight;
|
|
}
|
|
set
|
|
{
|
|
_CurrentFishInFight = value;
|
|
FishEntity.OnSetCurrentFishInFight?.Invoke(value);
|
|
}
|
|
}
|
|
|
|
public static FishEntity CurrentFishInAttack
|
|
{
|
|
get
|
|
{
|
|
return _CurrentFishInAttack;
|
|
}
|
|
set
|
|
{
|
|
_CurrentFishInAttack = value;
|
|
FishEntity.OnSetCurrentFishInAttack?.Invoke(value);
|
|
}
|
|
}
|
|
|
|
public Vector3Variable Player_CurrentPosition
|
|
{
|
|
set
|
|
{
|
|
player_CurrentPosition = value;
|
|
}
|
|
}
|
|
|
|
public Transform JointAnchor
|
|
{
|
|
get
|
|
{
|
|
return _JointAnchor;
|
|
}
|
|
set
|
|
{
|
|
_JointAnchor = value;
|
|
}
|
|
}
|
|
|
|
public Vector3 GetJointAnchorPositionScaled => Vector3.Scale(JointAnchor.localPosition, base.transform.GetChild(0).localScale);
|
|
|
|
public FishData Data => _Data;
|
|
|
|
public FishPhysics Physics => _Physics;
|
|
|
|
public LocalAvoidance AI => _AI;
|
|
|
|
public Transform Target
|
|
{
|
|
get
|
|
{
|
|
return _AI.Target;
|
|
}
|
|
set
|
|
{
|
|
_AI.Target = value;
|
|
}
|
|
}
|
|
|
|
public FishScanner FishScanner => _FishScanner;
|
|
|
|
public float Weight => _Weight;
|
|
|
|
public bool IsHooked
|
|
{
|
|
get
|
|
{
|
|
return _IsHooked;
|
|
}
|
|
set
|
|
{
|
|
_IsHooked = value;
|
|
if (_IsHooked)
|
|
{
|
|
FishEntity.OnFishHooked?.Invoke();
|
|
}
|
|
}
|
|
}
|
|
|
|
public float LastCatchTime
|
|
{
|
|
get
|
|
{
|
|
return lastCatchTime;
|
|
}
|
|
set
|
|
{
|
|
lastCatchTime = value;
|
|
}
|
|
}
|
|
|
|
public FishState CurrentFishState => _State;
|
|
|
|
public bool IsCanFight => _IsCanFight;
|
|
|
|
private bool _CanInteractWithRod
|
|
{
|
|
get
|
|
{
|
|
if ((bool)rod)
|
|
{
|
|
if (!(FScriptsHandler.Instance.m_PlayerMain.currentRod == null))
|
|
{
|
|
return FScriptsHandler.Instance.m_PlayerMain.currentRod == rod;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private bool _IsCanAttack
|
|
{
|
|
get
|
|
{
|
|
if (!_IsDistanceToPlayerTresholdReached && (CurrentFishInAttack == null || CurrentFishInAttack == this) && CurrentFishInFight == null && (bool)LureTarget && CanFightWithLure() && GameWaterSystem.IsPositionUnderWater(LureTarget.position))
|
|
{
|
|
return _CanInteractWithRod;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private bool _IsCanFight
|
|
{
|
|
get
|
|
{
|
|
if (CurrentFishInFight == this && (bool)LureTarget)
|
|
{
|
|
return _CanInteractWithRod;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private bool _IsCanSendRequest => lastServerRequestTime + 0.2f < Time.time;
|
|
|
|
public float MoveSpeed
|
|
{
|
|
get
|
|
{
|
|
return _AI.MoveSpeed;
|
|
}
|
|
set
|
|
{
|
|
float moveSpeed = Mathf.Clamp(value, 0f, Data.MoveMaxSpeed);
|
|
_AI.MoveSpeed = moveSpeed;
|
|
}
|
|
}
|
|
|
|
private bool _IsDistanceToPlayerTresholdReached => _DistanceToPlayer < 3.5f;
|
|
|
|
private float _DistanceToPlayer => Vector3.Distance(player_CurrentPosition.Value, base.transform.position);
|
|
|
|
public bool IsCulled
|
|
{
|
|
get
|
|
{
|
|
return _IsCulled;
|
|
}
|
|
set
|
|
{
|
|
_IsCulled = value;
|
|
}
|
|
}
|
|
|
|
public static event Action<FishEntity> OnSetCurrentFishInFight;
|
|
|
|
public static event Action<FishEntity> OnSetCurrentFishInAttack;
|
|
|
|
public static event Action<Transform> OnBaitLock;
|
|
|
|
public static event Action<FishEntity> OnPreSpitOutBait;
|
|
|
|
public static event Action<FishEntity> OnPostSpitOutBait;
|
|
|
|
public static event Action<FishEntity> OnOldFishKill;
|
|
|
|
public static event Action OnFishHooked;
|
|
|
|
public float GetMoveSpeedAnimation()
|
|
{
|
|
return _AI.MoveSpeed * 0.25f;
|
|
}
|
|
|
|
private void FPlayer_OnFishPicked()
|
|
{
|
|
if (!(CurrentFishInFight != this))
|
|
{
|
|
IsCatched = true;
|
|
}
|
|
}
|
|
|
|
private void FRod_OnLineCutedGlobal(Transform obj)
|
|
{
|
|
TryDestroyFish();
|
|
}
|
|
|
|
private void FReel_OnReelDamagedGlobal(Transform obj)
|
|
{
|
|
TryDestroyFish();
|
|
}
|
|
|
|
private void FRod_OnRodDamagedGlobal(Transform obj)
|
|
{
|
|
TryDestroyFish();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
_IK = GetComponentInChildren<CCDIK>();
|
|
_Physics = GetComponent<FishPhysics>();
|
|
_FishScanner = GetComponent<FishScanner>();
|
|
_Animator = GetComponentInChildren<Animator>();
|
|
_AI = GetComponent<LocalAvoidance>();
|
|
_AI.OnLureHit += _AI_OnBaitHit;
|
|
_Physics.OnEnterWater += BuildSplash;
|
|
_Physics.Rbody.mass = 15f;
|
|
InitializeFSM(this);
|
|
SetIKAndAnimatorLayers(0f);
|
|
SetUpRendererMaterialsOriginal();
|
|
if (IsCulled)
|
|
{
|
|
Cull();
|
|
}
|
|
else
|
|
{
|
|
Draw();
|
|
}
|
|
if (MultiplayerFishSpawner.IsOnline)
|
|
{
|
|
networkedTarget = new GameObject(base.name + "_NT").GetComponent<Transform>();
|
|
networkedTarget.SetParent(base.transform.parent);
|
|
}
|
|
}
|
|
|
|
private new void OnDestroy()
|
|
{
|
|
base.OnDestroy();
|
|
if (networkedTarget != null)
|
|
{
|
|
UnityEngine.Object.Destroy(networkedTarget.gameObject);
|
|
}
|
|
CleanupRendererMaterialsEagle();
|
|
}
|
|
|
|
public void ResetRotate()
|
|
{
|
|
_AI.ResetRoot();
|
|
}
|
|
|
|
private void _AI_OnBaitHit(RaycastHit obj)
|
|
{
|
|
SetLureTarget(obj.transform);
|
|
}
|
|
|
|
public void SetLureTarget(Transform target)
|
|
{
|
|
if ((bool)CurrentFishInFight)
|
|
{
|
|
return;
|
|
}
|
|
FRod fRod = null;
|
|
FHook component2;
|
|
if (target.TryGetComponent<FLure>(out var component))
|
|
{
|
|
fRod = component.currentRod;
|
|
}
|
|
else if (target.TryGetComponent<FHook>(out component2))
|
|
{
|
|
fRod = component2.currentRod;
|
|
}
|
|
if ((bool)fRod)
|
|
{
|
|
bool flag = false;
|
|
int gameItemIndexByItemId = GameManager.Instance._playerData.GetGameItemIndexByItemId(GameManager.ItemType.Bait, Singleton<SaveDataManager>.Instance.GetCurrentPlayerData().PlayerSlotsEquip[fRod.indexOfslot].bait.ID);
|
|
if ((bool)fRod.currentLure && IsLureAccepted(gameItemIndexByItemId))
|
|
{
|
|
flag = true;
|
|
}
|
|
else if ((bool)fRod.currentBait && IsBaitAccepted(gameItemIndexByItemId))
|
|
{
|
|
flag = true;
|
|
}
|
|
bool flag2 = false;
|
|
if (!fRod.currentBait)
|
|
{
|
|
flag2 = true;
|
|
}
|
|
else
|
|
{
|
|
gameItemIndexByItemId = GameManager.Instance._playerData.GetGameItemIndexByItemId(GameManager.ItemType.Hook, Singleton<SaveDataManager>.Instance.GetCurrentPlayerData().PlayerSlotsEquip[fRod.indexOfslot].hook.ID);
|
|
flag2 = GameManager.Instance.gameHooks[gameItemIndexByItemId].CheckIsFishAccept(Weight);
|
|
}
|
|
if (flag && flag2)
|
|
{
|
|
rod = fRod;
|
|
LureTarget = target;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ResetBaitRefferences()
|
|
{
|
|
LureTarget = null;
|
|
if ((bool)rod && rod.currentFishEntity == this)
|
|
{
|
|
rod.currentFishEntity = null;
|
|
}
|
|
rod = null;
|
|
LastCatchTime = Time.time;
|
|
}
|
|
|
|
public void SetCurrentFishInAttack()
|
|
{
|
|
if (!CurrentFishInAttack)
|
|
{
|
|
CurrentFishInAttack = this;
|
|
}
|
|
}
|
|
|
|
public void ResetCurrentFishInAttack()
|
|
{
|
|
if (CurrentFishInAttack == this)
|
|
{
|
|
CurrentFishInAttack = null;
|
|
}
|
|
}
|
|
|
|
public void SetCurrentFishInFight(FRod rod)
|
|
{
|
|
if (!CurrentFishInFight)
|
|
{
|
|
CurrentFishInFight = this;
|
|
rod.currentFishEntity = this;
|
|
this.rod = rod;
|
|
}
|
|
}
|
|
|
|
public void ResetCurrentFishInFight()
|
|
{
|
|
ResetBaitRefferences();
|
|
if (CurrentFishInFight == this)
|
|
{
|
|
CurrentFishInFight = null;
|
|
}
|
|
}
|
|
|
|
public void EnableAIRaycasting()
|
|
{
|
|
_AI.IsUpdateEnabled = true;
|
|
}
|
|
|
|
private void FishEntity_OnPostSpitOutBait(FishEntity fish)
|
|
{
|
|
ChangeState(FishState.Idle);
|
|
}
|
|
|
|
private void FishEntityManager_OnGrowFish(FishEntity fish, float weightNew)
|
|
{
|
|
if (!(fish != this))
|
|
{
|
|
TryGrowFish(weightNew);
|
|
}
|
|
}
|
|
|
|
private void FishEntityManager_OnFishReachMaxSize(FishEntity fish)
|
|
{
|
|
if (!(fish != this))
|
|
{
|
|
TryKillOldFish();
|
|
}
|
|
}
|
|
|
|
public void SetIKAndAnimatorLayers(float weight)
|
|
{
|
|
_IK.solver.SetIKPositionWeight(weight);
|
|
_Animator.SetLayerWeight(_Animator.GetLayerIndex("Jump"), weight);
|
|
_Animator.SetLayerWeight(_Animator.GetLayerIndex("Attack"), weight);
|
|
_Animator.SetLayerWeight(_Animator.GetLayerIndex("Fight"), weight);
|
|
}
|
|
|
|
public float GetIKAndAnimatorLayers()
|
|
{
|
|
return _IK.solver.GetIKPositionWeight();
|
|
}
|
|
|
|
public void SetUpRendererMaterialsOriginal()
|
|
{
|
|
lodGroup = GetComponentInChildren<LODGroup>();
|
|
if (!(lodGroup != null))
|
|
{
|
|
return;
|
|
}
|
|
LOD[] lODs = lodGroup.GetLODs();
|
|
rendererMaterialsOriginal = new Material[lODs.Length][];
|
|
for (int i = 0; i < lODs.Length; i++)
|
|
{
|
|
Renderer renderer = ((lODs[i].renderers.Length != 0) ? lODs[i].renderers[0] : null);
|
|
if (renderer != null)
|
|
{
|
|
rendererMaterialsOriginal[i] = renderer.sharedMaterials;
|
|
}
|
|
else
|
|
{
|
|
rendererMaterialsOriginal[i] = new Material[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
private void CleanupRendererMaterialsEagle()
|
|
{
|
|
if (rendererMaterialsEagle == null)
|
|
{
|
|
return;
|
|
}
|
|
Material[][] array = rendererMaterialsEagle;
|
|
for (int i = 0; i < array.Length; i++)
|
|
{
|
|
array[i].ForEach(delegate(Material element)
|
|
{
|
|
UnityEngine.Object.Destroy(element);
|
|
});
|
|
}
|
|
rendererMaterialsEagle = null;
|
|
}
|
|
|
|
private void LODCorrection()
|
|
{
|
|
LODGroup componentInChildren = base.gameObject.GetComponentInChildren<LODGroup>();
|
|
if (componentInChildren == null)
|
|
{
|
|
Debug.LogError("Fish have not LOD Group: " + base.name);
|
|
return;
|
|
}
|
|
SkinnedMeshRenderer component = componentInChildren.GetComponent<SkinnedMeshRenderer>();
|
|
if (componentInChildren.transform.childCount == 0)
|
|
{
|
|
Debug.LogWarning("Problem with lods in fish " + base.gameObject.name);
|
|
return;
|
|
}
|
|
GameObject obj = UnityEngine.Object.Instantiate(componentInChildren.transform.GetChild(0).gameObject, component.transform);
|
|
obj.transform.localPosition = Vector3.zero;
|
|
obj.transform.localRotation = Quaternion.identity;
|
|
obj.transform.localScale = Vector3.one;
|
|
SkinnedMeshRenderer component2 = obj.GetComponent<SkinnedMeshRenderer>();
|
|
component2.sharedMesh = component.sharedMesh;
|
|
LOD[] lODs = componentInChildren.GetLODs();
|
|
lODs[0].renderers[0] = component2;
|
|
componentInChildren.SetLODs(lODs);
|
|
UnityEngine.Object.Destroy(component);
|
|
}
|
|
|
|
private void InstallMeshRenderer()
|
|
{
|
|
SkinnedMeshRenderer componentInChildren = GetComponentInChildren<SkinnedMeshRenderer>();
|
|
MeshRenderer meshRenderer = base.gameObject.AddComponent<MeshRenderer>();
|
|
MeshFilter meshFilter = base.gameObject.AddComponent<MeshFilter>();
|
|
meshRenderer.material = componentInChildren.material;
|
|
meshFilter.sharedMesh = componentInChildren.sharedMesh;
|
|
componentInChildren.enabled = false;
|
|
_Animator.enabled = false;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
FPlayer.OnFishPicked += FPlayer_OnFishPicked;
|
|
FishCatchPanel.OnFishKeepGlobal += TryDestroyFish;
|
|
FishCatchPanel.OnFishReleaseGlobal += TryDestroyFish;
|
|
FRod.OnRodDamagedGlobal += FRod_OnRodDamagedGlobal;
|
|
FReel.OnReelDamagedGlobal += FReel_OnReelDamagedGlobal;
|
|
FRod.OnLineCutedGlobal += FRod_OnLineCutedGlobal;
|
|
FHook.OnHookWaterExit += OnLureChangeWaterState;
|
|
FHook.OnHookWaterEnter += OnLureChangeWaterState;
|
|
FLure.OnLureEnterWater += OnLureChangeWaterState;
|
|
FLure.OnLureExitWater += OnLureChangeWaterState;
|
|
OnPostSpitOutBait += FishEntity_OnPostSpitOutBait;
|
|
FRod.OnEquipmentBreak = (Action<FRod>)Delegate.Combine(FRod.OnEquipmentBreak, new Action<FRod>(FRodOnEQBreak));
|
|
FishEntityManager.OnGrowFish += FishEntityManager_OnGrowFish;
|
|
FishEntityManager.OnFishReachMaxSize += FishEntityManager_OnFishReachMaxSize;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
FPlayer.OnFishPicked -= FPlayer_OnFishPicked;
|
|
FishCatchPanel.OnFishKeepGlobal -= TryDestroyFish;
|
|
FishCatchPanel.OnFishReleaseGlobal -= TryDestroyFish;
|
|
FRod.OnRodDamagedGlobal -= FRod_OnRodDamagedGlobal;
|
|
FReel.OnReelDamagedGlobal -= FReel_OnReelDamagedGlobal;
|
|
FRod.OnLineCutedGlobal -= FRod_OnLineCutedGlobal;
|
|
FHook.OnHookWaterExit -= OnLureChangeWaterState;
|
|
FHook.OnHookWaterEnter -= OnLureChangeWaterState;
|
|
FLure.OnLureEnterWater -= OnLureChangeWaterState;
|
|
FLure.OnLureExitWater -= OnLureChangeWaterState;
|
|
OnPostSpitOutBait -= FishEntity_OnPostSpitOutBait;
|
|
FRod.OnEquipmentBreak = (Action<FRod>)Delegate.Remove(FRod.OnEquipmentBreak, new Action<FRod>(FRodOnEQBreak));
|
|
FishEntityManager.OnGrowFish -= FishEntityManager_OnGrowFish;
|
|
FishEntityManager.OnFishReachMaxSize -= FishEntityManager_OnFishReachMaxSize;
|
|
}
|
|
|
|
private void FRodOnEQBreak(object obj)
|
|
{
|
|
TryDestroyFish();
|
|
}
|
|
|
|
private void OnLureChangeWaterState()
|
|
{
|
|
if (!(CurrentFishInFight == this))
|
|
{
|
|
ResetBaitRefferences();
|
|
}
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (!IsCulled)
|
|
{
|
|
_FSM.Update();
|
|
if (MultiplayerFishSpawner.IsOnline)
|
|
{
|
|
StateSwitchMultiplayer();
|
|
}
|
|
else
|
|
{
|
|
StateSwitchSingleplayer();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void StateSwitchSingleplayer()
|
|
{
|
|
switch (_State)
|
|
{
|
|
case FishState.Idle:
|
|
if (_StateChangeTime < Time.time)
|
|
{
|
|
ChangeState(FishState.MoveToWaypoint);
|
|
}
|
|
if (_IsCanAttack)
|
|
{
|
|
ChangeState(FishState.Atack);
|
|
}
|
|
if (_IsAtracted)
|
|
{
|
|
ChangeState(FishState.Interest);
|
|
}
|
|
break;
|
|
case FishState.Atack:
|
|
if (!_IsCanAttack || Target == null)
|
|
{
|
|
ResetBaitRefferences();
|
|
SetStateTimer(2f);
|
|
ChangeState(FishState.Idle);
|
|
break;
|
|
}
|
|
if (IsInDistanceToLure)
|
|
{
|
|
ChangeState(FishState.Fight);
|
|
}
|
|
if ((bool)Target && !GameWaterSystem.IsPositionUnderWater(Target.position))
|
|
{
|
|
ChangeState(FishState.Idle);
|
|
}
|
|
break;
|
|
case FishState.MoveToWaypoint:
|
|
if (Target == null)
|
|
{
|
|
ChangeState(FishState.Idle);
|
|
break;
|
|
}
|
|
if (GetDistanceToTarget() <= _Physics.Rbody.velocity.magnitude)
|
|
{
|
|
ChangeState(FishState.Idle);
|
|
SetStateTimer(UnityEngine.Random.Range(0.5f, 5f));
|
|
}
|
|
if (_IsAtracted)
|
|
{
|
|
ChangeState(FishState.Interest);
|
|
}
|
|
if (_IsCanAttack)
|
|
{
|
|
ChangeState(FishState.Atack);
|
|
}
|
|
break;
|
|
case FishState.Fight:
|
|
if (!_IsCanFight)
|
|
{
|
|
ResetCurrentFishInFight();
|
|
ChangeState(FishState.Idle);
|
|
}
|
|
else if (IsCatched)
|
|
{
|
|
ChangeState(FishState.Catched);
|
|
}
|
|
break;
|
|
case FishState.Interest:
|
|
if (Target == null)
|
|
{
|
|
ChangeState(FishState.Idle);
|
|
}
|
|
else if (!_IsAtracted)
|
|
{
|
|
ChangeState(FishState.MoveToWaypoint);
|
|
}
|
|
break;
|
|
case FishState.Dash:
|
|
case FishState.Stun:
|
|
case FishState.Catched:
|
|
case FishState.BaitEat:
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void StateSwitchMultiplayer()
|
|
{
|
|
MultiplayerFishSpawner.NetworkedFish networkedFish = MultiplayerFishSpawner.GetNetworkedFish(this);
|
|
networkedTarget.position = networkedFish.position;
|
|
MultiplayerFishSpawner.CheckFishInteractionWithPlayer(this, out var withLocalPlayer, out var _);
|
|
bool flag = MultiplayerFishSpawner.CheckFishInteractionWithPlayer(this);
|
|
switch (_State)
|
|
{
|
|
case FishState.Idle:
|
|
case FishState.MoveToWaypoint:
|
|
ChangeState(FishState.MultiplayerIdle);
|
|
break;
|
|
case FishState.MultiplayerIdle:
|
|
if (HandleInteractionWithLocalPlayer() || withLocalPlayer)
|
|
{
|
|
break;
|
|
}
|
|
if (MultiplayerFishSpawner.IsMaster)
|
|
{
|
|
if (_StateChangeTime < Time.time)
|
|
{
|
|
ChangeState(FishState.MultiplayerMoveToWaypoint);
|
|
}
|
|
}
|
|
else if (GetDistanceToTarget() > 0.2f)
|
|
{
|
|
ChangeState(FishState.MultiplayerMoveToWaypoint);
|
|
}
|
|
break;
|
|
case FishState.MultiplayerMoveToWaypoint:
|
|
if (HandleInteractionWithLocalPlayer() || withLocalPlayer)
|
|
{
|
|
break;
|
|
}
|
|
if (MultiplayerFishSpawner.IsMaster)
|
|
{
|
|
if (Target == null)
|
|
{
|
|
ChangeState(FishState.MultiplayerIdle);
|
|
}
|
|
else if (GetDistanceToTarget() <= _Physics.Rbody.velocity.magnitude)
|
|
{
|
|
ChangeState(FishState.MultiplayerIdle);
|
|
SetStateTimer(UnityEngine.Random.Range(0.5f, 5f));
|
|
}
|
|
}
|
|
else if (Target == null || GetDistanceToTarget() <= _Physics.Rbody.velocity.magnitude)
|
|
{
|
|
ChangeState(FishState.MultiplayerIdle);
|
|
}
|
|
break;
|
|
case FishState.MultiplayerHide:
|
|
if (!flag)
|
|
{
|
|
ChangeState(FishState.MultiplayerIdle);
|
|
}
|
|
break;
|
|
case FishState.Atack:
|
|
if (!withLocalPlayer || !_IsCanAttack || Target == null)
|
|
{
|
|
ResetBaitRefferences();
|
|
ChangeState(FishState.MultiplayerIdle);
|
|
}
|
|
else if (IsInDistanceToLure)
|
|
{
|
|
ChangeState(FishState.Fight);
|
|
}
|
|
break;
|
|
case FishState.Fight:
|
|
if (!withLocalPlayer || !_IsCanFight)
|
|
{
|
|
ResetCurrentFishInFight();
|
|
ChangeState(FishState.MultiplayerIdle);
|
|
}
|
|
else if (IsCatched)
|
|
{
|
|
ChangeState(FishState.Catched);
|
|
}
|
|
break;
|
|
case FishState.Interest:
|
|
if (!withLocalPlayer || Target == null)
|
|
{
|
|
ChangeState(FishState.MultiplayerIdle);
|
|
}
|
|
else if (!_IsAtracted)
|
|
{
|
|
ChangeState(FishState.MoveToWaypoint);
|
|
}
|
|
break;
|
|
case FishState.Dash:
|
|
case FishState.Stun:
|
|
case FishState.Catched:
|
|
case FishState.BaitEat:
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void OnGUI()
|
|
{
|
|
if (GameManager.IsDevModeAllowed && !(CurrentFishInFight == null) && CurrentFishInFight == this)
|
|
{
|
|
string text = $"Distance: {_DistanceToPlayer}";
|
|
if (!(Camera.main == null))
|
|
{
|
|
Vector3 vector = Camera.main.WorldToScreenPoint(base.gameObject.transform.position);
|
|
Vector2 vector2 = GUI.skin.label.CalcSize(new GUIContent(text));
|
|
GUI.Label(new Rect(vector.x, (float)Screen.height - vector.y, vector2.x, vector2.y), text);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void TryAttract(Transform target)
|
|
{
|
|
if (!_IsAtracted && !_IsScarred)
|
|
{
|
|
Target = target;
|
|
if (Vector3.Distance(base.transform.position, target.position) >= 0.5f)
|
|
{
|
|
_IsAtracted = true;
|
|
}
|
|
else
|
|
{
|
|
_IsScarred = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsLureAccepted(int id)
|
|
{
|
|
foreach (GameManager.AcceptFishBait acceptFishLure in Data.acceptFishLures)
|
|
{
|
|
if (acceptFishLure.baitId == id)
|
|
{
|
|
Debug.Log(base.gameObject.name + " accept lure");
|
|
return true;
|
|
}
|
|
}
|
|
Debug.Log(base.gameObject.name + " is not accept lure");
|
|
return false;
|
|
}
|
|
|
|
public bool IsBaitAccepted(int id)
|
|
{
|
|
foreach (GameManager.AcceptFishBait acceptFishBait in Data.acceptFishBaits)
|
|
{
|
|
if (acceptFishBait.baitId == id)
|
|
{
|
|
Debug.Log(base.gameObject.name + " accept bait");
|
|
return true;
|
|
}
|
|
}
|
|
Debug.Log(base.gameObject.name + " is not accept bait");
|
|
return false;
|
|
}
|
|
|
|
public void EagleEyeRender(bool isEagleEyeEnabled = false, Material eagleMaterial = null, float opacity = 0f)
|
|
{
|
|
if (lodGroup == null)
|
|
{
|
|
return;
|
|
}
|
|
if (isEagleEyeEnabled && eagleMaterial == null)
|
|
{
|
|
throw new ArgumentNullException("eagleMaterial", "Eagle Eye mode is enabled, but no material was provided.");
|
|
}
|
|
if (isEagleEyeEnabled)
|
|
{
|
|
if (rendererMaterialsEagle == null)
|
|
{
|
|
rendererMaterialsEagle = new Material[rendererMaterialsOriginal.Length][];
|
|
for (int i = 0; i < rendererMaterialsOriginal.Length; i++)
|
|
{
|
|
rendererMaterialsEagle[i] = new Material[rendererMaterialsOriginal[i].Length];
|
|
for (int j = 0; j < rendererMaterialsOriginal[i].Length; j++)
|
|
{
|
|
rendererMaterialsEagle[i][j] = new Material(eagleMaterial)
|
|
{
|
|
mainTexture = rendererMaterialsOriginal[i][j].mainTexture
|
|
};
|
|
}
|
|
}
|
|
}
|
|
if (lodGroup.gameObject.layer != LayerMask.NameToLayer("EagleEye"))
|
|
{
|
|
lodGroup.gameObject.layer = LayerMask.NameToLayer("EagleEye");
|
|
LOD[] lODs = lodGroup.GetLODs();
|
|
for (int k = 0; k < lODs.Length; k++)
|
|
{
|
|
if (lODs[k].renderers.Length != 0 && lODs[k].renderers[0] != null)
|
|
{
|
|
lODs[k].renderers[0].sharedMaterials = rendererMaterialsEagle[k];
|
|
}
|
|
}
|
|
}
|
|
Material[][] array = rendererMaterialsEagle;
|
|
foreach (Material[] array2 in array)
|
|
{
|
|
for (int m = 0; m < array2.Length; m++)
|
|
{
|
|
array2[m].SetFloat("_Opacity", opacity);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (lodGroup.gameObject.layer == LayerMask.NameToLayer("Fish"))
|
|
{
|
|
return;
|
|
}
|
|
lodGroup.gameObject.layer = LayerMask.NameToLayer("Fish");
|
|
LOD[] lODs2 = lodGroup.GetLODs();
|
|
for (int n = 0; n < lODs2.Length; n++)
|
|
{
|
|
if (lODs2[n].renderers.Length != 0 && lODs2[n].renderers[0] != null)
|
|
{
|
|
lODs2[n].renderers[0].sharedMaterials = rendererMaterialsOriginal[n];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SpitOutBait()
|
|
{
|
|
if (!(CurrentFishInFight != this))
|
|
{
|
|
FishEntity.OnPreSpitOutBait?.Invoke(this);
|
|
ResetCurrentFishInFight();
|
|
Physics.RemoveJoint();
|
|
FishEntity.OnPostSpitOutBait?.Invoke(this);
|
|
}
|
|
}
|
|
|
|
public void LostAttract()
|
|
{
|
|
_IsAtracted = false;
|
|
}
|
|
|
|
public void Cull()
|
|
{
|
|
Physics.Rbody.isKinematic = true;
|
|
Physics.Rbody.velocity = Vector3.zero;
|
|
base.transform.position = new Vector3(0f, 1000f, 0f);
|
|
IsCulled = true;
|
|
ChangeState(FishState.Idle);
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
base.transform.position = Target.position;
|
|
Physics.Rbody.isKinematic = false;
|
|
Physics.Rbody.freezeRotation = true;
|
|
IsCulled = false;
|
|
ChangeState(FishState.Idle);
|
|
}
|
|
|
|
public void Draw(FishTarget target)
|
|
{
|
|
CurrentArea = target.Area;
|
|
base.transform.position = target.Transform.position;
|
|
Physics.Rbody.isKinematic = false;
|
|
IsCulled = false;
|
|
ChangeState(FishState.Idle);
|
|
}
|
|
|
|
private void BuildSplash()
|
|
{
|
|
Vector3 position = base.transform.position;
|
|
Rigidbody rbody = Physics.Rbody;
|
|
if (!(rbody.velocity.y > 0.3f))
|
|
{
|
|
Vector3 vector = Vector3.one * base.transform.localScale.x;
|
|
vector *= Mathf.Max(0.07f, 0.04f * Mathf.Abs(rbody.velocity.y));
|
|
int num = 0;
|
|
GameObject obj = LeanPool.Spawn(FScriptsHandler.Instance.waterFishSplash[num]);
|
|
GameWaterSystem.FindWaterLevelAtLocation(base.transform.position, out var waterLevel);
|
|
obj.transform.position = new Vector3(position.x, waterLevel + 0.05f, position.z);
|
|
obj.GetComponent<AudioSource>().volume = 0.5f * vector.x;
|
|
vector = Vector3.ClampMagnitude(vector, 1f);
|
|
obj.transform.localScale = vector * 1.5f;
|
|
}
|
|
}
|
|
|
|
public void SetAIEnabled(bool value)
|
|
{
|
|
_AI.IsEnabled = value;
|
|
}
|
|
|
|
public void SetRandomWaypoint(float moveSpeed)
|
|
{
|
|
FishTarget randomTarget = CurrentArea.GetRandomTarget(_Data.BehaviourType);
|
|
if (randomTarget != null && !(randomTarget.Transform == null))
|
|
{
|
|
_AI.Target = randomTarget.Transform;
|
|
_AI.MoveSpeed = moveSpeed;
|
|
}
|
|
}
|
|
|
|
public float GetDistanceToTarget()
|
|
{
|
|
return Vector3.Distance(_AI.Target.position, base.transform.position);
|
|
}
|
|
|
|
public void SetAnimatorFloat(string s, float f)
|
|
{
|
|
if (_Animator == null)
|
|
{
|
|
Debug.LogWarning("There is no animator");
|
|
}
|
|
else
|
|
{
|
|
_Animator.SetFloat(s, f);
|
|
}
|
|
}
|
|
|
|
public void SetAnimatorBool(string s, bool b)
|
|
{
|
|
if (_Animator == null)
|
|
{
|
|
Debug.LogWarning("There is no animator");
|
|
}
|
|
else
|
|
{
|
|
_Animator.SetBool(s, b);
|
|
}
|
|
}
|
|
|
|
public void ClampMaxDistance(float maxDistance, Transform targetTransform)
|
|
{
|
|
if (Vector3.Distance(base.transform.position, targetTransform.position) > maxDistance)
|
|
{
|
|
Vector3 normalized = (base.transform.position - targetTransform.position).normalized;
|
|
base.transform.position = targetTransform.position + normalized * maxDistance;
|
|
}
|
|
}
|
|
|
|
public void InitializeData(FishData data, float weight)
|
|
{
|
|
_Data = data;
|
|
_Weight = weight;
|
|
base.transform.GetChild(0).localScale = data.GetFishScale(weight);
|
|
}
|
|
|
|
private float GetDistanceThreshold(Vector3 target, float speed)
|
|
{
|
|
Vector3 b = JointAnchor.position + base.transform.forward * speed;
|
|
return Vector3.Distance(target, b);
|
|
}
|
|
|
|
private bool CanFightWithLure()
|
|
{
|
|
return LastCatchTime + nextCatchDelayInterval < Time.time;
|
|
}
|
|
|
|
private void SetStateTimer(float timer)
|
|
{
|
|
_StateChangeTime = timer + Time.time;
|
|
}
|
|
|
|
private bool HandleInteractionWithLocalPlayer()
|
|
{
|
|
bool result = false;
|
|
MultiplayerFishSpawner.CheckFishInteractionWithPlayer(this, out var withLocalPlayer, out var withRemotePlayer);
|
|
MultiplayerFishSpawner.NetworkedFish networkedFish = MultiplayerFishSpawner.GetNetworkedFish(this);
|
|
if (withRemotePlayer)
|
|
{
|
|
ChangeState(FishState.MultiplayerHide);
|
|
result = true;
|
|
}
|
|
else if (withLocalPlayer)
|
|
{
|
|
ChangeState(FishState.Atack);
|
|
result = true;
|
|
}
|
|
else if (_IsCanAttack || _IsAtracted)
|
|
{
|
|
if (networkedFish.actorInControl == PhotonNetwork.LocalPlayer.ActorNumber)
|
|
{
|
|
MultiplayerFishSpawner.SpawnMultiplayerFishEntity(this);
|
|
}
|
|
else if (_IsCanSendRequest)
|
|
{
|
|
MultiplayerFishSpawner.FishControlRequest(this);
|
|
lastServerRequestTime = Time.time;
|
|
}
|
|
}
|
|
else if (networkedFish.actorInControl == PhotonNetwork.LocalPlayer.ActorNumber && _IsCanSendRequest)
|
|
{
|
|
MultiplayerFishSpawner.FishControlRequestCancel(this);
|
|
lastServerRequestTime = Time.time;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public void ReJoinChwytak(Rigidbody newJoin)
|
|
{
|
|
if (!TryGetComponent<ConfigurableJoint>(out var component))
|
|
{
|
|
component = base.gameObject.AddComponent<ConfigurableJoint>();
|
|
}
|
|
component.anchor = base.transform.InverseTransformVector(JointAnchor.position - base.transform.position);
|
|
component.autoConfigureConnectedAnchor = false;
|
|
component.connectedAnchor = Vector3.zero;
|
|
component.xMotion = ConfigurableJointMotion.Locked;
|
|
component.yMotion = ConfigurableJointMotion.Locked;
|
|
component.zMotion = ConfigurableJointMotion.Locked;
|
|
component.angularXMotion = ConfigurableJointMotion.Free;
|
|
component.angularYMotion = ConfigurableJointMotion.Free;
|
|
component.angularZMotion = ConfigurableJointMotion.Free;
|
|
component.connectedBody = newJoin;
|
|
component.projectionMode = JointProjectionMode.PositionAndRotation;
|
|
}
|
|
|
|
[Command("destroy_hooked_fish", Platform.AllPlatforms, MonoTargetType.Single)]
|
|
private void TryDestroyFish()
|
|
{
|
|
if (!(CurrentFishInFight != this))
|
|
{
|
|
Debug.Log("DestroyFish now");
|
|
FishSpawner.Despawn(CurrentFishInFight);
|
|
UnityEngine.Object.Destroy(base.gameObject);
|
|
FishEntity.OnPreSpitOutBait?.Invoke(this);
|
|
FishEntity.OnPostSpitOutBait?.Invoke(this);
|
|
ResetCurrentFishInFight();
|
|
ResetCurrentFishInAttack();
|
|
}
|
|
}
|
|
|
|
public void TryGrowFish(float weightNew)
|
|
{
|
|
if (!(CurrentFishInFight == this) && CurrentFishState != FishState.Atack && !MultiplayerFishSpawner.CheckFishInteractionWithPlayer(this) && !IsCulled)
|
|
{
|
|
InitializeData(Data, weightNew);
|
|
}
|
|
}
|
|
|
|
public void TryKillOldFish()
|
|
{
|
|
if (!(CurrentFishInFight == this) && CurrentFishState != FishState.Atack && !MultiplayerFishSpawner.CheckFishInteractionWithPlayer(this) && !IsCulled)
|
|
{
|
|
FishSpawner.Despawn(this);
|
|
UnityEngine.Object.Destroy(base.gameObject);
|
|
FishEntity.OnOldFishKill?.Invoke(this);
|
|
}
|
|
}
|
|
|
|
[Command("attach_fish", Platform.AllPlatforms, MonoTargetType.Single)]
|
|
private void TryAttachNearFish()
|
|
{
|
|
if (CurrentFishInFight != null)
|
|
{
|
|
return;
|
|
}
|
|
float num = float.PositiveInfinity;
|
|
FLure fLure = UnityEngine.Object.FindObjectOfType<FLure>();
|
|
FishEntity fishEntity = null;
|
|
FishEntity[] array = UnityEngine.Object.FindObjectsOfType<FishEntity>();
|
|
foreach (FishEntity fishEntity2 in array)
|
|
{
|
|
float num2 = Vector3.Distance(fLure.transform.position, fishEntity2.transform.position);
|
|
if (num2 < num)
|
|
{
|
|
fishEntity = fishEntity2;
|
|
num = num2;
|
|
}
|
|
}
|
|
Debug.Log($"FISH ATTACH {fishEntity}");
|
|
if (fishEntity != null)
|
|
{
|
|
fishEntity.SetLureTarget(fLure.transform);
|
|
fishEntity.ChangeState(FishState.Atack);
|
|
}
|
|
}
|
|
|
|
[Command("toggle-fish-movement", MonoTargetType.All, Platform.AllPlatforms)]
|
|
public void ToggleFishLabel()
|
|
{
|
|
AI.enabled = !AI.enabled;
|
|
}
|
|
}
|
|
}
|