772 lines
No EOL
30 KiB
C#
772 lines
No EOL
30 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using Npgsql;
|
|
using PhoenixLib.Logging;
|
|
using WingsAPI.Data.GameData;
|
|
using WingsAPI.Packets.Enums.Shells;
|
|
using WingsEmu.DTOs.BCards;
|
|
using WingsEmu.DTOs.Items;
|
|
using WingsEmu.Game._enum;
|
|
using WingsEmu.Packets.Enums;
|
|
using WingsEmu.Packets.Enums.Battle;
|
|
|
|
namespace Plugin.ResourceLoader.Loaders
|
|
{
|
|
public class ItemResourceFileLoader : IResourceLoader<ItemDTO>
|
|
{
|
|
private const string FILE_NAME = "Item.dat";
|
|
private readonly ResourceLoadingConfiguration _configuration;
|
|
private readonly List<ItemDTO> _itemDtos = new();
|
|
|
|
public ItemResourceFileLoader(ResourceLoadingConfiguration configuration) => _configuration = configuration;
|
|
|
|
public async Task<IReadOnlyList<ItemDTO>> LoadAsync()
|
|
{
|
|
if (_itemDtos.Any())
|
|
{
|
|
return _itemDtos;
|
|
}
|
|
|
|
string filePath = Path.Combine(_configuration.GameDataPath, FILE_NAME);
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
bool dbFirst = string.Equals(Environment.GetEnvironmentVariable("DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase)
|
|
|| string.Equals(Environment.GetEnvironmentVariable("RESOURCE_DB_FIRST"), "true", StringComparison.OrdinalIgnoreCase);
|
|
if (dbFirst)
|
|
{
|
|
TryHydrateItemDatFromDatabase(filePath);
|
|
}
|
|
}
|
|
|
|
if (!File.Exists(filePath))
|
|
{
|
|
throw new FileNotFoundException($"{filePath} should be present");
|
|
}
|
|
|
|
using var npcIdStream = new StreamReader(filePath, Encoding.GetEncoding(1252));
|
|
|
|
var item = new ItemDTO();
|
|
bool itemAreaBegin = false;
|
|
int itemCounter = 0;
|
|
|
|
string line;
|
|
while ((line = await npcIdStream.ReadLineAsync()) != null)
|
|
{
|
|
try
|
|
{
|
|
string[] currentLine = line.Split('\t');
|
|
|
|
switch (currentLine.Length)
|
|
{
|
|
case > 3 when currentLine[1] == "VNUM":
|
|
itemAreaBegin = true;
|
|
item.Id = int.Parse(currentLine[2]);
|
|
item.Price = long.Parse(currentLine[3]);
|
|
break;
|
|
case > 1 when currentLine[1] == "END":
|
|
{
|
|
if (!itemAreaBegin)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
_itemDtos.Add(item);
|
|
itemCounter++;
|
|
|
|
item = new ItemDTO();
|
|
itemAreaBegin = false;
|
|
break;
|
|
}
|
|
case > 2 when currentLine[1] == "NAME":
|
|
item.Name = currentLine[2];
|
|
break;
|
|
case > 7 when currentLine[1] == "INDEX":
|
|
FillMorphAndIndexValues(currentLine, item);
|
|
break;
|
|
case > 3 when currentLine[1] == "TYPE":
|
|
// currentLine[2] 0-range 2-range 3-magic
|
|
item.AttackType = (AttackType)Convert.ToByte(currentLine[2]);
|
|
item.Class = item.EquipmentSlot == EquipmentType.Fairy ? (byte)15 : Convert.ToByte(currentLine[3]);
|
|
break;
|
|
case > 3 when currentLine[1] == "FLAG":
|
|
FillFlags(item, currentLine);
|
|
break;
|
|
case > 1 when currentLine[1] == "DATA":
|
|
FillData(item, currentLine);
|
|
break;
|
|
case > 1 when currentLine[1] == "BUFF":
|
|
FillBuff(currentLine, item);
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Log.Error("Error while loading Item.dat", e);
|
|
}
|
|
}
|
|
|
|
Log.Info($"[RESOURCE_LOADER] {itemCounter.ToString()} Items loaded");
|
|
return _itemDtos;
|
|
}
|
|
|
|
private static void FillBuff(IReadOnlyList<string> currentLine, ItemDTO item)
|
|
{
|
|
for (int i = 0; i < 5; i++)
|
|
{
|
|
byte type = (byte)int.Parse(currentLine[2 + 5 * i]);
|
|
if (type is 0 or 255) // 255 = -1
|
|
{
|
|
continue;
|
|
}
|
|
|
|
int first = int.Parse(currentLine[3 + 5 * i]);
|
|
int second = int.Parse(currentLine[4 + 5 * i]);
|
|
|
|
int firstModulo = first % 4;
|
|
firstModulo = firstModulo switch
|
|
{
|
|
-1 => 1,
|
|
-2 => 2,
|
|
-3 => 1,
|
|
_ => firstModulo
|
|
};
|
|
|
|
int secondModulo = second % 4;
|
|
secondModulo = secondModulo switch
|
|
{
|
|
-1 => 1,
|
|
-2 => 2,
|
|
-3 => 1,
|
|
_ => secondModulo
|
|
};
|
|
|
|
var itemCard = new BCardDTO
|
|
{
|
|
ItemVNum = item.Id,
|
|
Type = type,
|
|
SubType = (byte)((int.Parse(currentLine[5 + i * 5]) + 1) * 10 + 1 + (first < 0 ? 1 : 0)),
|
|
FirstDataScalingType = (BCardScalingType)firstModulo,
|
|
SecondDataScalingType = (BCardScalingType)secondModulo,
|
|
FirstData = (int)Math.Abs(Math.Floor(first / 4.0)),
|
|
SecondData = (int)Math.Abs(Math.Floor(second / 4.0)),
|
|
CastType = byte.Parse(currentLine[6 + 5 * i])
|
|
};
|
|
|
|
item.BCards.Add(itemCard);
|
|
}
|
|
}
|
|
|
|
private static void FillFlags(ItemDTO item, IReadOnlyList<string> currentLine)
|
|
{
|
|
// useless [2]
|
|
// useless [3]
|
|
// useless [4]
|
|
item.IsSoldable = currentLine[5] == "0";
|
|
item.IsDroppable = currentLine[6] == "0";
|
|
item.IsTradable = currentLine[7] == "0";
|
|
item.IsMinilandActionable = currentLine[8] == "1";
|
|
item.IsWarehouse = currentLine[9] == "1";
|
|
item.ShowWarningOnUse = currentLine[10] == "1";
|
|
item.IsTimeSpaceRewardBox = currentLine[11] == "1";
|
|
item.ShowDescriptionOnHover = currentLine[12] == "1";
|
|
item.Flag3 = currentLine[13] == "1";
|
|
item.FollowMouseOnUse = currentLine[14] == "1";
|
|
item.ShowSomethingOnHover = currentLine[15] == "1";
|
|
item.IsColorable = currentLine[16] == "1";
|
|
item.Sex = currentLine[18] == "1"
|
|
? (byte)1
|
|
: currentLine[17] == "1"
|
|
? (byte)2
|
|
: (byte)0;
|
|
//not used item.Flag6 = currentLine[19] == "1";
|
|
item.PlaySoundOnPickup = currentLine[20] == "1";
|
|
item.UseReputationAsPrice = currentLine[21] == "1";
|
|
if (item.UseReputationAsPrice)
|
|
{
|
|
item.ReputPrice = item.Price;
|
|
}
|
|
|
|
item.IsHeroic = currentLine[22] == "1";
|
|
item.Flag7 = currentLine[23] == "1";
|
|
item.IsLimited = currentLine[24] == "1";
|
|
}
|
|
|
|
private static void FillData(ItemDTO item, string[] currentLine)
|
|
{
|
|
item.Data = new int[20];
|
|
|
|
for (int i = 0; i < 20; i++)
|
|
{
|
|
item.Data[i] = Convert.ToInt32(currentLine[2 + i]);
|
|
}
|
|
|
|
switch (item.ItemType)
|
|
{
|
|
case ItemType.Weapon:
|
|
item.LevelMinimum = Convert.ToByte(currentLine[2]);
|
|
item.DamageMinimum = Convert.ToInt16(currentLine[3]);
|
|
item.DamageMaximum = Convert.ToInt16(currentLine[4]);
|
|
item.HitRate = Convert.ToInt16(currentLine[5]);
|
|
item.CriticalLuckRate = Convert.ToSByte(currentLine[6]);
|
|
item.CriticalRate = Convert.ToInt16(currentLine[7]);
|
|
item.BasicUpgrade = Convert.ToByte(currentLine[10]);
|
|
item.MaximumAmmo = 100;
|
|
break;
|
|
|
|
case ItemType.Armor:
|
|
item.LevelMinimum = Convert.ToByte(currentLine[2]);
|
|
item.CloseDefence = Convert.ToInt16(currentLine[3]);
|
|
item.DistanceDefence = Convert.ToInt16(currentLine[4]);
|
|
item.MagicDefence = Convert.ToInt16(currentLine[5]);
|
|
item.DefenceDodge = Convert.ToInt16(currentLine[6]);
|
|
item.DistanceDefenceDodge = Convert.ToInt16(currentLine[6]);
|
|
item.BasicUpgrade = Convert.ToByte(currentLine[10]);
|
|
break;
|
|
|
|
case ItemType.Box:
|
|
item.Effect = Convert.ToInt16(currentLine[21]);
|
|
item.EffectValue = Convert.ToInt32(currentLine[3]);
|
|
item.LevelMinimum = Convert.ToByte(currentLine[4]);
|
|
|
|
if (item.ItemSubType == 7) // Magic Speed Booster
|
|
{
|
|
long time = Convert.ToInt32(currentLine[4]);
|
|
item.ItemValidTime = time == 0 ? -1 : Convert.ToInt32(currentLine[4]) * 3600;
|
|
}
|
|
|
|
break;
|
|
|
|
case ItemType.Fashion:
|
|
item.LevelMinimum = Convert.ToByte(currentLine[2]);
|
|
item.CloseDefence = Convert.ToInt16(currentLine[3]);
|
|
item.DistanceDefence = Convert.ToInt16(currentLine[4]);
|
|
item.MagicDefence = Convert.ToInt16(currentLine[5]);
|
|
item.DefenceDodge = Convert.ToInt16(currentLine[6]);
|
|
item.DistanceDefenceDodge = Convert.ToInt16(currentLine[6]);
|
|
|
|
if (item.EquipmentSlot == EquipmentType.CostumeHat || item.EquipmentSlot == EquipmentType.CostumeSuit || item.EquipmentSlot == EquipmentType.WeaponSkin)
|
|
{
|
|
long time = Convert.ToInt32(currentLine[13]);
|
|
item.ItemValidTime = time == 0 ? -1 : Convert.ToInt32(currentLine[13]) * 3600;
|
|
}
|
|
|
|
break;
|
|
|
|
case ItemType.Food:
|
|
item.Hp = Convert.ToInt16(currentLine[2]);
|
|
item.Mp = Convert.ToInt16(currentLine[4]);
|
|
break;
|
|
|
|
case ItemType.Jewelry:
|
|
switch (item.EquipmentSlot)
|
|
{
|
|
case EquipmentType.Amulet:
|
|
item.LevelMinimum = Convert.ToByte(currentLine[2]);
|
|
item.ItemLeftType = Convert.ToInt16(currentLine[4]);
|
|
if (item.ItemLeftType == 100)
|
|
{
|
|
item.LeftUsages = Convert.ToInt32(currentLine[3]);
|
|
}
|
|
else if (item.ItemLeftType >= 1000)
|
|
{
|
|
item.ItemValidTime = Convert.ToInt64(currentLine[13]) * 3600;
|
|
}
|
|
else
|
|
{
|
|
item.ItemValidTime = Convert.ToInt64(currentLine[3]) == 0 ? -1 : Convert.ToInt64(currentLine[3]) / 10;
|
|
}
|
|
|
|
break;
|
|
case EquipmentType.Fairy:
|
|
item.Element = Convert.ToByte(currentLine[2]);
|
|
item.ElementRate = Convert.ToInt16(currentLine[3]);
|
|
if (item.Id <= 256)
|
|
{
|
|
item.MaxElementRate = 50;
|
|
}
|
|
else if (item.ElementRate == 0)
|
|
{
|
|
if (item.Id >= 800 && item.Id <= 804)
|
|
{
|
|
item.MaxElementRate = 50;
|
|
}
|
|
else
|
|
{
|
|
item.MaxElementRate = 70;
|
|
}
|
|
}
|
|
else if (item.ElementRate == 30)
|
|
{
|
|
item.MaxElementRate = 30;
|
|
}
|
|
else if (item.ElementRate == 35)
|
|
{
|
|
item.MaxElementRate = 35;
|
|
}
|
|
else if (item.ElementRate == 40)
|
|
{
|
|
item.MaxElementRate = 70;
|
|
}
|
|
else if (item.ElementRate == 50)
|
|
{
|
|
item.MaxElementRate = 80;
|
|
}
|
|
|
|
break;
|
|
default:
|
|
item.LevelMinimum = Convert.ToByte(currentLine[2]);
|
|
item.MaxCellonLvl = Convert.ToByte(currentLine[3]);
|
|
item.MaxCellon = Convert.ToByte(currentLine[4]);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case ItemType.Event:
|
|
item.Effect = Convert.ToInt16(currentLine[2]);
|
|
item.EffectValue = Convert.ToInt16(currentLine[3]);
|
|
break;
|
|
|
|
case ItemType.Special:
|
|
switch (item.Id)
|
|
{
|
|
case 5853:
|
|
item.Effect = 1717;
|
|
item.EffectValue = 1;
|
|
break;
|
|
case 5854:
|
|
item.Effect = 1717;
|
|
item.EffectValue = 2;
|
|
break;
|
|
case 5855:
|
|
item.Effect = 1717;
|
|
item.EffectValue = 3;
|
|
break;
|
|
case 1272:
|
|
case 1858:
|
|
case 9047:
|
|
item.Effect = 1005;
|
|
item.EffectValue = 10;
|
|
break;
|
|
|
|
case 1273:
|
|
case 9024:
|
|
item.Effect = 1005;
|
|
item.EffectValue = 30;
|
|
break;
|
|
|
|
case 1274:
|
|
case 9025:
|
|
item.Effect = 1005;
|
|
item.EffectValue = 60;
|
|
break;
|
|
|
|
case 1279:
|
|
case 9029:
|
|
item.Effect = 1007;
|
|
item.EffectValue = 30;
|
|
break;
|
|
|
|
case 1280:
|
|
case 9030:
|
|
item.Effect = 1007;
|
|
item.EffectValue = 60;
|
|
break;
|
|
|
|
case 1923:
|
|
case 9056:
|
|
item.Effect = 1007;
|
|
item.EffectValue = 10;
|
|
break;
|
|
|
|
case 1275:
|
|
case 1886:
|
|
case 9026:
|
|
item.Effect = 1008;
|
|
item.EffectValue = 10;
|
|
break;
|
|
|
|
case 1276:
|
|
case 9027:
|
|
item.Effect = 1008;
|
|
item.EffectValue = 30;
|
|
break;
|
|
|
|
case 1277:
|
|
case 9028:
|
|
item.Effect = 1008;
|
|
item.EffectValue = 60;
|
|
break;
|
|
|
|
case 5060:
|
|
case 9066:
|
|
item.Effect = 1003;
|
|
item.EffectValue = 30;
|
|
break;
|
|
|
|
case 5061:
|
|
case 9067:
|
|
item.Effect = 1004;
|
|
item.EffectValue = 7;
|
|
break;
|
|
|
|
case 5062:
|
|
case 9068:
|
|
item.Effect = 1004;
|
|
item.EffectValue = 1;
|
|
break;
|
|
case 5115:
|
|
item.Effect = 652;
|
|
break;
|
|
|
|
case 1981:
|
|
item.Effect = 34; // imagined number as for I = √(-1), complex z = a + bi
|
|
break;
|
|
|
|
case 1982:
|
|
item.Effect = 6969; // imagined number as for I = √(-1), complex z = a + bi
|
|
break;
|
|
|
|
case 9071:
|
|
case 5119: // Speed booster
|
|
item.Effect = 998;
|
|
break;
|
|
|
|
case 180: // attack amulet
|
|
item.Effect = 932;
|
|
break;
|
|
|
|
case 181: // defense amulet
|
|
item.Effect = 933;
|
|
break;
|
|
|
|
default:
|
|
if (item.Id > 5891 && item.Id < 5900 || item.Id > 9100 && item.Id < 9109)
|
|
{
|
|
item.Effect = 69; // imagined number as for I = √(-1), complex z = a + bi
|
|
}
|
|
else
|
|
{
|
|
item.Effect = Convert.ToInt16(currentLine[2]);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
switch (item.Effect)
|
|
{
|
|
case 305:
|
|
item.EffectValue = Convert.ToInt32(currentLine[5]);
|
|
item.Morph = Convert.ToInt16(currentLine[4]);
|
|
break;
|
|
|
|
default:
|
|
item.EffectValue = item.EffectValue == 0 ? Convert.ToInt32(currentLine[4]) : item.EffectValue;
|
|
break;
|
|
}
|
|
|
|
item.WaitDelay = 5000;
|
|
break;
|
|
|
|
case ItemType.Magical:
|
|
item.Effect = Convert.ToInt16(currentLine[2]);
|
|
|
|
if (item.Effect == 99)
|
|
{
|
|
item.LevelMinimum = Convert.ToByte(currentLine[4]);
|
|
item.EffectValue = Convert.ToByte(currentLine[5]);
|
|
}
|
|
else
|
|
{
|
|
item.EffectValue = Convert.ToInt32(currentLine[4]);
|
|
}
|
|
|
|
break;
|
|
|
|
case ItemType.Specialist:
|
|
item.IsPartnerSpecialist = item.ItemSubType == 4;
|
|
item.Speed = Convert.ToByte(currentLine[5]);
|
|
if (item.IsPartnerSpecialist)
|
|
{
|
|
item.Element = Convert.ToByte(currentLine[3]);
|
|
item.ElementRate = Convert.ToInt16(currentLine[4]);
|
|
item.PartnerClass = Convert.ToByte(currentLine[19]);
|
|
item.LevelMinimum = Convert.ToByte(currentLine[20]);
|
|
}
|
|
else
|
|
{
|
|
item.LevelJobMinimum = Convert.ToByte(currentLine[20]);
|
|
item.ReputationMinimum = Convert.ToByte(currentLine[21]);
|
|
}
|
|
|
|
item.SpPointsUsage = Convert.ToByte(currentLine[13]);
|
|
item.SpMorphId = item.IsPartnerSpecialist ? (byte)(1 + Convert.ToByte(currentLine[14])) : Convert.ToByte(currentLine[14]);
|
|
item.FireResistance = Convert.ToByte(currentLine[15]);
|
|
item.WaterResistance = Convert.ToByte(currentLine[16]);
|
|
item.LightResistance = Convert.ToByte(currentLine[17]);
|
|
item.DarkResistance = Convert.ToByte(currentLine[18]);
|
|
|
|
var elementdic = new Dictionary<int, int> { { 0, 0 } };
|
|
if (item.FireResistance != 0)
|
|
{
|
|
elementdic.Add(1, item.FireResistance);
|
|
}
|
|
|
|
if (item.WaterResistance != 0)
|
|
{
|
|
elementdic.Add(2, item.WaterResistance);
|
|
}
|
|
|
|
if (item.LightResistance != 0)
|
|
{
|
|
elementdic.Add(3, item.LightResistance);
|
|
}
|
|
|
|
if (item.DarkResistance != 0)
|
|
{
|
|
elementdic.Add(4, item.DarkResistance);
|
|
}
|
|
|
|
if (!item.IsPartnerSpecialist)
|
|
{
|
|
item.Element = (byte)elementdic.OrderByDescending(s => s.Value).First().Key;
|
|
}
|
|
|
|
// needs to be hardcoded
|
|
switch (item.Id)
|
|
{
|
|
case 901:
|
|
item.Element = 1;
|
|
break;
|
|
|
|
case 903:
|
|
item.Element = 2;
|
|
break;
|
|
|
|
case 906:
|
|
item.Element = 3;
|
|
break;
|
|
|
|
case 909:
|
|
item.Element = 3;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case ItemType.Shell:
|
|
byte shellType = Convert.ToByte(currentLine[5]);
|
|
|
|
item.ShellMinimumLevel = Convert.ToInt16(currentLine[3]);
|
|
item.ShellMaximumLevel = Convert.ToInt16(currentLine[4]);
|
|
item.ShellType = (ShellType)(item.ItemSubType == 1 ? shellType + 50 : shellType);
|
|
break;
|
|
|
|
case ItemType.Main:
|
|
item.Effect = Convert.ToInt16(currentLine[2]);
|
|
item.EffectValue = Convert.ToInt32(currentLine[4]);
|
|
break;
|
|
|
|
case ItemType.Upgrade:
|
|
item.Effect = Convert.ToInt16(currentLine[2]);
|
|
switch (item.Id)
|
|
{
|
|
// UpgradeItems (needed to be hardcoded)
|
|
case (int)ItemVnums.EQ_NORMAL_SCROLL:
|
|
item.EffectValue = 26;
|
|
break;
|
|
|
|
case (int)ItemVnums.LOWER_SP_SCROLL:
|
|
item.EffectValue = 27;
|
|
break;
|
|
|
|
case (int)ItemVnums.HIGHER_SP_SCROLL:
|
|
item.EffectValue = 28;
|
|
break;
|
|
|
|
case (int)ItemVnums.SCROLL_CHICKEN:
|
|
item.EffectValue = 47;
|
|
break;
|
|
|
|
case (int)ItemVnums.SCROLL_PYJAMA:
|
|
item.EffectValue = 50;
|
|
break;
|
|
|
|
case (int)ItemVnums.EQ_GOLD_SCROLL:
|
|
item.EffectValue = 61;
|
|
break;
|
|
|
|
case (int)ItemVnums.SCROLL_PIRATE:
|
|
item.EffectValue = 60;
|
|
break;
|
|
|
|
default:
|
|
item.EffectValue = Convert.ToInt32(currentLine[4]);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case ItemType.Production:
|
|
item.Effect = Convert.ToInt16(currentLine[2]);
|
|
item.EffectValue = Convert.ToInt32(currentLine[4]);
|
|
break;
|
|
|
|
case ItemType.Map:
|
|
item.Effect = Convert.ToInt16(currentLine[2]);
|
|
item.EffectValue = Convert.ToInt32(currentLine[4]);
|
|
break;
|
|
|
|
case ItemType.Potion:
|
|
item.Hp = Convert.ToInt16(currentLine[2]);
|
|
item.Mp = Convert.ToInt16(currentLine[4]);
|
|
break;
|
|
|
|
case ItemType.Snack:
|
|
item.Hp = Convert.ToInt16(currentLine[2]);
|
|
item.Mp = Convert.ToInt16(currentLine[4]);
|
|
break;
|
|
|
|
case ItemType.PetPartnerItem:
|
|
item.Effect = Convert.ToInt16(currentLine[2]);
|
|
item.EffectValue = Convert.ToInt32(currentLine[4]);
|
|
break;
|
|
|
|
case ItemType.Material:
|
|
case ItemType.Sell:
|
|
case ItemType.Quest2:
|
|
case ItemType.Quest1:
|
|
case ItemType.Ammo:
|
|
// nothing to parse
|
|
break;
|
|
}
|
|
|
|
if (item.Type == InventoryType.Miniland)
|
|
{
|
|
item.MinilandObjectPoint = int.Parse(currentLine[2]);
|
|
item.EffectValue = short.Parse(currentLine[8]);
|
|
item.Width = Convert.ToByte(currentLine[9]) == 0 ? (byte)1 : Convert.ToByte(currentLine[9]);
|
|
item.Height = Convert.ToByte(currentLine[10]) == 0 ? (byte)1 : Convert.ToByte(currentLine[10]);
|
|
}
|
|
|
|
if (item.EquipmentSlot != EquipmentType.Boots && item.EquipmentSlot != EquipmentType.Gloves || item.Type != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
item.FireResistance = Convert.ToByte(currentLine[7]);
|
|
item.WaterResistance = Convert.ToByte(currentLine[8]);
|
|
item.LightResistance = Convert.ToByte(currentLine[9]);
|
|
item.DarkResistance = Convert.ToByte(currentLine[11]);
|
|
}
|
|
|
|
private void TryHydrateItemDatFromDatabase(string filePath)
|
|
{
|
|
try
|
|
{
|
|
string host = Environment.GetEnvironmentVariable("DATABASE_IP")
|
|
?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_IP")
|
|
?? "127.0.0.1";
|
|
string port = Environment.GetEnvironmentVariable("DATABASE_PORT")
|
|
?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_PORT")
|
|
?? "5432";
|
|
string db = Environment.GetEnvironmentVariable("DATABASE_NAME")
|
|
?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_NAME")
|
|
?? "game";
|
|
string user = Environment.GetEnvironmentVariable("DATABASE_USER")
|
|
?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_USER")
|
|
?? "postgres";
|
|
string pass = Environment.GetEnvironmentVariable("DATABASE_PASSWORD")
|
|
?? Environment.GetEnvironmentVariable("POSTGRES_DATABASE_PASSWORD")
|
|
?? "postgres";
|
|
|
|
using var conn = new NpgsqlConnection($"Host={host};Port={port};Database={db};Username={user};Password={pass}");
|
|
conn.Open();
|
|
using var cmd = new NpgsqlCommand("SELECT content FROM resource_files WHERE category='dat' AND (relative_path='dat/Item.dat' OR relative_path='Item.dat') LIMIT 1;", conn);
|
|
object result = cmd.ExecuteScalar();
|
|
if (result is byte[] bytes && bytes.Length > 0)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(filePath) ?? _configuration.GameDataPath);
|
|
File.WriteAllBytes(filePath, bytes);
|
|
Log.Info("[DB_FIRST] Hydrated Item.dat from resource_files");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error("[DB_FIRST] Could not hydrate Item.dat from database", ex);
|
|
}
|
|
}
|
|
|
|
private static void FillMorphAndIndexValues(string[] currentLine, ItemDTO item)
|
|
{
|
|
switch (Convert.ToByte(currentLine[2]))
|
|
{
|
|
case 4:
|
|
item.Type = InventoryType.Equipment;
|
|
break;
|
|
|
|
case 8:
|
|
item.Type = InventoryType.Equipment;
|
|
break;
|
|
|
|
case 9:
|
|
item.Type = InventoryType.Main;
|
|
break;
|
|
|
|
case 10:
|
|
item.Type = InventoryType.Etc;
|
|
break;
|
|
|
|
default:
|
|
item.Type = (InventoryType)Enum.Parse(typeof(InventoryType), currentLine[2]);
|
|
break;
|
|
}
|
|
|
|
item.ItemType = currentLine[3] != "-1" ? (ItemType)Enum.Parse(typeof(ItemType), $"{(short)item.Type}{currentLine[3]}") : ItemType.Weapon;
|
|
item.ItemSubType = Convert.ToByte(currentLine[4]);
|
|
item.EquipmentSlot = (EquipmentType)Enum.Parse(typeof(EquipmentType), currentLine[5] != "-1" ? currentLine[5] : "0");
|
|
|
|
item.IconId = Convert.ToInt32(currentLine[6]);
|
|
switch (item.Id)
|
|
{
|
|
case 4101:
|
|
case 4102:
|
|
case 4103:
|
|
case 4104:
|
|
case 4105:
|
|
item.EquipmentSlot = 0;
|
|
break;
|
|
|
|
default:
|
|
if (item.EquipmentSlot.Equals(EquipmentType.Amulet))
|
|
{
|
|
switch (item.Id)
|
|
{
|
|
case 4503:
|
|
item.EffectValue = 4544;
|
|
break;
|
|
|
|
case 4504:
|
|
item.EffectValue = 4294;
|
|
break;
|
|
|
|
default:
|
|
item.EffectValue = Convert.ToInt16(currentLine[7]);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
item.Morph = Convert.ToInt16(currentLine[7]);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} |