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
}