Files
test/Assets/PerfectWorld/Scripts/Managers/EC_IvtrEquip.cs
T
2025-11-05 16:08:51 +07:00

2552 lines
111 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using ModelRenderer.Scripts.GameData;
using BrewMonster;
using BrewMonster.Common;
using BrewMonster.Network;
using System.IO;
using System.Text.RegularExpressions;
using System.Reflection;
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
{
/// <summary>
/// Equipment item class that handles all equipment-specific functionality
/// Converted from C++ EC_IvtrEquip.cpp
/// </summary>
public class EC_IvtrEquip
{
#region Constants and Enums
// Item Class IDs
public const int ICID_EQUIP = 1;
public const int ICID_WEAPON = 2;
// Item Made From Types
public const byte IMT_NULL = 0;
public const byte IMT_SIGN = 1;
// Property Effect Essence Flags
public const uint PEE_PHYDAMAGE = 0x00000001;
public const uint PEE_MAGICDAMAGE = 0x00000002;
public const uint PEE_PHYDEF = 0x00000004;
public const uint PEE_GOLDDEF = 0x00000008;
public const uint PEE_WOODDEF = 0x00000010;
public const uint PEE_WATERDEF = 0x00000020;
public const uint PEE_FIREDEF = 0x00000040;
public const uint PEE_EARTHDEF = 0x00000080;
public const uint PEE_ATKSPEED = 0x00000100;
public const uint PEE_ATKDIST = 0x00000200;
public const uint PEE_HP = 0x00000400;
public const uint PEE_MP = 0x00000800;
public const uint PEE_DODGE = 0x00001000;
public const uint PEE_ENDURANCE = 0x00002000;
public const uint PEE_STRENGTHREQ = 0x00004000;
public const uint PEE_AGILITYREQ = 0x00008000;
public const uint PEE_ENERGYREQ = 0x00010000;
public const uint PEE_VITALITYREQ = 0x00020000;
// Property Effect Essence Indexes
public const int PEEI_PHYDAMAGE = 0;
public const int PEEI_MAX_PHYDAMAGE = 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;
// Refine Indexes
public const int REFINE_PHYDAMAGE = 0;
public const int REFINE_MAGICDAMAGE = 1;
public const int REFINE_PHYDEF = 2;
public const int REFINE_GOLDDEF = 3;
public const int REFINE_WOODDEF = 4;
public const int REFINE_WATERDEF = 5;
public const int REFINE_FIREDEF = 6;
public const int REFINE_EARTHDEF = 7;
public const int REFINE_HP = 8;
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;
// Scale Types
public const int SCALE_SELL = 1;
// Endurance Scale
public const int ENDURANCE_SCALE = 100;
#endregion
#region Fields
// Basic Item Properties
public int TemplateId { get; set; }
public int ExpireDate { get; set; }
public int CID { get; set; }
public int Price { get; set; }
public int Count { get; set; }
public float PriceScale { get; set; }
public int ScaleType { get; set; }
// Equipment Requirements
public int LevelReq { get; set; }
public int StrengthReq { get; set; }
public int AgilityReq { get; set; }
public int ProfReq { get; set; }
public int VitalityReq { get; set; }
public int EnergyReq { get; set; }
public int ReputationReq { get; set; }
// Endurance
public int CurEndurance { get; set; }
public int MaxEndurance { get; set; }
public int RepairFee { get; set; }
// Maker Information
public byte MadeFrom { get; set; }
public string Maker { get; set; }
// Equipment Properties
public ushort StoneMask { get; set; }
public int FixProps { get; set; }
public int RefineLvl { get; set; }
public byte PropNum { get; set; }
public byte EmbedNum { get; set; }
// Equipment Arrays
public List<int> Holes { get; set; }
public List<Property> Props { get; set; }
// Description
protected string m_strDesc = "";
#endregion
#region Base Stats (from Element Data)
private static bool TryGetNumber<T>(object data, string[] names, out T value) where T : struct
{
value = default;
if (data == null) return false;
var t = data.GetType();
foreach (var name in names)
{
var f = t.GetField(name, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
if (f != null)
{
try
{
object v = f.GetValue(data);
if (v == null) continue;
if (typeof(T) == typeof(float))
{
float fv = Convert.ToSingle(v);
value = (T)(object)fv;
return true;
}
else
{
int iv = Convert.ToInt32(v);
if (typeof(T) == typeof(int)) { value = (T)(object)iv; return true; }
}
}
catch { }
}
var p = t.GetProperty(name, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
if (p != null)
{
try
{
object v = p.GetValue(data, null);
if (v == null) continue;
if (typeof(T) == typeof(float))
{
float fv = Convert.ToSingle(v);
value = (T)(object)fv;
return true;
}
else
{
int iv = Convert.ToInt32(v);
if (typeof(T) == typeof(int)) { value = (T)(object)iv; return true; }
}
}
catch { }
}
}
return false;
}
public string GetBaseStatsForDisplay()
{
return GetBaseStatsDesc();
}
private string GetBaseStatsDesc()
{
elementdataman edm = ElementDataManProvider.GetElementDataMan();
if (edm == null) return string.Empty;
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;
// Try weapon-style fields first
int dmgLow = 0, dmgHighMax = 0;
bool hasDmgLow = TryGetNumber<int>(data, new[] { "damage_low" }, out dmgLow);
bool hasDmgHighMax = TryGetNumber<int>(data, new[] { "damage_high_max", "damage_high" }, out dmgHighMax);
List<string> lines = new List<string>();
if (hasDmgLow && hasDmgHighMax)
{
// Physical damage range
lines.Add(string.Format("{0} {1}-{2}", GetItemDescString(ITEMDESC_ADDPHYDAMAGE), dmgLow, dmgHighMax));
// Magic damage if available
if (TryGetNumber<int>(data, new[] { "magic_damage_low" }, out int mdLow) &&
TryGetNumber<int>(data, new[] { "magic_damage_high_max", "magic_damage_high" }, out int mdHigh))
{
lines.Add(string.Format("{0} {1}-{2}", GetItemDescString(ITEMDESC_ADDMAGICDAMAGE), mdLow, mdHigh));
}
// Attack time/speed
float atkTime;
if (TryGetNumber<float>(data, new[] { "attack_time", "atk_time" }, out atkTime) && atkTime > 0.0001f)
{
// 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<float>(data, new[] { "attack_speed", "atk_speed" }, out float atkSpeed) && atkSpeed > 0)
{
lines.Add(string.Format("{0} {1:F2}", GetItemDescString(ITEMDESC_ATKTIME), atkSpeed));
}
// Range
float range;
if (TryGetNumber<float>(data, new[] { "range", "attack_range", "atk_range" }, out range))
{
lines.Add(string.Format("{0} {1:F2}", GetItemDescString(ITEMDESC_ADDATKDIST), range));
}
}
else
{
// Try armor-style fields
if (TryGetNumber<int>(data, new[] { "defence_high", "defense_high", "defence", "defense" }, out int defHigh))
{
lines.Add(string.Format("{0} +{1}", GetItemDescString(ITEMDESC_PHYDEFENCE), defHigh));
}
// Elemental resistances (look for *_resist or specific names)
(string label, string[] names)[] res = new (string, string[])[]
{
(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"})
};
for (int i = 0; i < res.Length; i++)
{
var label = res[i].label;
var names = res[i].names;
if (TryGetNumber<int>(data, names, out int v))
{
lines.Add(string.Format("{0} +{1}", label, v));
}
}
}
return string.Join("\\r", lines);
}
catch { return string.Empty; }
}
private static object TryFindElementByScanningArraysLocal(object edm, uint id)
{
if (edm == null) return null;
try
{
var fields = edm.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var f in fields)
{
if (!f.FieldType.IsArray) continue;
var arr = f.GetValue(edm) as Array;
if (arr == null || arr.Length == 0) continue;
var elemType = f.FieldType.GetElementType();
var idField = elemType.GetField("id", BindingFlags.Public | BindingFlags.Instance);
if (idField == null || idField.FieldType != typeof(uint)) continue;
for (int i = 0; i < arr.Length; i++)
{
var element = arr.GetValue(i);
if (element == null) continue;
var value = (uint)idField.GetValue(element);
if (value == id)
{
return element;
}
}
}
}
catch { }
return null;
}
#endregion
#region Property Structure
public class Property
{
public int Type { get; set; }
public int NumParam { get; set; }
public bool Embed { get; set; }
public bool Suite { get; set; }
public bool Engraved { get; set; }
public bool Local { get; set; }
public int[] Params { get; set; }
public Property()
{
Params = new int[4];
}
public Property(Property other)
{
Type = other.Type;
NumParam = other.NumParam;
Embed = other.Embed;
Suite = other.Suite;
Engraved = other.Engraved;
Local = other.Local;
Params = new int[4];
Array.Copy(other.Params, Params, Math.Min(4, other.Params.Length));
}
}
#endregion
#region Constructor
public EC_IvtrEquip(int tid, int expireDate)
{
TemplateId = tid;
ExpireDate = expireDate;
CID = ICID_EQUIP;
Price = 0;
Count = 1;
PriceScale = 1.0f;
ScaleType = 0;
LevelReq = 0;
StrengthReq = 0;
AgilityReq = 0;
ProfReq = 0;
VitalityReq = 0;
EnergyReq = 0;
ReputationReq = 0;
CurEndurance = 0;
MaxEndurance = 0;
RepairFee = 0;
MadeFrom = 0;
StoneMask = 0;
FixProps = 0;
RefineLvl = 0;
PropNum = 0;
EmbedNum = 0;
Holes = new List<int>();
Props = new List<Property>();
}
public EC_IvtrEquip(EC_IvtrEquip other)
{
// Copy basic properties
TemplateId = other.TemplateId;
ExpireDate = other.ExpireDate;
CID = other.CID;
Price = other.Price;
Count = other.Count;
PriceScale = other.PriceScale;
ScaleType = other.ScaleType;
// Copy equipment properties
LevelReq = other.LevelReq;
ProfReq = other.ProfReq;
StrengthReq = other.StrengthReq;
AgilityReq = other.AgilityReq;
VitalityReq = other.VitalityReq;
EnergyReq = other.EnergyReq;
ReputationReq = other.ReputationReq;
CurEndurance = other.CurEndurance;
MaxEndurance = other.MaxEndurance;
RepairFee = other.RepairFee;
MadeFrom = other.MadeFrom;
Maker = other.Maker;
StoneMask = other.StoneMask;
FixProps = other.FixProps;
RefineLvl = other.RefineLvl;
PropNum = other.PropNum;
EmbedNum = other.EmbedNum;
Holes = new List<int>(other.Holes);
Props = new List<Property>(other.Props.Select(p => new Property(p)));
}
#endregion
#region Core Methods
/// <summary>
/// Set item detail information from binary data
/// </summary>
public bool SetItemInfo(byte[] infoData, int dataLen)
{
if (infoData == null || dataLen == 0)
return true;
// Try native order (as original client):
// [6 x short requirements][2 x int endurance][short essenceSize][maker info][essence bytes][short numHole][WORD stoneMask][numHole x int holes][int numProp][props]
if (TryParseEquipInfoNative(infoData, dataLen))
{
ParseProperties();
return true;
}
// Fallback to legacy/custom order if server payload differs
if (TryParseEquipInfoLegacy(infoData, dataLen))
{
ParseProperties();
return true;
}
Debug.LogError("EC_IvtrEquip::SetItemInfo: could not parse detail payload");
return false;
}
private bool TryParseEquipInfoNative(byte[] data, int len)
{
try
{
int offset = 0;
if (len < 6 * 2 + 2 * 4 + 2) return false;
LevelReq = BitConverter.ToInt16(data, offset); offset += 2;
ProfReq = BitConverter.ToInt16(data, offset); offset += 2;
StrengthReq= BitConverter.ToInt16(data, offset); offset += 2;
VitalityReq= BitConverter.ToInt16(data, offset); offset += 2;
AgilityReq = BitConverter.ToInt16(data, offset); offset += 2;
EnergyReq = BitConverter.ToInt16(data, offset); offset += 2;
CurEndurance = BitConverter.ToInt32(data, offset); offset += 4;
MaxEndurance = BitConverter.ToInt32(data, offset); offset += 4;
int essenceSize = BitConverter.ToInt16(data, offset); offset += 2;
// Maker info (type + length + payload)
if (offset + 2 <= len)
{
ReadMakerInfo(data, ref offset);
}
if (essenceSize < 0 || offset + essenceSize > len) return false;
offset += essenceSize; // skip essence for now
if (offset + 2 + 2 > len) return false;
int numHole = BitConverter.ToInt16(data, offset); offset += 2;
StoneMask = BitConverter.ToUInt16(data, offset); offset += 2;
Holes.Clear();
if (numHole > 0)
{
if (offset + 4 * numHole > len) return false;
Holes.Capacity = numHole;
for (int i = 0; i < numHole; i++)
{
Holes.Add(BitConverter.ToInt32(data, offset)); offset += 4;
}
}
else if (numHole < 0)
{
return false;
}
if (offset + 4 > len) return false;
int numProp = BitConverter.ToInt32(data, offset); offset += 4;
Props.Clear();
if (numProp > 0)
{
Props.Capacity = numProp;
for (int i = 0; i < numProp; i++)
{
if (offset + 4 > len) return false;
int type = BitConverter.ToInt32(data, offset); offset += 4;
Property prop = new Property();
prop.Type = type & 0x1fff;
prop.NumParam = (type & 0x6000) >> 13;
prop.Embed = (type & 0x8000) != 0;
prop.Suite = (type & 0x10000) != 0;
prop.Engraved = (type & 0x20000) != 0;
prop.Local = false;
for (int j = 0; j < prop.NumParam; j++)
{
if (offset + 4 > len) return false;
prop.Params[j] = BitConverter.ToInt32(data, offset); offset += 4;
}
Props.Add(prop);
}
}
else if (numProp < 0)
{
return false;
}
// Sanity check to catch misalignment
if (LevelReq < 0 || LevelReq > 2000) return false;
if (MaxEndurance < 0 || MaxEndurance > 1000000) return false;
return true;
}
catch { return false; }
}
private bool TryParseEquipInfoLegacy(byte[] data, int len)
{
try
{
int offset = 0;
if (len < 16 + 6 * 2 + 8 + 2) return false;
// A legacy format we used earlier that prefixed price/scale before requirements
Price = BitConverter.ToInt32(data, offset); offset += 4;
Count = BitConverter.ToInt32(data, offset); offset += 4;
PriceScale = BitConverter.ToSingle(data, offset); offset += 4;
ScaleType = BitConverter.ToInt32(data, offset); offset += 4;
LevelReq = BitConverter.ToInt16(data, offset); offset += 2;
ProfReq = BitConverter.ToInt16(data, offset); offset += 2;
StrengthReq= BitConverter.ToInt16(data, offset); offset += 2;
VitalityReq= BitConverter.ToInt16(data, offset); offset += 2;
AgilityReq = BitConverter.ToInt16(data, offset); offset += 2;
EnergyReq = BitConverter.ToInt16(data, offset); offset += 2;
CurEndurance = BitConverter.ToInt32(data, offset); offset += 4;
MaxEndurance = BitConverter.ToInt32(data, offset); offset += 4;
int essenceSize = BitConverter.ToInt16(data, offset); offset += 2;
ReadMakerInfo(data, ref offset);
if (essenceSize < 0 || offset + essenceSize > len) return false;
offset += essenceSize;
int numHole = BitConverter.ToInt16(data, offset); offset += 2;
StoneMask = BitConverter.ToUInt16(data, offset); offset += 2;
Holes.Clear();
if (numHole > 0)
{
if (offset + 4 * numHole > len) return false;
for (int i = 0; i < numHole; i++) { Holes.Add(BitConverter.ToInt32(data, offset)); offset += 4; }
}
else if (numHole < 0) return false;
if (offset + 4 > len) return false;
int numProp = BitConverter.ToInt32(data, offset); offset += 4;
Props.Clear();
if (numProp > 0)
{
for (int i = 0; i < numProp; i++)
{
if (offset + 4 > len) return false;
int type = BitConverter.ToInt32(data, offset); offset += 4;
Property prop = new Property();
prop.Type = type & 0x1fff;
prop.NumParam = (type & 0x6000) >> 13;
prop.Embed = (type & 0x8000) != 0;
prop.Suite = (type & 0x10000) != 0;
prop.Engraved = (type & 0x20000) != 0;
for (int j = 0; j < prop.NumParam; j++)
{
if (offset + 4 > len) return false;
prop.Params[j] = BitConverter.ToInt32(data, offset); offset += 4;
}
Props.Add(prop);
}
}
return true;
}
catch { return false; }
}
/// <summary>
/// Read maker information from binary data
/// </summary>
private void ReadMakerInfo(byte[] data, ref int offset)
{
MadeFrom = data[offset++];
int makerLen = data[offset++];
if (makerLen > 0)
{
if (MadeFrom == IMT_SIGN)
{
ushort color = BitConverter.ToUInt16(data, offset); offset += 2;
makerLen -= 2;
string maker = System.Text.Encoding.Unicode.GetString(data, offset, makerLen);
offset += makerLen;
if (string.IsNullOrEmpty(maker))
{
Debug.LogWarning($"EC_IvtrEquip::ReadMakerInfo: Invalid maker info with makerLen={makerLen + 2}");
return;
}
SetNewMark(maker, ColorFromWord(color));
}
else
{
Maker = System.Text.Encoding.Unicode.GetString(data, offset, makerLen);
offset += makerLen;
}
}
else
{
Maker = "";
}
}
/// <summary>
/// Set new mark with color
/// </summary>
public void SetNewMark(string mark, Color color)
{
Maker = mark;
if (!string.IsNullOrEmpty(Maker))
{
// Convert hint string
// Filter bad words
// g_pGame->GetGameRun()->GetUIManager()->FilterBadWords(m_strMaker);
// Add color using ^RRGGBB from Color32 bytes
Color32 c32 = color;
string colorStr = $"^{c32.r:X2}{c32.g:X2}{c32.b:X2}";
Maker = colorStr + Maker;
// Add equipment mark display string
Maker = string.Format(GetItemDescString(ITEMDESC_EQUIPMARK), Maker);
}
MadeFrom = string.IsNullOrEmpty(mark) ? IMT_NULL : IMT_SIGN;
}
#endregion
#region Utility Methods
/// <summary>
/// Get item name
/// </summary>
public string GetName()
{
return EC_IvtrItemUtils.ResolveItemName(TemplateId);
}
/// <summary>
/// Add current endurance
/// </summary>
public int AddCurEndurance(int value)
{
CurEndurance += value;
CurEndurance = Mathf.Clamp(CurEndurance, 0, MaxEndurance);
return CurEndurance;
}
/// <summary>
/// Convert endurance real value to displaying value
/// </summary>
public static int VisualizeEndurance(int v)
{
return (v + ENDURANCE_SCALE - 1) / ENDURANCE_SCALE;
}
/// <summary>
/// Get empty hole number
/// </summary>
public int GetEmptyHoleNum()
{
int count = 0;
foreach (int hole in Holes)
{
if (hole == 0)
count++;
}
return count;
}
/// <summary>
/// Get repair cost
/// </summary>
public int GetRepairCost()
{
if (MaxEndurance == 0 || MaxEndurance == CurEndurance)
return 0;
int cost = (int)GetRawRepairCost();
if (cost < 1)
cost = 1;
return cost;
}
/// <summary>
/// Get raw repair cost
/// </summary>
public float GetRawRepairCost()
{
float cost = 0.0f;
if (!IsRepairable())
return cost;
if (CurEndurance == 0)
{
cost = RepairFee;
}
else if (MaxEndurance > 0 && CurEndurance < MaxEndurance)
{
float factor = (MaxEndurance - CurEndurance) / (float)MaxEndurance;
cost = RepairFee * factor;
}
return cost;
}
/// <summary>
/// Get scaled item price
/// </summary>
public int GetScaledPrice()
{
if (ScaleType != SCALE_SELL)
return (int)(Price * Count * PriceScale + 0.5f);
int price = Price * Count;
if (MaxEndurance == CurEndurance || MaxEndurance == 0)
return (int)(price * PriceScale + 0.5f);
else
return (int)(price * PriceScale * CurEndurance / (float)MaxEndurance + 0.5f);
}
/// <summary>
/// Check if item is repairable
/// </summary>
public bool IsRepairable()
{
return MaxEndurance > 0;
}
/// <summary>
/// Check if item is destroying
/// </summary>
public bool IsDestroying()
{
return CurEndurance == 0 && MaxEndurance > 0;
}
/// <summary>
/// Check if item is rare
/// </summary>
public bool IsRare()
{
return RefineLvl >= 3;
}
#endregion
#region Property System
/// <summary>
/// Get property effect essence flags
/// </summary>
public uint PropEffectEssence()
{
uint flags = 0;
foreach (Property prop in Props)
{
flags = PropEffectMask(prop, flags);
}
return flags;
}
/// <summary>
/// Get property effect mask for a specific property
/// </summary>
public uint PropEffectMask(Property prop, uint flags)
{
// Get property type from game's item ext prop table
byte propType = GetPropertyType(prop.Type);
switch (propType)
{
case 0: // Physical damage
flags |= PEE_PHYDAMAGE;
break;
case 1: // Max physical damage
flags |= PEE_PHYDAMAGE;
break;
case 2: // Physical damage (%)
flags |= PEE_PHYDAMAGE;
break;
case 3: // Magic damage
flags |= PEE_MAGICDAMAGE;
break;
case 4: // Max magic damage
case 5: // Magic damage (%)
flags |= PEE_MAGICDAMAGE;
break;
case 6: // +Def -Atk
flags |= PEE_PHYDAMAGE;
flags |= PEE_PHYDEF;
break;
case 7: // +Atk -Def
flags |= PEE_PHYDAMAGE;
flags |= PEE_PHYDEF;
break;
case 8: // +Magic -MagicDef
flags |= PEE_MAGICDAMAGE;
flags |= PEE_GOLDDEF;
flags |= PEE_WOODDEF;
flags |= PEE_WATERDEF;
flags |= PEE_FIREDEF;
flags |= PEE_EARTHDEF;
break;
case 9: // Attack speed
flags |= PEE_ATKSPEED;
break;
case 10: // Attack distance
flags |= PEE_ATKDIST;
break;
case 11: // Cast time
break;
case 12: // Physical defense
flags |= PEE_PHYDEF;
break;
case 13: // Physical defense (%)
flags |= PEE_PHYDEF;
break;
case 14: // All magic defense
flags |= PEE_GOLDDEF;
flags |= PEE_WOODDEF;
flags |= PEE_WATERDEF;
flags |= PEE_FIREDEF;
flags |= PEE_EARTHDEF;
break;
case 15: // Gold defense
flags |= PEE_GOLDDEF;
break;
case 16: // Gold defense (%)
flags |= PEE_GOLDDEF;
break;
case 17: // Wood defense
flags |= PEE_WOODDEF;
break;
case 18: // Wood defense (%)
flags |= PEE_WOODDEF;
break;
case 19: // Water defense
flags |= PEE_WATERDEF;
break;
case 20: // Water defense (%)
flags |= PEE_WATERDEF;
break;
case 21: // Fire defense
flags |= PEE_FIREDEF;
break;
case 22: // Fire defense (%)
flags |= PEE_FIREDEF;
break;
case 23: // Earth defense
flags |= PEE_EARTHDEF;
break;
case 24: // Earth defense (%)
flags |= PEE_EARTHDEF;
break;
case 30: // +Gold -Fire
flags |= PEE_GOLDDEF;
flags |= PEE_FIREDEF;
break;
case 31: // +Wood -Gold
flags |= PEE_GOLDDEF;
flags |= PEE_WOODDEF;
break;
case 32: // +Water -Earth
flags |= PEE_WATERDEF;
flags |= PEE_EARTHDEF;
break;
case 33: // +Fire -Water
flags |= PEE_WATERDEF;
flags |= PEE_FIREDEF;
break;
case 34: // +Earth -Wood
flags |= PEE_WOODDEF;
flags |= PEE_EARTHDEF;
break;
case 35: // HP
flags |= PEE_HP;
break;
case 36: // MP
flags |= PEE_MP;
break;
case 37: // HP (%)
flags |= PEE_HP;
break;
case 38: // MP (%)
flags |= PEE_MP;
break;
case 50: // Dodge
flags |= PEE_DODGE;
break;
case 53: // Endurance (%)
flags |= PEE_ENDURANCE;
break;
case 56: // Equipment requirements
flags |= PEE_STRENGTHREQ;
flags |= PEE_AGILITYREQ;
flags |= PEE_ENERGYREQ;
flags |= PEE_VITALITYREQ;
break;
case 92: // +Physical +Magic
flags |= PEE_PHYDEF;
flags |= PEE_GOLDDEF;
flags |= PEE_WOODDEF;
flags |= PEE_WATERDEF;
flags |= PEE_FIREDEF;
flags |= PEE_EARTHDEF;
break;
case 200:
case 201:
case 202:
case 203:
case 204:
case 205:
case 206:
case 207:
case 208:
case 209:
case 210:
case 211:
case 212:
// refine props do not change mask further
break;
}
return flags;
}
/// <summary>
/// Get property type from property ID
/// </summary>
private static Dictionary<int, byte> s_propIdToType;
private static bool s_propMapLoaded;
private static readonly object s_propLock = new object();
private static void EnsurePropMapLoaded()
{
if (s_propMapLoaded) return;
lock (s_propLock)
{
if (s_propMapLoaded) return;
s_propIdToType = new Dictionary<int, byte>();
try
{
// Parse configs/item_ext_prop.txt to learn valid property type ids
string path = Path.Combine(UnityEngine.Application.streamingAssetsPath, "configs/item_ext_prop.txt");
if (File.Exists(path))
{
int currentType = -1;
bool inTypeBlock = false;
bool inBlockComment = false;
foreach (var rawLine in File.ReadLines(path))
{
string src = rawLine;
if (string.IsNullOrEmpty(src)) continue;
// strip block comments /* ... */ possibly spanning lines
System.Text.StringBuilder sb = new System.Text.StringBuilder();
int i = 0;
while (i < src.Length)
{
if (inBlockComment)
{
int end = src.IndexOf("*/", i, StringComparison.Ordinal);
if (end < 0) { i = src.Length; break; }
inBlockComment = false; i = end + 2; continue;
}
int start = src.IndexOf("/*", i, StringComparison.Ordinal);
if (start < 0)
{
sb.Append(src, i, src.Length - i);
break;
}
sb.Append(src, i, start - i);
int end2 = src.IndexOf("*/", start + 2, StringComparison.Ordinal);
if (end2 < 0) { inBlockComment = true; break; }
i = end2 + 2;
}
string line = sb.ToString().Trim();
if (line.Length == 0) continue;
if (line.StartsWith("//")) continue;
// Detect a new type section: e.g., "type: 45"
var typeMatch = Regex.Match(line, "^type:\\s*(?<type>\\d+)");
if (typeMatch.Success)
{
if (int.TryParse(typeMatch.Groups["type"].Value, out int t)) currentType = t;
inTypeBlock = line.Contains("{");
if (line.Contains("}")) { inTypeBlock = false; currentType = -1; }
continue;
}
if (line.Contains("{")) inTypeBlock = true;
if (line.Contains("}")) { inTypeBlock = false; currentType = -1; }
if (inTypeBlock && currentType >= 0)
{
foreach (Match m in Regex.Matches(line, "\\b(?<id>\\d{1,6})\\b"))
{
if (int.TryParse(m.Groups["id"].Value, out int id))
{
if (!s_propIdToType.ContainsKey(id)) s_propIdToType[id] = (byte)Mathf.Clamp(currentType, 0, 255);
}
}
}
}
}
}
catch { /* ignore parse errors; fallback below will handle */ }
s_propMapLoaded = true;
}
}
private byte GetPropertyType(int propId)
{
// Load once from item_ext_prop.txt; if not enough info, fall back to heuristics
EnsurePropMapLoaded();
if (s_propIdToType != null && s_propIdToType.TryGetValue(propId, out byte mapped))
return mapped;
// Unknown
return 0xff;
}
/// <summary>
/// Set properties to local
/// </summary>
public void SetLocalProps()
{
if (Props.Count == 0)
return;
foreach (Property prop in Props)
{
prop.Local = true;
}
}
/// <summary>
/// Get deadly strike rate provided by this equipment
/// </summary>
public int GetDeadlyStrikeRate(bool suiteGen)
{
int val = 0;
if (suiteGen)
{
// Suite generation logic would go here
// This is a simplified version
}
else
{
foreach (Property prop in Props)
{
byte propType = GetPropertyType(prop.Type);
if (propType == 45 || propType == 110)
val += prop.Params[0];
}
}
return val;
}
/// <summary>
/// Decide equipment name color
/// </summary>
public int DecideNameCol()
{
int index = GetColorStrID(TemplateId);
if (index >= 0)
return index;
int col = 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;
default:
if (PropNum > 0)
col = ITEMDESC_COL_LIGHTBLUE;
break;
}
return col;
}
/// <summary>
/// Get color string ID for template
/// </summary>
private int GetColorStrID(int templateId)
{
// This would normally query the game's color system
return -1;
}
#endregion
#region Description Methods
/// <summary>
/// Get item description for booth buying
/// </summary>
public string GetBoothBuyDesc()
{
m_strDesc = "";
int white = ITEMDESC_COL_WHITE;
// Item name
AddDescText(white, true, GetItemDescString(ITEMDESC_NAME), GetName());
// Base stats from element data
string baseStats = GetBaseStatsDesc();
if (!string.IsNullOrEmpty(baseStats))
{
m_strDesc += GetColorString(ITEMDESC_COL_WHITE);
m_strDesc += baseStats;
m_strDesc += "\\r";
}
// Add-on properties
BuildAddOnPropDesc(null, null);
// Tessera / stones
BuildTesseraDesc();
// Suite info (if any)
AddSuiteDesc();
// Price
AddPriceDesc(white, false);
return m_strDesc;
}
/// <summary>
/// Add price description
/// </summary>
public void AddPriceDesc(int col, bool repair)
{
if (repair)
AddDescText(col, false, GetItemDescString(ITEMDESC_REPAIRCOST), GetRepairCost());
else
AddDescText(col, true, "Price: {0}", GetScaledPrice());
}
/// <summary>
/// Format property description
/// </summary>
public string FormatPropDesc(Property prop)
{
string tmpDesc = m_strDesc;
m_strDesc = "";
AddOneAddOnPropDesc(prop.Type, prop.Params, null, null, prop.Local);
string result = m_strDesc;
m_strDesc = tmpDesc;
return result;
}
/// <summary>
/// Format refine data into a string
/// </summary>
public string FormatRefineData(uint addonId)
{
// This would normally query the equipment addon data
// For now, return empty string
return "";
}
/// <summary>
/// Check property range value
/// </summary>
public bool CheckPropRangeValue(Property prop)
{
int idProp = prop.Type;
byte propType = GetPropertyType(idProp);
switch (propType)
{
case 25: // +Gold(%) -Fire(%)
case 26: // +Wood(%) -Gold(%)
case 27: // +Water(%) -Earth(%)
case 28: // +Fire(%) -Water(%)
case 29: // +Earth(%) -Wood(%)
case 30: // +Gold -Fire
case 31: // +Wood -Gold
case 32: // +Water -Earth
case 33: // +Fire -Water
case 34: // +Earth -Wood
case 55: // Add skill
return false;
}
// Check for range values in equipment addon data
// This would normally query the equipment addon data
return false;
}
#endregion
#region Helper Methods
/// <summary>
/// Parse properties
/// </summary>
private void ParseProperties()
{
RefineLvl = 0;
PropNum = 0;
EmbedNum = 0;
if (Props.Count == 0)
return;
foreach (Property prop in Props)
{
int level = 0;
if (prop.Embed)
{
EmbedNum++;
continue;
}
else if (prop.Suite)
continue;
else if (prop.Engraved)
continue;
byte propType = GetPropertyType(prop.Type);
switch (propType)
{
case 200: // Refine physical damage
case 201: // Refine magic damage
case 202: // Refine physical defense
case 203: // Refine gold defense
case 204: // Refine wood defense
case 205: // Refine water defense
case 206: // Refine fire defense
case 207: // Refine earth defense
case 208: // Refine HP
case 209: // Refine dodge
case 210: // Refine all magic defense
case 211: // Refine physical damage & magic damage
case 212: // Refine physical defense & magic defense
level = prop.Params[1];
break;
}
if (level > 0)
RefineLvl = level;
else
PropNum++;
}
}
/// <summary>
/// Check if this equipment belongs to a suite
/// </summary>
public int GetSuiteID()
{
// This would normally query the game's suite equip table
return 0;
}
/// <summary>
/// Get item description string by ID
/// </summary>
private string GetItemDescString(int id)
{
var tab = EC_Game.GetItemDesc();
if (tab != null && tab.IsInitialized())
{
string s = tab.GetString(id);
if (!string.IsNullOrEmpty(s)) return s;
}
// Fallback labels for common IDs when the table lacks #_index entries
switch (id)
{
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}";
}
}
/// <summary>
/// Add description text
/// </summary>
private void AddDescText(int color, bool newLine, string format, params object[] args)
{
if (color >= 0)
{
string colorStr = GetColorString(color);
m_strDesc += colorStr;
}
if (args.Length > 0)
{
// Accept both C#-style ("{0}") and printf-style ("%d", "%+d", "%.2f", "%%") formats
string output;
if (format.IndexOf('%') >= 0 && format.IndexOf('{') < 0)
{
output = FormatPrintfLike(format, args);
}
else
{
output = string.Format(format, args);
}
m_strDesc += output;
}
else
{
m_strDesc += format;
}
if (newLine)
m_strDesc += "\\r";
}
private static string FormatPrintfLike(string fmt, object[] args)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
int argIndex = 0;
for (int i = 0; i < fmt.Length; i++)
{
char c = fmt[i];
if (c != '%')
{
sb.Append(c);
continue;
}
if (i + 1 < fmt.Length && fmt[i + 1] == '%')
{
sb.Append('%');
i += 1;
continue;
}
bool plus = false;
int precision = -1;
int j = i + 1;
if (j < fmt.Length && fmt[j] == '+') { plus = true; j++; }
if (j < fmt.Length && fmt[j] == '.')
{
// precision like %.2f
j++;
int start = j;
while (j < fmt.Length && char.IsDigit(fmt[j])) j++;
int.TryParse(fmt.Substring(start, j - start), out precision);
}
if (j < fmt.Length)
{
char spec = fmt[j];
if (spec == 'd')
{
object val = argIndex < args.Length ? args[argIndex++] : 0;
long iv = Convert.ToInt64(val);
string s = iv.ToString();
if (plus && iv >= 0) s = "+" + s;
sb.Append(s);
i = j;
continue;
}
else if (spec == 'f')
{
object val = argIndex < args.Length ? args[argIndex++] : 0.0;
double dv = Convert.ToDouble(val);
string s = precision >= 0 ? dv.ToString("F" + precision) : dv.ToString("F");
if (plus && dv >= 0) s = "+" + s;
sb.Append(s);
i = j;
continue;
}
}
// Fallback: treat '%' as literal if format not recognized
sb.Append('%');
}
return sb.ToString();
}
/// <summary>
/// Get color string for color ID
/// </summary>
private string GetColorString(int 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";
}
}
/// <summary>
/// Convert word color to Unity Color
/// </summary>
private Color ColorFromWord(ushort wordColor)
{
// Convert word color to Unity Color
// This is a simplified conversion
return new Color(
((wordColor >> 10) & 0x1F) / 31.0f,
((wordColor >> 5) & 0x1F) / 31.0f,
(wordColor & 0x1F) / 31.0f,
1.0f
);
}
/// <summary>
/// Check if property is sharpener property
/// </summary>
private bool IsSharpenerProperty(byte propType)
{
return propType >= 100 && propType <= 115;
}
/// <summary>
/// Visualize float percent
/// </summary>
private int VisualizeFloatPercent(int value)
{
return value / 100;
}
/// <summary>
/// Add one add-on property description
/// </summary>
private void AddOneAddOnPropDesc(int idProp, int[] param, int[] aPEEVals, int[] aRefines, bool local)
{
byte propType = GetPropertyType(idProp);
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:
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
{
if (aPEEVals != null) aPEEVals[PEEI_MAX_PHYDAMAGE] += param[0];
AddDescText(-1, true, GetItemDescString(ITEMDESC_MAXPHYDAMAGE), param[0]);
}
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;
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;
}
}
}
/// <summary>
/// Build add-ons properties description
/// </summary>
private void BuildAddOnPropDesc(int[] aPEEVals, int[] aRefines)
{
if (Props.Count == 0)
return;
// Change color
m_strDesc += GetColorString(ITEMDESC_COL_LIGHTBLUE);
foreach (Property prop in Props)
{
// Properties added by Embedded stone will be printed by BuildTesseraDesc() later
// Ignore suite properties also
if (prop.Embed || prop.Suite || prop.Engraved)
continue;
AddOneAddOnPropDesc(prop.Type, prop.Params, aPEEVals, aRefines, prop.Local);
}
}
/// <summary>
/// Get soul power added by this equipment
/// </summary>
public int GetSoulPowerAdded()
{
int added = 0;
int propertyCount = Props.Count;
foreach (Property prop in Props)
{
if (prop.NumParam > 0)
{
byte propType = GetPropertyType(prop.Type);
if (propType == 63) // Soul power property
{
added += prop.Params[0];
}
}
}
return added;
}
/// <summary>
/// Build tessera description
/// </summary>
private void BuildTesseraDesc()
{
if (Holes.Count == 0)
return;
int cyanine = ITEMDESC_COL_CYANINE;
foreach (int hole in Holes)
{
if (hole == 0)
continue;
// Get item name
string itemName = EC_IvtrItemUtils.ResolveItemName(hole);
string descText = "null";
// This would normally check if it's a stone and get its description
// For now, use the item name
descText = itemName;
AddDescText(cyanine, true, GetItemDescString(ITEMDESC_2STRINGS), itemName, descText);
}
}
/// <summary>
/// Add suite description
/// </summary>
public 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");
}
/// <summary>
/// Add destroying description
/// </summary>
public void AddDestroyingDesc(int dropItemID, int num)
{
if (!IsDestroying() || dropItemID == 0 || num == 0)
return;
// This would normally get the destroying info from element data
int red = ITEMDESC_COL_RED;
m_strDesc += "\\r";
AddDescText(red, true, GetItemDescString(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)));
}
/// <summary>
/// Add reputation requirement description
/// </summary>
public 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);
}
}
/// <summary>
/// Get engraved property number
/// </summary>
public int GetEngravedPropertyNum()
{
int num = 0;
foreach (Property prop in Props)
{
if (prop.Engraved)
num++;
}
return num;
}
/// <summary>
/// Get preview info
/// </summary>
public string GetPreviewInfo()
{
m_strDesc = "";
BuildAddOnPropDesc(null, null);
return m_strDesc;
}
/// <summary>
/// Get add-on property description
/// </summary>
public string GetAddOnPropDesc(int num, int[] addons)
{
int[] aPEEVals = new int[MAX_PEEINDEX];
int[] aRefines = new int[MAX_REFINEINDEX];
m_strDesc = "";
if (Props.Count == 0)
return m_strDesc;
// Change color
m_strDesc += GetColorString(ITEMDESC_COL_LIGHTBLUE);
foreach (Property prop in Props)
{
if (prop.Embed || prop.Suite || prop.Engraved)
continue;
for (int j = 0; j < num; j++)
{
if ((addons[j] & 0x1fff) == prop.Type)
{
AddOneAddOnPropDesc(prop.Type, prop.Params, aPEEVals, aRefines, prop.Local);
break;
}
}
}
return m_strDesc;
}
/// <summary>
/// Get engrave description
/// </summary>
public string GetEngraveDesc()
{
int[] aPEEVals = new int[MAX_PEEINDEX];
int[] aRefines = new int[MAX_REFINEINDEX];
m_strDesc = "";
if (Props.Count == 0)
return m_strDesc;
// Change color
m_strDesc += GetColorString(ITEMDESC_COL_YELLOW);
foreach (Property prop in Props)
{
if (prop.Engraved)
AddOneAddOnPropDesc(prop.Type, prop.Params, aPEEVals, aRefines, prop.Local);
}
return m_strDesc;
}
#endregion
}
/// <summary>
/// Equipment addon description class
/// </summary>
public class EC_IvtrEquipAddonDesc
{
private object m_pAddon;
private string m_strDesc = "";
/// <summary>
/// Set addon
/// </summary>
public bool SetAddon(uint idEquipAddon)
{
if (idEquipAddon == 0)
return false;
// This would normally get the addon data from element data manager
// For now, return false
return false;
}
}
}