256 lines
5.7 KiB
C#
Raw Normal View History

2025-09-06 17:17:39 +04:00
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.VFX;
using DG.Tweening;
public class NPC : MonoBehaviour
{
public event Action OnDead;
public void Dead() => OnDead?.Invoke();
private void Awake()
{
npcAssistant = new NPCAssistant(this);
entityManager = Client.Instance.gameObject.GetComponent<NPCManager>();
//projectile origin is normally the RIGHT hand. LEFT hand for troll / NPC's with bows.
Transform[] children = GetComponentsInChildren<Transform>();
foreach (Transform transforms in children)
{
if (transforms.name == "projectileOrigin")
{
projectileOrigin = transforms.gameObject;
}
if (transforms.CompareTag("Head"))
{
headTransform = transforms;
}
if (transforms.TryGetComponent(out SkinnedMeshRenderer skinnedMesh))
{
//Debug.LogError($"SkinnedMesh Found: {skinnedMesh.name}");
this.skinnedMesh = skinnedMesh;
}
if (transforms.TryGetComponent(out Collider collider))
{
npcColliders.Add(collider);
}
}
weaponRandomizer = GetComponent<NPCWeaponRandomizer>();
sampleMesh = GetComponent<SkinnedMeshToMesh>();
healthBarComponent = GetComponent<NPCHealthBar>();
healthBarComponent.HeadTransform = headTransform;
}
private void Start()
{
if (localPathfinding())
{
l = new LocalNPC(this);
l.Start();
}
animator = GetComponent<Animator>();
targetPosition = transform.position;
previousPosition = transform.position;
lastUpdate = Time.time;
forcePositionUpdate = false;
}
private void Update()
{
if (Time.time - lastUpdate > 7.0f)
{
entityManager.RemoveNPC(this);
return;
}
//force update position
if (forcePositionUpdate)
{
transform.position = targetPosition;
forcePositionUpdate = false;
return;
}
}
private void FixedUpdate()
{
if (localPathfinding())
{
l.FixedUpdate();
return;
}
if (isDead) { return; }
getNA().InterpolateEntity();
getNA().BindEntityToTerrain();
showMesh();
}
public void processUpdateMessage(int id, float x, float z, int deltaMultiplier, float face, float normalizedHealth)
{
lastUpdate = Time.time;
if (localPathfinding())
{
return;
}
if (deltaMultiplier == -1)
this.forcePositionUpdate = true;
else
this.deltaMultiplier = deltaMultiplier;
targetPosition = new Vector3(x + (getNA().getSize(this.type) / 2.0f), transform.position.y, z + (getNA().getSize(this.type) / 2.0f));
transform.rotation = Quaternion.Euler(0, face, 0);
if (healthBarComponent.healthBar != null)
healthBarComponent.healthBar.SetHealth(normalizedHealth);
if (normalizedHealth <= 0.0f)
{
Destroy(GetComponent<AudioSource>());
isDead = true;
}
}
public void PlayAnimation(string anim)
{
if (anim.ToLower().Equals("death"))
{
Destroy(GetComponent<AudioSource>());
isDead = true;
getNA().ToggleColliders(false);
StartCoroutine(getNA().DeathFadePosition());
StartCoroutine(getNA().WaitToSpawnDeathSoul());
getNA().FadeHealthCanvas();
OnDead?.Invoke();
}
//print("trying to play animation: " + anim);
animator?.Play(anim);
}
public void showMesh()
{
if (Time.time - lastDistanceCheck < 3.0f) { return; }
//if distance to player > 80
if (Vector3.Distance(transform.position, Client.Instance.mainPlayer.transform.position) > 80)
{
skinnedMesh.enabled = false;
}
else
{
skinnedMesh.enabled = true;
}
}
public int GetID()
{
return id;
}
public void SetID(int id)
{
this.id = id;
}
public void SetHitPoints(int hp)
{
hitPoints = hp;
}
public int GetHitPoints()
{
return hitPoints;
}
public NPCAssistant getNA()
{
return npcAssistant;
}
public bool localPathfinding()
{
return Misc.checkBit(flags, 0);
}
public Projectile Instantiate2(Projectile g)
{
return Instantiate(g);
}
private int id;//uuid
public int flags;
public Vector3 targetPosition;
public float lastUpdate;
public bool forcePositionUpdate;
public int hitPoints;
private NPCManager entityManager;
public GameObject projectileOrigin;
[System.NonSerialized] public Animator animator;
[System.NonSerialized] public int type;
//when dead, stop interpolation
[System.NonSerialized] public bool isDead = false;
public float damping = 10.0f;
public Vector3 previousPosition;
public Transform headTransform;
public SkinnedMeshRenderer skinnedMesh = null;
public SkinnedMeshToMesh sampleMesh = null;
public NPCWeaponRandomizer weaponRandomizer = null;
public NPCHealthBar healthBarComponent;
public int deltaMultiplier;
private float lastDistanceCheck = 0.0f;
public List<Collider> npcColliders = new List<Collider>();
public NPCAssistant npcAssistant;
//only used for npcs where pathfinding and AI is done locally
public LocalNPC l;
}