BattleActionIntegration.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. using UnityEngine;
  2. using UnityEngine.UIElements;
  3. /// <summary>
  4. /// Integration script that connects the new battle action system with existing character selection
  5. /// This allows switching between the old click-drag system and the new action wheel system
  6. /// </summary>
  7. public class BattleActionIntegration : MonoBehaviour
  8. {
  9. [Header("System References")]
  10. public PlayerDecisionController playerDecisionController;
  11. public BattleActionSystem battleActionSystem;
  12. public BattleActionWheel actionWheel; // Legacy Canvas-based wheel
  13. public EnemySelectionUI enemySelectionUI; // TODO: Add after compilation
  14. public BattleItemSelector itemSelectionUI;
  15. [Header("Settings")]
  16. [Tooltip("Enable new action wheel system (false = use old click-drag system)")]
  17. public bool useNewActionSystem = false; // Changed to false by default for simpler testing
  18. [Space]
  19. [Tooltip("Press this key to toggle between action systems")]
  20. public KeyCode toggleSystemKey = KeyCode.T;
  21. private Character lastSelectedCharacter;
  22. private MonoBehaviour simpleWheelComponent;
  23. private string currentInstruction = "";
  24. private float instructionTimer = 0f;
  25. private float instructionDuration = 5f;
  26. void Start()
  27. {
  28. // FORCE useNewActionSystem to false to preserve drag functionality
  29. useNewActionSystem = false;
  30. // Find components if not assigned
  31. if (playerDecisionController == null)
  32. playerDecisionController = FindFirstObjectByType<PlayerDecisionController>();
  33. if (battleActionSystem == null)
  34. battleActionSystem = FindFirstObjectByType<BattleActionSystem>();
  35. if (actionWheel == null)
  36. actionWheel = FindFirstObjectByType<BattleActionWheel>();
  37. if (enemySelectionUI == null)
  38. enemySelectionUI = FindFirstObjectByType<EnemySelectionUI>();
  39. if (itemSelectionUI == null)
  40. itemSelectionUI = FindFirstObjectByType<BattleItemSelector>();
  41. // Ensure PlayerDecisionController is always enabled for drag functionality
  42. if (playerDecisionController != null)
  43. {
  44. playerDecisionController.enabled = true;
  45. playerDecisionController.SetEnabled(true);
  46. }
  47. // Try to find or create a simple wheel component
  48. var existingWheels = FindObjectsByType<MonoBehaviour>(FindObjectsSortMode.None);
  49. foreach (var comp in existingWheels)
  50. {
  51. if (comp.GetType().Name == "SimpleActionWheel")
  52. {
  53. simpleWheelComponent = comp;
  54. break;
  55. }
  56. }
  57. if (simpleWheelComponent == null)
  58. {
  59. // Create simple wheel if it doesn't exist
  60. GameObject wheelObj = new GameObject("SimpleActionWheel");
  61. // Use reflection to add the component
  62. var componentType = System.Type.GetType("SimpleActionWheel");
  63. if (componentType != null)
  64. {
  65. simpleWheelComponent = wheelObj.AddComponent(componentType) as MonoBehaviour;
  66. }
  67. else
  68. {
  69. Debug.LogError("❌ Could not find SimpleActionWheel type");
  70. }
  71. }
  72. // Subscribe to events
  73. if (battleActionSystem != null)
  74. {
  75. battleActionSystem.OnActionCompleted += OnCharacterActionCompleted;
  76. }
  77. // Connect SimpleActionWheel events using reflection
  78. if (simpleWheelComponent != null)
  79. {
  80. ConnectSimpleWheelEvents();
  81. }
  82. }
  83. void Update()
  84. {
  85. // Allow toggling between systems
  86. if (Input.GetKeyDown(toggleSystemKey))
  87. {
  88. ToggleActionSystem();
  89. }
  90. // Handle action wheel key from SimpleActionWheel
  91. // Get the key from SimpleActionWheel component if available
  92. KeyCode wheelKey = KeyCode.Q; // Default fallback
  93. if (simpleWheelComponent != null)
  94. {
  95. var toggleKeyField = simpleWheelComponent.GetType().GetField("toggleKey");
  96. if (toggleKeyField != null)
  97. {
  98. wheelKey = (KeyCode)toggleKeyField.GetValue(simpleWheelComponent);
  99. }
  100. }
  101. if (Input.GetKeyDown(wheelKey))
  102. {
  103. // Clear any existing instruction when opening wheel
  104. currentInstruction = "";
  105. instructionTimer = 0f;
  106. // When using old system, get the selected character from PlayerDecisionController
  107. Character characterForWheel = lastSelectedCharacter;
  108. if (!useNewActionSystem && playerDecisionController != null)
  109. {
  110. Character currentlySelected = playerDecisionController.GetSelectedCharacter();
  111. if (currentlySelected != null)
  112. {
  113. characterForWheel = currentlySelected;
  114. lastSelectedCharacter = currentlySelected; // Update for consistency
  115. }
  116. }
  117. if (characterForWheel != null)
  118. {
  119. // Allow reopening the action wheel even if an action is already selected
  120. // This enables canceling/changing the selected action
  121. ShowActionWheelForCharacter(characterForWheel);
  122. }
  123. }
  124. if (useNewActionSystem)
  125. {
  126. HandleNewActionSystemInput();
  127. }
  128. else
  129. {
  130. // When using old system, track character selection for action wheel
  131. // Monitor PlayerDecisionController's targeting state to update lastSelectedCharacter
  132. if (playerDecisionController != null && playerDecisionController.IsInTargetingMode)
  133. {
  134. Character currentlySelected = playerDecisionController.GetSelectedCharacter();
  135. if (currentlySelected != null && currentlySelected != lastSelectedCharacter)
  136. {
  137. lastSelectedCharacter = currentlySelected;
  138. // Clear any old instructions and show current action status
  139. ShowCharacterActionStatus(currentlySelected);
  140. }
  141. }
  142. }
  143. // Note: When useNewActionSystem is false, the old PlayerDecisionController.Update()
  144. // will handle input automatically - no need to interfere
  145. // Update instruction timer
  146. if (instructionTimer > 0f)
  147. {
  148. instructionTimer -= Time.deltaTime;
  149. if (instructionTimer <= 0f)
  150. {
  151. currentInstruction = "";
  152. }
  153. }
  154. }
  155. /// <summary>
  156. /// Get the action wheel key from SimpleActionWheel component
  157. /// </summary>
  158. private KeyCode GetActionWheelKey()
  159. {
  160. if (simpleWheelComponent != null)
  161. {
  162. var toggleKeyField = simpleWheelComponent.GetType().GetField("toggleKey");
  163. if (toggleKeyField != null)
  164. {
  165. return (KeyCode)toggleKeyField.GetValue(simpleWheelComponent);
  166. }
  167. }
  168. return KeyCode.Q; // Default fallback
  169. }
  170. void OnGUI()
  171. {
  172. // Show instruction message if active
  173. if (!string.IsNullOrEmpty(currentInstruction))
  174. {
  175. GUIStyle instructionStyle = new GUIStyle(GUI.skin.label);
  176. instructionStyle.fontSize = 18;
  177. instructionStyle.fontStyle = FontStyle.Bold;
  178. instructionStyle.alignment = TextAnchor.MiddleCenter;
  179. instructionStyle.normal.textColor = Color.yellow;
  180. Rect instructionRect = new Rect(0, 50, Screen.width, 30);
  181. // Background
  182. GUI.color = new Color(0, 0, 0, 0.7f);
  183. GUI.Box(instructionRect, "");
  184. // Text
  185. GUI.color = Color.white;
  186. GUI.Label(instructionRect, currentInstruction, instructionStyle);
  187. }
  188. // Simple UI for testing - show regardless of system mode
  189. GUILayout.BeginArea(new Rect(10, 10, 300, 250));
  190. GUILayout.Label($"Battle Action System (Mode: {(useNewActionSystem ? "New" : "Old")})");
  191. GUILayout.Label($"Action Key: {GetActionWheelKey()}");
  192. GUILayout.Label($"Simple Wheel: {(simpleWheelComponent != null ? "✅" : "❌")}");
  193. if (lastSelectedCharacter != null)
  194. {
  195. GUILayout.Label($"Selected: {lastSelectedCharacter.CharacterName}");
  196. var actionData = lastSelectedCharacter.GetEnhancedActionData<EnhancedCharacterActionData>();
  197. if (actionData != null && actionData.hasValidAction)
  198. {
  199. GUILayout.Label($"Action: {actionData.GetActionDescription()}");
  200. GUILayout.Label($"Press {GetActionWheelKey()} again to change action", GUI.skin.box);
  201. }
  202. else
  203. {
  204. GUILayout.Label($"Press {GetActionWheelKey()} to choose action");
  205. }
  206. }
  207. else
  208. {
  209. GUILayout.Label("No character selected");
  210. GUILayout.Label("Click a player character to select");
  211. }
  212. GUILayout.Label($"Press {GetActionWheelKey()} to show action wheel");
  213. if (GUILayout.Button("Test Action Wheel"))
  214. {
  215. var testCharacter = FindFirstObjectByType<Character>();
  216. if (testCharacter != null)
  217. {
  218. ShowActionWheelForCharacter(testCharacter);
  219. }
  220. }
  221. if (GUILayout.Button("Reset PlayerDecisionController"))
  222. {
  223. if (playerDecisionController != null)
  224. {
  225. playerDecisionController.ResetState();
  226. }
  227. }
  228. GUILayout.EndArea();
  229. }
  230. private void HandleNewActionSystemInput()
  231. {
  232. // Don't interfere with mouse input if PlayerDecisionController is in targeting mode
  233. if (playerDecisionController != null && playerDecisionController.IsInTargetingMode)
  234. {
  235. // Let PlayerDecisionController handle the input for targeting
  236. return;
  237. }
  238. // Check for character selection
  239. if (Input.GetMouseButtonDown(0))
  240. {
  241. Character selectedCharacter = GetCharacterAtMousePosition();
  242. if (selectedCharacter != null)
  243. {
  244. if (selectedCharacter.CompareTag("Player"))
  245. {
  246. SelectCharacterForAction(selectedCharacter);
  247. }
  248. else
  249. {
  250. SelectCharacterForAction(selectedCharacter);
  251. }
  252. }
  253. }
  254. }
  255. private Character GetCharacterAtMousePosition()
  256. {
  257. Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  258. RaycastHit hit;
  259. if (Physics.Raycast(ray, out hit))
  260. {
  261. return hit.collider.GetComponent<Character>();
  262. }
  263. return null;
  264. }
  265. private void SelectCharacterForAction(Character character)
  266. {
  267. // Only clear visual state of previous selection if they don't have an action
  268. if (lastSelectedCharacter != null)
  269. {
  270. var prevActionData = lastSelectedCharacter.GetEnhancedActionData<EnhancedCharacterActionData>();
  271. if (prevActionData == null || !prevActionData.hasValidAction)
  272. {
  273. // Only reset to NoAction if they don't have a valid action
  274. lastSelectedCharacter.SetVisualState(ActionDecisionState.NoAction);
  275. }
  276. else
  277. {
  278. // Preserve their action state
  279. lastSelectedCharacter.SetVisualState(ActionDecisionState.ActionSelected);
  280. }
  281. }
  282. lastSelectedCharacter = character;
  283. // Initialize enhanced action data if needed
  284. var actionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  285. if (actionData == null)
  286. {
  287. // Create instance at runtime to avoid compilation issues
  288. actionData = new EnhancedCharacterActionData();
  289. character.SetEnhancedActionData(actionData);
  290. }
  291. // Highlight selected character (use a different state for "currently selected")
  292. character.SetVisualState(ActionDecisionState.NoAction);
  293. // Update all character visual states to maintain proper color coding
  294. UpdateAllCharacterVisualStates();
  295. }
  296. /// <summary>
  297. /// Update visual states for all characters to properly show action status
  298. /// </summary>
  299. private void UpdateAllCharacterVisualStates()
  300. {
  301. Character[] allCharacters = FindObjectsByType<Character>(FindObjectsSortMode.None);
  302. foreach (Character character in allCharacters)
  303. {
  304. if (character.CompareTag("Player"))
  305. {
  306. var actionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  307. if (character == lastSelectedCharacter)
  308. {
  309. // Currently selected character - show selection highlight
  310. character.SetVisualState(ActionDecisionState.NoAction); // Pink for selection
  311. }
  312. else if (actionData != null && actionData.hasValidAction)
  313. {
  314. // Has valid action selected - show action confirmed state
  315. character.SetVisualState(ActionDecisionState.ActionSelected); // Green for confirmed action
  316. }
  317. else
  318. {
  319. // No action selected
  320. character.SetVisualState(ActionDecisionState.NoAction); // Pink for no action
  321. }
  322. }
  323. }
  324. }
  325. private void ShowActionWheelForCharacter(Character character)
  326. {
  327. // Clear any existing instruction when showing the wheel
  328. currentInstruction = "";
  329. instructionTimer = 0f;
  330. // Reset PlayerDecisionController state to ensure clean state
  331. if (playerDecisionController != null)
  332. {
  333. playerDecisionController.ResetState();
  334. }
  335. // Reset any existing action for this character to allow changing selection
  336. var existingActionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  337. if (existingActionData != null && existingActionData.hasValidAction)
  338. {
  339. existingActionData.Reset();
  340. character.SetVisualState(ActionDecisionState.NoAction);
  341. }
  342. // Try simple wheel first
  343. if (simpleWheelComponent != null)
  344. {
  345. // Use reflection to call ShowWheelForCharacter
  346. var method = simpleWheelComponent.GetType().GetMethod("ShowWheelForCharacter");
  347. if (method != null)
  348. {
  349. method.Invoke(simpleWheelComponent, new object[] { character });
  350. return;
  351. }
  352. }
  353. // Fallback to battle action system
  354. if (battleActionSystem != null)
  355. {
  356. battleActionSystem.ShowActionWheel(character);
  357. }
  358. }
  359. private void ConnectSimpleWheelEvents()
  360. {
  361. if (simpleWheelComponent == null)
  362. {
  363. Debug.LogError("❌ simpleWheelComponent is null in ConnectSimpleWheelEvents");
  364. return;
  365. }
  366. // Use reflection to connect to OnActionSelected event
  367. var eventInfo = simpleWheelComponent.GetType().GetEvent("OnActionSelected");
  368. if (eventInfo != null)
  369. {
  370. // Create delegate that matches the event signature: Action<BattleActionType>
  371. var delegateType = eventInfo.EventHandlerType;
  372. var methodInfo = this.GetType().GetMethod("OnActionSelected", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
  373. if (methodInfo != null)
  374. {
  375. var handler = System.Delegate.CreateDelegate(delegateType, this, methodInfo);
  376. eventInfo.AddEventHandler(simpleWheelComponent, handler);
  377. }
  378. }
  379. else
  380. {
  381. Debug.LogError("❌ Could not find OnActionSelected event in SimpleActionWheel");
  382. }
  383. }
  384. private void OnActionSelected(BattleActionType actionType)
  385. {
  386. if (lastSelectedCharacter == null)
  387. {
  388. Debug.LogWarning("❌ Action selected but no character selected!");
  389. return;
  390. }
  391. // Set action data for the character
  392. var actionData = lastSelectedCharacter.GetEnhancedActionData<EnhancedCharacterActionData>();
  393. if (actionData == null)
  394. {
  395. actionData = new EnhancedCharacterActionData();
  396. lastSelectedCharacter.SetEnhancedActionData(actionData);
  397. }
  398. // Configure action based on type and enable targeting mode
  399. switch (actionType)
  400. {
  401. case BattleActionType.Attack:
  402. actionData.actionType = actionType;
  403. ShowInstructionMessage("ATTACK: Drag from character to enemy");
  404. StartTargetingMode(lastSelectedCharacter, actionType);
  405. break;
  406. case BattleActionType.Move:
  407. actionData.actionType = actionType;
  408. ShowInstructionMessage("MOVE: Drag from character to target position");
  409. StartTargetingMode(lastSelectedCharacter, actionType);
  410. break;
  411. case BattleActionType.UseItem:
  412. actionData.actionType = actionType;
  413. ShowInstructionMessage("USE ITEM: Select item from list");
  414. ShowItemSelection(lastSelectedCharacter);
  415. break;
  416. case BattleActionType.CastSpell:
  417. actionData.actionType = actionType;
  418. actionData.state = ActionDecisionState.ActionSelected;
  419. lastSelectedCharacter.SetVisualState(ActionDecisionState.ActionSelected);
  420. break;
  421. case BattleActionType.Defend:
  422. actionData.actionType = actionType;
  423. actionData.state = ActionDecisionState.ActionSelected;
  424. lastSelectedCharacter.SetVisualState(ActionDecisionState.ActionSelected);
  425. break;
  426. case BattleActionType.RunAway:
  427. actionData.actionType = actionType;
  428. actionData.state = ActionDecisionState.ActionSelected;
  429. lastSelectedCharacter.SetVisualState(ActionDecisionState.ActionSelected);
  430. break;
  431. }
  432. // Update all character visual states to show proper action status
  433. UpdateAllCharacterVisualStates();
  434. }
  435. private void StartTargetingMode(Character character, BattleActionType actionType)
  436. {
  437. // Enable the PlayerDecisionController to handle targeting
  438. if (playerDecisionController != null)
  439. {
  440. // Use the new public method to start targeting
  441. playerDecisionController.StartTargetingForCharacter(character, actionType);
  442. }
  443. else
  444. {
  445. Debug.LogError("❌ PlayerDecisionController not found - cannot start targeting mode");
  446. }
  447. }
  448. private void ShowItemSelection(Character character)
  449. {
  450. if (itemSelectionUI != null)
  451. {
  452. // Subscribe to item selection events
  453. itemSelectionUI.OnItemSelected -= OnItemSelected;
  454. itemSelectionUI.OnSelectionCancelled -= OnItemSelectionCancelled;
  455. itemSelectionUI.OnItemSelected += OnItemSelected;
  456. itemSelectionUI.OnSelectionCancelled += OnItemSelectionCancelled;
  457. itemSelectionUI.ShowItemSelection(character);
  458. }
  459. else
  460. {
  461. Debug.LogError("❌ BattleItemSelector not found!");
  462. // Fallback: Complete action immediately
  463. var actionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  464. if (actionData != null)
  465. {
  466. actionData.state = ActionDecisionState.ActionSelected;
  467. character.SetVisualState(ActionDecisionState.ActionSelected);
  468. }
  469. }
  470. }
  471. private void OnItemSelected(string itemName, int itemIndex)
  472. {
  473. if (lastSelectedCharacter != null)
  474. {
  475. var actionData = lastSelectedCharacter.GetEnhancedActionData<EnhancedCharacterActionData>();
  476. if (actionData != null)
  477. {
  478. // Check if item requires targeting (healing potions, etc. might target allies)
  479. bool requiresTargeting = IsItemRequiringTargeting(itemName);
  480. // Properly set the item action using the SetItemAction method
  481. actionData.SetItemAction(itemName, itemIndex, requiresTargeting);
  482. if (!requiresTargeting)
  483. {
  484. lastSelectedCharacter.SetVisualState(ActionDecisionState.ActionSelected);
  485. // Show the updated action status
  486. ShowCharacterActionStatus(lastSelectedCharacter);
  487. }
  488. else
  489. {
  490. ShowInstructionMessage($"TARGET: Select target for {itemName}");
  491. StartTargetingMode(lastSelectedCharacter, BattleActionType.UseItem);
  492. }
  493. }
  494. }
  495. }
  496. /// <summary>
  497. /// Check if an item requires targeting (healing items, targeted attacks, etc.)
  498. /// </summary>
  499. private bool IsItemRequiringTargeting(string itemName)
  500. {
  501. // Add logic here to determine if item needs targeting
  502. // For now, assume most items are self-use (like health potions)
  503. // Healing items that can target others would return true
  504. if (itemName.ToLower().Contains("heal") && itemName.ToLower().Contains("other"))
  505. return true;
  506. if (itemName.ToLower().Contains("revive"))
  507. return true;
  508. if (itemName.ToLower().Contains("bomb") || itemName.ToLower().Contains("throw"))
  509. return true;
  510. return false; // Most items are self-use
  511. }
  512. private void OnItemSelectionCancelled()
  513. {
  514. if (lastSelectedCharacter != null)
  515. {
  516. var actionData = lastSelectedCharacter.GetEnhancedActionData<EnhancedCharacterActionData>();
  517. if (actionData != null)
  518. {
  519. actionData.Reset();
  520. lastSelectedCharacter.SetVisualState(ActionDecisionState.NoAction);
  521. }
  522. }
  523. }
  524. private void OnCharacterActionCompleted(Character character)
  525. {
  526. // Clear selection after action is complete
  527. if (character == lastSelectedCharacter)
  528. {
  529. lastSelectedCharacter = null;
  530. }
  531. }
  532. /// <summary>
  533. /// Manually trigger action selection for a character (for use by other systems)
  534. /// </summary>
  535. public void SelectCharacter(Character character)
  536. {
  537. SelectCharacterForAction(character);
  538. }
  539. /// <summary>
  540. /// Execute all selected actions (for turn-based systems)
  541. /// </summary>
  542. public void ExecuteAllPlayerActions()
  543. {
  544. Character[] playerCharacters = FindObjectsByType<Character>(FindObjectsSortMode.None);
  545. foreach (Character character in playerCharacters)
  546. {
  547. var actionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  548. if (character.CompareTag("Player") && actionData != null && actionData.hasValidAction)
  549. {
  550. if (battleActionSystem != null)
  551. {
  552. battleActionSystem.ExecuteCharacterAction(character);
  553. }
  554. }
  555. }
  556. }
  557. /// <summary>
  558. /// Switch between old and new action systems
  559. /// </summary>
  560. public void ToggleActionSystem()
  561. {
  562. useNewActionSystem = !useNewActionSystem;
  563. // Enable/disable appropriate systems
  564. if (playerDecisionController != null)
  565. {
  566. // Keep PlayerDecisionController enabled for targeting support
  567. // Just control its input handling behavior
  568. playerDecisionController.enabled = true;
  569. playerDecisionController.SetEnabled(true);
  570. }
  571. // Clear any instruction messages when switching
  572. currentInstruction = "";
  573. instructionTimer = 0f;
  574. }
  575. /// <summary>
  576. /// Check if all players have selected actions
  577. /// </summary>
  578. public bool AllPlayersHaveActions()
  579. {
  580. Character[] playerCharacters = FindObjectsByType<Character>(FindObjectsSortMode.None);
  581. foreach (Character character in playerCharacters)
  582. {
  583. if (character.CompareTag("Player"))
  584. {
  585. var actionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  586. if (actionData == null || !actionData.hasValidAction)
  587. {
  588. return false;
  589. }
  590. }
  591. }
  592. return true;
  593. }
  594. /// <summary>
  595. /// Reset all player actions (useful for new turns)
  596. /// </summary>
  597. public void ResetAllPlayerActions()
  598. {
  599. Character[] playerCharacters = FindObjectsByType<Character>(FindObjectsSortMode.None);
  600. foreach (Character character in playerCharacters)
  601. {
  602. if (character.CompareTag("Player"))
  603. {
  604. var actionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  605. if (actionData != null)
  606. actionData.Reset();
  607. character.SetVisualState(ActionDecisionState.NoAction);
  608. }
  609. }
  610. lastSelectedCharacter = null;
  611. }
  612. /// <summary>
  613. /// Cancel action for a specific character (useful for undoing individual selections)
  614. /// </summary>
  615. public void CancelCharacterAction(Character character)
  616. {
  617. if (character == null) return;
  618. var actionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  619. if (actionData != null && actionData.hasValidAction)
  620. {
  621. actionData.Reset();
  622. character.SetVisualState(ActionDecisionState.NoAction);
  623. ShowInstructionMessage($"Action canceled for {character.CharacterName}");
  624. }
  625. }
  626. private void ShowInstructionMessage(string message)
  627. {
  628. currentInstruction = message;
  629. instructionTimer = instructionDuration;
  630. }
  631. /// <summary>
  632. /// Show the current action status for a character or clear instructions if no action
  633. /// </summary>
  634. private void ShowCharacterActionStatus(Character character)
  635. {
  636. var actionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  637. if (actionData != null && actionData.hasValidAction)
  638. {
  639. // Show current action
  640. ShowInstructionMessage($"Current action: {actionData.GetActionDescription()}");
  641. }
  642. else
  643. {
  644. // Clear instructions if no action set
  645. currentInstruction = "";
  646. instructionTimer = 0f;
  647. }
  648. }
  649. /// <summary>
  650. /// Called by PlayerDecisionController when targeting is complete
  651. /// </summary>
  652. public void OnTargetingComplete(Character character)
  653. {
  654. // Update lastSelectedCharacter so action wheel knows which character was last used
  655. lastSelectedCharacter = character;
  656. // Update all character visual states to reflect the completed action
  657. UpdateAllCharacterVisualStates();
  658. // Show instruction that action is set
  659. var actionData = character.GetEnhancedActionData<EnhancedCharacterActionData>();
  660. if (actionData != null && actionData.hasValidAction)
  661. {
  662. ShowInstructionMessage($"Action set: {actionData.GetActionDescription()}");
  663. }
  664. }
  665. }