Files
2026-07-21 08:58:18 +05:30

738 lines
18 KiB
C#

using System.Collections;
using UnityEngine;
using UnityEngine.AI;
public class SimpleTeamAI : MonoBehaviour
{
public enum TeamType
{
PlayerTeam,
EnemyTeam
}
public enum AIState
{
Idle,
Combat,
Collect,
Deposit,
Vault,
Hit,
Patrol
}
[Header("Team Settings")]
[SerializeField] private TeamType teamType;
[SerializeField] private float roamRadius = 8f;
[SerializeField] private float roamChangeTime = 3f;
private float nextRoamTime;
[Header("Combat Settings")]
[SerializeField] private float attackRange = 2f;
[SerializeField] private float attackCooldown = 1.2f;
[SerializeField] private float targetPriorityRange = 100f;
private float nextCombatSearch;
[SerializeField] private float combatSearchInterval = 0.3f;
[Header("Collection Settings")]
[SerializeField] private float scanRadius = 15f;
[SerializeField] private int depositCashAmount = 500;
[Header("Debug")]
public AIState currentState;
public Transform currentTarget;
[SerializeField] private Transform combatTarget;
private NavMeshAgent agent;
private Animator anim;
private CashManager cashManager;
private Health health;
private TeamMember teamMember;
private bool isAttacking;
private bool isHit;
private bool hasCash;
private bool isBusy;
private Coroutine attackRoutine;
private string enemyTag;
private string depositStationTag;
private Vault openingVault;
private Coroutine depositRoutine;
private bool isDepositing;
[SerializeField] private ParticleSystem depositAura;
void Awake()
{
agent = GetComponent<NavMeshAgent>();
anim = GetComponent<Animator>();
cashManager = GetComponent<CashManager>();
health = GetComponent<Health>();
teamMember = GetComponent<TeamMember>();
StopDepositEffect();
}
void Start()
{
SetupTeam();
if (agent != null)
{
agent.enabled = true;
agent.isStopped = false;
agent.updatePosition = true;
//agent.updateRotation = false;
if (!agent.isOnNavMesh)
{
NavMeshHit hit;
if (NavMesh.SamplePosition(transform.position, out hit, 20f, NavMesh.AllAreas))
{
agent.Warp(hit.position);
}
else
{
Debug.LogError($"{gameObject.name} is not on NavMesh.");
}
}
}
currentState = AIState.Idle;
}
void SetupTeam()
{
// Auto-detect team from TeamMember first
if (teamMember != null)
{
if (teamMember.CurrentTeam == TeamMember.Team.PlayerTeam)
{
teamType = TeamType.PlayerTeam;
}
else
{
teamType = TeamType.EnemyTeam;
}
}
else
{
// Fallback: auto-detect from tag if TeamMember is missing
if (CompareTag("Player"))
{
teamType = TeamType.PlayerTeam;
}
else if (CompareTag("Enemy"))
{
teamType = TeamType.EnemyTeam;
}
else
{
Debug.LogWarning($"{gameObject.name}: No TeamMember and no Player/Enemy tag found. Using Inspector teamType.");
}
}
if (teamType == TeamType.PlayerTeam)
{
enemyTag = "Enemy";
depositStationTag = "PlayerDepositSt";
}
else
{
enemyTag = "Player";
depositStationTag = "EnemyDepositSt";
}
Debug.Log($"{gameObject.name}: SimpleTeamAI auto-detected team as {teamType}. EnemyTag={enemyTag}, DepositTag={depositStationTag}");
}
void Update()
{
if (agent == null || anim == null)
return;
if (!agent.enabled || !agent.isOnNavMesh)
return;
if (health != null && health.isDead)
{
DisableMovement();
return;
}
if (agent.speed == 0)
agent.speed = 6f;
if (isHit)
{
SetState(AIState.Hit);
}
if (isBusy)
{
anim.SetFloat("Speed", 0f);
return;
}
//else if (isBusy)
//{
// // Keep current state while opening vault / hit / special action
//}
else
{
//cashManager = GetComponent<CashManager>();
if (cashManager != null && cashManager.currentCash >= depositCashAmount)
{
SetState(AIState.Deposit);
}
else
{
if (Time.time >= nextCombatSearch)
{
nextCombatSearch = Time.time + combatSearchInterval;
combatTarget = FindNearestCombatTarget();
}
if (combatTarget != null)
{
float targetDist = Vector3.Distance(transform.position, combatTarget.position);
if (targetDist <= targetPriorityRange)
{
SetState(AIState.Combat);
}
else
{
SetState(AIState.Collect);
}
}
else
{
SetState(AIState.Collect);
}
}
}
HandleState();
anim.SetFloat("Speed", agent.velocity.magnitude);
}
void SetState(AIState newState)
{
currentState = newState;
}
void HandleState()
{
switch (currentState)
{
case AIState.Combat:
HandleCombat();
break;
case AIState.Collect:
HandleCollection();
break;
case AIState.Deposit:
HandleDeposit();
break;
case AIState.Hit:
DisableMovement();
break;
}
}
void HandleCombat()
{
if (combatTarget == null)
{
combatTarget = FindNearestCombatTarget();
if (combatTarget == null)
{
SetState(AIState.Collect);
return;
}
}
Health targetHealth = combatTarget.GetComponent<Health>();
if (targetHealth != null && targetHealth.isDead)
{
combatTarget = null;
SetState(AIState.Collect);
return;
}
float dist = Vector3.Distance(transform.position, combatTarget.position);
Vector3 dir = combatTarget.position - transform.position;
dir.y = 0;
if (dir.sqrMagnitude > 0.01f)
{
transform.rotation = Quaternion.Slerp(
transform.rotation,
Quaternion.LookRotation(dir),
Time.deltaTime * 10f
);
}
if (!isAttacking)
{
if (dist > attackRange)
{
agent.isStopped = false;
agent.SetDestination(combatTarget.position);
}
else
{
agent.isStopped = true;
agent.velocity = Vector3.zero;
if (attackRoutine == null)
attackRoutine = StartCoroutine(AttackRoutine());
}
}
}
void HandleCollection()
{
if (currentTarget == null)
{
currentTarget = FindVaultTarget();
if (currentTarget != null)
{
Vault vault = currentTarget.GetComponent<Vault>();
if (vault == null || !vault.TryReserve(this))
{
currentTarget = null;
return;
}
}
}
if (currentTarget == null)
{
RoamAround();
return;
}
Vault currentVault = currentTarget.GetComponent<Vault>();
if (currentVault == null || !currentVault.IsReservedBy(this))
{
currentTarget = null;
return;
}
agent.isStopped = false;
agent.SetDestination(currentTarget.position);
float dist = Vector3.Distance(transform.position, currentTarget.position);
if (!isBusy && currentTarget.CompareTag("Vault") && dist <= 1.5f)
{
SetState(AIState.Vault);
StartCoroutine(VaultRoutine());
}
}
void RoamAround()
{
if (Time.time < nextRoamTime && agent.hasPath)
return;
Vector3 randomPos = transform.position + Random.insideUnitSphere * roamRadius;
randomPos.y = transform.position.y;
NavMeshHit hit;
if (NavMesh.SamplePosition(randomPos, out hit, roamRadius, NavMesh.AllAreas))
{
agent.isStopped = false;
agent.SetDestination(hit.position);
nextRoamTime = Time.time + roamChangeTime;
}
}
Transform FindVaultTarget()
{
Collider[] hits = Physics.OverlapSphere(transform.position, scanRadius);
Transform best = null;
float minDist = Mathf.Infinity;
foreach (Collider hit in hits)
{
if (hit.CompareTag("Vault"))
{
Vault vault = hit.GetComponent<Vault>();
if (vault == null)
continue;
if (vault.IsReserved())
continue;
float d = Vector3.Distance(transform.position, hit.transform.position);
if (d < minDist)
{
minDist = d;
best = hit.transform;
}
}
}
return best;
}
Transform FindNearestCombatTarget()
{
if (teamMember == null)
return null;
Transform best = null;
float minDist = Mathf.Infinity;
foreach (TeamMember other in TeamMember.AllMembers)
{
if (other == null)
continue;
if (other == teamMember)
continue;
if (!teamMember.IsEnemy(other))
continue;
Health targetHealth = other.GetComponent<Health>();
if (targetHealth != null && targetHealth.isDead)
continue;
float d = Vector3.Distance(
transform.position,
other.transform.position);
if (d < minDist)
{
minDist = d;
best = other.transform;
}
}
return best;
}
IEnumerator VaultRoutine()
{
if (isBusy) yield break;
if (currentTarget == null)
yield break;
Vault vault = currentTarget.GetComponent<Vault>();
openingVault = vault;
if (vault.IsPlayerInside())
{
vault.Release(this);
currentTarget = null;
openingVault = null;
yield break;
}
if (vault == null || !vault.IsReservedBy(this))
{
currentTarget = null;
yield break;
}
isBusy = true;
vault.MarkBeingOpened(this);
agent.isStopped = true;
agent.velocity = Vector3.zero;
if (vault != null && vault.InteractionPoint != null)
{
transform.position = vault.InteractionPoint.position;
agent.Warp(transform.position);
Vector3 lookDir = vault.transform.position - transform.position;
lookDir.y = 0;
if (lookDir.sqrMagnitude > 0.01f)
transform.rotation = Quaternion.LookRotation(lookDir);
}
anim.SetTrigger("OpenVault");
yield return new WaitForSeconds(6f);
//cashManager = GetComponent<CashManager>();
//if (cashManager != null && vault != null)
//{
// cashManager.AddCash(vault.GetVaultCash());
//}
//if (currentTarget != null)
//{
// Destroy(currentTarget.gameObject);
//}
hasCash = true;
currentTarget = null;
agent.isStopped = false;
isBusy = false;
}
public void AddVaultCashAndDestroyVault()
{
if (openingVault == null)
return;
if (isHit || currentState == AIState.Hit)
return;
if (health != null && health.isDead)
return;
if (cashManager == null)
cashManager = GetComponent<CashManager>();
if (cashManager != null)
cashManager.AddCash(openingVault.GetVaultCash());
VaultSpawner.Instance?.NotifyVaultDestroyed();
Destroy(openingVault.gameObject);
openingVault = null;
currentTarget = null;
hasCash = true;
isBusy = false;
if (agent != null && agent.enabled && agent.isOnNavMesh)
agent.isStopped = false;
SetState(AIState.Deposit);
}
void HandleDeposit()
{
GameObject deposit = GameObject.FindGameObjectWithTag(depositStationTag);
if (deposit == null)
{
Debug.LogWarning($"{gameObject.name}: Deposit station not found with tag {depositStationTag}");
return;
}
Transform point = deposit.transform.Find("DepositPoint");
if (point == null)
{
Debug.LogWarning($"{gameObject.name}: DepositPoint child missing under {depositStationTag}");
return;
}
currentTarget = point;
agent.isStopped = false;
agent.SetDestination(point.position);
}
IEnumerator AttackRoutine()
{
if (isAttacking || isHit) yield break;
if (combatTarget == null)
{
attackRoutine = null;
yield break;
}
float dist = Vector3.Distance(transform.position, combatTarget.position);
if (dist > attackRange)
{
attackRoutine = null;
yield break;
}
isAttacking = true;
agent.isStopped = true;
int attackIndex = Random.Range(0, 6);
switch (attackIndex)
{
case 0: anim.SetTrigger("Haymaker"); break;
case 1: anim.SetTrigger("LeftKick"); break;
case 2: anim.SetTrigger("LowKick"); break;
case 3: anim.SetTrigger("BicycleKick"); break;
case 4: anim.SetTrigger("SpinningBackFist"); break;
case 5: anim.SetTrigger("ElbowSmash"); break;
}
yield return new WaitForSeconds(1f);
isAttacking = false;
//agent.isStopped = false;
yield return new WaitForSeconds(attackCooldown);
attackRoutine = null;
}
public void CancelAttackAndHit(string bodyPart = "Body")
{
isHit = true;
SetState(AIState.Hit);
if (attackRoutine != null)
{
StopCoroutine(attackRoutine);
attackRoutine = null;
}
isAttacking = false;
DisableMovement();
anim.ResetTrigger("Haymaker");
anim.ResetTrigger("LeftKick");
anim.ResetTrigger("LowKick");
anim.ResetTrigger("BicycleKick");
anim.ResetTrigger("SpinningBackFist");
anim.ResetTrigger("ElbowSmash");
CharacterCombat combat = GetComponent<CharacterCombat>();
combat?.OnDamageTaken(bodyPart);
StartCoroutine(RecoverFromHit());
}
IEnumerator RecoverFromHit()
{
yield return new WaitForSeconds(0.5f);
isHit = false;
SetState(AIState.Idle);
EnableMovement();
}
public void DisableMovement()
{
if (agent != null && agent.enabled && agent.isOnNavMesh)
{
agent.isStopped = true;
agent.ResetPath();
agent.velocity = Vector3.zero;
}
}
public void EnableMovement()
{
if (agent != null && agent.enabled && agent.isOnNavMesh)
{
agent.speed = 6f;
agent.isStopped = false;
}
}
public void OnHitStart()
{
isHit = true;
SetState(AIState.Hit);
DisableMovement();
}
public void OnHitEnd()
{
isHit = false;
SetState(AIState.Idle);
EnableMovement();
}
public void ResetAfterDeposit()
{
hasCash = false;
currentTarget = null;
SetState(AIState.Idle);
}
public void StartDeposit(float depositTime)
{
if (isDepositing)
return;
depositRoutine =
StartCoroutine(DepositRoutine(depositTime));
}
IEnumerator DepositRoutine(float depositTime)
{
isDepositing = true;
isBusy = true;
agent.isStopped = true;
agent.velocity = Vector3.zero;
//anim.SetTrigger("Deposit");
yield return new WaitForSeconds(depositTime);
CashManager cash =
GetComponent<CashManager>();
if (cash != null)
{
int depositedAmount =
cash.DepositAllCash();
DepositStationManager.Instance.AddCash(
depositedAmount,
teamMember.CurrentTeam
);
}
StopDepositEffect();
isDepositing = false;
isBusy = false;
ResetAfterDeposit();
}
public void StartDepositEffect()
{
if (depositAura != null)
depositAura.Play();
}
public void StopDepositEffect()
{
if (depositAura != null)
depositAura.Stop();
}
}