Files
ZMMO/Source/ZMMOAttributes/Public/ZMMOAttributeComponent.h
Mateus Rodrigues f585b0d2b9 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.
2026-05-23 11:22:58 -03:00

106 lines
4.4 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "ZMMOAttributeTypes.h"
#include "ZMMOAttributeComponent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FZMMOOnAttributesChanged, const FZMMOAttributesSnapshot&, Snapshot);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FZMMOOnHpSpChanged, int32, Hp, int32, Sp);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FZMMOOnLevelUp, int32, NewBaseLevel, int32, StatusPointDelta);
/// Resposta server ao C_STAT_ALLOC. Reason e' EAllocRejectReason (None=0,
/// InvalidStat=1, InvalidAmount=2, NotEnoughPoints=3, StatCapped=4, NoSession=5).
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FZMMOOnStatAllocReply, bool, bAccepted, int32, Reason);
/**
* Componente de atributos do MMO ligado ao ator que o representa em-jogo
* (player local, proxies remotos, NPCs futuros).
*
* Estado authoritative vive no servidor (CharRuntimeStatus em
* Game/MMO/Modules/AttributeSystem). Cliente apenas armazena o ultimo
* snapshot recebido e expoe delegates para UI/HUD reagir.
*
* Roteamento server → componente: `UZMMOAttributeNetworkHandler`
* (UWorldSubsystem) liga em `UZeusNetworkSubsystem::OnAttributeSnapshotFull`,
* resolve `EntityId -> AActor*` via `UZMMOWorldSubsystem` e chama
* `ApplySnapshot` no componente do ator.
*/
UCLASS(ClassGroup=(ZMMO), meta=(BlueprintSpawnableComponent),
hidecategories=(Activation, Collision, Cooking, Object, Replication))
class ZMMOATTRIBUTES_API UZMMOAttributeComponent : public UActorComponent
{
GENERATED_BODY()
public:
UZMMOAttributeComponent();
/// Aplica snapshot full recebido do servidor. Substitui `Current` e
/// dispara `OnAttributesChanged` + `OnHpSpChanged` (se hp/sp mudaram).
UFUNCTION(BlueprintCallable, Category = "Zeus|Attributes")
void ApplySnapshot(const FZMMOAttributesSnapshot& InSnapshot);
/// Aplica apenas delta de HP/SP (sem mexer em outros campos).
UFUNCTION(BlueprintCallable, Category = "Zeus|Attributes")
void ApplyHpSpUpdate(int32 NewHp, int32 NewSp);
/// Notifica level up — o snapshot subsequente atualiza demais campos.
UFUNCTION(BlueprintCallable, Category = "Zeus|Attributes")
void NotifyLevelUp(int32 NewBaseLevel, int32 StatusPointDelta);
/// Notifica resposta server ao C_STAT_ALLOC. UI pode reagir (toast/SFX
/// quando aceito, erro vermelho quando rejeitado).
UFUNCTION(BlueprintCallable, Category = "Zeus|Attributes")
void NotifyStatAllocReply(bool bAccepted, int32 Reason);
/// Envia C_STAT_ALLOC pro server. Wrapper conveniente — busca o
/// UZeusNetworkSubsystem via GameInstance + chama SendStatAlloc.
/// `StatId`: 0=STR, 1=AGI, 2=VIT, 3=INT, 4=DEX, 5=LUK. `Amount`: 1..10.
UFUNCTION(BlueprintCallable, Category = "Zeus|Attributes")
void RequestStatAlloc(int32 StatId, int32 Amount = 1);
/// Seed do EntityId vindo de S_SPAWN_PLAYER local. Chamado pelo
/// `AZMMOPlayerCharacter` antes do primeiro S_ATTRIBUTE_SNAPSHOT_FULL
/// chegar, garantindo que o NetworkHandler consiga rotear via lookup
/// por EntityId desde o inicio.
UFUNCTION(BlueprintCallable, Category = "Zeus|Attributes")
void SeedEntityId(int32 InEntityId) { Current.EntityId = InEntityId; }
UFUNCTION(BlueprintPure, Category = "Zeus|Attributes")
const FZMMOAttributesSnapshot& GetSnapshot() const { return Current; }
UFUNCTION(BlueprintPure, Category = "Zeus|Attributes")
float GetHpRatio() const
{
return Current.MaxHp > 0 ? static_cast<float>(Current.Hp) / static_cast<float>(Current.MaxHp) : 0.f;
}
UFUNCTION(BlueprintPure, Category = "Zeus|Attributes")
float GetSpRatio() const
{
return Current.MaxSp > 0 ? static_cast<float>(Current.Sp) / static_cast<float>(Current.MaxSp) : 0.f;
}
// === Delegates Blueprint ===
/** Snapshot novo aplicado. Use isto na UI para refresh geral. */
UPROPERTY(BlueprintAssignable, Category = "Zeus|Attributes")
FZMMOOnAttributesChanged OnAttributesChanged;
/** HP ou SP mudou (efêmero ou via snapshot). Para barras animadas. */
UPROPERTY(BlueprintAssignable, Category = "Zeus|Attributes")
FZMMOOnHpSpChanged OnHpSpChanged;
/** Subiu de nível. Para efeitos visuais ("LEVEL UP!" toast). */
UPROPERTY(BlueprintAssignable, Category = "Zeus|Attributes")
FZMMOOnLevelUp OnLevelUp;
/** Resposta ao C_STAT_ALLOC (aceito ou rejeitado). UI reage. */
UPROPERTY(BlueprintAssignable, Category = "Zeus|Attributes")
FZMMOOnStatAllocReply OnStatAllocReply;
protected:
UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes")
FZMMOAttributesSnapshot Current;
};