PostBattleLootSystem.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using System.Linq;
  4. using UnityEngine.UIElements;
  5. #if UNITY_EDITOR
  6. using UnityEditor;
  7. #endif
  8. /// <summary>
  9. /// Handles post-battle looting when all enemies are defeated
  10. /// Allows players to loot enemy corpses and manage inventory weight
  11. /// </summary>
  12. public class PostBattleLootSystem : MonoBehaviour
  13. {
  14. [Header("UI Toolkit References")]
  15. public UIDocument lootUIDocument;
  16. public VisualTreeAsset lootScreenTemplate;
  17. public PanelSettings panelSettings;
  18. [Header("Currency Settings")]
  19. public int baseGoldReward = 5;
  20. public int baseSilverReward = 15;
  21. public int baseCopperReward = 25;
  22. [Header("Debug Settings")]
  23. public bool showDebugLogs = true;
  24. // Events
  25. public event System.Action OnLootingComplete;
  26. private List<LootableEnemy> lootableEnemies = new List<LootableEnemy>();
  27. private bool isLootingActive = false;
  28. private VisualElement rootElement;
  29. private bool takeAllPressed = false;
  30. /// <summary>
  31. /// Gets whether the looting process is currently active
  32. /// </summary>
  33. public bool IsLootingActive => isLootingActive;
  34. [System.Serializable]
  35. public class LootableEnemy
  36. {
  37. public string enemyName;
  38. public List<string> dropItems = new List<string>();
  39. public int goldReward;
  40. public int silverReward;
  41. public int copperReward;
  42. public bool hasBeenLooted = false;
  43. public Vector3 corpsePosition;
  44. public LootableEnemy(string name, Vector3 position)
  45. {
  46. enemyName = name;
  47. corpsePosition = position;
  48. }
  49. }
  50. [System.Serializable]
  51. public class LootableItem
  52. {
  53. public string itemName;
  54. public string description;
  55. public int weight = 1;
  56. public int value = 1; // In copper
  57. public bool isSelected = false;
  58. public LootableItem(string name, string desc, int itemWeight = 1, int itemValue = 1)
  59. {
  60. itemName = name;
  61. description = desc;
  62. weight = itemWeight;
  63. value = itemValue;
  64. }
  65. }
  66. /// <summary>
  67. /// Initialize looting system with defeated enemies
  68. /// </summary>
  69. public void InitializeLootSystem(List<GameObject> defeatedEnemies)
  70. {
  71. lootableEnemies.Clear();
  72. foreach (var enemy in defeatedEnemies)
  73. {
  74. if (enemy == null) continue;
  75. Character enemyCharacter = enemy.GetComponent<Character>();
  76. if (enemyCharacter == null || !enemyCharacter.IsDead) continue;
  77. var lootableEnemy = new LootableEnemy(enemyCharacter.CharacterName, enemy.transform.position);
  78. // Generate loot based on enemy type and random factors
  79. GenerateEnemyLoot(lootableEnemy, enemyCharacter);
  80. lootableEnemies.Add(lootableEnemy);
  81. }
  82. if (showDebugLogs)
  83. Debug.Log($"💰 Initialized loot system with {lootableEnemies.Count} lootable enemies");
  84. }
  85. /// <summary>
  86. /// Show the loot UI and start looting phase
  87. /// </summary>
  88. public void StartLooting()
  89. {
  90. if (lootableEnemies.Count == 0)
  91. {
  92. if (showDebugLogs)
  93. Debug.Log("💰 No enemies to loot, ending battle");
  94. OnLootingComplete?.Invoke();
  95. return;
  96. }
  97. isLootingActive = true;
  98. CreateAndShowLootUI();
  99. if (showDebugLogs)
  100. Debug.Log("💰 Started post-battle looting phase");
  101. }
  102. /// <summary>
  103. /// Create and show the UI Toolkit loot interface
  104. /// </summary>
  105. private void CreateAndShowLootUI()
  106. {
  107. // Find or create UI Document
  108. if (lootUIDocument == null)
  109. {
  110. GameObject uiGO = new GameObject("LootUIDocument");
  111. uiGO.transform.SetParent(transform);
  112. lootUIDocument = uiGO.AddComponent<UIDocument>();
  113. }
  114. // Set up the UI Document with proper references
  115. SetupLootUIDocument();
  116. // Get the root element
  117. if (lootUIDocument.visualTreeAsset != null)
  118. {
  119. rootElement = lootUIDocument.rootVisualElement;
  120. // Show the overlay
  121. var overlay = rootElement.Q<VisualElement>("LootScreenOverlay");
  122. if (overlay != null)
  123. {
  124. overlay.style.display = DisplayStyle.Flex;
  125. }
  126. // Populate the UI with loot data
  127. PopulateLootUI();
  128. // Set up button callbacks
  129. SetupUICallbacks();
  130. }
  131. else
  132. {
  133. // Fallback - create basic UI if template loading failed
  134. Debug.LogWarning("PostBattleLootScreen.uxml not found. Creating basic UI.");
  135. CreateBasicLootUI();
  136. }
  137. }
  138. /// <summary>
  139. /// Set up the UIDocument with proper UXML template and panel settings
  140. /// </summary>
  141. private void SetupLootUIDocument()
  142. {
  143. if (lootUIDocument == null) return;
  144. // Load the UXML template if not assigned
  145. if (lootScreenTemplate == null)
  146. {
  147. lootScreenTemplate = Resources.Load<VisualTreeAsset>("UI/BattleSceneUI/PostBattleLootScreen");
  148. if (lootScreenTemplate == null)
  149. {
  150. #if UNITY_EDITOR
  151. // Try alternative path in editor
  152. lootScreenTemplate = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/UI/BattleSceneUI/PostBattleLootScreen.uxml");
  153. #endif
  154. }
  155. }
  156. // Load panel settings if not assigned
  157. if (panelSettings == null)
  158. {
  159. panelSettings = Resources.Load<PanelSettings>("MainSettings");
  160. if (panelSettings == null)
  161. {
  162. // Try alternative panel settings
  163. panelSettings = Resources.Load<PanelSettings>("UI/TravelPanelSettings");
  164. if (panelSettings == null)
  165. {
  166. // Try to find any PanelSettings in the project
  167. var allPanelSettings = Resources.FindObjectsOfTypeAll<PanelSettings>();
  168. if (allPanelSettings.Length > 0)
  169. panelSettings = allPanelSettings[0];
  170. }
  171. }
  172. }
  173. // Configure the UIDocument
  174. lootUIDocument.visualTreeAsset = lootScreenTemplate;
  175. lootUIDocument.panelSettings = panelSettings;
  176. // Load and apply stylesheet
  177. var stylesheet = Resources.Load<StyleSheet>("UI/BattleSceneUI/PostBattleLootScreen");
  178. if (stylesheet == null)
  179. {
  180. #if UNITY_EDITOR
  181. stylesheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/UI/BattleSceneUI/PostBattleLootScreen.uss");
  182. #endif
  183. }
  184. if (stylesheet != null && lootUIDocument.rootVisualElement != null)
  185. {
  186. lootUIDocument.rootVisualElement.styleSheets.Add(stylesheet);
  187. }
  188. if (lootScreenTemplate == null)
  189. {
  190. Debug.LogError("PostBattleLootSystem: Could not load PostBattleLootScreen.uxml template!");
  191. }
  192. if (panelSettings == null)
  193. {
  194. Debug.LogWarning("PostBattleLootSystem: No PanelSettings found. UI may not display correctly.");
  195. }
  196. }
  197. /// <summary>
  198. /// Create a basic fallback UI if the UXML template isn't available
  199. /// </summary>
  200. private void CreateBasicLootUI()
  201. {
  202. // Create a simple overlay using UI Toolkit elements
  203. rootElement = lootUIDocument.rootVisualElement;
  204. // Create overlay
  205. var overlay = new VisualElement();
  206. overlay.name = "LootScreenOverlay";
  207. overlay.style.position = Position.Absolute;
  208. overlay.style.top = 0;
  209. overlay.style.left = 0;
  210. overlay.style.right = 0;
  211. overlay.style.bottom = 0;
  212. overlay.style.backgroundColor = new Color(0, 0, 0, 0.8f);
  213. overlay.style.justifyContent = Justify.Center;
  214. overlay.style.alignItems = Align.Center;
  215. // Create background panel
  216. var background = new VisualElement();
  217. background.style.backgroundColor = new Color(0.1f, 0.1f, 0.2f, 0.95f);
  218. background.style.borderTopWidth = 2;
  219. background.style.borderBottomWidth = 2;
  220. background.style.borderLeftWidth = 2;
  221. background.style.borderRightWidth = 2;
  222. background.style.borderTopColor = new Color(0.7f, 0.5f, 0.2f);
  223. background.style.borderBottomColor = new Color(0.7f, 0.5f, 0.2f);
  224. background.style.borderLeftColor = new Color(0.7f, 0.5f, 0.2f);
  225. background.style.borderRightColor = new Color(0.7f, 0.5f, 0.2f);
  226. background.style.borderTopLeftRadius = 15;
  227. background.style.borderTopRightRadius = 15;
  228. background.style.borderBottomLeftRadius = 15;
  229. background.style.borderBottomRightRadius = 15;
  230. background.style.paddingTop = 30;
  231. background.style.paddingBottom = 30;
  232. background.style.paddingLeft = 30;
  233. background.style.paddingRight = 30;
  234. background.style.width = new Length(80, LengthUnit.Percent);
  235. background.style.maxWidth = 800;
  236. // Add title
  237. var title = new Label("🏆 VICTORY! 🏆");
  238. title.style.fontSize = 36;
  239. title.style.color = new Color(1f, 0.84f, 0f);
  240. title.style.unityTextAlign = TextAnchor.MiddleCenter;
  241. title.style.marginBottom = 20;
  242. // Add loot info
  243. var lootInfo = new Label();
  244. lootInfo.name = "LootInfo";
  245. lootInfo.style.fontSize = 14;
  246. lootInfo.style.color = Color.white;
  247. lootInfo.style.whiteSpace = WhiteSpace.Normal;
  248. lootInfo.style.marginBottom = 20;
  249. // Add continue button
  250. var continueButton = new Button(() => CompleteLootingProcess());
  251. continueButton.text = "Continue";
  252. continueButton.name = "ContinueButton";
  253. continueButton.style.fontSize = 16;
  254. continueButton.style.paddingTop = 10;
  255. continueButton.style.paddingBottom = 10;
  256. continueButton.style.paddingLeft = 20;
  257. continueButton.style.paddingRight = 20;
  258. // Assemble the UI
  259. background.Add(title);
  260. background.Add(lootInfo);
  261. background.Add(continueButton);
  262. overlay.Add(background);
  263. rootElement.Add(overlay);
  264. // Populate basic loot info
  265. PopulateBasicLootInfo(lootInfo);
  266. }
  267. /// <summary>
  268. /// Set up UI element callbacks for the loot interface
  269. /// </summary>
  270. private void SetupUICallbacks()
  271. {
  272. if (rootElement == null) return;
  273. // Set up Take All button
  274. var takeAllButton = rootElement.Q<Button>("TakeAllButton");
  275. if (takeAllButton != null)
  276. {
  277. takeAllButton.clicked += () =>
  278. {
  279. takeAllPressed = true;
  280. AutoLootAll();
  281. CompleteLootingProcess();
  282. };
  283. }
  284. // Set up Continue button
  285. var continueButton = rootElement.Q<Button>("ContinueButton");
  286. if (continueButton != null)
  287. {
  288. continueButton.clicked += () =>
  289. {
  290. if (!takeAllPressed)
  291. {
  292. AutoLootAll(); // Auto-loot if not already done
  293. }
  294. CompleteLootingProcess();
  295. };
  296. }
  297. // Set up keyboard input for space key
  298. rootElement.RegisterCallback<KeyDownEvent>(OnKeyDown);
  299. // Make sure the root element can receive focus for keyboard events
  300. rootElement.focusable = true;
  301. rootElement.Focus();
  302. }
  303. /// <summary>
  304. /// Handle keyboard input for the loot UI
  305. /// </summary>
  306. private void OnKeyDown(KeyDownEvent evt)
  307. {
  308. if (evt.keyCode == KeyCode.Space)
  309. {
  310. if (!takeAllPressed)
  311. {
  312. AutoLootAll();
  313. }
  314. CompleteLootingProcess();
  315. }
  316. }
  317. /// <summary>
  318. /// Populate basic loot information for fallback UI
  319. /// </summary>
  320. private void PopulateBasicLootInfo(Label lootInfo)
  321. {
  322. var lootText = "Collecting loot from defeated enemies...\n\n";
  323. int totalGold = 0, totalSilver = 0, totalCopper = 0;
  324. List<string> allItems = new List<string>();
  325. foreach (var enemy in lootableEnemies)
  326. {
  327. totalGold += enemy.goldReward;
  328. totalSilver += enemy.silverReward;
  329. totalCopper += enemy.copperReward;
  330. allItems.AddRange(enemy.dropItems);
  331. lootText += $"💀 {enemy.enemyName}: {enemy.goldReward}g {enemy.silverReward}s {enemy.copperReward}c\n";
  332. foreach (var item in enemy.dropItems)
  333. {
  334. lootText += $" 📦 {item}\n";
  335. }
  336. }
  337. lootText += $"\n💰 Total: {totalGold} gold, {totalSilver} silver, {totalCopper} copper\n";
  338. lootText += $"📦 {allItems.Count} items collected\n\n";
  339. lootText += "Click Continue to proceed or press SPACE...";
  340. lootInfo.text = lootText;
  341. }
  342. /// <summary>
  343. /// Show a temporary on-screen message for looting
  344. /// </summary>
  345. private System.Collections.IEnumerator ShowLootingMessage()
  346. {
  347. // Create a temporary UI GameObject
  348. GameObject tempUI = new GameObject("TempLootUI");
  349. tempUI.transform.SetParent(FindFirstObjectByType<Canvas>()?.transform, false);
  350. // Add background panel
  351. var canvasGroup = tempUI.AddComponent<CanvasGroup>();
  352. var image = tempUI.AddComponent<UnityEngine.UI.Image>();
  353. image.color = new Color(0, 0, 0, 0.8f); // Semi-transparent black
  354. // Set full screen size
  355. var rectTransform = tempUI.GetComponent<RectTransform>();
  356. rectTransform.anchorMin = Vector2.zero;
  357. rectTransform.anchorMax = Vector2.one;
  358. rectTransform.offsetMin = Vector2.zero;
  359. rectTransform.offsetMax = Vector2.zero;
  360. // Add text
  361. GameObject textObj = new GameObject("LootText");
  362. textObj.transform.SetParent(tempUI.transform, false);
  363. var text = textObj.AddComponent<UnityEngine.UI.Text>();
  364. text.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
  365. text.fontSize = 24;
  366. text.color = Color.white;
  367. text.alignment = TextAnchor.MiddleCenter;
  368. // Set text content
  369. string lootText = "🏆 VICTORY! 🏆\n\n";
  370. lootText += "Collecting loot from defeated enemies...\n\n";
  371. int totalGold = 0, totalSilver = 0, totalCopper = 0;
  372. List<string> allItems = new List<string>();
  373. foreach (var enemy in lootableEnemies)
  374. {
  375. totalGold += enemy.goldReward;
  376. totalSilver += enemy.silverReward;
  377. totalCopper += enemy.copperReward;
  378. allItems.AddRange(enemy.dropItems);
  379. lootText += $"💀 {enemy.enemyName}: {enemy.goldReward}g {enemy.silverReward}s {enemy.copperReward}c\n";
  380. foreach (var item in enemy.dropItems)
  381. {
  382. lootText += $" 📦 {item}\n";
  383. }
  384. }
  385. lootText += $"\n💰 Total: {totalGold} gold, {totalSilver} silver, {totalCopper} copper\n";
  386. lootText += $"📦 {allItems.Count} items collected\n\n";
  387. lootText += "Press SPACE to continue...";
  388. text.text = lootText;
  389. // Set text position
  390. var textRect = textObj.GetComponent<RectTransform>();
  391. textRect.anchorMin = Vector2.zero;
  392. textRect.anchorMax = Vector2.one;
  393. textRect.offsetMin = new Vector2(50, 50);
  394. textRect.offsetMax = new Vector2(-50, -50);
  395. // Auto-loot everything
  396. AutoLootAll();
  397. // Wait for space key or 5 seconds
  398. float timer = 0f;
  399. while (timer < 5f && !Input.GetKeyDown(KeyCode.Space))
  400. {
  401. timer += Time.deltaTime;
  402. yield return null;
  403. }
  404. // Cleanup UI
  405. if (tempUI != null)
  406. Destroy(tempUI);
  407. // Complete looting
  408. CompleteLootingProcess();
  409. }
  410. /// <summary>
  411. /// Complete the looting process and trigger the callback
  412. /// </summary>
  413. private void CompleteLootingProcess()
  414. {
  415. isLootingActive = false;
  416. if (showDebugLogs)
  417. Debug.Log("💰 Looting completed, triggering OnLootingComplete");
  418. OnLootingComplete?.Invoke();
  419. }
  420. /// <summary>
  421. /// Generate loot for a defeated enemy
  422. /// </summary>
  423. private void GenerateEnemyLoot(LootableEnemy lootableEnemy, Character enemyCharacter)
  424. {
  425. // Base currency rewards
  426. lootableEnemy.goldReward = Random.Range(0, baseGoldReward + 1);
  427. lootableEnemy.silverReward = Random.Range(0, baseSilverReward + 1);
  428. lootableEnemy.copperReward = Random.Range(baseCopperReward - 5, baseCopperReward + 10);
  429. // Basic item drops based on enemy type
  430. GenerateBasicDrops(lootableEnemy, enemyCharacter.CharacterName);
  431. // Try to get drops from enemy data if available
  432. TryGetEnemyDataDrops(lootableEnemy, enemyCharacter);
  433. if (showDebugLogs)
  434. {
  435. Debug.Log($"💰 Generated loot for {lootableEnemy.enemyName}: " +
  436. $"{lootableEnemy.goldReward}g {lootableEnemy.silverReward}s {lootableEnemy.copperReward}c, " +
  437. $"{lootableEnemy.dropItems.Count} items");
  438. }
  439. }
  440. /// <summary>
  441. /// Generate basic drops based on enemy name/type
  442. /// </summary>
  443. private void GenerateBasicDrops(LootableEnemy lootableEnemy, string enemyName)
  444. {
  445. string lowerName = enemyName.ToLower();
  446. // Skeleton-type enemies
  447. if (lowerName.Contains("skeleton"))
  448. {
  449. if (Random.Range(0f, 1f) < 0.3f) lootableEnemy.dropItems.Add("Bone");
  450. if (Random.Range(0f, 1f) < 0.2f) lootableEnemy.dropItems.Add("Rusty Sword");
  451. if (Random.Range(0f, 1f) < 0.15f) lootableEnemy.dropItems.Add("Bone Dust");
  452. }
  453. // Bandit-type enemies
  454. else if (lowerName.Contains("bandit") || lowerName.Contains("thief"))
  455. {
  456. if (Random.Range(0f, 1f) < 0.4f) lootableEnemy.dropItems.Add("Thieves' Tools");
  457. if (Random.Range(0f, 1f) < 0.3f) lootableEnemy.dropItems.Add("Rope");
  458. if (Random.Range(0f, 1f) < 0.2f) lootableEnemy.dropItems.Add("Dagger");
  459. // Bandits often have extra coin
  460. lootableEnemy.copperReward += Random.Range(5, 15);
  461. }
  462. // Orc-type enemies
  463. else if (lowerName.Contains("orc") || lowerName.Contains("goblin"))
  464. {
  465. if (Random.Range(0f, 1f) < 0.3f) lootableEnemy.dropItems.Add("Crude Axe");
  466. if (Random.Range(0f, 1f) < 0.25f) lootableEnemy.dropItems.Add("Hide Armor");
  467. if (Random.Range(0f, 1f) < 0.2f) lootableEnemy.dropItems.Add("Iron Ration");
  468. }
  469. // Default/unknown enemies
  470. else
  471. {
  472. if (Random.Range(0f, 1f) < 0.2f) lootableEnemy.dropItems.Add("Leather Scraps");
  473. if (Random.Range(0f, 1f) < 0.15f) lootableEnemy.dropItems.Add("Iron Ration");
  474. }
  475. // Common drops for all enemies
  476. if (Random.Range(0f, 1f) < 0.1f) lootableEnemy.dropItems.Add("Health Potion");
  477. if (Random.Range(0f, 1f) < 0.05f) lootableEnemy.dropItems.Add("Bandage");
  478. }
  479. /// <summary>
  480. /// Try to get drops from EnemyCharacterData if available
  481. /// </summary>
  482. private void TryGetEnemyDataDrops(LootableEnemy lootableEnemy, Character enemyCharacter)
  483. {
  484. // This would integrate with the EnemyCharacterData system
  485. // For now, we'll use the basic drop system above
  486. // TODO: Integrate with EnemyCharacterData.dropTable when available
  487. }
  488. /// <summary>
  489. /// Show the loot UI
  490. /// </summary>
  491. private void ShowLootUI()
  492. {
  493. if (rootElement != null)
  494. {
  495. // Show the UI Toolkit loot interface
  496. rootElement.style.display = DisplayStyle.Flex;
  497. PopulateLootUI();
  498. }
  499. else
  500. {
  501. // Fallback to console-based looting for now
  502. Debug.Log("💰 === POST-BATTLE LOOT ===");
  503. foreach (var enemy in lootableEnemies)
  504. {
  505. Debug.Log($"💰 {enemy.enemyName}: {enemy.goldReward}g {enemy.silverReward}s {enemy.copperReward}c");
  506. foreach (var item in enemy.dropItems)
  507. {
  508. Debug.Log($"💰 - {item}");
  509. }
  510. }
  511. Debug.Log("💰 ========================");
  512. // Auto-loot everything for now
  513. AutoLootAll();
  514. }
  515. }
  516. /// <summary>
  517. /// Populate the loot UI with available items
  518. /// </summary>
  519. private void PopulateLootUI()
  520. {
  521. if (rootElement == null) return;
  522. // Calculate totals first
  523. int totalGold = 0, totalSilver = 0, totalCopper = 0;
  524. List<string> allItems = new List<string>();
  525. foreach (var enemy in lootableEnemies)
  526. {
  527. totalGold += enemy.goldReward;
  528. totalSilver += enemy.silverReward;
  529. totalCopper += enemy.copperReward;
  530. allItems.AddRange(enemy.dropItems);
  531. }
  532. // Update currency displays
  533. var goldLabel = rootElement.Q<Label>("GoldAmount");
  534. var silverLabel = rootElement.Q<Label>("SilverAmount");
  535. var copperLabel = rootElement.Q<Label>("CopperAmount");
  536. if (goldLabel != null) goldLabel.text = totalGold.ToString();
  537. if (silverLabel != null) silverLabel.text = totalSilver.ToString();
  538. if (copperLabel != null) copperLabel.text = totalCopper.ToString();
  539. // Update item count
  540. var itemCountLabel = rootElement.Q<Label>("ItemCount");
  541. if (itemCountLabel != null)
  542. itemCountLabel.text = $"{allItems.Count} items";
  543. // Populate enemy loot sections
  544. var enemyLootContainer = rootElement.Q<VisualElement>("EnemyLootContainer");
  545. if (enemyLootContainer != null)
  546. {
  547. enemyLootContainer.Clear();
  548. foreach (var enemy in lootableEnemies)
  549. {
  550. var enemySection = new VisualElement();
  551. enemySection.AddToClassList("enemy-loot-section");
  552. // Enemy header
  553. var enemyHeader = new Label($"💀 {enemy.enemyName}");
  554. enemyHeader.AddToClassList("enemy-name");
  555. enemySection.Add(enemyHeader);
  556. // Enemy currency
  557. if (enemy.goldReward > 0 || enemy.silverReward > 0 || enemy.copperReward > 0)
  558. {
  559. var currencyContainer = new VisualElement();
  560. currencyContainer.AddToClassList("enemy-currency");
  561. if (enemy.goldReward > 0)
  562. {
  563. var enemyGoldLabel = new Label($"🪙 {enemy.goldReward}");
  564. enemyGoldLabel.AddToClassList("currency-gold");
  565. currencyContainer.Add(enemyGoldLabel);
  566. }
  567. if (enemy.silverReward > 0)
  568. {
  569. var enemySilverLabel = new Label($"🪙 {enemy.silverReward}");
  570. enemySilverLabel.AddToClassList("currency-silver");
  571. currencyContainer.Add(enemySilverLabel);
  572. }
  573. if (enemy.copperReward > 0)
  574. {
  575. var enemyCopperLabel = new Label($"🪙 {enemy.copperReward}");
  576. enemyCopperLabel.AddToClassList("currency-copper");
  577. currencyContainer.Add(enemyCopperLabel);
  578. }
  579. enemySection.Add(currencyContainer);
  580. }
  581. // Enemy items
  582. if (enemy.dropItems != null && enemy.dropItems.Count > 0)
  583. {
  584. var itemsContainer = new VisualElement();
  585. itemsContainer.AddToClassList("enemy-items");
  586. foreach (var item in enemy.dropItems)
  587. {
  588. var itemLabel = new Label($"📦 {item}");
  589. itemLabel.AddToClassList("item-entry");
  590. itemsContainer.Add(itemLabel);
  591. }
  592. enemySection.Add(itemsContainer);
  593. }
  594. enemyLootContainer.Add(enemySection);
  595. }
  596. }
  597. }
  598. /// <summary>
  599. /// Auto-loot all items and currency (temporary solution)
  600. /// </summary>
  601. private void AutoLootAll()
  602. {
  603. int totalGold = 0, totalSilver = 0, totalCopper = 0;
  604. List<string> allItems = new List<string>();
  605. foreach (var enemy in lootableEnemies)
  606. {
  607. if (!enemy.hasBeenLooted)
  608. {
  609. totalGold += enemy.goldReward;
  610. totalSilver += enemy.silverReward;
  611. totalCopper += enemy.copperReward;
  612. allItems.AddRange(enemy.dropItems);
  613. enemy.hasBeenLooted = true;
  614. }
  615. }
  616. // Distribute rewards to players
  617. DistributeRewards(totalGold, totalSilver, totalCopper, allItems);
  618. if (showDebugLogs)
  619. {
  620. Debug.Log($"💰 Auto-looted: {totalGold}g {totalSilver}s {totalCopper}c and {allItems.Count} items");
  621. }
  622. // End looting phase
  623. FinishLooting();
  624. }
  625. /// <summary>
  626. /// Distribute looted rewards among surviving players
  627. /// </summary>
  628. private void DistributeRewards(int gold, int silver, int copper, List<string> items)
  629. {
  630. // Get surviving players
  631. var survivingPlayers = GetSurvivingPlayers();
  632. if (survivingPlayers.Count == 0)
  633. {
  634. Debug.LogWarning("💰 No surviving players to distribute loot to!");
  635. return;
  636. }
  637. // Distribute currency evenly
  638. int goldPerPlayer = gold / survivingPlayers.Count;
  639. int silverPerPlayer = silver / survivingPlayers.Count;
  640. int copperPerPlayer = copper / survivingPlayers.Count;
  641. // Handle remainder
  642. int goldRemainder = gold % survivingPlayers.Count;
  643. int silverRemainder = silver % survivingPlayers.Count;
  644. int copperRemainder = copper % survivingPlayers.Count;
  645. for (int i = 0; i < survivingPlayers.Count; i++)
  646. {
  647. var player = survivingPlayers[i];
  648. Character playerCharacter = player.GetComponent<Character>();
  649. if (playerCharacter == null) continue;
  650. // Get player's bank (assuming it exists)
  651. var bank = playerCharacter.GetComponent<Bank>();
  652. if (bank != null)
  653. {
  654. bank.gold += goldPerPlayer + (i < goldRemainder ? 1 : 0);
  655. bank.silver += silverPerPlayer + (i < silverRemainder ? 1 : 0);
  656. bank.copper += copperPerPlayer + (i < copperRemainder ? 1 : 0);
  657. }
  658. // Distribute items (simple round-robin for now)
  659. var inventory = playerCharacter.GetComponent<Inventory>();
  660. if (inventory != null)
  661. {
  662. for (int j = i; j < items.Count; j += survivingPlayers.Count)
  663. {
  664. // TODO: Create proper Item objects instead of strings
  665. // For now, add to string-based inventory if available
  666. AddItemToPlayer(playerCharacter, items[j]);
  667. }
  668. }
  669. if (showDebugLogs)
  670. {
  671. int finalGold = goldPerPlayer + (i < goldRemainder ? 1 : 0);
  672. int finalSilver = silverPerPlayer + (i < silverRemainder ? 1 : 0);
  673. int finalCopper = copperPerPlayer + (i < copperRemainder ? 1 : 0);
  674. Debug.Log($"💰 {playerCharacter.CharacterName} received: {finalGold}g {finalSilver}s {finalCopper}c");
  675. }
  676. }
  677. }
  678. /// <summary>
  679. /// Add an item to a player's inventory
  680. /// </summary>
  681. private void AddItemToPlayer(Character player, string itemName)
  682. {
  683. // Try to add to CombatDataTransfer session data
  684. if (CombatDataTransfer.HasValidSession())
  685. {
  686. var session = CombatDataTransfer.GetCurrentSession();
  687. var playerData = session.playerTeam.Find(p =>
  688. p.characterName == player.CharacterName ||
  689. player.CharacterName.StartsWith(p.characterName));
  690. if (playerData != null)
  691. {
  692. if (playerData.miscItems == null)
  693. playerData.miscItems = new List<string>();
  694. playerData.miscItems.Add(itemName);
  695. if (showDebugLogs)
  696. Debug.Log($"💰 Added {itemName} to {player.CharacterName}'s inventory");
  697. return;
  698. }
  699. }
  700. // Fallback: log that item would be added
  701. if (showDebugLogs)
  702. Debug.Log($"💰 Would add {itemName} to {player.CharacterName} (no inventory system found)");
  703. }
  704. /// <summary>
  705. /// Get list of surviving player characters
  706. /// </summary>
  707. private List<GameObject> GetSurvivingPlayers()
  708. {
  709. var gameManager = GameManager.Instance;
  710. if (gameManager == null) return new List<GameObject>();
  711. return gameManager.playerCharacters
  712. .Where(p => p != null)
  713. .Where(p =>
  714. {
  715. var character = p.GetComponent<Character>();
  716. return character != null && !character.IsDead;
  717. })
  718. .ToList();
  719. }
  720. /// <summary>
  721. /// Complete the looting phase
  722. /// </summary>
  723. private void FinishLooting()
  724. {
  725. isLootingActive = false;
  726. if (rootElement != null)
  727. rootElement.style.display = DisplayStyle.None;
  728. OnLootingComplete?.Invoke();
  729. if (showDebugLogs)
  730. Debug.Log("💰 Looting phase completed");
  731. }
  732. /// <summary>
  733. /// Skip looting and proceed to battle end
  734. /// </summary>
  735. public void SkipLooting()
  736. {
  737. if (showDebugLogs)
  738. Debug.Log("💰 Skipping looting phase");
  739. FinishLooting();
  740. }
  741. /// <summary>
  742. /// Check if all enemies have been looted
  743. /// </summary>
  744. public bool AllEnemiesLooted()
  745. {
  746. return lootableEnemies.All(e => e.hasBeenLooted);
  747. }
  748. /// <summary>
  749. /// Get total weight of all available loot
  750. /// </summary>
  751. public int GetTotalLootWeight()
  752. {
  753. // TODO: Implement when item weight system is added
  754. return lootableEnemies.Sum(e => e.dropItems.Count); // Placeholder: 1 weight per item
  755. }
  756. /// <summary>
  757. /// Get total value of all available loot in copper
  758. /// </summary>
  759. public int GetTotalLootValue()
  760. {
  761. int totalValue = 0;
  762. foreach (var enemy in lootableEnemies)
  763. {
  764. totalValue += enemy.goldReward * 100; // 1 gold = 100 copper
  765. totalValue += enemy.silverReward * 10; // 1 silver = 10 copper
  766. totalValue += enemy.copperReward;
  767. // TODO: Add item values when item system is integrated
  768. }
  769. return totalValue;
  770. }
  771. }