|
|
|
@@ -0,0 +1,555 @@
|
|
|
|
|
using NUnit.Framework;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using TMPro;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.AI;
|
|
|
|
|
using UnityEngine.Diagnostics;
|
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
|
|
|
|
|
public class TinkyWinky : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
// singleton
|
|
|
|
|
public static TinkyWinky Instance;
|
|
|
|
|
|
|
|
|
|
// const
|
|
|
|
|
private const float offscreenDotRange = 0.7f;
|
|
|
|
|
private const float minDistanceForChase = 20f;
|
|
|
|
|
private const float minGazeTimeForChase = 2f;
|
|
|
|
|
private const float minIgnoredNearbyTimeForChase = 15f;
|
|
|
|
|
private const float minGazeTimeForDeath = 6f;
|
|
|
|
|
|
|
|
|
|
private const float minDistanceForStalk = 100f;
|
|
|
|
|
private const float maxDistanceForStalk = 200f;
|
|
|
|
|
private const float keptDistanceForStalk = 30f;
|
|
|
|
|
|
|
|
|
|
private const float loseChaseDuration = 45f;
|
|
|
|
|
private const float loseChaseDistance = 50f;
|
|
|
|
|
|
|
|
|
|
private const float pathRefreshInterval = 0.25f;
|
|
|
|
|
|
|
|
|
|
// state
|
|
|
|
|
public enum States
|
|
|
|
|
{
|
|
|
|
|
None,
|
|
|
|
|
Idle,
|
|
|
|
|
Wander,
|
|
|
|
|
Stalk,
|
|
|
|
|
Chase
|
|
|
|
|
}
|
|
|
|
|
public States ActiveState { get; private set; } = States.None;
|
|
|
|
|
public States NextState { get; private set; } = States.None;
|
|
|
|
|
|
|
|
|
|
[Header("Setup")]
|
|
|
|
|
public NavMeshAgent Agent;
|
|
|
|
|
public LayerMask LayerMask;
|
|
|
|
|
public Vector3 RaycastOffset;
|
|
|
|
|
[Header("Stats")]
|
|
|
|
|
public float WalkSpeed = 3;
|
|
|
|
|
public float RunSpeed = 7;
|
|
|
|
|
public float KillRange = 1f;
|
|
|
|
|
public Vector3 KillOffset;
|
|
|
|
|
[Header("the SCARY stuff")]
|
|
|
|
|
public int SprintOnlyCustardThreshold = 2;
|
|
|
|
|
[Header("Visuals")]
|
|
|
|
|
public Transform Model;
|
|
|
|
|
public MeshRenderer MeshRenderer;
|
|
|
|
|
public Texture2D ChaseFace;
|
|
|
|
|
public Texture2D NormalFace;
|
|
|
|
|
[Header("Audio")]
|
|
|
|
|
public AudioSource FootstepSource;
|
|
|
|
|
public AudioSource EhOhSource;
|
|
|
|
|
public AudioSource ScreamSource;
|
|
|
|
|
public float MaxFootstepVolume = 0.3f;
|
|
|
|
|
|
|
|
|
|
// behaviour stuff
|
|
|
|
|
int custardCount => (CollectGamemode.Instance) ? CollectGamemode.Instance.CustardAmount - CollectGamemode.Instance.CollectedCustard : 99;
|
|
|
|
|
List<Custard> custards => CollectGamemode.Instance.Custards ?? null;
|
|
|
|
|
GameObject[] fallbackSpots;
|
|
|
|
|
|
|
|
|
|
float speed;
|
|
|
|
|
|
|
|
|
|
Vector3? targetPosition;
|
|
|
|
|
[HideInInspector] public Vector3? recentlyCollectedCustard;
|
|
|
|
|
|
|
|
|
|
float nextStalkRefresh;
|
|
|
|
|
float nextChaseRefresh;
|
|
|
|
|
float nextTargetInvalidation;
|
|
|
|
|
float nextTeleport;
|
|
|
|
|
|
|
|
|
|
float chaseDuration;
|
|
|
|
|
float gazeDurationInStalk;
|
|
|
|
|
float ignoredNearbyDurationInStalk;
|
|
|
|
|
float gazeDurationInChase;
|
|
|
|
|
|
|
|
|
|
float timeSinceTooDistant;
|
|
|
|
|
|
|
|
|
|
bool chargeTowardPlayerInWander;
|
|
|
|
|
bool angeredInStalk;
|
|
|
|
|
|
|
|
|
|
bool saidEhOh;
|
|
|
|
|
|
|
|
|
|
bool nightmare;
|
|
|
|
|
|
|
|
|
|
bool isOffscreen;
|
|
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
|
{
|
|
|
|
|
Instance = this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Start()
|
|
|
|
|
{
|
|
|
|
|
if (DynamicTime.Instance)
|
|
|
|
|
nightmare = DynamicTime.Instance.ActiveTOD == DynamicTime.TimeOfDay.Nightmare;
|
|
|
|
|
|
|
|
|
|
if (nightmare)
|
|
|
|
|
{
|
|
|
|
|
WalkSpeed = RunSpeed / 1.2f;
|
|
|
|
|
MaxFootstepVolume /= 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fallbackSpots = GameObject.FindGameObjectsWithTag("Fallback Spot");
|
|
|
|
|
StartCoroutine(StateUpdate());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void LateUpdate()
|
|
|
|
|
{
|
|
|
|
|
isOffscreen = CheckIfOffScreen();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Update()
|
|
|
|
|
{
|
|
|
|
|
if (Player.Instance) {
|
|
|
|
|
Model.LookAt(Player.Instance.Camera.transform.position);
|
|
|
|
|
Model.transform.eulerAngles = new Vector3(-90, Model.transform.eulerAngles.y, Model.transform.eulerAngles.z);
|
|
|
|
|
if (Vector3.Distance(this.transform.position + KillOffset, Player.Instance.transform.position) < KillRange)
|
|
|
|
|
Player.Instance.Kill();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Agent.desiredVelocity.sqrMagnitude > 0.1f)
|
|
|
|
|
FootstepSource.volume = Mathf.Lerp(FootstepSource.volume, 0.3f, Time.deltaTime * 20f);
|
|
|
|
|
else
|
|
|
|
|
FootstepSource.volume = Mathf.Lerp(FootstepSource.volume, 0f, Time.deltaTime * 20f);
|
|
|
|
|
|
|
|
|
|
Agent.speed = speed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IEnumerator StateUpdate()
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
switch (ActiveState)
|
|
|
|
|
{
|
|
|
|
|
case States.None:
|
|
|
|
|
case States.Idle:
|
|
|
|
|
RequestState(States.Wander);
|
|
|
|
|
break;
|
|
|
|
|
case States.Wander:
|
|
|
|
|
yield return WanderUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case States.Stalk:
|
|
|
|
|
yield return StalkUpdate();
|
|
|
|
|
break;
|
|
|
|
|
case States.Chase:
|
|
|
|
|
yield return ChaseUpdate();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NextState == ActiveState) NextState = States.None;
|
|
|
|
|
if (NextState != States.None)
|
|
|
|
|
{
|
|
|
|
|
targetPosition = null;
|
|
|
|
|
Agent.ResetPath();
|
|
|
|
|
|
|
|
|
|
chaseDuration = 0;
|
|
|
|
|
gazeDurationInStalk = 0;
|
|
|
|
|
gazeDurationInChase = 0;
|
|
|
|
|
ignoredNearbyDurationInStalk = 0;
|
|
|
|
|
|
|
|
|
|
angeredInStalk = false;
|
|
|
|
|
chargeTowardPlayerInWander = false;
|
|
|
|
|
|
|
|
|
|
timeSinceTooDistant = 0;
|
|
|
|
|
|
|
|
|
|
ActiveState = NextState;
|
|
|
|
|
NextState = States.None;
|
|
|
|
|
|
|
|
|
|
if (ActiveState == States.Chase) {
|
|
|
|
|
MeshRenderer.materials[0].SetTexture("_BaseMap", ChaseFace);
|
|
|
|
|
ScreamSource.Play();
|
|
|
|
|
|
|
|
|
|
this.transform.position = GetChaseTeleportPosition();
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
MeshRenderer.materials[0].SetTexture("_BaseMap", NormalFace);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield return new WaitForEndOfFrame();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IEnumerator ChaseUpdate()
|
|
|
|
|
{
|
|
|
|
|
if (!Player.Instance) {
|
|
|
|
|
RequestState(States.Idle);
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float tpChance = 0; // used to be rng too
|
|
|
|
|
if (nightmare)
|
|
|
|
|
tpChance = (isOffscreen) ? 80 : 90;
|
|
|
|
|
else
|
|
|
|
|
tpChance = (isOffscreen) ? 50 : 80;
|
|
|
|
|
|
|
|
|
|
speed = (isOffscreen) ? RunSpeed/1.2f : RunSpeed*3;
|
|
|
|
|
|
|
|
|
|
if (!isOffscreen)
|
|
|
|
|
NearbyVignette.Show();
|
|
|
|
|
|
|
|
|
|
if (Time.time > nextChaseRefresh)
|
|
|
|
|
{
|
|
|
|
|
if (gazeDurationInChase < 3 && Random.Range(0, 100) < tpChance && Vector3.Distance(this.transform.position + KillOffset, Player.Instance.transform.position) > KillRange * 2 && Time.time > nextTeleport)
|
|
|
|
|
{
|
|
|
|
|
Agent.ResetPath();
|
|
|
|
|
|
|
|
|
|
this.transform.position = GetChaseTeleportPosition();
|
|
|
|
|
nextTeleport = Time.time + Random.Range(1f,2f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Agent.SetDestination(GetNavPosition(Player.Instance.transform.position));
|
|
|
|
|
nextChaseRefresh = Time.time + pathRefreshInterval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isOffscreen)
|
|
|
|
|
gazeDurationInChase = Mathf.Clamp(gazeDurationInChase + Time.deltaTime, 0, 10f);
|
|
|
|
|
else
|
|
|
|
|
gazeDurationInChase = Mathf.Clamp(gazeDurationInChase - Time.deltaTime * 2f, 0, 10f);
|
|
|
|
|
|
|
|
|
|
chaseDuration += (isOffscreen) ? Time.deltaTime * 2 : Time.deltaTime;
|
|
|
|
|
|
|
|
|
|
if (gazeDurationInChase > minGazeTimeForDeath)
|
|
|
|
|
Player.Instance.Kill();
|
|
|
|
|
|
|
|
|
|
if (chaseDuration >= loseChaseDuration || Vector3.Distance(this.transform.position, Player.Instance.transform.position) > loseChaseDistance)
|
|
|
|
|
{
|
|
|
|
|
this.transform.position = fallbackSpots[Random.Range(0, fallbackSpots.Length)].transform.position;
|
|
|
|
|
RequestState(States.Idle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IEnumerator StalkUpdate()
|
|
|
|
|
{
|
|
|
|
|
if (!Player.Instance) yield break;
|
|
|
|
|
|
|
|
|
|
if (angeredInStalk || nightmare)
|
|
|
|
|
{
|
|
|
|
|
speed = (!nightmare) ? RunSpeed * 2 : RunSpeed * 3;
|
|
|
|
|
|
|
|
|
|
if (Time.time > nextChaseRefresh)
|
|
|
|
|
{
|
|
|
|
|
Agent.SetDestination(GetNavPosition(Player.Instance.transform.position));
|
|
|
|
|
nextChaseRefresh = Time.time + pathRefreshInterval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PlayerDistance() <= minDistanceForChase / 1.5f) // replace back to 1.75 if range too big
|
|
|
|
|
RequestState(States.Chase);
|
|
|
|
|
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PlayerDistance() > minDistanceForStalk/2)
|
|
|
|
|
{
|
|
|
|
|
speed = RunSpeed * 4;
|
|
|
|
|
if (Time.time > nextChaseRefresh)
|
|
|
|
|
{
|
|
|
|
|
Agent.SetDestination(GetNavPosition(Player.Instance.transform.position - Player.Instance.transform.forward * keptDistanceForStalk));
|
|
|
|
|
nextChaseRefresh = Time.time + pathRefreshInterval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (PlayerDistance() >= maxDistanceForStalk)
|
|
|
|
|
{
|
|
|
|
|
RequestState(States.Wander);
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
speed = WalkSpeed * 1.5f;
|
|
|
|
|
|
|
|
|
|
if ((!targetPosition.HasValue || ReachedDestination()) && Time.time > nextStalkRefresh)
|
|
|
|
|
{
|
|
|
|
|
targetPosition = GetStalkPosition();
|
|
|
|
|
Agent.SetDestination(targetPosition.Value);
|
|
|
|
|
nextStalkRefresh = Time.time + Random.Range(5,10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isOffscreen)
|
|
|
|
|
{
|
|
|
|
|
float multi = 1f;
|
|
|
|
|
|
|
|
|
|
// pure evil
|
|
|
|
|
if (PlayerDistance() <= keptDistanceForStalk)
|
|
|
|
|
multi += 1.5f;
|
|
|
|
|
if (PlayerDistance() <= keptDistanceForStalk/2)
|
|
|
|
|
multi += 1.5f;
|
|
|
|
|
|
|
|
|
|
gazeDurationInStalk = Mathf.Clamp(gazeDurationInStalk + Time.deltaTime * multi, 0, minGazeTimeForChase);
|
|
|
|
|
|
|
|
|
|
ignoredNearbyDurationInStalk = Mathf.Clamp(ignoredNearbyDurationInStalk - Time.deltaTime * 2, 0, ignoredNearbyDurationInStalk);
|
|
|
|
|
if (gazeDurationInStalk > 0.5f && !saidEhOh)
|
|
|
|
|
{
|
|
|
|
|
saidEhOh = true;
|
|
|
|
|
EhOhSource.Play();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Agent.isStopped = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
gazeDurationInStalk = Mathf.Clamp(gazeDurationInStalk - Time.deltaTime / 2f, 0, minGazeTimeForChase);
|
|
|
|
|
if (PlayerDistance() <= keptDistanceForStalk * 1.2f)
|
|
|
|
|
ignoredNearbyDurationInStalk = Mathf.Clamp(ignoredNearbyDurationInStalk + Time.deltaTime, 0, ignoredNearbyDurationInStalk);
|
|
|
|
|
|
|
|
|
|
Agent.isStopped = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((gazeDurationInStalk >= minGazeTimeForChase || ignoredNearbyDurationInStalk >= minIgnoredNearbyTimeForChase) && PlayerDistance() <= minDistanceForChase * 2)
|
|
|
|
|
angeredInStalk = true;
|
|
|
|
|
|
|
|
|
|
if (PlayerDistance() <= minDistanceForChase / 1.75f)
|
|
|
|
|
RequestState(States.Chase);
|
|
|
|
|
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IEnumerator WanderUpdate()
|
|
|
|
|
{
|
|
|
|
|
if (nightmare && Player.Instance || chargeTowardPlayerInWander)
|
|
|
|
|
{
|
|
|
|
|
speed = RunSpeed * 4;
|
|
|
|
|
if (Time.time > nextChaseRefresh)
|
|
|
|
|
{
|
|
|
|
|
Agent.SetDestination(GetNavPosition(Player.Instance.transform.position));
|
|
|
|
|
nextChaseRefresh = Time.time + pathRefreshInterval;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NextState < States.Stalk)
|
|
|
|
|
{
|
|
|
|
|
if (isOffscreen && PlayerDistance() <= minDistanceForStalk && !chargeTowardPlayerInWander)
|
|
|
|
|
RequestState(States.Stalk);
|
|
|
|
|
if (!isOffscreen && PlayerDistance() <= minDistanceForChase)
|
|
|
|
|
RequestState(States.Chase);
|
|
|
|
|
if (PlayerDistance() <= minDistanceForChase / 1.25f)
|
|
|
|
|
RequestState(States.Chase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Player.Instance)
|
|
|
|
|
{
|
|
|
|
|
// "behind u" logic stuff
|
|
|
|
|
if (PlayerDistance() <= minDistanceForStalk)
|
|
|
|
|
timeSinceTooDistant = 0;
|
|
|
|
|
|
|
|
|
|
if (PlayerDistance() > minDistanceForStalk)
|
|
|
|
|
timeSinceTooDistant += Time.deltaTime;
|
|
|
|
|
|
|
|
|
|
if (PlayerDistance() > minDistanceForStalk * 2)
|
|
|
|
|
timeSinceTooDistant += Time.deltaTime;
|
|
|
|
|
|
|
|
|
|
if (PlayerDistance() > keptDistanceForStalk * 1.1f && custardCount <= 4)
|
|
|
|
|
timeSinceTooDistant += Time.deltaTime;
|
|
|
|
|
|
|
|
|
|
if (timeSinceTooDistant > 15)
|
|
|
|
|
{
|
|
|
|
|
Agent.ResetPath();
|
|
|
|
|
timeSinceTooDistant = 0;
|
|
|
|
|
|
|
|
|
|
Vector3 behind = GetNavPosition(Player.Instance.Camera.transform.position - Player.Instance.Camera.transform.forward * minDistanceForStalk / 1.25f);
|
|
|
|
|
Vector3 front = GetNavPosition(Player.Instance.Camera.transform.position + Player.Instance.Camera.transform.forward * minDistanceForStalk / 1.25f);
|
|
|
|
|
|
|
|
|
|
if (Random.Range(0, 100) < 50 && custardCount <= 2)
|
|
|
|
|
{
|
|
|
|
|
// tinky casually rushing towards you from the fog in front of you
|
|
|
|
|
if (Random.Range(0, 100) < 60)
|
|
|
|
|
chargeTowardPlayerInWander = true;
|
|
|
|
|
|
|
|
|
|
this.transform.position = front;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
this.transform.position = behind;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (custards != null)
|
|
|
|
|
speed = (custards.Count <= SprintOnlyCustardThreshold) ? RunSpeed : WalkSpeed;
|
|
|
|
|
else
|
|
|
|
|
speed = WalkSpeed;
|
|
|
|
|
|
|
|
|
|
if (Random.Range(0, 1000) < 5 && Time.time > nextTargetInvalidation) {
|
|
|
|
|
nextTargetInvalidation = Time.time + Random.Range(10, 40);
|
|
|
|
|
targetPosition = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (recentlyCollectedCustard == null) {
|
|
|
|
|
if (!targetPosition.HasValue || ReachedDestination())
|
|
|
|
|
{
|
|
|
|
|
if (Random.Range(0, 100) < 10 && custards != null)
|
|
|
|
|
{
|
|
|
|
|
var custard = custards[Random.Range(0, custards.Count)];
|
|
|
|
|
targetPosition = GetNavPosition(custard.transform.position);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
targetPosition = GetNavPosition(this.transform.position + (Random.insideUnitSphere * 40));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Random.Range(0, 100) < 20 || Random.Range(0, 100) < 70 && custardCount < SprintOnlyCustardThreshold)
|
|
|
|
|
targetPosition = GetNavPosition(Player.Instance.transform.position + (Random.insideUnitSphere * 15));
|
|
|
|
|
|
|
|
|
|
Agent.SetDestination(targetPosition.Value);
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
targetPosition = recentlyCollectedCustard;
|
|
|
|
|
Agent.SetDestination(targetPosition.Value);
|
|
|
|
|
recentlyCollectedCustard = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NextState < States.Stalk)
|
|
|
|
|
{
|
|
|
|
|
if (isOffscreen && PlayerDistance() <= minDistanceForStalk)
|
|
|
|
|
RequestState(States.Stalk);
|
|
|
|
|
if (!isOffscreen && PlayerDistance() <= minDistanceForChase)
|
|
|
|
|
RequestState(States.Chase);
|
|
|
|
|
if (PlayerDistance() <= minDistanceForChase / 1.25f)
|
|
|
|
|
RequestState(States.Chase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RequestState(States state)
|
|
|
|
|
{
|
|
|
|
|
NextState = state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float PlayerDistance()
|
|
|
|
|
{
|
|
|
|
|
if (!Player.Instance) return 0;
|
|
|
|
|
|
|
|
|
|
return Vector3.Distance(this.transform.position, Player.Instance.transform.position);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool CheckIfOffScreen(bool blockedCheck = false) // use isOffscreen instead of this
|
|
|
|
|
{
|
|
|
|
|
if (!Player.Instance) return true;
|
|
|
|
|
|
|
|
|
|
Vector3 normalized = Player.Instance.Camera.transform.forward.normalized;
|
|
|
|
|
Vector3 normalized2 = (Player.Instance.Camera.transform.position - (this.transform.position + RaycastOffset)).normalized;
|
|
|
|
|
float num = Vector3.Dot(normalized, normalized2);
|
|
|
|
|
|
|
|
|
|
bool blocked = true;
|
|
|
|
|
RaycastHit hit;
|
|
|
|
|
if (Physics.Raycast(this.transform.position + RaycastOffset, normalized2, out hit, 1000f, LayerMask))
|
|
|
|
|
if (hit.transform.CompareTag("Player"))
|
|
|
|
|
blocked = false;
|
|
|
|
|
|
|
|
|
|
if (num < offscreenDotRange && (!blocked || !blockedCheck))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void OnDrawGizmos()
|
|
|
|
|
{
|
|
|
|
|
Gizmos.color = Color.green;
|
|
|
|
|
if (targetPosition != null)
|
|
|
|
|
Gizmos.DrawLine(this.transform.position, targetPosition.Value);
|
|
|
|
|
|
|
|
|
|
Gizmos.color = Color.pink;
|
|
|
|
|
if (recentlyCollectedCustard != null)
|
|
|
|
|
Gizmos.DrawLine(this.transform.position, recentlyCollectedCustard.Value);
|
|
|
|
|
|
|
|
|
|
Gizmos.color = new Color(1f, 0.5f, 0f, 0.5f);
|
|
|
|
|
Gizmos.DrawWireSphere(this.transform.position, minDistanceForStalk);
|
|
|
|
|
|
|
|
|
|
Gizmos.color = new Color(1f, 0.25f, 0f, 0.25f);
|
|
|
|
|
Gizmos.DrawWireSphere(this.transform.position, keptDistanceForStalk);
|
|
|
|
|
|
|
|
|
|
Gizmos.color = new Color(1f, 0f, 0f, 0.1f);
|
|
|
|
|
Gizmos.DrawWireSphere(this.transform.position, minDistanceForChase);
|
|
|
|
|
Gizmos.color = new Color(1f, 0f, 0f, 0.25f);
|
|
|
|
|
Gizmos.DrawWireSphere(this.transform.position, minDistanceForChase / 1.25f);
|
|
|
|
|
Gizmos.color = new Color(1f, 0f, 0f, 1f);
|
|
|
|
|
Gizmos.DrawWireSphere(this.transform.position, minDistanceForChase / 1.75f);
|
|
|
|
|
|
|
|
|
|
Gizmos.color = Color.red;
|
|
|
|
|
Gizmos.DrawLine(this.transform.position + RaycastOffset, this.transform.position + RaycastOffset + this.transform.forward * 10f);
|
|
|
|
|
|
|
|
|
|
Gizmos.color = Color.lightPink;
|
|
|
|
|
Gizmos.DrawWireSphere(this.transform.position + KillOffset, KillRange);
|
|
|
|
|
|
|
|
|
|
Gizmos.color = Color.white;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool ReachedDestination()
|
|
|
|
|
{
|
|
|
|
|
if (Agent.pathPending)
|
|
|
|
|
return false;
|
|
|
|
|
if (Agent.remainingDistance > Agent.stoppingDistance + 0.25f)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return !Agent.hasPath || Agent.velocity.sqrMagnitude < 0.01f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Vector3 GetNavPosition(Vector3 pos)
|
|
|
|
|
{
|
|
|
|
|
NavMeshHit hit;
|
|
|
|
|
if (NavMesh.SamplePosition(pos, out hit, 5f, NavMesh.AllAreas))
|
|
|
|
|
return hit.position;
|
|
|
|
|
|
|
|
|
|
return Agent.transform.position;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Vector3 GetStalkPosition()
|
|
|
|
|
{
|
|
|
|
|
float back = Random.Range(keptDistanceForStalk / 2f, keptDistanceForStalk);
|
|
|
|
|
|
|
|
|
|
float side = Random.Range(-keptDistanceForStalk / 4f, keptDistanceForStalk / 4f);
|
|
|
|
|
|
|
|
|
|
Vector3 desired = Player.Instance.transform.position - (Player.Instance.transform.forward * back) + (Player.Instance.transform.right * side);
|
|
|
|
|
|
|
|
|
|
NavMeshHit hit;
|
|
|
|
|
if (NavMesh.SamplePosition(desired, out hit, 5f, NavMesh.AllAreas))
|
|
|
|
|
return hit.position;
|
|
|
|
|
|
|
|
|
|
return Agent.transform.position;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Vector3 GetChaseTeleportPosition()
|
|
|
|
|
{
|
|
|
|
|
float side = Random.Range(-keptDistanceForStalk / 5f, keptDistanceForStalk / 5f);
|
|
|
|
|
float dist = Vector3.Distance(this.transform.position, Player.Instance.transform.position);
|
|
|
|
|
|
|
|
|
|
Vector3 desired = Player.Instance.transform.position + (Player.Instance.transform.forward * dist) + (Player.Instance.transform.right * side);
|
|
|
|
|
|
|
|
|
|
NavMeshHit hit;
|
|
|
|
|
if (NavMesh.SamplePosition(desired, out hit, 5f, NavMesh.AllAreas))
|
|
|
|
|
return hit.position;
|
|
|
|
|
|
|
|
|
|
return Agent.transform.position;
|
|
|
|
|
}
|
|
|
|
|
}
|