diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgSkillSubList.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgSkillSubList.cs
index 35b1d68853..934e9787fa 100644
--- a/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgSkillSubList.cs
+++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgSkillSubList.cs
@@ -190,7 +190,15 @@ namespace BrewMonster.UI
FitSize();
ShowLastSelectedSkill();
}
- totalSPText.text = " Nguyên Thần: " + GetHostPlayer().GetBasicProps().iSP.ToString() + "";
+ UpdateTotalSPText();
+ }
+
+ public void UpdateTotalSPText()
+ {
+ if (totalSPText != null && GetHostPlayer() != null)
+ {
+ totalSPText.text = " Nguyên Thần: " + GetHostPlayer().GetBasicProps().iSP.ToString() + "";
+ }
}
// ��鵯��ħ״̬ / Reset when switching between god/evil
@@ -495,6 +503,7 @@ namespace BrewMonster.UI
}
else if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_LEVEL_UP)
{
+ UpdateTotalSPText();
if (q.m_skillLevel == 1)
{
foreach (var kv in m_skillSubDialogsMap)
diff --git a/Assets/PerfectWorld/Scripts/UI/GamePlay/SkillUI/CDlgSkillSubListItem.cs b/Assets/PerfectWorld/Scripts/UI/GamePlay/SkillUI/CDlgSkillSubListItem.cs
index 016d9227fe..5fd18450fc 100644
--- a/Assets/PerfectWorld/Scripts/UI/GamePlay/SkillUI/CDlgSkillSubListItem.cs
+++ b/Assets/PerfectWorld/Scripts/UI/GamePlay/SkillUI/CDlgSkillSubListItem.cs
@@ -106,6 +106,7 @@ namespace BrewMonster
int needMoney = CECHostSkillModel.Instance.GetSkillMoney(m_skillID, m_curLevel + 1);
int needSp = CECHostSkillModel.Instance.GetSkillSp(m_skillID, m_curLevel + 1);
+
string str = GPDataTypeHelper.ReplacePercentD(GetStringFromTable(11326), needMoney, needSp);
// var messagebox = uiManager.ShowMessageBox(new MessageBoxData()
// {
@@ -115,16 +116,38 @@ namespace BrewMonster
// });
var messagebox = uiManager.ShowMessageBoxYes("Game_LearnSkill", str, this,
() => {
- UnityGameSession.c2s_SendCmdNPCSevLearnSkill(m_skillID);
- int skillID = (int)GetData();
- int nCondition = EC_Game.GetGameRun().GetHostPlayer().CheckSkillLearnCondition(skillID, true);
- // BMLogger.LogError("HoangDev: CDlgSkillSubListItem OnCommand_Upgrade clicked yes for nCondition " + nCondition);
+ CECHostPlayer hostPlayer = GetHostPlayer();
+ if (hostPlayer == null)
+ return;
- if (0 == nCondition)
+ int skillID = m_skillID;
+ int recheck = hostPlayer.CheckSkillLearnCondition(skillID, true);
+
+ if (recheck != 0)
{
- UnityGameSession.c2s_SendCmdNPCSevLearnSkill(skillID);
+ UpdateUpgradeBtn();
+ if (!string.IsNullOrEmpty(m_upgradeDisabledReason))
+ {
+ uiManager.ShowMessageBoxGeneral("MessageBox", m_upgradeDisabledReason, this);
+ }
+ return;
}
+ int costMoney = CECHostSkillModel.Instance.GetSkillMoney(skillID, m_curLevel + 1);
+ int costSp = CECHostSkillModel.Instance.GetSkillSp(skillID, m_curLevel + 1);
+
+ if(!hostPlayer.TryConsumeSkillLearnCost(costMoney, costSp))
+ {
+ UpdateUpgradeBtn();
+ if(!string.IsNullOrEmpty(m_upgradeDisabledReason))
+ {
+ uiManager.ShowMessageBoxGeneral("MessageBox", m_upgradeDisabledReason, this);
+ }
+ return;
+ }
+
+ UnityGameSession.c2s_SendCmdNPCSevLearnSkill(skillID);
+ UpdateUpgradeBtn();
});
messagebox.SetData((uint)m_skillID);
//GetGameUIMan()->MessageBox("Game_LearnSkill", str, //GetGameUIMan()->GetStringFromTable(231),
diff --git a/Assets/PerfectWorld/Scripts/UI/NPCShopUIManager.cs b/Assets/PerfectWorld/Scripts/UI/NPCShopUIManager.cs
index 90454bde48..b1186b88cd 100644
--- a/Assets/PerfectWorld/Scripts/UI/NPCShopUIManager.cs
+++ b/Assets/PerfectWorld/Scripts/UI/NPCShopUIManager.cs
@@ -1247,7 +1247,6 @@ public class NPCShopUIManager : AUIDialog
return;
}
- // Server requires greeting before NPC service commands.
if (CurrentNPCID != 0)
UnityGameSession.c2s_CmdNPCSevHello((int)CurrentNPCID);
@@ -1259,7 +1258,9 @@ public class NPCShopUIManager : AUIDialog
return;
}
+ long totalSellValue = 0;
var itemsToSell = new List(sellSlotToSourceSlot.Count);
+
foreach (var pair in sellSlotToSourceSlot)
{
int sourceSlot = pair.Value;
@@ -1276,10 +1277,13 @@ public class NPCShopUIManager : AUIDialog
continue;
}
- // Ensure local DB props (including price) are present when needed.
item.GetDetailDataFromLocal();
int price = item.GetScaledPrice();
+ long itemTotal = (long)price * item.m_iCount;
+ if (itemTotal > 0)
+ totalSellValue += itemTotal;
+
itemsToSell.Add(new npc_sell_item
{
tid = item.m_tid,
@@ -1298,17 +1302,56 @@ public class NPCShopUIManager : AUIDialog
UnityGameSession.c2s_CmdNPCSevSell(itemsToSell.Count, itemsToSell.ToArray());
Debug.Log($"[NPCShopUIManager] Sent sell command for {itemsToSell.Count} item(s) to NPC {CurrentNPCID}");
- ResetSellReadySlots();
+ // Optimistic local money update: cộng tiền ngay trên client
+ if (host != null && totalSellValue > 0)
+ {
+ ulong currentMoney = host.GetMoneyAmount();
+ ulong nextMoney = currentMoney + (ulong)totalSellValue;
+ if (nextMoney > uint.MaxValue)
+ nextMoney = uint.MaxValue;
+
+ host.SetMoneyAmount((uint)nextMoney);
+ RefreshMoneyUiFromHost(host);
+ }
+
+ ResetSellReadySlots();
+ UpdateSellTotalPriceText();
+ UpdateBuyPriceTexts();
- // Ask server for refreshed inventory, then repaint UI so sold items disappear.
var inventoryUI = FindFirstObjectByType();
UnityGameSession.RequestInventoryAsync(0, () =>
{
if (inventoryUI != null)
inventoryUI.RefreshAll();
+
+ var callbackHost = CECGameRun.Instance?.GetHostPlayer();
+ if (callbackHost != null)
+ RefreshMoneyUiFromHost(callbackHost);
+
+ UpdateBuyPriceTexts();
+ UpdateSellTotalPriceText();
});
}
+ private void RefreshMoneyUiFromHost(CECHostPlayer host)
+ {
+ if (host == null)
+ return;
+
+ ulong amount = host.GetMoneyAmount();
+ ulong maxAmount = (ulong)Math.Max(0, host.GetMaxMoneyAmount());
+
+ var inventoryUI = FindFirstObjectByType();
+ if (inventoryUI != null && inventoryUI.gameObject.activeInHierarchy)
+ {
+ inventoryUI.UpdateMoney(amount, maxAmount);
+ }
+ else
+ {
+ EC_InventoryUI.CacheMoney(amount, maxAmount);
+ }
+ }
+
private void OnUseItemClicked()
{
if (!TryGetSelectedInventoryItem(out var selectedItem, out var selectedSlot))
diff --git a/Assets/Scripts/CECHostPlayer.Inventory.cs b/Assets/Scripts/CECHostPlayer.Inventory.cs
index b542a8b890..3bcf0669ed 100644
--- a/Assets/Scripts/CECHostPlayer.Inventory.cs
+++ b/Assets/Scripts/CECHostPlayer.Inventory.cs
@@ -1732,5 +1732,27 @@ namespace BrewMonster
return bCanPick;
}
+
+ ///
+ /// Consume money + SP for learning skill on client side after player confirms.
+ /// Returns false if resources are not enough at commit time.
+ ///
+ public bool TryConsumeSkillLearnCost(int moneyCost, int spCost)
+ {
+ if (moneyCost < 0)
+ moneyCost = 0;
+ if (spCost < 0)
+ spCost = 0;
+
+ if ((long)GetMoneyAmount() < moneyCost)
+ return false;
+
+ if (m_BasicProps.iSP < spCost)
+ return false;
+
+ AddMoneyAmount(-moneyCost);
+ m_BasicProps.iSP = Math.Max(0, m_BasicProps.iSP - spCost);
+ return true;
+ }
}
}