using UnityEngine; using System.Collections.Generic; using System.Collections; /// /// Manages the execution of battle actions and coordinates with existing systems /// public class BattleActionSystem : MonoBehaviour { [Header("References")] public BattleActionWheel actionWheel; [Header("Item System")] public BattleItemSelector itemSelectionUI; [Header("Spell System")] public SpellSelectionUI spellSelectionUI; [Header("Settings")] public LayerMask enemyLayerMask = 1 << 10; public LayerMask playerLayerMask = 1 << 9; public LayerMask groundLayerMask = 1 << 0; private Character currentCharacter; private EnhancedCharacterActionData pendingAction; private bool isWaitingForTarget = false; private Camera mainCamera; // Events public event System.Action OnActionCompleted; public event System.Action OnActionStarted; void Awake() { mainCamera = Camera.main; // Find or create action wheel if (actionWheel == null) actionWheel = FindFirstObjectByType(); } void Start() { // Subscribe to action wheel events if (actionWheel != null) { actionWheel.OnActionSelected += OnActionTypeSelected; actionWheel.OnWheelClosed += OnActionWheelClosed; } // Subscribe to item/spell selection events if (itemSelectionUI != null) { itemSelectionUI.OnItemSelected += OnItemSelected; itemSelectionUI.OnSelectionCancelled += OnItemSelectionCancelled; } if (spellSelectionUI != null) { spellSelectionUI.OnSpellSelected += OnSpellSelected; spellSelectionUI.OnSelectionCancelled += OnSpellSelectionCancelled; } } void Update() { if (isWaitingForTarget) { HandleTargetSelection(); } } /// /// Shows the action wheel for a character /// public void ShowActionWheel(Character character) { currentCharacter = character; if (actionWheel != null) { Vector3 wheelPosition = character.transform.position + Vector3.up * 2f; actionWheel.ShowWheel(character, wheelPosition); } else { Debug.LogError("BattleActionSystem: No action wheel assigned!"); } } /// /// Hides the action wheel /// public void HideActionWheel() { if (actionWheel != null) { actionWheel.HideWheel(); } } /// /// Executes the character's selected action /// public void ExecuteCharacterAction(Character character) { if (character == null) { Debug.LogWarning("BattleActionSystem: Invalid character"); return; } var actionData = character.GetEnhancedActionData(); if (actionData == null) { Debug.LogWarning($"BattleActionSystem: Character {character.CharacterName} has no enhanced action data"); return; } if (!actionData.hasValidAction) { Debug.LogWarning($"BattleActionSystem: Character {character.CharacterName} has no valid action"); return; } OnActionStarted?.Invoke(character, actionData.actionType); StartCoroutine(ExecuteActionCoroutine(character, actionData)); } private IEnumerator ExecuteActionCoroutine(Character character, EnhancedCharacterActionData actionData) { switch (actionData.actionType) { case BattleActionType.Move: yield return ExecuteMoveAction(character, actionData); break; case BattleActionType.Attack: yield return ExecuteAttackAction(character, actionData); break; case BattleActionType.UseItem: yield return ExecuteItemAction(character, actionData); break; case BattleActionType.CastSpell: yield return ExecuteSpellAction(character, actionData); break; case BattleActionType.Defend: yield return ExecuteDefendAction(character, actionData); break; case BattleActionType.Wait: yield return ExecuteWaitAction(character, actionData); break; case BattleActionType.RunAway: yield return ExecuteRunAwayAction(character, actionData); break; } actionData.state = ActionDecisionState.ActionExecuted; OnActionCompleted?.Invoke(character); } #region Action Execution Methods private IEnumerator ExecuteMoveAction(Character character, EnhancedCharacterActionData actionData) { // Use existing movement system or implement new one character.transform.position = actionData.targetPosition; yield return new WaitForSeconds(0.5f); // Animation time } private IEnumerator ExecuteAttackAction(Character character, EnhancedCharacterActionData actionData) { if (actionData.targetEnemy == null) { Debug.LogWarning($"Attack action for {character.CharacterName} has no target!"); yield break; } // Use existing attack system Character targetCharacter = actionData.targetEnemy.GetComponent(); if (targetCharacter != null) { character.AttackTarget(targetCharacter); } yield return new WaitForSeconds(1f); // Attack animation time } private IEnumerator ExecuteItemAction(Character character, EnhancedCharacterActionData actionData) { // Placeholder item usage logic yield return UseItem(character, actionData.selectedItemName, actionData.selectedItemIndex, actionData.targetCharacter); yield return new WaitForSeconds(0.8f); } private IEnumerator ExecuteSpellAction(Character character, EnhancedCharacterActionData actionData) { // Placeholder spell casting logic yield return CastSpell(character, actionData.selectedSpellName, actionData.targetCharacter, actionData.targetPosition); yield return new WaitForSeconds(1.2f); } private IEnumerator ExecuteDefendAction(Character character, EnhancedCharacterActionData actionData) { // Apply defend buff (reduce incoming damage, increase AC, etc.) ApplyDefendBuff(character); yield return new WaitForSeconds(0.3f); } private IEnumerator ExecuteWaitAction(Character character, EnhancedCharacterActionData actionData) { // Character does nothing but maintains position yield return new WaitForSeconds(0.1f); } private IEnumerator ExecuteRunAwayAction(Character character, EnhancedCharacterActionData actionData) { // Move character away from enemies or off battlefield yield return HandleRunAway(character); yield return new WaitForSeconds(1f); } #endregion #region Event Handlers private void OnActionTypeSelected(BattleActionType actionType) { if (currentCharacter == null) return; // Initialize enhanced action data if needed var actionData = currentCharacter.GetEnhancedActionData(); if (actionData == null) { actionData = new EnhancedCharacterActionData(); currentCharacter.SetEnhancedActionData(actionData); } switch (actionType) { case BattleActionType.Move: StartTargetSelectionForMove(); break; case BattleActionType.Attack: StartTargetSelectionForAttack(); break; case BattleActionType.UseItem: ShowItemSelection(); break; case BattleActionType.CastSpell: ShowSpellSelection(); break; case BattleActionType.Defend: actionData.SetDefendAction(); CompleteActionSelection(); break; case BattleActionType.Wait: actionData.SetWaitAction(); CompleteActionSelection(); break; case BattleActionType.RunAway: actionData.SetRunAwayAction(); CompleteActionSelection(); break; } } private void OnActionWheelClosed() { if (!isWaitingForTarget) { CancelActionSelection(); } } private void OnItemSelected(string itemName, int itemIndex) { var actionData = currentCharacter?.GetEnhancedActionData(); if (actionData == null) return; // Determine if item requires targeting bool requiresTarget = DoesItemRequireTarget(itemName); actionData.SetItemAction(itemName, itemIndex, requiresTarget); if (requiresTarget) { StartTargetSelectionForItem(); } else { CompleteActionSelection(); } } private void OnItemSelectionCancelled() { CancelActionSelection(); } private void OnSpellSelected(string spellName) { var actionData = currentCharacter?.GetEnhancedActionData(); if (actionData == null) return; // Determine spell properties var spellInfo = GetSpellInfo(spellName); actionData.SetSpellAction(spellName, spellInfo.requiresTarget, spellInfo.isAoE, spellInfo.aoeRadius); if (spellInfo.requiresTarget) { StartTargetSelectionForSpell(); } else { CompleteActionSelection(); } } private void OnSpellSelectionCancelled() { CancelActionSelection(); } #endregion #region Target Selection private void StartTargetSelectionForMove() { pendingAction = currentCharacter.GetEnhancedActionData(); isWaitingForTarget = true; // Show move cursor or indicators } private void StartTargetSelectionForAttack() { pendingAction = currentCharacter.GetEnhancedActionData(); isWaitingForTarget = true; // Show attack cursor or highlight enemies } private void StartTargetSelectionForItem() { pendingAction = currentCharacter.GetEnhancedActionData(); isWaitingForTarget = true; } private void StartTargetSelectionForSpell() { pendingAction = currentCharacter.GetEnhancedActionData(); isWaitingForTarget = true; } private void HandleTargetSelection() { if (Input.GetMouseButtonDown(0)) { Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition); RaycastHit hit; // Check for character targets if (Physics.Raycast(ray, out hit, Mathf.Infinity, enemyLayerMask | playerLayerMask)) { Character targetCharacter = hit.collider.GetComponent(); if (targetCharacter != null) { SetCharacterTarget(targetCharacter); return; } } // Check for ground/position targets if (Physics.Raycast(ray, out hit, Mathf.Infinity, groundLayerMask)) { SetPositionTarget(hit.point); return; } } // Cancel targeting with right click or escape if (Input.GetMouseButtonDown(1) || Input.GetKeyDown(KeyCode.Escape)) { CancelTargetSelection(); } } private void SetCharacterTarget(Character target) { if (pendingAction == null) return; if (pendingAction.actionType == BattleActionType.Attack && target.CompareTag("Enemy")) { pendingAction.SetTarget(target.gameObject); CompleteActionSelection(); } else if (pendingAction.actionType == BattleActionType.UseItem || pendingAction.actionType == BattleActionType.CastSpell) { pendingAction.SetTarget(target); CompleteActionSelection(); } } private void SetPositionTarget(Vector3 position) { if (pendingAction == null) return; if (pendingAction.actionType == BattleActionType.Move) { pendingAction.SetMoveAction(position); CompleteActionSelection(); } else if (pendingAction.actionType == BattleActionType.CastSpell && pendingAction.isAreaOfEffect) { pendingAction.SetTarget(position); CompleteActionSelection(); } } private void CancelTargetSelection() { isWaitingForTarget = false; pendingAction = null; CancelActionSelection(); } #endregion #region Helper Methods private void CompleteActionSelection() { isWaitingForTarget = false; pendingAction = null; if (currentCharacter != null) { currentCharacter.SetVisualState(ActionDecisionState.ActionSelected); var actionData = currentCharacter.GetEnhancedActionData(); } } private void CancelActionSelection() { isWaitingForTarget = false; pendingAction = null; if (currentCharacter != null) { var actionData = currentCharacter.GetEnhancedActionData(); if (actionData != null) actionData.Reset(); currentCharacter.SetVisualState(ActionDecisionState.NoAction); } currentCharacter = null; } private void ShowItemSelection() { if (itemSelectionUI != null) { itemSelectionUI.ShowItemSelection(currentCharacter); } else { Debug.LogWarning("No ItemSelectionUI found - creating placeholder item action"); // Placeholder: auto-select a health potion OnItemSelected("Health Potion", 0); } } private void ShowSpellSelection() { if (spellSelectionUI != null) { spellSelectionUI.ShowSpellSelection(currentCharacter); } else { Debug.LogWarning("No SpellSelectionUI found - creating placeholder spell action"); // Placeholder: auto-select a basic spell OnSpellSelected("Magic Missile"); } } private bool DoesItemRequireTarget(string itemName) { // Placeholder logic - determine if item needs a target return itemName.ToLower().Contains("heal") || itemName.ToLower().Contains("buff") || itemName.ToLower().Contains("restore"); } private (bool requiresTarget, bool isAoE, float aoeRadius) GetSpellInfo(string spellName) { // Placeholder spell database switch (spellName.ToLower()) { case "magic missile": return (true, false, 0f); case "heal": return (true, false, 0f); case "fireball": return (true, true, 3f); case "shield": return (false, false, 0f); default: return (true, false, 0f); } } private IEnumerator UseItem(Character user, string itemName, int itemIndex, Character target) { // Try to find and use the actual item from inventory bool itemConsumed = false; var inventory = user.GetComponent(); if (inventory != null) { // Try to find the item in the inventory var miscItems = inventory.Miscellaneous; foreach (var slot in miscItems) { if (slot.item != null && slot.item.itemName == itemName && slot.quantity > 0) { if (slot.item is MiscellaneousItem miscItem && miscItem.isConsumable) { // Use the item effect Character effectTarget = target ?? user; miscItem.UseItem(effectTarget); // Remove one from inventory inventory.RemoveItem(slot.item, 1); itemConsumed = true; break; } } } } // If no ScriptableObject item found, try CombatDataTransfer session data if (!itemConsumed && CombatDataTransfer.HasValidSession()) { var session = CombatDataTransfer.GetCurrentSession(); var playerData = session.playerTeam.Find(p => p.characterName == user.CharacterName || user.CharacterName.StartsWith(p.characterName)); if (playerData != null && playerData.miscItems != null) { // Remove item from session data for (int i = 0; i < playerData.miscItems.Count; i++) { if (playerData.miscItems[i] == itemName) { playerData.miscItems.RemoveAt(i); itemConsumed = true; // Apply basic effects based on item name Character effectTarget = target ?? user; ApplyItemEffectByName(itemName, effectTarget); break; } } } } // Fallback - basic effects without consumption if (!itemConsumed) { Debug.LogWarning($"📦 Could not find consumable item {itemName} in {user.CharacterName}'s inventory - applying basic effect"); Character effectTarget = target ?? user; ApplyItemEffectByName(itemName, effectTarget); } yield return null; } /// /// Apply item effects based on item name (fallback method) /// private void ApplyItemEffectByName(string itemName, Character target) { string lowerName = itemName.ToLower(); if (lowerName.Contains("heal") || lowerName.Contains("potion")) { target.Heal(20); // Standard healing amount } else if (lowerName.Contains("antidote")) { // Could add poison removal here if implemented target.Heal(5); // Minor healing from antidote } else if (lowerName.Contains("bread") || lowerName.Contains("food")) { target.Heal(10); // Minor healing from food } else { // Generic beneficial effect target.Heal(15); } } private IEnumerator CastSpell(Character caster, string spellName, Character target, Vector3 targetPosition) { // Placeholder spell effects switch (spellName.ToLower()) { case "magic missile": if (target != null) { target.TakeDamage(15); } break; case "heal": if (target != null) { target.Heal(25); } break; case "fireball": // AoE damage around target position break; } yield return null; } private void ApplyDefendBuff(Character character) { // Placeholder: apply defensive buff // TODO: Implement actual defensive bonuses } private IEnumerator HandleRunAway(Character character) { // Placeholder: move character away from combat Vector3 runDirection = -character.transform.forward; Vector3 runTarget = character.transform.position + runDirection * 5f; character.transform.position = runTarget; yield return null; } #endregion }