test commit

This commit is contained in:
niko
2026-10-11 20:26:48 +02:00
parent 4dbd3c0ab3
commit 6fee00e7ff
2187 changed files with 760371 additions and 2 deletions
+34
View File
@@ -0,0 +1,34 @@
using NUnit.Framework;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
public class DummyWinky : MonoBehaviour
{
public static DummyWinky Instance;
private void Awake()
{
Instance = this;
}
public bool unleashed = false;
public void Unleash()
{
unleashed = true;
}
private void Update()
{
if (unleashed)
{
Vector3 normalized2 = (this.transform.position - Player.Instance.Camera.transform.position).normalized;
this.transform.localScale += Vector3.one * Time.deltaTime;
this.transform.LookAt(Player.Instance.transform.position);
this.transform.position -= normalized2 * Time.deltaTime * 3;
}
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1eb97d07c3f34ae4199bf0bbcd3d4b07
+555
View File
@@ -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;
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1c494df9d7e33f645997302b855b3ec6