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(); //projectile origin is normally the RIGHT hand. LEFT hand for troll / NPC's with bows. Transform[] children = GetComponentsInChildren(); 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(); sampleMesh = GetComponent(); healthBarComponent = GetComponent(); healthBarComponent.HeadTransform = headTransform; } private void Start() { if (localPathfinding()) { l = new LocalNPC(this); l.Start(); } animator = GetComponent(); 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()); isDead = true; } } public void PlayAnimation(string anim) { if (anim.ToLower().Equals("death")) { Destroy(GetComponent()); 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 npcColliders = new List(); public NPCAssistant npcAssistant; //only used for npcs where pathfinding and AI is done locally public LocalNPC l; }