TeamOverviewController.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. using UnityEngine;
  2. using UnityEngine.UIElements;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using UnityEngine.SceneManagement;
  6. /// <summary>
  7. /// Controls the TeamOverview UI panel on the right side of the map scene.
  8. /// Displays current team information, stats, and provides navigation controls.
  9. /// Works with the main map UI document.
  10. /// </summary>
  11. public class TeamOverviewController : MonoBehaviour
  12. {
  13. [Header("Settings")]
  14. [SerializeField] public bool showDebugLogs = false;
  15. // UI Elements
  16. private VisualElement teamOverviewPanel;
  17. private ScrollView teamMembersList;
  18. private Button manageTeamButton;
  19. private Button saveGameButton;
  20. private Label memberCountLabel;
  21. private Label totalGoldLabel;
  22. private Label averageLevelLabel;
  23. private Toggle perceptionVisualizationToggle;
  24. // UI Document reference (shared with map)
  25. private UIDocument uiDocument;
  26. // Team data
  27. private List<TeamCharacter> currentTeam;
  28. void Awake()
  29. {
  30. // Get the UIDocument component from this GameObject
  31. uiDocument = GetComponent<UIDocument>();
  32. if (uiDocument == null)
  33. {
  34. Debug.LogError("❌ TeamOverviewController: No UIDocument component found on this GameObject!");
  35. }
  36. }
  37. void Start()
  38. {
  39. // Ensure GameStateManager has loaded data if it exists
  40. if (GameStateManager.Instance != null && PlayerPrefs.HasKey("GameSaved"))
  41. {
  42. GameStateManager.Instance.LoadGame();
  43. }
  44. SetupUI();
  45. LoadTeamData();
  46. ShowTeamOverview();
  47. }
  48. /// <summary>
  49. /// Sets up the UI elements and event handlers
  50. /// </summary>
  51. private void SetupUI()
  52. {
  53. if (uiDocument?.rootVisualElement == null)
  54. {
  55. Debug.LogError("❌ TeamOverviewController: UIDocument not found or has no root element!");
  56. return;
  57. }
  58. var root = uiDocument.rootVisualElement;
  59. // Find UI elements - using the correct button names from TeamOverview.uxml
  60. teamOverviewPanel = root.Q("TeamOverviewPanel");
  61. teamMembersList = root.Q<ScrollView>("TeamMembersList");
  62. manageTeamButton = root.Q<Button>("ReturnToTeamSelectButton");
  63. saveGameButton = root.Q<Button>("SaveGameButton");
  64. memberCountLabel = root.Q<Label>("MemberCountLabel");
  65. totalGoldLabel = root.Q<Label>("TotalGoldLabel");
  66. averageLevelLabel = root.Q<Label>("AverageLevelLabel");
  67. perceptionVisualizationToggle = root.Q<Toggle>("PerceptionVisualizationToggle");
  68. // Debug: Check which elements were found
  69. if (showDebugLogs)
  70. {
  71. Debug.Log($"🔍 UI Elements found:");
  72. Debug.Log($" TeamOverviewPanel: {teamOverviewPanel != null}");
  73. Debug.Log($" TeamMembersList: {teamMembersList != null}");
  74. Debug.Log($" ManageTeamButton: {manageTeamButton != null}");
  75. Debug.Log($" SaveGameButton: {saveGameButton != null}");
  76. Debug.Log($" MemberCountLabel: {memberCountLabel != null}");
  77. Debug.Log($" TotalGoldLabel: {totalGoldLabel != null}");
  78. Debug.Log($" AverageLevelLabel: {averageLevelLabel != null}");
  79. Debug.Log($" PerceptionVisualizationToggle: {perceptionVisualizationToggle != null}");
  80. }
  81. // Setup event handlers
  82. if (manageTeamButton != null)
  83. {
  84. manageTeamButton.clicked += OnManageTeamClicked;
  85. }
  86. if (saveGameButton != null)
  87. {
  88. saveGameButton.clicked += OnSaveGameClicked;
  89. }
  90. if (perceptionVisualizationToggle != null)
  91. {
  92. // Load saved toggle state
  93. bool savedState = PlayerPrefs.GetInt("ShowPerceptionVisualization", 1) == 1;
  94. perceptionVisualizationToggle.value = savedState;
  95. // Set up event handler
  96. perceptionVisualizationToggle.RegisterValueChangedCallback(OnPerceptionVisualizationToggled);
  97. // Apply initial state to visualizer
  98. UpdatePerceptionVisualizationState(savedState);
  99. }
  100. if (showDebugLogs)
  101. {
  102. Debug.Log("✅ TeamOverviewController: UI setup complete");
  103. }
  104. }
  105. /// <summary>
  106. /// Loads current team data from the save system
  107. /// </summary>
  108. private void LoadTeamData()
  109. {
  110. currentTeam = new List<TeamCharacter>();
  111. // Method 1: Try to load from MainTeamSelectScript (if in TeamSelect scene)
  112. var teamSelectScript = FindFirstObjectByType<MainTeamSelectScript>();
  113. if (teamSelectScript != null)
  114. {
  115. currentTeam = teamSelectScript.GetConfiguredCharacters();
  116. if (showDebugLogs)
  117. {
  118. Debug.Log($"📋 Loaded team from MainTeamSelectScript: {currentTeam.Count} members");
  119. }
  120. return;
  121. }
  122. // Method 2: Try to load from GameStateManager
  123. if (GameStateManager.Instance != null && GameStateManager.Instance.savedTeam != null)
  124. {
  125. foreach (var character in GameStateManager.Instance.savedTeam)
  126. {
  127. if (character != null)
  128. {
  129. currentTeam.Add(character);
  130. }
  131. }
  132. if (currentTeam.Count > 0)
  133. {
  134. if (showDebugLogs)
  135. {
  136. Debug.Log($"📋 Loaded team from GameStateManager: {currentTeam.Count} members");
  137. }
  138. return;
  139. }
  140. }
  141. // Method 3: Try to load directly from PlayerPrefs (fallback)
  142. for (int i = 0; i < 4; i++)
  143. {
  144. string prefix = $"Character{i}_";
  145. if (PlayerPrefs.HasKey(prefix + "Exists") && PlayerPrefs.GetInt(prefix + "Exists") == 1)
  146. {
  147. var character = new TeamCharacter();
  148. character.name = PlayerPrefs.GetString(prefix + "Name", "");
  149. character.isMale = PlayerPrefs.GetInt(prefix + "IsMale", 1) == 1;
  150. character.strength = PlayerPrefs.GetInt(prefix + "Strength", 10);
  151. character.dexterity = PlayerPrefs.GetInt(prefix + "Dexterity", 10);
  152. character.constitution = PlayerPrefs.GetInt(prefix + "Constitution", 10);
  153. character.wisdom = PlayerPrefs.GetInt(prefix + "Wisdom", 10);
  154. character.perception = PlayerPrefs.GetInt(prefix + "Perception", 10);
  155. character.gold = PlayerPrefs.GetInt(prefix + "Gold", 25);
  156. character.silver = PlayerPrefs.GetInt(prefix + "Silver", 0);
  157. character.copper = PlayerPrefs.GetInt(prefix + "Copper", 0);
  158. if (!string.IsNullOrEmpty(character.name))
  159. {
  160. currentTeam.Add(character);
  161. }
  162. }
  163. }
  164. if (currentTeam.Count > 0)
  165. {
  166. if (showDebugLogs)
  167. {
  168. Debug.Log($"📋 Loaded team from PlayerPrefs: {currentTeam.Count} members");
  169. }
  170. }
  171. else
  172. {
  173. if (showDebugLogs)
  174. {
  175. Debug.Log("ℹ️ No team data found - this is normal for a new game");
  176. }
  177. }
  178. } /// <summary>
  179. /// Shows the team overview panel
  180. /// </summary>
  181. public void ShowTeamOverview()
  182. {
  183. if (teamOverviewPanel == null) return;
  184. teamOverviewPanel.style.display = DisplayStyle.Flex;
  185. UpdateTeamDisplay();
  186. if (showDebugLogs)
  187. {
  188. Debug.Log("👥 TeamOverviewController: Team overview panel shown");
  189. }
  190. }
  191. /// <summary>
  192. /// Hides the team overview panel
  193. /// </summary>
  194. public void HideTeamOverview()
  195. {
  196. if (teamOverviewPanel == null) return;
  197. teamOverviewPanel.style.display = DisplayStyle.None;
  198. if (showDebugLogs)
  199. {
  200. Debug.Log("👻 TeamOverviewController: Team overview panel hidden");
  201. }
  202. }
  203. /// <summary>
  204. /// Updates the team display with current data
  205. /// </summary>
  206. private void UpdateTeamDisplay()
  207. {
  208. if (currentTeam == null)
  209. {
  210. if (showDebugLogs)
  211. {
  212. Debug.Log("⚠️ UpdateTeamDisplay: currentTeam is null");
  213. }
  214. return;
  215. }
  216. if (teamMembersList == null)
  217. {
  218. if (showDebugLogs)
  219. {
  220. Debug.Log("⚠️ UpdateTeamDisplay: teamMembersList is null - UI elements not found");
  221. }
  222. return;
  223. }
  224. if (showDebugLogs)
  225. {
  226. Debug.Log($"🎨 UpdateTeamDisplay: Updating display for {currentTeam.Count} team members");
  227. }
  228. // Clear existing team member displays
  229. teamMembersList.Clear();
  230. // Add each team member
  231. foreach (var member in currentTeam)
  232. {
  233. if (member != null)
  234. {
  235. CreateTeamMemberCard(member);
  236. if (showDebugLogs)
  237. {
  238. Debug.Log($"📋 Added card for member: {member.name}");
  239. }
  240. }
  241. }
  242. // Update team stats
  243. UpdateTeamStats();
  244. if (showDebugLogs)
  245. {
  246. Debug.Log($"✅ UpdateTeamDisplay: Display updated with {currentTeam.Count} members");
  247. }
  248. }
  249. /// <summary>
  250. /// Creates a visual card for a team member
  251. /// </summary>
  252. private void CreateTeamMemberCard(TeamCharacter member)
  253. {
  254. var memberCard = new VisualElement();
  255. memberCard.style.backgroundColor = new StyleColor(new Color(0.3f, 0.3f, 0.3f, 0.8f));
  256. memberCard.style.borderTopColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f));
  257. memberCard.style.borderBottomColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f));
  258. memberCard.style.borderLeftColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f));
  259. memberCard.style.borderRightColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f));
  260. memberCard.style.borderTopWidth = 1;
  261. memberCard.style.borderBottomWidth = 1;
  262. memberCard.style.borderLeftWidth = 1;
  263. memberCard.style.borderRightWidth = 1;
  264. memberCard.style.borderTopLeftRadius = 4;
  265. memberCard.style.borderTopRightRadius = 4;
  266. memberCard.style.borderBottomLeftRadius = 4;
  267. memberCard.style.borderBottomRightRadius = 4;
  268. memberCard.style.marginBottom = 8;
  269. memberCard.style.paddingTop = 8;
  270. memberCard.style.paddingBottom = 8;
  271. memberCard.style.paddingLeft = 8;
  272. memberCard.style.paddingRight = 8;
  273. // Member header with name and level
  274. var memberHeader = new VisualElement();
  275. memberHeader.style.flexDirection = FlexDirection.Row;
  276. memberHeader.style.justifyContent = Justify.SpaceBetween;
  277. memberHeader.style.alignItems = Align.Center;
  278. memberHeader.style.marginBottom = 5;
  279. var nameLabel = new Label(member.name);
  280. nameLabel.style.color = new StyleColor(new Color(1f, 1f, 1f));
  281. nameLabel.style.fontSize = 12;
  282. nameLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
  283. var hpLabel = new Label($"HP: {member.HitPoints} | AC: {member.ArmorClass}");
  284. hpLabel.style.color = new StyleColor(new Color(0.8f, 0.8f, 1f));
  285. hpLabel.style.fontSize = 10;
  286. memberHeader.Add(nameLabel);
  287. memberHeader.Add(hpLabel);
  288. memberCard.Add(memberHeader);
  289. // Stats container
  290. var statsContainer = new VisualElement();
  291. statsContainer.style.flexDirection = FlexDirection.Row;
  292. statsContainer.style.flexWrap = Wrap.Wrap;
  293. statsContainer.style.justifyContent = Justify.SpaceBetween;
  294. // Add attribute stats in a compact layout
  295. AddCompactStatLabel(statsContainer, "STR", member.strength);
  296. AddCompactStatLabel(statsContainer, "DEX", member.dexterity);
  297. AddCompactStatLabel(statsContainer, "CON", member.constitution);
  298. AddCompactStatLabel(statsContainer, "WIS", member.wisdom);
  299. AddCompactStatLabel(statsContainer, "PER", member.perception);
  300. memberCard.Add(statsContainer);
  301. teamMembersList.Add(memberCard);
  302. }
  303. /// <summary>
  304. /// Adds a compact stat label to a container
  305. /// </summary>
  306. private void AddCompactStatLabel(VisualElement container, string statName, int statValue)
  307. {
  308. var statElement = new VisualElement();
  309. statElement.style.flexDirection = FlexDirection.Row;
  310. statElement.style.width = new StyleLength(new Length(18, LengthUnit.Percent));
  311. statElement.style.marginBottom = 1;
  312. var statLabel = new Label($"{statName}:");
  313. statLabel.style.color = new StyleColor(new Color(0.8f, 0.8f, 0.8f));
  314. statLabel.style.fontSize = 9;
  315. statLabel.style.width = new StyleLength(new Length(60, LengthUnit.Percent));
  316. var valueLabel = new Label(statValue.ToString());
  317. valueLabel.style.color = new StyleColor(new Color(1f, 1f, 1f));
  318. valueLabel.style.fontSize = 9;
  319. valueLabel.style.width = new StyleLength(new Length(40, LengthUnit.Percent));
  320. statElement.Add(statLabel);
  321. statElement.Add(valueLabel);
  322. container.Add(statElement);
  323. }
  324. /// <summary>
  325. /// Updates the team summary statistics
  326. /// </summary>
  327. private void UpdateTeamStats()
  328. {
  329. if (currentTeam == null) return;
  330. // Update member count
  331. if (memberCountLabel != null)
  332. {
  333. memberCountLabel.text = currentTeam.Count.ToString();
  334. }
  335. // Update total gold (assuming team shares resources)
  336. if (totalGoldLabel != null)
  337. {
  338. var totalGold = currentTeam.Sum(member => member.gold);
  339. totalGoldLabel.text = totalGold.ToString();
  340. }
  341. // Since TeamCharacter doesn't have level property, assume level 1 for all characters
  342. if (averageLevelLabel != null)
  343. {
  344. averageLevelLabel.text = "1";
  345. }
  346. }
  347. /// <summary>
  348. /// Handle manage team button click
  349. /// </summary>
  350. private void OnManageTeamClicked()
  351. {
  352. if (showDebugLogs)
  353. {
  354. Debug.Log("🔄 TeamOverviewController: Returning to Team Select scene");
  355. }
  356. // Load the Team Select scene
  357. var sceneManager = FindFirstObjectByType<SceneNavigationManager>();
  358. if (sceneManager != null)
  359. {
  360. sceneManager.GoToTeamSelect();
  361. }
  362. else
  363. {
  364. // Fallback to direct scene loading
  365. UnityEngine.SceneManagement.SceneManager.LoadScene("TeamSelect");
  366. }
  367. }
  368. /// <summary>
  369. /// Handle save game button click
  370. /// </summary>
  371. private void OnSaveGameClicked()
  372. {
  373. if (showDebugLogs)
  374. {
  375. Debug.Log("💾 TeamOverviewController: Saving game");
  376. }
  377. try
  378. {
  379. // Use GameStateManager to save current game state
  380. var gameStateManager = FindFirstObjectByType<GameStateManager>();
  381. if (gameStateManager != null)
  382. {
  383. gameStateManager.SaveGame();
  384. Debug.Log("✅ Game saved successfully!");
  385. }
  386. else
  387. {
  388. Debug.LogWarning("⚠️ GameStateManager not found!");
  389. }
  390. }
  391. catch (System.Exception e)
  392. {
  393. Debug.LogError($"❌ Failed to save game: {e.Message}");
  394. }
  395. }
  396. /// <summary>
  397. /// Handle perception visualization toggle change
  398. /// </summary>
  399. private void OnPerceptionVisualizationToggled(ChangeEvent<bool> evt)
  400. {
  401. bool newValue = evt.newValue;
  402. if (showDebugLogs)
  403. {
  404. Debug.Log($"👁️ TeamOverviewController: Perception visualization toggled to {newValue}");
  405. }
  406. // Save the setting
  407. PlayerPrefs.SetInt("ShowPerceptionVisualization", newValue ? 1 : 0);
  408. PlayerPrefs.Save();
  409. // Update the visualizer
  410. UpdatePerceptionVisualizationState(newValue);
  411. }
  412. /// <summary>
  413. /// Updates the perception visualization state
  414. /// </summary>
  415. private void UpdatePerceptionVisualizationState(bool enabled)
  416. {
  417. var visualizer = TeamPerceptionVisualizer.Instance;
  418. if (visualizer != null)
  419. {
  420. visualizer.SetPerceptionVisualizationEnabled(enabled);
  421. }
  422. else if (showDebugLogs)
  423. {
  424. Debug.LogWarning("⚠️ TeamPerceptionVisualizer instance not found");
  425. }
  426. }
  427. /// <summary>
  428. /// Refreshes the team data and display
  429. /// </summary>
  430. public void RefreshTeamData()
  431. {
  432. LoadTeamData();
  433. UpdateTeamDisplay();
  434. if (showDebugLogs)
  435. {
  436. Debug.Log("🔄 TeamOverviewController: Team data refreshed");
  437. }
  438. }
  439. /// <summary>
  440. /// Forces a reload of team data from all sources
  441. /// </summary>
  442. public void ForceReloadTeamData()
  443. {
  444. // Force GameStateManager to reload if possible
  445. if (GameStateManager.Instance != null && PlayerPrefs.HasKey("GameSaved"))
  446. {
  447. GameStateManager.Instance.LoadGame();
  448. }
  449. LoadTeamData();
  450. UpdateTeamDisplay();
  451. if (showDebugLogs)
  452. {
  453. Debug.Log("🔄 TeamOverviewController: Team data force reloaded");
  454. }
  455. }
  456. /// <summary>
  457. /// Context menu methods for debugging
  458. /// </summary>
  459. [ContextMenu("Show Team Overview")]
  460. public void TestShowTeamOverview()
  461. {
  462. ShowTeamOverview();
  463. }
  464. [ContextMenu("Hide Team Overview")]
  465. public void TestHideTeamOverview()
  466. {
  467. HideTeamOverview();
  468. }
  469. [ContextMenu("Refresh Team Data")]
  470. public void TestRefreshTeamData()
  471. {
  472. RefreshTeamData();
  473. }
  474. [ContextMenu("Force Reload Team Data")]
  475. public void TestForceReloadTeamData()
  476. {
  477. ForceReloadTeamData();
  478. }
  479. [ContextMenu("Debug Team Data Sources")]
  480. public void DebugTeamDataSources()
  481. {
  482. Debug.Log("=== TEAM DATA DEBUG ===");
  483. // Check MainTeamSelectScript
  484. var teamSelectScript = FindFirstObjectByType<MainTeamSelectScript>();
  485. Debug.Log($"MainTeamSelectScript found: {teamSelectScript != null}");
  486. if (teamSelectScript != null)
  487. {
  488. var characters = teamSelectScript.GetConfiguredCharacters();
  489. Debug.Log($"MainTeamSelectScript characters: {characters.Count}");
  490. }
  491. // Check GameStateManager
  492. Debug.Log($"GameStateManager.Instance: {GameStateManager.Instance != null}");
  493. if (GameStateManager.Instance != null)
  494. {
  495. Debug.Log($"GameStateManager.savedTeam: {GameStateManager.Instance.savedTeam != null}");
  496. if (GameStateManager.Instance.savedTeam != null)
  497. {
  498. int count = 0;
  499. foreach (var character in GameStateManager.Instance.savedTeam)
  500. {
  501. if (character != null) count++;
  502. }
  503. Debug.Log($"GameStateManager team count: {count}");
  504. }
  505. }
  506. // Check PlayerPrefs
  507. int playerPrefsCount = 0;
  508. for (int i = 0; i < 4; i++)
  509. {
  510. if (PlayerPrefs.HasKey($"Character{i}_Exists") && PlayerPrefs.GetInt($"Character{i}_Exists") == 1)
  511. {
  512. string name = PlayerPrefs.GetString($"Character{i}_Name", "");
  513. if (!string.IsNullOrEmpty(name))
  514. {
  515. playerPrefsCount++;
  516. Debug.Log($"PlayerPrefs Character {i}: {name}");
  517. }
  518. }
  519. }
  520. Debug.Log($"PlayerPrefs character count: {playerPrefsCount}");
  521. Debug.Log($"Current team loaded: {currentTeam?.Count ?? 0}");
  522. if (currentTeam != null)
  523. {
  524. foreach (var member in currentTeam)
  525. {
  526. Debug.Log($" - {member?.name ?? "null"} (STR:{member?.strength ?? 0}, DEX:{member?.dexterity ?? 0}, CON:{member?.constitution ?? 0}, WIS:{member?.wisdom ?? 0}, PER:{member?.perception ?? 0})");
  527. }
  528. }
  529. Debug.Log("=== END DEBUG ===");
  530. }
  531. [ContextMenu("Force Update Display")]
  532. public void ForceUpdateDisplay()
  533. {
  534. if (currentTeam != null && currentTeam.Count > 0)
  535. {
  536. Debug.Log($"🔄 Force updating display with {currentTeam.Count} team members");
  537. UpdateTeamDisplay();
  538. }
  539. else
  540. {
  541. Debug.Log("⚠️ No team data to display");
  542. }
  543. }
  544. }