using UnityEngine; using System.Collections; using DamageNumbersPro; using UnityEditor.Embree; public class MonsterController : MonoBehaviour { public MonsterData data; public MonsterFormationGroup formationGroup; private MonsterAnimatorController animator; private Vector3 currentTarget; public int currentHP; private float attackTimer = 0f; public float rotationSpeed = 40f; public DamageNumber damagePopupPrefab; public GameObject goldBagPrefab; public Transform goldSpawnPoint; public float goldDropYOffset = 0.15f; private void Start() { animator = GetComponent(); currentHP = data.maxHP; if (data != null) { attackTimer = data.attackCooldown; } FindFirstObjectByType()?.RegisterMonster(this); } public void ShowDamageNumber(float amount) { if (damagePopupPrefab == null) return; Vector3 popupPosition = transform.position + Vector3.up * 2f; DamageNumber newPopup = damagePopupPrefab.Spawn(popupPosition, amount); if (newPopup != null) { Transform cameraTransform = Camera.main?.transform; if (cameraTransform != null) { Vector3 cameraEuler = cameraTransform.eulerAngles; newPopup.transform.rotation = Quaternion.Euler(0f, cameraEuler.y, 0f); } } } public void MoveTo(Vector3 newPosition) { currentTarget = newPosition; StopAllCoroutines(); StartCoroutine(MoveStep()); } IEnumerator MoveStep() { animator?.PlayMove(); while (Vector3.Distance(transform.position, currentTarget) > 0.05f) { transform.position = Vector3.MoveTowards(transform.position, currentTarget, data.moveSpeed * Time.deltaTime); yield return null; } animator?.StopMove(); } public void FaceTarget(Vector3 target, bool instant = false) { Vector3 direction = (target - transform.position).normalized; direction.y = 0; if (direction != Vector3.zero) { Quaternion targetRotation = Quaternion.LookRotation(direction); if (instant) { transform.rotation = targetRotation; } else { transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed); } } } public bool IsFacingTarget(Vector3 target, float angleThreshold = 30f) { Vector3 directionToTarget = (target - transform.position).normalized; directionToTarget.y = 0; if (directionToTarget == Vector3.zero) return true; float angle = Vector3.Angle(transform.forward, directionToTarget); return angle <= angleThreshold; } public void StopMove() { animator?.StopMove(); } public void Attack() { animator?.PlayAttack(); } public void UpdateAttackTimer(float deltaTime) { attackTimer += deltaTime; } public bool CanAttack() { return attackTimer >= data.attackCooldown; } public void ResetAttackTimer() { attackTimer = 0f; } public int GetDamage() { if (Random.value < data.missChance) { return 0; } float min = data.attackDamage / 2f; float max = data.attackDamage * 1.5f; int damage = Mathf.RoundToInt(Random.Range(min, max)); return damage; } public void TakeDamage(int amount) { currentHP -= amount; ShowDamageNumber(amount); if (currentHP <= 0) { Die(); } else { animator?.PlayHurt(); } } public void Die() { animator?.PlayDeath(); Collider collider = GetComponent(); if (collider != null) { collider.enabled = false; } GrantExperienceToParty(); StartCoroutine(CoroutineDropGoldBag()); formationGroup?.NotifyMonsterDeath(this); Destroy(gameObject, 2f); } private IEnumerator CoroutineDropGoldBag() { if (Random.value < 0.5f) { if (goldBagPrefab != null) { Vector3 dropPosition; if (goldSpawnPoint != null) { dropPosition = goldSpawnPoint.position + Vector3.up * goldDropYOffset; } else { dropPosition = transform.position + Vector3.up * goldDropYOffset; } GameObject goldBag = Instantiate(goldBagPrefab, dropPosition, Quaternion.Euler(-90f, 0f, 0f)); } } yield return null; } private void GrantExperienceToParty() { TeamCohesionManager cohesionManager = FindFirstObjectByType(); if (cohesionManager == null || data == null) return; int expPerMember = Mathf.RoundToInt(data.exp); foreach (var character in cohesionManager.groupMembers) { character.experience += expPerMember; // Update the experience bar UIUpdater.Instance?.UpdateCharacterExperience(character); // Check for level up CheckLevelUp(character); } } private void CheckLevelUp(CharacterInGroup character) { while (character.experience >= 100) { character.experience -= 100; character.level++; int hpIncrease = 5 + character.constitution; int staminaIncrease = 5 + (character.constitution / 2); character.maxHP += hpIncrease; character.currentHP += hpIncrease; character.maxFatigue += staminaIncrease; character.currentFatigue += staminaIncrease; UIUpdater.Instance?.UpdateCharacterHP(character); UIUpdater.Instance?.UpdateCharacterFatigue(character); UIUpdater.Instance?.UpdateCharacterExperience(character); } } public void Setup(MonsterGroupManager mgr) { } }