Files
trail-into-darkness/Assets/Code/GameState/UI/PartyGuiView.cs
2026-04-06 17:41:35 +02:00

180 lines
6.5 KiB
C#

using System.Collections.Generic;
using Jovian.PopupSystem;
using Nox.UI;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Nox.Game.UI {
public class PartyGuiView {
private const int PoolSize = 4;
private readonly Transform portraitsContainer;
private readonly PartyMemberSlot slotPrefab;
private readonly PortraitsHolder portraitsHolder;
private readonly IPopupSystem popupSystem;
private readonly PartyMemberSlot[] slotPool = new PartyMemberSlot[PoolSize];
private PartyDefinition trackedParty;
private int activeCount;
public PartyGuiView(Transform portraitsContainer, PartyMemberSlot slotPrefab, PortraitsHolder portraitsHolder, IPopupSystem popupSystem = null) {
this.portraitsContainer = portraitsContainer;
this.slotPrefab = slotPrefab;
this.portraitsHolder = portraitsHolder;
this.popupSystem = popupSystem;
}
public void Initialize(PartyDefinition party) {
trackedParty = party;
activeCount = 0;
// Pre-create all slots (deactivated)
for(int i = 0; i < PoolSize; i++) {
if(slotPool[i] == null) {
slotPool[i] = Object.Instantiate(slotPrefab, portraitsContainer);
}
slotPool[i].gameObject.SetActive(false);
}
PopulateSlots();
}
public void Tick() {
if(trackedParty == null) {
return;
}
// Rebuild if member count changed
if(trackedParty.members.Count != activeCount) {
PopulateSlots();
}
// Update dynamic values
var memberCount = Mathf.Min(activeCount, trackedParty.members.Count);
for(int i = 0; i < memberCount; i++) {
UpdateSlotStats(slotPool[i], trackedParty.members[i]);
}
}
private void PopulateSlots() {
var memberCount = trackedParty?.members != null
? Mathf.Min(trackedParty.members.Count, PoolSize)
: 0;
// Activate slots for current members, deactivate the rest
for(int i = 0; i < PoolSize; i++) {
var slot = slotPool[i];
if(i < memberCount) {
var member = trackedParty.members[i];
slot.gameObject.SetActive(true);
// Portrait
if(portraitsHolder != null && portraitsHolder.portraits.Length > 0) {
var idx = Mathf.Clamp(member.PortraitIndex, 0, portraitsHolder.portraits.Length - 1);
slot.portrait.sprite = portraitsHolder.portraits[idx];
}
UpdateSlotStats(slot, member);
}
else {
slot.gameObject.SetActive(false);
}
}
activeCount = memberCount;
// Initialize popup triggers
if(popupSystem != null) {
popupSystem.InitializeTriggersInChildren(portraitsContainer, (trigger, view) => {
var slot = trigger.GetComponentInParent<PartyMemberSlot>();
if(slot == null) {
return;
}
var slotIndex = System.Array.IndexOf(slotPool, slot);
if(slotIndex < 0 || slotIndex >= activeCount) {
return;
}
var member = trackedParty.members[slotIndex];
view.SetContent(builder => BuildCharacterPopup(builder, member));
});
}
}
private void BuildCharacterPopup(PopupContentBuilder builder, CharacterDefinition member) {
// Header
builder
.AddHeader(member.Name)
.AddText($"{member.Race} {member.Class}", "#CCCCCC")
.AddText($"Role: {member.Role}")
.AddSeparator();
// Stats
if(member.Stats?.stats != null) {
var level = member.Stats.GetValue(StatType.Level);
var xp = member.Stats.GetValue(StatType.Experience);
var health = member.Stats.GetValue(StatType.Health);
var mana = member.Stats.GetValue(StatType.Mana);
builder
.AddStat("Level", level)
.AddStat("XP", xp)
.AddSeparator()
.AddStat("Health", health)
.AddStat("Mana", mana)
.AddSeparator();
}
// Attributes
if(member.Attributes?.attributes != null) {
foreach(var attr in member.Attributes.attributes) {
if(attr.attribute == AttributeType.None) {
continue;
}
builder.AddStat(attr.attribute.ToString(), attr.value);
}
}
builder.AddSeparator();
// Perks
if(member.Perks?.perks != null && member.Perks.perks.Count > 0) {
builder.AddText("Perks", "#FFD700");
foreach(var perk in member.Perks.perks) {
builder.AddText($" {perk.Name}");
}
builder.AddSeparator();
}
// Modifiers
if(member.Modifiers?.modifiers is { Count: > 0 }) {
builder.AddText("Modifiers", "#87CEEB");
foreach(var mod in member.Modifiers.modifiers) {
var target = mod.Target != null ? mod.Target.ToString() : "";
builder.AddText($" {mod.Name} ({mod.Operation} {mod.Value} {target})");
}
}
}
private static void UpdateSlotStats(PartyMemberSlot slot, CharacterDefinition member) {
var health = member.Stats.GetValue(StatType.Health);
var mana = member.Stats.GetValue(StatType.Mana);
if(slot.healthBar != null) {
slot.healthBar.fillAmount = Mathf.Clamp01(health / 100f);
}
if(slot.manaBar != null) {
slot.manaBar.fillAmount = Mathf.Clamp01(mana / 100f);
}
}
public void Dispose() {
for(int i = 0; i < PoolSize; i++) {
if(slotPool[i] != null) {
Object.Destroy(slotPool[i].gameObject);
slotPool[i] = null;
}
}
activeCount = 0;
}
}
}