|
@@ -59,9 +59,7 @@ private IEnumerator DelayedStart()
|
|
|
if (other.CompareTag("Player"))
|
|
if (other.CompareTag("Player"))
|
|
|
{
|
|
{
|
|
|
hasDetectedPlayer = true;
|
|
hasDetectedPlayer = true;
|
|
|
- Debug.Log("[MonsterGroup] Player entered detection zone");
|
|
|
|
|
|
|
|
|
|
- // Only start chase if not already chasing or attacking
|
|
|
|
|
if (!isChasing && attackLoopCoroutine == null)
|
|
if (!isChasing && attackLoopCoroutine == null)
|
|
|
{
|
|
{
|
|
|
StartChase();
|
|
StartChase();
|
|
@@ -74,16 +72,13 @@ private IEnumerator DelayedStart()
|
|
|
if (other.CompareTag("Player"))
|
|
if (other.CompareTag("Player"))
|
|
|
{
|
|
{
|
|
|
hasDetectedPlayer = false;
|
|
hasDetectedPlayer = false;
|
|
|
- Debug.Log("[MonsterGroup] Player exited detection zone");
|
|
|
|
|
|
|
|
|
|
- // Stop attack loop if player leaves
|
|
|
|
|
if (attackLoopCoroutine != null)
|
|
if (attackLoopCoroutine != null)
|
|
|
{
|
|
{
|
|
|
StopCoroutine(attackLoopCoroutine);
|
|
StopCoroutine(attackLoopCoroutine);
|
|
|
attackLoopCoroutine = null;
|
|
attackLoopCoroutine = null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Reset chase state
|
|
|
|
|
isChasing = false;
|
|
isChasing = false;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -143,29 +138,24 @@ private IEnumerator DelayedStart()
|
|
|
|
|
|
|
|
public void NotifyMonsterDeath(MonsterController dead)
|
|
public void NotifyMonsterDeath(MonsterController dead)
|
|
|
{
|
|
{
|
|
|
- Debug.Log("Boucle NotifyMonster");
|
|
|
|
|
-
|
|
|
|
|
Vector3 deadPosition = dead.transform.position;
|
|
Vector3 deadPosition = dead.transform.position;
|
|
|
|
|
|
|
|
if (frontRow.Contains(dead))
|
|
if (frontRow.Contains(dead))
|
|
|
{
|
|
{
|
|
|
- Debug.Log("FrontRow ...");
|
|
|
|
|
int index = frontRow.IndexOf(dead);
|
|
int index = frontRow.IndexOf(dead);
|
|
|
frontRow.RemoveAt(index);
|
|
frontRow.RemoveAt(index);
|
|
|
|
|
|
|
|
if (backRow.Count > 0)
|
|
if (backRow.Count > 0)
|
|
|
{
|
|
{
|
|
|
- Debug.Log("BackRow");
|
|
|
|
|
MonsterController replacement = GetClosestBacklinerTo(deadPosition);
|
|
MonsterController replacement = GetClosestBacklinerTo(deadPosition);
|
|
|
backRow.Remove(replacement);
|
|
backRow.Remove(replacement);
|
|
|
frontRow.Insert(index, replacement);
|
|
frontRow.Insert(index, replacement);
|
|
|
|
|
|
|
|
- StartCoroutine(MoveReplacementWithDelay(replacement, deadPosition, 2f)); // ๐ dรฉlai de 2s
|
|
|
|
|
|
|
+ StartCoroutine(MoveReplacementWithDelay(replacement, deadPosition, 2f));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- Debug.Log("BackRow Dead");
|
|
|
|
|
backRow.Remove(dead);
|
|
backRow.Remove(dead);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -181,28 +171,23 @@ private IEnumerator DelayedStart()
|
|
|
{
|
|
{
|
|
|
if (!isChasing)
|
|
if (!isChasing)
|
|
|
{
|
|
{
|
|
|
- // Ajout de vรฉrification avant de dรฉmarrer le combat
|
|
|
|
|
if (UIUpdater.Instance == null || UIUpdater.Instance.IsReady == false)
|
|
if (UIUpdater.Instance == null || UIUpdater.Instance.IsReady == false)
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] UI pas encore prรชte, attente du setup...");
|
|
|
|
|
StartCoroutine(WaitForUIThenChase());
|
|
StartCoroutine(WaitForUIThenChase());
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Debug.Log("[MonsterGroup] StartChase() appelรฉ");
|
|
|
|
|
StartCoroutine(ChaseRoutine());
|
|
StartCoroutine(ChaseRoutine());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
IEnumerator WaitForUIThenChase()
|
|
IEnumerator WaitForUIThenChase()
|
|
|
{
|
|
{
|
|
|
- // Attend que UIUpdater soit prรชt
|
|
|
|
|
while (UIUpdater.Instance == null || UIUpdater.Instance.IsReady == false)
|
|
while (UIUpdater.Instance == null || UIUpdater.Instance.IsReady == false)
|
|
|
{
|
|
{
|
|
|
yield return null;
|
|
yield return null;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Debug.Log("[MonsterGroup] UI prรชte, dรฉmarrage de la chasse !");
|
|
|
|
|
StartCoroutine(ChaseRoutine());
|
|
StartCoroutine(ChaseRoutine());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -211,41 +196,32 @@ private IEnumerator DelayedStart()
|
|
|
{
|
|
{
|
|
|
isChasing = true;
|
|
isChasing = true;
|
|
|
distanceTravelled = 0f;
|
|
distanceTravelled = 0f;
|
|
|
-
|
|
|
|
|
- Debug.Log("[MonsterGroup] Chase routine started");
|
|
|
|
|
|
|
|
|
|
while (isChasing && hasDetectedPlayer)
|
|
while (isChasing && hasDetectedPlayer)
|
|
|
{
|
|
{
|
|
|
- // Check if player left detection zone
|
|
|
|
|
if (!hasDetectedPlayer)
|
|
if (!hasDetectedPlayer)
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] Player left detection zone during chase");
|
|
|
|
|
isChasing = false;
|
|
isChasing = false;
|
|
|
yield break;
|
|
yield break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
float distanceToPlayer = Vector3.Distance(transform.position, player.position);
|
|
float distanceToPlayer = Vector3.Distance(transform.position, player.position);
|
|
|
|
|
|
|
|
- // Reached attack range
|
|
|
|
|
if (distanceToPlayer <= attackRange || IsAdjacentToPlayer())
|
|
if (distanceToPlayer <= attackRange || IsAdjacentToPlayer())
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] Reached attack range, starting combat");
|
|
|
|
|
isChasing = false;
|
|
isChasing = false;
|
|
|
attackLoopCoroutine = StartCoroutine(LoopAttack());
|
|
attackLoopCoroutine = StartCoroutine(LoopAttack());
|
|
|
yield break;
|
|
yield break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Continue chasing
|
|
|
|
|
Vector3 dirToPlayer = (player.position - transform.position).normalized;
|
|
Vector3 dirToPlayer = (player.position - transform.position).normalized;
|
|
|
Vector3 step = new Vector3(Mathf.Round(dirToPlayer.x), 0, Mathf.Round(dirToPlayer.z)) * cellSize;
|
|
Vector3 step = new Vector3(Mathf.Round(dirToPlayer.x), 0, Mathf.Round(dirToPlayer.z)) * cellSize;
|
|
|
|
|
|
|
|
MoveGroupBy(step);
|
|
MoveGroupBy(step);
|
|
|
distanceTravelled += cellSize + 1f;
|
|
distanceTravelled += cellSize + 1f;
|
|
|
|
|
|
|
|
- // Tactical pause every 5 meters
|
|
|
|
|
if (distanceTravelled >= stopAfterDistance)
|
|
if (distanceTravelled >= stopAfterDistance)
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] Tactical pause after moving 5m");
|
|
|
|
|
yield return new WaitForSeconds(stopDuration);
|
|
yield return new WaitForSeconds(stopDuration);
|
|
|
distanceTravelled = 0f;
|
|
distanceTravelled = 0f;
|
|
|
}
|
|
}
|
|
@@ -255,7 +231,6 @@ private IEnumerator DelayedStart()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Debug.Log("[MonsterGroup] Chase routine ended");
|
|
|
|
|
isChasing = false;
|
|
isChasing = false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -271,21 +246,13 @@ private IEnumerator DelayedStart()
|
|
|
|
|
|
|
|
private void Update()
|
|
private void Update()
|
|
|
{
|
|
{
|
|
|
- // Only act if player is in detection zone
|
|
|
|
|
if (!hasDetectedPlayer) return;
|
|
if (!hasDetectedPlayer) return;
|
|
|
-
|
|
|
|
|
- // If player not assigned yet, wait
|
|
|
|
|
if (player == null) return;
|
|
if (player == null) return;
|
|
|
-
|
|
|
|
|
- // Prevent interference with active states
|
|
|
|
|
if (isChasing || attackLoopCoroutine != null) return;
|
|
if (isChasing || attackLoopCoroutine != null) return;
|
|
|
|
|
|
|
|
- // If not currently doing anything and player is detected
|
|
|
|
|
if (!isChasing && attackLoopCoroutine == null)
|
|
if (!isChasing && attackLoopCoroutine == null)
|
|
|
{
|
|
{
|
|
|
- // Check if any front row monster is in attack range
|
|
|
|
|
bool anyMonsterInAttackRange = false;
|
|
bool anyMonsterInAttackRange = false;
|
|
|
- float closestMonsterDistance = float.MaxValue;
|
|
|
|
|
|
|
|
|
|
if (frontRow.Count > 0)
|
|
if (frontRow.Count > 0)
|
|
|
{
|
|
{
|
|
@@ -295,34 +262,25 @@ private IEnumerator DelayedStart()
|
|
|
{
|
|
{
|
|
|
float monsterToPlayerDist = Vector3.Distance(monster.transform.position, player.position);
|
|
float monsterToPlayerDist = Vector3.Distance(monster.transform.position, player.position);
|
|
|
|
|
|
|
|
- if (monsterToPlayerDist < closestMonsterDistance)
|
|
|
|
|
- {
|
|
|
|
|
- closestMonsterDistance = monsterToPlayerDist;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
if (monsterToPlayerDist <= effectiveAttackRange)
|
|
if (monsterToPlayerDist <= effectiveAttackRange)
|
|
|
{
|
|
{
|
|
|
anyMonsterInAttackRange = true;
|
|
anyMonsterInAttackRange = true;
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- Debug.LogWarning("[MonsterGroup] Update: No front row monsters available!");
|
|
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (anyMonsterInAttackRange)
|
|
if (anyMonsterInAttackRange)
|
|
|
{
|
|
{
|
|
|
- // Monsters are close enough to attack
|
|
|
|
|
- Debug.Log($"[MonsterGroup] Update: Monsters in attack range (closest: {closestMonsterDistance:F1}m), starting attack loop");
|
|
|
|
|
attackLoopCoroutine = StartCoroutine(LoopAttack());
|
|
attackLoopCoroutine = StartCoroutine(LoopAttack());
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- // No monsters in attack range, should chase player
|
|
|
|
|
- Debug.Log($"[MonsterGroup] Update: Monsters out of attack range (closest: {closestMonsterDistance:F1}m), starting chase");
|
|
|
|
|
StartChase();
|
|
StartChase();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -335,68 +293,42 @@ private IEnumerator DelayedStart()
|
|
|
|
|
|
|
|
IEnumerator LoopAttack()
|
|
IEnumerator LoopAttack()
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] Attack loop started");
|
|
|
|
|
-
|
|
|
|
|
while (true)
|
|
while (true)
|
|
|
{
|
|
{
|
|
|
- // Check if game manager says player is dead (prevents attacks during death sequence)
|
|
|
|
|
if (GameManager.Instance != null && GameManager.Instance.IsPlayerDead())
|
|
if (GameManager.Instance != null && GameManager.Instance.IsPlayerDead())
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] Player is dead, stopping attack");
|
|
|
|
|
attackLoopCoroutine = null;
|
|
attackLoopCoroutine = null;
|
|
|
yield break;
|
|
yield break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Check if player left detection zone completely
|
|
|
|
|
if (!hasDetectedPlayer)
|
|
if (!hasDetectedPlayer)
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] Player left detection zone, stopping attack");
|
|
|
|
|
attackLoopCoroutine = null;
|
|
attackLoopCoroutine = null;
|
|
|
yield break;
|
|
yield break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Check if any party members are still alive
|
|
|
|
|
if (cohesionManager == null || cohesionManager.groupMembers.Count == 0)
|
|
if (cohesionManager == null || cohesionManager.groupMembers.Count == 0)
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] No party members alive, stopping attack");
|
|
|
|
|
attackLoopCoroutine = null;
|
|
attackLoopCoroutine = null;
|
|
|
yield break;
|
|
yield break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Check if any monsters are still alive
|
|
|
|
|
if (frontRow.Count == 0 && backRow.Count == 0)
|
|
if (frontRow.Count == 0 && backRow.Count == 0)
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] All monsters dead, stopping attack");
|
|
|
|
|
attackLoopCoroutine = null;
|
|
attackLoopCoroutine = null;
|
|
|
yield break;
|
|
yield break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Check if any monster is in attack range
|
|
|
|
|
bool anyInRange = frontRow.Any(monster =>
|
|
bool anyInRange = frontRow.Any(monster =>
|
|
|
monster != null && Vector3.Distance(monster.transform.position, player.position) <= effectiveAttackRange);
|
|
monster != null && Vector3.Distance(monster.transform.position, player.position) <= effectiveAttackRange);
|
|
|
|
|
|
|
|
if (!anyInRange)
|
|
if (!anyInRange)
|
|
|
{
|
|
{
|
|
|
- Debug.Log("[MonsterGroup] Player moved out of attack range - stopping attack loop");
|
|
|
|
|
attackLoopCoroutine = null;
|
|
attackLoopCoroutine = null;
|
|
|
-
|
|
|
|
|
- // Log state for debugging
|
|
|
|
|
- Debug.Log($"[MonsterGroup] State after attack stop: hasDetectedPlayer={hasDetectedPlayer}, isChasing={isChasing}, attackLoopCoroutine={attackLoopCoroutine}");
|
|
|
|
|
-
|
|
|
|
|
- if (hasDetectedPlayer)
|
|
|
|
|
- {
|
|
|
|
|
- Debug.Log("[MonsterGroup] Player still detected - Update() will handle re-engagement");
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- Debug.Log("[MonsterGroup] Player no longer detected - will wait for re-entry");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
yield break;
|
|
yield break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Attack with each front row monster
|
|
|
|
|
- foreach (var monster in frontRow.ToList()) // ToList to avoid modification during iteration
|
|
|
|
|
|
|
+ foreach (var monster in frontRow.ToList())
|
|
|
{
|
|
{
|
|
|
if (monster == null) continue;
|
|
if (monster == null) continue;
|
|
|
|
|
|
|
@@ -411,29 +343,19 @@ private IEnumerator DelayedStart()
|
|
|
monster.StopMove();
|
|
monster.StopMove();
|
|
|
monster.FaceTarget(player.position, instant: true);
|
|
monster.FaceTarget(player.position, instant: true);
|
|
|
|
|
|
|
|
- // Verify monster is facing player (required for melee)
|
|
|
|
|
if (!monster.IsFacingTarget(player.position, 45f))
|
|
if (!monster.IsFacingTarget(player.position, 45f))
|
|
|
{
|
|
{
|
|
|
- Debug.Log($"[Combat] {monster.name} not facing player, skipping");
|
|
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
monster.Attack();
|
|
monster.Attack();
|
|
|
|
|
|
|
|
- // Find the closest character on the party grid
|
|
|
|
|
var closest = cohesionManager.groupMembers
|
|
var closest = cohesionManager.groupMembers
|
|
|
.OrderBy(charac => Vector3.Distance(monster.transform.position, new Vector3(charac.gridX, 0, charac.gridY)))
|
|
.OrderBy(charac => Vector3.Distance(monster.transform.position, new Vector3(charac.gridX, 0, charac.gridY)))
|
|
|
.FirstOrDefault();
|
|
.FirstOrDefault();
|
|
|
|
|
|
|
|
- if (closest == null)
|
|
|
|
|
- {
|
|
|
|
|
- Debug.LogWarning("[Combat] No valid target found!");
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- Debug.Log($"[Combat] Target: {closest.characterName}");
|
|
|
|
|
|
|
+ if (closest == null) continue;
|
|
|
|
|
|
|
|
- // Apply damage to the character
|
|
|
|
|
var uiController = UIUpdater.Instance?.GetUIForCharacterByName(closest.characterName);
|
|
var uiController = UIUpdater.Instance?.GetUIForCharacterByName(closest.characterName);
|
|
|
if (uiController != null)
|
|
if (uiController != null)
|
|
|
{
|
|
{
|
|
@@ -443,26 +365,18 @@ private IEnumerator DelayedStart()
|
|
|
|
|
|
|
|
uiController.UpdateHPBar();
|
|
uiController.UpdateHPBar();
|
|
|
uiController.ShowDamageOnCard(damage);
|
|
uiController.ShowDamageOnCard(damage);
|
|
|
- Debug.Log($"[Combat] {monster.name} dealt {damage} damage to {closest.characterName} ({closest.currentHP}/{closest.maxHP} HP remaining)");
|
|
|
|
|
|
|
|
|
|
- // Check if character died
|
|
|
|
|
if (closest.currentHP <= 0)
|
|
if (closest.currentHP <= 0)
|
|
|
{
|
|
{
|
|
|
- Debug.Log($"[Combat] {closest.characterName} has been defeated!");
|
|
|
|
|
uiController.HandleCharacterDeath();
|
|
uiController.HandleCharacterDeath();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- Debug.LogWarning($"[Combat] UI not found for {closest.characterName}");
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
yield return new WaitForSeconds(attackInterval);
|
|
yield return new WaitForSeconds(attackInterval);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
yield return new WaitForSeconds(attackRepeatDelay);
|
|
yield return new WaitForSeconds(attackRepeatDelay);
|
|
|
- Debug.Log("[MonsterGroup] Starting next attack round...");
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|