From 5418da185e0a9f9433e10eafc6aaf854803560b2 Mon Sep 17 00:00:00 2001 From: Mateus Rodrigues Date: Sat, 23 May 2026 11:47:10 -0300 Subject: [PATCH] =?UTF-8?q?feat(attributes/ui):=20display=20"ATK=20base=20?= =?UTF-8?q?+=20bonus"=20igual=20RO=20+=20ASPD=20=C3=BAnico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FZMMOAttributesSnapshot ganha 7 pares (AtkBase/AtkEquipBonus, ...) + Aspd único, espelhando split do server. - ZMMOAttributeNetworkHandler::ToSnapshot mapeia campos novos do FZeusAttributesPayload. - WBP_StatusWindow / RefreshFromSnapshot agora formata derivados como "ATK 51 + 0", "CRIT 1.3 + 0.0", "ASPD 150" (este sem split — cálculo não-linear no server via aspd_base × stats). Quando InventorySystem entrar, equipar arma muda `currentWeapon` no server, Recalculate roda, e UI mostra ATK/MATK/DEF/etc com bonus > 0 e ASPD ajustado pela aspd_base da arma equipada. Sem código de migração — schema do snapshot já está estabilizado. --- .../Game/UI/InGame/ZMMOStatusWindowWidget.cpp | 28 +++++++++------- .../Private/ZMMOAttributeNetworkHandler.cpp | 23 ++++++++----- .../Public/ZMMOAttributeTypes.h | 33 ++++++++++++++----- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/Source/ZMMO/Game/UI/InGame/ZMMOStatusWindowWidget.cpp b/Source/ZMMO/Game/UI/InGame/ZMMOStatusWindowWidget.cpp index b32c6f0..0278c7e 100644 --- a/Source/ZMMO/Game/UI/InGame/ZMMOStatusWindowWidget.cpp +++ b/Source/ZMMO/Game/UI/InGame/ZMMOStatusWindowWidget.cpp @@ -110,20 +110,26 @@ void UZMMOStatusWindowWidget::RefreshFromSnapshot(const FZMMOAttributesSnapshot& FString::Printf(TEXT("Status Points: %d"), S.StatusPoint))); } - // Derivados — sempre vem prontos do servidor (camadas equip/buff ja somadas). - // CritX10 vem internamente x10 (1.0 = 10); divide pra exibicao com 1 casa. - if (AtkText) AtkText->SetText(FText::FromString(FString::Printf(TEXT("ATK %d"), S.Atk))); - if (MatkText) MatkText->SetText(FText::FromString(FString::Printf(TEXT("MATK %d"), S.Matk))); - if (DefText) DefText->SetText(FText::FromString(FString::Printf(TEXT("DEF %d"), S.Def))); - if (MdefText) MdefText->SetText(FText::FromString(FString::Printf(TEXT("MDEF %d"), S.Mdef))); - if (HitText) HitText->SetText(FText::FromString(FString::Printf(TEXT("HIT %d"), S.Hit))); - if (FleeText) FleeText->SetText(FText::FromString(FString::Printf(TEXT("FLEE %d"), S.Flee))); + // Derivados — formato RO "STAT base + equip" (ex.: "ATK 51 + 0"). + // Servidor manda os dois separados; cliente NUNCA recalcula. + if (AtkText) AtkText->SetText(FText::FromString(FString::Printf(TEXT("ATK %d + %d"), S.AtkBase, S.AtkEquipBonus))); + if (MatkText) MatkText->SetText(FText::FromString(FString::Printf(TEXT("MATK %d + %d"), S.MatkBase, S.MatkEquipBonus))); + if (DefText) DefText->SetText(FText::FromString(FString::Printf(TEXT("DEF %d + %d"), S.DefBase, S.DefEquipBonus))); + if (MdefText) MdefText->SetText(FText::FromString(FString::Printf(TEXT("MDEF %d + %d"), S.MdefBase, S.MdefEquipBonus))); + if (HitText) HitText->SetText(FText::FromString(FString::Printf(TEXT("HIT %d + %d"), S.HitBase, S.HitEquipBonus))); + if (FleeText) FleeText->SetText(FText::FromString(FString::Printf(TEXT("FLEE %d + %d"), S.FleeBase, S.FleeEquipBonus))); if (CritText) { - const int32 CritInt = S.CritX10 / 10; - const int32 CritFrac = S.CritX10 % 10; - CritText->SetText(FText::FromString(FString::Printf(TEXT("CRIT %d.%d"), CritInt, CritFrac))); + // CRIT vem ×10 em ambas as camadas — soma X10 antes de converter pra + // decimal (10 = 1.0). Display: "CRIT base + equip" com 1 casa cada. + const int32 BaseInt = S.CritBaseX10 / 10; + const int32 BaseFrac = S.CritBaseX10 % 10; + const int32 EquipInt = S.CritEquipBonusX10 / 10; + const int32 EquipFrac = S.CritEquipBonusX10 % 10; + CritText->SetText(FText::FromString(FString::Printf( + TEXT("CRIT %d.%d + %d.%d"), BaseInt, BaseFrac, EquipInt, EquipFrac))); } + // ASPD nao splita (calculo nao-linear server-side via aspd_base × stats). if (AspdText) AspdText->SetText(FText::FromString(FString::Printf(TEXT("ASPD %d"), S.Aspd))); // Habilita botões `+` somente se ha status_point disponível. const bool bCanAlloc = S.StatusPoint > 0; diff --git a/Source/ZMMOAttributes/Private/ZMMOAttributeNetworkHandler.cpp b/Source/ZMMOAttributes/Private/ZMMOAttributeNetworkHandler.cpp index 3a20330..8512a5f 100644 --- a/Source/ZMMOAttributes/Private/ZMMOAttributeNetworkHandler.cpp +++ b/Source/ZMMOAttributes/Private/ZMMOAttributeNetworkHandler.cpp @@ -35,14 +35,21 @@ namespace S.Sp = P.Sp; S.MaxSp = P.MaxSp; S.Money = P.Money; - S.Atk = P.Atk; - S.Matk = P.Matk; - S.Def = P.Def; - S.Mdef = P.Mdef; - S.Hit = P.Hit; - S.Flee = P.Flee; - S.CritX10 = P.CritX10; - S.Aspd = P.Aspd; + S.AtkBase = P.AtkBase; + S.AtkEquipBonus = P.AtkEquipBonus; + S.MatkBase = P.MatkBase; + S.MatkEquipBonus = P.MatkEquipBonus; + S.DefBase = P.DefBase; + S.DefEquipBonus = P.DefEquipBonus; + S.MdefBase = P.MdefBase; + S.MdefEquipBonus = P.MdefEquipBonus; + S.HitBase = P.HitBase; + S.HitEquipBonus = P.HitEquipBonus; + S.FleeBase = P.FleeBase; + S.FleeEquipBonus = P.FleeEquipBonus; + S.CritBaseX10 = P.CritBaseX10; + S.CritEquipBonusX10 = P.CritEquipBonusX10; + S.Aspd = P.Aspd; return S; } diff --git a/Source/ZMMOAttributes/Public/ZMMOAttributeTypes.h b/Source/ZMMOAttributes/Public/ZMMOAttributeTypes.h index 339525c..3d893e8 100644 --- a/Source/ZMMOAttributes/Public/ZMMOAttributeTypes.h +++ b/Source/ZMMOAttributes/Public/ZMMOAttributeTypes.h @@ -50,14 +50,31 @@ struct ZMMOATTRIBUTES_API FZMMOAttributesSnapshot // === Moeda === UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes") int64 Money = 0; - // === Derivados (efetivos; servidor sempre recalcula) === - UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 Atk = 0; - UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 Matk = 0; - UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 Def = 0; - UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 Mdef = 0; - UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 Hit = 0; - UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 Flee = 0; + // === Derivados split em pares (base, equipBonus) === + // Padrao RO: display mostra "ATK 51 + 0" (base + equip). Cliente NUNCA + // recalcula — servidor envia ambos prontos no S_ATTRIBUTE_SNAPSHOT_FULL. + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 AtkBase = 0; + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 AtkEquipBonus = 0; + + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 MatkBase = 0; + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 MatkEquipBonus = 0; + + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 DefBase = 0; + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 DefEquipBonus = 0; + + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 MdefBase = 0; + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 MdefEquipBonus = 0; + + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 HitBase = 0; + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 HitEquipBonus = 0; + + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 FleeBase = 0; + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 FleeEquipBonus = 0; + /** Critico × 10 internamente (10 = 1.0). Divida por 10 para exibir. */ - UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 CritX10 = 0; + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 CritBaseX10 = 0; + UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 CritEquipBonusX10 = 0; + + /** ASPD nao splita — calculo nao-linear via aspd_base × stats. Display direto. */ UPROPERTY(BlueprintReadOnly, Category = "Zeus|Attributes|Derived") int32 Aspd = 0; };