40f17dadab
# Conflicts: # Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs # Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs # Assets/Scenes/NPCRender.unity # Assets/Scenes/a61.unity # Assets/Scripts/CECHostPlayer.cs
2552 lines
111 KiB
C#
2552 lines
111 KiB
C#
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.GetWideString(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;
|
||
}
|
||
}
|
||
} |