From d117d8141dbf334ed123ce9d33531ac7d4b30c29 Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 10 Aug 2023 14:43:35 +0900 Subject: [PATCH 01/20] Introduce exp field in Equipment model --- Lib9c/Model/Item/Equipment.cs | 23 +++++++++++++++++++++-- Lib9c/SerializeKeys.cs | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Lib9c/Model/Item/Equipment.cs b/Lib9c/Model/Item/Equipment.cs index 9bca8623a5..1818e4ea16 100644 --- a/Lib9c/Model/Item/Equipment.cs +++ b/Lib9c/Model/Item/Equipment.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Numerics; using System.Runtime.Serialization; using Bencodex.Types; using Libplanet.Action; -using Nekoyume.Action; using Nekoyume.Extensions; using Nekoyume.Model.Stat; using Nekoyume.Model.State; @@ -19,6 +19,7 @@ public class Equipment : ItemUsable, IEquippableItem // FIXME: Whether the equipment is equipped or not has no asset value and must be removed from the state. public bool equipped; public int level; + public BigInteger exp; public int optionCountFromCombination; public DecimalStat Stat { get; } @@ -62,6 +63,18 @@ public Equipment(Dictionary serialized) : base(serialized) } } + if (serialized.TryGetValue((Text)EquipmentExpKey, out value)) + { + try + { + exp = value.ToBigInteger(); + } + catch (InvalidCastException) + { + exp = ((Integer)value).Value; + } + } + if (serialized.TryGetValue((Text) LegacyStatKey, out value)) { Stat = value.ToDecimalStat(); @@ -113,6 +126,11 @@ public override IValue Serialize() dict = dict.SetItem(MadeWithMimisbrunnrRecipeKey, MadeWithMimisbrunnrRecipe.Serialize()); } + if (exp > 0) + { + dict = dict.SetItem(EquipmentExpKey, exp.Serialize()); + } + return dict; #pragma warning restore LAA1002 } @@ -253,7 +271,8 @@ private void UpdateOptionsV2(IRandom random, EnhancementCostSheetV2.Row row, boo protected bool Equals(Equipment other) { return base.Equals(other) && equipped == other.equipped && level == other.level && - Equals(Stat, other.Stat) && SetId == other.SetId && SpineResourcePath == other.SpineResourcePath; + exp == other.exp && Equals(Stat, other.Stat) && SetId == other.SetId && + SpineResourcePath == other.SpineResourcePath; } public override bool Equals(object obj) diff --git a/Lib9c/SerializeKeys.cs b/Lib9c/SerializeKeys.cs index bcb208d19b..f6dd67e6a8 100644 --- a/Lib9c/SerializeKeys.cs +++ b/Lib9c/SerializeKeys.cs @@ -44,6 +44,7 @@ public static class SerializeKeys public const string OptionCountFromCombinationKey = "oc"; public const string RequiredCharacterLevelKey = "rc"; public const string MadeWithMimisbrunnrRecipeKey = "mwmr"; + public const string EquipmentExpKey = "e"; // Stat public const string StatTypeKey = "stt"; From 6a8d658bdb5ca56f5a9da4d5f468c7ff2fc5c36b Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 10 Aug 2023 14:44:04 +0900 Subject: [PATCH 02/20] Update test to validate exp value --- .Lib9c.Tests/Model/Item/EquipmentTest.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.Lib9c.Tests/Model/Item/EquipmentTest.cs b/.Lib9c.Tests/Model/Item/EquipmentTest.cs index 3567ddc766..4816451b2f 100644 --- a/.Lib9c.Tests/Model/Item/EquipmentTest.cs +++ b/.Lib9c.Tests/Model/Item/EquipmentTest.cs @@ -2,9 +2,11 @@ namespace Lib9c.Tests.Model.Item { using System; using System.Collections.Generic; + using System.Numerics; using Nekoyume.Model.Item; using Nekoyume.TableData; using Xunit; + using static SerializeKeys; public class EquipmentTest { @@ -27,16 +29,24 @@ public static Equipment CreateFirstEquipment( return new Equipment(row, guid == default ? Guid.NewGuid() : guid, requiredBlockIndex); } - [Fact] - public void Serialize() + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(14176747520000)] // Max exp. of equipment + public void Serialize(BigInteger exp) { Assert.NotNull(_equipmentRow); var costume = new Equipment(_equipmentRow, Guid.NewGuid(), 0); + costume.exp = exp; var serialized = costume.Serialize(); var deserialized = new Equipment((Bencodex.Types.Dictionary)serialized); var reSerialized = deserialized.Serialize(); + Assert.Equal( + exp != 0, + ((Bencodex.Types.Dictionary)serialized).ContainsKey(EquipmentExpKey) + ); Assert.Equal(costume, deserialized); Assert.Equal(serialized, reSerialized); } From 5eed2539a226374e717134c920e8c46d46c82689 Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 11 Aug 2023 11:41:16 +0900 Subject: [PATCH 03/20] Change EquipmentExpKey to avoid duplication --- Lib9c/SerializeKeys.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib9c/SerializeKeys.cs b/Lib9c/SerializeKeys.cs index f6dd67e6a8..f1e5daebab 100644 --- a/Lib9c/SerializeKeys.cs +++ b/Lib9c/SerializeKeys.cs @@ -44,7 +44,7 @@ public static class SerializeKeys public const string OptionCountFromCombinationKey = "oc"; public const string RequiredCharacterLevelKey = "rc"; public const string MadeWithMimisbrunnrRecipeKey = "mwmr"; - public const string EquipmentExpKey = "e"; + public const string EquipmentExpKey = "eq_exp"; // Stat public const string StatTypeKey = "stt"; From fcc31971e1cc4ae6a4279e638575d3028ab3d84a Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 11 Aug 2023 15:42:45 +0900 Subject: [PATCH 04/20] Change exp data type to long to avoid build error at BigInteger field --- .Lib9c.Tests/Model/Item/EquipmentTest.cs | 2 +- Lib9c/Model/Item/Equipment.cs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.Lib9c.Tests/Model/Item/EquipmentTest.cs b/.Lib9c.Tests/Model/Item/EquipmentTest.cs index 4816451b2f..6174c90751 100644 --- a/.Lib9c.Tests/Model/Item/EquipmentTest.cs +++ b/.Lib9c.Tests/Model/Item/EquipmentTest.cs @@ -33,7 +33,7 @@ public static Equipment CreateFirstEquipment( [InlineData(0)] [InlineData(1)] [InlineData(14176747520000)] // Max exp. of equipment - public void Serialize(BigInteger exp) + public void Serialize(long exp) { Assert.NotNull(_equipmentRow); diff --git a/Lib9c/Model/Item/Equipment.cs b/Lib9c/Model/Item/Equipment.cs index 1818e4ea16..74a59441c3 100644 --- a/Lib9c/Model/Item/Equipment.cs +++ b/Lib9c/Model/Item/Equipment.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Numerics; using System.Runtime.Serialization; using Bencodex.Types; using Libplanet.Action; @@ -19,7 +18,7 @@ public class Equipment : ItemUsable, IEquippableItem // FIXME: Whether the equipment is equipped or not has no asset value and must be removed from the state. public bool equipped; public int level; - public BigInteger exp; + public long exp; public int optionCountFromCombination; public DecimalStat Stat { get; } @@ -67,11 +66,11 @@ public Equipment(Dictionary serialized) : base(serialized) { try { - exp = value.ToBigInteger(); + exp = value.ToLong(); } catch (InvalidCastException) { - exp = ((Integer)value).Value; + exp = (long)((Integer)value).Value; } } From bfb3356beac19aee3857c5b7423ccd82ee90aa21 Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 17 Aug 2023 15:07:00 +0900 Subject: [PATCH 05/20] Backup old version --- .Lib9c.Tests/Action/ItemEnhancement11Test.cs | 234 ++++++++++ Lib9c/Action/ItemEnhancement11.cs | 436 +++++++++++++++++++ 2 files changed, 670 insertions(+) create mode 100644 .Lib9c.Tests/Action/ItemEnhancement11Test.cs create mode 100644 Lib9c/Action/ItemEnhancement11.cs diff --git a/.Lib9c.Tests/Action/ItemEnhancement11Test.cs b/.Lib9c.Tests/Action/ItemEnhancement11Test.cs new file mode 100644 index 0000000000..45fdcdb953 --- /dev/null +++ b/.Lib9c.Tests/Action/ItemEnhancement11Test.cs @@ -0,0 +1,234 @@ +namespace Lib9c.Tests.Action +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using Bencodex.Types; + using Libplanet.Action; + using Libplanet.Action.State; + using Libplanet.Crypto; + using Libplanet.Types.Assets; + using Nekoyume; + using Nekoyume.Action; + using Nekoyume.Extensions; + using Nekoyume.Helper; + using Nekoyume.Model.Item; + using Nekoyume.Model.Mail; + using Nekoyume.Model.State; + using Xunit; + using static Lib9c.SerializeKeys; + + public class ItemEnhancement11Test + { + private readonly TableSheets _tableSheets; + private readonly Address _agentAddress; + private readonly Address _avatarAddress; + private readonly AvatarState _avatarState; + private readonly Currency _currency; + private IAccountStateDelta _initialState; + + public ItemEnhancement11Test() + { + var sheets = TableSheetsImporter.ImportSheets(); + _tableSheets = new TableSheets(sheets); + var privateKey = new PrivateKey(); + _agentAddress = privateKey.PublicKey.ToAddress(); + var agentState = new AgentState(_agentAddress); + + _avatarAddress = _agentAddress.Derive("avatar"); + _avatarState = new AvatarState( + _avatarAddress, + _agentAddress, + 0, + _tableSheets.GetAvatarSheets(), + new GameConfigState(), + default + ); + + agentState.avatarAddresses.Add(0, _avatarAddress); + +#pragma warning disable CS0618 + // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 + _currency = Currency.Legacy("NCG", 2, null); +#pragma warning restore CS0618 + var gold = new GoldCurrencyState(_currency); + var slotAddress = _avatarAddress.Derive(string.Format(CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, 0)); + + var context = new ActionContext(); + _initialState = new MockStateDelta() + .SetState(_agentAddress, agentState.Serialize()) + .SetState(_avatarAddress, _avatarState.Serialize()) + .SetState(slotAddress, new CombinationSlotState(slotAddress, 0).Serialize()) + .SetState(GoldCurrencyState.Address, gold.Serialize()) + .MintAsset(context, GoldCurrencyState.Address, gold.Currency * 100000000000) + .TransferAsset(context, Addresses.GoldCurrency, _agentAddress, gold.Currency * 1000); + + Assert.Equal(gold.Currency * 99999999000, _initialState.GetBalance(Addresses.GoldCurrency, gold.Currency)); + Assert.Equal(gold.Currency * 1000, _initialState.GetBalance(_agentAddress, gold.Currency)); + + foreach (var (key, value) in sheets) + { + _initialState = _initialState.SetState(Addresses.TableSheet.Derive(key), value.Serialize()); + } + } + + [Theory] + [InlineData(0, 1000, true, 0, 1, ItemEnhancement.EnhancementResult.Success, 0, 0, false)] + [InlineData(6, 980, true, 0, 7, ItemEnhancement.EnhancementResult.Success, 0, 0, false)] + [InlineData(0, 1000, false, 1, 1, ItemEnhancement.EnhancementResult.GreatSuccess, 0, 0, false)] + [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 0, 320, false)] + [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 2, 480, false)] + [InlineData(0, 1000, true, 0, 1, ItemEnhancement.EnhancementResult.Success, 0, 0, true)] + [InlineData(6, 980, true, 0, 7, ItemEnhancement.EnhancementResult.Success, 0, 0, true)] + [InlineData(0, 1000, false, 1, 1, ItemEnhancement.EnhancementResult.GreatSuccess, 0, 0, true)] + [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 0, 320, true)] + [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 2, 480, true)] + public void Execute( + int level, + int expectedGold, + bool backward, + int randomSeed, + int expectedLevel, + ItemEnhancement.EnhancementResult expected, + int monsterCollectLevel, + int expectedCrystal, + bool stake + ) + { + var context = new ActionContext(); + var row = _tableSheets.EquipmentItemSheet.Values.First(r => r.Grade == 1); + var equipment = (Equipment)ItemFactory.CreateItemUsable(row, default, 0, level); + var materialId = Guid.NewGuid(); + var material = (Equipment)ItemFactory.CreateItemUsable(row, materialId, 0, level); + + _avatarState.inventory.AddItem(equipment, count: 1); + _avatarState.inventory.AddItem(material, count: 1); + + var result = new CombinationConsumable5.ResultModel() + { + id = default, + gold = 0, + actionPoint = 0, + recipeId = 1, + materials = new Dictionary(), + itemUsable = equipment, + }; + var preItemUsable = new Equipment((Dictionary)equipment.Serialize()); + + for (var i = 0; i < 100; i++) + { + var mail = new CombinationMail(result, i, default, 0); + _avatarState.Update(mail); + } + + _avatarState.worldInformation.ClearStage(1, 1, 1, _tableSheets.WorldSheet, _tableSheets.WorldUnlockSheet); + + var slotAddress = + _avatarAddress.Derive(string.Format(CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, 0)); + + Assert.Equal(level, equipment.level); + + if (backward) + { + _initialState = _initialState.SetState(_avatarAddress, _avatarState.Serialize()); + } + else + { + _initialState = _initialState + .SetState(_avatarAddress.Derive(LegacyInventoryKey), _avatarState.inventory.Serialize()) + .SetState(_avatarAddress.Derive(LegacyWorldInformationKey), _avatarState.worldInformation.Serialize()) + .SetState(_avatarAddress.Derive(LegacyQuestListKey), _avatarState.questList.Serialize()) + .SetState(_avatarAddress, _avatarState.SerializeV2()); + } + + if (monsterCollectLevel > 0) + { + var requiredGold = _tableSheets.StakeRegularRewardSheet.OrderedRows + .First(r => r.Level == monsterCollectLevel).RequiredGold; + if (stake) + { + // StakeState; + var stakeStateAddress = StakeState.DeriveAddress(_agentAddress); + var stakeState = new StakeState(stakeStateAddress, 1); + _initialState = _initialState + .SetState(stakeStateAddress, stakeState.SerializeV2()) + .MintAsset(context, stakeStateAddress, requiredGold * _currency); + } + else + { + var mcAddress = MonsterCollectionState.DeriveAddress(_agentAddress, 0); + _initialState = _initialState.SetState( + mcAddress, + new MonsterCollectionState(mcAddress, monsterCollectLevel, 0).Serialize() + ) + .MintAsset(context, mcAddress, requiredGold * _currency); + } + } + + var action = new ItemEnhancement11() + { + itemId = default, + materialId = materialId, + avatarAddress = _avatarAddress, + slotIndex = 0, + }; + + var nextState = action.Execute(new ActionContext() + { + PreviousState = _initialState, + Signer = _agentAddress, + BlockIndex = 1, + Random = new TestRandom(randomSeed), + }); + + var slotState = nextState.GetCombinationSlotState(_avatarAddress, 0); + var resultEquipment = (Equipment)slotState.Result.itemUsable; + var nextAvatarState = nextState.GetAvatarState(_avatarAddress); + Assert.Equal(default, resultEquipment.ItemId); + Assert.Equal(expectedLevel, resultEquipment.level); + Assert.Equal(expectedGold * _currency, nextState.GetBalance(_agentAddress, _currency)); + + var arenaSheet = _tableSheets.ArenaSheet; + var arenaData = arenaSheet.GetRoundByBlockIndex(1); + var feeStoreAddress = Addresses.GetBlacksmithFeeAddress(arenaData.ChampionshipId, arenaData.Round); + Assert.Equal( + (1000 - expectedGold) * _currency, + nextState.GetBalance(feeStoreAddress, _currency) + ); + Assert.Equal(30, nextAvatarState.mailBox.Count); + + var costRow = _tableSheets.EnhancementCostSheetV2 + .OrderedList + .First(x => x.Grade == 1 && x.Level == level + 1); + var stateDict = (Dictionary)nextState.GetState(slotAddress); + var slot = new CombinationSlotState(stateDict); + var slotResult = (ItemEnhancement.ResultModel)slot.Result; + Assert.Equal(expected, slotResult.enhancementResult); + + switch (slotResult.enhancementResult) + { + case ItemEnhancement.EnhancementResult.GreatSuccess: + var baseAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); + var extraAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + 1); + Assert.Equal((int)(baseAtk + extraAtk), resultEquipment.StatsMap.ATK); + break; + case ItemEnhancement.EnhancementResult.Success: + var baseMinAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMin.NormalizeFromTenThousandths() + 1); + var baseMaxAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); + var extraMinAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMin.NormalizeFromTenThousandths() + 1); + var extraMaxAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + 1); + Assert.InRange(resultEquipment.StatsMap.ATK, baseMinAtk + extraMinAtk, baseMaxAtk + extraMaxAtk + 1); + break; + case ItemEnhancement.EnhancementResult.Fail: + Assert.Equal(preItemUsable.StatsMap.ATK, resultEquipment.StatsMap.ATK); + break; + } + + Assert.Equal(preItemUsable.TradableId, slotResult.preItemUsable.TradableId); + Assert.Equal(preItemUsable.TradableId, resultEquipment.TradableId); + Assert.Equal(costRow.Cost, slotResult.gold); + Assert.Equal(expectedCrystal * CrystalCalculator.CRYSTAL, slotResult.CRYSTAL); + } + } +} diff --git a/Lib9c/Action/ItemEnhancement11.cs b/Lib9c/Action/ItemEnhancement11.cs new file mode 100644 index 0000000000..7a25cfb413 --- /dev/null +++ b/Lib9c/Action/ItemEnhancement11.cs @@ -0,0 +1,436 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Numerics; +using Bencodex.Types; +using Lib9c.Abstractions; +using Libplanet.Action; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Libplanet.Types.Assets; +using Nekoyume.Extensions; +using Nekoyume.Helper; +using Nekoyume.Model.Item; +using Nekoyume.Model.Mail; +using Nekoyume.Model.State; +using Nekoyume.TableData; +using Nekoyume.TableData.Crystal; +using Serilog; + +using static Lib9c.SerializeKeys; + +namespace Nekoyume.Action +{ + /// + /// Updated at https://github.com/planetarium/lib9c/pull/1164 + /// + [Serializable] + [ActionType("item_enhancement11")] + public class ItemEnhancement11 : GameAction, IItemEnhancementV2 + { + public enum EnhancementResult + { + GreatSuccess = 0, + Success = 1, + Fail = 2, + } + + public Guid itemId; + public Guid materialId; + public Address avatarAddress; + public int slotIndex; + + Guid IItemEnhancementV2.ItemId => itemId; + Guid IItemEnhancementV2.MaterialId => materialId; + Address IItemEnhancementV2.AvatarAddress => avatarAddress; + int IItemEnhancementV2.SlotIndex => slotIndex; + + [Serializable] + public class ResultModel : AttachmentActionResult + { + protected override string TypeId => "item_enhancement11.result"; + public Guid id; + public IEnumerable materialItemIdList; + public BigInteger gold; + public int actionPoint; + public EnhancementResult enhancementResult; + public ItemUsable preItemUsable; + public FungibleAssetValue CRYSTAL; + + public ResultModel() + { + } + + public ResultModel(Dictionary serialized) : base(serialized) + { + id = serialized["id"].ToGuid(); + materialItemIdList = serialized["materialItemIdList"].ToList(StateExtensions.ToGuid); + gold = serialized["gold"].ToBigInteger(); + actionPoint = serialized["actionPoint"].ToInteger(); + enhancementResult = serialized["enhancementResult"].ToEnum(); + preItemUsable = serialized.ContainsKey("preItemUsable") + ? (ItemUsable)ItemFactory.Deserialize((Dictionary)serialized["preItemUsable"]) + : null; + CRYSTAL = serialized["c"].ToFungibleAssetValue(); + } + + public override IValue Serialize() => +#pragma warning disable LAA1002 + new Dictionary(new Dictionary + { + [(Text)"id"] = id.Serialize(), + [(Text)"materialItemIdList"] = materialItemIdList + .OrderBy(i => i) + .Select(g => g.Serialize()).Serialize(), + [(Text)"gold"] = gold.Serialize(), + [(Text)"actionPoint"] = actionPoint.Serialize(), + [(Text)"enhancementResult"] = enhancementResult.Serialize(), + [(Text)"preItemUsable"] = preItemUsable.Serialize(), + [(Text)"c"] = CRYSTAL.Serialize(), + }.Union((Dictionary)base.Serialize())); +#pragma warning restore LAA1002 + } + + protected override IImmutableDictionary PlainValueInternal + { + get + { + var dict = new Dictionary + { + ["itemId"] = itemId.Serialize(), + ["materialId"] = materialId.Serialize(), + ["avatarAddress"] = avatarAddress.Serialize(), + ["slotIndex"] = slotIndex.Serialize(), + }; + + return dict.ToImmutableDictionary(); + } + } + + protected override void LoadPlainValueInternal(IImmutableDictionary plainValue) + { + itemId = plainValue["itemId"].ToGuid(); + materialId = plainValue["materialId"].ToGuid(); + avatarAddress = plainValue["avatarAddress"].ToAddress(); + if (plainValue.TryGetValue((Text)"slotIndex", out var value)) + { + slotIndex = value.ToInteger(); + } + } + + public override IAccountStateDelta Execute(IActionContext context) + { + context.UseGas(1); + var ctx = context; + var states = ctx.PreviousState; + var slotAddress = avatarAddress.Derive( + string.Format( + CultureInfo.InvariantCulture, + CombinationSlotState.DeriveFormat, + slotIndex + ) + ); + var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); + var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); + var questListAddress = avatarAddress.Derive(LegacyQuestListKey); + + if (ctx.Rehearsal) + { + return states; + } + + var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); + + var sw = new Stopwatch(); + sw.Start(); + var started = DateTimeOffset.UtcNow; + Log.Debug("{AddressesHex}ItemEnhancement exec started", addressesHex); + if (!states.TryGetAgentAvatarStatesV2(ctx.Signer, avatarAddress, out var agentState, out var avatarState, out _)) + { + throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); + } + + if (!avatarState.inventory.TryGetNonFungibleItem(itemId, out ItemUsable enhancementItem)) + { + throw new ItemDoesNotExistException( + $"{addressesHex}Aborted as the NonFungibleItem ({itemId}) was failed to load from avatar's inventory." + ); + } + + if (enhancementItem.RequiredBlockIndex > context.BlockIndex) + { + throw new RequiredBlockIndexException( + $"{addressesHex}Aborted as the equipment to enhance ({itemId}) is not available yet;" + + $" it will be available at the block #{enhancementItem.RequiredBlockIndex}." + ); + } + + if (!(enhancementItem is Equipment enhancementEquipment)) + { + throw new InvalidCastException( + $"{addressesHex}Aborted as the item is not a {nameof(Equipment)}, but {enhancementItem.GetType().Name}." + + ); + } + + var slotState = states.GetCombinationSlotState(avatarAddress, slotIndex); + if (slotState is null) + { + throw new FailedLoadStateException($"{addressesHex}Aborted as the slot state was failed to load. #{slotIndex}"); + } + + if (!slotState.Validate(avatarState, ctx.BlockIndex)) + { + throw new CombinationSlotUnlockException($"{addressesHex}Aborted as the slot state was failed to invalid. #{slotIndex}"); + } + sw.Stop(); + Log.Verbose("{AddressesHex}ItemEnhancement Get Equipment: {Elapsed}", addressesHex, sw.Elapsed); + + sw.Restart(); + + Dictionary sheets = states.GetSheets(sheetTypes: new[] + { + typeof(EnhancementCostSheetV2), + typeof(MaterialItemSheet), + typeof(CrystalEquipmentGrindingSheet), + typeof(CrystalMonsterCollectionMultiplierSheet), + typeof(StakeRegularRewardSheet) + }); + + var enhancementCostSheet = sheets.GetSheet(); + if (!TryGetRow(enhancementEquipment, enhancementCostSheet, out var row)) + { + throw new SheetRowNotFoundException(addressesHex, nameof(WorldSheet), enhancementEquipment.level); + } + + var maxLevel = GetEquipmentMaxLevel(enhancementEquipment, enhancementCostSheet); + if (enhancementEquipment.level >= maxLevel) + { + throw new EquipmentLevelExceededException( + $"{addressesHex}Aborted due to invalid equipment level: {enhancementEquipment.level} < {maxLevel}"); + } + + if (!avatarState.inventory.TryGetNonFungibleItem(materialId, out ItemUsable materialItem)) + { + throw new NotEnoughMaterialException( + $"{addressesHex}Aborted as the signer does not have a necessary material ({materialId})." + ); + } + + if (materialItem.RequiredBlockIndex > context.BlockIndex) + { + throw new RequiredBlockIndexException( + $"{addressesHex}Aborted as the material ({materialId}) is not available yet;" + + $" it will be available at the block #{materialItem.RequiredBlockIndex}." + ); + } + + if (!(materialItem is Equipment materialEquipment)) + { + throw new InvalidCastException( + $"{addressesHex}Aborted as the material item is not an {nameof(Equipment)}, but {materialItem.GetType().Name}." + ); + } + + if (enhancementEquipment.ItemId == materialId) + { + throw new InvalidMaterialException( + $"{addressesHex}Aborted as an equipment to enhance ({materialId}) was used as a material too." + ); + } + + if (materialEquipment.ItemSubType != enhancementEquipment.ItemSubType) + { + throw new InvalidMaterialException( + $"{addressesHex}Aborted as the material item is not a {enhancementEquipment.ItemSubType}," + + $" but {materialEquipment.ItemSubType}." + ); + } + + if (materialEquipment.Grade != enhancementEquipment.Grade) + { + throw new InvalidMaterialException( + $"{addressesHex}Aborted as grades of the equipment to enhance ({enhancementEquipment.Grade})" + + $" and a material ({materialEquipment.Grade}) does not match." + ); + } + + if (materialEquipment.level != enhancementEquipment.level) + { + throw new InvalidMaterialException( + $"{addressesHex}Aborted as levels of the equipment to enhance ({enhancementEquipment.level})" + + $" and a material ({materialEquipment.level}) does not match." + ); + } + sw.Stop(); + Log.Verbose("{AddressesHex}ItemEnhancement Get Material: {Elapsed}", addressesHex, sw.Elapsed); + + sw.Restart(); + // Subtract required action point + var requiredActionPoint = GetRequiredAp(); + if (avatarState.actionPoint < requiredActionPoint) + { + throw new NotEnoughActionPointException( + $"{addressesHex}Aborted due to insufficient action point: {avatarState.actionPoint} < {requiredActionPoint}" + ); + } + avatarState.actionPoint -= requiredActionPoint; + + // TransferAsset (NCG) + var requiredNcg = row.Cost; + if (requiredNcg > 0) + { + var arenaSheet = states.GetSheet(); + var arenaData = arenaSheet.GetRoundByBlockIndex(context.BlockIndex); + var feeStoreAddress = Addresses.GetBlacksmithFeeAddress(arenaData.ChampionshipId, arenaData.Round); + states = states.TransferAsset(ctx, ctx.Signer, feeStoreAddress, states.GetGoldCurrency() * requiredNcg); + } + + // Unequip items + materialEquipment.Unequip(); + enhancementEquipment.Unequip(); + + // clone items + var preItemUsable = new Equipment((Dictionary)enhancementEquipment.Serialize()); + + // Equipment level up & Update + var equipmentResult = GetEnhancementResult(row, ctx.Random); + FungibleAssetValue crystal = 0 * CrystalCalculator.CRYSTAL; + if (equipmentResult != EnhancementResult.Fail) + { + enhancementEquipment.LevelUp(ctx.Random, row, equipmentResult == EnhancementResult.GreatSuccess); + } + else + { + Address monsterCollectionAddress = MonsterCollectionState.DeriveAddress( + context.Signer, + agentState.MonsterCollectionRound + ); + + Currency currency = states.GetGoldCurrency(); + FungibleAssetValue stakedAmount = 0 * currency; + if (states.TryGetStakeState(context.Signer, out StakeState stakeState)) + { + stakedAmount = states.GetBalance(stakeState.address, currency); + } + else + { + if (states.TryGetState(monsterCollectionAddress, out Dictionary _)) + { + stakedAmount = states.GetBalance(monsterCollectionAddress, currency); + } + } + + crystal = CrystalCalculator.CalculateCrystal( + context.Signer, + new[] { preItemUsable }, + stakedAmount, + true, + sheets.GetSheet(), + sheets.GetSheet(), + sheets.GetSheet() + ); + + if (crystal > 0 * CrystalCalculator.CRYSTAL) + { + states = states.MintAsset(context, context.Signer, crystal); + } + } + + var requiredBlockCount = GetRequiredBlockCount(row, equipmentResult); + var requiredBlockIndex = ctx.BlockIndex + requiredBlockCount; + enhancementEquipment.Update(requiredBlockIndex); + + // Remove material + avatarState.inventory.RemoveNonFungibleItem(materialId); + sw.Stop(); + Log.Verbose("{AddressesHex}ItemEnhancement Upgrade Equipment: {Elapsed}", addressesHex, sw.Elapsed); + + // Send scheduled mail + var result = new ResultModel + { + preItemUsable = preItemUsable, + itemUsable = enhancementEquipment, + materialItemIdList = new[] { materialId }, + actionPoint = requiredActionPoint, + enhancementResult = equipmentResult, + gold = requiredNcg, + CRYSTAL = crystal, + }; + + var mail = new ItemEnhanceMail(result, ctx.BlockIndex, ctx.Random.GenerateRandomGuid(), requiredBlockIndex); + result.id = mail.id; + avatarState.inventory.RemoveNonFungibleItem(enhancementEquipment); + avatarState.Update(mail); + avatarState.UpdateFromItemEnhancement(enhancementEquipment); + + // Update quest reward + var materialSheet = sheets.GetSheet(); + avatarState.UpdateQuestRewards(materialSheet); + + // Update slot state + slotState.Update(result, ctx.BlockIndex, requiredBlockIndex); + + // Set state + sw.Restart(); + states = states + .SetState(inventoryAddress, avatarState.inventory.Serialize()) + .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) + .SetState(questListAddress, avatarState.questList.Serialize()) + .SetState(avatarAddress, avatarState.SerializeV2()); + sw.Stop(); + Log.Verbose("{AddressesHex}ItemEnhancement Set AvatarState: {Elapsed}", addressesHex, sw.Elapsed); + var ended = DateTimeOffset.UtcNow; + Log.Debug("{AddressesHex}ItemEnhancement Total Executed Time: {Elapsed}", addressesHex, ended - started); + return states.SetState(slotAddress, slotState.Serialize()); + } + + public static EnhancementResult GetEnhancementResult(EnhancementCostSheetV2.Row row, IRandom random) + { + var rand = random.Next(1, GameConfig.MaximumProbability + 1); + if (rand <= row.GreatSuccessRatio) + { + return EnhancementResult.GreatSuccess; + } + + return rand <= row.GreatSuccessRatio + row.SuccessRatio ? EnhancementResult.Success : EnhancementResult.Fail; + } + + public static int GetRequiredBlockCount(EnhancementCostSheetV2.Row row, EnhancementResult result) + { + switch (result) + { + case EnhancementResult.GreatSuccess: + return row.GreatSuccessRequiredBlockIndex; + case EnhancementResult.Success: + return row.SuccessRequiredBlockIndex; + case EnhancementResult.Fail: + return row.FailRequiredBlockIndex; + default: + throw new ArgumentOutOfRangeException(nameof(result), result, null); + } + } + + public static bool TryGetRow(Equipment equipment, EnhancementCostSheetV2 sheet, out EnhancementCostSheetV2.Row row) + { + var grade = equipment.Grade; + var level = equipment.level + 1; + var itemSubType = equipment.ItemSubType; + row = sheet.OrderedList.FirstOrDefault(x => x.Grade == grade && x.Level == level && x.ItemSubType == itemSubType); + return row != null; + } + + public static int GetEquipmentMaxLevel(Equipment equipment, EnhancementCostSheetV2 sheet) + { + return sheet.OrderedList.Where(x => x.Grade == equipment.Grade).Max(x => x.Level); + } + + public static int GetRequiredAp() + { + return GameConfig.EnhanceEquipmentCostAP; + } + } +} From 14cb51ebe1def48215e6eb54b17234724148f602 Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 17 Aug 2023 15:07:47 +0900 Subject: [PATCH 06/20] Specify Action version --- .Lib9c.Tests/Action/ItemEnhancement9Test.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.Lib9c.Tests/Action/ItemEnhancement9Test.cs b/.Lib9c.Tests/Action/ItemEnhancement9Test.cs index 33643d5345..0ac80e3154 100644 --- a/.Lib9c.Tests/Action/ItemEnhancement9Test.cs +++ b/.Lib9c.Tests/Action/ItemEnhancement9Test.cs @@ -164,15 +164,15 @@ public void Execute(int level, int expectedGold, bool backward) var slot = new CombinationSlotState(stateDict); var slotResult = (ItemEnhancement9.ResultModel)slot.Result; - switch ((ItemEnhancement.EnhancementResult)slotResult.enhancementResult) + switch ((ItemEnhancement9.EnhancementResult)slotResult.enhancementResult) { - case ItemEnhancement.EnhancementResult.GreatSuccess: + case ItemEnhancement9.EnhancementResult.GreatSuccess: var baseAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); var extraAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + 1); Assert.Equal((int)(baseAtk + extraAtk), resultEquipment.StatsMap.ATK); Assert.Equal(preItemUsable.level + 1, resultEquipment.level); break; - case ItemEnhancement.EnhancementResult.Success: + case ItemEnhancement9.EnhancementResult.Success: var baseMinAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMin.NormalizeFromTenThousandths() + 1); var baseMaxAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); var extraMinAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMin.NormalizeFromTenThousandths() + 1); @@ -180,7 +180,7 @@ public void Execute(int level, int expectedGold, bool backward) Assert.InRange(resultEquipment.StatsMap.ATK, (int)(baseMinAtk + extraMinAtk), (int)(baseMaxAtk + extraMaxAtk) + 1); Assert.Equal(preItemUsable.level + 1, resultEquipment.level); break; - case ItemEnhancement.EnhancementResult.Fail: + case ItemEnhancement9.EnhancementResult.Fail: Assert.Equal(preItemUsable.StatsMap.ATK, resultEquipment.StatsMap.ATK); Assert.Equal(preItemUsable.level, resultEquipment.level); break; From ee662c522c9a6abb7cb1168ee7f5c50358ce0cde Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 17 Aug 2023 15:11:32 +0900 Subject: [PATCH 07/20] Introduce SetLevel function to set to required level at once --- Lib9c/Model/Item/Equipment.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Lib9c/Model/Item/Equipment.cs b/Lib9c/Model/Item/Equipment.cs index 74a59441c3..571993e906 100644 --- a/Lib9c/Model/Item/Equipment.cs +++ b/Lib9c/Model/Item/Equipment.cs @@ -157,6 +157,7 @@ public void LevelUpV1() } } + [Obsolete("Since ItemEnhancement12, Use `SetLevel` instead.")] public void LevelUp(IRandom random, EnhancementCostSheetV2.Row row, bool isGreatSuccess) { level++; @@ -177,6 +178,26 @@ public void LevelUp(IRandom random, EnhancementCostSheetV2.Row row, bool isGreat } } + public void SetLevel(IRandom random, EquipmentItemUpgradePointSheet.Row targetLevelRow, + EnhancementCostSheetV2.Row costRow) + { + level = targetLevelRow.Level; + var rand = random.Next(costRow.BaseStatGrowthMin, costRow.BaseStatGrowthMax + 1); + var ratio = rand.NormalizeFromTenThousandths(); + var baseStat = StatsMap.GetBaseStat(UniqueStatType) * ratio; + if (baseStat > 0) + { + baseStat = Math.Max(1.0m, baseStat); + } + + StatsMap.AddStatValue(UniqueStatType, baseStat); + + if (GetOptionCount() > 0) + { + UpdateOptionsV2(random, costRow, false); + } + } + public List GetOptions() { var options = new List(); From 1a7d6765964ed14e57742060140e6dea7383d594 Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 17 Aug 2023 15:12:45 +0900 Subject: [PATCH 08/20] Introduce IItemEnhancementV4 - This interface gets multilpe ItemIds as enhancement material. - This is used from ItemEnhancement12 action. --- Lib9c.Abstractions/IItemEnhancementV4.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Lib9c.Abstractions/IItemEnhancementV4.cs diff --git a/Lib9c.Abstractions/IItemEnhancementV4.cs b/Lib9c.Abstractions/IItemEnhancementV4.cs new file mode 100644 index 0000000000..5c31ea6a1d --- /dev/null +++ b/Lib9c.Abstractions/IItemEnhancementV4.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using Libplanet.Crypto; + +namespace Lib9c.Abstractions +{ + public interface IItemEnhancementV4 + { + Guid ItemId { get; } + IEnumerable MaterialIds { get; } + Address AvatarAddress { get; } + int SlotIndex { get; } + } +} From 4c691bc2d65d11a8c33c4371b28130e3054cf3c3 Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 17 Aug 2023 15:23:07 +0900 Subject: [PATCH 09/20] Update related actions to apply old action name --- .Lib9c.Tests/Action/RapidCombination6Test.cs | 10 +++++----- ...ombinationTest7.cs => RapidCombination7Test.cs} | 14 +++++++------- .Lib9c.Tests/Action/RapidCombination8Test.cs | 10 +++++----- .Lib9c.Tests/Action/RapidCombinationTest.cs | 8 ++++---- 4 files changed, 21 insertions(+), 21 deletions(-) rename .Lib9c.Tests/Action/{RapidCombinationTest7.cs => RapidCombination7Test.cs} (98%) diff --git a/.Lib9c.Tests/Action/RapidCombination6Test.cs b/.Lib9c.Tests/Action/RapidCombination6Test.cs index 54c19fd085..a1172cb4b7 100644 --- a/.Lib9c.Tests/Action/RapidCombination6Test.cs +++ b/.Lib9c.Tests/Action/RapidCombination6Test.cs @@ -643,16 +643,16 @@ public void Execute_Throw_InvalidOperationException_When_TargetSlotCreatedBy( case 11: { - Assert.True(ItemEnhancement.TryGetRow( + Assert.True(ItemEnhancement11.TryGetRow( equipment, _tableSheets.EnhancementCostSheetV2, out var costRow)); - var equipmentResult = ItemEnhancement.GetEnhancementResult(costRow, random); + var equipmentResult = ItemEnhancement11.GetEnhancementResult(costRow, random); equipment.LevelUp( random, costRow, - equipmentResult == ItemEnhancement.EnhancementResult.GreatSuccess); - resultModel = new ItemEnhancement.ResultModel + equipmentResult == ItemEnhancement11.EnhancementResult.GreatSuccess); + resultModel = new ItemEnhancement11.ResultModel { id = mailId, preItemUsable = preItemUsable, @@ -660,7 +660,7 @@ public void Execute_Throw_InvalidOperationException_When_TargetSlotCreatedBy( materialItemIdList = new[] { materialEquipment.NonFungibleId }, gold = 0, actionPoint = 0, - enhancementResult = ItemEnhancement.EnhancementResult.GreatSuccess, + enhancementResult = ItemEnhancement11.EnhancementResult.GreatSuccess, CRYSTAL = 0 * CrystalCalculator.CRYSTAL, }; diff --git a/.Lib9c.Tests/Action/RapidCombinationTest7.cs b/.Lib9c.Tests/Action/RapidCombination7Test.cs similarity index 98% rename from .Lib9c.Tests/Action/RapidCombinationTest7.cs rename to .Lib9c.Tests/Action/RapidCombination7Test.cs index 917bfd5687..d61a794d22 100644 --- a/.Lib9c.Tests/Action/RapidCombinationTest7.cs +++ b/.Lib9c.Tests/Action/RapidCombination7Test.cs @@ -20,7 +20,7 @@ namespace Lib9c.Tests.Action using Xunit; using static Lib9c.SerializeKeys; - public class RapidCombinationTest7 + public class RapidCombination7Test { private readonly IAccountStateDelta _initialState; @@ -29,7 +29,7 @@ public class RapidCombinationTest7 private readonly Address _agentAddress; private readonly Address _avatarAddress; - public RapidCombinationTest7() + public RapidCombination7Test() { _initialState = new MockStateDelta(); @@ -642,16 +642,16 @@ public void Execute_NotThrow_InvalidOperationException_When_TargetSlotCreatedBy( case 11: { - Assert.True(ItemEnhancement.TryGetRow( + Assert.True(ItemEnhancement11.TryGetRow( equipment, _tableSheets.EnhancementCostSheetV2, out var costRow)); - var equipmentResult = ItemEnhancement.GetEnhancementResult(costRow, random); + var equipmentResult = ItemEnhancement11.GetEnhancementResult(costRow, random); equipment.LevelUp( random, costRow, - equipmentResult == ItemEnhancement.EnhancementResult.GreatSuccess); - resultModel = new ItemEnhancement.ResultModel + equipmentResult == ItemEnhancement11.EnhancementResult.GreatSuccess); + resultModel = new ItemEnhancement11.ResultModel { id = mailId, preItemUsable = preItemUsable, @@ -659,7 +659,7 @@ public void Execute_NotThrow_InvalidOperationException_When_TargetSlotCreatedBy( materialItemIdList = new[] { materialEquipment.NonFungibleId }, gold = 0, actionPoint = 0, - enhancementResult = ItemEnhancement.EnhancementResult.GreatSuccess, + enhancementResult = ItemEnhancement11.EnhancementResult.GreatSuccess, CRYSTAL = 0 * CrystalCalculator.CRYSTAL, }; diff --git a/.Lib9c.Tests/Action/RapidCombination8Test.cs b/.Lib9c.Tests/Action/RapidCombination8Test.cs index 9666c06142..a0fdb3cc41 100644 --- a/.Lib9c.Tests/Action/RapidCombination8Test.cs +++ b/.Lib9c.Tests/Action/RapidCombination8Test.cs @@ -642,16 +642,16 @@ public void Execute_NotThrow_InvalidOperationException_When_TargetSlotCreatedBy( case 11: { - Assert.True(ItemEnhancement.TryGetRow( + Assert.True(ItemEnhancement11.TryGetRow( equipment, _tableSheets.EnhancementCostSheetV2, out var costRow)); - var equipmentResult = ItemEnhancement.GetEnhancementResult(costRow, random); + var equipmentResult = ItemEnhancement11.GetEnhancementResult(costRow, random); equipment.LevelUp( random, costRow, - equipmentResult == ItemEnhancement.EnhancementResult.GreatSuccess); - resultModel = new ItemEnhancement.ResultModel + equipmentResult == ItemEnhancement11.EnhancementResult.GreatSuccess); + resultModel = new ItemEnhancement11.ResultModel { id = mailId, preItemUsable = preItemUsable, @@ -659,7 +659,7 @@ public void Execute_NotThrow_InvalidOperationException_When_TargetSlotCreatedBy( materialItemIdList = new[] { materialEquipment.NonFungibleId }, gold = 0, actionPoint = 0, - enhancementResult = ItemEnhancement.EnhancementResult.GreatSuccess, + enhancementResult = ItemEnhancement11.EnhancementResult.GreatSuccess, CRYSTAL = 0 * CrystalCalculator.CRYSTAL, }; diff --git a/.Lib9c.Tests/Action/RapidCombinationTest.cs b/.Lib9c.Tests/Action/RapidCombinationTest.cs index a04e0ca5eb..2708dbaa9b 100644 --- a/.Lib9c.Tests/Action/RapidCombinationTest.cs +++ b/.Lib9c.Tests/Action/RapidCombinationTest.cs @@ -642,16 +642,16 @@ public void Execute_NotThrow_InvalidOperationException_When_TargetSlotCreatedBy( case 11: { - Assert.True(ItemEnhancement.TryGetRow( + Assert.True(ItemEnhancement11.TryGetRow( equipment, _tableSheets.EnhancementCostSheetV2, out var costRow)); - var equipmentResult = ItemEnhancement.GetEnhancementResult(costRow, random); + var equipmentResult = ItemEnhancement11.GetEnhancementResult(costRow, random); equipment.LevelUp( random, costRow, - equipmentResult == ItemEnhancement.EnhancementResult.GreatSuccess); - resultModel = new ItemEnhancement.ResultModel + equipmentResult == ItemEnhancement11.EnhancementResult.GreatSuccess); + resultModel = new ItemEnhancement11.ResultModel { id = mailId, preItemUsable = preItemUsable, From 308966477ef7156cba9c24d61c874abb3f16330a Mon Sep 17 00:00:00 2001 From: hyeon Date: Thu, 17 Aug 2023 16:19:03 +0900 Subject: [PATCH 10/20] Introduce EquipmentItemUpgradePoint CSV and sheet model - NOTE: Uploaded CSV file is draft version. The contents can be changed. - New model for Equipment upgrade exp point sheet. --- .Lib9c.Tests/TableSheets.cs | 2 + .../Item/EquipmentItemUpgradePoint.csv | 111 ++++++++++++++++++ .../Item/EquipmentItemUpgradePointSheet.cs | 45 +++++++ 3 files changed, 158 insertions(+) create mode 100644 Lib9c/TableCSV/Item/EquipmentItemUpgradePoint.csv create mode 100644 Lib9c/TableData/Item/EquipmentItemUpgradePointSheet.cs diff --git a/.Lib9c.Tests/TableSheets.cs b/.Lib9c.Tests/TableSheets.cs index 96e46ad40e..1c536116aa 100644 --- a/.Lib9c.Tests/TableSheets.cs +++ b/.Lib9c.Tests/TableSheets.cs @@ -129,6 +129,8 @@ public TableSheets(Dictionary sheets) public EnhancementCostSheet EnhancementCostSheet { get; private set; } + public EquipmentItemUpgradePointSheet EquipmentItemUpgradePointSheet { get; private set; } + public EnhancementCostSheetV2 EnhancementCostSheetV2 { get; private set; } public WeeklyArenaRewardSheet WeeklyArenaRewardSheet { get; internal set; } diff --git a/Lib9c/TableCSV/Item/EquipmentItemUpgradePoint.csv b/Lib9c/TableCSV/Item/EquipmentItemUpgradePoint.csv new file mode 100644 index 0000000000..904e4774c3 --- /dev/null +++ b/Lib9c/TableCSV/Item/EquipmentItemUpgradePoint.csv @@ -0,0 +1,111 @@ +ID,item_sub_type,level,Normal,Rare,Epic,Unique,Legend +1000,Weapon,0,10,80,16020,426000,6760000 +1001,Weapon,1,20,160,32040,852000,13520000 +1002,Weapon,2,40,320,64080,1704000,27040000 +1003,Weapon,3,80,640,128160,3408000,54080000 +1004,Weapon,4,160,1280,256320,6816000,108160000 +1005,Weapon,5,320,2560,512640,13632000,216320000 +1006,Weapon,6,640,5120,1025280,27264000,432640000 +1007,Weapon,7,1280,10240,2050560,54528000,865280000 +1008,Weapon,8,2560,20480,4101120,109056000,1730560000 +1009,Weapon,9,5120,40960,8202240,218112000,3461120000 +1010,Weapon,10,10240,81920,16404480,436224000,6922240000 +1011,Weapon,11,20480,163840,32808960,872448000,13844480000 +1012,Weapon,12,40960,327680,65617920,1744896000,27688960000 +1013,Weapon,13,81920,655360,131235840,3489792000,55377920000 +1014,Weapon,14,163840,1310720,262471680,6979584000,110755840000 +1015,Weapon,15,327680,2621440,524943360,13959168000,221511680000 +1016,Weapon,16,655360,5242880,1049886720,27918336000,443023360000 +1017,Weapon,17,1310720,10485760,2099773440,55836672000,886046720000 +1018,Weapon,18,2621440,20971520,4199546880,111673344000,1772093440000 +1019,Weapon,19,5242880,41943040,8399093760,223346688000,3544186880000 +1020,Weapon,20,10485760,83886080,16798187520,446693376000,7088373760000 +1021,Weapon,21,20971520,167772160,33596375040,893386752000,14176747520000 +2000,Armor,0,19,103,9600,426000,6760000 +2001,Armor,1,38,206,19200,852000,13520000 +2002,Armor,2,76,412,38400,1704000,27040000 +2003,Armor,3,152,824,76800,3408000,54080000 +2004,Armor,4,304,1648,153600,6816000,108160000 +2005,Armor,5,608,3296,307200,13632000,216320000 +2006,Armor,6,1216,6592,614400,27264000,432640000 +2007,Armor,7,2432,13184,1228800,54528000,865280000 +2008,Armor,8,4864,26368,2457600,109056000,1730560000 +2009,Armor,9,9728,52736,4915200,218112000,3461120000 +2010,Armor,10,19456,105472,9830400,436224000,6922240000 +2011,Armor,11,38912,210944,19660800,872448000,13844480000 +2012,Armor,12,77824,421888,39321600,1744896000,27688960000 +2013,Armor,13,155648,843776,78643200,3489792000,55377920000 +2014,Armor,14,311296,1687552,157286400,6979584000,110755840000 +2015,Armor,15,622592,3375104,314572800,13959168000,221511680000 +2016,Armor,16,1245184,6750208,629145600,27918336000,443023360000 +2017,Armor,17,2490368,13500416,1258291200,55836672000,886046720000 +2018,Armor,18,4980736,27000832,2516582400,111673344000,1772093440000 +2019,Armor,19,9961472,54001664,5033164800,223346688000,3544186880000 +2020,Armor,20,19922944,108003328,10066329600,446693376000,7088373760000 +2021,Armor,21,39845888,216006656,20132659200,893386752000,14176747520000 +3000,Belt,0,954,1496,3864,96600,6760000 +3001,Belt,1,1908,2992,7728,193200,13520000 +3002,Belt,2,3816,5984,15456,386400,27040000 +3003,Belt,3,7632,11968,30912,772800,54080000 +3004,Belt,4,15264,23936,61824,1545600,108160000 +3005,Belt,5,30528,47872,123648,3091200,216320000 +3006,Belt,6,61056,95744,247296,6182400,432640000 +3007,Belt,7,122112,191488,494592,12364800,865280000 +3008,Belt,8,244224,382976,989184,24729600,1730560000 +3009,Belt,9,488448,765952,1978368,49459200,3461120000 +3010,Belt,10,976896,1531904,3956736,98918400,6922240000 +3011,Belt,11,1953792,3063808,7913472,197836800,13844480000 +3012,Belt,12,3907584,6127616,15826944,395673600,27688960000 +3013,Belt,13,7815168,12255232,31653888,791347200,55377920000 +3014,Belt,14,15630336,24510464,63307776,1582694400,110755840000 +3015,Belt,15,31260672,49020928,126615552,3165388800,221511680000 +3016,Belt,16,62521344,98041856,253231104,6330777600,443023360000 +3017,Belt,17,125042688,196083712,506462208,12661555200,886046720000 +3018,Belt,18,250085376,392167424,1012924416,25323110400,1772093440000 +3019,Belt,19,500170752,784334848,2025848832,50646220800,3544186880000 +3020,Belt,20,1000341504,1568669696,4051697664,101292441600,7088373760000 +3021,Belt,21,2000683008,3137339392,8103395328,202584883200,14176747520000 +4000,Necklace,0,315,1736,65040,243000,6760000 +4001,Necklace,1,630,3472,130080,486000,13520000 +4002,Necklace,2,1260,6944,260160,972000,27040000 +4003,Necklace,3,2520,13888,520320,1944000,54080000 +4004,Necklace,4,5040,27776,1040640,3888000,108160000 +4005,Necklace,5,10080,55552,2081280,7776000,216320000 +4006,Necklace,6,20160,111104,4162560,15552000,432640000 +4007,Necklace,7,40320,222208,8325120,31104000,865280000 +4008,Necklace,8,80640,444416,16650240,62208000,1730560000 +4009,Necklace,9,161280,888832,33300480,124416000,3461120000 +4010,Necklace,10,322560,1777664,66600960,248832000,6922240000 +4011,Necklace,11,645120,3555328,133201920,497664000,13844480000 +4012,Necklace,12,1290240,7110656,266403840,995328000,27688960000 +4013,Necklace,13,2580480,14221312,532807680,1990656000,55377920000 +4014,Necklace,14,5160960,28442624,1065615360,3981312000,110755840000 +4015,Necklace,15,10321920,56885248,2131230720,7962624000,221511680000 +4016,Necklace,16,20643840,113770496,4262461440,15925248000,443023360000 +4017,Necklace,17,41287680,227540992,8524922880,31850496000,886046720000 +4018,Necklace,18,82575360,455081984,17049845760,63700992000,1772093440000 +4019,Necklace,19,165150720,910163968,34099691520,127401984000,3544186880000 +4020,Necklace,20,330301440,1820327936,68199383040,254803968000,7088373760000 +4021,Necklace,21,660602880,3640655872,136398766080,509607936000,14176747520000 +5000,Ring,0,10,216,5568,426000,6760000 +5001,Ring,1,20,432,11136,852000,13520000 +5002,Ring,2,40,864,22272,1704000,27040000 +5003,Ring,3,80,1728,44544,3408000,54080000 +5004,Ring,4,160,3456,89088,6816000,108160000 +5005,Ring,5,320,6912,178176,13632000,216320000 +5006,Ring,6,640,13824,356352,27264000,432640000 +5007,Ring,7,1280,27648,712704,54528000,865280000 +5008,Ring,8,2560,55296,1425408,109056000,1730560000 +5009,Ring,9,5120,110592,2850816,218112000,3461120000 +5010,Ring,10,10240,221184,5701632,436224000,6922240000 +5011,Ring,11,20480,442368,11403264,872448000,13844480000 +5012,Ring,12,40960,884736,22806528,1744896000,27688960000 +5013,Ring,13,81920,1769472,45613056,3489792000,55377920000 +5014,Ring,14,163840,3538944,91226112,6979584000,110755840000 +5015,Ring,15,327680,7077888,182452224,13959168000,221511680000 +5016,Ring,16,655360,14155776,364904448,27918336000,443023360000 +5017,Ring,17,1310720,28311552,729808896,55836672000,886046720000 +5018,Ring,18,2621440,56623104,1459617792,111673344000,1772093440000 +5019,Ring,19,5242880,113246208,2919235584,223346688000,3544186880000 +5020,Ring,20,10485760,226492416,5838471168,446693376000,7088373760000 +5021,Ring,21,20971520,452984832,11676942336,893386752000,14176747520000 \ No newline at end of file diff --git a/Lib9c/TableData/Item/EquipmentItemUpgradePointSheet.cs b/Lib9c/TableData/Item/EquipmentItemUpgradePointSheet.cs new file mode 100644 index 0000000000..9417f4b353 --- /dev/null +++ b/Lib9c/TableData/Item/EquipmentItemUpgradePointSheet.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using Nekoyume.Model.EnumType; +using Nekoyume.Model.Item; +using static Nekoyume.TableData.TableExtensions; + +namespace Nekoyume.TableData +{ + [Serializable] + public class EquipmentItemUpgradePointSheet : Sheet + { + [Serializable] + public class Row : SheetRow + { + public override int Key => Id; + public int Id { get; private set; } + public ItemSubType ItemSubType { get; private set; } + public int Level { get; private set; } + public Dictionary ExpMap { get; private set; } + + public Row() + { + } + + public override void Set(IReadOnlyList fields) + { + Id = ParseInt(fields[0]); + ItemSubType = (ItemSubType)Enum.Parse(typeof(ItemSubType), fields[1]); + Level = ParseInt(fields[2]); + ExpMap = new Dictionary + { + { Grade.Normal, ParseLong(fields[3]) }, + { Grade.Rare, ParseLong(fields[4]) }, + { Grade.Epic, ParseLong(fields[5]) }, + { Grade.Unique, ParseLong(fields[6]) }, + { Grade.Legendary, ParseLong(fields[7]) }, + }; + } + } + + public EquipmentItemUpgradePointSheet() : base(nameof(EquipmentItemUpgradePointSheet)) + { + } + } +} From a06c4c37470eecec80c6a9c8c347ced5bbac7426 Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 03:20:58 +0900 Subject: [PATCH 11/20] Update data structure of CSVs - Delete `EquipmentItemUpgradePointSheet` and integrate to `EnhancementCostSheet` - Update `EnhancementCostSheet` to V3. - Remove unused columns. - Add `exp` column for required exp to reach level. - Update `EquipmentItemSheet` - Add `exp` column for initial exp of new equipment. --- .../TableCSV/Cost/EnhancementCostSheetV3.csv | 526 ++++++++++++++++++ Lib9c/TableCSV/Item/EquipmentItemSheet.csv | 354 ++++++------ .../Item/EquipmentItemUpgradePoint.csv | 111 ---- .../TableData/Cost/EnhancementCostSheetV3.cs | 45 ++ Lib9c/TableData/Item/EquipmentItemSheet.cs | 47 +- .../Item/EquipmentItemUpgradePointSheet.cs | 45 -- 6 files changed, 782 insertions(+), 346 deletions(-) create mode 100644 Lib9c/TableCSV/Cost/EnhancementCostSheetV3.csv delete mode 100644 Lib9c/TableCSV/Item/EquipmentItemUpgradePoint.csv create mode 100644 Lib9c/TableData/Cost/EnhancementCostSheetV3.cs delete mode 100644 Lib9c/TableData/Item/EquipmentItemUpgradePointSheet.cs diff --git a/Lib9c/TableCSV/Cost/EnhancementCostSheetV3.csv b/Lib9c/TableCSV/Cost/EnhancementCostSheetV3.csv new file mode 100644 index 0000000000..0cd2fe44c7 --- /dev/null +++ b/Lib9c/TableCSV/Cost/EnhancementCostSheetV3.csv @@ -0,0 +1,526 @@ +id,item_sub_type,grade,level,cost,exp,required_block_index,base_stat_growth_min,base_stat_growth_max,extra_stat_growth_min,extra_stat_growth_max,extra_skill_damage_growth_min,extra_skill_damage_growth_max,extra_skill_chance_growth_min,extra_skill_chance_growth_max +1,Weapon,1,1,0,20,25,800,1200,0,0,0,0,0,0 +2,Weapon,1,2,0,40,62,800,1200,0,0,0,0,0,0 +3,Weapon,1,3,0,80,125,800,1200,0,0,0,0,0,0 +4,Weapon,1,4,20,160,625,800,1200,2500,3500,2500,3500,1200,1800 +5,Weapon,1,5,40,320,925,800,1200,0,0,0,0,0,0 +6,Weapon,1,6,80,640,1300,800,1200,0,0,0,0,0,0 +7,Weapon,1,7,160,1280,2500,800,1200,2500,3500,2500,3500,1200,1800 +8,Weapon,1,8,320,2560,2975,800,1200,600,1000,600,1000,400,600 +9,Weapon,1,9,640,5120,3500,800,1200,600,1000,600,1000,400,600 +10,Weapon,1,10,1280,10240,4750,800,1200,1100,1700,1100,1700,700,1100 +11,Weapon,1,11,2560,20480,5000,800,1200,600,1000,600,1000,400,600 +12,Weapon,1,12,5120,40960,5250,800,1200,600,1000,600,1000,400,600 +13,Weapon,1,13,10240,81920,5500,800,1200,1100,1700,1100,1700,700,1100 +14,Weapon,1,14,20480,163840,5750,800,1200,600,1000,600,1000,400,600 +15,Weapon,1,15,40960,327680,6000,800,1200,600,1000,600,1000,400,600 +16,Weapon,1,16,81920,655360,6250,800,1200,1100,1700,1100,1700,700,1100 +17,Weapon,1,17,163840,1310720,6500,800,1200,600,1000,600,1000,400,600 +18,Weapon,1,18,327680,2621440,6750,800,1200,600,1000,600,1000,400,600 +19,Weapon,1,19,655360,5242880,7000,800,1200,1100,1700,1100,1700,700,1100 +20,Weapon,1,20,1310720,10485760,7250,800,1200,800,1200,800,1200,400,600 +21,Weapon,1,21,2621440,20971520,7500,800,1200,800,1200,800,1200,400,600 +22,Weapon,2,1,0,160,37,800,1200,0,0,0,0,0,0 +23,Weapon,2,2,0,320,93,800,1200,0,0,0,0,0,0 +24,Weapon,2,3,0,640,187,800,1200,0,0,0,0,0,0 +25,Weapon,2,4,20,1280,937,800,1200,2500,3500,2500,3500,1200,1800 +26,Weapon,2,5,40,2560,1387,800,1200,0,0,0,0,0,0 +27,Weapon,2,6,80,5120,1950,800,1200,0,0,0,0,0,0 +28,Weapon,2,7,160,10240,3750,800,1200,2500,3500,2500,3500,1200,1800 +29,Weapon,2,8,320,20480,4462,800,1200,600,1000,600,1000,400,600 +30,Weapon,2,9,640,40960,5250,800,1200,600,1000,600,1000,400,600 +31,Weapon,2,10,1280,81920,7125,800,1200,1100,1700,1100,1700,700,1100 +32,Weapon,2,11,2560,163840,7500,800,1200,600,1000,600,1000,400,600 +33,Weapon,2,12,5120,327680,7875,800,1200,600,1000,600,1000,400,600 +34,Weapon,2,13,10240,655360,8250,800,1200,1100,1700,1100,1700,700,1100 +35,Weapon,2,14,20480,1310720,8625,800,1200,600,1000,600,1000,400,600 +36,Weapon,2,15,40960,2621440,9000,800,1200,600,1000,600,1000,400,600 +37,Weapon,2,16,81920,5242880,9375,800,1200,1100,1700,1100,1700,700,1100 +38,Weapon,2,17,163840,10485760,9750,800,1200,600,1000,600,1000,400,600 +39,Weapon,2,18,327680,20971520,10125,800,1200,600,1000,600,1000,400,600 +40,Weapon,2,19,655360,41943040,10500,800,1200,1100,1700,1100,1700,700,1100 +41,Weapon,2,20,1310720,83886080,10875,800,1200,800,1200,800,1200,400,600 +42,Weapon,2,21,2621440,167772160,11250,800,1200,800,1200,800,1200,400,600 +43,Weapon,3,1,0,32040,75,800,1200,0,0,0,0,0,0 +44,Weapon,3,2,0,64080,187,800,1200,0,0,0,0,0,0 +45,Weapon,3,3,0,128160,375,800,1200,0,0,0,0,0,0 +46,Weapon,3,4,20,256320,1875,800,1200,2500,3500,2500,3500,1200,1800 +47,Weapon,3,5,40,512640,2775,800,1200,0,0,0,0,0,0 +48,Weapon,3,6,80,1025280,3900,800,1200,0,0,0,0,0,0 +49,Weapon,3,7,160,2050560,7500,800,1200,2500,3500,2500,3500,1200,1800 +50,Weapon,3,8,320,4101120,8925,800,1200,600,1000,600,1000,400,600 +51,Weapon,3,9,640,8202240,10500,800,1200,600,1000,600,1000,400,600 +52,Weapon,3,10,1280,16404480,14250,800,1200,1100,1700,1100,1700,700,1100 +53,Weapon,3,11,2560,32808960,15000,800,1200,600,1000,600,1000,400,600 +54,Weapon,3,12,5120,65617920,15750,800,1200,600,1000,600,1000,400,600 +55,Weapon,3,13,10240,131235840,16500,800,1200,1100,1700,1100,1700,700,1100 +56,Weapon,3,14,20480,262471680,17250,800,1200,600,1000,600,1000,400,600 +57,Weapon,3,15,40960,524943360,18000,800,1200,600,1000,600,1000,400,600 +58,Weapon,3,16,81920,1049886720,18750,800,1200,1100,1700,1100,1700,700,1100 +59,Weapon,3,17,163840,2099773440,19500,800,1200,600,1000,600,1000,400,600 +60,Weapon,3,18,327680,4199546880,20250,800,1200,600,1000,600,1000,400,600 +61,Weapon,3,19,655360,8399093760,21000,800,1200,1100,1700,1100,1700,700,1100 +62,Weapon,3,20,1310720,16798187520,21750,800,1200,800,1200,800,1200,400,600 +63,Weapon,3,21,2621440,33596375040,22500,800,1200,800,1200,800,1200,400,600 +64,Weapon,4,1,0,852000,162,800,1200,0,0,0,0,0,0 +65,Weapon,4,2,0,1704000,406,800,1200,0,0,0,0,0,0 +66,Weapon,4,3,0,3408000,812,800,1200,0,0,0,0,0,0 +67,Weapon,4,4,20,6816000,4062,800,1200,2500,3500,2500,3500,1200,1800 +68,Weapon,4,5,40,13632000,6012,800,1200,0,0,0,0,0,0 +69,Weapon,4,6,80,27264000,8450,800,1200,0,0,0,0,0,0 +70,Weapon,4,7,160,54528000,16250,800,1200,2500,3500,2500,3500,1200,1800 +71,Weapon,4,8,320,109056000,19337,800,1200,600,1000,600,1000,400,600 +72,Weapon,4,9,640,218112000,22750,800,1200,600,1000,600,1000,400,600 +73,Weapon,4,10,1280,436224000,30875,800,1200,1100,1700,1100,1700,700,1100 +74,Weapon,4,11,2560,872448000,32500,800,1200,600,1000,600,1000,400,600 +75,Weapon,4,12,5120,1744896000,34125,800,1200,600,1000,600,1000,400,600 +76,Weapon,4,13,10240,3489792000,35750,800,1200,1100,1700,1100,1700,700,1100 +77,Weapon,4,14,20480,6979584000,37375,800,1200,600,1000,600,1000,400,600 +78,Weapon,4,15,40960,13959168000,39000,800,1200,600,1000,600,1000,400,600 +79,Weapon,4,16,81920,27918336000,40625,800,1200,1100,1700,1100,1700,700,1100 +80,Weapon,4,17,163840,55836672000,42250,800,1200,600,1000,600,1000,400,600 +81,Weapon,4,18,327680,111673344000,43875,800,1200,600,1000,600,1000,400,600 +82,Weapon,4,19,655360,223346688000,45500,800,1200,1100,1700,1100,1700,700,1100 +83,Weapon,4,20,1310720,446693376000,47125,800,1200,800,1200,800,1200,400,600 +84,Weapon,4,21,2621440,893386752000,48750,800,1200,800,1200,800,1200,400,600 +85,Weapon,5,1,0,13520000,3600,1300,1400,1200,1300,0,0,0,0 +86,Weapon,5,2,0,27040000,3600,1300,1400,1200,1300,0,0,0,0 +87,Weapon,5,3,0,54080000,3600,1300,1400,1200,1300,0,0,0,0 +88,Weapon,5,4,20,108160000,3600,3500,3600,3500,3600,2000,2000,1500,1500 +89,Weapon,5,5,40,216320000,3600,1300,1400,1200,1300,0,0,0,0 +90,Weapon,5,6,80,432640000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +91,Weapon,5,7,160,865280000,3600,1300,1400,1200,1300,0,0,0,0 +92,Weapon,5,8,320,1730560000,3600,1300,1400,1200,1300,0,0,0,0 +93,Weapon,5,9,640,3461120000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +94,Weapon,5,10,1280,6922240000,3600,1300,1400,1200,1300,0,0,0,0 +95,Weapon,5,11,2560,13844480000,3600,1300,1400,1200,1300,0,0,0,0 +96,Weapon,5,12,5120,27688960000,3600,1300,1400,1200,1300,0,0,0,0 +97,Weapon,5,13,10240,55377920000,3600,1300,1400,1200,1300,0,0,0,0 +98,Weapon,5,14,20480,110755840000,3600,1300,1400,1200,1300,0,0,0,0 +99,Weapon,5,15,40960,221511680000,3600,1300,1400,1200,1300,0,0,0,0 +100,Weapon,5,16,81920,443023360000,3600,1300,1400,1200,1300,0,0,0,0 +101,Weapon,5,17,163840,886046720000,3600,1300,1400,1200,1300,0,0,0,0 +102,Weapon,5,18,327680,1772093440000,3600,1300,1400,1200,1300,0,0,0,0 +103,Weapon,5,19,655360,3544186880000,3600,1300,1400,1200,1300,0,0,0,0 +104,Weapon,5,20,1310720,7088373760000,3600,1300,1400,1200,1300,0,0,0,0 +105,Weapon,5,21,2621440,14176747520000,3600,1300,1400,1200,1300,0,0,0,0 +106,Armor,1,1,0,38,20,800,1200,0,0,0,0,0,0 +107,Armor,1,2,0,76,50,800,1200,0,0,0,0,0,0 +108,Armor,1,3,0,152,100,800,1200,0,0,0,0,0,0 +109,Armor,1,4,20,304,500,800,1200,2500,3500,2500,3500,1200,1800 +110,Armor,1,5,40,608,740,800,1200,0,0,0,0,0,0 +111,Armor,1,6,80,1216,1040,800,1200,0,0,0,0,0,0 +112,Armor,1,7,160,2432,2000,800,1200,2500,3500,2500,3500,1200,1800 +113,Armor,1,8,320,4864,2380,800,1200,600,1000,600,1000,400,600 +114,Armor,1,9,640,9728,2800,800,1200,600,1000,600,1000,400,600 +115,Armor,1,10,1280,19456,3800,800,1200,1100,1700,1100,1700,700,1100 +116,Armor,1,11,2560,38912,4000,800,1200,600,1000,600,1000,400,600 +117,Armor,1,12,5120,77824,4200,800,1200,600,1000,600,1000,400,600 +118,Armor,1,13,10240,155648,4400,800,1200,1100,1700,1100,1700,700,1100 +119,Armor,1,14,20480,311296,4600,800,1200,600,1000,600,1000,400,600 +120,Armor,1,15,40960,622592,4800,800,1200,600,1000,600,1000,400,600 +121,Armor,1,16,81920,1245184,5000,800,1200,1100,1700,1100,1700,700,1100 +122,Armor,1,17,163840,2490368,5200,800,1200,600,1000,600,1000,400,600 +123,Armor,1,18,327680,4980736,5400,800,1200,600,1000,600,1000,400,600 +124,Armor,1,19,655360,9961472,5600,800,1200,1100,1700,1100,1700,700,1100 +125,Armor,1,20,1310720,19922944,5800,800,1200,800,1200,800,1200,400,600 +126,Armor,1,21,2621440,39845888,6000,800,1200,800,1200,800,1200,400,600 +127,Armor,2,1,0,206,30,800,1200,0,0,0,0,0,0 +128,Armor,2,2,0,412,75,800,1200,0,0,0,0,0,0 +129,Armor,2,3,0,824,150,800,1200,0,0,0,0,0,0 +130,Armor,2,4,20,1648,750,800,1200,2500,3500,2500,3500,1200,1800 +131,Armor,2,5,40,3296,1110,800,1200,0,0,0,0,0,0 +132,Armor,2,6,80,6592,1560,800,1200,0,0,0,0,0,0 +133,Armor,2,7,160,13184,3000,800,1200,2500,3500,2500,3500,1200,1800 +134,Armor,2,8,320,26368,3570,800,1200,600,1000,600,1000,400,600 +135,Armor,2,9,640,52736,4200,800,1200,600,1000,600,1000,400,600 +136,Armor,2,10,1280,105472,5700,800,1200,1100,1700,1100,1700,700,1100 +137,Armor,2,11,2560,210944,6000,800,1200,600,1000,600,1000,400,600 +138,Armor,2,12,5120,421888,6300,800,1200,600,1000,600,1000,400,600 +139,Armor,2,13,10240,843776,6600,800,1200,1100,1700,1100,1700,700,1100 +140,Armor,2,14,20480,1687552,6900,800,1200,600,1000,600,1000,400,600 +141,Armor,2,15,40960,3375104,7200,800,1200,600,1000,600,1000,400,600 +142,Armor,2,16,81920,6750208,7500,800,1200,1100,1700,1100,1700,700,1100 +143,Armor,2,17,163840,13500416,7800,800,1200,600,1000,600,1000,400,600 +144,Armor,2,18,327680,27000832,8100,800,1200,600,1000,600,1000,400,600 +145,Armor,2,19,655360,54001664,8400,800,1200,1100,1700,1100,1700,700,1100 +146,Armor,2,20,1310720,108003328,8700,800,1200,800,1200,800,1200,400,600 +147,Armor,2,21,2621440,216006656,9000,800,1200,800,1200,800,1200,400,600 +148,Armor,3,1,0,19200,60,800,1200,0,0,0,0,0,0 +149,Armor,3,2,0,38400,150,800,1200,0,0,0,0,0,0 +150,Armor,3,3,0,76800,300,800,1200,0,0,0,0,0,0 +151,Armor,3,4,20,153600,1500,800,1200,2500,3500,2500,3500,1200,1800 +152,Armor,3,5,40,307200,2220,800,1200,0,0,0,0,0,0 +153,Armor,3,6,80,614400,3120,800,1200,0,0,0,0,0,0 +154,Armor,3,7,160,1228800,6000,800,1200,2500,3500,2500,3500,1200,1800 +155,Armor,3,8,320,2457600,7140,800,1200,600,1000,600,1000,400,600 +156,Armor,3,9,640,4915200,8400,800,1200,600,1000,600,1000,400,600 +157,Armor,3,10,1280,9830400,11400,800,1200,1100,1700,1100,1700,700,1100 +158,Armor,3,11,2560,19660800,12000,800,1200,600,1000,600,1000,400,600 +159,Armor,3,12,5120,39321600,12600,800,1200,600,1000,600,1000,400,600 +160,Armor,3,13,10240,78643200,13200,800,1200,1100,1700,1100,1700,700,1100 +161,Armor,3,14,20480,157286400,13800,800,1200,600,1000,600,1000,400,600 +162,Armor,3,15,40960,314572800,14400,800,1200,600,1000,600,1000,400,600 +163,Armor,3,16,81920,629145600,15000,800,1200,1100,1700,1100,1700,700,1100 +164,Armor,3,17,163840,1258291200,15600,800,1200,600,1000,600,1000,400,600 +165,Armor,3,18,327680,2516582400,16200,800,1200,600,1000,600,1000,400,600 +166,Armor,3,19,655360,5033164800,16800,800,1200,1100,1700,1100,1700,700,1100 +167,Armor,3,20,1310720,10066329600,17400,800,1200,800,1200,800,1200,400,600 +168,Armor,3,21,2621440,20132659200,18000,800,1200,800,1200,800,1200,400,600 +169,Armor,4,1,0,852000,130,800,1200,0,0,0,0,0,0 +170,Armor,4,2,0,1704000,325,800,1200,0,0,0,0,0,0 +171,Armor,4,3,0,3408000,650,800,1200,0,0,0,0,0,0 +172,Armor,4,4,20,6816000,3250,800,1200,2500,3500,2500,3500,1200,1800 +173,Armor,4,5,40,13632000,4810,800,1200,0,0,0,0,0,0 +174,Armor,4,6,80,27264000,6760,800,1200,0,0,0,0,0,0 +175,Armor,4,7,160,54528000,13000,800,1200,2500,3500,2500,3500,1200,1800 +176,Armor,4,8,320,109056000,15470,800,1200,600,1000,600,1000,400,600 +177,Armor,4,9,640,218112000,18200,800,1200,600,1000,600,1000,400,600 +178,Armor,4,10,1280,436224000,24700,800,1200,1100,1700,1100,1700,700,1100 +179,Armor,4,11,2560,872448000,26000,800,1200,600,1000,600,1000,400,600 +180,Armor,4,12,5120,1744896000,27300,800,1200,600,1000,600,1000,400,600 +181,Armor,4,13,10240,3489792000,28600,800,1200,1100,1700,1100,1700,700,1100 +182,Armor,4,14,20480,6979584000,29900,800,1200,600,1000,600,1000,400,600 +183,Armor,4,15,40960,13959168000,31200,800,1200,600,1000,600,1000,400,600 +184,Armor,4,16,81920,27918336000,32500,800,1200,1100,1700,1100,1700,700,1100 +185,Armor,4,17,163840,55836672000,33800,800,1200,600,1000,600,1000,400,600 +186,Armor,4,18,327680,111673344000,35100,800,1200,600,1000,600,1000,400,600 +187,Armor,4,19,655360,223346688000,36400,800,1200,1100,1700,1100,1700,700,1100 +188,Armor,4,20,1310720,446693376000,37700,800,1200,800,1200,800,1200,400,600 +189,Armor,4,21,2621440,893386752000,39000,800,1200,800,1200,800,1200,400,600 +190,Armor,5,1,0,13520000,3600,1300,1400,1200,1300,0,0,0,0 +191,Armor,5,2,0,27040000,3600,1300,1400,1200,1300,0,0,0,0 +192,Armor,5,3,0,54080000,3600,1300,1400,1200,1300,0,0,0,0 +193,Armor,5,4,20,108160000,3600,3500,3600,3500,3600,2000,2000,1500,1500 +194,Armor,5,5,40,216320000,3600,1300,1400,1200,1300,0,0,0,0 +195,Armor,5,6,80,432640000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +196,Armor,5,7,160,865280000,3600,1300,1400,1200,1300,0,0,0,0 +197,Armor,5,8,320,1730560000,3600,1300,1400,1200,1300,0,0,0,0 +198,Armor,5,9,640,3461120000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +199,Armor,5,10,1280,6922240000,3600,1300,1400,1200,1300,0,0,0,0 +200,Armor,5,11,2560,13844480000,3600,1300,1400,1200,1300,0,0,0,0 +201,Armor,5,12,5120,27688960000,3600,1300,1400,1200,1300,0,0,0,0 +202,Armor,5,13,10240,55377920000,3600,1300,1400,1200,1300,0,0,0,0 +203,Armor,5,14,20480,110755840000,3600,1300,1400,1200,1300,0,0,0,0 +204,Armor,5,15,40960,221511680000,3600,1300,1400,1200,1300,0,0,0,0 +205,Armor,5,16,81920,443023360000,3600,1300,1400,1200,1300,0,0,0,0 +206,Armor,5,17,163840,886046720000,3600,1300,1400,1200,1300,0,0,0,0 +207,Armor,5,18,327680,1772093440000,3600,1300,1400,1200,1300,0,0,0,0 +208,Armor,5,19,655360,3544186880000,3600,1300,1400,1200,1300,0,0,0,0 +209,Armor,5,20,1310720,7088373760000,3600,1300,1400,1200,1300,0,0,0,0 +210,Armor,5,21,2621440,14176747520000,3600,1300,1400,1200,1300,0,0,0,0 +211,Belt,1,1,0,1908,20,800,1200,0,0,0,0,0,0 +212,Belt,1,2,0,3816,50,800,1200,0,0,0,0,0,0 +213,Belt,1,3,0,7632,100,800,1200,0,0,0,0,0,0 +214,Belt,1,4,20,15264,500,800,1200,2500,3500,2500,3500,1200,1800 +215,Belt,1,5,40,30528,740,800,1200,0,0,0,0,0,0 +216,Belt,1,6,80,61056,1040,800,1200,0,0,0,0,0,0 +217,Belt,1,7,160,122112,2000,800,1200,2500,3500,2500,3500,1200,1800 +218,Belt,1,8,320,244224,2380,800,1200,600,1000,600,1000,400,600 +219,Belt,1,9,640,488448,2800,800,1200,600,1000,600,1000,400,600 +220,Belt,1,10,1280,976896,3800,800,1200,1100,1700,1100,1700,700,1100 +221,Belt,1,11,2560,1953792,4000,800,1200,600,1000,600,1000,400,600 +222,Belt,1,12,5120,3907584,4200,800,1200,600,1000,600,1000,400,600 +223,Belt,1,13,10240,7815168,4400,800,1200,1100,1700,1100,1700,700,1100 +224,Belt,1,14,20480,15630336,4600,800,1200,600,1000,600,1000,400,600 +225,Belt,1,15,40960,31260672,4800,800,1200,600,1000,600,1000,400,600 +226,Belt,1,16,81920,62521344,5000,800,1200,1100,1700,1100,1700,700,1100 +227,Belt,1,17,163840,125042688,5200,800,1200,600,1000,600,1000,400,600 +228,Belt,1,18,327680,250085376,5400,800,1200,600,1000,600,1000,400,600 +229,Belt,1,19,655360,500170752,5600,800,1200,1100,1700,1100,1700,700,1100 +230,Belt,1,20,1310720,1000341504,5800,800,1200,800,1200,800,1200,400,600 +231,Belt,1,21,2621440,2000683008,6000,800,1200,800,1200,800,1200,400,600 +232,Belt,2,1,0,2992,30,800,1200,0,0,0,0,0,0 +233,Belt,2,2,0,5984,75,800,1200,0,0,0,0,0,0 +234,Belt,2,3,0,11968,150,800,1200,0,0,0,0,0,0 +235,Belt,2,4,20,23936,750,800,1200,2500,3500,2500,3500,1200,1800 +236,Belt,2,5,40,47872,1110,800,1200,0,0,0,0,0,0 +237,Belt,2,6,80,95744,1560,800,1200,0,0,0,0,0,0 +238,Belt,2,7,160,191488,3000,800,1200,2500,3500,2500,3500,1200,1800 +239,Belt,2,8,320,382976,3570,800,1200,600,1000,600,1000,400,600 +240,Belt,2,9,640,765952,4200,800,1200,600,1000,600,1000,400,600 +241,Belt,2,10,1280,1531904,5700,800,1200,1100,1700,1100,1700,700,1100 +242,Belt,2,11,2560,3063808,6000,800,1200,600,1000,600,1000,400,600 +243,Belt,2,12,5120,6127616,6300,800,1200,600,1000,600,1000,400,600 +244,Belt,2,13,10240,12255232,6600,800,1200,1100,1700,1100,1700,700,1100 +245,Belt,2,14,20480,24510464,6900,800,1200,600,1000,600,1000,400,600 +246,Belt,2,15,40960,49020928,7200,800,1200,600,1000,600,1000,400,600 +247,Belt,2,16,81920,98041856,7500,800,1200,1100,1700,1100,1700,700,1100 +248,Belt,2,17,163840,196083712,7800,800,1200,600,1000,600,1000,400,600 +249,Belt,2,18,327680,392167424,8100,800,1200,600,1000,600,1000,400,600 +250,Belt,2,19,655360,784334848,8400,800,1200,1100,1700,1100,1700,700,1100 +251,Belt,2,20,1310720,1568669696,8700,800,1200,800,1200,800,1200,400,600 +252,Belt,2,21,2621440,3137339392,9000,800,1200,800,1200,800,1200,400,600 +253,Belt,3,1,0,7728,60,800,1200,0,0,0,0,0,0 +254,Belt,3,2,0,15456,150,800,1200,0,0,0,0,0,0 +255,Belt,3,3,0,30912,300,800,1200,0,0,0,0,0,0 +256,Belt,3,4,20,61824,1500,800,1200,2500,3500,2500,3500,1200,1800 +257,Belt,3,5,40,123648,2220,800,1200,0,0,0,0,0,0 +258,Belt,3,6,80,247296,3120,800,1200,0,0,0,0,0,0 +259,Belt,3,7,160,494592,6000,800,1200,2500,3500,2500,3500,1200,1800 +260,Belt,3,8,320,989184,7140,800,1200,600,1000,600,1000,400,600 +261,Belt,3,9,640,1978368,8400,800,1200,600,1000,600,1000,400,600 +262,Belt,3,10,1280,3956736,11400,800,1200,1100,1700,1100,1700,700,1100 +263,Belt,3,11,2560,7913472,12000,800,1200,600,1000,600,1000,400,600 +264,Belt,3,12,5120,15826944,12600,800,1200,600,1000,600,1000,400,600 +265,Belt,3,13,10240,31653888,13200,800,1200,1100,1700,1100,1700,700,1100 +266,Belt,3,14,20480,63307776,13800,800,1200,600,1000,600,1000,400,600 +267,Belt,3,15,40960,126615552,14400,800,1200,600,1000,600,1000,400,600 +268,Belt,3,16,81920,253231104,15000,800,1200,1100,1700,1100,1700,700,1100 +269,Belt,3,17,163840,506462208,15600,800,1200,600,1000,600,1000,400,600 +270,Belt,3,18,327680,1012924416,16200,800,1200,600,1000,600,1000,400,600 +271,Belt,3,19,655360,2025848832,16800,800,1200,1100,1700,1100,1700,700,1100 +272,Belt,3,20,1310720,4051697664,17400,800,1200,800,1200,800,1200,400,600 +273,Belt,3,21,2621440,8103395328,18000,800,1200,800,1200,800,1200,400,600 +274,Belt,4,1,0,193200,130,800,1200,0,0,0,0,0,0 +275,Belt,4,2,0,386400,325,800,1200,0,0,0,0,0,0 +276,Belt,4,3,0,772800,650,800,1200,0,0,0,0,0,0 +277,Belt,4,4,20,1545600,3250,800,1200,2500,3500,2500,3500,1200,1800 +278,Belt,4,5,40,3091200,4810,800,1200,0,0,0,0,0,0 +279,Belt,4,6,80,6182400,6760,800,1200,0,0,0,0,0,0 +280,Belt,4,7,160,12364800,13000,800,1200,2500,3500,2500,3500,1200,1800 +281,Belt,4,8,320,24729600,15470,800,1200,600,1000,600,1000,400,600 +282,Belt,4,9,640,49459200,18200,800,1200,600,1000,600,1000,400,600 +283,Belt,4,10,1280,98918400,24700,800,1200,1100,1700,1100,1700,700,1100 +284,Belt,4,11,2560,197836800,26000,800,1200,600,1000,600,1000,400,600 +285,Belt,4,12,5120,395673600,27300,800,1200,600,1000,600,1000,400,600 +286,Belt,4,13,10240,791347200,28600,800,1200,1100,1700,1100,1700,700,1100 +287,Belt,4,14,20480,1582694400,29900,800,1200,600,1000,600,1000,400,600 +288,Belt,4,15,40960,3165388800,31200,800,1200,600,1000,600,1000,400,600 +289,Belt,4,16,81920,6330777600,32500,800,1200,1100,1700,1100,1700,700,1100 +290,Belt,4,17,163840,12661555200,33800,800,1200,600,1000,600,1000,400,600 +291,Belt,4,18,327680,25323110400,35100,800,1200,600,1000,600,1000,400,600 +292,Belt,4,19,655360,50646220800,36400,800,1200,1100,1700,1100,1700,700,1100 +293,Belt,4,20,1310720,101292441600,37700,800,1200,800,1200,800,1200,400,600 +294,Belt,4,21,2621440,202584883200,39000,800,1200,800,1200,800,1200,400,600 +295,Belt,5,1,0,13520000,3600,1300,1400,1200,1300,0,0,0,0 +296,Belt,5,2,0,27040000,3600,1300,1400,1200,1300,0,0,0,0 +297,Belt,5,3,0,54080000,3600,1300,1400,1200,1300,0,0,0,0 +298,Belt,5,4,20,108160000,3600,3500,3600,3500,3600,2000,2000,1500,1500 +299,Belt,5,5,40,216320000,3600,1300,1400,1200,1300,0,0,0,0 +300,Belt,5,6,80,432640000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +301,Belt,5,7,160,865280000,3600,1300,1400,1200,1300,0,0,0,0 +302,Belt,5,8,320,1730560000,3600,1300,1400,1200,1300,0,0,0,0 +303,Belt,5,9,640,3461120000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +304,Belt,5,10,1280,6922240000,3600,1300,1400,1200,1300,0,0,0,0 +305,Belt,5,11,2560,13844480000,3600,1300,1400,1200,1300,0,0,0,0 +306,Belt,5,12,5120,27688960000,3600,1300,1400,1200,1300,0,0,0,0 +307,Belt,5,13,10240,55377920000,3600,1300,1400,1200,1300,0,0,0,0 +308,Belt,5,14,20480,110755840000,3600,1300,1400,1200,1300,0,0,0,0 +309,Belt,5,15,40960,221511680000,3600,1300,1400,1200,1300,0,0,0,0 +310,Belt,5,16,81920,443023360000,3600,1300,1400,1200,1300,0,0,0,0 +311,Belt,5,17,163840,886046720000,3600,1300,1400,1200,1300,0,0,0,0 +312,Belt,5,18,327680,1772093440000,3600,1300,1400,1200,1300,0,0,0,0 +313,Belt,5,19,655360,3544186880000,3600,1300,1400,1200,1300,0,0,0,0 +314,Belt,5,20,1310720,7088373760000,3600,1300,1400,1200,1300,0,0,0,0 +315,Belt,5,21,2621440,14176747520000,3600,1300,1400,1200,1300,0,0,0,0 +316,Necklace,1,1,0,630,25,800,1200,0,0,0,0,0,0 +317,Necklace,1,2,0,1260,62,800,1200,0,0,0,0,0,0 +318,Necklace,1,3,0,2520,125,800,1200,0,0,0,0,0,0 +319,Necklace,1,4,20,5040,625,800,1200,2500,3500,2500,3500,1200,1800 +320,Necklace,1,5,40,10080,925,800,1200,0,0,0,0,0,0 +321,Necklace,1,6,80,20160,1300,800,1200,0,0,0,0,0,0 +322,Necklace,1,7,160,40320,2500,800,1200,2500,3500,2500,3500,1200,1800 +323,Necklace,1,8,320,80640,2975,800,1200,600,1000,600,1000,400,600 +324,Necklace,1,9,640,161280,3500,800,1200,600,1000,600,1000,400,600 +325,Necklace,1,10,1280,322560,4750,800,1200,1100,1700,1100,1700,700,1100 +326,Necklace,1,11,2560,645120,5000,800,1200,600,1000,600,1000,400,600 +327,Necklace,1,12,5120,1290240,5250,800,1200,600,1000,600,1000,400,600 +328,Necklace,1,13,10240,2580480,5500,800,1200,1100,1700,1100,1700,700,1100 +329,Necklace,1,14,20480,5160960,5750,800,1200,600,1000,600,1000,400,600 +330,Necklace,1,15,40960,10321920,6000,800,1200,600,1000,600,1000,400,600 +331,Necklace,1,16,81920,20643840,6250,800,1200,1100,1700,1100,1700,700,1100 +332,Necklace,1,17,163840,41287680,6500,800,1200,600,1000,600,1000,400,600 +333,Necklace,1,18,327680,82575360,6750,800,1200,600,1000,600,1000,400,600 +334,Necklace,1,19,655360,165150720,7000,800,1200,1100,1700,1100,1700,700,1100 +335,Necklace,1,20,1310720,330301440,7250,800,1200,800,1200,800,1200,400,600 +336,Necklace,1,21,2621440,660602880,7500,800,1200,800,1200,800,1200,400,600 +337,Necklace,2,1,0,3472,37,800,1200,0,0,0,0,0,0 +338,Necklace,2,2,0,6944,93,800,1200,0,0,0,0,0,0 +339,Necklace,2,3,0,13888,187,800,1200,0,0,0,0,0,0 +340,Necklace,2,4,20,27776,937,800,1200,2500,3500,2500,3500,1200,1800 +341,Necklace,2,5,40,55552,1387,800,1200,0,0,0,0,0,0 +342,Necklace,2,6,80,111104,1950,800,1200,0,0,0,0,0,0 +343,Necklace,2,7,160,222208,3750,800,1200,2500,3500,2500,3500,1200,1800 +344,Necklace,2,8,320,444416,4462,800,1200,600,1000,600,1000,400,600 +345,Necklace,2,9,640,888832,5250,800,1200,600,1000,600,1000,400,600 +346,Necklace,2,10,1280,1777664,7125,800,1200,1100,1700,1100,1700,700,1100 +347,Necklace,2,11,2560,3555328,7500,800,1200,600,1000,600,1000,400,600 +348,Necklace,2,12,5120,7110656,7875,800,1200,600,1000,600,1000,400,600 +349,Necklace,2,13,10240,14221312,8250,800,1200,1100,1700,1100,1700,700,1100 +350,Necklace,2,14,20480,28442624,8625,800,1200,600,1000,600,1000,400,600 +351,Necklace,2,15,40960,56885248,9000,800,1200,600,1000,600,1000,400,600 +352,Necklace,2,16,81920,113770496,9375,800,1200,1100,1700,1100,1700,700,1100 +353,Necklace,2,17,163840,227540992,9750,800,1200,600,1000,600,1000,400,600 +354,Necklace,2,18,327680,455081984,10125,800,1200,600,1000,600,1000,400,600 +355,Necklace,2,19,655360,910163968,10500,800,1200,1100,1700,1100,1700,700,1100 +356,Necklace,2,20,1310720,1820327936,10875,800,1200,800,1200,800,1200,400,600 +357,Necklace,2,21,2621440,3640655872,11250,800,1200,800,1200,800,1200,400,600 +358,Necklace,3,1,0,130080,75,800,1200,0,0,0,0,0,0 +359,Necklace,3,2,0,260160,187,800,1200,0,0,0,0,0,0 +360,Necklace,3,3,0,520320,375,800,1200,0,0,0,0,0,0 +361,Necklace,3,4,20,1040640,1875,800,1200,2500,3500,2500,3500,1200,1800 +362,Necklace,3,5,40,2081280,2775,800,1200,0,0,0,0,0,0 +363,Necklace,3,6,80,4162560,3900,800,1200,0,0,0,0,0,0 +364,Necklace,3,7,160,8325120,7500,800,1200,2500,3500,2500,3500,1200,1800 +365,Necklace,3,8,320,16650240,8925,800,1200,600,1000,600,1000,400,600 +366,Necklace,3,9,640,33300480,10500,800,1200,600,1000,600,1000,400,600 +367,Necklace,3,10,1280,66600960,14250,800,1200,1100,1700,1100,1700,700,1100 +368,Necklace,3,11,2560,133201920,15000,800,1200,600,1000,600,1000,400,600 +369,Necklace,3,12,5120,266403840,15750,800,1200,600,1000,600,1000,400,600 +370,Necklace,3,13,10240,532807680,16500,800,1200,1100,1700,1100,1700,700,1100 +371,Necklace,3,14,20480,1065615360,17250,800,1200,600,1000,600,1000,400,600 +372,Necklace,3,15,40960,2131230720,18000,800,1200,600,1000,600,1000,400,600 +373,Necklace,3,16,81920,4262461440,18750,800,1200,1100,1700,1100,1700,700,1100 +374,Necklace,3,17,163840,8524922880,19500,800,1200,600,1000,600,1000,400,600 +375,Necklace,3,18,327680,17049845760,20250,800,1200,600,1000,600,1000,400,600 +376,Necklace,3,19,655360,34099691520,21000,800,1200,1100,1700,1100,1700,700,1100 +377,Necklace,3,20,1310720,68199383040,21750,800,1200,800,1200,800,1200,400,600 +378,Necklace,3,21,2621440,136398766080,22500,800,1200,800,1200,800,1200,400,600 +379,Necklace,4,1,0,486000,162,800,1200,0,0,0,0,0,0 +380,Necklace,4,2,0,972000,406,800,1200,0,0,0,0,0,0 +381,Necklace,4,3,0,1944000,812,800,1200,0,0,0,0,0,0 +382,Necklace,4,4,20,3888000,4062,800,1200,2500,3500,2500,3500,1200,1800 +383,Necklace,4,5,40,7776000,6012,800,1200,0,0,0,0,0,0 +384,Necklace,4,6,80,15552000,8450,800,1200,0,0,0,0,0,0 +385,Necklace,4,7,160,31104000,16250,800,1200,2500,3500,2500,3500,1200,1800 +386,Necklace,4,8,320,62208000,19337,800,1200,600,1000,600,1000,400,600 +387,Necklace,4,9,640,124416000,22750,800,1200,600,1000,600,1000,400,600 +388,Necklace,4,10,1280,248832000,30875,800,1200,1100,1700,1100,1700,700,1100 +389,Necklace,4,11,2560,497664000,32500,800,1200,600,1000,600,1000,400,600 +390,Necklace,4,12,5120,995328000,34125,800,1200,600,1000,600,1000,400,600 +391,Necklace,4,13,10240,1990656000,35750,800,1200,1100,1700,1100,1700,700,1100 +392,Necklace,4,14,20480,3981312000,37375,800,1200,600,1000,600,1000,400,600 +393,Necklace,4,15,40960,7962624000,39000,800,1200,600,1000,600,1000,400,600 +394,Necklace,4,16,81920,15925248000,40625,800,1200,1100,1700,1100,1700,700,1100 +395,Necklace,4,17,163840,31850496000,42250,800,1200,600,1000,600,1000,400,600 +396,Necklace,4,18,327680,63700992000,43875,800,1200,600,1000,600,1000,400,600 +397,Necklace,4,19,655360,127401984000,45500,800,1200,1100,1700,1100,1700,700,1100 +398,Necklace,4,20,1310720,254803968000,47125,800,1200,800,1200,800,1200,400,600 +399,Necklace,4,21,2621440,509607936000,48750,800,1200,800,1200,800,1200,400,600 +400,Necklace,5,1,0,13520000,3600,1300,1400,1200,1300,0,0,0,0 +401,Necklace,5,2,0,27040000,3600,1300,1400,1200,1300,0,0,0,0 +402,Necklace,5,3,0,54080000,3600,1300,1400,1200,1300,0,0,0,0 +403,Necklace,5,4,20,108160000,3600,3500,3600,3500,3600,2000,2000,1500,1500 +404,Necklace,5,5,40,216320000,3600,1300,1400,1200,1300,0,0,0,0 +405,Necklace,5,6,80,432640000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +406,Necklace,5,7,160,865280000,3600,1300,1400,1200,1300,0,0,0,0 +407,Necklace,5,8,320,1730560000,3600,1300,1400,1200,1300,0,0,0,0 +408,Necklace,5,9,640,3461120000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +409,Necklace,5,10,1280,6922240000,3600,1300,1400,1200,1300,0,0,0,0 +410,Necklace,5,11,2560,13844480000,3600,1300,1400,1200,1300,0,0,0,0 +411,Necklace,5,12,5120,27688960000,3600,1300,1400,1200,1300,0,0,0,0 +412,Necklace,5,13,10240,55377920000,3600,1300,1400,1200,1300,0,0,0,0 +413,Necklace,5,14,20480,110755840000,3600,1300,1400,1200,1300,0,0,0,0 +414,Necklace,5,15,40960,221511680000,3600,1300,1400,1200,1300,0,0,0,0 +415,Necklace,5,16,81920,443023360000,3600,1300,1400,1200,1300,0,0,0,0 +416,Necklace,5,17,163840,886046720000,3600,1300,1400,1200,1300,0,0,0,0 +417,Necklace,5,18,327680,1772093440000,3600,1300,1400,1200,1300,0,0,0,0 +418,Necklace,5,19,655360,3544186880000,3600,1300,1400,1200,1300,0,0,0,0 +419,Necklace,5,20,1310720,7088373760000,3600,1300,1400,1200,1300,0,0,0,0 +420,Necklace,5,21,2621440,14176747520000,3600,1300,1400,1200,1300,0,0,0,0 +421,Ring,1,1,0,20,30,800,1200,0,0,0,0,0,0 +422,Ring,1,2,0,40,75,800,1200,0,0,0,0,0,0 +423,Ring,1,3,0,80,150,800,1200,0,0,0,0,0,0 +424,Ring,1,4,20,160,750,800,1200,2500,3500,2500,3500,1200,1800 +425,Ring,1,5,40,320,1110,800,1200,0,0,0,0,0,0 +426,Ring,1,6,80,640,1560,800,1200,0,0,0,0,0,0 +427,Ring,1,7,160,1280,3000,800,1200,2500,3500,2500,3500,1200,1800 +428,Ring,1,8,320,2560,3570,800,1200,600,1000,600,1000,400,600 +429,Ring,1,9,640,5120,4200,800,1200,600,1000,600,1000,400,600 +430,Ring,1,10,1280,10240,5700,800,1200,1100,1700,1100,1700,700,1100 +431,Ring,1,11,2560,20480,6000,800,1200,600,1000,600,1000,400,600 +432,Ring,1,12,5120,40960,6300,800,1200,600,1000,600,1000,400,600 +433,Ring,1,13,10240,81920,6600,800,1200,1100,1700,1100,1700,700,1100 +434,Ring,1,14,20480,163840,6900,800,1200,600,1000,600,1000,400,600 +435,Ring,1,15,40960,327680,7200,800,1200,600,1000,600,1000,400,600 +436,Ring,1,16,81920,655360,7500,800,1200,1100,1700,1100,1700,700,1100 +437,Ring,1,17,163840,1310720,7800,800,1200,600,1000,600,1000,400,600 +438,Ring,1,18,327680,2621440,8100,800,1200,600,1000,600,1000,400,600 +439,Ring,1,19,655360,5242880,8400,800,1200,1100,1700,1100,1700,700,1100 +440,Ring,1,20,1310720,10485760,8700,800,1200,800,1200,800,1200,400,600 +441,Ring,1,21,2621440,20971520,9000,800,1200,800,1200,800,1200,400,600 +442,Ring,2,1,0,432,45,800,1200,0,0,0,0,0,0 +443,Ring,2,2,0,864,112,800,1200,0,0,0,0,0,0 +444,Ring,2,3,0,1728,225,800,1200,0,0,0,0,0,0 +445,Ring,2,4,20,3456,1125,800,1200,2500,3500,2500,3500,1200,1800 +446,Ring,2,5,40,6912,1665,800,1200,0,0,0,0,0,0 +447,Ring,2,6,80,13824,2340,800,1200,0,0,0,0,0,0 +448,Ring,2,7,160,27648,4500,800,1200,2500,3500,2500,3500,1200,1800 +449,Ring,2,8,320,55296,5355,800,1200,600,1000,600,1000,400,600 +450,Ring,2,9,640,110592,6300,800,1200,600,1000,600,1000,400,600 +451,Ring,2,10,1280,221184,8550,800,1200,1100,1700,1100,1700,700,1100 +452,Ring,2,11,2560,442368,9000,800,1200,600,1000,600,1000,400,600 +453,Ring,2,12,5120,884736,9450,800,1200,600,1000,600,1000,400,600 +454,Ring,2,13,10240,1769472,9900,800,1200,1100,1700,1100,1700,700,1100 +455,Ring,2,14,20480,3538944,10350,800,1200,600,1000,600,1000,400,600 +456,Ring,2,15,40960,7077888,10800,800,1200,600,1000,600,1000,400,600 +457,Ring,2,16,81920,14155776,11250,800,1200,1100,1700,1100,1700,700,1100 +458,Ring,2,17,163840,28311552,11700,800,1200,600,1000,600,1000,400,600 +459,Ring,2,18,327680,56623104,12150,800,1200,600,1000,600,1000,400,600 +460,Ring,2,19,655360,113246208,12600,800,1200,1100,1700,1100,1700,700,1100 +461,Ring,2,20,1310720,226492416,13050,800,1200,800,1200,800,1200,400,600 +462,Ring,2,21,2621440,452984832,13500,800,1200,800,1200,800,1200,400,600 +463,Ring,3,1,0,11136,90,800,1200,0,0,0,0,0,0 +464,Ring,3,2,0,22272,225,800,1200,0,0,0,0,0,0 +465,Ring,3,3,0,44544,450,800,1200,0,0,0,0,0,0 +466,Ring,3,4,20,89088,2250,800,1200,2500,3500,2500,3500,1200,1800 +467,Ring,3,5,40,178176,3330,800,1200,0,0,0,0,0,0 +468,Ring,3,6,80,356352,4680,800,1200,0,0,0,0,0,0 +469,Ring,3,7,160,712704,9000,800,1200,2500,3500,2500,3500,1200,1800 +470,Ring,3,8,320,1425408,10710,800,1200,600,1000,600,1000,400,600 +471,Ring,3,9,640,2850816,12600,800,1200,600,1000,600,1000,400,600 +472,Ring,3,10,1280,5701632,17100,800,1200,1100,1700,1100,1700,700,1100 +473,Ring,3,11,2560,11403264,18000,800,1200,600,1000,600,1000,400,600 +474,Ring,3,12,5120,22806528,18900,800,1200,600,1000,600,1000,400,600 +475,Ring,3,13,10240,45613056,19800,800,1200,1100,1700,1100,1700,700,1100 +476,Ring,3,14,20480,91226112,20700,800,1200,600,1000,600,1000,400,600 +477,Ring,3,15,40960,182452224,21600,800,1200,600,1000,600,1000,400,600 +478,Ring,3,16,81920,364904448,22500,800,1200,1100,1700,1100,1700,700,1100 +479,Ring,3,17,163840,729808896,23400,800,1200,600,1000,600,1000,400,600 +480,Ring,3,18,327680,1459617792,24300,800,1200,600,1000,600,1000,400,600 +481,Ring,3,19,655360,2919235584,25200,800,1200,1100,1700,1100,1700,700,1100 +482,Ring,3,20,1310720,5838471168,26100,800,1200,800,1200,800,1200,400,600 +483,Ring,3,21,2621440,11676942336,27000,800,1200,800,1200,800,1200,400,600 +484,Ring,4,1,0,852000,195,800,1200,0,0,0,0,0,0 +485,Ring,4,2,0,1704000,487,800,1200,0,0,0,0,0,0 +486,Ring,4,3,0,3408000,975,800,1200,0,0,0,0,0,0 +487,Ring,4,4,20,6816000,4875,800,1200,2500,3500,2500,3500,1200,1800 +488,Ring,4,5,40,13632000,7215,800,1200,0,0,0,0,0,0 +489,Ring,4,6,80,27264000,10140,800,1200,0,0,0,0,0,0 +490,Ring,4,7,160,54528000,19500,800,1200,2500,3500,2500,3500,1200,1800 +491,Ring,4,8,320,109056000,23205,800,1200,600,1000,600,1000,400,600 +492,Ring,4,9,640,218112000,27300,800,1200,600,1000,600,1000,400,600 +493,Ring,4,10,1280,436224000,37050,800,1200,1100,1700,1100,1700,700,1100 +494,Ring,4,11,2560,872448000,39000,800,1200,600,1000,600,1000,400,600 +495,Ring,4,12,5120,1744896000,40950,800,1200,600,1000,600,1000,400,600 +496,Ring,4,13,10240,3489792000,42900,800,1200,1100,1700,1100,1700,700,1100 +497,Ring,4,14,20480,6979584000,44850,800,1200,600,1000,600,1000,400,600 +498,Ring,4,15,40960,13959168000,46800,800,1200,600,1000,600,1000,400,600 +499,Ring,4,16,81920,27918336000,48750,800,1200,1100,1700,1100,1700,700,1100 +500,Ring,4,17,163840,55836672000,50700,800,1200,600,1000,600,1000,400,600 +501,Ring,4,18,327680,111673344000,52650,800,1200,600,1000,600,1000,400,600 +502,Ring,4,19,655360,223346688000,54600,800,1200,1100,1700,1100,1700,700,1100 +503,Ring,4,20,1310720,446693376000,56550,800,1200,800,1200,800,1200,400,600 +504,Ring,4,21,2621440,893386752000,58500,800,1200,800,1200,800,1200,400,600 +505,Ring,5,1,0,13520000,3600,1300,1400,1200,1300,0,0,0,0 +506,Ring,5,2,0,27040000,3600,1300,1400,1200,1300,0,0,0,0 +507,Ring,5,3,0,54080000,3600,1300,1400,1200,1300,0,0,0,0 +508,Ring,5,4,20,108160000,3600,3500,3600,3500,3600,2000,2000,1500,1500 +509,Ring,5,5,40,216320000,3600,1300,1400,1200,1300,0,0,0,0 +510,Ring,5,6,80,432640000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +511,Ring,5,7,160,865280000,3600,1300,1400,1200,1300,0,0,0,0 +512,Ring,5,8,320,1730560000,3600,1300,1400,1200,1300,0,0,0,0 +513,Ring,5,9,640,3461120000,3600,1300,1400,1200,1300,2000,2000,1500,1500 +514,Ring,5,10,1280,6922240000,3600,1300,1400,1200,1300,0,0,0,0 +515,Ring,5,11,2560,13844480000,3600,1300,1400,1200,1300,0,0,0,0 +516,Ring,5,12,5120,27688960000,3600,1300,1400,1200,1300,0,0,0,0 +517,Ring,5,13,10240,55377920000,3600,1300,1400,1200,1300,0,0,0,0 +518,Ring,5,14,20480,110755840000,3600,1300,1400,1200,1300,0,0,0,0 +519,Ring,5,15,40960,221511680000,3600,1300,1400,1200,1300,0,0,0,0 +520,Ring,5,16,81920,443023360000,3600,1300,1400,1200,1300,0,0,0,0 +521,Ring,5,17,163840,886046720000,3600,1300,1400,1200,1300,0,0,0,0 +522,Ring,5,18,327680,1772093440000,3600,1300,1400,1200,1300,0,0,0,0 +523,Ring,5,19,655360,3544186880000,3600,1300,1400,1200,1300,0,0,0,0 +524,Ring,5,20,1310720,7088373760000,3600,1300,1400,1200,1300,0,0,0,0 +525,Ring,5,21,2621440,14176747520000,3600,1300,1400,1200,1300,0,0,0,0 diff --git a/Lib9c/TableCSV/Item/EquipmentItemSheet.csv b/Lib9c/TableCSV/Item/EquipmentItemSheet.csv index 18ed960a0a..f31ffe1526 100644 --- a/Lib9c/TableCSV/Item/EquipmentItemSheet.csv +++ b/Lib9c/TableCSV/Item/EquipmentItemSheet.csv @@ -1,177 +1,177 @@ -id,_name,item_sub_type,grade,elemental_type,set_id,stat_type,stat_value,attack_range,spine_resource_path -10100000,나뭇가지,Weapon,0,Normal,0,ATK,1,2,10100000 -10110000,검,Weapon,1,Normal,1,ATK,11,2,10110000 -10111000,롱 소드(불),Weapon,1,Fire,2,ATK,14,2,10111000 -10112000,롱 소드(물),Weapon,1,Water,3,ATK,17,2,10112000 -10113000,롱 소드(땅),Weapon,1,Land,4,ATK,55,2,10113000 -10114000,롱 소드(바람),Weapon,1,Wind,5,ATK,136,2,10114000 -10120000,검투사 검,Weapon,2,Normal,6,ATK,31,2,10120000 -10121000,검투사 검(불),Weapon,2,Fire,7,ATK,32,2,10121000 -10122000,검투사 검(물),Weapon,2,Water,8,ATK,38,2,10122000 -10123000,검투사 검(땅),Weapon,2,Land,9,ATK,152,2,10123000 -10124000,검투사 검(바람),Weapon,2,Wind,10,ATK,327,2,10124000 -10130000,까마귀의 검,Weapon,3,Normal,11,ATK,78,2,10130000 -10131000,까마귀의 검(불),Weapon,3,Fire,12,ATK,81,2,10131000 -10132000,까마귀의 검(물),Weapon,3,Water,13,ATK,92,2,10132000 -10133000,까마귀의 검(땅),Weapon,3,Land,14,ATK,354,2,10133000 -10134000,까마귀의 검(바람),Weapon,3,Wind,15,ATK,693,2,10134000 -10130001,무거운 검,Weapon,3,Normal,11,ATK,170,2,10130001 -10131001,무거운 검(불),Weapon,3,Fire,12,ATK,179,2,10131001 -10132001,무거운 검(물),Weapon,3,Water,13,ATK,196,2,10132001 -10133001,무거운 검(땅),Weapon,3,Land,14,ATK,908,2,10133001 -10134001,무거운 검(바람),Weapon,3,Wind,15,ATK,967,2,10134001 -10140000,전쟁 검,Weapon,4,Normal,11,ATK,3094,2,10140000 -10141000,전쟁 검(불),Weapon,4,Fire,12,ATK,1934,2,10141000 -10142000,전쟁 검(물),Weapon,4,Water,13,ATK,2224,2,10142000 -10143000,전쟁 검(땅),Weapon,4,Land,14,ATK,2514,2,10143000 -10144000,전쟁 검(바람),Weapon,4,Wind,15,ATK,2804,2,10144000 -10150000,다인슬레이프,Weapon,5,Normal,16,ATK,6063,2,10150000 -10151000,다인슬레이프(불),Weapon,5,Fire,17,ATK,4331,2,10151000 -10152000,다인슬레이프(물),Weapon,5,Water,18,ATK,4331,2,10152000 -10153000,다인슬레이프(땅),Weapon,5,Land,19,ATK,6063,2,10153000 -10154000,다인슬레이프(바람),Weapon,5,Wind,20,ATK,6063,2,10154000 -10140001,아스가르드의 검,Weapon,5,Normal,11,ATK,765,2,10140001 -10141001,아스가르드의 검(불),Weapon,5,Fire,12,ATK,782,2,10141001 -10142001,아스가르드의 검(물),Weapon,5,Water,13,ATK,798,2,10142001 -10143001,아스가르드의 검(땅),Weapon,5,Land,14,ATK,1221,2,10143001 -10144001,아스가르드의 검(바람),Weapon,5,Wind,15,ATK,1525,2,10144001 -10150001,수르트의 검,Weapon,5,Normal,16,ATK,2157,2,10150001 -10151001,수르트의 검(불),Weapon,5,Fire,17,ATK,2190,2,10151001 -10152001,수르트의 검(물),Weapon,5,Water,18,ATK,2223,2,10152001 -10153001,수르트의 검(땅),Weapon,5,Land,19,ATK,3390,2,10153001 -10154001,수르트의 검(바람),Weapon,5,Wind,20,ATK,4219,2,10154001 -10155000,발키리의 검,Weapon,5,Normal,15,ATK,2902,2,10155000 -10200000,누더기 옷,Armor,0,Normal,0,HP,30,2,Character/Player/10200000 -10210000,옷,Armor,1,Normal,1,HP,180,2,Character/Player/10210000 -10211000,천 옷(불),Armor,1,Fire,2,HP,222,2,Character/Player/10211000 -10212000,천 옷(물),Armor,1,Water,3,HP,288,2,Character/Player/10212000 -10213000,천 옷(땅),Armor,1,Land,4,HP,915,2,Character/Player/10213000 -10214000,천 옷(바람),Armor,1,Wind,5,HP,2182,2,Character/Player/10214000 -10220000,가죽 옷,Armor,2,Normal,6,HP,531,2,Character/Player/10220000 -10221000,가죽 옷(불),Armor,2,Fire,7,HP,549,2,Character/Player/10221000 -10222000,가죽 옷(물),Armor,2,Water,8,HP,621,2,Character/Player/10222000 -10223000,가죽 옷(땅),Armor,2,Land,9,HP,2431,2,Character/Player/10223000 -10224000,가죽 옷(바람),Armor,2,Wind,10,HP,5109,2,Character/Player/10224000 -10230000,검은 까마귀의 갑옷,Armor,3,Normal,11,HP,1337,2,Character/Player/10230000 -10231000,검은 까마귀의 갑옷(불),Armor,3,Fire,12,HP,1418,2,Character/Player/10231000 -10232000,검은 까마귀의 갑옷(물),Armor,3,Water,13,HP,1580,2,Character/Player/10232000 -10233000,검은 까마귀의 갑옷(땅),Armor,3,Land,14,HP,8370,2,Character/Player/10233000 -10234000,검은 까마귀의 갑옷(바람),Armor,3,Wind,15,HP,10571,2,Character/Player/10234000 -10230001,헤르메스의 옷,Armor,3,Normal,11,HP,2811,2,Character/Player/10230001 -10231001,헤르메스의 옷(불),Armor,3,Fire,12,HP,3009,2,Character/Player/10231001 -10232001,헤르메스의 옷(물),Armor,3,Water,13,HP,3141,2,Character/Player/10232001 -10233001,헤르메스의 옷(땅),Armor,3,Land,14,HP,11482,2,Character/Player/10233001 -10234001,헤르메스의 옷(바람),Armor,3,Wind,15,HP,12302,2,Character/Player/10234001 -10240000,전쟁 갑옷,Armor,4,Normal,11,HP,34446,2,Character/Player/10240000 -10241000,전쟁 갑옷(불),Armor,4,Fire,12,HP,24604,2,Character/Player/10241000 -10242000,전쟁 갑옷(물),Armor,4,Water,13,HP,27064,2,Character/Player/10242000 -10243000,전쟁 갑옷(땅),Armor,4,Land,14,HP,29525,2,Character/Player/10243000 -10244000,전쟁 갑옷(바람),Armor,4,Wind,15,HP,31985,2,Character/Player/10244000 -10250001,고대의 갑옷,Armor,5,Normal,11,HP,67513,2,Character/Player/10250001 -10251001,고대의 갑옷(불),Armor,5,Fire,12,HP,48224,2,Character/Player/10251001 -10252001,고대의 갑옷(물),Armor,5,Water,13,HP,48224,2,Character/Player/10252001 -10253001,고대의 갑옷(땅),Armor,5,Land,14,HP,67513,2,Character/Player/10253001 -10254001,고대의 갑옷(바람),Armor,5,Wind,15,HP,67513,2,Character/Player/10254001 -10250000,전설의 갑옷,Armor,5,Normal,11,HP,15550,2,Character/Player/10250000 -10251000,전설의 갑옷(불),Armor,5,Fire,12,HP,15848,2,Character/Player/10251000 -10252000,전설의 갑옷(물),Armor,5,Water,13,HP,16146,2,Character/Player/10252000 -10253000,전설의 갑옷(땅),Armor,5,Land,14,HP,24665,2,Character/Player/10253000 -10254000,전설의 갑옷(바람),Armor,5,Wind,15,HP,30823,2,Character/Player/10254000 -10240001,아스가르드의 갑옷,Armor,5,Normal,11,HP,10358,2,Character/Player/10240001 -10241001,아스가르드의 갑옷(불),Armor,5,Fire,12,HP,10571,2,Character/Player/10241001 -10242001,아스가르드의 갑옷(물),Armor,5,Water,13,HP,10783,2,Character/Player/10242001 -10243001,아스가르드의 갑옷(땅),Armor,5,Land,14,HP,16494,2,Character/Player/10243001 -10244001,아스가르드의 갑옷(바람),Armor,5,Wind,15,HP,20647,2,Character/Player/10244001 -10255000,천상의 고양이,Armor,5,Normal,11,HP,42856,2,Character/Player/10235000 -10310000,허리끈,Belt,1,Normal,1,SPD,46,2,10310000 -10311000,허리끈(불),Belt,1,Fire,2,SPD,62,2,10311000 -10312000,허리끈(물),Belt,1,Water,3,SPD,69,2,10312000 -10313000,허리끈(땅),Belt,1,Land,4,SPD,239,2,10313000 -10314000,허리끈(바람),Belt,1,Wind,5,SPD,610,2,10314000 -10320000,가죽 벨트,Belt,2,Normal,6,SPD,137,2,10320000 -10321000,가죽 벨트(불),Belt,2,Fire,7,SPD,141,2,10321000 -10322000,가죽 벨트(물),Belt,2,Water,8,SPD,166,2,10322000 -10323000,가죽 벨트(땅),Belt,2,Land,9,SPD,718,2,10323000 -10324000,가죽 벨트(바람),Belt,2,Wind,10,SPD,1314,2,10324000 -10330000,견고한 벨트,Belt,3,Normal,11,SPD,350,2,10330000 -10331000,견고한 벨트(불),Belt,3,Fire,12,SPD,359,2,10331000 -10332000,견고한 벨트(물),Belt,3,Water,13,SPD,425,2,10332000 -10333000,견고한 벨트(땅),Belt,3,Land,14,SPD,1701,2,10333000 -10334000,견고한 벨트(바람),Belt,3,Wind,15,SPD,2883,2,10334000 -10340000,전쟁 벨트,Belt,4,Normal,11,SPD,1215,2,10340000 -10341000,전쟁 벨트(불),Belt,4,Fire,12,SPD,1262,2,10341000 -10342000,전쟁 벨트(물),Belt,4,Water,13,SPD,2292,2,10342000 -10343000,전쟁 벨트(땅),Belt,4,Land,14,SPD,2292,2,10343000 -10344000,전쟁 벨트(바람),Belt,4,Wind,15,SPD,2292,2,10344000 -10350000,전설의 벨트,Belt,4,Normal,11,SPD,7334,2,10350000 -10351000,전설의 벨트(불),Belt,4,Fire,12,SPD,4584,2,10351000 -10352000,전설의 벨트(물),Belt,4,Water,13,SPD,5272,2,10352000 -10353000,전설의 벨트(땅),Belt,4,Land,14,SPD,5959,2,10353000 -10354000,전설의 벨트(바람),Belt,4,Wind,15,SPD,6647,2,10354000 -10350001,고대의 벨트,Belt,5,Normal,15,SPD,14373,2,10350000 -10351001,고대의 벨트(불),Belt,5,Fire,15,SPD,10267,2,10351000 -10352001,고대의 벨트(물),Belt,5,Water,15,SPD,10267,2,10352000 -10353001,고대의 벨트(땅),Belt,5,Land,15,SPD,14373,2,10353000 -10354001,고대의 벨트(바람),Belt,5,Wind,15,SPD,14373,2,10354000 -10410000,얇은 목걸이,Necklace,1,Normal,1,HIT,70,0,10410000 -10411000,얇은 목걸이(불),Necklace,1,Fire,2,HIT,81,0,10411000 -10412000,얇은 목걸이(물),Necklace,1,Water,3,HIT,99,0,10412000 -10413000,얇은 목걸이(땅),Necklace,1,Land,4,HIT,357,0,10413000 -10414000,얇은 목걸이(바람),Necklace,1,Wind,5,HIT,863,0,10414000 -10420000,수호의 목걸이,Necklace,2,Normal,6,HIT,192,0,10420000 -10421000,수호의 목걸이(불),Necklace,2,Fire,7,HIT,197,0,10421000 -10422000,수호의 목걸이(물),Necklace,2,Water,8,HIT,230,0,10422000 -10423000,수호의 목걸이(땅),Necklace,2,Land,9,HIT,1002,0,10423000 -10424000,수호의 목걸이(바람),Necklace,2,Wind,10,HIT,1682,0,10424000 -10430000,마력의 목걸이,Necklace,3,Normal,11,HIT,510,0,10430000 -10431000,마력의 목걸이(불),Necklace,3,Fire,12,HIT,522,0,10431000 -10432000,마력의 목걸이(물),Necklace,3,Water,13,HIT,608,0,10432000 -10433000,마력의 목걸이(땅),Necklace,3,Land,14,HIT,2151,0,10433000 -10434000,마력의 목걸이(바람),Necklace,3,Wind,15,HIT,2333,0,10434000 -10440000,전사의 목걸이,Necklace,4,Normal,11,HIT,2031,0,10440000 -10441000,전사의 목걸이(불),Necklace,4,Fire,12,HIT,3047,0,10441000 -10442000,전사의 목걸이(물),Necklace,4,Water,13,HIT,3047,0,10442000 -10443000,전사의 목걸이(땅),Necklace,4,Land,14,HIT,3047,0,10443000 -10444000,전사의 목걸이(바람),Necklace,4,Wind,15,HIT,3047,0,10444000 -10450000,전설의 목걸이,Necklace,4,Normal,11,HIT,7466,0,10450000 -10451000,전설의 목걸이(불),Necklace,4,Fire,12,HIT,4666,0,10451000 -10452000,전설의 목걸이(물),Necklace,4,Water,13,HIT,5366,0,10452000 -10453000,전설의 목걸이(땅),Necklace,4,Land,14,HIT,6066,0,10453000 -10454000,전설의 목걸이(바람),Necklace,4,Wind,15,HIT,6766,0,10454000 -10450001,고대의 목걸이,Necklace,5,Normal,15,HIT,15363,0,10450000 -10451001,고대의 목걸이(불),Necklace,5,Fire,15,HIT,10452,0,10451000 -10452001,고대의 목걸이(물),Necklace,5,Water,15,HIT,10452,0,10452000 -10453001,고대의 목걸이(땅),Necklace,5,Land,15,HIT,15363,0,10453000 -10454001,고대의 목걸이(바람),Necklace,5,Wind,15,HIT,15363,0,10454000 -10510000,얇은 반지,Ring,1,Normal,1,DEF,8,0,10510000 -10511000,얇은 반지(불),Ring,1,Fire,2,DEF,9,0,10511000 -10512000,얇은 반지(물),Ring,1,Water,3,DEF,11,0,10512000 -10513000,얇은 반지(땅),Ring,1,Land,4,DEF,44,0,10513000 -10514000,얇은 반지(바람),Ring,1,Wind,5,DEF,107,0,10514000 -10520000,수호의 반지,Ring,2,Normal,6,DEF,23,0,10520000 -10521000,수호의 반지(불),Ring,2,Fire,7,DEF,24,0,10521000 -10522000,수호의 반지(물),Ring,2,Water,8,DEF,29,0,10522000 -10523000,수호의 반지(땅),Ring,2,Land,9,DEF,122,0,10523000 -10524000,수호의 반지(바람),Ring,2,Wind,10,DEF,189,0,10524000 -10530000,마나 반지,Ring,3,Normal,11,DEF,63,0,10530000 -10531000,마나 반지(불),Ring,3,Fire,12,DEF,65,0,10531000 -10532000,마나 반지(물),Ring,3,Water,13,DEF,74,0,10532000 -10533000,마나 반지(땅),Ring,3,Land,14,DEF,251,0,10533000 -10534000,마나 반지(바람),Ring,3,Wind,15,DEF,270,0,10534000 -10540000,전사의 반지,Ring,4,Normal,11,DEF,864,0,10540000 -10541000,전사의 반지(불),Ring,4,Fire,12,DEF,540,0,10541000 -10542000,전사의 반지(물),Ring,4,Water,13,DEF,621,0,10542000 -10543000,전사의 반지(땅),Ring,4,Land,14,DEF,702,0,10543000 -10544000,전사의 반지(바람),Ring,4,Wind,15,DEF,783,0,10544000 -10550000,고대의 반지,Ring,5,Normal,11,DEF,1946,0,10550000 -10551000,고대의 반지(불),Ring,5,Fire,12,DEF,1209,0,10551000 -10552000,고대의 반지(물),Ring,5,Water,13,DEF,1209,0,10552000 -10553000,고대의 반지(땅),Ring,5,Land,14,DEF,1946,0,10553000 -10554000,고대의 반지(바람),Ring,5,Wind,15,DEF,1946,0,10554000 -11320000,블루 사파이어 벨트,Belt,2,Normal,6,SPD,176,2,11320000 -11420000,블루 사파이어 목걸이,Necklace,2,Normal,6,HIT,227,0,11420000 -11520000,블루 사파이어 반지,Ring,2,Normal,6,DEF,50,0,11520000 -12001001,Special Crystal Belt,Belt,2,Normal,0,ATK,1,0,12001001 -12001002,Special Crystal Necklace,Necklace,3,Normal,1,ATK,1,0,12001002 -12001003,Special Crystal Ring,Ring,4,Normal,2,ATK,1,0,12001003 -13001000,Aura,Aura,0,Normal,0,ATK,1,0,10100000 +id,_name,item_sub_type,grade,elemental_type,set_id,stat_type,stat_value,attack_range,spine_resource_path,exp +10100000,나뭇가지,Weapon,0,Normal,0,ATK,1,2,10100000,0 +10110000,검,Weapon,1,Normal,1,ATK,11,2,10110000,10 +10111000,롱 소드(불),Weapon,1,Fire,2,ATK,14,2,10111000,10 +10112000,롱 소드(물),Weapon,1,Water,3,ATK,17,2,10112000,10 +10113000,롱 소드(땅),Weapon,1,Land,4,ATK,55,2,10113000,10 +10114000,롱 소드(바람),Weapon,1,Wind,5,ATK,136,2,10114000,10 +10120000,검투사 검,Weapon,2,Normal,6,ATK,31,2,10120000,80 +10121000,검투사 검(불),Weapon,2,Fire,7,ATK,32,2,10121000,80 +10122000,검투사 검(물),Weapon,2,Water,8,ATK,38,2,10122000,80 +10123000,검투사 검(땅),Weapon,2,Land,9,ATK,152,2,10123000,80 +10124000,검투사 검(바람),Weapon,2,Wind,10,ATK,327,2,10124000,80 +10130000,까마귀의 검,Weapon,3,Normal,11,ATK,78,2,10130000,16020 +10131000,까마귀의 검(불),Weapon,3,Fire,12,ATK,81,2,10131000,16020 +10132000,까마귀의 검(물),Weapon,3,Water,13,ATK,92,2,10132000,16020 +10133000,까마귀의 검(땅),Weapon,3,Land,14,ATK,354,2,10133000,16020 +10134000,까마귀의 검(바람),Weapon,3,Wind,15,ATK,693,2,10134000,16020 +10130001,무거운 검,Weapon,3,Normal,11,ATK,170,2,10130001,16020 +10131001,무거운 검(불),Weapon,3,Fire,12,ATK,179,2,10131001,16020 +10132001,무거운 검(물),Weapon,3,Water,13,ATK,196,2,10132001,16020 +10133001,무거운 검(땅),Weapon,3,Land,14,ATK,908,2,10133001,16020 +10134001,무거운 검(바람),Weapon,3,Wind,15,ATK,967,2,10134001,16020 +10140000,전쟁 검,Weapon,4,Normal,11,ATK,3094,2,10140000,426000 +10141000,전쟁 검(불),Weapon,4,Fire,12,ATK,1934,2,10141000,426000 +10142000,전쟁 검(물),Weapon,4,Water,13,ATK,2224,2,10142000,426000 +10143000,전쟁 검(땅),Weapon,4,Land,14,ATK,2514,2,10143000,426000 +10144000,전쟁 검(바람),Weapon,4,Wind,15,ATK,2804,2,10144000,426000 +10150000,다인슬레이프,Weapon,5,Normal,16,ATK,6063,2,10150000,6760000 +10151000,다인슬레이프(불),Weapon,5,Fire,17,ATK,4331,2,10151000,6760000 +10152000,다인슬레이프(물),Weapon,5,Water,18,ATK,4331,2,10152000,6760000 +10153000,다인슬레이프(땅),Weapon,5,Land,19,ATK,6063,2,10153000,6760000 +10154000,다인슬레이프(바람),Weapon,5,Wind,20,ATK,6063,2,10154000,6760000 +10140001,아스가르드의 검,Weapon,5,Normal,11,ATK,765,2,10140001,6760000 +10141001,아스가르드의 검(불),Weapon,5,Fire,12,ATK,782,2,10141001,6760000 +10142001,아스가르드의 검(물),Weapon,5,Water,13,ATK,798,2,10142001,6760000 +10143001,아스가르드의 검(땅),Weapon,5,Land,14,ATK,1221,2,10143001,6760000 +10144001,아스가르드의 검(바람),Weapon,5,Wind,15,ATK,1525,2,10144001,6760000 +10150001,수르트의 검,Weapon,5,Normal,16,ATK,2157,2,10150001,6760000 +10151001,수르트의 검(불),Weapon,5,Fire,17,ATK,2190,2,10151001,6760000 +10152001,수르트의 검(물),Weapon,5,Water,18,ATK,2223,2,10152001,6760000 +10153001,수르트의 검(땅),Weapon,5,Land,19,ATK,3390,2,10153001,6760000 +10154001,수르트의 검(바람),Weapon,5,Wind,20,ATK,4219,2,10154001,6760000 +10155000,발키리의 검,Weapon,5,Normal,15,ATK,2902,2,10155000,6760000 +10200000,누더기 옷,Armor,0,Normal,0,HP,30,2,Character/Player/10200000,0 +10210000,옷,Armor,1,Normal,1,HP,180,2,Character/Player/10210000,19 +10211000,천 옷(불),Armor,1,Fire,2,HP,222,2,Character/Player/10211000,19 +10212000,천 옷(물),Armor,1,Water,3,HP,288,2,Character/Player/10212000,19 +10213000,천 옷(땅),Armor,1,Land,4,HP,915,2,Character/Player/10213000,19 +10214000,천 옷(바람),Armor,1,Wind,5,HP,2182,2,Character/Player/10214000,19 +10220000,가죽 옷,Armor,2,Normal,6,HP,531,2,Character/Player/10220000,103 +10221000,가죽 옷(불),Armor,2,Fire,7,HP,549,2,Character/Player/10221000,103 +10222000,가죽 옷(물),Armor,2,Water,8,HP,621,2,Character/Player/10222000,103 +10223000,가죽 옷(땅),Armor,2,Land,9,HP,2431,2,Character/Player/10223000,103 +10224000,가죽 옷(바람),Armor,2,Wind,10,HP,5109,2,Character/Player/10224000,103 +10230000,검은 까마귀의 갑옷,Armor,3,Normal,11,HP,1337,2,Character/Player/10230000,9600 +10231000,검은 까마귀의 갑옷(불),Armor,3,Fire,12,HP,1418,2,Character/Player/10231000,9600 +10232000,검은 까마귀의 갑옷(물),Armor,3,Water,13,HP,1580,2,Character/Player/10232000,9600 +10233000,검은 까마귀의 갑옷(땅),Armor,3,Land,14,HP,8370,2,Character/Player/10233000,9600 +10234000,검은 까마귀의 갑옷(바람),Armor,3,Wind,15,HP,10571,2,Character/Player/10234000,9600 +10230001,헤르메스의 옷,Armor,3,Normal,11,HP,2811,2,Character/Player/10230001,9600 +10231001,헤르메스의 옷(불),Armor,3,Fire,12,HP,3009,2,Character/Player/10231001,9600 +10232001,헤르메스의 옷(물),Armor,3,Water,13,HP,3141,2,Character/Player/10232001,9600 +10233001,헤르메스의 옷(땅),Armor,3,Land,14,HP,11482,2,Character/Player/10233001,9600 +10234001,헤르메스의 옷(바람),Armor,3,Wind,15,HP,12302,2,Character/Player/10234001,9600 +10240000,전쟁 갑옷,Armor,4,Normal,11,HP,34446,2,Character/Player/10240000,426000 +10241000,전쟁 갑옷(불),Armor,4,Fire,12,HP,24604,2,Character/Player/10241000,426000 +10242000,전쟁 갑옷(물),Armor,4,Water,13,HP,27064,2,Character/Player/10242000,426000 +10243000,전쟁 갑옷(땅),Armor,4,Land,14,HP,29525,2,Character/Player/10243000,426000 +10244000,전쟁 갑옷(바람),Armor,4,Wind,15,HP,31985,2,Character/Player/10244000,426000 +10250001,고대의 갑옷,Armor,5,Normal,11,HP,67513,2,Character/Player/10250001,6760000 +10251001,고대의 갑옷(불),Armor,5,Fire,12,HP,48224,2,Character/Player/10251001,6760000 +10252001,고대의 갑옷(물),Armor,5,Water,13,HP,48224,2,Character/Player/10252001,6760000 +10253001,고대의 갑옷(땅),Armor,5,Land,14,HP,67513,2,Character/Player/10253001,6760000 +10254001,고대의 갑옷(바람),Armor,5,Wind,15,HP,67513,2,Character/Player/10254001,6760000 +10250000,전설의 갑옷,Armor,5,Normal,11,HP,15550,2,Character/Player/10250000,6760000 +10251000,전설의 갑옷(불),Armor,5,Fire,12,HP,15848,2,Character/Player/10251000,6760000 +10252000,전설의 갑옷(물),Armor,5,Water,13,HP,16146,2,Character/Player/10252000,6760000 +10253000,전설의 갑옷(땅),Armor,5,Land,14,HP,24665,2,Character/Player/10253000,6760000 +10254000,전설의 갑옷(바람),Armor,5,Wind,15,HP,30823,2,Character/Player/10254000,6760000 +10240001,아스가르드의 갑옷,Armor,5,Normal,11,HP,10358,2,Character/Player/10240001,6760000 +10241001,아스가르드의 갑옷(불),Armor,5,Fire,12,HP,10571,2,Character/Player/10241001,6760000 +10242001,아스가르드의 갑옷(물),Armor,5,Water,13,HP,10783,2,Character/Player/10242001,6760000 +10243001,아스가르드의 갑옷(땅),Armor,5,Land,14,HP,16494,2,Character/Player/10243001,6760000 +10244001,아스가르드의 갑옷(바람),Armor,5,Wind,15,HP,20647,2,Character/Player/10244001,6760000 +10255000,천상의 고양이,Armor,5,Normal,11,HP,42856,2,Character/Player/10235000,6760000 +10310000,허리끈,Belt,1,Normal,1,SPD,46,2,10310000,954 +10311000,허리끈(불),Belt,1,Fire,2,SPD,62,2,10311000,954 +10312000,허리끈(물),Belt,1,Water,3,SPD,69,2,10312000,954 +10313000,허리끈(땅),Belt,1,Land,4,SPD,239,2,10313000,954 +10314000,허리끈(바람),Belt,1,Wind,5,SPD,610,2,10314000,954 +10320000,가죽 벨트,Belt,2,Normal,6,SPD,137,2,10320000,1496 +10321000,가죽 벨트(불),Belt,2,Fire,7,SPD,141,2,10321000,1496 +10322000,가죽 벨트(물),Belt,2,Water,8,SPD,166,2,10322000,1496 +10323000,가죽 벨트(땅),Belt,2,Land,9,SPD,718,2,10323000,1496 +10324000,가죽 벨트(바람),Belt,2,Wind,10,SPD,1314,2,10324000,1496 +10330000,견고한 벨트,Belt,3,Normal,11,SPD,350,2,10330000,3864 +10331000,견고한 벨트(불),Belt,3,Fire,12,SPD,359,2,10331000,3864 +10332000,견고한 벨트(물),Belt,3,Water,13,SPD,425,2,10332000,3864 +10333000,견고한 벨트(땅),Belt,3,Land,14,SPD,1701,2,10333000,3864 +10334000,견고한 벨트(바람),Belt,3,Wind,15,SPD,2883,2,10334000,3864 +10340000,전쟁 벨트,Belt,4,Normal,11,SPD,1215,2,10340000,96600 +10341000,전쟁 벨트(불),Belt,4,Fire,12,SPD,1262,2,10341000,96600 +10342000,전쟁 벨트(물),Belt,4,Water,13,SPD,2292,2,10342000,96600 +10343000,전쟁 벨트(땅),Belt,4,Land,14,SPD,2292,2,10343000,96600 +10344000,전쟁 벨트(바람),Belt,4,Wind,15,SPD,2292,2,10344000,96600 +10350000,전설의 벨트,Belt,4,Normal,11,SPD,7334,2,10350000,96600 +10351000,전설의 벨트(불),Belt,4,Fire,12,SPD,4584,2,10351000,96600 +10352000,전설의 벨트(물),Belt,4,Water,13,SPD,5272,2,10352000,96600 +10353000,전설의 벨트(땅),Belt,4,Land,14,SPD,5959,2,10353000,96600 +10354000,전설의 벨트(바람),Belt,4,Wind,15,SPD,6647,2,10354000,96600 +10350001,고대의 벨트,Belt,5,Normal,15,SPD,14373,2,10350000,6760000 +10351001,고대의 벨트(불),Belt,5,Fire,15,SPD,10267,2,10351000,6760000 +10352001,고대의 벨트(물),Belt,5,Water,15,SPD,10267,2,10352000,6760000 +10353001,고대의 벨트(땅),Belt,5,Land,15,SPD,14373,2,10353000,6760000 +10354001,고대의 벨트(바람),Belt,5,Wind,15,SPD,14373,2,10354000,6760000 +10410000,얇은 목걸이,Necklace,1,Normal,1,HIT,70,0,10410000,315 +10411000,얇은 목걸이(불),Necklace,1,Fire,2,HIT,81,0,10411000,315 +10412000,얇은 목걸이(물),Necklace,1,Water,3,HIT,99,0,10412000,315 +10413000,얇은 목걸이(땅),Necklace,1,Land,4,HIT,357,0,10413000,315 +10414000,얇은 목걸이(바람),Necklace,1,Wind,5,HIT,863,0,10414000,315 +10420000,수호의 목걸이,Necklace,2,Normal,6,HIT,192,0,10420000,1736 +10421000,수호의 목걸이(불),Necklace,2,Fire,7,HIT,197,0,10421000,1736 +10422000,수호의 목걸이(물),Necklace,2,Water,8,HIT,230,0,10422000,1736 +10423000,수호의 목걸이(땅),Necklace,2,Land,9,HIT,1002,0,10423000,1736 +10424000,수호의 목걸이(바람),Necklace,2,Wind,10,HIT,1682,0,10424000,1736 +10430000,마력의 목걸이,Necklace,3,Normal,11,HIT,510,0,10430000,65040 +10431000,마력의 목걸이(불),Necklace,3,Fire,12,HIT,522,0,10431000,65040 +10432000,마력의 목걸이(물),Necklace,3,Water,13,HIT,608,0,10432000,65040 +10433000,마력의 목걸이(땅),Necklace,3,Land,14,HIT,2151,0,10433000,65040 +10434000,마력의 목걸이(바람),Necklace,3,Wind,15,HIT,2333,0,10434000,65040 +10440000,전사의 목걸이,Necklace,4,Normal,11,HIT,2031,0,10440000,243000 +10441000,전사의 목걸이(불),Necklace,4,Fire,12,HIT,3047,0,10441000,243000 +10442000,전사의 목걸이(물),Necklace,4,Water,13,HIT,3047,0,10442000,243000 +10443000,전사의 목걸이(땅),Necklace,4,Land,14,HIT,3047,0,10443000,243000 +10444000,전사의 목걸이(바람),Necklace,4,Wind,15,HIT,3047,0,10444000,243000 +10450000,전설의 목걸이,Necklace,4,Normal,11,HIT,7466,0,10450000,243000 +10451000,전설의 목걸이(불),Necklace,4,Fire,12,HIT,4666,0,10451000,243000 +10452000,전설의 목걸이(물),Necklace,4,Water,13,HIT,5366,0,10452000,243000 +10453000,전설의 목걸이(땅),Necklace,4,Land,14,HIT,6066,0,10453000,243000 +10454000,전설의 목걸이(바람),Necklace,4,Wind,15,HIT,6766,0,10454000,243000 +10450001,고대의 목걸이,Necklace,5,Normal,15,HIT,15363,0,10450000,6760000 +10451001,고대의 목걸이(불),Necklace,5,Fire,15,HIT,10452,0,10451000,6760000 +10452001,고대의 목걸이(물),Necklace,5,Water,15,HIT,10452,0,10452000,6760000 +10453001,고대의 목걸이(땅),Necklace,5,Land,15,HIT,15363,0,10453000,6760000 +10454001,고대의 목걸이(바람),Necklace,5,Wind,15,HIT,15363,0,10454000,6760000 +10510000,얇은 반지,Ring,1,Normal,1,DEF,8,0,10510000,10 +10511000,얇은 반지(불),Ring,1,Fire,2,DEF,9,0,10511000,10 +10512000,얇은 반지(물),Ring,1,Water,3,DEF,11,0,10512000,10 +10513000,얇은 반지(땅),Ring,1,Land,4,DEF,44,0,10513000,10 +10514000,얇은 반지(바람),Ring,1,Wind,5,DEF,107,0,10514000,10 +10520000,수호의 반지,Ring,2,Normal,6,DEF,23,0,10520000,216 +10521000,수호의 반지(불),Ring,2,Fire,7,DEF,24,0,10521000,216 +10522000,수호의 반지(물),Ring,2,Water,8,DEF,29,0,10522000,216 +10523000,수호의 반지(땅),Ring,2,Land,9,DEF,122,0,10523000,216 +10524000,수호의 반지(바람),Ring,2,Wind,10,DEF,189,0,10524000,216 +10530000,마나 반지,Ring,3,Normal,11,DEF,63,0,10530000,5568 +10531000,마나 반지(불),Ring,3,Fire,12,DEF,65,0,10531000,5568 +10532000,마나 반지(물),Ring,3,Water,13,DEF,74,0,10532000,5568 +10533000,마나 반지(땅),Ring,3,Land,14,DEF,251,0,10533000,5568 +10534000,마나 반지(바람),Ring,3,Wind,15,DEF,270,0,10534000,5568 +10540000,전사의 반지,Ring,4,Normal,11,DEF,864,0,10540000,426000 +10541000,전사의 반지(불),Ring,4,Fire,12,DEF,540,0,10541000,426000 +10542000,전사의 반지(물),Ring,4,Water,13,DEF,621,0,10542000,426000 +10543000,전사의 반지(땅),Ring,4,Land,14,DEF,702,0,10543000,426000 +10544000,전사의 반지(바람),Ring,4,Wind,15,DEF,783,0,10544000,426000 +10550000,고대의 반지,Ring,5,Normal,11,DEF,1946,0,10550000,6760000 +10551000,고대의 반지(불),Ring,5,Fire,12,DEF,1209,0,10551000,6760000 +10552000,고대의 반지(물),Ring,5,Water,13,DEF,1209,0,10552000,6760000 +10553000,고대의 반지(땅),Ring,5,Land,14,DEF,1946,0,10553000,6760000 +10554000,고대의 반지(바람),Ring,5,Wind,15,DEF,1946,0,10554000,6760000 +11320000,블루 사파이어 벨트,Belt,2,Normal,6,SPD,176,2,11320000,1496 +11420000,블루 사파이어 목걸이,Necklace,2,Normal,6,HIT,227,0,11420000,1736 +11520000,블루 사파이어 반지,Ring,2,Normal,6,DEF,50,0,11520000,216 +12001001,Special Crystal Belt,Belt,2,Normal,0,ATK,1,0,12001001,1496 +12001002,Special Crystal Necklace,Necklace,3,Normal,1,ATK,1,0,12001002,65040 +12001003,Special Crystal Ring,Ring,4,Normal,2,ATK,1,0,12001003,426000 +13001000,Aura,Aura,0,Normal,0,ATK,1,0,10100000,0 diff --git a/Lib9c/TableCSV/Item/EquipmentItemUpgradePoint.csv b/Lib9c/TableCSV/Item/EquipmentItemUpgradePoint.csv deleted file mode 100644 index 904e4774c3..0000000000 --- a/Lib9c/TableCSV/Item/EquipmentItemUpgradePoint.csv +++ /dev/null @@ -1,111 +0,0 @@ -ID,item_sub_type,level,Normal,Rare,Epic,Unique,Legend -1000,Weapon,0,10,80,16020,426000,6760000 -1001,Weapon,1,20,160,32040,852000,13520000 -1002,Weapon,2,40,320,64080,1704000,27040000 -1003,Weapon,3,80,640,128160,3408000,54080000 -1004,Weapon,4,160,1280,256320,6816000,108160000 -1005,Weapon,5,320,2560,512640,13632000,216320000 -1006,Weapon,6,640,5120,1025280,27264000,432640000 -1007,Weapon,7,1280,10240,2050560,54528000,865280000 -1008,Weapon,8,2560,20480,4101120,109056000,1730560000 -1009,Weapon,9,5120,40960,8202240,218112000,3461120000 -1010,Weapon,10,10240,81920,16404480,436224000,6922240000 -1011,Weapon,11,20480,163840,32808960,872448000,13844480000 -1012,Weapon,12,40960,327680,65617920,1744896000,27688960000 -1013,Weapon,13,81920,655360,131235840,3489792000,55377920000 -1014,Weapon,14,163840,1310720,262471680,6979584000,110755840000 -1015,Weapon,15,327680,2621440,524943360,13959168000,221511680000 -1016,Weapon,16,655360,5242880,1049886720,27918336000,443023360000 -1017,Weapon,17,1310720,10485760,2099773440,55836672000,886046720000 -1018,Weapon,18,2621440,20971520,4199546880,111673344000,1772093440000 -1019,Weapon,19,5242880,41943040,8399093760,223346688000,3544186880000 -1020,Weapon,20,10485760,83886080,16798187520,446693376000,7088373760000 -1021,Weapon,21,20971520,167772160,33596375040,893386752000,14176747520000 -2000,Armor,0,19,103,9600,426000,6760000 -2001,Armor,1,38,206,19200,852000,13520000 -2002,Armor,2,76,412,38400,1704000,27040000 -2003,Armor,3,152,824,76800,3408000,54080000 -2004,Armor,4,304,1648,153600,6816000,108160000 -2005,Armor,5,608,3296,307200,13632000,216320000 -2006,Armor,6,1216,6592,614400,27264000,432640000 -2007,Armor,7,2432,13184,1228800,54528000,865280000 -2008,Armor,8,4864,26368,2457600,109056000,1730560000 -2009,Armor,9,9728,52736,4915200,218112000,3461120000 -2010,Armor,10,19456,105472,9830400,436224000,6922240000 -2011,Armor,11,38912,210944,19660800,872448000,13844480000 -2012,Armor,12,77824,421888,39321600,1744896000,27688960000 -2013,Armor,13,155648,843776,78643200,3489792000,55377920000 -2014,Armor,14,311296,1687552,157286400,6979584000,110755840000 -2015,Armor,15,622592,3375104,314572800,13959168000,221511680000 -2016,Armor,16,1245184,6750208,629145600,27918336000,443023360000 -2017,Armor,17,2490368,13500416,1258291200,55836672000,886046720000 -2018,Armor,18,4980736,27000832,2516582400,111673344000,1772093440000 -2019,Armor,19,9961472,54001664,5033164800,223346688000,3544186880000 -2020,Armor,20,19922944,108003328,10066329600,446693376000,7088373760000 -2021,Armor,21,39845888,216006656,20132659200,893386752000,14176747520000 -3000,Belt,0,954,1496,3864,96600,6760000 -3001,Belt,1,1908,2992,7728,193200,13520000 -3002,Belt,2,3816,5984,15456,386400,27040000 -3003,Belt,3,7632,11968,30912,772800,54080000 -3004,Belt,4,15264,23936,61824,1545600,108160000 -3005,Belt,5,30528,47872,123648,3091200,216320000 -3006,Belt,6,61056,95744,247296,6182400,432640000 -3007,Belt,7,122112,191488,494592,12364800,865280000 -3008,Belt,8,244224,382976,989184,24729600,1730560000 -3009,Belt,9,488448,765952,1978368,49459200,3461120000 -3010,Belt,10,976896,1531904,3956736,98918400,6922240000 -3011,Belt,11,1953792,3063808,7913472,197836800,13844480000 -3012,Belt,12,3907584,6127616,15826944,395673600,27688960000 -3013,Belt,13,7815168,12255232,31653888,791347200,55377920000 -3014,Belt,14,15630336,24510464,63307776,1582694400,110755840000 -3015,Belt,15,31260672,49020928,126615552,3165388800,221511680000 -3016,Belt,16,62521344,98041856,253231104,6330777600,443023360000 -3017,Belt,17,125042688,196083712,506462208,12661555200,886046720000 -3018,Belt,18,250085376,392167424,1012924416,25323110400,1772093440000 -3019,Belt,19,500170752,784334848,2025848832,50646220800,3544186880000 -3020,Belt,20,1000341504,1568669696,4051697664,101292441600,7088373760000 -3021,Belt,21,2000683008,3137339392,8103395328,202584883200,14176747520000 -4000,Necklace,0,315,1736,65040,243000,6760000 -4001,Necklace,1,630,3472,130080,486000,13520000 -4002,Necklace,2,1260,6944,260160,972000,27040000 -4003,Necklace,3,2520,13888,520320,1944000,54080000 -4004,Necklace,4,5040,27776,1040640,3888000,108160000 -4005,Necklace,5,10080,55552,2081280,7776000,216320000 -4006,Necklace,6,20160,111104,4162560,15552000,432640000 -4007,Necklace,7,40320,222208,8325120,31104000,865280000 -4008,Necklace,8,80640,444416,16650240,62208000,1730560000 -4009,Necklace,9,161280,888832,33300480,124416000,3461120000 -4010,Necklace,10,322560,1777664,66600960,248832000,6922240000 -4011,Necklace,11,645120,3555328,133201920,497664000,13844480000 -4012,Necklace,12,1290240,7110656,266403840,995328000,27688960000 -4013,Necklace,13,2580480,14221312,532807680,1990656000,55377920000 -4014,Necklace,14,5160960,28442624,1065615360,3981312000,110755840000 -4015,Necklace,15,10321920,56885248,2131230720,7962624000,221511680000 -4016,Necklace,16,20643840,113770496,4262461440,15925248000,443023360000 -4017,Necklace,17,41287680,227540992,8524922880,31850496000,886046720000 -4018,Necklace,18,82575360,455081984,17049845760,63700992000,1772093440000 -4019,Necklace,19,165150720,910163968,34099691520,127401984000,3544186880000 -4020,Necklace,20,330301440,1820327936,68199383040,254803968000,7088373760000 -4021,Necklace,21,660602880,3640655872,136398766080,509607936000,14176747520000 -5000,Ring,0,10,216,5568,426000,6760000 -5001,Ring,1,20,432,11136,852000,13520000 -5002,Ring,2,40,864,22272,1704000,27040000 -5003,Ring,3,80,1728,44544,3408000,54080000 -5004,Ring,4,160,3456,89088,6816000,108160000 -5005,Ring,5,320,6912,178176,13632000,216320000 -5006,Ring,6,640,13824,356352,27264000,432640000 -5007,Ring,7,1280,27648,712704,54528000,865280000 -5008,Ring,8,2560,55296,1425408,109056000,1730560000 -5009,Ring,9,5120,110592,2850816,218112000,3461120000 -5010,Ring,10,10240,221184,5701632,436224000,6922240000 -5011,Ring,11,20480,442368,11403264,872448000,13844480000 -5012,Ring,12,40960,884736,22806528,1744896000,27688960000 -5013,Ring,13,81920,1769472,45613056,3489792000,55377920000 -5014,Ring,14,163840,3538944,91226112,6979584000,110755840000 -5015,Ring,15,327680,7077888,182452224,13959168000,221511680000 -5016,Ring,16,655360,14155776,364904448,27918336000,443023360000 -5017,Ring,17,1310720,28311552,729808896,55836672000,886046720000 -5018,Ring,18,2621440,56623104,1459617792,111673344000,1772093440000 -5019,Ring,19,5242880,113246208,2919235584,223346688000,3544186880000 -5020,Ring,20,10485760,226492416,5838471168,446693376000,7088373760000 -5021,Ring,21,20971520,452984832,11676942336,893386752000,14176747520000 \ No newline at end of file diff --git a/Lib9c/TableData/Cost/EnhancementCostSheetV3.cs b/Lib9c/TableData/Cost/EnhancementCostSheetV3.cs new file mode 100644 index 0000000000..7f66acf82b --- /dev/null +++ b/Lib9c/TableData/Cost/EnhancementCostSheetV3.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Numerics; +using Nekoyume.Model.Item; + +namespace Nekoyume.TableData +{ + using static TableExtensions; + + public class EnhancementCostSheetV3 : Sheet + { + public class Row : EnhancementCostSheet.Row + { + public long Exp { get; private set; } + public int RequiredBlockIndex { get; private set; } + public int BaseStatGrowthMin { get; private set; } + public int BaseStatGrowthMax { get; private set; } + public int ExtraStatGrowthMin { get; private set; } + public int ExtraStatGrowthMax { get; private set; } + public int ExtraSkillDamageGrowthMin { get; private set; } + public int ExtraSkillDamageGrowthMax { get; private set; } + public int ExtraSkillChanceGrowthMin { get; private set; } + public int ExtraSkillChanceGrowthMax { get; private set; } + + public override void Set(IReadOnlyList fields) + { + base.Set(fields); + Exp = ParseLong(fields[5], 0); + RequiredBlockIndex = ParseInt(fields[6], 0); + BaseStatGrowthMin = ParseInt(fields[7], 0); + BaseStatGrowthMax = ParseInt(fields[8], 0); + ExtraStatGrowthMin = ParseInt(fields[9], 0); + ExtraStatGrowthMax = ParseInt(fields[10], 0); + ExtraSkillDamageGrowthMin = ParseInt(fields[11], 0); + ExtraSkillDamageGrowthMax = ParseInt(fields[12], 0); + ExtraSkillChanceGrowthMin = ParseInt(fields[13], 0); + ExtraSkillChanceGrowthMax = ParseInt(fields[14], 0); + } + } + + public EnhancementCostSheetV3() : base(nameof(EnhancementCostSheetV2)) + { + } + } +} diff --git a/Lib9c/TableData/Item/EquipmentItemSheet.cs b/Lib9c/TableData/Item/EquipmentItemSheet.cs index d9a84345cd..91fe1c5d31 100644 --- a/Lib9c/TableData/Item/EquipmentItemSheet.cs +++ b/Lib9c/TableData/Item/EquipmentItemSheet.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using Bencodex.Types; using Nekoyume.Model.Item; @@ -21,15 +20,22 @@ public class Row : ItemSheet.Row public DecimalStat Stat { get; private set; } public decimal AttackRange { get; private set; } public string SpineResourcePath { get; private set; } + public long? Exp { get; private set; } - public Row() {} + public Row() + { + } - public Row(Bencodex.Types.Dictionary serialized) : base(serialized) + public Row(Dictionary serialized) : base(serialized) { - SetId = (Integer) serialized["set_id"]; + SetId = (Integer)serialized["set_id"]; Stat = serialized["stat"].ToDecimalStat(); AttackRange = serialized["attack_range"].ToDecimal(); - SpineResourcePath = (Text) serialized["spine_resource_path"]; + SpineResourcePath = (Text)serialized["spine_resource_path"]; + if (serialized.ContainsKey("exp")) + { + Exp = serialized["exp"].ToLong(); + } } public override void Set(IReadOnlyList fields) @@ -37,23 +43,38 @@ public override void Set(IReadOnlyList fields) base.Set(fields); SetId = string.IsNullOrEmpty(fields[4]) ? 0 : ParseInt(fields[4]); Stat = new DecimalStat( - (StatType) Enum.Parse(typeof(StatType), fields[5]), + (StatType)Enum.Parse(typeof(StatType), fields[5]), ParseDecimal(fields[6])); AttackRange = ParseDecimal(fields[7]); SpineResourcePath = fields[8]; + if (fields.Count >= 10) + { + Exp = string.IsNullOrEmpty(fields[9]) ? 0L : ParseLong(fields[9]); + } } #pragma warning disable LAA1002 - public override IValue Serialize() => new Bencodex.Types.Dictionary(new Dictionary + public override IValue Serialize() { - [(Text) "set_id"] = (Integer) SetId, - [(Text) "stat"] = Stat.SerializeForLegacyEquipmentStat(), - [(Text) "attack_range"] = AttackRange.Serialize(), - [(Text) "spine_resource_path"] = (Text) SpineResourcePath, - }.Union((Bencodex.Types.Dictionary) base.Serialize())); + var pairs = new Dictionary + { + [(Text)"set_id"] = (Integer)SetId, + [(Text)"stat"] = Stat.SerializeForLegacyEquipmentStat(), + [(Text)"attack_range"] = AttackRange.Serialize(), + [(Text)"spine_resource_path"] = (Text)SpineResourcePath, + }; + if (!(Exp is null)) + { + pairs[(Text)"exp"] = Exp.Serialize(); + } + + return new Dictionary( + new Dictionary(pairs).Union((Dictionary)base.Serialize()) + ); + } #pragma warning restore LAA1002 } - + public EquipmentItemSheet() : base(nameof(EquipmentItemSheet)) { } diff --git a/Lib9c/TableData/Item/EquipmentItemUpgradePointSheet.cs b/Lib9c/TableData/Item/EquipmentItemUpgradePointSheet.cs deleted file mode 100644 index 9417f4b353..0000000000 --- a/Lib9c/TableData/Item/EquipmentItemUpgradePointSheet.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using Nekoyume.Model.EnumType; -using Nekoyume.Model.Item; -using static Nekoyume.TableData.TableExtensions; - -namespace Nekoyume.TableData -{ - [Serializable] - public class EquipmentItemUpgradePointSheet : Sheet - { - [Serializable] - public class Row : SheetRow - { - public override int Key => Id; - public int Id { get; private set; } - public ItemSubType ItemSubType { get; private set; } - public int Level { get; private set; } - public Dictionary ExpMap { get; private set; } - - public Row() - { - } - - public override void Set(IReadOnlyList fields) - { - Id = ParseInt(fields[0]); - ItemSubType = (ItemSubType)Enum.Parse(typeof(ItemSubType), fields[1]); - Level = ParseInt(fields[2]); - ExpMap = new Dictionary - { - { Grade.Normal, ParseLong(fields[3]) }, - { Grade.Rare, ParseLong(fields[4]) }, - { Grade.Epic, ParseLong(fields[5]) }, - { Grade.Unique, ParseLong(fields[6]) }, - { Grade.Legendary, ParseLong(fields[7]) }, - }; - } - } - - public EquipmentItemUpgradePointSheet() : base(nameof(EquipmentItemUpgradePointSheet)) - { - } - } -} From d03f07840160bd28dd8c969c414a6112cd80a353 Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 03:27:30 +0900 Subject: [PATCH 12/20] Apply new data model - Create `UpdateOptionsV3` function - This function uses `EnhancementCostSheetV3`. - This function does not check `GreatSuccess` due to deletion. --- Lib9c/Model/Item/Equipment.cs | 63 ++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/Lib9c/Model/Item/Equipment.cs b/Lib9c/Model/Item/Equipment.cs index 571993e906..d22d5dd905 100644 --- a/Lib9c/Model/Item/Equipment.cs +++ b/Lib9c/Model/Item/Equipment.cs @@ -178,11 +178,10 @@ public void LevelUp(IRandom random, EnhancementCostSheetV2.Row row, bool isGreat } } - public void SetLevel(IRandom random, EquipmentItemUpgradePointSheet.Row targetLevelRow, - EnhancementCostSheetV2.Row costRow) + public void SetLevel(IRandom random, EnhancementCostSheetV3.Row row) { - level = targetLevelRow.Level; - var rand = random.Next(costRow.BaseStatGrowthMin, costRow.BaseStatGrowthMax + 1); + level = row.Level; + var rand = random.Next(row.BaseStatGrowthMin, row.BaseStatGrowthMax + 1); var ratio = rand.NormalizeFromTenThousandths(); var baseStat = StatsMap.GetBaseStat(UniqueStatType) * ratio; if (baseStat > 0) @@ -194,7 +193,7 @@ public void SetLevel(IRandom random, EquipmentItemUpgradePointSheet.Row targetLe if (GetOptionCount() > 0) { - UpdateOptionsV2(random, costRow, false); + UpdateOptionsV3(random, row); } } @@ -235,6 +234,7 @@ private void UpdateOptions() } } + [Obsolete("Since ItemEnhancement12, Use UpdateOptionV3 instead.")] private void UpdateOptionsV2(IRandom random, EnhancementCostSheetV2.Row row, bool isGreatSuccess) { foreach (var stat in StatsMap.GetAdditionalStats()) @@ -274,6 +274,59 @@ private void UpdateOptionsV2(IRandom random, EnhancementCostSheetV2.Row row, boo { addPower = Math.Max(1.0m, addPower); } + + var addStatPowerRatio = skill.StatPowerRatio * damageRatio; + if (addStatPowerRatio > 0) + { + addStatPowerRatio = Math.Max(1.0m, addStatPowerRatio); + } + + var chance = skill.Chance + (int)addChance; + var power = skill.Power + (int)addPower; + var statPowerRatio = skill.StatPowerRatio + (int)addStatPowerRatio; + + skill.Update(chance, power, statPowerRatio); + } + } + + private void UpdateOptionsV3(IRandom random, EnhancementCostSheetV3.Row row) + { + foreach (var stat in StatsMap.GetAdditionalStats()) + { + var rand = random.Next(row.ExtraStatGrowthMin, row.ExtraStatGrowthMax + 1); + var ratio = rand.NormalizeFromTenThousandths(); + var addValue = stat.AdditionalValue * ratio; + if (addValue > 0) + { + addValue = Math.Max(1.0m, addValue); + } + + StatsMap.SetStatAdditionalValue(stat.StatType, stat.AdditionalValue + addValue); + } + + var skills = new List(); + skills.AddRange(Skills); + skills.AddRange(BuffSkills); + foreach (var skill in skills) + { + var chanceRand = random.Next(row.ExtraSkillChanceGrowthMin, + row.ExtraSkillChanceGrowthMax + 1); + var chanceRatio = chanceRand.NormalizeFromTenThousandths(); + var addChance = skill.Chance * chanceRatio; + if (addChance > 0) + { + addChance = Math.Max(1.0m, addChance); + } + + var damageRand = random.Next(row.ExtraSkillDamageGrowthMin, + row.ExtraSkillDamageGrowthMax + 1); + var damageRatio = damageRand.NormalizeFromTenThousandths(); + var addPower = skill.Power * damageRatio; + if (addPower > 0) + { + addPower = Math.Max(1.0m, addPower); + } + var addStatPowerRatio = skill.StatPowerRatio * damageRatio; if (addStatPowerRatio > 0) { From ebb57f58b4f7df34c92b049e913e69e7dbd8db34 Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 03:32:07 +0900 Subject: [PATCH 13/20] Update backed-up test --- .Lib9c.Tests/Action/ItemEnhancement11Test.cs | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.Lib9c.Tests/Action/ItemEnhancement11Test.cs b/.Lib9c.Tests/Action/ItemEnhancement11Test.cs index 45fdcdb953..2affd37714 100644 --- a/.Lib9c.Tests/Action/ItemEnhancement11Test.cs +++ b/.Lib9c.Tests/Action/ItemEnhancement11Test.cs @@ -5,7 +5,6 @@ namespace Lib9c.Tests.Action using System.Globalization; using System.Linq; using Bencodex.Types; - using Libplanet.Action; using Libplanet.Action.State; using Libplanet.Crypto; using Libplanet.Types.Assets; @@ -17,7 +16,8 @@ namespace Lib9c.Tests.Action using Nekoyume.Model.Mail; using Nekoyume.Model.State; using Xunit; - using static Lib9c.SerializeKeys; + using static Nekoyume.Action.ItemEnhancement11; + using static SerializeKeys; public class ItemEnhancement11Test { @@ -74,23 +74,23 @@ public ItemEnhancement11Test() } [Theory] - [InlineData(0, 1000, true, 0, 1, ItemEnhancement.EnhancementResult.Success, 0, 0, false)] - [InlineData(6, 980, true, 0, 7, ItemEnhancement.EnhancementResult.Success, 0, 0, false)] - [InlineData(0, 1000, false, 1, 1, ItemEnhancement.EnhancementResult.GreatSuccess, 0, 0, false)] - [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 0, 320, false)] - [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 2, 480, false)] - [InlineData(0, 1000, true, 0, 1, ItemEnhancement.EnhancementResult.Success, 0, 0, true)] - [InlineData(6, 980, true, 0, 7, ItemEnhancement.EnhancementResult.Success, 0, 0, true)] - [InlineData(0, 1000, false, 1, 1, ItemEnhancement.EnhancementResult.GreatSuccess, 0, 0, true)] - [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 0, 320, true)] - [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 2, 480, true)] + [InlineData(0, 1000, true, 0, 1, EnhancementResult.Success, 0, 0, false)] + [InlineData(6, 980, true, 0, 7, EnhancementResult.Success, 0, 0, false)] + [InlineData(0, 1000, false, 1, 1, EnhancementResult.GreatSuccess, 0, 0, false)] + [InlineData(6, 980, false, 10, 6, EnhancementResult.Fail, 0, 320, false)] + [InlineData(6, 980, false, 10, 6, EnhancementResult.Fail, 2, 480, false)] + [InlineData(0, 1000, true, 0, 1, EnhancementResult.Success, 0, 0, true)] + [InlineData(6, 980, true, 0, 7, EnhancementResult.Success, 0, 0, true)] + [InlineData(0, 1000, false, 1, 1, EnhancementResult.GreatSuccess, 0, 0, true)] + [InlineData(6, 980, false, 10, 6, EnhancementResult.Fail, 0, 320, true)] + [InlineData(6, 980, false, 10, 6, EnhancementResult.Fail, 2, 480, true)] public void Execute( int level, int expectedGold, bool backward, int randomSeed, int expectedLevel, - ItemEnhancement.EnhancementResult expected, + EnhancementResult expected, int monsterCollectLevel, int expectedCrystal, bool stake @@ -203,24 +203,24 @@ bool stake .First(x => x.Grade == 1 && x.Level == level + 1); var stateDict = (Dictionary)nextState.GetState(slotAddress); var slot = new CombinationSlotState(stateDict); - var slotResult = (ItemEnhancement.ResultModel)slot.Result; + var slotResult = (ResultModel)slot.Result; Assert.Equal(expected, slotResult.enhancementResult); switch (slotResult.enhancementResult) { - case ItemEnhancement.EnhancementResult.GreatSuccess: + case EnhancementResult.GreatSuccess: var baseAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); var extraAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + 1); Assert.Equal((int)(baseAtk + extraAtk), resultEquipment.StatsMap.ATK); break; - case ItemEnhancement.EnhancementResult.Success: + case EnhancementResult.Success: var baseMinAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMin.NormalizeFromTenThousandths() + 1); var baseMaxAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); var extraMinAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMin.NormalizeFromTenThousandths() + 1); var extraMaxAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + 1); Assert.InRange(resultEquipment.StatsMap.ATK, baseMinAtk + extraMinAtk, baseMaxAtk + extraMaxAtk + 1); break; - case ItemEnhancement.EnhancementResult.Fail: + case EnhancementResult.Fail: Assert.Equal(preItemUsable.StatsMap.ATK, resultEquipment.StatsMap.ATK); break; } From 326c0fa2fd570446a0e9680e1fa5c95685b697fa Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 03:33:23 +0900 Subject: [PATCH 14/20] Introduce ItemEnhancement12 action - Enhancement result is fixed to `Success`. - Gets multiple materials regardless of grade and level. - Uses exp of `Equipment` model and use `SetLevel` function to manage level. - Update claculation logic of NCG cost and required block index. --- Lib9c/Action/AttachmentActionResult.cs | 3 +- Lib9c/Action/ItemEnhancement.cs | 372 +++++++++++++------------ 2 files changed, 201 insertions(+), 174 deletions(-) diff --git a/Lib9c/Action/AttachmentActionResult.cs b/Lib9c/Action/AttachmentActionResult.cs index 5b1a3a46c4..24927fc514 100644 --- a/Lib9c/Action/AttachmentActionResult.cs +++ b/Lib9c/Action/AttachmentActionResult.cs @@ -21,7 +21,8 @@ private static readonly Dictionary new CombinationConsumable5.ResultModel(d), ["itemEnhancement.result"] = d => new ItemEnhancement7.ResultModel(d), ["item_enhancement9.result"] = d => new ItemEnhancement9.ResultModel(d), - ["item_enhancement11.result"] = d => new ItemEnhancement.ResultModel(d), + ["item_enhancement11.result"] = d => new ItemEnhancement11.ResultModel(d), + ["item_enhancement12.result"] = d => new ItemEnhancement.ResultModel(d), ["sellCancellation.result"] = d => new SellCancellation.Result(d), ["rapidCombination.result"] = d => new RapidCombination0.ResultModel(d), ["rapid_combination5.result"] = d => new RapidCombination5.ResultModel(d), diff --git a/Lib9c/Action/ItemEnhancement.cs b/Lib9c/Action/ItemEnhancement.cs index 186fb9007e..86d7ef5bdd 100644 --- a/Lib9c/Action/ItemEnhancement.cs +++ b/Lib9c/Action/ItemEnhancement.cs @@ -19,39 +19,41 @@ using Nekoyume.TableData; using Nekoyume.TableData.Crystal; using Serilog; - using static Lib9c.SerializeKeys; namespace Nekoyume.Action { /// - /// Updated at https://github.com/planetarium/lib9c/pull/1164 + /// Updated at https://github.com/planetarium/lib9c/pull/2068 /// [Serializable] - [ActionType("item_enhancement11")] - public class ItemEnhancement : GameAction, IItemEnhancementV2 + [ActionType("item_enhancement12")] + public class ItemEnhancement : GameAction, IItemEnhancementV4 { public enum EnhancementResult { - GreatSuccess = 0, + // Result is fixed to Success. + // GreatSuccess = 0, Success = 1, - Fail = 2, + // Fail = 2, } + public const int MaterialCountLimit = 50; + public Guid itemId; - public Guid materialId; + public List materialIds; public Address avatarAddress; public int slotIndex; - Guid IItemEnhancementV2.ItemId => itemId; - Guid IItemEnhancementV2.MaterialId => materialId; - Address IItemEnhancementV2.AvatarAddress => avatarAddress; - int IItemEnhancementV2.SlotIndex => slotIndex; + Guid IItemEnhancementV4.ItemId => itemId; + IEnumerable IItemEnhancementV4.MaterialIds => materialIds; + Address IItemEnhancementV4.AvatarAddress => avatarAddress; + int IItemEnhancementV4.SlotIndex => slotIndex; [Serializable] public class ResultModel : AttachmentActionResult { - protected override string TypeId => "item_enhancement11.result"; + protected override string TypeId => "item_enhancement12.result"; public Guid id; public IEnumerable materialItemIdList; public BigInteger gold; @@ -101,7 +103,9 @@ protected override IImmutableDictionary PlainValueInternal var dict = new Dictionary { ["itemId"] = itemId.Serialize(), - ["materialId"] = materialId.Serialize(), + ["materialIds"] = new List( + materialIds.OrderBy(i => i).Select(i => i.Serialize()) + ), ["avatarAddress"] = avatarAddress.Serialize(), ["slotIndex"] = slotIndex.Serialize(), }; @@ -113,7 +117,7 @@ protected override IImmutableDictionary PlainValueInternal protected override void LoadPlainValueInternal(IImmutableDictionary plainValue) { itemId = plainValue["itemId"].ToGuid(); - materialId = plainValue["materialId"].ToGuid(); + materialIds = plainValue["materialId"].ToList(StateExtensions.ToGuid); avatarAddress = plainValue["avatarAddress"].ToAddress(); if (plainValue.TryGetValue((Text)"slotIndex", out var value)) { @@ -126,6 +130,13 @@ public override IAccountStateDelta Execute(IActionContext context) context.UseGas(1); var ctx = context; var states = ctx.PreviousState; + + if (ctx.Rehearsal) + { + return states; + } + + // Collect addresses var slotAddress = avatarAddress.Derive( string.Format( CultureInfo.InvariantCulture, @@ -136,34 +147,44 @@ public override IAccountStateDelta Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - - if (ctx.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var sw = new Stopwatch(); sw.Start(); var started = DateTimeOffset.UtcNow; - Log.Debug("{AddressesHex}ItemEnhancement exec started", addressesHex); - if (!states.TryGetAgentAvatarStatesV2(ctx.Signer, avatarAddress, out var agentState, out var avatarState, out _)) + Log.Debug("{AddressesHex} ItemEnhancement exec started", addressesHex); + + // Validate avatar + if (!states.TryGetAgentAvatarStatesV2(ctx.Signer, avatarAddress, out var agentState, + out var avatarState, out var migrationRequired)) + { + throw new FailedLoadStateException( + $"{addressesHex} Aborted as the avatar state of the signer was failed to load." + ); + } + + // Validate AP + var requiredActionPoint = GetRequiredAp(); + if (avatarState.actionPoint < requiredActionPoint) { - throw new FailedLoadStateException($"{addressesHex}Aborted as the avatar state of the signer was failed to load."); + throw new NotEnoughActionPointException( + $"{addressesHex} Aborted due to insufficient action point: {avatarState.actionPoint} < {requiredActionPoint}" + ); } - if (!avatarState.inventory.TryGetNonFungibleItem(itemId, out ItemUsable enhancementItem)) + // Validate target equipment item + if (!avatarState.inventory.TryGetNonFungibleItem(itemId, + out ItemUsable enhancementItem)) { throw new ItemDoesNotExistException( - $"{addressesHex}Aborted as the NonFungibleItem ({itemId}) was failed to load from avatar's inventory." + $"{addressesHex} Aborted as the NonFungibleItem ({itemId}) was failed to load from avatar's inventory." ); } if (enhancementItem.RequiredBlockIndex > context.BlockIndex) { throw new RequiredBlockIndexException( - $"{addressesHex}Aborted as the equipment to enhance ({itemId}) is not available yet;" + + $"{addressesHex} Aborted as the equipment to enhance ({itemId}) is not available yet;" + $" it will be available at the block #{enhancementItem.RequiredBlockIndex}." ); } @@ -171,194 +192,204 @@ public override IAccountStateDelta Execute(IActionContext context) if (!(enhancementItem is Equipment enhancementEquipment)) { throw new InvalidCastException( - $"{addressesHex}Aborted as the item is not a {nameof(Equipment)}, but {enhancementItem.GetType().Name}." - + $"{addressesHex} Aborted as the item is not a {nameof(Equipment)}, but {enhancementItem.GetType().Name}." ); } + // Validate combination slot var slotState = states.GetCombinationSlotState(avatarAddress, slotIndex); if (slotState is null) { - throw new FailedLoadStateException($"{addressesHex}Aborted as the slot state was failed to load. #{slotIndex}"); + throw new FailedLoadStateException( + $"{addressesHex} Aborted as the slot state was failed to load. #{slotIndex}" + ); } if (!slotState.Validate(avatarState, ctx.BlockIndex)) { - throw new CombinationSlotUnlockException($"{addressesHex}Aborted as the slot state was failed to invalid. #{slotIndex}"); + throw new CombinationSlotUnlockException( + $"{addressesHex} Aborted as the slot state was failed to invalid. #{slotIndex}" + ); } + sw.Stop(); - Log.Verbose("{AddressesHex}ItemEnhancement Get Equipment: {Elapsed}", addressesHex, sw.Elapsed); + Log.Verbose("{AddressesHex} ItemEnhancement Get Equipment: {Elapsed}", addressesHex, + sw.Elapsed); sw.Restart(); Dictionary sheets = states.GetSheets(sheetTypes: new[] { - typeof(EnhancementCostSheetV2), + typeof(EnhancementCostSheetV3), typeof(MaterialItemSheet), typeof(CrystalEquipmentGrindingSheet), typeof(CrystalMonsterCollectionMultiplierSheet), typeof(StakeRegularRewardSheet) }); - var enhancementCostSheet = sheets.GetSheet(); - if (!TryGetRow(enhancementEquipment, enhancementCostSheet, out var row)) + // Validate from sheet + var enhancementCostSheet = sheets.GetSheet(); + EnhancementCostSheetV3.Row startCostRow; + if (enhancementEquipment.level == 0) + { + startCostRow = new EnhancementCostSheetV3.Row(); + } + else { - throw new SheetRowNotFoundException(addressesHex, nameof(WorldSheet), enhancementEquipment.level); + if (!TryGetRow(enhancementEquipment, enhancementCostSheet, out startCostRow)) + { + throw new SheetRowNotFoundException(addressesHex, nameof(WorldSheet), + enhancementEquipment.level); + } } var maxLevel = GetEquipmentMaxLevel(enhancementEquipment, enhancementCostSheet); if (enhancementEquipment.level >= maxLevel) { throw new EquipmentLevelExceededException( - $"{addressesHex}Aborted due to invalid equipment level: {enhancementEquipment.level} < {maxLevel}"); + $"{addressesHex} Aborted due to invalid equipment level: {enhancementEquipment.level} < {maxLevel}"); } - if (!avatarState.inventory.TryGetNonFungibleItem(materialId, out ItemUsable materialItem)) + // Validate enhancement materials + if (!materialIds.Any() || materialIds.Count > MaterialCountLimit) { - throw new NotEnoughMaterialException( - $"{addressesHex}Aborted as the signer does not have a necessary material ({materialId})." - ); + throw new InvalidItemCountException(); } - if (materialItem.RequiredBlockIndex > context.BlockIndex) - { - throw new RequiredBlockIndexException( - $"{addressesHex}Aborted as the material ({materialId}) is not available yet;" + - $" it will be available at the block #{materialItem.RequiredBlockIndex}." - ); - } + var materialEquipments = new List(); - if (!(materialItem is Equipment materialEquipment)) + foreach (var materialId in materialIds) { - throw new InvalidCastException( - $"{addressesHex}Aborted as the material item is not an {nameof(Equipment)}, but {materialItem.GetType().Name}." - ); - } + if (!avatarState.inventory.TryGetNonFungibleItem(materialId, + out ItemUsable materialItem)) + { + throw new NotEnoughMaterialException( + $"{addressesHex} Aborted as the signer does not have a necessary material ({materialId})." + ); + } - if (enhancementEquipment.ItemId == materialId) - { - throw new InvalidMaterialException( - $"{addressesHex}Aborted as an equipment to enhance ({materialId}) was used as a material too." - ); - } + if (materialItem.RequiredBlockIndex > context.BlockIndex) + { + throw new RequiredBlockIndexException( + $"{addressesHex} Aborted as the material ({materialId}) is not available yet;" + + $" it will be available at the block #{materialItem.RequiredBlockIndex}." + ); + } - if (materialEquipment.ItemSubType != enhancementEquipment.ItemSubType) - { - throw new InvalidMaterialException( - $"{addressesHex}Aborted as the material item is not a {enhancementEquipment.ItemSubType}," + - $" but {materialEquipment.ItemSubType}." - ); - } + if (!(materialItem is Equipment materialEquipment)) + { + throw new InvalidCastException( + $"{addressesHex} Aborted as the material item is not an {nameof(Equipment)}, but {materialItem.GetType().Name}." + ); + } - if (materialEquipment.Grade != enhancementEquipment.Grade) - { - throw new InvalidMaterialException( - $"{addressesHex}Aborted as grades of the equipment to enhance ({enhancementEquipment.Grade})" + - $" and a material ({materialEquipment.Grade}) does not match." - ); - } + if (enhancementEquipment.ItemId == materialId) + { + throw new InvalidMaterialException( + $"{addressesHex} Aborted as an equipment to enhance ({materialId}) was used as a material too." + ); + } - if (materialEquipment.level != enhancementEquipment.level) - { - throw new InvalidMaterialException( - $"{addressesHex}Aborted as levels of the equipment to enhance ({enhancementEquipment.level})" + - $" and a material ({materialEquipment.level}) does not match." - ); + if (materialEquipment.ItemSubType != enhancementEquipment.ItemSubType) + { + throw new InvalidMaterialException( + $"{addressesHex} Aborted as the material item is not a {enhancementEquipment.ItemSubType}," + + $" but {materialEquipment.ItemSubType}." + ); + } + + materialEquipments.Add(materialEquipment); } + sw.Stop(); - Log.Verbose("{AddressesHex}ItemEnhancement Get Material: {Elapsed}", addressesHex, sw.Elapsed); + Log.Verbose("{AddressesHex} ItemEnhancement Get Material: {Elapsed}", + addressesHex, sw.Elapsed); sw.Restart(); + + // Do the action // Subtract required action point - var requiredActionPoint = GetRequiredAp(); - if (avatarState.actionPoint < requiredActionPoint) - { - throw new NotEnoughActionPointException( - $"{addressesHex}Aborted due to insufficient action point: {avatarState.actionPoint} < {requiredActionPoint}" - ); - } avatarState.actionPoint -= requiredActionPoint; - // TransferAsset (NCG) - var requiredNcg = row.Cost; - if (requiredNcg > 0) - { - var arenaSheet = states.GetSheet(); - var arenaData = arenaSheet.GetRoundByBlockIndex(context.BlockIndex); - var feeStoreAddress = Addresses.GetBlacksmithFeeAddress(arenaData.ChampionshipId, arenaData.Round); - states = states.TransferAsset(ctx, ctx.Signer, feeStoreAddress, states.GetGoldCurrency() * requiredNcg); - } - // Unequip items - materialEquipment.Unequip(); enhancementEquipment.Unequip(); + foreach (var materialEquipment in materialEquipments) + { + materialEquipment.Unequip(); + } - // clone items + // clone enhancement item var preItemUsable = new Equipment((Dictionary)enhancementEquipment.Serialize()); // Equipment level up & Update - var equipmentResult = GetEnhancementResult(row, ctx.Random); - FungibleAssetValue crystal = 0 * CrystalCalculator.CRYSTAL; - if (equipmentResult != EnhancementResult.Fail) + enhancementEquipment.exp += + materialEquipments.Aggregate(0L, (total, m) => total + m.exp); + var row = enhancementCostSheet + .OrderByDescending(r => r.Value.Exp) + .First(row => + row.Value.ItemSubType == enhancementEquipment.ItemSubType && + row.Value.Grade == enhancementEquipment.Grade && + row.Value.Exp <= enhancementEquipment.exp + ).Value; + + if (row.Level > enhancementEquipment.level) { - enhancementEquipment.LevelUp(ctx.Random, row, equipmentResult == EnhancementResult.GreatSuccess); + enhancementEquipment.SetLevel(ctx.Random, row); + } + + EnhancementCostSheetV3.Row targetCostRow; + if (enhancementEquipment.level == 0) + { + targetCostRow = new EnhancementCostSheetV3.Row(); } else { - Address monsterCollectionAddress = MonsterCollectionState.DeriveAddress( - context.Signer, - agentState.MonsterCollectionRound - ); - - Currency currency = states.GetGoldCurrency(); - FungibleAssetValue stakedAmount = 0 * currency; - if (states.TryGetStakeState(context.Signer, out StakeState stakeState)) + if (!TryGetRow(enhancementEquipment, enhancementCostSheet, out targetCostRow)) { - stakedAmount = states.GetBalance(stakeState.address, currency); + throw new SheetRowNotFoundException(addressesHex, nameof(WorldSheet), + enhancementEquipment.level); } - else - { - if (states.TryGetState(monsterCollectionAddress, out Dictionary _)) - { - stakedAmount = states.GetBalance(monsterCollectionAddress, currency); - } - } - - crystal = CrystalCalculator.CalculateCrystal( - context.Signer, - new[] { preItemUsable }, - stakedAmount, - true, - sheets.GetSheet(), - sheets.GetSheet(), - sheets.GetSheet() - ); + } - if (crystal > 0 * CrystalCalculator.CRYSTAL) - { - states = states.MintAsset(context, context.Signer, crystal); - } + // TransferAsset (NCG) + // Total cost = Total cost to reach target level - total cost to reach start level (already used) + var requiredNcg = targetCostRow.Cost - startCostRow.Cost; + if (requiredNcg > 0) + { + var arenaSheet = states.GetSheet(); + var arenaData = arenaSheet.GetRoundByBlockIndex(context.BlockIndex); + var feeStoreAddress = + Addresses.GetBlacksmithFeeAddress(arenaData.ChampionshipId, arenaData.Round); + states = states.TransferAsset(ctx, ctx.Signer, feeStoreAddress, + states.GetGoldCurrency() * requiredNcg); } - var requiredBlockCount = GetRequiredBlockCount(row, equipmentResult); + // Required block index = Sum of all required blocks from start level to target level + var requiredBlockCount = GetRequiredBlockCount(preItemUsable, enhancementEquipment, + enhancementCostSheet); var requiredBlockIndex = ctx.BlockIndex + requiredBlockCount; enhancementEquipment.Update(requiredBlockIndex); - // Remove material - avatarState.inventory.RemoveNonFungibleItem(materialId); + // Remove materials + foreach (var materialId in materialIds) + { + avatarState.inventory.RemoveNonFungibleItem(materialId); + } + sw.Stop(); - Log.Verbose("{AddressesHex}ItemEnhancement Upgrade Equipment: {Elapsed}", addressesHex, sw.Elapsed); + Log.Verbose("{AddressesHex} ItemEnhancement Upgrade Equipment: {Elapsed}", addressesHex, + sw.Elapsed); // Send scheduled mail var result = new ResultModel { preItemUsable = preItemUsable, itemUsable = enhancementEquipment, - materialItemIdList = new[] { materialId }, + materialItemIdList = materialIds.ToArray(), actionPoint = requiredActionPoint, - enhancementResult = equipmentResult, + enhancementResult = EnhancementResult.Success, // Result is fixed to Success gold = requiredNcg, - CRYSTAL = crystal, + CRYSTAL = 0 * CrystalCalculator.CRYSTAL, }; var mail = new ItemEnhanceMail(result, ctx.BlockIndex, ctx.Random.GenerateRandomGuid(), requiredBlockIndex); @@ -378,52 +409,47 @@ public override IAccountStateDelta Execute(IActionContext context) sw.Restart(); states = states .SetState(inventoryAddress, avatarState.inventory.Serialize()) - .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) - .SetState(questListAddress, avatarState.questList.Serialize()) - .SetState(avatarAddress, avatarState.SerializeV2()); - sw.Stop(); - Log.Verbose("{AddressesHex}ItemEnhancement Set AvatarState: {Elapsed}", addressesHex, sw.Elapsed); - var ended = DateTimeOffset.UtcNow; - Log.Debug("{AddressesHex}ItemEnhancement Total Executed Time: {Elapsed}", addressesHex, ended - started); - return states.SetState(slotAddress, slotState.Serialize()); - } - - public static EnhancementResult GetEnhancementResult(EnhancementCostSheetV2.Row row, IRandom random) - { - var rand = random.Next(1, GameConfig.MaximumProbability + 1); - if (rand <= row.GreatSuccessRatio) + .SetState(questListAddress, avatarState.questList.Serialize()); + if (migrationRequired) { - return EnhancementResult.GreatSuccess; + states = states + .SetState(worldInformationAddress, avatarState.worldInformation.Serialize()) + .SetState(avatarAddress, avatarState.SerializeV2()); } - return rand <= row.GreatSuccessRatio + row.SuccessRatio ? EnhancementResult.Success : EnhancementResult.Fail; + sw.Stop(); + Log.Verbose("{AddressesHex} ItemEnhancement Set AvatarState: {Elapsed}", addressesHex, + sw.Elapsed); + var ended = DateTimeOffset.UtcNow; + Log.Debug("{AddressesHex} ItemEnhancement Total Executed Time: {Elapsed}", addressesHex, + ended - started); + return states.SetState(slotAddress, slotState.Serialize()); } - public static int GetRequiredBlockCount(EnhancementCostSheetV2.Row row, EnhancementResult result) + public static int GetRequiredBlockCount(Equipment preEquipment, Equipment targetEquipment, + EnhancementCostSheetV3 sheet) { - switch (result) - { - case EnhancementResult.GreatSuccess: - return row.GreatSuccessRequiredBlockIndex; - case EnhancementResult.Success: - return row.SuccessRequiredBlockIndex; - case EnhancementResult.Fail: - return row.FailRequiredBlockIndex; - default: - throw new ArgumentOutOfRangeException(nameof(result), result, null); - } + return sheet.OrderedList + .Where(e => + e.ItemSubType == targetEquipment.ItemSubType && + e.Grade == targetEquipment.Grade && + e.Level > preEquipment.level && + e.Level <= targetEquipment.level) + .Aggregate(0, (blocks, row) => blocks + row.RequiredBlockIndex); } - public static bool TryGetRow(Equipment equipment, EnhancementCostSheetV2 sheet, out EnhancementCostSheetV2.Row row) + public static bool TryGetRow(Equipment equipment, EnhancementCostSheetV3 sheet, + out EnhancementCostSheetV3.Row row) { - var grade = equipment.Grade; - var level = equipment.level + 1; - var itemSubType = equipment.ItemSubType; - row = sheet.OrderedList.FirstOrDefault(x => x.Grade == grade && x.Level == level && x.ItemSubType == itemSubType); + row = sheet.OrderedList.FirstOrDefault(x => + x.Grade == equipment.Grade && + x.Level == equipment.level && + x.ItemSubType == equipment.ItemSubType + ); return row != null; } - public static int GetEquipmentMaxLevel(Equipment equipment, EnhancementCostSheetV2 sheet) + public static int GetEquipmentMaxLevel(Equipment equipment, EnhancementCostSheetV3 sheet) { return sheet.OrderedList.Where(x => x.Grade == equipment.Grade).Max(x => x.Level); } From 9423ebab4d0bc3aeb4196a8bcb76c392cb0fe4ab Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 12:56:23 +0900 Subject: [PATCH 15/20] Update ItemEnhancement action - Write tests (Failing) - Change level checking logic - Change SetLevel params --- .Lib9c.Tests/Action/ItemEnhancementTest.cs | 258 +++++++++++++-------- .Lib9c.Tests/TableSheets.cs | 4 +- Lib9c/Action/ItemEnhancement.cs | 4 +- Lib9c/Model/Item/Equipment.cs | 31 ++- 4 files changed, 180 insertions(+), 117 deletions(-) diff --git a/.Lib9c.Tests/Action/ItemEnhancementTest.cs b/.Lib9c.Tests/Action/ItemEnhancementTest.cs index d9e8c8cb37..2d1968551a 100644 --- a/.Lib9c.Tests/Action/ItemEnhancementTest.cs +++ b/.Lib9c.Tests/Action/ItemEnhancementTest.cs @@ -5,19 +5,18 @@ namespace Lib9c.Tests.Action using System.Globalization; using System.Linq; using Bencodex.Types; - using Libplanet.Action; using Libplanet.Action.State; using Libplanet.Crypto; using Libplanet.Types.Assets; using Nekoyume; using Nekoyume.Action; using Nekoyume.Extensions; - using Nekoyume.Helper; using Nekoyume.Model.Item; using Nekoyume.Model.Mail; using Nekoyume.Model.State; + using Nekoyume.TableData; using Xunit; - using static Lib9c.SerializeKeys; + using static SerializeKeys; public class ItemEnhancementTest { @@ -53,7 +52,11 @@ public ItemEnhancementTest() _currency = Currency.Legacy("NCG", 2, null); #pragma warning restore CS0618 var gold = new GoldCurrencyState(_currency); - var slotAddress = _avatarAddress.Derive(string.Format(CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, 0)); + var slotAddress = _avatarAddress.Derive(string.Format( + CultureInfo.InvariantCulture, + CombinationSlotState.DeriveFormat, + 0 + )); var context = new ActionContext(); _initialState = new MockStateDelta() @@ -61,49 +64,97 @@ public ItemEnhancementTest() .SetState(_avatarAddress, _avatarState.Serialize()) .SetState(slotAddress, new CombinationSlotState(slotAddress, 0).Serialize()) .SetState(GoldCurrencyState.Address, gold.Serialize()) - .MintAsset(context, GoldCurrencyState.Address, gold.Currency * 100000000000) - .TransferAsset(context, Addresses.GoldCurrency, _agentAddress, gold.Currency * 1000); + .MintAsset(context, GoldCurrencyState.Address, gold.Currency * 100_000_000_000) + .TransferAsset( + context, + Addresses.GoldCurrency, + _agentAddress, + gold.Currency * 3_000_000 + ); - Assert.Equal(gold.Currency * 99999999000, _initialState.GetBalance(Addresses.GoldCurrency, gold.Currency)); - Assert.Equal(gold.Currency * 1000, _initialState.GetBalance(_agentAddress, gold.Currency)); + Assert.Equal( + gold.Currency * 99_997_000_000, + _initialState.GetBalance(Addresses.GoldCurrency, gold.Currency) + ); + Assert.Equal( + gold.Currency * 3_000_000, + _initialState.GetBalance(_agentAddress, gold.Currency) + ); foreach (var (key, value) in sheets) { - _initialState = _initialState.SetState(Addresses.TableSheet.Derive(key), value.Serialize()); + _initialState = + _initialState.SetState(Addresses.TableSheet.Derive(key), value.Serialize()); } } [Theory] - [InlineData(0, 1000, true, 0, 1, ItemEnhancement.EnhancementResult.Success, 0, 0, false)] - [InlineData(6, 980, true, 0, 7, ItemEnhancement.EnhancementResult.Success, 0, 0, false)] - [InlineData(0, 1000, false, 1, 1, ItemEnhancement.EnhancementResult.GreatSuccess, 0, 0, false)] - [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 0, 320, false)] - [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 2, 480, false)] - [InlineData(0, 1000, true, 0, 1, ItemEnhancement.EnhancementResult.Success, 0, 0, true)] - [InlineData(6, 980, true, 0, 7, ItemEnhancement.EnhancementResult.Success, 0, 0, true)] - [InlineData(0, 1000, false, 1, 1, ItemEnhancement.EnhancementResult.GreatSuccess, 0, 0, true)] - [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 0, 320, true)] - [InlineData(6, 980, false, 10, 6, ItemEnhancement.EnhancementResult.Fail, 2, 480, true)] + // from 0 to 1 using one level 0 material + [InlineData(0, 1, 0, 25, 0, 1)] + // from 0 to N using multiple level 0 materials + [InlineData(0, 2, 0, 87, 0, 3)] + [InlineData(0, 4, 20, 837, 0, 15)] + // from K to K with material(s). Check requiredBlock == 0 + [InlineData(10, 10, 0, 0, 0, 1)] + // from K to N using one level X material + [InlineData(5, 6, 40, 1300, 6, 1)] + // from K to N using multiple materials + [InlineData(5, 7, 120, 3800, 4, 6)] + [InlineData(5, 9, 600, 10275, 7, 5)] + // from 20 to 21 (just to reach level 21 exp) + [InlineData(20, 21, 1310720, 7500, 20, 1)] + // from 20 to 21 (over level 21) + [InlineData(20, 21, 1310720, 7500, 20, 2)] + // from 21 to 21 (no level up) + [InlineData(21, 21, 0, 0, 1, 1)] + [InlineData(21, 21, 0, 0, 21, 1)] + // Test: change of exp, change of level, required block, NCG price public void Execute( - int level, - int expectedGold, - bool backward, - int randomSeed, + int startLevel, int expectedLevel, - ItemEnhancement.EnhancementResult expected, - int monsterCollectLevel, - int expectedCrystal, - bool stake - ) + int expectedCost, + int expectedBlockIndex, + int materialLevel, + int materialCount) { - var context = new ActionContext(); - var row = _tableSheets.EquipmentItemSheet.Values.First(r => r.Grade == 1); - var equipment = (Equipment)ItemFactory.CreateItemUsable(row, default, 0, level); - var materialId = Guid.NewGuid(); - var material = (Equipment)ItemFactory.CreateItemUsable(row, materialId, 0, level); + var row = _tableSheets.EquipmentItemSheet.Values.First(r => r.Grade == 1 && r.Exp > 0); + var equipment = (Equipment)ItemFactory.CreateItemUsable(row, default, 0, startLevel); + if (startLevel == 0) + { + equipment.exp = (long)row.Exp!; + } + else + { + equipment.exp = _tableSheets.EnhancementCostSheetV3.Values.First(r => + r.Grade == equipment.Grade && r.ItemSubType == equipment.ItemSubType && + r.Level == equipment.level).Exp; + } + var startExp = equipment.exp; _avatarState.inventory.AddItem(equipment, count: 1); - _avatarState.inventory.AddItem(material, count: 1); + + var expectedExpIncrement = 0L; + var materialIds = new List(); + for (var i = 0; i < materialCount; i++) + { + var materialId = Guid.NewGuid(); + materialIds.Add(materialId); + var material = + (Equipment)ItemFactory.CreateItemUsable(row, materialId, 0, materialLevel); + if (materialLevel == 0) + { + material.exp = (long)row.Exp!; + } + else + { + material.exp = _tableSheets.EnhancementCostSheetV3.Values.First(r => + r.Grade == material.Grade && r.ItemSubType == material.ItemSubType && + r.Level == material.level).Exp; + } + + expectedExpIncrement += material.exp; + _avatarState.inventory.AddItem(material, count: 1); + } var result = new CombinationConsumable5.ResultModel() { @@ -122,54 +173,42 @@ bool stake _avatarState.Update(mail); } - _avatarState.worldInformation.ClearStage(1, 1, 1, _tableSheets.WorldSheet, _tableSheets.WorldUnlockSheet); + _avatarState.worldInformation.ClearStage( + 1, + 1, + 1, + _tableSheets.WorldSheet, + _tableSheets.WorldUnlockSheet + ); var slotAddress = - _avatarAddress.Derive(string.Format(CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, 0)); + _avatarAddress.Derive(string.Format( + CultureInfo.InvariantCulture, + CombinationSlotState.DeriveFormat, + 0 + )); - Assert.Equal(level, equipment.level); + Assert.Equal(startLevel, equipment.level); - if (backward) - { - _initialState = _initialState.SetState(_avatarAddress, _avatarState.Serialize()); - } - else - { - _initialState = _initialState - .SetState(_avatarAddress.Derive(LegacyInventoryKey), _avatarState.inventory.Serialize()) - .SetState(_avatarAddress.Derive(LegacyWorldInformationKey), _avatarState.worldInformation.Serialize()) - .SetState(_avatarAddress.Derive(LegacyQuestListKey), _avatarState.questList.Serialize()) - .SetState(_avatarAddress, _avatarState.SerializeV2()); - } - - if (monsterCollectLevel > 0) - { - var requiredGold = _tableSheets.StakeRegularRewardSheet.OrderedRows - .First(r => r.Level == monsterCollectLevel).RequiredGold; - if (stake) - { - // StakeState; - var stakeStateAddress = StakeState.DeriveAddress(_agentAddress); - var stakeState = new StakeState(stakeStateAddress, 1); - _initialState = _initialState - .SetState(stakeStateAddress, stakeState.SerializeV2()) - .MintAsset(context, stakeStateAddress, requiredGold * _currency); - } - else - { - var mcAddress = MonsterCollectionState.DeriveAddress(_agentAddress, 0); - _initialState = _initialState.SetState( - mcAddress, - new MonsterCollectionState(mcAddress, monsterCollectLevel, 0).Serialize() - ) - .MintAsset(context, mcAddress, requiredGold * _currency); - } - } + _initialState = _initialState + .SetState( + _avatarAddress.Derive(LegacyInventoryKey), + _avatarState.inventory.Serialize() + ) + .SetState( + _avatarAddress.Derive(LegacyWorldInformationKey), + _avatarState.worldInformation.Serialize() + ) + .SetState( + _avatarAddress.Derive(LegacyQuestListKey), + _avatarState.questList.Serialize() + ) + .SetState(_avatarAddress, _avatarState.SerializeV2()); var action = new ItemEnhancement() { itemId = default, - materialId = materialId, + materialIds = materialIds, avatarAddress = _avatarAddress, slotIndex = 0, }; @@ -179,7 +218,7 @@ bool stake PreviousState = _initialState, Signer = _agentAddress, BlockIndex = 1, - Random = new TestRandom(randomSeed), + Random = new TestRandom(), }); var slotState = nextState.GetCombinationSlotState(_avatarAddress, 0); @@ -187,48 +226,65 @@ bool stake var nextAvatarState = nextState.GetAvatarState(_avatarAddress); Assert.Equal(default, resultEquipment.ItemId); Assert.Equal(expectedLevel, resultEquipment.level); - Assert.Equal(expectedGold * _currency, nextState.GetBalance(_agentAddress, _currency)); + Assert.Equal(startExp + expectedExpIncrement, resultEquipment.exp); + Assert.Equal( + (3_000_000 - expectedCost) * _currency, + nextState.GetBalance(_agentAddress, _currency) + ); var arenaSheet = _tableSheets.ArenaSheet; var arenaData = arenaSheet.GetRoundByBlockIndex(1); - var feeStoreAddress = Addresses.GetBlacksmithFeeAddress(arenaData.ChampionshipId, arenaData.Round); + var feeStoreAddress = + Addresses.GetBlacksmithFeeAddress(arenaData.ChampionshipId, arenaData.Round); Assert.Equal( - (1000 - expectedGold) * _currency, + expectedCost * _currency, nextState.GetBalance(feeStoreAddress, _currency) ); Assert.Equal(30, nextAvatarState.mailBox.Count); - var costRow = _tableSheets.EnhancementCostSheetV2 - .OrderedList - .First(x => x.Grade == 1 && x.Level == level + 1); + EnhancementCostSheetV3.Row startRow; + + if (startLevel != 0) + { + startRow = _tableSheets.EnhancementCostSheetV3.OrderedList + .First(x => x.Grade == 1 && x.Level == startLevel); + } + else + { + startRow = new EnhancementCostSheetV3.Row(); + } + + var targetRow = _tableSheets.EnhancementCostSheetV3.OrderedList + .First(x => x.Grade == 1 && x.Level == expectedLevel); var stateDict = (Dictionary)nextState.GetState(slotAddress); var slot = new CombinationSlotState(stateDict); var slotResult = (ItemEnhancement.ResultModel)slot.Result; - Assert.Equal(expected, slotResult.enhancementResult); - - switch (slotResult.enhancementResult) + if (startLevel != expectedLevel) { - case ItemEnhancement.EnhancementResult.GreatSuccess: - var baseAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); - var extraAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + 1); - Assert.Equal((int)(baseAtk + extraAtk), resultEquipment.StatsMap.ATK); - break; - case ItemEnhancement.EnhancementResult.Success: - var baseMinAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMin.NormalizeFromTenThousandths() + 1); - var baseMaxAtk = preItemUsable.StatsMap.BaseATK * (costRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); - var extraMinAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMin.NormalizeFromTenThousandths() + 1); - var extraMaxAtk = preItemUsable.StatsMap.AdditionalATK * (costRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + 1); - Assert.InRange(resultEquipment.StatsMap.ATK, baseMinAtk + extraMinAtk, baseMaxAtk + extraMaxAtk + 1); - break; - case ItemEnhancement.EnhancementResult.Fail: - Assert.Equal(preItemUsable.StatsMap.ATK, resultEquipment.StatsMap.ATK); - break; + var baseMinAtk = preItemUsable.StatsMap.BaseATK * + (targetRow.BaseStatGrowthMin.NormalizeFromTenThousandths() + 1); + var baseMaxAtk = preItemUsable.StatsMap.BaseATK * + (targetRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); + var extraMinAtk = preItemUsable.StatsMap.AdditionalATK * + (targetRow.ExtraStatGrowthMin.NormalizeFromTenThousandths() + + 1); + var extraMaxAtk = preItemUsable.StatsMap.AdditionalATK * + (targetRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + + 1); + Assert.InRange( + resultEquipment.StatsMap.ATK, + baseMinAtk + extraMinAtk, + baseMaxAtk + extraMaxAtk + 1 + ); } + Assert.Equal( + expectedBlockIndex + 1, // +1 for execution + resultEquipment.RequiredBlockIndex + ); Assert.Equal(preItemUsable.TradableId, slotResult.preItemUsable.TradableId); Assert.Equal(preItemUsable.TradableId, resultEquipment.TradableId); - Assert.Equal(costRow.Cost, slotResult.gold); - Assert.Equal(expectedCrystal * CrystalCalculator.CRYSTAL, slotResult.CRYSTAL); + Assert.Equal(targetRow.Cost - startRow.Cost, slotResult.gold); } } } diff --git a/.Lib9c.Tests/TableSheets.cs b/.Lib9c.Tests/TableSheets.cs index 1c536116aa..f334270d82 100644 --- a/.Lib9c.Tests/TableSheets.cs +++ b/.Lib9c.Tests/TableSheets.cs @@ -129,10 +129,10 @@ public TableSheets(Dictionary sheets) public EnhancementCostSheet EnhancementCostSheet { get; private set; } - public EquipmentItemUpgradePointSheet EquipmentItemUpgradePointSheet { get; private set; } - public EnhancementCostSheetV2 EnhancementCostSheetV2 { get; private set; } + public EnhancementCostSheetV3 EnhancementCostSheetV3 { get; private set; } + public WeeklyArenaRewardSheet WeeklyArenaRewardSheet { get; internal set; } public CostumeStatSheet CostumeStatSheet { get; private set; } diff --git a/Lib9c/Action/ItemEnhancement.cs b/Lib9c/Action/ItemEnhancement.cs index 86d7ef5bdd..d77ee51200 100644 --- a/Lib9c/Action/ItemEnhancement.cs +++ b/Lib9c/Action/ItemEnhancement.cs @@ -244,7 +244,7 @@ public override IAccountStateDelta Execute(IActionContext context) } var maxLevel = GetEquipmentMaxLevel(enhancementEquipment, enhancementCostSheet); - if (enhancementEquipment.level >= maxLevel) + if (enhancementEquipment.level > maxLevel) { throw new EquipmentLevelExceededException( $"{addressesHex} Aborted due to invalid equipment level: {enhancementEquipment.level} < {maxLevel}"); @@ -334,7 +334,7 @@ public override IAccountStateDelta Execute(IActionContext context) if (row.Level > enhancementEquipment.level) { - enhancementEquipment.SetLevel(ctx.Random, row); + enhancementEquipment.SetLevel(ctx.Random, row.Level, enhancementCostSheet); } EnhancementCostSheetV3.Row targetCostRow; diff --git a/Lib9c/Model/Item/Equipment.cs b/Lib9c/Model/Item/Equipment.cs index d22d5dd905..37a0dfed67 100644 --- a/Lib9c/Model/Item/Equipment.cs +++ b/Lib9c/Model/Item/Equipment.cs @@ -178,22 +178,29 @@ public void LevelUp(IRandom random, EnhancementCostSheetV2.Row row, bool isGreat } } - public void SetLevel(IRandom random, EnhancementCostSheetV3.Row row) + public void SetLevel(IRandom random, int targetLevel, EnhancementCostSheetV3 sheet) { - level = row.Level; - var rand = random.Next(row.BaseStatGrowthMin, row.BaseStatGrowthMax + 1); - var ratio = rand.NormalizeFromTenThousandths(); - var baseStat = StatsMap.GetBaseStat(UniqueStatType) * ratio; - if (baseStat > 0) + var startLevel = level; + level = targetLevel; + for (var i = startLevel + 1; i <= targetLevel; i++) { - baseStat = Math.Max(1.0m, baseStat); - } + var row = sheet.OrderedList.First( + r => r.Level == i && r.Grade == Grade && r.ItemSubType == ItemSubType + ); + var rand = random.Next(row.BaseStatGrowthMin, row.BaseStatGrowthMax + 1); + var ratio = rand.NormalizeFromTenThousandths(); + var baseStat = StatsMap.GetBaseStat(UniqueStatType) * ratio; + if (baseStat > 0) + { + baseStat = Math.Max(1.0m, baseStat); + } - StatsMap.AddStatValue(UniqueStatType, baseStat); + StatsMap.AddStatValue(UniqueStatType, baseStat); - if (GetOptionCount() > 0) - { - UpdateOptionsV3(random, row); + if (GetOptionCount() > 0) + { + UpdateOptionsV3(random, row); + } } } From 33859588052be9d06eaa589cf615c4e1f5887604 Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 16:10:24 +0900 Subject: [PATCH 16/20] Fix wrong test values --- .Lib9c.Tests/Action/ItemEnhancementTest.cs | 27 ++++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/.Lib9c.Tests/Action/ItemEnhancementTest.cs b/.Lib9c.Tests/Action/ItemEnhancementTest.cs index 2d1968551a..d6dcc25546 100644 --- a/.Lib9c.Tests/Action/ItemEnhancementTest.cs +++ b/.Lib9c.Tests/Action/ItemEnhancementTest.cs @@ -261,16 +261,23 @@ public void Execute( var slotResult = (ItemEnhancement.ResultModel)slot.Result; if (startLevel != expectedLevel) { - var baseMinAtk = preItemUsable.StatsMap.BaseATK * - (targetRow.BaseStatGrowthMin.NormalizeFromTenThousandths() + 1); - var baseMaxAtk = preItemUsable.StatsMap.BaseATK * - (targetRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1); - var extraMinAtk = preItemUsable.StatsMap.AdditionalATK * - (targetRow.ExtraStatGrowthMin.NormalizeFromTenThousandths() + - 1); - var extraMaxAtk = preItemUsable.StatsMap.AdditionalATK * - (targetRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + - 1); + var baseMinAtk = (decimal)preItemUsable.StatsMap.BaseATK; + var baseMaxAtk = (decimal)preItemUsable.StatsMap.BaseATK; + var extraMinAtk = (decimal)preItemUsable.StatsMap.AdditionalATK; + var extraMaxAtk = (decimal)preItemUsable.StatsMap.AdditionalATK; + + for (var i = startLevel + 1; i <= expectedLevel; i++) + { + var currentRow = _tableSheets.EnhancementCostSheetV3.OrderedList + .First(x => + x.Grade == 1 && x.ItemSubType == equipment.ItemSubType && x.Level == i); + + baseMinAtk *= currentRow.BaseStatGrowthMin.NormalizeFromTenThousandths() + 1; + baseMaxAtk *= currentRow.BaseStatGrowthMax.NormalizeFromTenThousandths() + 1; + extraMinAtk *= currentRow.ExtraStatGrowthMin.NormalizeFromTenThousandths() + 1; + extraMaxAtk *= currentRow.ExtraStatGrowthMax.NormalizeFromTenThousandths() + 1; + } + Assert.InRange( resultEquipment.StatsMap.ATK, baseMinAtk + extraMinAtk, From 926ea4581bfa43f5112b5470adbadd1e0b86c33e Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 16:10:43 +0900 Subject: [PATCH 17/20] Update ItemEnhancement action - Fix typo - Change `IEnumerable` to `List` --- Lib9c.Abstractions/IItemEnhancementV4.cs | 2 +- Lib9c/Action/ItemEnhancement.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib9c.Abstractions/IItemEnhancementV4.cs b/Lib9c.Abstractions/IItemEnhancementV4.cs index 5c31ea6a1d..f5bccd91f7 100644 --- a/Lib9c.Abstractions/IItemEnhancementV4.cs +++ b/Lib9c.Abstractions/IItemEnhancementV4.cs @@ -7,7 +7,7 @@ namespace Lib9c.Abstractions public interface IItemEnhancementV4 { Guid ItemId { get; } - IEnumerable MaterialIds { get; } + List MaterialIds { get; } Address AvatarAddress { get; } int SlotIndex { get; } } diff --git a/Lib9c/Action/ItemEnhancement.cs b/Lib9c/Action/ItemEnhancement.cs index d77ee51200..c7547657e6 100644 --- a/Lib9c/Action/ItemEnhancement.cs +++ b/Lib9c/Action/ItemEnhancement.cs @@ -46,7 +46,7 @@ public enum EnhancementResult public int slotIndex; Guid IItemEnhancementV4.ItemId => itemId; - IEnumerable IItemEnhancementV4.MaterialIds => materialIds; + List IItemEnhancementV4.MaterialIds => materialIds; Address IItemEnhancementV4.AvatarAddress => avatarAddress; int IItemEnhancementV4.SlotIndex => slotIndex; @@ -117,7 +117,7 @@ protected override IImmutableDictionary PlainValueInternal protected override void LoadPlainValueInternal(IImmutableDictionary plainValue) { itemId = plainValue["itemId"].ToGuid(); - materialIds = plainValue["materialId"].ToList(StateExtensions.ToGuid); + materialIds = plainValue["materialIds"].ToList(StateExtensions.ToGuid); avatarAddress = plainValue["avatarAddress"].ToAddress(); if (plainValue.TryGetValue((Text)"slotIndex", out var value)) { From 33d2d5cf6c7f18b560ccf8c3f9ab4b1cf2cb3190 Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 16:50:37 +0900 Subject: [PATCH 18/20] Specify ItemEnhancement version --- .Lib9c.Tests/Action/RapidCombinationTest.cs | 2 +- Lib9c.DevExtensions/Action/CreateOrReplaceAvatar.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.Lib9c.Tests/Action/RapidCombinationTest.cs b/.Lib9c.Tests/Action/RapidCombinationTest.cs index 2708dbaa9b..6182af6ed7 100644 --- a/.Lib9c.Tests/Action/RapidCombinationTest.cs +++ b/.Lib9c.Tests/Action/RapidCombinationTest.cs @@ -659,7 +659,7 @@ public void Execute_NotThrow_InvalidOperationException_When_TargetSlotCreatedBy( materialItemIdList = new[] { materialEquipment.NonFungibleId }, gold = 0, actionPoint = 0, - enhancementResult = ItemEnhancement.EnhancementResult.GreatSuccess, + enhancementResult = ItemEnhancement11.EnhancementResult.GreatSuccess, CRYSTAL = 0 * CrystalCalculator.CRYSTAL, }; diff --git a/Lib9c.DevExtensions/Action/CreateOrReplaceAvatar.cs b/Lib9c.DevExtensions/Action/CreateOrReplaceAvatar.cs index 90e84332b3..12448377a3 100644 --- a/Lib9c.DevExtensions/Action/CreateOrReplaceAvatar.cs +++ b/Lib9c.DevExtensions/Action/CreateOrReplaceAvatar.cs @@ -529,7 +529,7 @@ public IAccountStateDelta Execute( } if (eLevel > 0 && - ItemEnhancement.TryGetRow( + ItemEnhancement11.TryGetRow( equipment, enhancementCostSheetV2, out var enhancementCostRow)) From e75ee20eca972ce9bc36be385f826a032c9d0680 Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 17:19:56 +0900 Subject: [PATCH 19/20] Fix broken ActionEvaluationTest --- .Lib9c.Tests/Action/ActionEvaluationTest.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.Lib9c.Tests/Action/ActionEvaluationTest.cs b/.Lib9c.Tests/Action/ActionEvaluationTest.cs index 9a811172d9..6bed9f1a1e 100644 --- a/.Lib9c.Tests/Action/ActionEvaluationTest.cs +++ b/.Lib9c.Tests/Action/ActionEvaluationTest.cs @@ -192,7 +192,10 @@ private ActionBase GetAction(Type type) AuthorizedMiners = Dictionary.Empty, Credits = Dictionary.Empty, }, - ItemEnhancement _ => new ItemEnhancement(), + ItemEnhancement _ => new ItemEnhancement + { + materialIds = new List(), + }, MigrationActivatedAccountsState _ => new MigrationActivatedAccountsState(), MigrationAvatarState _ => new MigrationAvatarState { From 7610b6c173ddc916ad57fde2a9e52bb58dd6f86f Mon Sep 17 00:00:00 2001 From: hyeon Date: Fri, 18 Aug 2023 17:56:04 +0900 Subject: [PATCH 20/20] Fix broken RapidCombination tests --- .../CombinationSlotStateExtensions.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Lib9c/Extensions/CombinationSlotStateExtensions.cs b/Lib9c/Extensions/CombinationSlotStateExtensions.cs index 04561cc687..9724b67a2b 100644 --- a/Lib9c/Extensions/CombinationSlotStateExtensions.cs +++ b/Lib9c/Extensions/CombinationSlotStateExtensions.cs @@ -59,6 +59,9 @@ public static bool TryGetResultId(this CombinationSlotState state, out Guid resu case ItemEnhancement10.ResultModel r: resultId = r.id; break; + case ItemEnhancement11.ResultModel r: + resultId = r.id; + break; case MonsterCollectionResult r: resultId = r.id; break; @@ -111,6 +114,9 @@ public static bool TryGetResultIdV1(this CombinationSlotState state, out Guid re case ItemEnhancement7.ResultModel r: resultId = r.id; break; + case ItemEnhancement11.ResultModel r: + resultId = r.id; + break; case MonsterCollectionResult r: resultId = r.id; break; @@ -182,6 +188,13 @@ public static bool TryGetMail( resultId, requiredBlockIndex); return true; + case ItemEnhancement11.ResultModel r: + itemEnhanceMail = new ItemEnhanceMail( + r, + blockIndex, + resultId, + requiredBlockIndex); + return true; case CombinationConsumable5.ResultModel r: combinationMail = new CombinationMail( r, @@ -226,6 +239,13 @@ public static bool TryGetMailV1( resultId, requiredBlockIndex); return true; + case ItemEnhancement11.ResultModel r: + itemEnhanceMail = new ItemEnhanceMail( + r, + blockIndex, + resultId, + requiredBlockIndex); + return true; case CombinationConsumable5.ResultModel r: combinationMail = new CombinationMail( r,