402 lines
12 KiB
C#
402 lines
12 KiB
C#
using System.Collections;
|
|
using GameNetcodeStuff;
|
|
using Unity.Netcode;
|
|
using UnityEngine;
|
|
|
|
public class BlobAI : EnemyAI
|
|
{
|
|
[Header("Fluid simulation")]
|
|
public Transform centerPoint;
|
|
|
|
public Transform[] SlimeRaycastTargets;
|
|
|
|
public Rigidbody[] SlimeBones;
|
|
|
|
private Vector3[] SlimeBonePositions = new Vector3[8];
|
|
|
|
public float slimeRange = 8f;
|
|
|
|
public float currentSlimeRange;
|
|
|
|
private float[] maxDistanceForSlimeRays = new float[8];
|
|
|
|
private float[] distanceOfRaysLastFrame = new float[8];
|
|
|
|
private int partsMovingUpSlope;
|
|
|
|
private Ray slimeRay;
|
|
|
|
private RaycastHit slimeRayHit;
|
|
|
|
private RaycastHit slimePlayerRayHit;
|
|
|
|
private float timeSinceHittingLocalPlayer;
|
|
|
|
[Header("Behaviors")]
|
|
public AISearchRoutine searchForPlayers;
|
|
|
|
private float tamedTimer;
|
|
|
|
private float angeredTimer;
|
|
|
|
private Material thisSlimeMaterial;
|
|
|
|
private float slimeJiggleAmplitude;
|
|
|
|
private float slimeJiggleDensity;
|
|
|
|
[Header("SFX")]
|
|
public AudioSource movableAudioSource;
|
|
|
|
public AudioClip agitatedSFX;
|
|
|
|
public AudioClip jiggleSFX;
|
|
|
|
public AudioClip hitSlimeSFX;
|
|
|
|
public AudioClip killPlayerSFX;
|
|
|
|
public AudioClip idleSFX;
|
|
|
|
private Collider[] ragdollColliders;
|
|
|
|
private Coroutine eatPlayerBodyCoroutine;
|
|
|
|
private DeadBodyInfo bodyBeingCarried;
|
|
|
|
private int slimeMask = 268470529;
|
|
|
|
public Mesh emptySuitMesh;
|
|
|
|
public override void Start()
|
|
{
|
|
ragdollColliders = new Collider[4];
|
|
base.Start();
|
|
thisSlimeMaterial = skinnedMeshRenderers[0].material;
|
|
for (int i = 0; i < maxDistanceForSlimeRays.Length; i++)
|
|
{
|
|
maxDistanceForSlimeRays[i] = 3.7f;
|
|
SlimeBonePositions[i] = SlimeBones[i].transform.position;
|
|
}
|
|
}
|
|
|
|
public override void DoAIInterval()
|
|
{
|
|
base.DoAIInterval();
|
|
if (!isEnemyDead && !StartOfRound.Instance.allPlayersDead)
|
|
{
|
|
if (TargetClosestPlayer(4f))
|
|
{
|
|
StopSearch(searchForPlayers);
|
|
movingTowardsTargetPlayer = true;
|
|
}
|
|
else
|
|
{
|
|
movingTowardsTargetPlayer = false;
|
|
StartSearch(base.transform.position, searchForPlayers);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SimulateSurfaceTensionInRaycasts(int i)
|
|
{
|
|
float num = distanceOfRaysLastFrame[(i + 1) % SlimeRaycastTargets.Length];
|
|
float num2 = ((i != 0) ? distanceOfRaysLastFrame[i - 1] : distanceOfRaysLastFrame[SlimeRaycastTargets.Length - 1]);
|
|
float num3 = Mathf.Clamp((num2 + num) / 2f, 0.5f, 200f);
|
|
float num4 = 1f;
|
|
if (num3 < 2f)
|
|
{
|
|
num4 = 2f;
|
|
}
|
|
maxDistanceForSlimeRays[i] = Mathf.Clamp(num3 * 2f * num4, 0f, currentSlimeRange);
|
|
}
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
if (!ventAnimationFinished)
|
|
{
|
|
return;
|
|
}
|
|
for (int i = 0; i < SlimeBonePositions.Length; i++)
|
|
{
|
|
if (Vector3.Distance(centerPoint.position, SlimeBonePositions[i]) > distanceOfRaysLastFrame[i])
|
|
{
|
|
SlimeBones[i].MovePosition(Vector3.Lerp(SlimeBones[i].position, SlimeBonePositions[i], 10f * Time.deltaTime));
|
|
}
|
|
else
|
|
{
|
|
SlimeBones[i].MovePosition(Vector3.Lerp(SlimeBones[i].position, SlimeBonePositions[i], 5f * Time.deltaTime));
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
base.Update();
|
|
if (!ventAnimationFinished || !(creatureAnimator != null))
|
|
{
|
|
return;
|
|
}
|
|
creatureAnimator.enabled = false;
|
|
if (isEnemyDead || StartOfRound.Instance.allPlayersDead)
|
|
{
|
|
return;
|
|
}
|
|
timeSinceHittingLocalPlayer += Time.deltaTime;
|
|
partsMovingUpSlope = 0;
|
|
Vector3 vector = serverPosition;
|
|
for (int i = 0; i < SlimeRaycastTargets.Length; i++)
|
|
{
|
|
Vector3 direction = SlimeRaycastTargets[i].position - centerPoint.position;
|
|
slimeRay = new Ray(vector, direction);
|
|
RaycastCollisionWithPlayers(Vector3.Distance(vector, SlimeBones[i].transform.position));
|
|
if (Physics.Raycast(slimeRay, out slimeRayHit, maxDistanceForSlimeRays[i], slimeMask, QueryTriggerInteraction.Ignore))
|
|
{
|
|
MoveSlimeBoneToRaycastHit(0f, i);
|
|
continue;
|
|
}
|
|
Vector3 navMeshPosition = RoundManager.Instance.GetNavMeshPosition(slimeRay.GetPoint(maxDistanceForSlimeRays[i]));
|
|
SlimeBonePositions[i] = Vector3.Lerp(SlimeBonePositions[i], navMeshPosition, 1f * Time.deltaTime);
|
|
distanceOfRaysLastFrame[i] = maxDistanceForSlimeRays[i];
|
|
}
|
|
if (stunNormalizedTimer > 0f)
|
|
{
|
|
thisSlimeMaterial.SetFloat("_Frequency", 4f);
|
|
slimeJiggleDensity = Mathf.Lerp(slimeJiggleDensity, 1f, 10f * Time.deltaTime);
|
|
thisSlimeMaterial.SetFloat("_Ripple_Density", slimeJiggleDensity);
|
|
slimeJiggleAmplitude = Mathf.Lerp(slimeJiggleAmplitude, 0.17f, 10f * Time.deltaTime);
|
|
thisSlimeMaterial.SetFloat("_Amplitude", slimeJiggleAmplitude);
|
|
agent.speed = 0f;
|
|
currentSlimeRange = Mathf.Lerp(currentSlimeRange, 2f, Time.deltaTime * 4f);
|
|
angeredTimer = 7f;
|
|
return;
|
|
}
|
|
if (angeredTimer > 0f)
|
|
{
|
|
angeredTimer -= Time.deltaTime;
|
|
currentSlimeRange = Mathf.Lerp(currentSlimeRange, slimeRange + 6f, Time.deltaTime * 3f);
|
|
thisSlimeMaterial.SetFloat("_Frequency", 3f);
|
|
slimeJiggleDensity = Mathf.Lerp(slimeJiggleDensity, 1f, 10f * Time.deltaTime);
|
|
thisSlimeMaterial.SetFloat("_Ripple_Density", slimeJiggleDensity);
|
|
slimeJiggleAmplitude = Mathf.Lerp(slimeJiggleAmplitude, 0.14f, 10f * Time.deltaTime);
|
|
thisSlimeMaterial.SetFloat("_Amplitude", slimeJiggleAmplitude);
|
|
if (creatureSFX.clip != agitatedSFX)
|
|
{
|
|
creatureSFX.clip = agitatedSFX;
|
|
creatureSFX.Play();
|
|
}
|
|
if (base.IsOwner)
|
|
{
|
|
agent.stoppingDistance = 0.1f;
|
|
agent.speed = 0.6f;
|
|
}
|
|
return;
|
|
}
|
|
if (tamedTimer > 0f)
|
|
{
|
|
tamedTimer -= Time.deltaTime;
|
|
currentSlimeRange = 1.5f;
|
|
thisSlimeMaterial.SetFloat("_Frequency", 4.3f);
|
|
slimeJiggleDensity = Mathf.Lerp(slimeJiggleDensity, 1.3f, 10f * Time.deltaTime);
|
|
thisSlimeMaterial.SetFloat("_Ripple_Density", slimeJiggleDensity);
|
|
slimeJiggleAmplitude = Mathf.Lerp(slimeJiggleAmplitude, 0.2f, 10f * Time.deltaTime);
|
|
thisSlimeMaterial.SetFloat("_Amplitude", slimeJiggleAmplitude);
|
|
if (creatureSFX.clip != jiggleSFX)
|
|
{
|
|
creatureSFX.clip = jiggleSFX;
|
|
creatureSFX.Play();
|
|
}
|
|
if (base.IsOwner)
|
|
{
|
|
agent.stoppingDistance = 5f;
|
|
agent.speed = Mathf.Lerp(agent.speed, 3f, 0.7f * Time.deltaTime);
|
|
}
|
|
return;
|
|
}
|
|
if (partsMovingUpSlope >= 2)
|
|
{
|
|
currentSlimeRange = Mathf.Clamp(slimeRange / 2f, 1.5f, 100f);
|
|
}
|
|
else
|
|
{
|
|
currentSlimeRange = slimeRange;
|
|
}
|
|
thisSlimeMaterial.SetFloat("_Frequency", 2f);
|
|
slimeJiggleDensity = Mathf.Lerp(slimeJiggleDensity, 0.6f, 10f * Time.deltaTime);
|
|
thisSlimeMaterial.SetFloat("_Ripple_Density", slimeJiggleDensity);
|
|
slimeJiggleAmplitude = Mathf.Lerp(slimeJiggleAmplitude, 0.15f, 10f * Time.deltaTime);
|
|
thisSlimeMaterial.SetFloat("_Amplitude", slimeJiggleAmplitude);
|
|
if (creatureSFX.clip != idleSFX)
|
|
{
|
|
creatureSFX.clip = idleSFX;
|
|
creatureSFX.Play();
|
|
}
|
|
if (base.IsOwner)
|
|
{
|
|
agent.stoppingDistance = 0.1f;
|
|
agent.speed = 0.5f;
|
|
}
|
|
}
|
|
|
|
private void MoveSlimeBoneToRaycastHit(float currentRangeOfRaycast, int i)
|
|
{
|
|
float num = 1.8f;
|
|
if (slimeRayHit.distance + currentRangeOfRaycast < distanceOfRaysLastFrame[i])
|
|
{
|
|
num = 5f;
|
|
}
|
|
SlimeBonePositions[i] = Vector3.Lerp(SlimeBonePositions[i], slimeRay.GetPoint(slimeRayHit.distance), num * Time.deltaTime);
|
|
distanceOfRaysLastFrame[i] = slimeRayHit.distance + currentRangeOfRaycast;
|
|
}
|
|
|
|
private void RaycastCollisionWithPlayers(float maxDistance)
|
|
{
|
|
maxDistance -= 1.55f;
|
|
if (Physics.SphereCast(slimeRay, 0.7f, out slimePlayerRayHit, maxDistance, 2312) && slimePlayerRayHit.collider.gameObject.CompareTag("Player"))
|
|
{
|
|
OnCollideWithPlayer(slimePlayerRayHit.collider);
|
|
}
|
|
}
|
|
|
|
public override void OnCollideWithPlayer(Collider other)
|
|
{
|
|
base.OnCollideWithPlayer(other);
|
|
if (timeSinceHittingLocalPlayer < 0.25f || (tamedTimer > 0f && angeredTimer < 0f))
|
|
{
|
|
return;
|
|
}
|
|
PlayerControllerB playerControllerB = MeetsStandardPlayerCollisionConditions(other);
|
|
if (playerControllerB != null)
|
|
{
|
|
timeSinceHittingLocalPlayer = 0f;
|
|
playerControllerB.DamagePlayer(35);
|
|
if (playerControllerB.isPlayerDead)
|
|
{
|
|
SlimeKillPlayerEffectServerRpc((int)playerControllerB.playerClientId);
|
|
}
|
|
}
|
|
}
|
|
|
|
[ServerRpc(RequireOwnership = false)]
|
|
public void SlimeKillPlayerEffectServerRpc(int playerKilled)
|
|
{
|
|
NetworkManager networkManager = base.NetworkManager;
|
|
if ((object)networkManager != null && networkManager.IsListening)
|
|
{
|
|
if (__rpc_exec_stage != __RpcExecStage.Server && (networkManager.IsClient || networkManager.IsHost))
|
|
{
|
|
ServerRpcParams serverRpcParams = default(ServerRpcParams);
|
|
FastBufferWriter bufferWriter = __beginSendServerRpc(3848306567u, serverRpcParams, RpcDelivery.Reliable);
|
|
BytePacker.WriteValueBitPacked(bufferWriter, playerKilled);
|
|
__endSendServerRpc(ref bufferWriter, 3848306567u, serverRpcParams, RpcDelivery.Reliable);
|
|
}
|
|
if (__rpc_exec_stage == __RpcExecStage.Server && (networkManager.IsServer || networkManager.IsHost))
|
|
{
|
|
SlimeKillPlayerEffectClientRpc(playerKilled);
|
|
}
|
|
}
|
|
}
|
|
|
|
[ClientRpc]
|
|
public void SlimeKillPlayerEffectClientRpc(int playerKilled)
|
|
{
|
|
NetworkManager networkManager = base.NetworkManager;
|
|
if ((object)networkManager == null || !networkManager.IsListening)
|
|
{
|
|
return;
|
|
}
|
|
if (__rpc_exec_stage != __RpcExecStage.Client && (networkManager.IsServer || networkManager.IsHost))
|
|
{
|
|
ClientRpcParams clientRpcParams = default(ClientRpcParams);
|
|
FastBufferWriter bufferWriter = __beginSendClientRpc(1531516867u, clientRpcParams, RpcDelivery.Reliable);
|
|
BytePacker.WriteValueBitPacked(bufferWriter, playerKilled);
|
|
__endSendClientRpc(ref bufferWriter, 1531516867u, clientRpcParams, RpcDelivery.Reliable);
|
|
}
|
|
if (__rpc_exec_stage == __RpcExecStage.Client && (networkManager.IsClient || networkManager.IsHost))
|
|
{
|
|
creatureSFX.PlayOneShot(killPlayerSFX);
|
|
angeredTimer = 0f;
|
|
if (eatPlayerBodyCoroutine == null)
|
|
{
|
|
eatPlayerBodyCoroutine = StartCoroutine(eatPlayerBody(playerKilled));
|
|
}
|
|
}
|
|
}
|
|
|
|
private IEnumerator eatPlayerBody(int playerKilled)
|
|
{
|
|
yield return null;
|
|
PlayerControllerB playerScript = StartOfRound.Instance.allPlayerScripts[playerKilled];
|
|
float startTime = Time.realtimeSinceStartup;
|
|
yield return new WaitUntil(() => playerScript.deadBody != null || Time.realtimeSinceStartup - startTime > 2f);
|
|
if (playerScript.deadBody == null)
|
|
{
|
|
Debug.Log("Blob: Player body was not spawned or found within 2 seconds.");
|
|
yield break;
|
|
}
|
|
playerScript.deadBody.attachedLimb = playerScript.deadBody.bodyParts[6];
|
|
playerScript.deadBody.attachedTo = centerPoint;
|
|
playerScript.deadBody.matchPositionExactly = false;
|
|
yield return new WaitForSeconds(2f);
|
|
playerScript.deadBody.attachedTo = null;
|
|
playerScript.deadBody.ChangeMesh(emptySuitMesh);
|
|
}
|
|
|
|
public override void HitEnemy(int force = 1, PlayerControllerB playerWhoHit = null, bool playHitSFX = false)
|
|
{
|
|
base.HitEnemy(force, playerWhoHit);
|
|
angeredTimer = 18f;
|
|
movableAudioSource.transform.position = playerWhoHit.gameplayCamera.transform.position + playerWhoHit.gameplayCamera.transform.forward * 1.5f;
|
|
movableAudioSource.PlayOneShot(hitSlimeSFX);
|
|
}
|
|
|
|
public override void DetectNoise(Vector3 noisePosition, float noiseLoudness, int timesPlayedInOneSpot = 0, int noiseID = 0)
|
|
{
|
|
base.DetectNoise(noisePosition, noiseLoudness, timesPlayedInOneSpot, noiseID);
|
|
if (noiseID == 5 && !Physics.Linecast(base.transform.position, noisePosition, StartOfRound.Instance.collidersAndRoomMask) && Vector3.Distance(base.transform.position, noisePosition) < 12f)
|
|
{
|
|
tamedTimer = 2f;
|
|
}
|
|
}
|
|
|
|
protected override void __initializeVariables()
|
|
{
|
|
base.__initializeVariables();
|
|
}
|
|
|
|
[RuntimeInitializeOnLoadMethod]
|
|
internal static void InitializeRPCS_BlobAI()
|
|
{
|
|
NetworkManager.__rpc_func_table.Add(3848306567u, __rpc_handler_3848306567);
|
|
NetworkManager.__rpc_func_table.Add(1531516867u, __rpc_handler_1531516867);
|
|
}
|
|
|
|
private static void __rpc_handler_3848306567(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
|
|
{
|
|
NetworkManager networkManager = target.NetworkManager;
|
|
if ((object)networkManager != null && networkManager.IsListening)
|
|
{
|
|
ByteUnpacker.ReadValueBitPacked(reader, out int value);
|
|
target.__rpc_exec_stage = __RpcExecStage.Server;
|
|
((BlobAI)target).SlimeKillPlayerEffectServerRpc(value);
|
|
target.__rpc_exec_stage = __RpcExecStage.None;
|
|
}
|
|
}
|
|
|
|
private static void __rpc_handler_1531516867(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams)
|
|
{
|
|
NetworkManager networkManager = target.NetworkManager;
|
|
if ((object)networkManager != null && networkManager.IsListening)
|
|
{
|
|
ByteUnpacker.ReadValueBitPacked(reader, out int value);
|
|
target.__rpc_exec_stage = __RpcExecStage.Client;
|
|
((BlobAI)target).SlimeKillPlayerEffectClientRpc(value);
|
|
target.__rpc_exec_stage = __RpcExecStage.None;
|
|
}
|
|
}
|
|
|
|
protected internal override string __getTypeName()
|
|
{
|
|
return "BlobAI";
|
|
}
|
|
}
|