From 66dc12ef4af0782989fa059c38c163322ea76aa8 Mon Sep 17 00:00:00 2001 From: HungDK <> Date: Mon, 8 Dec 2025 09:30:59 +0700 Subject: [PATCH] Update item detail --- .../Scripts/Managers/EC_IvtrEquip.cs | 3966 +++++++++++++---- .../Scripts/Managers/EC_IvtrItem.cs | 136 +- .../Scripts/UI/NPCShopDetailPanel.cs | 38 +- 3 files changed, 3172 insertions(+), 968 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrEquip.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrEquip.cs index 311bb7e50a..90426521cf 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrEquip.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrEquip.cs @@ -3,13 +3,16 @@ using System.Collections.Generic; using System.Linq; using UnityEngine; using ModelRenderer.Scripts.GameData; +using ModelRenderer.Scripts.Common; using BrewMonster; using BrewMonster.Common; using BrewMonster.Network; using System.IO; +using System.Text; using System.Text.RegularExpressions; using System.Reflection; using BrewMonster.Scripts.Managers; +using BrewMonster.Scripts; namespace PerfectWorld.Scripts.Managers { @@ -49,22 +52,26 @@ namespace PerfectWorld.Scripts.Managers public const uint PEE_ENERGYREQ = 0x00010000; public const uint PEE_VITALITYREQ = 0x00020000; - // Property Effect Essence Indexes + // Property Effect Essence Indexes (must match C++ enum order) public const int PEEI_PHYDAMAGE = 0; - public const int PEEI_MAX_PHYDAMAGE = 1; + public const int PEEI_PHYDEF = 1; public const int PEEI_MAGICDAMAGE = 2; - public const int PEEI_MAX_MAGICDAMAGE = 3; - public const int PEEI_PHYDEF = 4; - public const int PEEI_GOLDDEF = 5; - public const int PEEI_WOODDEF = 6; - public const int PEEI_WATERDEF = 7; - public const int PEEI_FIREDEF = 8; - public const int PEEI_EARTHDEF = 9; - public const int PEEI_ATKDIST = 10; - public const int PEEI_HP = 11; - public const int PEEI_MP = 12; - public const int PEEI_DODGE = 13; - public const int MAX_PEEINDEX = 14; + public const int PEEI_GOLDDEF = 3; + public const int PEEI_WOODDEF = 4; + public const int PEEI_WATERDEF = 5; + public const int PEEI_FIREDEF = 6; + public const int PEEI_EARTHDEF = 7; + public const int PEEI_HP = 8; + public const int PEEI_MP = 9; + public const int PEEI_ENDURANCE = 10; + public const int PEEI_ATKDIST = 11; + public const int PEEI_STRENGTHREQ = 12; + public const int PEEI_AGILITYREQ = 13; + public const int PEEI_ATKSPEED = 14; + public const int PEEI_MAX_PHYDAMAGE = 15; + public const int PEEI_MAX_MAGICDAMAGE = 16; + public const int PEEI_DODGE = 17; + public const int MAX_PEEINDEX = 18; // Refine Indexes public const int REFINE_PHYDAMAGE = 0; @@ -79,74 +86,7 @@ namespace PerfectWorld.Scripts.Managers public const int REFINE_DODGE = 9; public const int MAX_REFINEINDEX = 10; - // Item Description Colors - public const int ITEMDESC_COL_WHITE = 0; - public const int ITEMDESC_COL_GREEN = 1; - public const int ITEMDESC_COL_YELLOW = 2; - public const int ITEMDESC_COL_DARKGOLD = 3; - public const int ITEMDESC_COL_LIGHTBLUE = 4; - public const int ITEMDESC_COL_CYANINE = 5; - public const int ITEMDESC_COL_RED = 6; - public const int ITEMDESC_COL_GRAY = 7; - - // Item Description String IDs - public const int ITEMDESC_NAME = 1000; - public const int ITEMDESC_ADDPHYDAMAGE = 1001; - public const int ITEMDESC_MAXPHYDAMAGE = 1002; - public const int ITEMDESC_ADDMAGICDAMAGE = 1003; - public const int ITEMDESC_MAXMAGICDAMAGE = 1004; - public const int ITEMDESC_PHYDEFENCE = 1005; - public const int ITEMDESC_ALLMAGICDEF = 1006; - public const int ITEMDESC_GOLDDEFENCE = 1007; - public const int ITEMDESC_WOODDEFENCE = 1008; - public const int ITEMDESC_WATERDEFENCE = 1009; - public const int ITEMDESC_FIREDEFENCE = 1010; - public const int ITEMDESC_EARTHDEFENCE = 1011; - public const int ITEMDESC_ADDHP = 1012; - public const int ITEMDESC_ADDMP = 1013; - public const int ITEMDESC_STRENGTH = 1014; - public const int ITEMDESC_AGILITY = 1015; - public const int ITEMDESC_ENERGY = 1016; - public const int ITEMDESC_VITALITY = 1017; - public const int ITEMDESC_DODGE = 1018; - public const int ITEMDESC_DEADLYSTRIKE = 1019; - public const int ITEMDESC_ATKRATING = 1020; - public const int ITEMDESC_ATKTIME = 1021; - public const int ITEMDESC_ADDATKDIST = 1022; - public const int ITEMDESC_CASTTIME = 1023; - public const int ITEMDESC_ENDURANCE = 1024; - public const int ITEMDESC_REPAIRCOST = 1025; - public const int ITEMDESC_EQUIPMARK = 1026; - public const int ITEMDESC_MADEFROM = 1027; - public const int ITEMDESC_2STRINGS = 1028; - public const int ITEMDESC_REPUTATION_REQ = 1029; - public const int ITEMDESC_EQUIP_DESTROYING = 1030; - public const int ITEMDESC_EQUIP_REPAIR_NEED_ITEM = 1031; - public const int ITEMDESC_EQUIP_REPAIR_NEED_ITEMCNT = 1032; - public const int ITEMDESC_ERRORPROP = 1033; - public const int ITEMDESC_RANDOMPROP = 1034; - public const int ITEMDESC_ATK_DEGREE = 1035; - public const int ITEMDESC_DEF_DEGREE = 1036; - public const int ITEMDESC_SOULPOWER = 1037; - public const int ITEMDESC_VIGOUR = 1038; - public const int ITEMDESC_ADDRIDEONPETSPEED = 1039; - public const int ITEMDESC_PENETRATION = 1040; - public const int ITEMDESC_RESILIENCE = 1041; - public const int ITEMDESC_PROFVIEW = 1042; - public const int ITEMDESC_REQEXTRA = 1043; - public const int ITEMDESC_HPRECOVER = 1044; - public const int ITEMDESC_MPRECOVER = 1045; - public const int ITEMDESC_RUNSPEED = 1046; - public const int ITEMDESC_RUNSPEEDEXTRA = 1047; - public const int ITEMDESC_PHYRESIST = 1048; - public const int ITEMDESC_TOTAL_DEFENCE_ADD = 1049; - public const int ITEMDESC_GOLDRESIST = 1050; - public const int ITEMDESC_WOODRESIST = 1051; - public const int ITEMDESC_WATERRESIST = 1052; - public const int ITEMDESC_FIRERESIST = 1053; - public const int ITEMDESC_EARTHRESIST = 1054; - public const int ITEMDESC_ALLMAGICRESIST = 1055; - public const int ITEMDESC_EXP = 1056; + // Item Description Colors and String IDs are now in DescriptipionMsg enum from EC_FixedMsg.cs // Scale Types public const int SCALE_SELL = 1; @@ -261,55 +201,80 @@ namespace PerfectWorld.Scripts.Managers return GetBaseStatsDesc(); } - private string GetBaseStatsDesc() + private void AddBaseStatsDesc(int[] aPEEVals, int[] aRefines) { elementdataman edm = ElementDataManProvider.GetElementDataMan(); - if (edm == null) return string.Empty; + if (edm == null) return; try { DATA_TYPE dt = DATA_TYPE.DT_INVALID; object data = edm.get_data_ptr(unchecked((uint)TemplateId), ID_SPACE.ID_SPACE_ESSENCE, ref dt); if (data == null) data = TryFindElementByScanningArraysLocal(edm, unchecked((uint)TemplateId)); - if (data == null) return string.Empty; + if (data == null) return; + + int white = (int)DescriptipionMsg.ITEMDESC_COL_WHITE; + int lblue = (int)DescriptipionMsg.ITEMDESC_COL_LIGHTBLUE; // Try weapon-style fields first - int dmgLow = 0, dmgHighMax = 0; + int dmgLow = 0, dmgHigh = 0; bool hasDmgLow = TryGetNumber(data, new[] { "damage_low" }, out dmgLow); - bool hasDmgHighMax = TryGetNumber(data, new[] { "damage_high_max", "damage_high" }, out dmgHighMax); + bool hasDmgHigh = TryGetNumber(data, new[] { "damage_high_max", "damage_high" }, out dmgHigh); - List lines = new List(); - - if (hasDmgLow && hasDmgHighMax) + if (hasDmgLow && hasDmgHigh) { - // Physical damage range - lines.Add(string.Format("{0} {1}-{2}", GetItemDescString(ITEMDESC_ADDPHYDAMAGE), dmgLow, dmgHighMax)); + // Physical damage range - adjust by aPEEVals and aRefines (like C++: m_Essence.damage_low - aPEEVals[PEEI_PHYDAMAGE] + aRefines[REFINE_PHYDAMAGE]) + int adjDmgLow = dmgLow - aPEEVals[PEEI_PHYDAMAGE] + aRefines[REFINE_PHYDAMAGE]; + int adjDmgHigh = dmgHigh - aPEEVals[PEEI_PHYDAMAGE] - aPEEVals[PEEI_MAX_PHYDAMAGE] + aRefines[REFINE_PHYDAMAGE]; + + if (adjDmgLow > 0 || adjDmgHigh > 0 || aRefines[REFINE_PHYDAMAGE] != 0) + { + string dmgFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDAMAGE); + AddDescText(white, false, dmgFmt); + AddDescText(white, true, " {0}-{1}", adjDmgLow, adjDmgHigh); + } // Magic damage if available if (TryGetNumber(data, new[] { "magic_damage_low" }, out int mdLow) && TryGetNumber(data, new[] { "magic_damage_high_max", "magic_damage_high" }, out int mdHigh)) { - lines.Add(string.Format("{0} {1}-{2}", GetItemDescString(ITEMDESC_ADDMAGICDAMAGE), mdLow, mdHigh)); + int adjMdLow = mdLow - aPEEVals[PEEI_MAGICDAMAGE] + aRefines[REFINE_MAGICDAMAGE]; + int adjMdHigh = mdHigh - aPEEVals[PEEI_MAGICDAMAGE] - aPEEVals[PEEI_MAX_MAGICDAMAGE] + aRefines[REFINE_MAGICDAMAGE]; + + if (adjMdLow > 0 || adjMdHigh > 0 || aRefines[REFINE_MAGICDAMAGE] != 0) + { + string mdFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_MAGICDAMAGE); + AddDescText(white, false, mdFmt); + AddDescText(white, true, " {0}-{1}", adjMdLow, adjMdHigh); + } } - // Attack time/speed - float atkTime; - if (TryGetNumber(data, new[] { "attack_time", "atk_time" }, out atkTime) && atkTime > 0.0001f) + // Attack time/speed - adjust color based on PEE_ATKSPEED + int atkCol = white; + if ((PropEffectEssence() & (1 << PEEI_ATKSPEED)) != 0) + atkCol = lblue; + + if (TryGetNumber(data, new[] { "attack_speed", "atk_speed" }, out float atkSpeed) && atkSpeed > 0) { - // Show speed in attacks per second (1 / time) - float aps = 1.0f / atkTime; - lines.Add(string.Format("{0} {1:F2}", GetItemDescString(ITEMDESC_ATKTIME), aps)); - } - else if (TryGetNumber(data, new[] { "attack_speed", "atk_speed" }, out float atkSpeed) && atkSpeed > 0) - { - lines.Add(string.Format("{0} {1:F2}", GetItemDescString(ITEMDESC_ATKTIME), atkSpeed)); + // Show speed in attacks per second (1 / (attack_speed * 0.05)) + float aps = 1.0f / (atkSpeed * 0.05f); + string atkFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_ATKSPEED); + if (atkFmt.Contains("%.2f") || atkFmt.Contains("%f")) + AddDescText(atkCol, true, atkFmt, aps); + else + AddDescText(atkCol, true, "{0} {1:F2}", atkFmt, aps); } - // Range + // Range - adjust by aPEEVals[PEEI_ATKDIST] float range; if (TryGetNumber(data, new[] { "range", "attack_range", "atk_range" }, out range)) { - lines.Add(string.Format("{0} {1:F2}", GetItemDescString(ITEMDESC_ADDATKDIST), range)); + float adjRange = range - BitConverter.ToSingle(BitConverter.GetBytes(aPEEVals[PEEI_ATKDIST]), 0); + string rangeFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_ATKDISTANCE); + if (rangeFmt.Contains("%") && (rangeFmt.Contains("f") || rangeFmt.Contains("d"))) + AddDescText(white, true, rangeFmt, adjRange); + else + AddDescText(white, true, "{0} {1:F2}", rangeFmt, adjRange); } } else @@ -317,32 +282,152 @@ namespace PerfectWorld.Scripts.Managers // Try armor-style fields if (TryGetNumber(data, new[] { "defence_high", "defense_high", "defence", "defense" }, out int defHigh)) { - lines.Add(string.Format("{0} +{1}", GetItemDescString(ITEMDESC_PHYDEFENCE), defHigh)); + int adjDef = defHigh - aPEEVals[PEEI_PHYDEF] + aRefines[REFINE_PHYDEF]; + if (adjDef > 0 || aRefines[REFINE_PHYDEF] != 0) + { + string defFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDEFENCE); + AddDescText(white, false, defFmt); + AddDescText(white, true, " {0:+0;-#;+0}", adjDef); + } } - // Elemental resistances (look for *_resist or specific names) - (string label, string[] names)[] res = new (string, string[])[] + // Dodge + if (TryGetNumber(data, new[] { "armor", "dodge" }, out int dodge)) { - (GetItemDescString(ITEMDESC_GOLDDEFENCE), new[]{"resist_metal","resistance_metal","gold_resist"}), - (GetItemDescString(ITEMDESC_WOODDEFENCE), new[]{"resist_wood","resistance_wood","wood_resist"}), - (GetItemDescString(ITEMDESC_WATERDEFENCE), new[]{"resist_water","resistance_water","water_resist"}), - (GetItemDescString(ITEMDESC_FIREDEFENCE), new[]{"resist_fire","resistance_fire","fire_resist"}), - (GetItemDescString(ITEMDESC_EARTHDEFENCE), new[]{"resist_earth","resistance_earth","earth_resist"}) + int adjDodge = dodge - aPEEVals[PEEI_DODGE] + aRefines[REFINE_DODGE]; + if (adjDodge > 0 || aRefines[REFINE_DODGE] != 0) + { + string dodgeFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_DODGE); + AddDescText(white, false, dodgeFmt); + AddDescText(white, true, " {0:+0;-#;+0}", adjDodge); + } + } + + // HP + if (TryGetNumber(data, new[] { "hp_enhance", "hp" }, out int hp)) + { + int adjHp = hp - aPEEVals[PEEI_HP] + aRefines[REFINE_HP]; + if (adjHp > 0 || aRefines[REFINE_HP] != 0) + { + string hpFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_ADDHP); + AddDescText(white, false, hpFmt); + AddDescText(white, true, " {0:+0;-#;+0}", adjHp); + } + } + + // MP + if (TryGetNumber(data, new[] { "mp_enhance", "mp" }, out int mp)) + { + int adjMp = mp - aPEEVals[PEEI_MP]; + if (adjMp > 0) + { + string mpFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_ADDMP); + AddDescText(white, false, mpFmt); + AddDescText(white, true, " {0:+0;-#;+0}", adjMp); + } + } + + // Elemental resistances - adjust by aPEEVals and aRefines + // In C++: m_Essence.resistance[MAGICCLASS_GOLD] - aPEEVals[PEEI_GOLDDEF] + aRefines[REFINE_GOLDDEF] + // In C# struct: resistance is stored in magic_defences array + (DescriptipionMsg descId, int refineIdx, int peeIdx, int magicClassIdx)[] res = new (DescriptipionMsg, int, int, int)[] + { + (DescriptipionMsg.ITEMDESC_GOLDDEFENCE, REFINE_GOLDDEF, PEEI_GOLDDEF, 0), // MAGICCLASS_GOLD = 0 + (DescriptipionMsg.ITEMDESC_WOODDEFENCE, REFINE_WOODDEF, PEEI_WOODDEF, 1), // MAGICCLASS_WOOD = 1 + (DescriptipionMsg.ITEMDESC_WATERDEFENCE, REFINE_WATERDEF, PEEI_WATERDEF, 2), // MAGICCLASS_WATER = 2 + (DescriptipionMsg.ITEMDESC_FIREDEFENCE, REFINE_FIREDEF, PEEI_FIREDEF, 3), // MAGICCLASS_FIRE = 3 + (DescriptipionMsg.ITEMDESC_EARTHDEFENCE, REFINE_EARTHDEF, PEEI_EARTHDEF, 4) // MAGICCLASS_EARTH = 4 }; + + // Try to read from magic_defences array first (C# struct format) + bool foundResistanceArray = false; + try + { + var dataType = data.GetType(); + var magicDefencesField = dataType.GetField("magic_defences"); + if (magicDefencesField != null) + { + var magicDefences = magicDefencesField.GetValue(data); + if (magicDefences != null && magicDefences is Array) + { + foundResistanceArray = true; + Array arr = (Array)magicDefences; + for (int i = 0; i < res.Length && i < arr.Length; i++) + { + var magicDef = arr.GetValue(i); + if (magicDef != null) + { + var highField = magicDef.GetType().GetField("high"); + if (highField != null) + { + int v = Convert.ToInt32(highField.GetValue(magicDef)); + var descId = res[i].descId; + var refineIdx = res[i].refineIdx; + var peeIdx = res[i].peeIdx; + + int adjV = v - aPEEVals[peeIdx] + aRefines[refineIdx]; + if (adjV > 0 || aRefines[refineIdx] != 0) + { + string resFmt = GetItemDescString(descId); + AddDescText(white, false, resFmt); + AddDescText(white, true, " {0:+0;-#;+0}", adjV); + } + } + } + } + } + } + } + catch { } + + // Fallback: try reading from individual fields if array method didn't work + if (!foundResistanceArray) + { for (int i = 0; i < res.Length; i++) { - var label = res[i].label; - var names = res[i].names; + var descId = res[i].descId; + var refineIdx = res[i].refineIdx; + var peeIdx = res[i].peeIdx; + var magicClassIdx = res[i].magicClassIdx; + + // Try multiple field name patterns + string[] names = new[] + { + $"magic_defences[{magicClassIdx}].high", + $"magic_defences_{magicClassIdx}_high", + $"resistance_{magicClassIdx}", + $"resist_{magicClassIdx}", + "resist_metal", "resistance_metal", "gold_resist" // For index 0 + }; + if (TryGetNumber(data, names, out int v)) { - lines.Add(string.Format("{0} +{1}", label, v)); + int adjV = v - aPEEVals[peeIdx] + aRefines[refineIdx]; + if (adjV > 0 || aRefines[refineIdx] != 0) + { + string resFmt = GetItemDescString(descId); + AddDescText(white, false, resFmt); + AddDescText(white, true, " {0:+0;-#;+0}", adjV); } } } - - return string.Join("\\r", lines); + } + } } - catch { return string.Empty; } + catch { } + } + + // Keep old method for backward compatibility + private string GetBaseStatsDesc() + { + string oldDesc = m_strDesc; + m_strDesc = ""; + int[] emptyPEE = new int[MAX_PEEINDEX]; + int[] emptyRefines = new int[MAX_REFINEINDEX]; + AddBaseStatsDesc(emptyPEE, emptyRefines); + string result = m_strDesc; + m_strDesc = oldDesc; + return result; } private static object TryFindElementByScanningArraysLocal(object edm, uint id) @@ -721,7 +806,7 @@ namespace PerfectWorld.Scripts.Managers Maker = colorStr + Maker; // Add equipment mark display string - Maker = string.Format(GetItemDescString(ITEMDESC_EQUIPMARK), Maker); + Maker = string.Format(GetItemDescString(DescriptipionMsg.ITEMDESC_EQUIPMARK), Maker); } MadeFrom = string.IsNullOrEmpty(mark) ? IMT_NULL : IMT_SIGN; } @@ -1177,16 +1262,16 @@ namespace PerfectWorld.Scripts.Managers if (index >= 0) return index; - int col = ITEMDESC_COL_WHITE; + int col = (int)DescriptipionMsg.ITEMDESC_COL_WHITE; switch (FixProps) { - case 1: col = ITEMDESC_COL_GREEN; break; - case 2: col = ITEMDESC_COL_YELLOW; break; - case 3: col = ITEMDESC_COL_DARKGOLD; break; + case 1: col = (int)DescriptipionMsg.ITEMDESC_COL_GREEN; break; + case 2: col = (int)DescriptipionMsg.ITEMDESC_COL_YELLOW; break; + case 3: col = (int)DescriptipionMsg.ITEMDESC_COL_DARKGOLD; break; default: if (PropNum > 0) - col = ITEMDESC_COL_LIGHTBLUE; + col = (int)DescriptipionMsg.ITEMDESC_COL_LIGHTBLUE; break; } @@ -1204,7 +1289,100 @@ namespace PerfectWorld.Scripts.Managers #endregion - #region Description Methods + #region Description Methods (high level entry points) + + /// + /// Get normal in-inventory description, mirroring C++ CECIvtrEquip::GetNormalDesc. + /// This is a single formatted string using ^color codes and '\\r' as line separators. + /// + public string GetNormalDesc() + { + // Build addon and refine properties and save it (like C++ does first) + int[] aPEEVals = new int[MAX_PEEINDEX]; + int[] aRefines = new int[MAX_REFINEINDEX]; + for (int i = 0; i < MAX_PEEINDEX; i++) + aPEEVals[i] = 0; + for (int i = 0; i < MAX_REFINEINDEX; i++) + aRefines[i] = 0; + + m_strDesc = ""; + BuildAddOnPropDesc(aPEEVals, aRefines); + string strAddon = m_strDesc; + + // Reset and build description from scratch + m_strDesc = ""; + + int white = (int)DescriptipionMsg.ITEMDESC_COL_WHITE; + int lblue = (int)DescriptipionMsg.ITEMDESC_COL_LIGHTBLUE; + int red = (int)DescriptipionMsg.ITEMDESC_COL_RED; + + // 1) Item name + AddDescText(white, true, GetItemDescString(DescriptipionMsg.ITEMDESC_NAME), GetName()); + + // 1.5) Sub class name (loại trang bị) - like C++: AddDescText(white, true, pDescTab->GetWideString(ITEMDESC_CLASSNAME), m_pDBSubType->name); + // In C++, this is always called (no null check), so we always call it too + string subTypeName = GetSubTypeName(); + AddDescText(white, true, GetItemDescString(DescriptipionMsg.ITEMDESC_CLASSNAME), subTypeName ?? ""); + + // 1.6) Item level (cấp vũ khí/trang bị) - like C++: AddDescText(-1, true, pDescTab->GetWideString(ITEMDESC_LEVEL), m_Essence.weapon_level); + int itemLevel = GetItemLevel(); + if (itemLevel > 0) + { + AddDescText(-1, true, GetItemDescString(DescriptipionMsg.ITEMDESC_LEVEL), itemLevel); + } + + // 2) Base stats from element data (damage/defence/speed/range/resists) + // Adjust base stats by subtracting aPEEVals and adding aRefines + AddBaseStatsDesc(aPEEVals, aRefines); + + // 3) Endurance (current / max) - adjust color based on PEE_ENDURANCE + if (MaxEndurance > 0) + { + int col = white; + if (CurEndurance == 0) + col = red; + else if ((PropEffectEssence() & (1 << PEEI_ENDURANCE)) != 0) + col = lblue; + + int curVis = VisualizeEndurance(CurEndurance); + int maxVis = VisualizeEndurance(MaxEndurance); + AddDescText(col, true, "{0} {1}/{2}", + GetItemDescString(DescriptipionMsg.ITEMDESC_ENDURANCE), curVis, maxVis); + } + + // 4) Requirements (level / stats / reputation) + AddRequirementDesc(aPEEVals); + AddReputationReqDesc(); + + // 4.5) Profession restriction (phái hạn chế) - like C++: AddProfReqDesc(m_iProfReq); + // In C++, this is always called regardless of value (the function checks internally) + AddProfReqDesc(ProfReq); + + // 5) Add-on properties (non-embedded, non-suite, non-engraved) + if (!string.IsNullOrEmpty(strAddon)) + m_strDesc += strAddon; + + // 6) Tessera / stones (socketed gems) + BuildTesseraDesc(); + + // 7) Sharpener properties + AddSharpenerDesc(); + + // 8) Engraved properties + AddEngravedDesc(); + + // 9) Suite information + AddSuiteDesc(); + + // 10) Maker & destroying info if any + AddMakerDesc(); + // Destroying description is added by caller when needed; keep it optional here. + + // 11) Price (sell price scaled) + AddPriceDesc(white, false); + + return m_strDesc; + } /// /// Get item description for booth buying @@ -1213,16 +1391,16 @@ namespace PerfectWorld.Scripts.Managers { m_strDesc = ""; - int white = ITEMDESC_COL_WHITE; + int white = (int)DescriptipionMsg.ITEMDESC_COL_WHITE; // Item name - AddDescText(white, true, GetItemDescString(ITEMDESC_NAME), GetName()); + AddDescText(white, true, GetItemDescString(DescriptipionMsg.ITEMDESC_NAME), GetName()); // Base stats from element data string baseStats = GetBaseStatsDesc(); if (!string.IsNullOrEmpty(baseStats)) { - m_strDesc += GetColorString(ITEMDESC_COL_WHITE); + m_strDesc += GetColorString(DescriptipionMsg.ITEMDESC_COL_WHITE); m_strDesc += baseStats; m_strDesc += "\\r"; } @@ -1242,13 +1420,353 @@ namespace PerfectWorld.Scripts.Managers return m_strDesc; } + /// + /// Add concise requirement description (level / stats / profession). + /// This is a simplified mirror of the original C++ text; colors are kept white for now. + /// + private void AddRequirementDesc(int[] aPEEVals) + { + int white = (int)DescriptipionMsg.ITEMDESC_COL_WHITE; + int lblue = (int)DescriptipionMsg.ITEMDESC_COL_LIGHTBLUE; + + // Get host player for requirement checks (via GameRun if available) + object hostPlayer = null; + try + { + var gameRun = EC_Game.GetGameRun(); + if (gameRun != null) + { + // Try to get host player - method name may vary + hostPlayer = gameRun; // Placeholder - would need actual GetHostPlayer() method + } + } + catch { } + + uint dwPEE = PropEffectEssence(); + + // Level requirement + if (LevelReq > 0) + { + int col = white; + if (hostPlayer != null) + { + // In C++: pHost->GetMaxLevelSofar() >= m_iLevelReq ? white : red + // For now, use a simple check - would need GetMaxLevelSofar() equivalent + col = white; // TODO: Check actual player level + } + + string levelFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_LEVELREQ); + if (levelFmt.Contains("%d")) + AddDescText(col, true, levelFmt, LevelReq); + else + AddDescText(col, true, "{0} {1}", levelFmt, LevelReq); + } + + // Stat requirements - adjust color based on PEE flags and player stats + if (StrengthReq > 0) + { + int col = white; + if (hostPlayer != null) + { + // In C++: pHost->GetExtendProps().bs.strength < m_iStrengthReq ? red : ((dwPEE & PEE_STRENGTHREQ) ? lblue : white) + // For now, use simple check + if ((dwPEE & (1 << PEEI_STRENGTHREQ)) != 0) + col = lblue; + // TODO: Check actual player strength + } + + string strFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_STRENGTHREQ); + if (strFmt.Contains("%d")) + AddDescText(col, true, strFmt, StrengthReq); + else + AddDescText(col, true, "{0} {1}", strFmt, StrengthReq); + } + if (AgilityReq > 0) + { + int col = white; + if (hostPlayer != null) + { + if ((dwPEE & (1 << PEEI_AGILITYREQ)) != 0) + col = lblue; + // TODO: Check actual player agility + } + + string agiFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_AGILITYREQ); + if (agiFmt.Contains("%d")) + AddDescText(col, true, agiFmt, AgilityReq); + else + AddDescText(col, true, "{0} {1}", agiFmt, AgilityReq); + } + if (VitalityReq > 0) + { + int col = white; + if (hostPlayer != null) + { + // TODO: Check PEE_VITALITYREQ flag and player vitality + } + + string vitFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_VITALITYREQ); + if (vitFmt.Contains("%d")) + AddDescText(col, true, vitFmt, VitalityReq); + else + AddDescText(col, true, "{0} {1}", vitFmt, VitalityReq); + } + if (EnergyReq > 0) + { + int col = white; + if (hostPlayer != null) + { + // TODO: Check PEE_ENERGYREQ flag and player energy + } + + string eneFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_ENERGYREQ); + if (eneFmt.Contains("%d")) + AddDescText(col, true, eneFmt, EnergyReq); + else + AddDescText(col, true, "{0} {1}", eneFmt, EnergyReq); + } + } + + /// + /// Get sub type name (loại trang bị) from element data + /// + private string GetSubTypeName() + { + elementdataman edm = ElementDataManProvider.GetElementDataMan(); + if (edm == null) return null; + + try + { + DATA_TYPE dt = DATA_TYPE.DT_INVALID; + object data = edm.get_data_ptr(unchecked((uint)TemplateId), ID_SPACE.ID_SPACE_ESSENCE, ref dt); + if (data == null) data = TryFindElementByScanningArraysLocal(edm, unchecked((uint)TemplateId)); + if (data == null) return null; + + // Get id_sub_type from essence + uint idSubType = 0; + if (TryGetNumber(data, new[] { "id_sub_type" }, out idSubType) && idSubType > 0) + { + // Try to get sub type data - check if it's weapon or armor + DATA_TYPE subTypeDt = DATA_TYPE.DT_INVALID; + object subTypeData = null; + + // Try weapon sub type first + subTypeData = edm.get_data_ptr(idSubType, ID_SPACE.ID_SPACE_ESSENCE, ref subTypeDt); + if (subTypeDt == DATA_TYPE.DT_WEAPON_SUB_TYPE) + { + var nameField = subTypeData.GetType().GetField("name"); + if (nameField != null) + { + var nameArray = nameField.GetValue(subTypeData); + if (nameArray != null && nameArray is ushort[]) + { + return ByteToStringUtils.UshortArrayToUnicodeString((ushort[])nameArray); + } + } + } + + // Try armor sub type + subTypeDt = DATA_TYPE.DT_INVALID; + subTypeData = edm.get_data_ptr(idSubType, ID_SPACE.ID_SPACE_ESSENCE, ref subTypeDt); + if (subTypeDt == DATA_TYPE.DT_ARMOR_SUB_TYPE) + { + var nameField = subTypeData.GetType().GetField("name"); + if (nameField != null) + { + var nameArray = nameField.GetValue(subTypeData); + if (nameArray != null && nameArray is ushort[]) + { + return ByteToStringUtils.UshortArrayToUnicodeString((ushort[])nameArray); + } + } + } + } + } + catch { } + + return null; + } + + /// + /// Get item level (cấp vũ khí/trang bị) from element data + /// + private int GetItemLevel() + { + elementdataman edm = ElementDataManProvider.GetElementDataMan(); + if (edm == null) return 0; + + try + { + DATA_TYPE dt = DATA_TYPE.DT_INVALID; + object data = edm.get_data_ptr(unchecked((uint)TemplateId), ID_SPACE.ID_SPACE_ESSENCE, ref dt); + if (data == null) data = TryFindElementByScanningArraysLocal(edm, unchecked((uint)TemplateId)); + if (data == null) return 0; + + // Try weapon_level first (for weapons) + if (TryGetNumber(data, new[] { "weapon_level" }, out int weaponLevel) && weaponLevel > 0) + return weaponLevel; + + // Try level (for armor and other items) + if (TryGetNumber(data, new[] { "level" }, out int level) && level > 0) + return level; + } + catch { } + + return 0; + } + + /// + /// Get character combo ID (phái hạn chế) from element data + /// + private uint GetCharacterComboId() + { + elementdataman edm = ElementDataManProvider.GetElementDataMan(); + if (edm == null) return 0; + + try + { + DATA_TYPE dt = DATA_TYPE.DT_INVALID; + object data = edm.get_data_ptr(unchecked((uint)TemplateId), ID_SPACE.ID_SPACE_ESSENCE, ref dt); + if (data == null) data = TryFindElementByScanningArraysLocal(edm, unchecked((uint)TemplateId)); + if (data == null) return 0; + + if (TryGetNumber(data, new[] { "character_combo_id" }, out uint comboId)) + return comboId; + } + catch { } + + return 0; + } + + /// + /// Add profession requirement description (phái hạn chế) + /// Like C++: AddProfReqDesc(int iProfReq) - displays class restrictions + /// + private void AddProfReqDesc(int profReq) + { + // In C++: if (CECProfConfig::Instance().ContainsAllProfession(iProfReq)) return; + // Check if all professions are allowed - if so, don't display restriction + // If profReq == 0, it means no restriction (all professions allowed) + // If all 12 bits are set (0xFFF = 4095), it also means all professions allowed + if (profReq == 0) + return; // No restriction + + const int NUM_PROFESSION = 12; + const int allProfMask = (1 << NUM_PROFESSION) - 1; // 0xFFF = 4095 (all 12 bits set) + if ((profReq & allProfMask) == allProfMask) + return; // All professions allowed + + // Check if any profession bit is set - if none, don't display + bool hasAnyProf = false; + for (int i = 0; i < NUM_PROFESSION; i++) + { + if ((profReq & (1 << i)) != 0) + { + hasAnyProf = true; + break; + } + } + if (!hasAnyProf) + return; // No profession restriction specified + + int white = (int)DescriptipionMsg.ITEMDESC_COL_WHITE; + int red = (int)DescriptipionMsg.ITEMDESC_COL_RED; + + // Get host player profession for color check + int playerProf = -1; + try + { + var gameRun = EC_Game.GetGameRun(); + if (gameRun != null) + { + var hostPlayer = gameRun.GetHostPlayer(); + if (hostPlayer != null) + { + playerProf = hostPlayer.GetProfession(); + } + } + } + catch { } + + int col = white; + if (playerProf >= 0) + { + // In C++: col = (iProfReq & (1 << pHost->GetProfession())) ? ITEMDESC_COL_WHITE : ITEMDESC_COL_RED; + if ((profReq & (1 << playerProf)) == 0) + col = red; + } + + string profFmt = GetItemDescString(DescriptipionMsg.ITEMDESC_PROFESSIONREQ); + AddDescText(col, false, profFmt); + + // List all allowed professions + // In C++: for (int i=0; i < NUM_PROFESSION; i++) { if (iProfReq & (1 << i)) { m_strDesc += _AL(" "); AddDescText(col, false, pGameRun->GetProfName(i)); } } + // Profession message IDs matching C++ GetProfName: FIXMSG_PROF_WARRIOR, FIXMSG_PROF_MAGE, etc. + FixedMsg[] profMsgIds = new FixedMsg[] + { + FixedMsg.FIXMSG_PROF_WARRIOR, // 0 + FixedMsg.FIXMSG_PROF_MAGE, // 1 + FixedMsg.FIXMSG_PROF_MONK, // 2 + FixedMsg.FIXMSG_PROF_HAG, // 3 + FixedMsg.FIXMSG_PROF_ORC, // 4 + FixedMsg.FIXMSG_PROF_GHOST, // 5 + FixedMsg.FIXMSG_PROF_ARCHOR, // 6 + FixedMsg.FIXMSG_PROF_ANGEL, // 7 + FixedMsg.FIXMSG_PROF_JIANLING, // 8 + FixedMsg.FIXMSG_PROF_MEILING, // 9 + FixedMsg.FIXMSG_PROF_YEYING, // 10 + FixedMsg.FIXMSG_PROF_YUEXIAN // 11 + }; + + for (int i = 0; i < NUM_PROFESSION && i < profMsgIds.Length; i++) + { + if ((profReq & (1 << i)) != 0) + { + // In C++, space is always added before each profession name + m_strDesc += " "; + // Get profession name from fixed messages (like C++ GetProfName does) + // C++ uses: pStrTab->GetWideString(s_ProfDesc[i]) where s_ProfDesc[i] = FIXMSG_PROF_WARRIOR, etc. + string profName = null; + try + { + var fixedMsgs = EC_Game.GetFixedMsgs(); + if (fixedMsgs != null && fixedMsgs.IsInitialized()) + { + profName = fixedMsgs.GetWideString((int)profMsgIds[i]); + // Trim whitespace if present + if (!string.IsNullOrEmpty(profName)) + profName = profName.Trim(); + } + } + catch (Exception ex) + { + UnityEngine.Debug.LogWarning($"[EC_IvtrEquip] Failed to get profession name for index {i}: {ex.Message}"); + } + + // If we got a valid name, use it; otherwise use fallback + if (!string.IsNullOrEmpty(profName)) + { + AddDescText(col, false, profName); + } + else + { + // Fallback: show profession index (should not happen if fixed_msg.txt is loaded correctly) + UnityEngine.Debug.LogWarning($"[EC_IvtrEquip] Profession name not found for index {i}, enum value {(int)profMsgIds[i]}, profReq={profReq}"); + AddDescText(col, false, $"P{i}"); + } + } + } + + m_strDesc += "\\r"; + } + /// /// Add price description /// public void AddPriceDesc(int col, bool repair) { if (repair) - AddDescText(col, false, GetItemDescString(ITEMDESC_REPAIRCOST), GetRepairCost()); + AddDescText(col, false, GetItemDescString(DescriptipionMsg.ITEMDESC_REPAIRCOST), GetRepairCost()); else AddDescText(col, true, "Price: {0}", GetScaledPrice()); } @@ -1270,12 +1788,254 @@ namespace PerfectWorld.Scripts.Managers /// /// Format refine data into a string + /// (hack function, do NOT use it in multi-thread environment) /// public string FormatRefineData(uint addonId) { - // This would normally query the equipment addon data - // For now, return empty string + DATA_TYPE dataType = DATA_TYPE.DT_INVALID; + elementdataman edm = EC_Game.GetElementDataMan(); + if (edm == null) return ""; + + object data = edm.get_data_ptr(addonId, ID_SPACE.ID_SPACE_ADDON, ref dataType); + if (dataType != DATA_TYPE.DT_EQUIPMENT_ADDON || data == null) + return ""; + + EQUIPMENT_ADDON pType = (EQUIPMENT_ADDON)data; + string szTxt = ""; + + // save current member for backup + string tmpDesc = m_strDesc; + m_strDesc = ""; + + // get the original refine data + int[] aRefines = new int[MAX_REFINEINDEX]; + for (int i = 0; i < MAX_REFINEINDEX; i++) + aRefines[i] = 0; + + int[] paramArray = new int[] { pType.param1, pType.param2, pType.param3 }; + AddOneAddOnPropDesc((int)pType.id, paramArray, null, aRefines, true); + + // get splitter + // In C++: g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan()->GetStringFromTable(8656) + string szSplitter = " "; // Default splitter + try + { + var gameRun = EC_Game.GetGameRun(); + if (gameRun != null) + { + // Try to get from UI manager if available + // Note: This may not be fully implemented in C# yet + var fixedMsgs = EC_Game.GetFixedMsgs(); + if (fixedMsgs != null) + { + string splitterStr = fixedMsgs.GetWideString(8656); + if (!string.IsNullOrEmpty(splitterStr)) + szSplitter = splitterStr; + } + } + } + catch + { + // Use default splitter if lookup fails + } + + int findSplitter = 0; + for (int pos = 0; pos < szSplitter.Length; pos++) + { + findSplitter = m_strDesc.IndexOf(szSplitter[pos]); + if (findSplitter >= 0) + break; + } + + szTxt = (findSplitter <= 0) ? m_strDesc : m_strDesc.Substring(0, findSplitter); + + // restore member because previous method may modify it + m_strDesc = tmpDesc; + + // replace all old splitter to new splitter + const string OldSplitter = "\\r"; + const string NewSplitter = " "; + string result = ""; + findSplitter = 0; + while (true) + { + int curfind = szTxt.IndexOf(OldSplitter, findSplitter); + if (curfind >= 0) + { + if (!string.IsNullOrEmpty(result)) + result += NewSplitter; + if (curfind > findSplitter) + { + result += szTxt.Substring(findSplitter, curfind - findSplitter); + } + findSplitter = curfind + OldSplitter.Length; + if (findSplitter >= szTxt.Length) + break; + } + else + { + if (!string.IsNullOrEmpty(result)) + result += NewSplitter; + result += szTxt.Substring(findSplitter); + break; + } + } + szTxt = result; + + // check the special refine property group + int[] ALLMAGIC_REFINE = new int[] { REFINE_GOLDDEF, REFINE_WOODDEF, REFINE_WATERDEF, REFINE_FIREDEF, REFINE_EARTHDEF }; + int[] ALLDAMAGE_REFINE = new int[] { REFINE_PHYDAMAGE, REFINE_MAGICDAMAGE }; + int[] ALLDEFENCE_REFINE = new int[] { REFINE_PHYDEF, REFINE_GOLDDEF, REFINE_WOODDEF, REFINE_WATERDEF, REFINE_FIREDEF, REFINE_EARTHDEF }; + + if (CheckSpecialRefineType(aRefines, ALLMAGIC_REFINE, ALLMAGIC_REFINE.Length)) + { + int value = aRefines[ALLMAGIC_REFINE[0]]; + // Format with %+d equivalent: always show sign + string szRefine = string.Format("{0} {1}{2}", + GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICDEF), + value >= 0 ? "+" : "", value); + if (!string.IsNullOrEmpty(szTxt)) + szTxt += NewSplitter; + szTxt += szRefine; + } + else if (CheckSpecialRefineType(aRefines, ALLDAMAGE_REFINE, ALLDAMAGE_REFINE.Length)) + { + int value = aRefines[ALLDAMAGE_REFINE[0]]; + // Format with %+d equivalent: always show sign + string szRefine = string.Format("{0} {1}{2}", + GetItemDescString(DescriptipionMsg.ITEMDESC_ADDDAMAGE), + value >= 0 ? "+" : "", value); + if (!string.IsNullOrEmpty(szTxt)) + szTxt += NewSplitter; + szTxt += szRefine; + } + else if (CheckSpecialRefineType(aRefines, ALLDEFENCE_REFINE, ALLDEFENCE_REFINE.Length)) + { + int value = aRefines[ALLDEFENCE_REFINE[0]]; + // Format with %+d equivalent: always show sign + string szRefine = string.Format("{0} {1}{2}", + GetItemDescString(DescriptipionMsg.ITEMDESC_DEFENCE), + value >= 0 ? "+" : "", value); + if (!string.IsNullOrEmpty(szTxt)) + szTxt += NewSplitter; + szTxt += szRefine; + } + else + { + int descId = 0; + for (int refineIndex = 0; refineIndex < MAX_REFINEINDEX; refineIndex++) + { + if (aRefines[refineIndex] == 0) + continue; + + // do NOT use loop because the enum value may changed + switch (refineIndex) + { + case REFINE_PHYDAMAGE: + descId = (int)DescriptipionMsg.ITEMDESC_ADDPHYDAMAGE; + break; + case REFINE_MAGICDAMAGE: + descId = (int)DescriptipionMsg.ITEMDESC_ADDMAGICDAMAGE; + break; + case REFINE_PHYDEF: + descId = (int)DescriptipionMsg.ITEMDESC_PHYDEFENCE; + break; + case REFINE_GOLDDEF: + descId = (int)DescriptipionMsg.ITEMDESC_GOLDDEFENCE; + break; + case REFINE_WOODDEF: + descId = (int)DescriptipionMsg.ITEMDESC_WOODDEFENCE; + break; + case REFINE_WATERDEF: + descId = (int)DescriptipionMsg.ITEMDESC_WATERDEFENCE; + break; + case REFINE_FIREDEF: + descId = (int)DescriptipionMsg.ITEMDESC_FIREDEFENCE; + break; + case REFINE_EARTHDEF: + descId = (int)DescriptipionMsg.ITEMDESC_EARTHDEFENCE; + break; + case REFINE_HP: + descId = (int)DescriptipionMsg.ITEMDESC_ADDHP; + break; + case REFINE_DODGE: + descId = (int)DescriptipionMsg.ITEMDESC_DODGE; + break; + default: + descId = -1; + break; + } + + if (descId >= 0) + { + int value = aRefines[refineIndex]; + // Format with %+d equivalent: always show sign + string szRefine = string.Format("{0} {1}{2} ", + GetItemDescString((DescriptipionMsg)descId), + value >= 0 ? "+" : "", value); + if (!string.IsNullOrEmpty(szTxt)) + szTxt += NewSplitter; + szTxt += szRefine; + } + } + } + + return szTxt; + } + + /// + /// Get refine addon ID (virtual method, override in derived classes) + /// + public virtual uint GetRefineAddOn() + { + return 0; + } + + /// + /// Check the special refine property + /// + private bool CheckSpecialRefineType(int[] aRefines, int[] types, int typeCount) + { + // check the special refine property + int sameValue = 0; + + for (int refineIndex = 0; refineIndex < MAX_REFINEINDEX; refineIndex++) + { + bool checked_ = false; + for (int i = 0; i < typeCount; i++) + { + if (types[i] == refineIndex) + { + if (sameValue == 0) + { + if (aRefines[refineIndex] == 0) + { + // specific property was not found + return false; + } + sameValue = aRefines[refineIndex]; + } + else if (sameValue != aRefines[refineIndex]) + { + // property values were different + return false; + } + + checked_ = true; + break; + } + } + + // check other refine property + if (!checked_ && aRefines[refineIndex] != 0) + { + // has other refine property + return false; + } + } + + return true; } /// @@ -1375,50 +2135,87 @@ namespace PerfectWorld.Scripts.Managers /// /// Get item description string by ID + /// Primary source: item_desc.txt table (loaded via EC_Game.GetItemDesc()) + /// Fallback: Directly reads from item_desc.txt file when table lookup fails /// - private string GetItemDescString(int id) + private string GetItemDescString(DescriptipionMsg id) { + int enumValue = (int)id; + + // First try to get from the loaded string table (item_desc.txt) + // The table contains strings indexed 0-416, matching enum values var tab = EC_Game.GetItemDesc(); - if (tab != null && tab.IsInitialized()) + if (tab != null) { - string s = tab.GetWideString(id); + string s = tab.GetWideString(enumValue); if (!string.IsNullOrEmpty(s)) return s; } - // Fallback labels for common IDs when the table lacks #_index entries - switch (id) + + // Fallback: Directly read f rom item_desc.txt file + // This handles cases where table lookup fails but the string exists in the file + try { - case ITEMDESC_ADDPHYDAMAGE: return "Công vật lý"; - case ITEMDESC_ADDMAGICDAMAGE: return "TC phép thuật"; - case ITEMDESC_PHYDEFENCE: return "Thủ vật lý"; - case ITEMDESC_GOLDDEFENCE: return "Kháng Kim"; - case ITEMDESC_WOODDEFENCE: return "Kháng Mộc"; - case ITEMDESC_WATERDEFENCE: return "Kháng Thủy"; - case ITEMDESC_FIREDEFENCE: return "Kháng Hỏa"; - case ITEMDESC_EARTHDEFENCE: return "Kháng Thổ"; - case ITEMDESC_ATKTIME: return "Tốc độ TC(lần/giây)"; - case ITEMDESC_ADDATKDIST: return "Phạm vi tấn công"; - case ITEMDESC_NAME: return "Tên"; - case ITEMDESC_ERRORPROP: return "Thuộc tính không xác định {0}"; - case ITEMDESC_ADDHP: return "HP"; - case ITEMDESC_ADDMP: return "MP"; - case ITEMDESC_DODGE: return "Né tránh"; - case ITEMDESC_DEADLYSTRIKE: return "Chí mạng"; - case ITEMDESC_HPRECOVER: return "Hồi phục HP"; - case ITEMDESC_MPRECOVER: return "Hồi phục MP"; - case ITEMDESC_RUNSPEED: return "Tốc độ chạy"; - case ITEMDESC_RUNSPEEDEXTRA: return "Tốc độ chạy (%)"; - case ITEMDESC_PHYRESIST: return "Kháng vật lý (%)"; - case ITEMDESC_TOTAL_DEFENCE_ADD: return "Tổng kháng ngũ hành (%)"; - case ITEMDESC_GOLDRESIST: return "Kháng Kim (%)"; - case ITEMDESC_WOODRESIST: return "Kháng Mộc (%)"; - case ITEMDESC_WATERRESIST: return "Kháng Thủy (%)"; - case ITEMDESC_FIRERESIST: return "Kháng Hỏa (%)"; - case ITEMDESC_EARTHRESIST: return "Kháng Thổ (%)"; - case ITEMDESC_ALLMAGICRESIST: return "Tổng kháng phép (%)"; - case ITEMDESC_EXP: return "Kinh nghiệm (%)"; - default: - return $"String_{id}"; + string filePath = Path.Combine(Application.streamingAssetsPath, "configs", "item_desc.txt"); + if (File.Exists(filePath)) + { + string content = File.ReadAllText(filePath, Encoding.UTF8); + string[] lines = content.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + + bool foundBegin = false; + int currentIndex = 0; + + foreach (string line in lines) + { + string trimmed = line.Trim(); + if (trimmed.Length == 0) continue; + + if (trimmed.Equals("#_begin", StringComparison.OrdinalIgnoreCase)) + { + foundBegin = true; + continue; + } + + if (!foundBegin) continue; + + // Skip comments + if (trimmed.StartsWith("#") || trimmed.StartsWith("//")) continue; + + // Remove quotes if present + if (trimmed.StartsWith("\"") && trimmed.EndsWith("\"")) + { + trimmed = trimmed.Substring(1, trimmed.Length - 2); + } + + if (currentIndex == enumValue) + { + return trimmed; + } + + currentIndex++; + } + } } + catch (Exception ex) + { + Debug.LogWarning($"[EC_IvtrEquip] Failed to read item_desc.txt fallback for ID {enumValue}: {ex.Message}"); + } + + // Final fallback: Return enum value as string + return enumValue.ToString(); + } + + /// + /// Add resistance property description with proper formatting + /// + private void AddResistDesc(int color, DescriptipionMsg resistId, int value, bool local) + { + string resistFmt = GetItemDescString(resistId); + int displayValue = local ? VisualizeFloatPercent(value) : value; + // Check if format string has placeholder, if not append value with + sign + if (resistFmt.Contains("%d") || resistFmt.Contains("%+d") || resistFmt.Contains("{0}")) + AddDescText(color, true, resistFmt, displayValue); + else + AddDescText(color, true, "{0} +{1}", resistFmt, displayValue); } /// @@ -1428,7 +2225,7 @@ namespace PerfectWorld.Scripts.Managers { if (color >= 0) { - string colorStr = GetColorString(color); + string colorStr = GetColorString((DescriptipionMsg)color); m_strDesc += colorStr; } @@ -1511,6 +2308,14 @@ namespace PerfectWorld.Scripts.Managers i = j; continue; } + else if (spec == 's') + { + object val = argIndex < args.Length ? args[argIndex++] : ""; + string s = val != null ? val.ToString() : ""; + sb.Append(s); + i = j; + continue; + } } // Fallback: treat '%' as literal if format not recognized @@ -1521,20 +2326,21 @@ namespace PerfectWorld.Scripts.Managers /// /// Get color string for color ID + /// Returns color codes in ^RRGGBB format (6 hex digits) for text formatting /// - private string GetColorString(int colorId) + private string GetColorString(DescriptipionMsg colorId) { switch (colorId) { - case ITEMDESC_COL_WHITE: return "^FF"; - case ITEMDESC_COL_GREEN: return "^GF"; - case ITEMDESC_COL_YELLOW: return "^YF"; - case ITEMDESC_COL_DARKGOLD: return "^DF"; - case ITEMDESC_COL_LIGHTBLUE: return "^BF"; - case ITEMDESC_COL_CYANINE: return "^CF"; - case ITEMDESC_COL_RED: return "^RF"; - case ITEMDESC_COL_GRAY: return "^gF"; - default: return "^FF"; + case DescriptipionMsg.ITEMDESC_COL_WHITE: return "^FFFFFF"; // White + case DescriptipionMsg.ITEMDESC_COL_GREEN: return "^00FF00"; // Green + case DescriptipionMsg.ITEMDESC_COL_YELLOW: return "^FFFF00"; // Yellow + case DescriptipionMsg.ITEMDESC_COL_DARKGOLD: return "^FF8C00"; // Dark Gold / Orange + case DescriptipionMsg.ITEMDESC_COL_LIGHTBLUE: return "^5998FF"; // Light Blue + case DescriptipionMsg.ITEMDESC_COL_CYANINE: return "^00FFFF"; // Cyan + case DescriptipionMsg.ITEMDESC_COL_RED: return "^FF0000"; // Red + case DescriptipionMsg.ITEMDESC_COL_GRAY: return "^808080"; // Gray + default: return "^FFFFFF"; // Default to white } } @@ -1569,762 +2375,1647 @@ namespace PerfectWorld.Scripts.Managers return value / 100; } + /// + /// Helper method to convert int to float (bit reinterpretation) + /// + private float IntToFloat(int value) + { + return BitConverter.ToSingle(BitConverter.GetBytes(value), 0); + } + + /// + /// Helper method to convert float to int (bit reinterpretation) + /// + private int FloatToInt(float value) + { + return BitConverter.ToInt32(BitConverter.GetBytes(value), 0); + } + + /// + /// Add range value description for normal integer values (replaces ADD_RANGE_VALUE_DESC_ID_NORMAL macro) + /// + private void AddRangeValueDescIdNormal(DescriptipionMsg idString, int p0, int p1, bool local, int color) + { + if (local) + { + if (p0 != p1) + { + AddDescText(color, false, GetItemDescString(idString), p0); + AddDescText(color, true, "~{0}", p1); + } + else + { + AddDescText(color, true, GetItemDescString(idString), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(idString), p0); + } + } + + /// + /// Add range value description for float values (replaces ADD_RANGE_VALUE_DESC_ID_FLOAT macro) + /// + private void AddRangeValueDescIdFloat(DescriptipionMsg idString, int p0, int p1, bool local, int color) + { + float f0 = IntToFloat(p0); + float f1 = IntToFloat(p1); + if (local) + { + if (p0 != p1) + { + AddDescText(color, false, GetItemDescString(idString), f0); + AddDescText(color, true, "~{0:F2}", f1); + } + else + { + AddDescText(color, true, GetItemDescString(idString), f0); + } + } + else + { + AddDescText(color, true, GetItemDescString(idString), f0); + } + } + + /// + /// Add range value description for percent values (replaces ADD_RANGE_VALUE_DESC_ID_PERCENT macro) + /// + private void AddRangeValueDescIdPercent(DescriptipionMsg idString, int p0, int p1, bool local, int color) + { + if (local) + { + int v0 = VisualizeFloatPercent(p0); + int v1 = VisualizeFloatPercent(p1); + if (v0 != v1) + { + AddDescText(color, false, GetItemDescString(idString), v0); + AddDescText(color, true, "~{0}%%", v1); + } + else + { + AddDescText(color, true, GetItemDescString(idString), v0); + } + } + else + { + AddDescText(color, true, GetItemDescString(idString), p0); + } + } + + /// + /// Add range value description for minus percent values variant 1 (replaces ADD_RANGE_VALUE_DESC_ID_MINUS_PERCENT_1 macro) + /// + private void AddRangeValueDescIdMinusPercent1(DescriptipionMsg idString, int p0, int p1, bool local, int color) + { + if (local) + { + int v0 = -VisualizeFloatPercent(p0); + int v1 = VisualizeFloatPercent(p1); + if (v0 != v1) + { + AddDescText(color, false, GetItemDescString(idString), v0); + AddDescText(color, true, "~{0}%%", v1); + } + else + { + AddDescText(color, true, GetItemDescString(idString), v0); + } + } + else + { + AddDescText(color, true, GetItemDescString(idString), -p0); + } + } + + /// + /// Add range value description for minus percent values variant 2 (replaces ADD_RANGE_VALUE_DESC_ID_MINUS_PERCENT_2 macro) + /// + private void AddRangeValueDescIdMinusPercent2(DescriptipionMsg idString, int p0, int p1, bool local, int color) + { + if (local) + { + int v0 = -VisualizeFloatPercent(p0); + int v1 = VisualizeFloatPercent(p1); + if (v0 != v1) + { + AddDescText(color, false, GetItemDescString(idString), v0); + AddDescText(color, true, "~{0}%%", v1); + } + else + { + AddDescText(color, true, GetItemDescString(idString), v0); + } + } + else + { + AddDescText(color, true, GetItemDescString(idString), -VisualizeFloatPercent(p0)); + } + } + + /// + /// Add range value description for half values (replaces ADD_RANGE_VALUE_DESC_ID_HALF macro) + /// + private void AddRangeValueDescIdHalf(DescriptipionMsg idString, int p0, int p1, bool local, int color) + { + int h0 = p0 / 2; + int h1 = p1 / 2; + if (local) + { + if (h0 != h1) + { + AddDescText(color, false, GetItemDescString(idString), h0); + AddDescText(color, true, "~{0}", h1); + } + else + { + AddDescText(color, true, GetItemDescString(idString), h0); + } + } + else + { + AddDescText(color, true, GetItemDescString(idString), h0); + } + } + + /// + /// Add range value description for string normal values (replaces ADD_RANGE_VALUE_DESC_STR_NORMAL macro) + /// + private void AddRangeValueDescStrNormal(DescriptipionMsg idString, int p0, int p1, bool local, int color) + { + if (local) + { + if (p0 != p1) + { + AddDescText(color, false, GetItemDescString(idString)); + AddDescText(color, true, " %+d~%d", p0, p1); + } + else + { + AddDescText(color, false, GetItemDescString(idString)); + AddDescText(color, true, " %+d", p0); + } + } + else + { + AddDescText(color, false, GetItemDescString(idString)); + AddDescText(color, true, " %+d", p0); + } + } + /// /// Add one add-on property description /// private void AddOneAddOnPropDesc(int idProp, int[] param, int[] aPEEVals, int[] aRefines, bool local) { + // Extract parameters from array + int p0 = param != null && param.Length > 0 ? param[0] : 0; + int p1 = param != null && param.Length > 1 ? param[1] : 0; + int p2 = param != null && param.Length > 2 ? param[2] : 0; + byte propType = GetPropertyType(idProp); + int color = -1; if (!IsSharpenerProperty(propType)) { switch (propType) - { - case 0: - if (!local && aPEEVals != null) aPEEVals[PEEI_PHYDAMAGE] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDPHYDAMAGE)); - AddDescText(-1, true, " %+d", param[0]); - break; - case 1: + { + case 0: // ������ + + if(!local) + { + if (aPEEVals != null) + aPEEVals[PEEI_PHYDAMAGE] += p0; + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDPHYDAMAGE)); + AddDescText(color, true, " %+d", p0); + break; + + case 1: // ���������� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_MAXPHYDAMAGE), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_MAXPHYDAMAGE), p0); + } + } + else + { + if (aPEEVals != null) + aPEEVals[PEEI_MAX_PHYDAMAGE] += p0; + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_MAXPHYDAMAGE), p0); + } + break; + + case 2: // ������(%) + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDMGEXTRA), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDMGEXTRA), p0); + } + break; + + case 3: // ħ������ + + if(!local) + { + if (aPEEVals != null) + aPEEVals[PEEI_MAGICDAMAGE] += p0; + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDMAGICDAMAGE)); + AddDescText(color, true, " %+d", p0); + break; + + case 4: // ħ���������� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_MAXMAGICDAMAGE), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_MAXMAGICDAMAGE), p0); + } + } + else + { + if (aPEEVals != null) + aPEEVals[PEEI_MAX_MAGICDAMAGE] += p0; + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_MAXMAGICDAMAGE), p0); + } + break; + + case 5: // ħ������(%) + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_MAGICDMGEXTRA), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_MAGICDMGEXTRA), p0); + } + break; + + case 6: // +���-�﹥ + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_PHYDEF] += p0; + aPEEVals[PEEI_PHYDAMAGE] -= p1; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDEFENCE)); + AddDescText(color, true, " %+d", p0); + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDPHYDAMAGE)); + AddDescText(color, true, " %+d", -p1); + break; + + case 7: // +�﹥-��� + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_PHYDAMAGE] += p0; + aPEEVals[PEEI_PHYDEF] -= p1; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDPHYDAMAGE)); + AddDescText(color, true, " %+d", p0); + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDEFENCE)); + AddDescText(color, true, " %+d", -p1); + break; + + case 8: // +ħ��-ħ�� + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_MAGICDAMAGE] += p0; + aPEEVals[PEEI_GOLDDEF] -= p1; + aPEEVals[PEEI_WOODDEF] -= p1; + aPEEVals[PEEI_WATERDEF] -= p1; + aPEEVals[PEEI_FIREDEF] -= p1; + aPEEVals[PEEI_EARTHDEF] -= p1; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDMAGICDAMAGE)); + AddDescText(color, true, " %+d", p0); + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICDEF)); + AddDescText(color, true, " %+d", -p1); + break; + + case 9: // �����ٶ� + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATKTIME), -IntToFloat(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATKTIME), -p0 * 0.05f); + } + break; + + case 10: // �������� + { + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDATKDIST), IntToFloat(p0)); + } + else + { + if (aPEEVals != null) + { + float fDist = IntToFloat(aPEEVals[PEEI_ATKDIST]) + IntToFloat(p0); + aPEEVals[PEEI_ATKDIST] = FloatToInt(fDist); + } + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDATKDIST), IntToFloat(p0)); + } + break; + } + case 11: // ����ʱ�� + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_CASTTIME), -VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_CASTTIME), -p0); + } + break; + + case 12: // ������� + + if(!local) + { + if (aPEEVals != null) + aPEEVals[PEEI_PHYDEF] += p0; + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDEFENCE)); + AddDescText(color, true, " %+d", p0); + break; + + case 13: // �������(%) + + if(local) + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDEFEXTRA), VisualizeFloatPercent(p0)); + else + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDEFEXTRA), p0); + + break; + + case 14: // ���з��� + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_GOLDDEF] += p0; + aPEEVals[PEEI_WOODDEF] += p0; + aPEEVals[PEEI_WATERDEF] += p0; + aPEEVals[PEEI_FIREDEF] += p0; + aPEEVals[PEEI_EARTHDEF] += p0; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICDEF)); + AddDescText(color, true, " %+d", p0); + break; + + case 15: // ��� + + if(local) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFENCE)); + + if(p0 != p1) + AddDescText(color, true, " %d~%d", p0, p1); + else + AddDescText(color, true, " %d", p0); + } + else + { + if (aPEEVals != null) + aPEEVals[PEEI_GOLDDEF] += p0; + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFENCE)); + AddDescText(color, true, " %+d", p0); + } + break; + + case 16: // ���(%) + + if(local) + { + if((p0) != (p1)) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFEXTRA), (p0)); + AddDescText(color, true, "~-%.2f%%",p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFEXTRA), (p0)); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFEXTRA), (p0)); + } + break; + + case 17: // ľ�� + + if(local) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFENCE)); + + if(p0 != p1) + AddDescText(color, true, " %d~%d", p0, p1); + else + AddDescText(color, true, " %d", p0); + } + else + { + if (aPEEVals != null) + aPEEVals[PEEI_WOODDEF] += p0; + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFENCE)); + AddDescText(color, true, " %+d", p0); + } + break; + + case 18: // ľ��(%) + + if(local) + { + if((p0) != (p1)) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFEXTRA), (p0)); + AddDescText(color, true, "~-%.2f%%",p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFEXTRA), (p0)); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFEXTRA), (p0)); + } + break; + + case 19: // ˮ�� + + if(local) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFENCE)); + + if(p0 != p1) + AddDescText(color, true, " %d~%d", p0, p1); + else + AddDescText(color, true, " %d", p0); + } + else + { + if (aPEEVals != null) + aPEEVals[PEEI_WATERDEF] += p0; + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFENCE)); + AddDescText(color, true, " %+d", p0); + } + break; + + case 20: // ˮ��(%) + + if(local) + { + if((p0) != (p1)) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFEXTRA), (p0)); + AddDescText(color, true, "~-%.2f%%",p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFEXTRA), (p0)); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFEXTRA), (p0)); + } + break; + + case 21: // ��� + + if(local) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFENCE)); + + if(p0 != p1) + AddDescText(color, true, " %d~%d", p0, p1); + else + AddDescText(color, true, " %d", p0); + } + else + { + if (aPEEVals != null) + aPEEVals[PEEI_FIREDEF] += p0; + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFENCE)); + AddDescText(color, true, " %+d", p0); + } + break; + + case 22: // ���(%) + + if(local) + { + if((p0) != (p1)) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFEXTRA), (p0)); + AddDescText(color, true, "~-%.2f%%",p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFEXTRA), (p0)); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFEXTRA), (p0)); + } + break; + + case 23: // ���� + + if(local) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFENCE)); + + if(p0 != p1) + AddDescText(color, true, " %d~%d", p0, p1); + else + AddDescText(color, true, " %d", p0); + } + else + { + if (aPEEVals != null) + aPEEVals[PEEI_EARTHDEF] += p0; + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFENCE)); + AddDescText(color, true, " %+d", p0); + } + + break; + + case 24: // ����(%) + + if(local) + { + if((p0) != (p1)) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFEXTRA), (p0)); + AddDescText(color, true, "~-%.2f%%",p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFEXTRA), (p0)); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFEXTRA), (p0)); + } + break; + + case 25: // +���(%)-���(%) + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFEXTRA), VisualizeFloatPercent(p0)); + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFEXTRA), -VisualizeFloatPercent(p1)); + break; + + case 26: // +ľ��(%)-���(%) + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFEXTRA), VisualizeFloatPercent(p0)); + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFEXTRA), -VisualizeFloatPercent(p1)); + break; + + case 27: // +ˮ��(%)-����(%) + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFEXTRA), VisualizeFloatPercent(p0)); + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFEXTRA), -VisualizeFloatPercent(p1)); + break; + + case 28: // +���(%)-ˮ��(%) + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFEXTRA), VisualizeFloatPercent(p0)); + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFEXTRA), -VisualizeFloatPercent(p1)); + break; + + case 29: // +����(%)-ľ��(%) + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFEXTRA), VisualizeFloatPercent(p0)); + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFEXTRA), -VisualizeFloatPercent(p1)); + break; + + case 30: // +���-��� + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_GOLDDEF] += p0; + aPEEVals[PEEI_FIREDEF] -= p1; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFENCE)); + AddDescText(color, true, " %+d", p0); + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFENCE)); + AddDescText(color, true, " %+d", -p1); + break; + + case 31: // +ľ��-��� + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_WOODDEF] += p0; + aPEEVals[PEEI_GOLDDEF] -= p1; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFENCE)); + AddDescText(color, true, " %+d", p0); + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFENCE)); + AddDescText(color, true, " %+d", -p1); + break; + + case 32: // +ˮ��-���� + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_WATERDEF] += p0; + aPEEVals[PEEI_EARTHDEF] -= p1; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFENCE)); + AddDescText(color, true, " %+d", p0); + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFENCE)); + AddDescText(color, true, " %+d", -p1); + break; + + case 33: // +���-ˮ�� + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_FIREDEF] += p0; + aPEEVals[PEEI_WATERDEF] -= p1; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFENCE)); + AddDescText(color, true, " %+d", p0); + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFENCE)); + AddDescText(color, true, " %+d", -p1); + break; + + case 34: // +����-ľ�� + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_EARTHDEF] += p0; + aPEEVals[PEEI_WOODDEF] -= p1; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFENCE)); + AddDescText(color, true, " %+d", p0); + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFENCE)); + AddDescText(color, true, " %+d", -p1); + break; + + case 35: // HP + + if(!local) + { + if (aPEEVals != null) + aPEEVals[PEEI_HP] += p0; + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDHP)); + AddDescText(color, true, " %+d", p0); + break; + + case 36: // MP + + if(!local) + { + if (aPEEVals != null) + aPEEVals[PEEI_MP] += p0; + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDMP)); + AddDescText(color, true, " %+d", p0); + break; + + case 37: // HP(%) + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_HPEXTRA), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_HPEXTRA), p0); + } + break; + + case 38: // MP(%) + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_MPEXTRA), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_MPEXTRA), p0); + } + break; + + case 39: // HP�ָ��ٶ� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_HPRECOVER), p0 / 2); + break; + + case 40: // MP�ָ��ٶ� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_MPRECOVER), p0 / 2); + break; + + case 41: // ���� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_STRENGTH), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_STRENGTH), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_STRENGTH), p0); + } + break; + + case 42: // ���� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_AGILITY), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_AGILITY), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_AGILITY), p0); + } + break; + + case 43: // ���� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ENERGY), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ENERGY), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ENERGY), p0); + } + break; + + case 44: // ���� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_VITALITY), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_VITALITY), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_VITALITY), p0); + } + break; + + case 45: // ����һ���� + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_DEADLYSTRIKE), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_DEADLYSTRIKE), p0); + } + break; + + case 46: // ���� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ATKRATING), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATKRATING), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATKRATING), p0); + } + break; + + case 47: // ����(%) + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATKRATINGEXTRA), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATKRATINGEXTRA), p0); + } + break; + + case 48: // �ƶ��ٶ� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_RUNSPEED), IntToFloat(p0)); + break; + + case 49: // �ƶ��ٶ�(%) + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_RUNSPEEDEXTRA), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_RUNSPEEDEXTRA), p0); + } + break; + + case 50: // ���� + + if(!local) + { + if (aPEEVals != null) + aPEEVals[PEEI_DODGE] += p0; + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_DODGE)); + AddDescText(color, true, " %+d", p0); + break; + + case 51: // ����(%) + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_DODGEEXTRA), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_DODGEEXTRA), p0); + } + break; + + case 52: // �;ö� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ENDURANCE)); + AddDescText(color, true, " %+d", p0); + break; + + case 53: // �;ö�(%) + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ENDURANCEEXTRA), VisualizeFloatPercent(p0)); + break; + + case 54: // �������� + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYRESIST), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYRESIST), p0); + } + break; + + case 55: // ���Ӽ��� + { + // Get skill description - TODO: Implement skill description retrieval + string skillDesc = $"Skill {p0}"; // Placeholder - needs proper implementation + AddDescText(color, true, "{0}", skillDesc); + break; + } + case 56: // װ������ + + if(local) + { + if(VisualizeFloatPercent(p0) != VisualizeFloatPercent(p1)) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_REQEXTRA), -VisualizeFloatPercent(p0)); + AddDescText(color, true, "~%d", VisualizeFloatPercent(p1)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_REQEXTRA), -VisualizeFloatPercent(p0)); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_REQEXTRA), -VisualizeFloatPercent(p0)); + } + break; + + case 57: // δ֪���� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_RANDOMPROP)); + break; + + case 58: // ����ֵ�ӳ� + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EXP), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EXP), p0); + } + break; + + case 59: // �����ȼ� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATK_DEGREE), p0); + break; + + case 60: // �����ȼ� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_DEF_DEGREE), p0); + break; + + case 61: // ���з�����%�� + + if(local) + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_TOTAL_DEFENCE_ADD), VisualizeFloatPercent(p0)); + else + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_TOTAL_DEFENCE_ADD), (p0)); + + break; + + case 62: // ����֮�� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PROFVIEW)); + break; + + case 63: // ���� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_SOULPOWER), p0); + break; + + case 64: // ��ϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_GOLDRESIST, p0, local); + break; + + case 65: // ľϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_WOODRESIST, p0, local); + break; + + case 66: // ˮϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_WATERRESIST, p0, local); + break; + + case 67: // ��ϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_FIRERESIST, p0, local); + break; + + case 68: // ��ϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_EARTHRESIST, p0, local); + break; + + case 69: // ���м���(%) + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICRESIST), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICRESIST), p0); + } + break; + + case 70: // �����ȼ���Χ������ֵ������ã� + + // ADD_RANGE_VALUE_DESC_ID_NORMAL equivalent if (local) { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_MAXPHYDAMAGE), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_MAXPHYDAMAGE), param[0]); } + if (p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ATK_DEGREE), p0); + AddDescText(color, true, "~{0}", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATK_DEGREE), p0); + } } else { - if (aPEEVals != null) aPEEVals[PEEI_MAX_PHYDAMAGE] += param[0]; - AddDescText(-1, true, GetItemDescString(ITEMDESC_MAXPHYDAMAGE), param[0]); + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATK_DEGREE), p0); } - break; - case 2: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ADDPHYDAMAGE) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 3: - if (!local && aPEEVals != null) aPEEVals[PEEI_MAGICDAMAGE] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDMAGICDAMAGE)); - AddDescText(-1, true, " %+d", param[0]); - break; - case 4: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_MAXMAGICDAMAGE), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_MAXMAGICDAMAGE), param[0]); } - } - else - { - if (aPEEVals != null) aPEEVals[PEEI_MAX_MAGICDAMAGE] += param[0]; - AddDescText(-1, true, GetItemDescString(ITEMDESC_MAXMAGICDAMAGE), param[0]); - } - break; - case 5: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ADDMAGICDAMAGE) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; + break; + + case 71: // �����ȼ���Χ������ֵ������ã� + + AddRangeValueDescIdNormal(DescriptipionMsg.ITEMDESC_DEF_DEGREE, p0, p1, local, color); + break; + + case 72: // ����һ����(%)��Χ������ֵ������ã� + + AddRangeValueDescIdPercent(DescriptipionMsg.ITEMDESC_DEADLYSTRIKE, p0, p1, local, color); + break; + + case 73: // HP��Χ������ֵ������ã� + + AddRangeValueDescStrNormal(DescriptipionMsg.ITEMDESC_ADDHP, p0, p1, local, color); + break; + + case 74: // MP��Χ������ֵ������ã� + + AddRangeValueDescStrNormal(DescriptipionMsg.ITEMDESC_ADDMP, p0, p1, local, color); + break; + + case 75: // ����(%)��Χ������ֵ������ã� + + AddRangeValueDescIdPercent(DescriptipionMsg.ITEMDESC_ATKRATINGEXTRA, p0, p1, local, color); + break; + + case 76: // ���������Χ������ֵ������ã� + + AddRangeValueDescStrNormal(DescriptipionMsg.ITEMDESC_PHYDEFENCE, p0, p1, local, color); + break; + + case 77: // ���з�����Χ������ֵ������ã� + + AddRangeValueDescStrNormal(DescriptipionMsg.ITEMDESC_ALLMAGICDEF, p0, p1, local, color); + break; + + case 78: // �������(%)��Χ������ֵ������ã� + + AddRangeValueDescIdPercent(DescriptipionMsg.ITEMDESC_PHYRESIST, p0, p1, local, color); + break; + + case 79: // ���м���(%)��Χ������ֵ������ã� + + AddRangeValueDescIdPercent(DescriptipionMsg.ITEMDESC_ALLMAGICRESIST, p0, p1, local, color); + break; + + case 80: // ����ʱ��(%)��Χ������ֵ������ã� + + AddRangeValueDescIdMinusPercent1(DescriptipionMsg.ITEMDESC_CASTTIME, p0, p1, local, color); + break; + + case 81: // �������뷶Χ������ֵ������ã� + + AddRangeValueDescIdFloat(DescriptipionMsg.ITEMDESC_ADDATKDIST, p0, p1, local, color); + break; + + case 82: // MP�ָ��ٶȷ�Χ������ֵ������ã� + + AddRangeValueDescIdHalf(DescriptipionMsg.ITEMDESC_MPRECOVER, p0, p1, local, color); + break; + + case 83: // �������(%)��Χ������ֵ������ã� + + AddRangeValueDescIdPercent(DescriptipionMsg.ITEMDESC_PHYDEFEXTRA, p0, p1, local, color); + break; + + case 84: // ���з���(%)��Χ������ֵ������ã� + + AddRangeValueDescIdPercent(DescriptipionMsg.ITEMDESC_TOTAL_DEFENCE_ADD, p0, p1, local, color); + break; + + case 85: // HP�ָ��ٶȷ�Χ������ֵ������ã� + + AddRangeValueDescIdHalf(DescriptipionMsg.ITEMDESC_HPRECOVER, p0, p1, local, color); + break; + + case 86: // ������Χ������ֵ������ã� + + AddRangeValueDescStrNormal(DescriptipionMsg.ITEMDESC_DODGE, p0, p1, local, color); + break; + + case 87: // ���������޷�Χ������ֵ������ã� + + AddRangeValueDescIdNormal(DescriptipionMsg.ITEMDESC_MAXPHYDAMAGE, p0, p1, local, color); + break; + + case 88: // ħ���������޷�Χ������ֵ������ã� + + AddRangeValueDescIdNormal(DescriptipionMsg.ITEMDESC_MAXMAGICDAMAGE, p0, p1, local, color); + break; + + case 89: // װ������Χ������ֵ������ã� + + AddRangeValueDescIdMinusPercent2(DescriptipionMsg.ITEMDESC_REQEXTRA, p0, p1, local, color); + break; + + case 90: // ��ħ�ȼ� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PENETRATION), p0); + break; + + case 91: // ��ħ�ȼ� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_RESILIENCE), p0); + break; + + case 92: // +���+ħ�� + + if(!local) + { + if (aPEEVals != null) + { + aPEEVals[PEEI_PHYDEF] += p0; + aPEEVals[PEEI_GOLDDEF] += p1; + aPEEVals[PEEI_WOODDEF] += p1; + aPEEVals[PEEI_WATERDEF] += p1; + aPEEVals[PEEI_FIREDEF] += p1; + aPEEVals[PEEI_EARTHDEF] += p1; + } + } + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDEFENCE)); + AddDescText(color, true, " %+d", p0); + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICDEF)); + AddDescText(color, true, " %+d", p1); + break; + + case 93: // ��ɫHP + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDHP)); + AddDescText(color, true, " %+d", p0); + break; + + case 94: // ��ɫHP��Χ + AddRangeValueDescStrNormal(DescriptipionMsg.ITEMDESC_ADDHP, p0, p1, local, color); + break; + + case 95: // ���� + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_STRENGTH), p0); + break; + + case 96: // ���� + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_AGILITY), p0); + break; + + case 97: // ���� + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ENERGY), p0); + break; + + case 98: // ���� + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_VITALITY), p0); + break; + + case 99: // ��ɫMP + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDMP)); + AddDescText(color, true, " %+d", p0); + break; + + case 160: // �����̶�ֵ + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_VIGOUR)); + AddDescText(color, true, " %+d", p0); + break; + + case 200: // ���������� + + if (aRefines != null) + aRefines[REFINE_PHYDAMAGE] += p0; + + break; + + case 201: // ����ħ������ + + if (aRefines != null) + aRefines[REFINE_MAGICDAMAGE] += p0; + + break; + + case 202: // ����������� + + if (aRefines != null) + aRefines[REFINE_PHYDEF] += p0; + + break; + + case 203: // ������� + + if (aRefines != null) + aRefines[REFINE_GOLDDEF] += p0; + + break; + + case 204: // ����ľ�� + + if (aRefines != null) + aRefines[REFINE_WOODDEF] += p0; + + break; + + case 205: // ����ˮ�� + + if (aRefines != null) + aRefines[REFINE_WATERDEF] += p0; + + break; + + case 206: // ������� + + if (aRefines != null) + aRefines[REFINE_FIREDEF] += p0; + + break; + + case 207: // �������� + + if (aRefines != null) + aRefines[REFINE_EARTHDEF] += p0; + + break; + + case 208: // ����HP + + if (aRefines != null) + aRefines[REFINE_HP] += p0; + + break; + + case 209: // �������� + + if (aRefines != null) + aRefines[REFINE_DODGE] += p0; + + break; + + case 210: // �������з��� + + if (aRefines != null) + { + aRefines[REFINE_GOLDDEF] += p0; + aRefines[REFINE_WOODDEF] += p0; + aRefines[REFINE_WATERDEF] += p0; + aRefines[REFINE_FIREDEF] += p0; + aRefines[REFINE_EARTHDEF] += p0; + } + + break; + + case 211: // ���������� & ħ������ + + if (aRefines != null) + { + aRefines[REFINE_PHYDAMAGE] += p0; + aRefines[REFINE_MAGICDAMAGE] += p0; + } + + break; + + case 212: // ����������� & ħ������ + + if (aRefines != null) + { + aRefines[REFINE_PHYDEF] += p0; + aRefines[REFINE_GOLDDEF] += p0; + aRefines[REFINE_WOODDEF] += p0; + aRefines[REFINE_WATERDEF] += p0; + aRefines[REFINE_FIREDEF] += p0; + aRefines[REFINE_EARTHDEF] += p0; + } + + break; + + // �Կ�������� + case 120: // �Կ̽�� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_GOLDDEFENCE)); + AddDescText(color, true, " %+d", p0); + break; + + case 121: // �Կ�ľ�� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WOODDEFENCE)); + AddDescText(color, true, " %+d", p0); + break; + + case 122: // �Կ�ˮ�� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_WATERDEFENCE)); + AddDescText(color, true, " %+d", p0); + break; + + case 123: // �Կ̻�� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_FIREDEFENCE)); + AddDescText(color, true, " %+d", p0); + break; + + case 124: // �Կ����� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_EARTHDEFENCE)); + AddDescText(color, true, " %+d", p0); + break; + + case 125: // �Կ����� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATKRATING), p0); + break; + + case 126: // �Կ̶��� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_DODGE)); + AddDescText(color, true, " %+d", p0); + break; + + case 127: // �Կ�MP + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDMP)); + AddDescText(color, true, " %+d", p0); + break; + + case 128: // �Կ����� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_VITALITY), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_VITALITY), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_VITALITY), p0); + } + break; + + case 129: // �Կ����� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_STRENGTH), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_STRENGTH), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_STRENGTH), p0); + } + break; + + case 130: // �Կ����� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_AGILITY), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_AGILITY), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_AGILITY), p0); + } + break; + + case 131: // �Կ����� + + if(local) + { + if(p0 != p1) + { + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ENERGY), p0); + AddDescText(color, true, "~%d", p1); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ENERGY), p0); + } + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ENERGY), p0); + } + break; + + case 132: // �Կ�HP + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDHP)); + AddDescText(color, true, " %+d", p0); + break; + + case 133: // �Կ�������� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDEFENCE)); + AddDescText(color, true, " %+d", p0); + break; + + case 134: // �Կ����з��� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICDEF)); + AddDescText(color, true, " %+d", p0); + break; + + case 135: // �Կ������� + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDPHYDAMAGE)); + AddDescText(color, true, " %+d", p0); + break; + + case 136: // �Կ�ħ������ + + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDMAGICDAMAGE)); + AddDescText(color, true, " %+d", p0); + break; + + case 137: // �Կ̽�ϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_GOLDRESIST, p0, local); + break; + + case 138: // �Կ�ľϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_WOODRESIST, p0, local); + break; + + case 139: // �Կ�ˮϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_WATERRESIST, p0, local); + break; + + case 140: // �Կ̻�ϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_FIRERESIST, p0, local); + break; + + case 141: // �Կ���ϵ����(%) + + AddResistDesc(color, DescriptipionMsg.ITEMDESC_EARTHRESIST, p0, local); + break; + + case 142: // �Կ����м���(%) + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICRESIST), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICRESIST), p0); + } + break; + + case 143: // �Կ�����һ���� + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_DEADLYSTRIKE), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_DEADLYSTRIKE), p0); + } + break; + + case 144: // �Կ̹����ȼ� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ATK_DEGREE), p0); + break; + + case 145: // �Կ̷����ȼ� + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_DEF_DEGREE), p0); + break; + + case 146: // �Կ��������� + + if(local) + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYRESIST), VisualizeFloatPercent(p0)); + } + else + { + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYRESIST), p0); + } + break; + + default: + + AddDescText(color, true, GetItemDescString(DescriptipionMsg.ITEMDESC_ERRORPROP), idProp); + break; + } + } - case 6: - if (!local && aPEEVals != null) { aPEEVals[PEEI_PHYDEF] += param[0]; aPEEVals[PEEI_PHYDAMAGE] -= param[1]; } - AddDescText(-1, false, GetItemDescString(ITEMDESC_PHYDEFENCE)); - AddDescText(-1, true, " %+d", param[0]); - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDPHYDAMAGE)); - AddDescText(-1, true, " %+d", -param[1]); - break; - case 7: - if (!local && aPEEVals != null) { aPEEVals[PEEI_PHYDAMAGE] += param[0]; aPEEVals[PEEI_PHYDEF] -= param[1]; } - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDPHYDAMAGE)); - AddDescText(-1, true, " %+d", param[0]); - AddDescText(-1, false, GetItemDescString(ITEMDESC_PHYDEFENCE)); - AddDescText(-1, true, " %+d", -param[1]); - break; - case 8: - if (!local && aPEEVals != null) - { - aPEEVals[PEEI_MAGICDAMAGE] += param[0]; - aPEEVals[PEEI_GOLDDEF] -= param[1]; aPEEVals[PEEI_WOODDEF] -= param[1]; aPEEVals[PEEI_WATERDEF] -= param[1]; aPEEVals[PEEI_FIREDEF] -= param[1]; aPEEVals[PEEI_EARTHDEF] -= param[1]; - } - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDMAGICDAMAGE)); - AddDescText(-1, true, " %+d", param[0]); - AddDescText(-1, false, GetItemDescString(ITEMDESC_ALLMAGICDEF)); - AddDescText(-1, true, " %+d", -param[1]); - break; - - case 9: - if (local) AddDescText(-1, true, GetItemDescString(ITEMDESC_ATKTIME), -BitConverter.ToSingle(BitConverter.GetBytes(param[0]), 0)); - else AddDescText(-1, true, GetItemDescString(ITEMDESC_ATKTIME), -param[0] * 0.05f); - break; - case 10: - float dist = BitConverter.ToSingle(BitConverter.GetBytes(param[0]), 0); - if (aPEEVals != null) - { - float cur = BitConverter.ToSingle(BitConverter.GetBytes(aPEEVals[PEEI_ATKDIST]), 0); - cur += dist; - aPEEVals[PEEI_ATKDIST] = BitConverter.ToInt32(BitConverter.GetBytes(cur), 0); - } - AddDescText(-1, true, GetItemDescString(ITEMDESC_ADDATKDIST), dist); - break; - case 11: - AddDescText(-1, true, GetItemDescString(ITEMDESC_CASTTIME), -(local ? VisualizeFloatPercent(param[0]) : param[0])); - break; - - case 12: - if (!local && aPEEVals != null) aPEEVals[PEEI_PHYDEF] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_PHYDEFENCE)); - AddDescText(-1, true, " %+d", param[0]); - break; - case 13: - AddDescText(-1, true, GetItemDescString(ITEMDESC_PHYDEFENCE) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 14: - if (!local && aPEEVals != null) - { - aPEEVals[PEEI_GOLDDEF] += param[0]; aPEEVals[PEEI_WOODDEF] += param[0]; aPEEVals[PEEI_WATERDEF] += param[0]; aPEEVals[PEEI_FIREDEF] += param[0]; aPEEVals[PEEI_EARTHDEF] += param[0]; - } - AddDescText(-1, false, GetItemDescString(ITEMDESC_ALLMAGICDEF)); - AddDescText(-1, true, " %+d", param[0]); - break; - case 15: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_GOLDDEFENCE)); - if (param[0] != param[1]) AddDescText(-1, true, " %d~%d", param[0], param[1]); else AddDescText(-1, true, " %d", param[0]); - } - else - { - if (aPEEVals != null) aPEEVals[PEEI_GOLDDEF] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_GOLDDEFENCE)); - AddDescText(-1, true, " %+d", param[0]); - } - break; - case 16: - AddDescText(-1, true, GetItemDescString(ITEMDESC_GOLDDEFENCE) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 17: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_WOODDEFENCE)); - if (param[0] != param[1]) AddDescText(-1, true, " %d~%d", param[0], param[1]); else AddDescText(-1, true, " %d", param[0]); - } - else - { - if (aPEEVals != null) aPEEVals[PEEI_WOODDEF] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_WOODDEFENCE)); - AddDescText(-1, true, " %+d", param[0]); - } - break; - case 18: - AddDescText(-1, true, GetItemDescString(ITEMDESC_WOODDEFENCE) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 19: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_WATERDEFENCE)); - if (param[0] != param[1]) AddDescText(-1, true, " %d~%d", param[0], param[1]); else AddDescText(-1, true, " %d", param[0]); - } - else - { - if (aPEEVals != null) aPEEVals[PEEI_WATERDEF] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_WATERDEFENCE)); - AddDescText(-1, true, " %+d", param[0]); - } - break; - case 20: - AddDescText(-1, true, GetItemDescString(ITEMDESC_WATERDEFENCE) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 21: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_FIREDEFENCE)); - if (param[0] != param[1]) AddDescText(-1, true, " %d~%d", param[0], param[1]); else AddDescText(-1, true, " %d", param[0]); - } - else - { - if (aPEEVals != null) aPEEVals[PEEI_FIREDEF] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_FIREDEFENCE)); - AddDescText(-1, true, " %+d", param[0]); - } - break; - case 22: - AddDescText(-1, true, GetItemDescString(ITEMDESC_FIREDEFENCE) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 23: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_EARTHDEFENCE)); - if (param[0] != param[1]) AddDescText(-1, true, " %d~%d", param[0], param[1]); else AddDescText(-1, true, " %d", param[0]); - } - else - { - if (aPEEVals != null) aPEEVals[PEEI_EARTHDEF] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_EARTHDEFENCE)); - AddDescText(-1, true, " %+d", param[0]); - } - break; - case 24: - AddDescText(-1, true, GetItemDescString(ITEMDESC_EARTHDEFENCE) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - - case 25: - AddDescText(-1, true, GetItemDescString(ITEMDESC_GOLDDEFENCE) + " %", VisualizeFloatPercent(param[0])); - AddDescText(-1, true, GetItemDescString(ITEMDESC_FIREDEFENCE) + " %", -VisualizeFloatPercent(param[1])); - break; - case 26: - AddDescText(-1, true, GetItemDescString(ITEMDESC_WOODDEFENCE) + " %", VisualizeFloatPercent(param[0])); - AddDescText(-1, true, GetItemDescString(ITEMDESC_GOLDDEFENCE) + " %", -VisualizeFloatPercent(param[1])); - break; - case 27: - AddDescText(-1, true, GetItemDescString(ITEMDESC_WATERDEFENCE) + " %", VisualizeFloatPercent(param[0])); - AddDescText(-1, true, GetItemDescString(ITEMDESC_EARTHDEFENCE) + " %", -VisualizeFloatPercent(param[1])); - break; - case 28: - AddDescText(-1, true, GetItemDescString(ITEMDESC_FIREDEFENCE) + " %", VisualizeFloatPercent(param[0])); - AddDescText(-1, true, GetItemDescString(ITEMDESC_WATERDEFENCE) + " %", -VisualizeFloatPercent(param[1])); - break; - case 29: - AddDescText(-1, true, GetItemDescString(ITEMDESC_EARTHDEFENCE) + " %", VisualizeFloatPercent(param[0])); - AddDescText(-1, true, GetItemDescString(ITEMDESC_WOODDEFENCE) + " %", -VisualizeFloatPercent(param[1])); - break; - - case 30: - if (!local && aPEEVals != null) { aPEEVals[PEEI_GOLDDEF] += param[0]; aPEEVals[PEEI_FIREDEF] -= param[1]; } - AddDescText(-1, false, GetItemDescString(ITEMDESC_GOLDDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - AddDescText(-1, false, GetItemDescString(ITEMDESC_FIREDEFENCE)); AddDescText(-1, true, " %+d", -param[1]); - break; - case 31: - if (!local && aPEEVals != null) { aPEEVals[PEEI_WOODDEF] += param[0]; aPEEVals[PEEI_GOLDDEF] -= param[1]; } - AddDescText(-1, false, GetItemDescString(ITEMDESC_WOODDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - AddDescText(-1, false, GetItemDescString(ITEMDESC_GOLDDEFENCE)); AddDescText(-1, true, " %+d", -param[1]); - break; - case 32: - if (!local && aPEEVals != null) { aPEEVals[PEEI_WATERDEF] += param[0]; aPEEVals[PEEI_EARTHDEF] -= param[1]; } - AddDescText(-1, false, GetItemDescString(ITEMDESC_WATERDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - AddDescText(-1, false, GetItemDescString(ITEMDESC_EARTHDEFENCE)); AddDescText(-1, true, " %+d", -param[1]); - break; - case 33: - if (!local && aPEEVals != null) { aPEEVals[PEEI_FIREDEF] += param[0]; aPEEVals[PEEI_WATERDEF] -= param[1]; } - AddDescText(-1, false, GetItemDescString(ITEMDESC_FIREDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - AddDescText(-1, false, GetItemDescString(ITEMDESC_WATERDEFENCE)); AddDescText(-1, true, " %+d", -param[1]); - break; - case 34: - if (!local && aPEEVals != null) { aPEEVals[PEEI_EARTHDEF] += param[0]; aPEEVals[PEEI_WOODDEF] -= param[1]; } - AddDescText(-1, false, GetItemDescString(ITEMDESC_EARTHDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - AddDescText(-1, false, GetItemDescString(ITEMDESC_WOODDEFENCE)); AddDescText(-1, true, " %+d", -param[1]); - break; - - case 35: - if (!local && aPEEVals != null) aPEEVals[PEEI_HP] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDHP)); AddDescText(-1, true, " %+d", param[0]); - break; - case 36: - if (!local && aPEEVals != null) aPEEVals[PEEI_MP] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDMP)); AddDescText(-1, true, " %+d", param[0]); - break; - case 37: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ADDHP) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 38: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ADDMP) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 39: - AddDescText(-1, true, GetItemDescString(ITEMDESC_HPRECOVER), param[0] / 2); - break; - case 40: - AddDescText(-1, true, GetItemDescString(ITEMDESC_MPRECOVER), param[0] / 2); - break; - - case 41: - if (local) { if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_STRENGTH), param[0]); AddDescText(-1, true, "~%d", param[1]); } else { AddDescText(-1, true, GetItemDescString(ITEMDESC_STRENGTH), param[0]); } } - else AddDescText(-1, true, GetItemDescString(ITEMDESC_STRENGTH), param[0]); - break; - case 42: - if (local) { if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_AGILITY), param[0]); AddDescText(-1, true, "~%d", param[1]); } else { AddDescText(-1, true, GetItemDescString(ITEMDESC_AGILITY), param[0]); } } - else AddDescText(-1, true, GetItemDescString(ITEMDESC_AGILITY), param[0]); - break; - case 43: - if (local) { if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_ENERGY), param[0]); AddDescText(-1, true, "~%d", param[1]); } else { AddDescText(-1, true, GetItemDescString(ITEMDESC_ENERGY), param[0]); } } - else AddDescText(-1, true, GetItemDescString(ITEMDESC_ENERGY), param[0]); - break; - case 44: - if (local) { if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_VITALITY), param[0]); AddDescText(-1, true, "~%d", param[1]); } else { AddDescText(-1, true, GetItemDescString(ITEMDESC_VITALITY), param[0]); } } - else AddDescText(-1, true, GetItemDescString(ITEMDESC_VITALITY), param[0]); - break; - case 45: - AddDescText(-1, true, GetItemDescString(ITEMDESC_DEADLYSTRIKE), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 46: - if (local) { if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_ATKRATING), param[0]); AddDescText(-1, true, "~%d", param[1]); } else { AddDescText(-1, true, GetItemDescString(ITEMDESC_ATKRATING), param[0]); } } - else AddDescText(-1, true, GetItemDescString(ITEMDESC_ATKRATING), param[0]); - break; - case 47: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ATKRATING) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 48: - AddDescText(-1, true, GetItemDescString(ITEMDESC_RUNSPEED), BitConverter.ToSingle(BitConverter.GetBytes(param[0]), 0)); - break; - case 49: - AddDescText(-1, true, GetItemDescString(ITEMDESC_RUNSPEEDEXTRA), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - - case 50: - if (!local && aPEEVals != null) aPEEVals[PEEI_DODGE] += param[0]; - AddDescText(-1, false, GetItemDescString(ITEMDESC_DODGE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 51: - AddDescText(-1, true, GetItemDescString(ITEMDESC_DODGE) + " %", local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 52: - AddDescText(-1, false, GetItemDescString(ITEMDESC_ENDURANCE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 53: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ENDURANCE) + " %", VisualizeFloatPercent(param[0])); - break; - case 54: - AddDescText(-1, true, GetItemDescString(ITEMDESC_PHYRESIST), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 55: - AddDescText(-1, true, GetItemDescString(ITEMDESC_RANDOMPROP)); - break; - case 56: - AddDescText(-1, true, GetItemDescString(ITEMDESC_REQEXTRA), -VisualizeFloatPercent(param[0])); - break; - case 57: - AddDescText(-1, true, GetItemDescString(ITEMDESC_RANDOMPROP)); - break; - case 58: - AddDescText(-1, true, GetItemDescString(ITEMDESC_EXP), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 59: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ATK_DEGREE), param[0]); - break; - case 60: - AddDescText(-1, true, GetItemDescString(ITEMDESC_DEF_DEGREE), param[0]); - break; - case 61: - AddDescText(-1, true, GetItemDescString(ITEMDESC_TOTAL_DEFENCE_ADD), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 62: - AddDescText(-1, true, GetItemDescString(ITEMDESC_PROFVIEW)); - break; - case 63: - AddDescText(-1, true, GetItemDescString(ITEMDESC_SOULPOWER), param[0]); - break; - case 64: - AddDescText(-1, true, GetItemDescString(ITEMDESC_GOLDRESIST), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 65: - AddDescText(-1, true, GetItemDescString(ITEMDESC_WOODRESIST), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 66: - AddDescText(-1, true, GetItemDescString(ITEMDESC_WATERRESIST), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 67: - AddDescText(-1, true, GetItemDescString(ITEMDESC_FIRERESIST), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 68: - AddDescText(-1, true, GetItemDescString(ITEMDESC_EARTHRESIST), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - case 69: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ALLMAGICRESIST), local ? VisualizeFloatPercent(param[0]) : param[0]); - break; - - case 70: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_ATK_DEGREE), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_ATK_DEGREE), param[0]); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_ATK_DEGREE), param[0]); - } - break; - case 71: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_DEF_DEGREE), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_DEF_DEGREE), param[0]); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_DEF_DEGREE), param[0]); - } - break; - case 72: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_DEADLYSTRIKE), VisualizeFloatPercent(param[0])); AddDescText(-1, true, "~%d%%", VisualizeFloatPercent(param[1])); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_DEADLYSTRIKE), VisualizeFloatPercent(param[0])); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_DEADLYSTRIKE), param[0]); - } - break; - case 73: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDHP)); - if (param[0] != param[1]) AddDescText(-1, true, " %+d~%d", param[0], param[1]); else AddDescText(-1, true, " %+d", param[0]); - } - else - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDHP)); AddDescText(-1, true, " %+d", param[0]); - } - break; - case 74: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDMP)); - if (param[0] != param[1]) AddDescText(-1, true, " %+d~%d", param[0], param[1]); else AddDescText(-1, true, " %+d", param[0]); - } - else - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDMP)); AddDescText(-1, true, " %+d", param[0]); - } - break; - case 75: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_ATKRATING) + " %", VisualizeFloatPercent(param[0])); AddDescText(-1, true, "~%d", VisualizeFloatPercent(param[1])); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_ATKRATING) + " %", VisualizeFloatPercent(param[0])); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_ATKRATING) + " %", param[0]); - } - break; - case 76: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_PHYDEFENCE)); - if (param[0] != param[1]) AddDescText(-1, true, " %+d~%d", param[0], param[1]); else AddDescText(-1, true, " %+d", param[0]); - } - else - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_PHYDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - } - break; - case 77: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_ALLMAGICDEF)); - if (param[0] != param[1]) AddDescText(-1, true, " %+d~%d", param[0], param[1]); else AddDescText(-1, true, " %+d", param[0]); - } - else - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_ALLMAGICDEF)); AddDescText(-1, true, " %+d", param[0]); - } - break; - case 78: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_PHYRESIST), VisualizeFloatPercent(param[0])); AddDescText(-1, true, "~%d", VisualizeFloatPercent(param[1])); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_PHYRESIST), VisualizeFloatPercent(param[0])); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_PHYRESIST), param[0]); - } - break; - case 79: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_ALLMAGICRESIST), VisualizeFloatPercent(param[0])); AddDescText(-1, true, "~%d", VisualizeFloatPercent(param[1])); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_ALLMAGICRESIST), VisualizeFloatPercent(param[0])); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_ALLMAGICRESIST), param[0]); - } - break; - case 80: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_CASTTIME), -VisualizeFloatPercent(param[0])); AddDescText(-1, true, "~%d%%", VisualizeFloatPercent(param[1])); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_CASTTIME), -VisualizeFloatPercent(param[0])); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_CASTTIME), -param[0]); - } - break; - case 81: - if (local) - { - float f0 = BitConverter.ToSingle(BitConverter.GetBytes(param[0]), 0); - float f1 = BitConverter.ToSingle(BitConverter.GetBytes(param[1]), 0); - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDATKDIST), f0); AddDescText(-1, true, "~%.2f", f1); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_ADDATKDIST), f0); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_ADDATKDIST), BitConverter.ToSingle(BitConverter.GetBytes(param[0]), 0)); - } - break; - case 82: - if (local) - { - int h0 = param[0] / 2; int h1 = param[1] / 2; - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_MPRECOVER), h0); AddDescText(-1, true, "~%d", h1); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_MPRECOVER), h0); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_MPRECOVER), param[0] / 2); - } - break; - case 83: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_PHYDEFENCE) + " %", VisualizeFloatPercent(param[0])); AddDescText(-1, true, "~%d", VisualizeFloatPercent(param[1])); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_PHYDEFENCE) + " %", VisualizeFloatPercent(param[0])); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_PHYDEFENCE) + " %", param[0]); - } - break; - case 84: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_TOTAL_DEFENCE_ADD), VisualizeFloatPercent(param[0])); AddDescText(-1, true, "~%d", VisualizeFloatPercent(param[1])); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_TOTAL_DEFENCE_ADD), VisualizeFloatPercent(param[0])); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_TOTAL_DEFENCE_ADD), param[0]); - } - break; - case 85: - if (local) - { - int hhp0 = param[0] / 2; int hhp1 = param[1] / 2; - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_HPRECOVER), hhp0); AddDescText(-1, true, "~%d", hhp1); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_HPRECOVER), hhp0); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_HPRECOVER), param[0] / 2); - } - break; - case 86: - if (local) - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_DODGE)); - if (param[0] != param[1]) AddDescText(-1, true, " %+d~%d", param[0], param[1]); else AddDescText(-1, true, " %+d", param[0]); - } - else - { - AddDescText(-1, false, GetItemDescString(ITEMDESC_DODGE)); AddDescText(-1, true, " %+d", param[0]); - } - break; - case 87: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_MAXPHYDAMAGE), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_MAXPHYDAMAGE), param[0]); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_MAXPHYDAMAGE), param[0]); - } - break; - case 88: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_MAXMAGICDAMAGE), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_MAXMAGICDAMAGE), param[0]); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_MAXMAGICDAMAGE), param[0]); - } - break; - case 89: - if (local) - { - if (VisualizeFloatPercent(param[0]) != VisualizeFloatPercent(param[1])) { AddDescText(-1, false, GetItemDescString(ITEMDESC_REQEXTRA), -VisualizeFloatPercent(param[0])); AddDescText(-1, true, "~%d", VisualizeFloatPercent(param[1])); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_REQEXTRA), -VisualizeFloatPercent(param[0])); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_REQEXTRA), -VisualizeFloatPercent(param[0])); - } - break; - - case 90: - AddDescText(-1, true, GetItemDescString(ITEMDESC_PENETRATION), param[0]); - break; - case 91: - AddDescText(-1, true, GetItemDescString(ITEMDESC_RESILIENCE), param[0]); - break; - case 92: - if (!local && aPEEVals != null) - { - aPEEVals[PEEI_PHYDEF] += param[0]; - aPEEVals[PEEI_GOLDDEF] += param[1]; aPEEVals[PEEI_WOODDEF] += param[1]; aPEEVals[PEEI_WATERDEF] += param[1]; aPEEVals[PEEI_FIREDEF] += param[1]; aPEEVals[PEEI_EARTHDEF] += param[1]; - } - AddDescText(-1, false, GetItemDescString(ITEMDESC_PHYDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - AddDescText(-1, false, GetItemDescString(ITEMDESC_ALLMAGICDEF)); AddDescText(-1, true, " %+d", param[1]); - break; - case 93: - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDHP)); AddDescText(-1, true, " %+d", param[0]); - break; - case 94: - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDHP)); if (param[0] != param[1]) AddDescText(-1, true, " %+d~%d", param[0], param[1]); else AddDescText(-1, true, " %+d", param[0]); - break; - case 95: - AddDescText(-1, true, GetItemDescString(ITEMDESC_STRENGTH), param[0]); - break; - case 96: - AddDescText(-1, true, GetItemDescString(ITEMDESC_AGILITY), param[0]); - break; - case 97: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ENERGY), param[0]); - break; - case 98: - AddDescText(-1, true, GetItemDescString(ITEMDESC_VITALITY), param[0]); - break; - case 99: - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDMP)); AddDescText(-1, true, " %+d", param[0]); - break; - case 120: - AddDescText(-1, false, GetItemDescString(ITEMDESC_GOLDDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 121: - AddDescText(-1, false, GetItemDescString(ITEMDESC_WOODDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 122: - AddDescText(-1, false, GetItemDescString(ITEMDESC_WATERDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 123: - AddDescText(-1, false, GetItemDescString(ITEMDESC_FIREDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 124: - AddDescText(-1, false, GetItemDescString(ITEMDESC_EARTHDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 125: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ATKRATING), param[0]); - break; - case 126: - AddDescText(-1, false, GetItemDescString(ITEMDESC_DODGE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 127: - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDMP)); AddDescText(-1, true, " %+d", param[0]); - break; - case 128: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_VITALITY), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_VITALITY), param[0]); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_VITALITY), param[0]); - } - break; - case 129: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_STRENGTH), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_STRENGTH), param[0]); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_STRENGTH), param[0]); - } - break; - case 130: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_AGILITY), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_AGILITY), param[0]); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_AGILITY), param[0]); - } - break; - case 131: - if (local) - { - if (param[0] != param[1]) { AddDescText(-1, false, GetItemDescString(ITEMDESC_ENERGY), param[0]); AddDescText(-1, true, "~%d", param[1]); } - else { AddDescText(-1, true, GetItemDescString(ITEMDESC_ENERGY), param[0]); } - } - else - { - AddDescText(-1, true, GetItemDescString(ITEMDESC_ENERGY), param[0]); - } - break; - case 132: - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDHP)); AddDescText(-1, true, " %+d", param[0]); - break; - case 133: - AddDescText(-1, false, GetItemDescString(ITEMDESC_PHYDEFENCE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 134: - AddDescText(-1, false, GetItemDescString(ITEMDESC_ALLMAGICDEF)); AddDescText(-1, true, " %+d", param[0]); - break; - case 135: - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDPHYDAMAGE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 136: - AddDescText(-1, false, GetItemDescString(ITEMDESC_ADDMAGICDAMAGE)); AddDescText(-1, true, " %+d", param[0]); - break; - case 137: - if (local) AddDescText(-1, true, GetItemDescString(ITEMDESC_GOLDRESIST), VisualizeFloatPercent(param[0])); else AddDescText(-1, true, GetItemDescString(ITEMDESC_GOLDRESIST), param[0]); - break; - case 138: - if (local) AddDescText(-1, true, GetItemDescString(ITEMDESC_WOODRESIST), VisualizeFloatPercent(param[0])); else AddDescText(-1, true, GetItemDescString(ITEMDESC_WOODRESIST), param[0]); - break; - case 139: - if (local) AddDescText(-1, true, GetItemDescString(ITEMDESC_WATERRESIST), VisualizeFloatPercent(param[0])); else AddDescText(-1, true, GetItemDescString(ITEMDESC_WATERRESIST), param[0]); - break; - case 140: - if (local) AddDescText(-1, true, GetItemDescString(ITEMDESC_FIRERESIST), VisualizeFloatPercent(param[0])); else AddDescText(-1, true, GetItemDescString(ITEMDESC_FIRERESIST), param[0]); - break; - case 141: - if (local) AddDescText(-1, true, GetItemDescString(ITEMDESC_EARTHRESIST), VisualizeFloatPercent(param[0])); else AddDescText(-1, true, GetItemDescString(ITEMDESC_EARTHRESIST), param[0]); - break; - case 142: - if (local) AddDescText(-1, true, GetItemDescString(ITEMDESC_ALLMAGICRESIST), VisualizeFloatPercent(param[0])); else AddDescText(-1, true, GetItemDescString(ITEMDESC_ALLMAGICRESIST), param[0]); - break; - case 143: - if (local) AddDescText(-1, true, GetItemDescString(ITEMDESC_DEADLYSTRIKE), VisualizeFloatPercent(param[0])); else AddDescText(-1, true, GetItemDescString(ITEMDESC_DEADLYSTRIKE), param[0]); - break; - case 144: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ATK_DEGREE), param[0]); - break; - case 145: - AddDescText(-1, true, GetItemDescString(ITEMDESC_DEF_DEGREE), param[0]); - break; - case 146: - if (local) AddDescText(-1, true, GetItemDescString(ITEMDESC_PHYRESIST), VisualizeFloatPercent(param[0])); else AddDescText(-1, true, GetItemDescString(ITEMDESC_PHYRESIST), param[0]); - break; - - case 160: - AddDescText(-1, false, GetItemDescString(ITEMDESC_VIGOUR)); AddDescText(-1, true, " %+d", param[0]); - break; - - case 200: if (aRefines != null) aRefines[REFINE_PHYDAMAGE] += param[0]; break; - case 201: if (aRefines != null) aRefines[REFINE_MAGICDAMAGE] += param[0]; break; - case 202: if (aRefines != null) aRefines[REFINE_PHYDEF] += param[0]; break; - case 203: if (aRefines != null) aRefines[REFINE_GOLDDEF] += param[0]; break; - case 204: if (aRefines != null) aRefines[REFINE_WOODDEF] += param[0]; break; - case 205: if (aRefines != null) aRefines[REFINE_WATERDEF] += param[0]; break; - case 206: if (aRefines != null) aRefines[REFINE_FIREDEF] += param[0]; break; - case 207: if (aRefines != null) aRefines[REFINE_EARTHDEF] += param[0]; break; - case 208: if (aRefines != null) aRefines[REFINE_HP] += param[0]; break; - case 209: if (aRefines != null) aRefines[REFINE_DODGE] += param[0]; break; - case 210: if (aRefines != null) { aRefines[REFINE_GOLDDEF] += param[0]; aRefines[REFINE_WOODDEF] += param[0]; aRefines[REFINE_WATERDEF] += param[0]; aRefines[REFINE_FIREDEF] += param[0]; aRefines[REFINE_EARTHDEF] += param[0]; } break; - case 211: if (aRefines != null) { aRefines[REFINE_PHYDAMAGE] += param[0]; aRefines[REFINE_MAGICDAMAGE] += param[0]; } break; - case 212: if (aRefines != null) { aRefines[REFINE_PHYDEF] += param[0]; aRefines[REFINE_GOLDDEF] += param[0]; aRefines[REFINE_WOODDEF] += param[0]; aRefines[REFINE_WATERDEF] += param[0]; aRefines[REFINE_FIREDEF] += param[0]; aRefines[REFINE_EARTHDEF] += param[0]; } break; - - default: - AddDescText(-1, true, GetItemDescString(ITEMDESC_ERRORPROP), idProp); - break; - } } - } + /// /// Build add-ons properties description /// @@ -2334,7 +4025,7 @@ namespace PerfectWorld.Scripts.Managers return; // Change color - m_strDesc += GetColorString(ITEMDESC_COL_LIGHTBLUE); + m_strDesc += GetColorString(DescriptipionMsg.ITEMDESC_COL_LIGHTBLUE); foreach (Property prop in Props) { @@ -2371,45 +4062,107 @@ namespace PerfectWorld.Scripts.Managers } /// - /// Build tessera description + /// Build tessera description (socketed gems/stones) /// private void BuildTesseraDesc() { if (Holes.Count == 0) return; - int cyanine = ITEMDESC_COL_CYANINE; + int cyanine = (int)DescriptipionMsg.ITEMDESC_COL_CYANINE; - foreach (int hole in Holes) + for (int i = 0; i < Holes.Count; i++) { - if (hole == 0) + if (Holes[i] == 0) continue; - // Get item name - string itemName = EC_IvtrItemUtils.Instance.ResolveItemName(hole); + // Get item name - would normally use CECIvtrItem::CreateItem + string itemName = EC_IvtrItemUtils.Instance.ResolveItemName(Holes[i]); string descText = "null"; - // This would normally check if it's a stone and get its description - // For now, use the item name + // Check if it's a stone and get its description + // In C++, this checks if pItem->GetClassID() == ICID_STONE + // and then gets weapon_desc or armor_desc based on equipment type + // For now, use item name as fallback descText = itemName; - AddDescText(cyanine, true, GetItemDescString(ITEMDESC_2STRINGS), itemName, descText); + AddDescText(cyanine, true, GetItemDescString(DescriptipionMsg.ITEMDESC_2STRINGS), itemName, descText); } } /// /// Add suite description /// - public void AddSuiteDesc() + private void AddSuiteDesc() { int idSuite = GetSuiteID(); if (idSuite == 0) return; // This equipment isn't one of any suite - // This would normally build the suite description - // For now, just add a placeholder - m_strDesc += "\\r\\r"; - AddDescText(ITEMDESC_COL_YELLOW, true, "Suite Equipment"); + // Get suite info + DATA_TYPE dataType = DATA_TYPE.DT_INVALID; + elementdataman dataMan = EC_Game.GetElementDataMan(); + object pData = dataMan.get_data_ptr((uint)idSuite, ID_SPACE.ID_SPACE_ESSENCE, ref dataType); + if (dataType != DATA_TYPE.DT_SUITE_ESSENCE) + { + // ASSERT in C++ + return; + } + + // In C#, we'd need to cast to SUITE_ESSENCE struct + // For now, use placeholder values + string suiteName = "Suite"; // TODO: Get from SUITE_ESSENCE.name + int maxEquips = 12; // TODO: Get from SUITE_ESSENCE.max_equips + + // Get host player (would normally come from EC_Game.GetGameRun().GetHostPlayer()) + // Check if this equipment is in host's equipment pack + bool showDetail = false; // TODO: Check if m_pDescIvtr == pHostPlayer->GetEquipment() + + // Colors + int nameCol = DecideNameCol(); + int lblue = (int)DescriptipionMsg.ITEMDESC_COL_LIGHTBLUE; + int yellow = (int)DescriptipionMsg.ITEMDESC_COL_YELLOW; + + // Save current description + string strCurDesc = m_strDesc; + + if (!showDetail) + { + // Isn't equipment inventory, only add total suite number info. + m_strDesc = "\\r\\r"; + AddDescText(nameCol, false, "{0} ({1})", suiteName, maxEquips); + m_strDesc = strCurDesc + m_strDesc; + return; + } + + // Maximum number of suite items + const int MAX_NUM = 12; + + // Get equipped suite item list + int[] aEquipped = new int[MAX_NUM]; + int itemCnt = 0; // TODO: Get from pHostPlayer->GetEquippedSuiteItem(idSuite, aEquipped) + if (itemCnt == 0) + return; + + m_strDesc = "\\r\\r"; + + // Build suite addon properties at first + if (itemCnt > 1) + { + // Change color + AddDescText(lblue, false, ""); + + // In C++, this loops through suite addons and displays them + // For now, skip detailed addon display + } + + // Add suite name + AddDescText(yellow, true, "{0} ({1} / {2})", suiteName, itemCnt, maxEquips); + + // List suite item names would go here + // In C++, this creates SUITEITEM array and lists enabled/disabled items + // green, gray, white colors would be used here for enabled/disabled items + // For now, simplified version } /// @@ -2420,28 +4173,47 @@ namespace PerfectWorld.Scripts.Managers if (!IsDestroying() || dropItemID == 0 || num == 0) return; - // This would normally get the destroying info from element data - int red = ITEMDESC_COL_RED; + // Get destroying info + DATA_TYPE dataType = DATA_TYPE.DT_INVALID; + elementdataman dataMan = EC_Game.GetElementDataMan(); + object pData = dataMan.get_data_ptr((uint)dropItemID, ID_SPACE.ID_SPACE_ESSENCE, ref dataType); + + if (dataType != DATA_TYPE.DT_ELEMENT_ESSENCE) + { + // ASSERT(0) in C++ + return; + } + + // Cast to ELEMENT_ESSENCE to get name + // In C#, we'd need to access the name field from the essence data + string essenceName = "Repair Item"; // TODO: Get from ELEMENT_ESSENCE.name + + int red = (int)DescriptipionMsg.ITEMDESC_COL_RED; m_strDesc += "\\r"; - AddDescText(red, true, GetItemDescString(ITEMDESC_EQUIP_DESTROYING)); + AddDescText(red, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EQUIP_DESTROYING)); - // This would normally get the item name from element data - AddDescText(red, true, GetItemDescString(ITEMDESC_EQUIP_REPAIR_NEED_ITEM), "Repair Item"); - AddDescText(red, true, GetItemDescString(ITEMDESC_EQUIP_REPAIR_NEED_ITEMCNT), (int)(Math.Ceiling(num * 1.2))); + AddDescText(red, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EQUIP_REPAIR_NEED_ITEM), essenceName); + AddDescText(red, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EQUIP_REPAIR_NEED_ITEMCNT), (int)(Math.Ceiling(num * 1.2))); } /// /// Add reputation requirement description /// - public void AddReputationReqDesc() + private void AddReputationReqDesc() { - if (ReputationReq > 0) - { - // This would normally check the host player's reputation - int col = ITEMDESC_COL_WHITE; // Default to white, would check against player reputation - AddDescText(col, true, GetItemDescString(ITEMDESC_REPUTATION_REQ), ReputationReq); - } + if (ReputationReq == 0) + return; + + // Get host player reputation + // In C++: CECHostPlayer* pHost = g_pGame->GetGameRun()->GetHostPlayer(); + // int col = pHost->GetReputation() >= m_iReputationReq ? ITEMDESC_COL_WHITE : ITEMDESC_COL_RED; + int playerReputation = 0; // TODO: Get from host player + int col = playerReputation >= ReputationReq ? + (int)DescriptipionMsg.ITEMDESC_COL_WHITE : + (int)DescriptipionMsg.ITEMDESC_COL_RED; + + AddDescText(col, true, GetItemDescString(DescriptipionMsg.ITEMDESC_REPUTATION_REQ), ReputationReq); } /// @@ -2457,6 +4229,305 @@ namespace PerfectWorld.Scripts.Managers } return num; } + + /// + /// Add sharpener description (磨刀石 properties) + /// + private void AddSharpenerDesc() + { + if (Props.Count == 0) + return; + + int color = (int)DescriptipionMsg.ITEMDESC_COL_LIGHTBLUE; + + // Check if all sharpener properties have the same expire time + bool sameExpireTime = true; + bool findFirst = true; + int lastExpireTime = 0; + + foreach (Property prop in Props) + { + if (prop.Embed || prop.Suite || prop.Engraved) + continue; + + byte propType = GetPropertyType(prop.Type); + if (!IsSharpenerProperty(propType)) + continue; + + int p1 = prop.Params.Length > 1 ? prop.Params[1] : 0; + if (findFirst) + { + // Found first sharpener property + lastExpireTime = p1; + findFirst = false; + } + else + { + // Found another sharpener property + if (p1 != lastExpireTime) + { + // Expire times are different + sameExpireTime = false; + break; + } + } + } + + if (findFirst) + { + // Didn't find any sharpener property + return; + } + + bool firstProp = true; + foreach (Property prop in Props) + { + if (prop.Embed || prop.Suite || prop.Engraved) + continue; + + byte propType = GetPropertyType(prop.Type); + if (!IsSharpenerProperty(propType)) + continue; + + if (firstProp) + { + m_strDesc += "\\r"; + firstProp = false; + } + + // New line + m_strDesc += "\\r"; + + int p0 = prop.Params.Length > 0 ? prop.Params[0] : 0; // First parameter value + int p1 = prop.Params.Length > 1 ? prop.Params[1] : 0; // Expire time + + // Add property description + switch (propType) + { + case 100: // Sharpener physical damage + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDPHYDAMAGE)); + AddDescText(color, false, p0 >= 0 ? " +{0}" : " {0}", p0); + break; + + case 101: // Sharpener max physical damage + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_MAXPHYDAMAGE), p0); + break; + + case 102: // Sharpener magic damage + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDMAGICDAMAGE)); + AddDescText(color, false, p0 >= 0 ? " +{0}" : " {0}", p0); + break; + + case 103: // Sharpener max magic damage + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_MAXMAGICDAMAGE), p0); + break; + + case 104: // Sharpener physical defence + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_PHYDEFENCE)); + AddDescText(color, false, p0 >= 0 ? " +{0}" : " {0}", p0); + break; + + case 105: // Sharpener HP + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDHP)); + AddDescText(color, false, p0 >= 0 ? " +{0}" : " {0}", p0); + break; + + case 106: // Sharpener strength + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_STRENGTH), p0); + break; + + case 107: // Sharpener agility + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_AGILITY), p0); + break; + + case 108: // Sharpener energy + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ENERGY), p0); + break; + + case 109: // Sharpener attack rating + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ATKRATING), p0); + break; + + case 110: // Sharpener deadly strike + if (prop.Local) + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_DEADLYSTRIKE), VisualizeFloatPercent(p0)); + else + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_DEADLYSTRIKE), p0); + break; + + case 111: // Sharpener attack degree + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ATK_DEGREE), p0); + break; + + case 112: // Sharpener defence degree + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_DEF_DEGREE), p0); + break; + + case 113: // Sharpener cast time + if (prop.Local) + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_CASTTIME), -VisualizeFloatPercent(p0)); + else + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_CASTTIME), -p0); + break; + + case 114: // Sharpener magic defence + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ALLMAGICDEF)); + AddDescText(color, false, p0 >= 0 ? " +{0}" : " {0}", p0); + break; + + case 115: // Sharpener ride pet speed + AddDescText(color, false, GetItemDescString(DescriptipionMsg.ITEMDESC_ADDRIDEONPETSPEED), IntToFloat(p0)); + break; + + default: + // ASSERT(false) in C++ + continue; + } + + // If expire times are different, add expire time after each property + if (!sameExpireTime) + { + if (p1 != 0) + { + m_strDesc += " "; + AddExpireTimeDesc(p1); + TrimLastReturn(); + } + } + } + + // If expire times are the same, add expire time at the end + if (sameExpireTime) + { + if (lastExpireTime != 0) + { + m_strDesc += "\\r"; + AddExpireTimeDesc(lastExpireTime); + TrimLastReturn(); + } + } + } + + /// + /// Append engraved property descriptions to the current description buffer. + /// Mirrors the behaviour of the original C++ AddEngravedDesc. + /// + private void AddEngravedDesc() + { + if (Props.Count == 0) + return; + + // Change color + bool firstProp = true; + + foreach (Property prop in Props) + { + if (!prop.Engraved) + continue; + + if (firstProp) + { + firstProp = false; + m_strDesc += "\\r"; + m_strDesc += GetColorString(DescriptipionMsg.ITEMDESC_COL_YELLOW); + } + AddOneAddOnPropDesc(prop.Type, prop.Params, null, null, prop.Local); + } + + if (!firstProp) + { + // Trim last return after engraved properties + TrimLastReturn(); + } + } + + /// + /// Append maker description (signature / crafted by) to the description buffer. + /// + private void AddMakerDesc() + { + if (string.IsNullOrEmpty(Maker)) + return; + + m_strDesc += "\\r"; + // For signed marks (IMT_SIGN), Maker already contains color codes and formatted text. + if (MadeFrom == IMT_SIGN) + { + m_strDesc += Maker; + } + else + { + // Normal "made by" line using item-desc string if available + string fmt = GetItemDescString(DescriptipionMsg.ITEMDESC_MADEFROM); + if (string.IsNullOrEmpty(fmt)) + { + fmt = "Made by {0}"; + } + AddDescText((int)DescriptipionMsg.ITEMDESC_COL_GREEN, false, fmt, Maker); + } + } + + /// + /// Trim the last '\r' in description string + /// + private void TrimLastReturn() + { + int len = m_strDesc.Length; + if (len >= 2 && m_strDesc[len - 2] == '\\' && m_strDesc[len - 1] == 'r') + { + m_strDesc = m_strDesc.Substring(0, len - 2); + } + } + + /// + /// Add expire time description + /// + private void AddExpireTimeDesc() + { + if (ExpireDate == 0) + return; + + int green = (int)DescriptipionMsg.ITEMDESC_COL_GREEN; + int yellow = (int)DescriptipionMsg.ITEMDESC_COL_YELLOW; + int gold = (int)DescriptipionMsg.ITEMDESC_COL_DARKGOLD; + int red = (int)DescriptipionMsg.ITEMDESC_COL_RED; + + // Get server GMT time (this would normally come from EC_Game) + long serverTime = 0; // TODO: Get from EC_Game.GetServerGMTTime() + long timeLeft = ExpireDate - serverTime; + if (timeLeft < 0) timeLeft = 0; + + if (timeLeft > 24 * 3600) + { + AddDescText(green, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EXPIRETIME_DAY), + (int)(timeLeft / (24 * 3600)), (int)((timeLeft % (24 * 3600)) / 3600)); + } + else if (timeLeft > 3600) + { + AddDescText(yellow, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EXPIRETIME_HOUR_MIN), + (int)(timeLeft / 3600), (int)((timeLeft % 3600) / 60)); + } + else if (timeLeft > 60) + { + AddDescText(gold, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EXPIRETIME_MIN_SEC), + (int)(timeLeft / 60), (int)(timeLeft % 60)); + } + else + { + AddDescText(red, true, GetItemDescString(DescriptipionMsg.ITEMDESC_EXPIRETIME_SECOND), (int)timeLeft); + } + } + + /// + /// Add expire time description with specific expire date + /// + private void AddExpireTimeDesc(int expireDate) + { + int temp = ExpireDate; + ExpireDate = expireDate; + AddExpireTimeDesc(); + ExpireDate = temp; + } /// /// Get preview info @@ -2481,7 +4552,7 @@ namespace PerfectWorld.Scripts.Managers return m_strDesc; // Change color - m_strDesc += GetColorString(ITEMDESC_COL_LIGHTBLUE); + m_strDesc += GetColorString(DescriptipionMsg.ITEMDESC_COL_LIGHTBLUE); foreach (Property prop in Props) { @@ -2514,7 +4585,7 @@ namespace PerfectWorld.Scripts.Managers return m_strDesc; // Change color - m_strDesc += GetColorString(ITEMDESC_COL_YELLOW); + m_strDesc += GetColorString(DescriptipionMsg.ITEMDESC_COL_YELLOW); foreach (Property prop in Props) { @@ -2549,4 +4620,5 @@ namespace PerfectWorld.Scripts.Managers return false; } } -} \ No newline at end of file +} + diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem.cs index dcf525698d..16b78930e5 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem.cs @@ -7,6 +7,8 @@ using BrewMonster; using ModelRenderer.Scripts.Common; using ModelRenderer.Scripts.GameData; using UnityEngine; +using PerfectWorld.Scripts.Managers; +using BrewMonster.Network; namespace BrewMonster.Scripts.Managers { @@ -1178,7 +1180,35 @@ namespace BrewMonster.Scripts.Managers /// protected virtual string GetNormalDesc(bool bRepair) { - return string.IsNullOrEmpty(m_strDesc) ? null : m_strDesc; + // Build a simple but centralized description: + // - Name + // - String-table description (if any) + // - Extended description (if any) + m_strDesc = string.Empty; + + // Item name line + string name = GetName(); + if (!string.IsNullOrEmpty(name)) + { + AddDescText(0, true, name); + } + + // Core description from item_desc.txt (via EC_Game / TryGetItemMsg) + string mainDesc = TryGetItemMainDesc(); + if (!string.IsNullOrEmpty(mainDesc)) + { + AddDescText(0, true, mainDesc); + } + + // Extended description from item_ext_desc.txt + string extDesc = TryGetItemExtDesc(); + if (!string.IsNullOrEmpty(extDesc)) + { + AddDescText(0, true, extDesc); + } + + TrimLastReturn(); + return m_strDesc; } protected virtual string GetBoothBuyDesc() @@ -1193,7 +1223,10 @@ namespace BrewMonster.Scripts.Managers protected virtual void AddPriceDesc(int col, bool bRepair) { - // Full text/color building uses string tables; keep a minimal stub for now. + // Basic price string using scaled price; color is ignored at this level. + int price = GetScaledPrice(); + if (price <= 0) return; + AddDescText(col, true, "Price: {0}", price); } protected virtual void AddProfReqDesc(int iProfReq) @@ -1219,27 +1252,47 @@ namespace BrewMonster.Scripts.Managers protected void AddExtDescText() { - // Extension description comes from game configs; keep stubbed for now. + // Extend description from item_ext_desc.txt via EC_Game + string ext = TryGetItemExtDesc(); + if (!string.IsNullOrEmpty(ext)) + { + AddDescText(0, true, ext); + } } protected void AddExpireTimeDesc() { + // Placeholder: expiry description can be added here when time system is fully wired. } protected void AddExpireTimeDesc(int expire_date) { + // Overwrite, call standard one; we don't change m_expire_date in this simplified port. + AddExpireTimeDesc(); } protected void AddIDDescText() { + // Optional: show internal id for debugging + AddDescText(0, true, "ID: {0}", m_tid); } protected void AddBindDescText() { + // Simple binding flags display based on ProcType + if ((m_iProcType & (int)ProcType.PROC_BINDING) != 0) + { + AddDescText(0, true, "[Bound]"); + } + else if ((m_iProcType & (int)ProcType.PROC_BIND) != 0) + { + AddDescText(0, true, "[Bind on Use]"); + } } protected void AddActionTypeDescText(int action_type) { + // Action/weapon type formatting can be added later as needed. } protected void TrimLastReturn() @@ -1247,7 +1300,10 @@ namespace BrewMonster.Scripts.Managers if (string.IsNullOrEmpty(m_strDesc)) return; - if (m_strDesc.EndsWith("\n", StringComparison.Ordinal)) + // Remove trailing "\r" or "\n" for consistency with C++ style + if (m_strDesc.EndsWith("\\r", StringComparison.Ordinal)) + m_strDesc = m_strDesc.Substring(0, m_strDesc.Length - 2); + else if (m_strDesc.EndsWith("\n", StringComparison.Ordinal)) m_strDesc = m_strDesc.Substring(0, m_strDesc.Length - 1); } @@ -1263,6 +1319,7 @@ namespace BrewMonster.Scripts.Managers protected int GetColorStrID(int tid) { + // Placeholder: color index lookup; return -1 (white) by default. return -1; } @@ -1273,6 +1330,77 @@ namespace BrewMonster.Scripts.Managers return (int)(f * 100.0f + 0.5f); } + /// + /// Try to get the main description line for this item from item_desc.txt via EC_Game. + /// This mirrors the behaviour used by Inventory UI and NPC shop, but centralised here. + /// + private string TryGetItemMainDesc() + { + try + { + if (EC_Game.TryGetItemMsg(m_tid, out int messageId, out int displayMode)) + { + var tab = EC_Game.GetItemDesc(); + if (tab != null && tab.IsInitialized()) + { + var s = tab.GetWideString(messageId); + if (!string.IsNullOrEmpty(s)) return s; + } + } + + // Fallback: direct template id lookup + { + var tab = EC_Game.GetItemDesc(); + if (tab != null && tab.IsInitialized()) + { + var s = tab.GetWideString(m_tid); + if (!string.IsNullOrEmpty(s)) return s; + } + } + } + catch (Exception ex) + { + Debug.LogWarning($"[EC_IvtrItem] Error getting main description for tid={m_tid}: {ex.Message}"); + } + + return string.Empty; + } + + /// + /// Try to get the extended description line from item_ext_desc.txt. + /// + private string TryGetItemExtDesc() + { + try + { + if (EC_Game.TryGetItemMsg(m_tid, out int messageId, out int displayMode)) + { + var tab = EC_Game.GetItemExtDesc(); + if (tab != null && tab.IsInitialized()) + { + var s = tab.GetWideString(messageId); + if (!string.IsNullOrEmpty(s)) return s; + } + } + + // Fallback: direct id + { + var tab = EC_Game.GetItemExtDesc(); + if (tab != null && tab.IsInitialized()) + { + var s = tab.GetWideString(m_tid); + if (!string.IsNullOrEmpty(s)) return s; + } + } + } + catch (Exception ex) + { + Debug.LogWarning($"[EC_IvtrItem] Error getting extended description for tid={m_tid}: {ex.Message}"); + } + + return string.Empty; + } + #endregion } diff --git a/Assets/PerfectWorld/Scripts/UI/NPCShopDetailPanel.cs b/Assets/PerfectWorld/Scripts/UI/NPCShopDetailPanel.cs index 1a5ed0520a..eb2f69fa6c 100644 --- a/Assets/PerfectWorld/Scripts/UI/NPCShopDetailPanel.cs +++ b/Assets/PerfectWorld/Scripts/UI/NPCShopDetailPanel.cs @@ -114,31 +114,35 @@ public class NPCShopDetailPanel : MonoBehaviour } } - string GetItemDescription(int itemId) + string GetItemDescription(int itemId) { // First check if description is already in the item data if (!string.IsNullOrEmpty(currentItem.desc)) { return currentItem.desc; } - - // Otherwise, get description from EC_IvtrItem - try - { - EC_IvtrItem item = EC_IvtrItem.CreateItem(itemId, 0, 1); - if (item != null) + + // Otherwise, build description using the same central pipeline as inventory: + try { - item.GetDetailDataFromLocal(); - string description = item.GetDesc(); - return !string.IsNullOrEmpty(description) ? description : "No description available."; + EC_IvtrItem item = EC_IvtrItem.CreateItem(itemId, 0, 1); + if (item != null) + { + // For NPC shop, we typically have static data only, so load from local DB + item.GetDetailDataFromLocal(); + string description = item.GetDesc(); + if (!string.IsNullOrEmpty(description)) + { + return description.Replace("\\r", "\n"); + } + } } - } - catch (System.Exception ex) - { - Debug.LogWarning($"[NPCShopDetailPanel] Failed to get description for item {itemId}: {ex.Message}"); - } - - return "No description available."; + catch (System.Exception ex) + { + Debug.LogWarning($"[NPCShopDetailPanel] Failed to get description for item {itemId}: {ex.Message}"); + } + + return "No description available."; } void OnCloseClicked()