CharacterUIController.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using DamageNumbersPro;
  4. using System.Collections;
  5. public class CharacterUIController : MonoBehaviour
  6. {
  7. public Slider hpSlider;
  8. public Slider fatigueSlider;
  9. public Slider expSlider;
  10. public GameObject skillPanel;
  11. public Transform skillListContainer;
  12. public GameObject skillButtonPrefab;
  13. public GameObject inventoryPanel; // Panel displaying character inventory
  14. public InventoryUIController inventoryUIController; // Reference to inventory UI controller
  15. public Image characterIcon;
  16. public Button attackButton;
  17. public Button repeatActionButton;
  18. public Button openSkillsButton;
  19. public Button openInventoryButton; // Button to open character inventory
  20. public Image cooldownOverlay;
  21. public FirstPersonWeapon assignedWeapon;
  22. public CharacterInGroup character;
  23. public CharacterInGroup Character => character;
  24. public DamageNumber damageUIPrefab; // à assigner dans l’inspector (UI)
  25. public RectTransform damageSpawnPoint;
  26. public void Setup(CharacterInGroup chara, FirstPersonWeapon weapon)
  27. {
  28. character = chara;
  29. assignedWeapon = weapon;
  30. // Initialisation des sliders
  31. if (hpSlider != null)
  32. {
  33. hpSlider.maxValue = character.maxHP;
  34. hpSlider.value = character.currentHP;
  35. }
  36. if (fatigueSlider != null)
  37. {
  38. fatigueSlider.maxValue = character.maxFatigue;
  39. fatigueSlider.value = character.currentFatigue;
  40. }
  41. if (expSlider != null)
  42. {
  43. expSlider.maxValue = 100; // ou prochain seuil de level
  44. expSlider.value = character.experience;
  45. }
  46. // Bind des boutons
  47. if (attackButton != null)
  48. attackButton.onClick.AddListener(OnAttack);
  49. if (repeatActionButton != null)
  50. repeatActionButton.onClick.AddListener(OnRepeat);
  51. if (openSkillsButton != null)
  52. openSkillsButton.onClick.AddListener(ToggleSkillPanel);
  53. if (openInventoryButton != null)
  54. openInventoryButton.onClick.AddListener(OnOpenInventory);
  55. // Enregistrement dans l'UIUpdater
  56. UIUpdater.Instance?.Register(character, this);
  57. PopulateSkillList();
  58. if (cooldownOverlay != null)
  59. {
  60. cooldownOverlay.gameObject.SetActive(false);
  61. }
  62. Debug.Log($"[UI Setup] {character.characterName} - HP: {character.currentHP}/{character.maxHP}, Fatigue: {character.currentFatigue}/{character.maxFatigue}");
  63. }
  64. public void ShowDamageOnCard(int amount)
  65. {
  66. if (damageUIPrefab != null && damageSpawnPoint != null)
  67. {
  68. Debug.Log($"[Damage UI] {character.characterName} subit {amount} dégâts");
  69. damageUIPrefab.SpawnGUI(damageSpawnPoint, Vector2.zero, amount);
  70. }
  71. else
  72. {
  73. Debug.LogWarning("Damage UI prefab ou spawn point manquant pour " + character.characterName);
  74. }
  75. }
  76. void PopulateSkillList()
  77. {
  78. foreach (Transform child in skillListContainer)
  79. Destroy(child.gameObject);
  80. foreach (var skill in character.learnedSkills)
  81. {
  82. SkillData data = skill.GetData();
  83. if (data == null) continue;
  84. var btnObj = Instantiate(skillButtonPrefab, skillListContainer);
  85. btnObj.transform.Find("Image").GetComponent<Image>().sprite = data.icon;
  86. Button btn = btnObj.GetComponent<Button>();
  87. if (btn != null)
  88. {
  89. // Capture la compétence associée
  90. SkillData capturedSkill = data;
  91. btn.onClick.AddListener(() => OnSkillButtonClicked(capturedSkill));
  92. }
  93. }
  94. }
  95. void OnAttack()
  96. {
  97. Debug.Log(character.characterName + " attaque ! - CHARUICONTR");
  98. // Check if character has no stamina - 80% miss chance
  99. if (character.currentFatigue <= 0)
  100. {
  101. if (Random.value < 0.8f) // 80% chance to miss
  102. {
  103. Debug.Log($"[Combat] {character.characterName} est trop fatigué et rate son attaque !");
  104. DisableButtonsTemporarily(5f);
  105. return;
  106. }
  107. }
  108. // 30% chance to consume stamina when attacking
  109. if (Random.value < 0.3f && character.currentFatigue > 0)
  110. {
  111. character.currentFatigue = Mathf.Max(0, character.currentFatigue - 5);
  112. UIUpdater.Instance?.UpdateCharacterFatigue(character);
  113. Debug.Log($"[Combat] {character.characterName} consomme 5 stamina en attaquant");
  114. }
  115. character.lastAction = ActionType.Attack;
  116. assignedWeapon?.TriggerAttack();
  117. DisableButtonsTemporarily(5f);
  118. }
  119. void OnSkillButtonClicked(SkillData skillData)
  120. {
  121. Debug.Log($"Compétence sélectionnée : {skillData.skillName}");
  122. // Check if character has enough stamina to cast skill
  123. int staminaCost = 15; // Default stamina cost for skills
  124. if (character.currentFatigue < staminaCost)
  125. {
  126. Debug.Log($"[Combat] {character.characterName} n'a pas assez de stamina pour utiliser {skillData.skillName} !");
  127. return;
  128. }
  129. // Consume stamina
  130. character.currentFatigue = Mathf.Max(0, character.currentFatigue - staminaCost);
  131. UIUpdater.Instance?.UpdateCharacterFatigue(character);
  132. Debug.Log($"[Combat] {character.characterName} consomme {staminaCost} stamina pour {skillData.skillName}");
  133. if (skillData.skillName == "Boule de Feu")
  134. {
  135. FindFirstObjectByType<SpellCastingManager>()?.StartFireballCasting(skillData.icon.texture);
  136. character.lastAction = ActionType.UseSkill;
  137. character.lastSkillName = skillData.skillName;
  138. }
  139. else
  140. {
  141. Debug.Log($"Action pour {skillData.skillName} non encore implémentée.");
  142. }
  143. DisableButtonsTemporarily(5f);
  144. }
  145. void OnRepeat()
  146. {
  147. switch (character.lastAction)
  148. {
  149. case ActionType.Attack:
  150. Debug.Log($"{character.characterName} répète : Attaque !");
  151. OnAttack();
  152. return; // OnAttack already calls DisableButtonsTemporarily
  153. case ActionType.UseSkill:
  154. Debug.Log($"{character.characterName} répète : Skill {character.lastSkillName}");
  155. // Find the skill and use it again
  156. var learnedSkill = character.learnedSkills.Find(s => s.GetData()?.skillName == character.lastSkillName);
  157. if (learnedSkill != null)
  158. {
  159. var skillData = learnedSkill.GetData();
  160. if (skillData != null)
  161. {
  162. OnSkillButtonClicked(skillData);
  163. return; // OnSkillButtonClicked already calls DisableButtonsTemporarily
  164. }
  165. }
  166. Debug.LogWarning($"Couldn't find previous skill: {character.lastSkillName}");
  167. break;
  168. case ActionType.Heal:
  169. Debug.Log($"{character.characterName} répète : Soin !");
  170. // Appelle ton système de heal
  171. break;
  172. default:
  173. Debug.Log($"{character.characterName} n'a aucune action précédente.");
  174. break;
  175. }
  176. DisableButtonsTemporarily(5f);
  177. }
  178. void ToggleSkillPanel()
  179. {
  180. if (skillPanel != null)
  181. skillPanel.SetActive(!skillPanel.activeSelf);
  182. }
  183. void OnOpenInventory()
  184. {
  185. Debug.Log($"{character.characterName} ouvre son inventaire");
  186. if (inventoryPanel != null)
  187. {
  188. inventoryPanel.SetActive(!inventoryPanel.activeSelf);
  189. // Bind the inventory to this character if opening
  190. if (inventoryPanel.activeSelf && inventoryUIController != null)
  191. {
  192. inventoryUIController.Bind(character);
  193. }
  194. }
  195. else
  196. {
  197. Debug.LogWarning("Inventory panel is not assigned in the inspector!");
  198. }
  199. }
  200. // Méthode appelée pour mettre à jour dynamiquement les PV
  201. public void UpdateHPBar()
  202. {
  203. if (hpSlider == null)
  204. {
  205. Debug.LogWarning($"[UI] HP Slider is null for {character?.characterName}");
  206. return;
  207. }
  208. if (character == null)
  209. {
  210. Debug.LogWarning("[UI] Character reference is null in UpdateHPBar");
  211. return;
  212. }
  213. Debug.Log($"[UI] Mise à jour barre de vie : {character.characterName} ({character.currentHP}/{character.maxHP})");
  214. // Update max first, then value to ensure proper ratio
  215. hpSlider.maxValue = character.maxHP;
  216. hpSlider.value = character.currentHP;
  217. // Force layout rebuild to ensure visual update
  218. UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(hpSlider.GetComponent<RectTransform>());
  219. }
  220. public void UpdateFatigueBar()
  221. {
  222. if (fatigueSlider == null)
  223. {
  224. Debug.LogWarning($"[UI] Fatigue Slider is null for {character?.characterName}");
  225. return;
  226. }
  227. if (character == null) return;
  228. fatigueSlider.maxValue = character.maxFatigue; // Update max in case of level up
  229. fatigueSlider.value = character.currentFatigue;
  230. UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(fatigueSlider.GetComponent<RectTransform>());
  231. Debug.Log($"[UI] Fatigue bar updated: {character.characterName} ({character.currentFatigue}/{character.maxFatigue})");
  232. }
  233. public void UpdateExpBar()
  234. {
  235. if (expSlider == null)
  236. {
  237. Debug.LogWarning($"[UI] Exp Slider is null for {character?.characterName}");
  238. return;
  239. }
  240. if (character == null) return;
  241. expSlider.value = character.experience;
  242. UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(expSlider.GetComponent<RectTransform>());
  243. Debug.Log($"[UI] Experience bar updated: {character.characterName} ({character.experience}/100)");
  244. }
  245. public void DisableButtonsTemporarily(float duration)
  246. {
  247. StartCoroutine(CooldownRoutine(duration));
  248. }
  249. private IEnumerator CooldownRoutine(float duration)
  250. {
  251. cooldownOverlay.gameObject.SetActive(true);
  252. SetButtonsInteractable(false);
  253. if (cooldownOverlay) cooldownOverlay.fillAmount = 1f;
  254. float elapsed = 0f;
  255. while (elapsed < duration)
  256. {
  257. elapsed += Time.deltaTime;
  258. float fill = Mathf.Clamp01(1f - elapsed / duration);
  259. if (cooldownOverlay) cooldownOverlay.fillAmount = fill;
  260. yield return null;
  261. }
  262. SetButtonsInteractable(true);
  263. if (cooldownOverlay) cooldownOverlay.fillAmount = 0f;
  264. }
  265. private void SetButtonsInteractable(bool interactable)
  266. {
  267. if (attackButton != null)
  268. attackButton.interactable = interactable;
  269. if (repeatActionButton != null)
  270. repeatActionButton.interactable = interactable;
  271. if (openSkillsButton != null)
  272. openSkillsButton.interactable = interactable;
  273. // Note: Inventory button should remain accessible during cooldown
  274. var fadedColor = interactable ? Color.white : new Color(1f, 1f, 1f, 0.5f);
  275. if (attackButton != null)
  276. attackButton.image.color = fadedColor;
  277. if (repeatActionButton != null)
  278. repeatActionButton.image.color = fadedColor;
  279. if (openSkillsButton != null)
  280. openSkillsButton.image.color = fadedColor;
  281. }
  282. public void HandleCharacterDeath()
  283. {
  284. Debug.Log($"[Death] {character.characterName} est mort, suppression de la carte UI");
  285. string characterName = character.characterName;
  286. // Remove character from the party
  287. TeamCohesionManager cohesionManager = FindFirstObjectByType<TeamCohesionManager>();
  288. if (cohesionManager != null)
  289. {
  290. cohesionManager.groupMembers.Remove(character);
  291. }
  292. // Remove from UIUpdater registry
  293. UIUpdater.Instance?.Unregister(characterName);
  294. // Destroy the card UI
  295. Destroy(gameObject);
  296. // Check if all characters are dead (party wipe)
  297. if (cohesionManager != null && cohesionManager.groupMembers.Count == 0)
  298. {
  299. Debug.Log("[Game Over] All party members are dead! Triggering respawn system...");
  300. // Notify GameManager of party wipe
  301. var gameManagerObj = GameObject.Find("GameManager");
  302. if (gameManagerObj != null)
  303. {
  304. gameManagerObj.SendMessage("OnPartyWiped", SendMessageOptions.DontRequireReceiver);
  305. }
  306. else
  307. {
  308. Debug.LogError("[Death] GameManager not found! Cannot trigger respawn system.");
  309. }
  310. }
  311. }
  312. }