PostBattleLootSystem.cs 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453
  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 = false;
  24. [Header("Item Distribution Settings")]
  25. public bool enablePlayerItemSelection = true; // Allow manual item distribution
  26. public bool autoDistributeItems = false; // If true, items are distributed automatically
  27. // Events
  28. public event System.Action OnLootingComplete;
  29. private List<LootableEnemy> lootableEnemies = new List<LootableEnemy>();
  30. private bool isLootingActive = false;
  31. private VisualElement rootElement;
  32. private bool takeAllPressed = false;
  33. private Dictionary<string, int> selectedPlayerForItem = new Dictionary<string, int>(); // itemName -> playerIndex
  34. /// <summary>
  35. /// Gets whether the looting process is currently active
  36. /// </summary>
  37. public bool IsLootingActive => isLootingActive;
  38. [System.Serializable]
  39. public class LootableEnemy
  40. {
  41. public string enemyName;
  42. public List<string> dropItems = new List<string>();
  43. public int goldReward;
  44. public int silverReward;
  45. public int copperReward;
  46. public bool hasBeenLooted = false;
  47. public Vector3 corpsePosition;
  48. public LootableEnemy(string name, Vector3 position)
  49. {
  50. enemyName = name;
  51. corpsePosition = position;
  52. }
  53. }
  54. [System.Serializable]
  55. public class LootableItem
  56. {
  57. public string itemName;
  58. public string description;
  59. public int weight = 1;
  60. public int value = 1; // In copper
  61. public bool isSelected = false;
  62. public LootableItem(string name, string desc, int itemWeight = 1, int itemValue = 1)
  63. {
  64. itemName = name;
  65. description = desc;
  66. weight = itemWeight;
  67. value = itemValue;
  68. }
  69. }
  70. /// <summary>
  71. /// Initialize looting system with defeated enemies
  72. /// </summary>
  73. public void InitializeLootSystem(List<GameObject> defeatedEnemies)
  74. {
  75. lootableEnemies.Clear();
  76. foreach (var enemy in defeatedEnemies)
  77. {
  78. if (enemy == null) continue;
  79. Character enemyCharacter = enemy.GetComponent<Character>();
  80. if (enemyCharacter == null || !enemyCharacter.IsDead) continue;
  81. var lootableEnemy = new LootableEnemy(enemyCharacter.CharacterName, enemy.transform.position);
  82. // Generate loot based on enemy type and random factors
  83. GenerateEnemyLoot(lootableEnemy, enemyCharacter);
  84. lootableEnemies.Add(lootableEnemy);
  85. }
  86. if (showDebugLogs)
  87. Debug.Log($"💰 Initialized loot system with {lootableEnemies.Count} lootable enemies");
  88. }
  89. /// <summary>
  90. /// Show the loot UI and start looting phase
  91. /// </summary>
  92. public void StartLooting()
  93. {
  94. if (lootableEnemies.Count == 0)
  95. {
  96. if (showDebugLogs)
  97. Debug.Log("💰 No enemies to loot, ending battle");
  98. OnLootingComplete?.Invoke();
  99. return;
  100. }
  101. isLootingActive = true;
  102. CreateAndShowLootUI();
  103. if (showDebugLogs)
  104. Debug.Log("💰 Started post-battle looting phase");
  105. }
  106. /// <summary>
  107. /// Create and show the UI Toolkit loot interface
  108. /// </summary>
  109. private void CreateAndShowLootUI()
  110. {
  111. // Find or create UI Document
  112. if (lootUIDocument == null)
  113. {
  114. GameObject uiGO = new GameObject("LootUIDocument");
  115. uiGO.transform.SetParent(transform);
  116. lootUIDocument = uiGO.AddComponent<UIDocument>();
  117. }
  118. // Set up the UI Document with proper references
  119. SetupLootUIDocument();
  120. // Get the root element
  121. if (lootUIDocument.visualTreeAsset != null)
  122. {
  123. rootElement = lootUIDocument.rootVisualElement;
  124. // Show the overlay
  125. var overlay = rootElement.Q<VisualElement>("LootScreenOverlay");
  126. if (overlay != null)
  127. {
  128. overlay.style.display = DisplayStyle.Flex;
  129. }
  130. // Populate the UI with loot data
  131. PopulateLootUI();
  132. // Set up button callbacks
  133. SetupUICallbacks();
  134. }
  135. else
  136. {
  137. // Fallback - create basic UI if template loading failed
  138. Debug.LogWarning("PostBattleLootScreen.uxml not found. Creating basic UI.");
  139. CreateBasicLootUI();
  140. }
  141. }
  142. /// <summary>
  143. /// Set up the UIDocument with proper UXML template and panel settings
  144. /// </summary>
  145. private void SetupLootUIDocument()
  146. {
  147. if (lootUIDocument == null) return;
  148. // Load the UXML template if not assigned
  149. if (lootScreenTemplate == null)
  150. {
  151. lootScreenTemplate = Resources.Load<VisualTreeAsset>("UI/BattleSceneUI/PostBattleLootScreen");
  152. if (lootScreenTemplate == null)
  153. {
  154. #if UNITY_EDITOR
  155. // Try alternative path in editor
  156. lootScreenTemplate = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>("Assets/UI/BattleSceneUI/PostBattleLootScreen.uxml");
  157. #endif
  158. }
  159. }
  160. // Load panel settings if not assigned
  161. if (panelSettings == null)
  162. {
  163. panelSettings = Resources.Load<PanelSettings>("MainSettings");
  164. if (panelSettings == null)
  165. {
  166. // Try alternative panel settings
  167. panelSettings = Resources.Load<PanelSettings>("UI/TravelPanelSettings");
  168. if (panelSettings == null)
  169. {
  170. // Try to find any PanelSettings in the project
  171. var allPanelSettings = Resources.FindObjectsOfTypeAll<PanelSettings>();
  172. if (allPanelSettings.Length > 0)
  173. panelSettings = allPanelSettings[0];
  174. }
  175. }
  176. }
  177. // Configure the UIDocument
  178. lootUIDocument.visualTreeAsset = lootScreenTemplate;
  179. lootUIDocument.panelSettings = panelSettings;
  180. // Load and apply stylesheet
  181. var stylesheet = Resources.Load<StyleSheet>("UI/BattleSceneUI/PostBattleLootScreen");
  182. if (stylesheet == null)
  183. {
  184. #if UNITY_EDITOR
  185. stylesheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/UI/BattleSceneUI/PostBattleLootScreen.uss");
  186. #endif
  187. }
  188. if (stylesheet != null && lootUIDocument.rootVisualElement != null)
  189. {
  190. lootUIDocument.rootVisualElement.styleSheets.Add(stylesheet);
  191. }
  192. if (lootScreenTemplate == null)
  193. {
  194. Debug.LogError("PostBattleLootSystem: Could not load PostBattleLootScreen.uxml template!");
  195. }
  196. if (panelSettings == null)
  197. {
  198. Debug.LogWarning("PostBattleLootSystem: No PanelSettings found. UI may not display correctly.");
  199. }
  200. }
  201. /// <summary>
  202. /// Create a basic fallback UI if the UXML template isn't available
  203. /// </summary>
  204. private void CreateBasicLootUI()
  205. {
  206. // Create a simple overlay using UI Toolkit elements
  207. rootElement = lootUIDocument.rootVisualElement;
  208. // Create overlay
  209. var overlay = new VisualElement();
  210. overlay.name = "LootScreenOverlay";
  211. overlay.style.position = Position.Absolute;
  212. overlay.style.top = 0;
  213. overlay.style.left = 0;
  214. overlay.style.right = 0;
  215. overlay.style.bottom = 0;
  216. overlay.style.backgroundColor = new Color(0, 0, 0, 0.8f);
  217. overlay.style.justifyContent = Justify.Center;
  218. overlay.style.alignItems = Align.Center;
  219. // Create background panel
  220. var background = new VisualElement();
  221. background.style.backgroundColor = new Color(0.1f, 0.1f, 0.2f, 0.95f);
  222. background.style.borderTopWidth = 2;
  223. background.style.borderBottomWidth = 2;
  224. background.style.borderLeftWidth = 2;
  225. background.style.borderRightWidth = 2;
  226. background.style.borderTopColor = new Color(0.7f, 0.5f, 0.2f);
  227. background.style.borderBottomColor = new Color(0.7f, 0.5f, 0.2f);
  228. background.style.borderLeftColor = new Color(0.7f, 0.5f, 0.2f);
  229. background.style.borderRightColor = new Color(0.7f, 0.5f, 0.2f);
  230. background.style.borderTopLeftRadius = 15;
  231. background.style.borderTopRightRadius = 15;
  232. background.style.borderBottomLeftRadius = 15;
  233. background.style.borderBottomRightRadius = 15;
  234. background.style.paddingTop = 30;
  235. background.style.paddingBottom = 30;
  236. background.style.paddingLeft = 30;
  237. background.style.paddingRight = 30;
  238. background.style.width = new Length(80, LengthUnit.Percent);
  239. background.style.maxWidth = 800;
  240. // Add title
  241. var title = new Label("🏆 VICTORY! 🏆");
  242. title.style.fontSize = 36;
  243. title.style.color = new Color(1f, 0.84f, 0f);
  244. title.style.unityTextAlign = TextAnchor.MiddleCenter;
  245. title.style.marginBottom = 20;
  246. // Add loot info
  247. var lootInfo = new Label();
  248. lootInfo.name = "LootInfo";
  249. lootInfo.style.fontSize = 14;
  250. lootInfo.style.color = Color.white;
  251. lootInfo.style.whiteSpace = WhiteSpace.Normal;
  252. lootInfo.style.marginBottom = 20;
  253. // Add continue button
  254. var continueButton = new Button(() => CompleteLootingProcess());
  255. continueButton.text = "Continue";
  256. continueButton.name = "ContinueButton";
  257. continueButton.style.fontSize = 16;
  258. continueButton.style.paddingTop = 10;
  259. continueButton.style.paddingBottom = 10;
  260. continueButton.style.paddingLeft = 20;
  261. continueButton.style.paddingRight = 20;
  262. // Assemble the UI
  263. background.Add(title);
  264. background.Add(lootInfo);
  265. background.Add(continueButton);
  266. overlay.Add(background);
  267. rootElement.Add(overlay);
  268. // Populate basic loot info
  269. PopulateBasicLootInfo(lootInfo);
  270. }
  271. /// <summary>
  272. /// Set up UI element callbacks for the loot interface
  273. /// </summary>
  274. private void SetupUICallbacks()
  275. {
  276. if (rootElement == null) return;
  277. // Set up Take All button
  278. var takeAllButton = rootElement.Q<Button>("TakeAllButton");
  279. if (takeAllButton != null)
  280. {
  281. takeAllButton.clicked += () =>
  282. {
  283. takeAllPressed = true;
  284. // Force auto-distribution and skip player selection
  285. bool originalAutoDistribute = autoDistributeItems;
  286. autoDistributeItems = true; // Temporarily force auto-distribution
  287. AutoLootAll();
  288. // Restore original setting
  289. autoDistributeItems = originalAutoDistribute;
  290. };
  291. }
  292. // Set up Continue button - this should return to map
  293. var continueButton = rootElement.Q<Button>("ContinueButton");
  294. if (continueButton != null)
  295. {
  296. continueButton.text = "Return to Map"; // Make it clear what this button does
  297. continueButton.clicked += () =>
  298. {
  299. if (!takeAllPressed)
  300. {
  301. AutoLootAll(); // Auto-loot if not already done
  302. }
  303. // CompleteLootingProcess is called by AutoLootAll, so scene transition will happen
  304. };
  305. }
  306. // Set up keyboard input for space key
  307. rootElement.RegisterCallback<KeyDownEvent>(OnKeyDown);
  308. // Make sure the root element can receive focus for keyboard events
  309. rootElement.focusable = true;
  310. rootElement.Focus();
  311. }
  312. /// <summary>
  313. /// Handle keyboard input for the loot UI
  314. /// </summary>
  315. private void OnKeyDown(KeyDownEvent evt)
  316. {
  317. if (evt.keyCode == KeyCode.Space)
  318. {
  319. if (!takeAllPressed)
  320. {
  321. takeAllPressed = true;
  322. // Force auto-distribution and skip player selection
  323. bool originalAutoDistribute = autoDistributeItems;
  324. autoDistributeItems = true; // Temporarily force auto-distribution
  325. AutoLootAll();
  326. // Restore original setting
  327. autoDistributeItems = originalAutoDistribute;
  328. }
  329. }
  330. }
  331. /// <summary>
  332. /// Populate basic loot information for fallback UI
  333. /// </summary>
  334. private void PopulateBasicLootInfo(Label lootInfo)
  335. {
  336. var lootText = "Collecting loot from defeated enemies...\n\n";
  337. int totalGold = 0, totalSilver = 0, totalCopper = 0;
  338. List<string> allItems = new List<string>();
  339. foreach (var enemy in lootableEnemies)
  340. {
  341. totalGold += enemy.goldReward;
  342. totalSilver += enemy.silverReward;
  343. totalCopper += enemy.copperReward;
  344. allItems.AddRange(enemy.dropItems);
  345. lootText += $"💀 {enemy.enemyName}: {enemy.goldReward}g {enemy.silverReward}s {enemy.copperReward}c\n";
  346. foreach (var item in enemy.dropItems)
  347. {
  348. lootText += $" 📦 {item}\n";
  349. }
  350. }
  351. lootText += $"\n💰 Total: {totalGold} gold, {totalSilver} silver, {totalCopper} copper\n";
  352. lootText += $"📦 {allItems.Count} items collected\n\n";
  353. lootText += "Click Continue to proceed or press SPACE...";
  354. lootInfo.text = lootText;
  355. }
  356. /// <summary>
  357. /// Show a temporary on-screen message for looting
  358. /// </summary>
  359. private System.Collections.IEnumerator ShowLootingMessage()
  360. {
  361. // Create a temporary UI GameObject
  362. GameObject tempUI = new GameObject("TempLootUI");
  363. tempUI.transform.SetParent(FindFirstObjectByType<Canvas>()?.transform, false);
  364. // Add background panel
  365. var canvasGroup = tempUI.AddComponent<CanvasGroup>();
  366. var image = tempUI.AddComponent<UnityEngine.UI.Image>();
  367. image.color = new Color(0, 0, 0, 0.8f); // Semi-transparent black
  368. // Set full screen size
  369. var rectTransform = tempUI.GetComponent<RectTransform>();
  370. rectTransform.anchorMin = Vector2.zero;
  371. rectTransform.anchorMax = Vector2.one;
  372. rectTransform.offsetMin = Vector2.zero;
  373. rectTransform.offsetMax = Vector2.zero;
  374. // Add text
  375. GameObject textObj = new GameObject("LootText");
  376. textObj.transform.SetParent(tempUI.transform, false);
  377. var text = textObj.AddComponent<UnityEngine.UI.Text>();
  378. text.font = Resources.GetBuiltinResource<Font>("Arial.ttf");
  379. text.fontSize = 24;
  380. text.color = Color.white;
  381. text.alignment = TextAnchor.MiddleCenter;
  382. // Set text content
  383. string lootText = "🏆 VICTORY! 🏆\n\n";
  384. lootText += "Collecting loot from defeated enemies...\n\n";
  385. int totalGold = 0, totalSilver = 0, totalCopper = 0;
  386. List<string> allItems = new List<string>();
  387. foreach (var enemy in lootableEnemies)
  388. {
  389. totalGold += enemy.goldReward;
  390. totalSilver += enemy.silverReward;
  391. totalCopper += enemy.copperReward;
  392. allItems.AddRange(enemy.dropItems);
  393. lootText += $"💀 {enemy.enemyName}: {enemy.goldReward}g {enemy.silverReward}s {enemy.copperReward}c\n";
  394. foreach (var item in enemy.dropItems)
  395. {
  396. lootText += $" 📦 {item}\n";
  397. }
  398. }
  399. lootText += $"\n💰 Total: {totalGold} gold, {totalSilver} silver, {totalCopper} copper\n";
  400. lootText += $"📦 {allItems.Count} items collected\n\n";
  401. lootText += "Press SPACE to continue...";
  402. text.text = lootText;
  403. // Set text position
  404. var textRect = textObj.GetComponent<RectTransform>();
  405. textRect.anchorMin = Vector2.zero;
  406. textRect.anchorMax = Vector2.one;
  407. textRect.offsetMin = new Vector2(50, 50);
  408. textRect.offsetMax = new Vector2(-50, -50);
  409. // Auto-loot everything
  410. AutoLootAll();
  411. // Wait for space key or 5 seconds
  412. float timer = 0f;
  413. while (timer < 5f && !Input.GetKeyDown(KeyCode.Space))
  414. {
  415. timer += Time.deltaTime;
  416. yield return null;
  417. }
  418. // Cleanup UI
  419. if (tempUI != null)
  420. Destroy(tempUI);
  421. // Complete looting
  422. CompleteLootingProcess();
  423. }
  424. /// <summary>
  425. /// Complete the looting process and trigger the callback
  426. /// </summary>
  427. private void CompleteLootingProcess()
  428. {
  429. isLootingActive = false;
  430. // Hide the loot UI
  431. if (rootElement != null)
  432. rootElement.style.display = DisplayStyle.None;
  433. if (showDebugLogs)
  434. Debug.Log("💰 Looting completed, triggering OnLootingComplete");
  435. OnLootingComplete?.Invoke();
  436. }
  437. /// <summary>
  438. /// Generate loot for a defeated enemy
  439. /// </summary>
  440. private void GenerateEnemyLoot(LootableEnemy lootableEnemy, Character enemyCharacter)
  441. {
  442. // Base currency rewards
  443. lootableEnemy.goldReward = Random.Range(0, baseGoldReward + 1);
  444. lootableEnemy.silverReward = Random.Range(0, baseSilverReward + 1);
  445. lootableEnemy.copperReward = Random.Range(baseCopperReward - 5, baseCopperReward + 10);
  446. // Basic item drops based on enemy type
  447. GenerateBasicDrops(lootableEnemy, enemyCharacter.CharacterName);
  448. // Try to get drops from enemy data if available
  449. TryGetEnemyDataDrops(lootableEnemy, enemyCharacter);
  450. if (showDebugLogs)
  451. {
  452. Debug.Log($"💰 Generated loot for {lootableEnemy.enemyName}: " +
  453. $"{lootableEnemy.goldReward}g {lootableEnemy.silverReward}s {lootableEnemy.copperReward}c, " +
  454. $"{lootableEnemy.dropItems.Count} items");
  455. }
  456. }
  457. /// <summary>
  458. /// Generate basic drops based on enemy name/type
  459. /// </summary>
  460. private void GenerateBasicDrops(LootableEnemy lootableEnemy, string enemyName)
  461. {
  462. string lowerName = enemyName.ToLower();
  463. // Skeleton-type enemies
  464. if (lowerName.Contains("skeleton"))
  465. {
  466. if (Random.Range(0f, 1f) < 0.3f) lootableEnemy.dropItems.Add("Bone");
  467. if (Random.Range(0f, 1f) < 0.2f) lootableEnemy.dropItems.Add("Rusty Sword");
  468. if (Random.Range(0f, 1f) < 0.15f) lootableEnemy.dropItems.Add("Bone Dust");
  469. }
  470. // Bandit-type enemies
  471. else if (lowerName.Contains("bandit") || lowerName.Contains("thief"))
  472. {
  473. if (Random.Range(0f, 1f) < 0.4f) lootableEnemy.dropItems.Add("Thieves' Tools");
  474. if (Random.Range(0f, 1f) < 0.3f) lootableEnemy.dropItems.Add("Rope");
  475. if (Random.Range(0f, 1f) < 0.2f) lootableEnemy.dropItems.Add("Dagger");
  476. // Bandits often have extra coin
  477. lootableEnemy.copperReward += Random.Range(5, 15);
  478. }
  479. // Orc-type enemies
  480. else if (lowerName.Contains("orc") || lowerName.Contains("goblin"))
  481. {
  482. if (Random.Range(0f, 1f) < 0.3f) lootableEnemy.dropItems.Add("Crude Axe");
  483. if (Random.Range(0f, 1f) < 0.25f) lootableEnemy.dropItems.Add("Hide Armor");
  484. if (Random.Range(0f, 1f) < 0.2f) lootableEnemy.dropItems.Add("Iron Ration");
  485. }
  486. // Default/unknown enemies
  487. else
  488. {
  489. if (Random.Range(0f, 1f) < 0.2f) lootableEnemy.dropItems.Add("Leather Scraps");
  490. if (Random.Range(0f, 1f) < 0.15f) lootableEnemy.dropItems.Add("Iron Ration");
  491. }
  492. // Common drops for all enemies
  493. if (Random.Range(0f, 1f) < 0.1f) lootableEnemy.dropItems.Add("Health Potion");
  494. if (Random.Range(0f, 1f) < 0.05f) lootableEnemy.dropItems.Add("Bandage");
  495. }
  496. /// <summary>
  497. /// Try to get drops from EnemyCharacterData if available
  498. /// </summary>
  499. private void TryGetEnemyDataDrops(LootableEnemy lootableEnemy, Character enemyCharacter)
  500. {
  501. // This would integrate with the EnemyCharacterData system
  502. // For now, we'll use the basic drop system above
  503. // TODO: Integrate with EnemyCharacterData.dropTable when available
  504. }
  505. /// <summary>
  506. /// Show the loot UI
  507. /// </summary>
  508. private void ShowLootUI()
  509. {
  510. if (rootElement != null)
  511. {
  512. // Show the UI Toolkit loot interface
  513. rootElement.style.display = DisplayStyle.Flex;
  514. PopulateLootUI();
  515. }
  516. else
  517. {
  518. // Auto-loot everything for now
  519. AutoLootAll();
  520. }
  521. }
  522. /// <summary>
  523. /// Populate the loot UI with available items
  524. /// </summary>
  525. private void PopulateLootUI()
  526. {
  527. if (rootElement == null) return;
  528. // Calculate totals first
  529. int totalGold = 0, totalSilver = 0, totalCopper = 0;
  530. List<string> allItems = new List<string>();
  531. foreach (var enemy in lootableEnemies)
  532. {
  533. totalGold += enemy.goldReward;
  534. totalSilver += enemy.silverReward;
  535. totalCopper += enemy.copperReward;
  536. allItems.AddRange(enemy.dropItems);
  537. }
  538. // Update currency displays with better formatting and tighter spacing
  539. var goldLabel = rootElement.Q<Label>("GoldAmount");
  540. var silverLabel = rootElement.Q<Label>("SilverAmount");
  541. var copperLabel = rootElement.Q<Label>("CopperAmount");
  542. if (goldLabel != null)
  543. {
  544. goldLabel.text = totalGold.ToString();
  545. goldLabel.style.fontSize = 18; // Slightly larger than before but not huge
  546. goldLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
  547. goldLabel.style.marginBottom = 2; // Reduce spacing
  548. goldLabel.style.marginTop = 2;
  549. }
  550. if (silverLabel != null)
  551. {
  552. silverLabel.text = totalSilver.ToString();
  553. silverLabel.style.fontSize = 18;
  554. silverLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
  555. silverLabel.style.marginBottom = 2;
  556. silverLabel.style.marginTop = 2;
  557. }
  558. if (copperLabel != null)
  559. {
  560. copperLabel.text = totalCopper.ToString();
  561. copperLabel.style.fontSize = 18;
  562. copperLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
  563. copperLabel.style.marginBottom = 2;
  564. copperLabel.style.marginTop = 2;
  565. }
  566. // Style the currency text labels to be closer to the numbers
  567. var goldText = rootElement.Q<Label>("GoldText");
  568. var silverText = rootElement.Q<Label>("SilverText");
  569. var copperText = rootElement.Q<Label>("CopperText");
  570. if (goldText != null)
  571. {
  572. goldText.style.fontSize = 12;
  573. goldText.style.marginTop = -2; // Move closer to number
  574. goldText.style.marginBottom = 8; // Add space after currency section
  575. }
  576. if (silverText != null)
  577. {
  578. silverText.style.fontSize = 12;
  579. silverText.style.marginTop = -2;
  580. silverText.style.marginBottom = 8;
  581. }
  582. if (copperText != null)
  583. {
  584. copperText.style.fontSize = 12;
  585. copperText.style.marginTop = -2;
  586. copperText.style.marginBottom = 8;
  587. }
  588. // Also style the currency icons to be smaller
  589. var goldIcon = rootElement.Q<Label>("GoldIcon");
  590. var silverIcon = rootElement.Q<Label>("SilverIcon");
  591. var copperIcon = rootElement.Q<Label>("CopperIcon");
  592. if (goldIcon != null) goldIcon.style.fontSize = 14;
  593. if (silverIcon != null) silverIcon.style.fontSize = 14;
  594. if (copperIcon != null) copperIcon.style.fontSize = 14;
  595. // Update item count
  596. var itemCountLabel = rootElement.Q<Label>("ItemCount");
  597. if (itemCountLabel != null)
  598. itemCountLabel.text = $"{allItems.Count} items";
  599. // Populate enemy loot sections
  600. var enemyLootContainer = rootElement.Q<VisualElement>("EnemyLootContainer");
  601. if (enemyLootContainer != null)
  602. {
  603. enemyLootContainer.Clear();
  604. foreach (var enemy in lootableEnemies)
  605. {
  606. var enemySection = new VisualElement();
  607. enemySection.AddToClassList("enemy-loot-section");
  608. // Enemy header
  609. var enemyHeader = new Label($"💀 {enemy.enemyName}");
  610. enemyHeader.AddToClassList("enemy-name");
  611. enemySection.Add(enemyHeader);
  612. // Enemy currency
  613. if (enemy.goldReward > 0 || enemy.silverReward > 0 || enemy.copperReward > 0)
  614. {
  615. var currencyContainer = new VisualElement();
  616. currencyContainer.AddToClassList("enemy-currency");
  617. if (enemy.goldReward > 0)
  618. {
  619. var enemyGoldLabel = new Label($"🪙 {enemy.goldReward}");
  620. enemyGoldLabel.AddToClassList("currency-gold");
  621. currencyContainer.Add(enemyGoldLabel);
  622. }
  623. if (enemy.silverReward > 0)
  624. {
  625. var enemySilverLabel = new Label($"🪙 {enemy.silverReward}");
  626. enemySilverLabel.AddToClassList("currency-silver");
  627. currencyContainer.Add(enemySilverLabel);
  628. }
  629. if (enemy.copperReward > 0)
  630. {
  631. var enemyCopperLabel = new Label($"🪙 {enemy.copperReward}");
  632. enemyCopperLabel.AddToClassList("currency-copper");
  633. currencyContainer.Add(enemyCopperLabel);
  634. }
  635. enemySection.Add(currencyContainer);
  636. }
  637. // Enemy items
  638. if (enemy.dropItems != null && enemy.dropItems.Count > 0)
  639. {
  640. var itemsContainer = new VisualElement();
  641. itemsContainer.AddToClassList("enemy-items");
  642. foreach (var item in enemy.dropItems)
  643. {
  644. var itemLabel = new Label($"📦 {item}");
  645. itemLabel.AddToClassList("item-entry");
  646. itemsContainer.Add(itemLabel);
  647. }
  648. enemySection.Add(itemsContainer);
  649. }
  650. enemyLootContainer.Add(enemySection);
  651. }
  652. }
  653. // Populate the total items list scrollview with better visibility
  654. var itemsListContainer = rootElement.Q<ScrollView>("ItemsList");
  655. if (itemsListContainer != null)
  656. {
  657. itemsListContainer.Clear();
  658. // Set scrollview properties for better visibility and containment
  659. itemsListContainer.style.minHeight = 80;
  660. itemsListContainer.style.maxHeight = 150;
  661. itemsListContainer.style.backgroundColor = new Color(0.15f, 0.15f, 0.25f, 0.9f);
  662. itemsListContainer.style.borderTopWidth = 2;
  663. itemsListContainer.style.borderBottomWidth = 2;
  664. itemsListContainer.style.borderLeftWidth = 2;
  665. itemsListContainer.style.borderRightWidth = 2;
  666. itemsListContainer.style.borderTopColor = new Color(0.6f, 0.6f, 0.8f, 0.8f);
  667. itemsListContainer.style.borderBottomColor = new Color(0.6f, 0.6f, 0.8f, 0.8f);
  668. itemsListContainer.style.borderLeftColor = new Color(0.6f, 0.6f, 0.8f, 0.8f);
  669. itemsListContainer.style.borderRightColor = new Color(0.6f, 0.6f, 0.8f, 0.8f);
  670. itemsListContainer.style.borderTopLeftRadius = 8;
  671. itemsListContainer.style.borderTopRightRadius = 8;
  672. itemsListContainer.style.borderBottomLeftRadius = 8;
  673. itemsListContainer.style.borderBottomRightRadius = 8;
  674. itemsListContainer.style.paddingTop = 8;
  675. itemsListContainer.style.paddingBottom = 8;
  676. itemsListContainer.style.paddingLeft = 8;
  677. itemsListContainer.style.paddingRight = 8;
  678. itemsListContainer.style.marginTop = 5;
  679. itemsListContainer.style.marginBottom = 10;
  680. itemsListContainer.style.marginLeft = 5;
  681. itemsListContainer.style.marginRight = 5;
  682. if (allItems.Count > 0)
  683. {
  684. foreach (var item in allItems)
  685. {
  686. var itemEntry = new Label($"📦 {item}");
  687. itemEntry.AddToClassList("total-item-entry");
  688. itemEntry.style.fontSize = 14;
  689. itemEntry.style.color = Color.white;
  690. itemEntry.style.marginBottom = 2;
  691. itemEntry.style.paddingLeft = 6;
  692. itemEntry.style.paddingRight = 6;
  693. itemEntry.style.paddingTop = 3;
  694. itemEntry.style.paddingBottom = 3;
  695. itemEntry.style.backgroundColor = new Color(0.25f, 0.35f, 0.45f, 0.8f);
  696. itemEntry.style.borderTopLeftRadius = 4;
  697. itemEntry.style.borderTopRightRadius = 4;
  698. itemEntry.style.borderBottomLeftRadius = 4;
  699. itemEntry.style.borderBottomRightRadius = 4;
  700. itemEntry.style.borderTopWidth = 1;
  701. itemEntry.style.borderBottomWidth = 1;
  702. itemEntry.style.borderLeftWidth = 1;
  703. itemEntry.style.borderRightWidth = 1;
  704. itemEntry.style.borderTopColor = new Color(0.7f, 0.7f, 0.9f, 0.6f);
  705. itemEntry.style.borderBottomColor = new Color(0.7f, 0.7f, 0.9f, 0.6f);
  706. itemEntry.style.borderLeftColor = new Color(0.7f, 0.7f, 0.9f, 0.6f);
  707. itemEntry.style.borderRightColor = new Color(0.7f, 0.7f, 0.9f, 0.6f);
  708. itemsListContainer.Add(itemEntry);
  709. }
  710. }
  711. else
  712. {
  713. var noItemsLabel = new Label("No items collected");
  714. noItemsLabel.style.fontSize = 14;
  715. noItemsLabel.style.color = new Color(0.7f, 0.7f, 0.7f, 1f);
  716. noItemsLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
  717. noItemsLabel.style.paddingTop = 20;
  718. itemsListContainer.Add(noItemsLabel);
  719. }
  720. }
  721. // Add informational message about item distribution
  722. if (allItems.Count > 0)
  723. {
  724. var distributionHint = rootElement.Q<Label>("DistributionHint");
  725. if (distributionHint == null)
  726. {
  727. distributionHint = new Label();
  728. distributionHint.name = "DistributionHint";
  729. // Find a good place to add it (after the items section)
  730. var itemsSection = rootElement.Q<VisualElement>("ItemsSection");
  731. if (itemsSection != null)
  732. {
  733. itemsSection.Add(distributionHint);
  734. }
  735. else
  736. {
  737. rootElement.Add(distributionHint);
  738. }
  739. }
  740. if (enablePlayerItemSelection && !takeAllPressed)
  741. {
  742. distributionHint.text = "💡 Click individual items above to choose which character gets them, or use 'Take All' for automatic distribution.";
  743. }
  744. else
  745. {
  746. distributionHint.text = "📋 Items will be distributed automatically among surviving party members.";
  747. }
  748. distributionHint.style.fontSize = 12;
  749. distributionHint.style.color = new Color(0.8f, 0.8f, 0.9f, 0.9f);
  750. distributionHint.style.unityTextAlign = TextAnchor.MiddleCenter;
  751. distributionHint.style.marginTop = 10;
  752. distributionHint.style.marginBottom = 5;
  753. distributionHint.style.paddingLeft = 10;
  754. distributionHint.style.paddingRight = 10;
  755. distributionHint.style.whiteSpace = WhiteSpace.Normal;
  756. }
  757. }
  758. /// <summary>
  759. /// Auto-loot all items and currency with optional player selection
  760. /// </summary>
  761. private void AutoLootAll()
  762. {
  763. int totalGold = 0, totalSilver = 0, totalCopper = 0;
  764. List<string> allItems = new List<string>();
  765. foreach (var enemy in lootableEnemies)
  766. {
  767. if (!enemy.hasBeenLooted)
  768. {
  769. totalGold += enemy.goldReward;
  770. totalSilver += enemy.silverReward;
  771. totalCopper += enemy.copperReward;
  772. allItems.AddRange(enemy.dropItems);
  773. enemy.hasBeenLooted = true;
  774. }
  775. }
  776. // Always distribute currency automatically
  777. DistributeCurrency(totalGold, totalSilver, totalCopper);
  778. // Handle item distribution based on settings
  779. // Show item distribution UI if:
  780. // 1. Player item selection is enabled
  781. // 2. There are items to distribute
  782. // 3. We're NOT in "Take All" mode (which forces auto-distribution)
  783. if (enablePlayerItemSelection && allItems.Count > 0 && !takeAllPressed)
  784. {
  785. ShowItemDistributionUI(allItems);
  786. }
  787. else
  788. {
  789. // Auto-distribute items
  790. DistributeItemsAutomatically(allItems);
  791. if (showDebugLogs)
  792. {
  793. Debug.Log($"💰 Auto-looted: {totalGold}g {totalSilver}s {totalCopper}c and {allItems.Count} items");
  794. }
  795. // End looting phase
  796. FinishLooting();
  797. }
  798. }
  799. /// <summary>
  800. /// Distribute looted rewards among surviving players
  801. /// </summary>
  802. private void DistributeRewards(int gold, int silver, int copper, List<string> items)
  803. {
  804. // Get surviving players
  805. var survivingPlayers = GetSurvivingPlayers();
  806. if (survivingPlayers.Count == 0)
  807. {
  808. Debug.LogWarning("💰 No surviving players to distribute loot to!");
  809. return;
  810. }
  811. // Distribute currency evenly
  812. int goldPerPlayer = gold / survivingPlayers.Count;
  813. int silverPerPlayer = silver / survivingPlayers.Count;
  814. int copperPerPlayer = copper / survivingPlayers.Count;
  815. // Handle remainder
  816. int goldRemainder = gold % survivingPlayers.Count;
  817. int silverRemainder = silver % survivingPlayers.Count;
  818. int copperRemainder = copper % survivingPlayers.Count;
  819. for (int i = 0; i < survivingPlayers.Count; i++)
  820. {
  821. var player = survivingPlayers[i];
  822. Character playerCharacter = player.GetComponent<Character>();
  823. if (playerCharacter == null) continue;
  824. // Get player's bank (assuming it exists)
  825. var bank = playerCharacter.GetComponent<Bank>();
  826. if (bank != null)
  827. {
  828. bank.gold += goldPerPlayer + (i < goldRemainder ? 1 : 0);
  829. bank.silver += silverPerPlayer + (i < silverRemainder ? 1 : 0);
  830. bank.copper += copperPerPlayer + (i < copperRemainder ? 1 : 0);
  831. }
  832. // Distribute items (simple round-robin for now)
  833. var inventory = playerCharacter.GetComponent<Inventory>();
  834. if (inventory != null)
  835. {
  836. for (int j = i; j < items.Count; j += survivingPlayers.Count)
  837. {
  838. // TODO: Create proper Item objects instead of strings
  839. // For now, add to string-based inventory if available
  840. AddItemToPlayer(playerCharacter, items[j]);
  841. }
  842. }
  843. if (showDebugLogs)
  844. {
  845. int finalGold = goldPerPlayer + (i < goldRemainder ? 1 : 0);
  846. int finalSilver = silverPerPlayer + (i < silverRemainder ? 1 : 0);
  847. int finalCopper = copperPerPlayer + (i < copperRemainder ? 1 : 0);
  848. Debug.Log($"💰 {playerCharacter.CharacterName} received: {finalGold}g {finalSilver}s {finalCopper}c");
  849. }
  850. }
  851. }
  852. /// <summary>
  853. /// Distribute currency to players (separated from items for flexibility)
  854. /// </summary>
  855. private void DistributeCurrency(int gold, int silver, int copper)
  856. {
  857. var survivingPlayers = GetSurvivingPlayers();
  858. if (survivingPlayers.Count == 0)
  859. {
  860. return;
  861. }
  862. // Distribute currency evenly
  863. int goldPerPlayer = gold / survivingPlayers.Count;
  864. int silverPerPlayer = silver / survivingPlayers.Count;
  865. int copperPerPlayer = copper / survivingPlayers.Count;
  866. // Handle remainder
  867. int goldRemainder = gold % survivingPlayers.Count;
  868. int silverRemainder = silver % survivingPlayers.Count;
  869. int copperRemainder = copper % survivingPlayers.Count;
  870. for (int i = 0; i < survivingPlayers.Count; i++)
  871. {
  872. var player = survivingPlayers[i];
  873. Character playerCharacter = player.GetComponent<Character>();
  874. if (playerCharacter == null) continue;
  875. // Get player's bank
  876. var bank = playerCharacter.GetComponent<Bank>();
  877. if (bank != null)
  878. {
  879. bank.gold += goldPerPlayer + (i < goldRemainder ? 1 : 0);
  880. bank.silver += silverPerPlayer + (i < silverRemainder ? 1 : 0);
  881. bank.copper += copperPerPlayer + (i < copperRemainder ? 1 : 0);
  882. if (showDebugLogs)
  883. {
  884. int finalGold = goldPerPlayer + (i < goldRemainder ? 1 : 0);
  885. int finalSilver = silverPerPlayer + (i < silverRemainder ? 1 : 0);
  886. int finalCopper = copperPerPlayer + (i < copperRemainder ? 1 : 0);
  887. }
  888. }
  889. }
  890. }
  891. /// <summary>
  892. /// Show UI for manually assigning items to players
  893. /// </summary>
  894. private void ShowItemDistributionUI(List<string> items)
  895. {
  896. var survivingPlayers = GetSurvivingPlayers();
  897. if (survivingPlayers.Count == 0)
  898. {
  899. FinishLooting();
  900. return;
  901. }
  902. // For now, create a simple distribution UI overlay
  903. var distributionOverlay = new VisualElement();
  904. distributionOverlay.name = "ItemDistributionOverlay";
  905. distributionOverlay.style.position = Position.Absolute;
  906. distributionOverlay.style.top = 0;
  907. distributionOverlay.style.left = 0;
  908. distributionOverlay.style.right = 0;
  909. distributionOverlay.style.bottom = 0;
  910. distributionOverlay.style.backgroundColor = new Color(0, 0, 0, 0.8f);
  911. distributionOverlay.style.justifyContent = Justify.Center;
  912. distributionOverlay.style.alignItems = Align.Center;
  913. // Create distribution panel
  914. var panel = new VisualElement();
  915. panel.style.backgroundColor = new Color(0.15f, 0.15f, 0.25f, 0.95f);
  916. panel.style.borderTopWidth = 2;
  917. panel.style.borderBottomWidth = 2;
  918. panel.style.borderLeftWidth = 2;
  919. panel.style.borderRightWidth = 2;
  920. panel.style.borderTopColor = Color.yellow;
  921. panel.style.borderBottomColor = Color.yellow;
  922. panel.style.borderLeftColor = Color.yellow;
  923. panel.style.borderRightColor = Color.yellow;
  924. panel.style.borderTopLeftRadius = 10;
  925. panel.style.borderTopRightRadius = 10;
  926. panel.style.borderBottomLeftRadius = 10;
  927. panel.style.borderBottomRightRadius = 10;
  928. panel.style.paddingTop = 20;
  929. panel.style.paddingBottom = 20;
  930. panel.style.paddingLeft = 20;
  931. panel.style.paddingRight = 20;
  932. panel.style.width = new Length(90, LengthUnit.Percent);
  933. panel.style.maxWidth = 600;
  934. panel.style.maxHeight = new Length(80, LengthUnit.Percent);
  935. // Title
  936. var title = new Label("Distribute Items to Players");
  937. title.style.fontSize = 24;
  938. title.style.color = Color.yellow;
  939. title.style.unityTextAlign = TextAnchor.MiddleCenter;
  940. title.style.marginBottom = 20;
  941. panel.Add(title);
  942. // Scroll view for items
  943. var scrollView = new ScrollView();
  944. scrollView.style.flexGrow = 1;
  945. scrollView.style.marginBottom = 15;
  946. // Create item distribution entries
  947. foreach (var item in items)
  948. {
  949. var itemRow = CreateItemDistributionRow(item, survivingPlayers);
  950. scrollView.Add(itemRow);
  951. }
  952. panel.Add(scrollView);
  953. // Buttons
  954. var buttonContainer = new VisualElement();
  955. buttonContainer.style.flexDirection = FlexDirection.Row;
  956. buttonContainer.style.justifyContent = Justify.SpaceAround;
  957. var autoDistributeBtn = new Button(() =>
  958. {
  959. DistributeItemsAutomatically(items);
  960. rootElement.Remove(distributionOverlay);
  961. FinishLooting();
  962. });
  963. autoDistributeBtn.text = "Auto Distribute";
  964. autoDistributeBtn.style.fontSize = 14;
  965. var confirmBtn = new Button(() =>
  966. {
  967. DistributeItemsManually(items, survivingPlayers);
  968. rootElement.Remove(distributionOverlay);
  969. FinishLooting();
  970. });
  971. confirmBtn.text = "Confirm Distribution";
  972. confirmBtn.style.fontSize = 14;
  973. buttonContainer.Add(autoDistributeBtn);
  974. buttonContainer.Add(confirmBtn);
  975. panel.Add(buttonContainer);
  976. distributionOverlay.Add(panel);
  977. rootElement.Add(distributionOverlay);
  978. }
  979. /// <summary>
  980. /// Create a row for item distribution with player selection buttons
  981. /// </summary>
  982. private VisualElement CreateItemDistributionRow(string itemName, List<GameObject> players)
  983. {
  984. var row = new VisualElement();
  985. row.style.flexDirection = FlexDirection.Row;
  986. row.style.alignItems = Align.Center;
  987. row.style.marginBottom = 10;
  988. row.style.paddingTop = 8;
  989. row.style.paddingBottom = 8;
  990. row.style.paddingLeft = 12;
  991. row.style.paddingRight = 12;
  992. row.style.backgroundColor = new Color(0.2f, 0.2f, 0.3f, 0.9f);
  993. row.style.borderTopLeftRadius = 8;
  994. row.style.borderTopRightRadius = 8;
  995. row.style.borderBottomLeftRadius = 8;
  996. row.style.borderBottomRightRadius = 8;
  997. row.style.borderTopWidth = 1;
  998. row.style.borderBottomWidth = 1;
  999. row.style.borderLeftWidth = 1;
  1000. row.style.borderRightWidth = 1;
  1001. row.style.borderTopColor = new Color(0.5f, 0.5f, 0.6f, 0.8f);
  1002. row.style.borderBottomColor = new Color(0.5f, 0.5f, 0.6f, 0.8f);
  1003. row.style.borderLeftColor = new Color(0.5f, 0.5f, 0.6f, 0.8f);
  1004. row.style.borderRightColor = new Color(0.5f, 0.5f, 0.6f, 0.8f);
  1005. // Item name with better styling
  1006. var itemLabel = new Label($"📦 {itemName}");
  1007. itemLabel.style.fontSize = 15;
  1008. itemLabel.style.color = Color.white;
  1009. itemLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
  1010. itemLabel.style.width = new Length(35, LengthUnit.Percent);
  1011. itemLabel.style.unityTextAlign = TextAnchor.MiddleLeft;
  1012. row.Add(itemLabel);
  1013. // "Assign to:" label
  1014. var assignLabel = new Label("→");
  1015. assignLabel.style.fontSize = 14;
  1016. assignLabel.style.color = Color.yellow;
  1017. assignLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
  1018. assignLabel.style.width = 20;
  1019. assignLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
  1020. row.Add(assignLabel);
  1021. // Player selection buttons
  1022. var buttonContainer = new VisualElement();
  1023. buttonContainer.style.flexDirection = FlexDirection.Row;
  1024. buttonContainer.style.flexGrow = 1;
  1025. buttonContainer.style.justifyContent = Justify.SpaceAround;
  1026. int selectedPlayerIndex = selectedPlayerForItem.ContainsKey(itemName) ? selectedPlayerForItem[itemName] : -1;
  1027. // Store button references for updating
  1028. var playerButtons = new List<Button>();
  1029. for (int i = 0; i < players.Count; i++)
  1030. {
  1031. var player = players[i];
  1032. var character = player.GetComponent<Character>();
  1033. if (character == null) continue;
  1034. int playerIndex = i; // Capture for closure
  1035. var playerBtn = new Button(() =>
  1036. {
  1037. selectedPlayerForItem[itemName] = playerIndex;
  1038. // Update all buttons in this row to show selection
  1039. UpdatePlayerButtonVisuals(playerButtons, playerIndex);
  1040. });
  1041. playerBtn.text = character.CharacterName;
  1042. playerBtn.style.fontSize = 13;
  1043. playerBtn.style.flexGrow = 1;
  1044. playerBtn.style.marginLeft = 3;
  1045. playerBtn.style.marginRight = 3;
  1046. playerBtn.style.paddingTop = 8;
  1047. playerBtn.style.paddingBottom = 8;
  1048. playerBtn.style.paddingLeft = 6;
  1049. playerBtn.style.paddingRight = 6;
  1050. playerBtn.style.borderTopLeftRadius = 5;
  1051. playerBtn.style.borderTopRightRadius = 5;
  1052. playerBtn.style.borderBottomLeftRadius = 5;
  1053. playerBtn.style.borderBottomRightRadius = 5;
  1054. playerBtn.style.borderTopWidth = 2;
  1055. playerBtn.style.borderBottomWidth = 2;
  1056. playerBtn.style.borderLeftWidth = 2;
  1057. playerBtn.style.borderRightWidth = 2;
  1058. // Set initial visual state
  1059. if (i == selectedPlayerIndex)
  1060. {
  1061. // Selected state
  1062. playerBtn.style.backgroundColor = new Color(0.2f, 0.8f, 0.2f, 0.9f);
  1063. playerBtn.style.borderTopColor = Color.green;
  1064. playerBtn.style.borderBottomColor = Color.green;
  1065. playerBtn.style.borderLeftColor = Color.green;
  1066. playerBtn.style.borderRightColor = Color.green;
  1067. playerBtn.style.color = Color.white;
  1068. }
  1069. else
  1070. {
  1071. // Unselected state
  1072. playerBtn.style.backgroundColor = new Color(0.3f, 0.3f, 0.4f, 0.8f);
  1073. playerBtn.style.borderTopColor = new Color(0.6f, 0.6f, 0.7f, 0.8f);
  1074. playerBtn.style.borderBottomColor = new Color(0.6f, 0.6f, 0.7f, 0.8f);
  1075. playerBtn.style.borderLeftColor = new Color(0.6f, 0.6f, 0.7f, 0.8f);
  1076. playerBtn.style.borderRightColor = new Color(0.6f, 0.6f, 0.7f, 0.8f);
  1077. playerBtn.style.color = new Color(0.9f, 0.9f, 0.9f, 0.9f);
  1078. }
  1079. playerButtons.Add(playerBtn);
  1080. buttonContainer.Add(playerBtn);
  1081. }
  1082. row.Add(buttonContainer);
  1083. return row;
  1084. }
  1085. /// <summary>
  1086. /// Update visual state of player selection buttons
  1087. /// </summary>
  1088. private void UpdatePlayerButtonVisuals(List<Button> buttons, int selectedIndex)
  1089. {
  1090. for (int i = 0; i < buttons.Count; i++)
  1091. {
  1092. var button = buttons[i];
  1093. if (i == selectedIndex)
  1094. {
  1095. // Selected state - green highlight
  1096. button.style.backgroundColor = new Color(0.2f, 0.8f, 0.2f, 0.9f);
  1097. button.style.borderTopColor = Color.green;
  1098. button.style.borderBottomColor = Color.green;
  1099. button.style.borderLeftColor = Color.green;
  1100. button.style.borderRightColor = Color.green;
  1101. button.style.color = Color.white;
  1102. }
  1103. else
  1104. {
  1105. // Unselected state - neutral gray
  1106. button.style.backgroundColor = new Color(0.3f, 0.3f, 0.4f, 0.8f);
  1107. button.style.borderTopColor = new Color(0.6f, 0.6f, 0.7f, 0.8f);
  1108. button.style.borderBottomColor = new Color(0.6f, 0.6f, 0.7f, 0.8f);
  1109. button.style.borderLeftColor = new Color(0.6f, 0.6f, 0.7f, 0.8f);
  1110. button.style.borderRightColor = new Color(0.6f, 0.6f, 0.7f, 0.8f);
  1111. button.style.color = new Color(0.9f, 0.9f, 0.9f, 0.9f);
  1112. }
  1113. }
  1114. }
  1115. /// <summary>
  1116. /// Distribute items automatically using round-robin
  1117. /// </summary>
  1118. private void DistributeItemsAutomatically(List<string> items)
  1119. {
  1120. var survivingPlayers = GetSurvivingPlayers();
  1121. if (survivingPlayers.Count == 0) return;
  1122. for (int i = 0; i < items.Count; i++)
  1123. {
  1124. var player = survivingPlayers[i % survivingPlayers.Count];
  1125. var character = player.GetComponent<Character>();
  1126. if (character != null)
  1127. {
  1128. AddItemToPlayer(character, items[i]);
  1129. }
  1130. }
  1131. if (showDebugLogs)
  1132. {
  1133. Debug.Log($"💰 Auto-distributed {items.Count} items among {survivingPlayers.Count} players");
  1134. }
  1135. }
  1136. /// <summary>
  1137. /// Distribute items based on manual player selection
  1138. /// </summary>
  1139. private void DistributeItemsManually(List<string> items, List<GameObject> players)
  1140. {
  1141. foreach (var item in items)
  1142. {
  1143. if (selectedPlayerForItem.ContainsKey(item))
  1144. {
  1145. int playerIndex = selectedPlayerForItem[item];
  1146. if (playerIndex >= 0 && playerIndex < players.Count)
  1147. {
  1148. var character = players[playerIndex].GetComponent<Character>();
  1149. if (character != null)
  1150. {
  1151. AddItemToPlayer(character, item);
  1152. if (showDebugLogs)
  1153. {
  1154. Debug.Log($"💰 Manually distributed {item} to {character.CharacterName}");
  1155. }
  1156. }
  1157. }
  1158. }
  1159. else
  1160. {
  1161. // If no selection was made, give to first player
  1162. var character = players[0].GetComponent<Character>();
  1163. if (character != null)
  1164. {
  1165. AddItemToPlayer(character, item);
  1166. if (showDebugLogs)
  1167. {
  1168. Debug.Log($"💰 {item} given to {character.CharacterName} (no selection made)");
  1169. }
  1170. }
  1171. }
  1172. }
  1173. // Clear selections for next battle
  1174. selectedPlayerForItem.Clear();
  1175. }
  1176. /// <summary>
  1177. /// Add an item to a player's inventory
  1178. /// </summary>
  1179. private void AddItemToPlayer(Character player, string itemName)
  1180. {
  1181. // Try to add to CombatDataTransfer session data
  1182. if (CombatDataTransfer.HasValidSession())
  1183. {
  1184. var session = CombatDataTransfer.GetCurrentSession();
  1185. var playerData = session.playerTeam.Find(p =>
  1186. p.characterName == player.CharacterName ||
  1187. player.CharacterName.StartsWith(p.characterName));
  1188. if (playerData != null)
  1189. {
  1190. if (playerData.miscItems == null)
  1191. playerData.miscItems = new List<string>();
  1192. playerData.miscItems.Add(itemName);
  1193. if (showDebugLogs)
  1194. Debug.Log($"💰 Added {itemName} to {player.CharacterName}'s inventory");
  1195. return;
  1196. }
  1197. }
  1198. // Fallback: log that item would be added
  1199. if (showDebugLogs)
  1200. Debug.Log($"💰 Would add {itemName} to {player.CharacterName} (no inventory system found)");
  1201. }
  1202. /// <summary>
  1203. /// Get list of surviving player characters
  1204. /// </summary>
  1205. private List<GameObject> GetSurvivingPlayers()
  1206. {
  1207. var gameManager = GameManager.Instance;
  1208. if (gameManager == null) return new List<GameObject>();
  1209. return gameManager.playerCharacters
  1210. .Where(p => p != null)
  1211. .Where(p =>
  1212. {
  1213. var character = p.GetComponent<Character>();
  1214. return character != null && !character.IsDead;
  1215. })
  1216. .ToList();
  1217. }
  1218. /// <summary>
  1219. /// Complete the looting phase
  1220. /// </summary>
  1221. private void FinishLooting()
  1222. {
  1223. isLootingActive = false;
  1224. if (rootElement != null)
  1225. rootElement.style.display = DisplayStyle.None;
  1226. OnLootingComplete?.Invoke();
  1227. if (showDebugLogs)
  1228. Debug.Log("💰 Looting phase completed");
  1229. }
  1230. /// <summary>
  1231. /// Skip looting and proceed to battle end
  1232. /// </summary>
  1233. public void SkipLooting()
  1234. {
  1235. if (showDebugLogs)
  1236. Debug.Log("💰 Skipping looting phase");
  1237. FinishLooting();
  1238. }
  1239. /// <summary>
  1240. /// Check if all enemies have been looted
  1241. /// </summary>
  1242. public bool AllEnemiesLooted()
  1243. {
  1244. return lootableEnemies.All(e => e.hasBeenLooted);
  1245. }
  1246. /// <summary>
  1247. /// Get total weight of all available loot
  1248. /// </summary>
  1249. public int GetTotalLootWeight()
  1250. {
  1251. // TODO: Implement when item weight system is added
  1252. return lootableEnemies.Sum(e => e.dropItems.Count); // Placeholder: 1 weight per item
  1253. }
  1254. /// <summary>
  1255. /// Get total value of all available loot in copper
  1256. /// </summary>
  1257. public int GetTotalLootValue()
  1258. {
  1259. int totalValue = 0;
  1260. foreach (var enemy in lootableEnemies)
  1261. {
  1262. totalValue += enemy.goldReward * 100; // 1 gold = 100 copper
  1263. totalValue += enemy.silverReward * 10; // 1 silver = 10 copper
  1264. totalValue += enemy.copperReward;
  1265. // TODO: Add item values when item system is integrated
  1266. }
  1267. return totalValue;
  1268. }
  1269. }