feat(attributes/ui): Status Window com alocação STR/AGI/VIT/INT/DEX/LUK + derivados

- ZMMOStatusWindowWidget (UCommonActivatableWidget, modo Menu): grid 2 colunas
  estilo RO. Esquerda: stats primários com botões + por stat (RequestStatAlloc).
  Direita: derivados ATK/MATK/DEF/MDEF/HIT/FLEE/CRIT/ASPD vindos do snapshot
  do server — cliente NUNCA recalcula (anti-cheat foundation).
- Botão + envia C_STAT_ALLOC → server valida cost RO (floor((stat-1)/10)+2),
  aplica + recalcula derivados + SaveCharFull async, manda
  S_ATTRIBUTE_SNAPSHOT_FULL + reply. UI atualiza em tempo real via
  OnAttributesChanged.
- ZMMOAttributeComponent ganha RequestStatAlloc + NotifyStatAllocReply +
  delegate OnStatAllocReply para feedback de rejeição.
- ZMMOAttributeNetworkHandler: HandleStatAllocReply roteia pro componente do
  player local (reply não traz EntityId — sempre quem fez o request).
- PlayerController: hotkey Alt+A (FInputChord legacy + BindKey, sem precisar
  de IA asset). ToggleStatusWindow via UUIInGameFlowSubsystem.
- WBP_StatusWindow: layout 2 colunas via MCP set_widget_tree (43 widgets) +
  BgBorder escuro semi-transparente + centralizado no overlay.
- DA_InGameScreenSet: StatusWindow → WBP_StatusWindow.
This commit is contained in:
2026-05-23 11:22:58 -03:00
parent 396223e2a8
commit f585b0d2b9
10 changed files with 372 additions and 0 deletions

View File

@@ -36,10 +36,16 @@ private:
void HandleAttributeSnapshotFull(const FZeusAttributesPayload& Payload);
void HandleHpSpUpdate(int32 EntityId, int32 Hp, int32 Sp);
void HandleLevelUp(int32 EntityId, int32 NewBaseLevel, int32 StatusPointDelta);
void HandleStatAllocReply(bool bAccepted, int32 Reason);
UZeusNetworkSubsystem* GetZeusNetSubsystem() const;
/// Acha o AttributeComponent do player local (Pawn->PlayerState).
/// Usado pro StatAllocReply (sem EntityId no payload).
class UZMMOAttributeComponent* FindLocalPlayerAttributeComponent() const;
FDelegateHandle SnapshotFullHandle;
FDelegateHandle HpSpUpdateHandle;
FDelegateHandle LevelUpHandle;
FDelegateHandle StatAllocReplyHandle;
};