diff --git a/.Lib9c.Tests/Action/AccountStateDeltaExtensionsTest.cs b/.Lib9c.Tests/Action/AccountStateDeltaExtensionsTest.cs index f8fcc75dfae..83fb2917c14 100644 --- a/.Lib9c.Tests/Action/AccountStateDeltaExtensionsTest.cs +++ b/.Lib9c.Tests/Action/AccountStateDeltaExtensionsTest.cs @@ -115,18 +115,11 @@ public void SetCouponWallet() var agentAddress1 = new Address("0000000000000000000000000000000000000000"); var agentAddress2 = new Address("0000000000000000000000000000000000000001"); - states = states.SetCouponWallet( - agentAddress1, - ImmutableDictionary.Empty - .Add(guid1, coupon1) - .Add(guid2, coupon2), true); - states = states.SetCouponWallet( agentAddress2, ImmutableDictionary.Empty); - Assert.Equal( - ActionBase.MarkChanged, + Assert.Null( states.GetState(agentAddress1.Derive(SerializeKeys.CouponWalletKey))); Assert.Equal( Bencodex.Types.List.Empty, diff --git a/.Lib9c.Tests/Action/ActionBaseExtensionsTest.cs b/.Lib9c.Tests/Action/ActionBaseExtensionsTest.cs deleted file mode 100644 index f40a828fef3..00000000000 --- a/.Lib9c.Tests/Action/ActionBaseExtensionsTest.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace Lib9c.Tests.Action -{ - using System.Collections.Immutable; - using Libplanet.Crypto; - using Nekoyume.Action; - using Xunit; - - public class ActionBaseExtensionsTest - { - [Fact] - public void CalculateUpdateAddresses() - { - var actions = new ActionBase[] - { - new TransferAsset( - sender: default, - recipient: default, - amount: Currencies.DailyRewardRune * 1 - ), - }; - - IImmutableSet
actual = actions.CalculateUpdateAddresses(); - Assert.Equal( - new Address[] - { - default, - }, - actual - ); - } - - [Fact] - public void CalculateUpdateAddressesWithIncompatibles() - { - var actions = new ActionBase[] - { - new TransferAsset( - sender: default, - recipient: default, - amount: Currencies.DailyRewardRune * 1 - ), - new HackAndSlashRandomBuff(), - }; - - IImmutableSet
actual = actions.CalculateUpdateAddresses(); - Assert.Equal( - new Address[] - { - default, - }, - actual - ); - } - } -} diff --git a/.Lib9c.Tests/Action/ActivateAccount0Test.cs b/.Lib9c.Tests/Action/ActivateAccount0Test.cs index 5157ab2676c..ff1904bb6b5 100644 --- a/.Lib9c.Tests/Action/ActivateAccount0Test.cs +++ b/.Lib9c.Tests/Action/ActivateAccount0Test.cs @@ -39,32 +39,6 @@ public void Execute() activatedAccounts.Accounts); } - [Fact] - public void Rehearsal() - { - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - var privateKey = new PrivateKey(); - (ActivationKey activationKey, PendingActivationState pendingActivation) = - ActivationKey.Create(privateKey, nonce); - - ActivateAccount0 action = activationKey.CreateActivateAccount0(nonce); - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - ActivatedAccountsState.Address, - pendingActivation.address - ), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void ExecuteWithInvalidSignature() { diff --git a/.Lib9c.Tests/Action/ActivateAccountTest.cs b/.Lib9c.Tests/Action/ActivateAccountTest.cs index 4006fe30594..33bf593c7de 100644 --- a/.Lib9c.Tests/Action/ActivateAccountTest.cs +++ b/.Lib9c.Tests/Action/ActivateAccountTest.cs @@ -62,33 +62,6 @@ public void Execute(bool invalid, bool pendingExist, bool alreadyActivated, Type } } - [Fact] - public void Rehearsal() - { - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - var privateKey = new PrivateKey(); - (ActivationKey activationKey, PendingActivationState pendingActivation) = - ActivationKey.Create(privateKey, nonce); - - ActivateAccount action = activationKey.CreateActivateAccount(nonce); - Address activatedAddress = default(Address).Derive(ActivationKey.DeriveKey); - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - activatedAddress, - pendingActivation.address - ), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void PlainValue() { diff --git a/.Lib9c.Tests/Action/AddActivatedAccount0Test.cs b/.Lib9c.Tests/Action/AddActivatedAccount0Test.cs index 051ba4fad36..50f35b07e34 100644 --- a/.Lib9c.Tests/Action/AddActivatedAccount0Test.cs +++ b/.Lib9c.Tests/Action/AddActivatedAccount0Test.cs @@ -39,35 +39,6 @@ public void Execute() ); } - [Fact] - public void Rehearsal() - { - var admin = new Address("8d9f76aF8Dc5A812aCeA15d8bf56E2F790F47fd7"); - var state = new Account( - MockState.Empty - .SetState(AdminState.Address, new AdminState(admin, 100).Serialize()) - .SetState(ActivatedAccountsState.Address, new ActivatedAccountsState().Serialize())); - var newComer = new Address("399bddF9F7B6d902ea27037B907B2486C9910730"); - var action = new AddActivatedAccount0(newComer); - - IAccount nextState = action.Execute(new ActionContext() - { - BlockIndex = 1, - Miner = default, - PreviousState = state, - Signer = admin, - Rehearsal = true, - }); - - Assert.Equal( - new[] - { - ActivatedAccountsState.Address, - }.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void ExecuteWithNonExistsAccounts() { diff --git a/.Lib9c.Tests/Action/AddActivatedAccountTest.cs b/.Lib9c.Tests/Action/AddActivatedAccountTest.cs index a9ca6661ea6..081d6622a47 100644 --- a/.Lib9c.Tests/Action/AddActivatedAccountTest.cs +++ b/.Lib9c.Tests/Action/AddActivatedAccountTest.cs @@ -55,34 +55,6 @@ public void Execute(bool isAdmin, long blockIndex, bool alreadyActivated, Type e } } - [Fact] - public void Rehearsal() - { - var admin = new Address("8d9f76aF8Dc5A812aCeA15d8bf56E2F790F47fd7"); - var state = new Account( - MockState.Empty - .SetState(AdminState.Address, new AdminState(admin, 100).Serialize())); - var newComer = new Address("399bddF9F7B6d902ea27037B907B2486C9910730"); - var action = new AddActivatedAccount(newComer); - - IAccount nextState = action.Execute(new ActionContext() - { - BlockIndex = 1, - Miner = default, - PreviousState = state, - Signer = admin, - Rehearsal = true, - }); - - Assert.Equal( - new[] - { - newComer.Derive(ActivationKey.DeriveKey), - }.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void PlainValue() { diff --git a/.Lib9c.Tests/Action/AddRedeemCodeTest.cs b/.Lib9c.Tests/Action/AddRedeemCodeTest.cs index 95dd080a1c9..f527e8beec0 100644 --- a/.Lib9c.Tests/Action/AddRedeemCodeTest.cs +++ b/.Lib9c.Tests/Action/AddRedeemCodeTest.cs @@ -105,26 +105,5 @@ public void ExecuteThrowSheetRowValidateException() }) ); } - - [Fact] - public void Rehearsal() - { - var action = new AddRedeemCode - { - redeemCsv = "test", - }; - - var nextState = action.Execute(new ActionContext - { - BlockIndex = 0, - PreviousState = new Account(MockState.Empty), - Rehearsal = true, - }); - - Assert.Equal( - nextState.Delta.UpdatedAddresses, - new[] { Addresses.RedeemCode }.ToImmutableHashSet() - ); - } } } diff --git a/.Lib9c.Tests/Action/BattleArena14Test.cs b/.Lib9c.Tests/Action/BattleArena14Test.cs new file mode 100644 index 00000000000..f22acdde836 --- /dev/null +++ b/.Lib9c.Tests/Action/BattleArena14Test.cs @@ -0,0 +1,1315 @@ +namespace Lib9c.Tests.Action +{ + using System; + using System.Collections.Generic; + 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.Arena; + using Nekoyume.Model; + using Nekoyume.Model.Arena; + using Nekoyume.Model.EnumType; + using Nekoyume.Model.Rune; + using Nekoyume.Model.State; + using Nekoyume.TableData; + using Serilog; + using Xunit; + using Xunit.Abstractions; + using static Lib9c.SerializeKeys; + + public class BattleArena14Test + { + private readonly Dictionary _sheets; + private readonly TableSheets _tableSheets; + + private readonly Address _agent1Address; + private readonly Address _agent2Address; + private readonly Address _agent3Address; + private readonly Address _agent4Address; + private readonly Address _avatar1Address; + private readonly Address _avatar2Address; + private readonly Address _avatar3Address; + private readonly Address _avatar4Address; + private readonly Currency _crystal; + private readonly Currency _ncg; + private IAccount _initialStates; + + public BattleArena14Test(ITestOutputHelper outputHelper) + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.TestOutput(outputHelper) + .CreateLogger(); + + _initialStates = new Account(MockState.Empty); + + _sheets = TableSheetsImporter.ImportSheets(); + foreach (var (key, value) in _sheets) + { + _initialStates = _initialStates.SetState( + Addresses.TableSheet.Derive(key), + value.Serialize()); + } + + _tableSheets = new TableSheets(_sheets); +#pragma warning disable CS0618 + // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1419 + _crystal = Currency.Legacy("CRYSTAL", 18, null); + _ncg = Currency.Legacy("NCG", 2, null); +#pragma warning restore CS0618 + var goldCurrencyState = new GoldCurrencyState(_ncg); + + var rankingMapAddress = new PrivateKey().ToAddress(); + var clearStageId = Math.Max( + _tableSheets.StageSheet.First?.Id ?? 1, + GameConfig.RequireClearedStageLevel.ActionsInRankingBoard); + + // account 1 + var (agent1State, avatar1State) = GetAgentStateWithAvatarState( + _sheets, + _tableSheets, + rankingMapAddress, + clearStageId); + + _agent1Address = agent1State.address; + _avatar1Address = avatar1State.address; + + // account 2 + var (agent2State, avatar2State) = GetAgentStateWithAvatarState( + _sheets, + _tableSheets, + rankingMapAddress, + clearStageId); + _agent2Address = agent2State.address; + _avatar2Address = avatar2State.address; + + // account 3 + var (agent3State, avatar3State) = GetAgentStateWithAvatarState( + _sheets, + _tableSheets, + rankingMapAddress, + 1); + _agent3Address = agent3State.address; + _avatar3Address = avatar3State.address; + + // account 4 + var (agent4State, avatar4State) = GetAgentStateWithAvatarState( + _sheets, + _tableSheets, + rankingMapAddress, + 1); + + _agent4Address = agent4State.address; + _avatar4Address = avatar4State.address; + + _initialStates = _initialStates + .SetState(Addresses.GoldCurrency, goldCurrencyState.Serialize()) + .SetState(_agent1Address, agent1State.Serialize()) + .SetState( + _avatar1Address.Derive(LegacyInventoryKey), + avatar1State.inventory.Serialize()) + .SetState( + _avatar1Address.Derive(LegacyWorldInformationKey), + avatar1State.worldInformation.Serialize()) + .SetState( + _avatar1Address.Derive(LegacyQuestListKey), + avatar1State.questList.Serialize()) + .SetState(_avatar1Address, avatar1State.SerializeV2()) + .SetState(_agent2Address, agent2State.Serialize()) + .SetState(_avatar2Address, avatar2State.Serialize()) + .SetState(_agent3Address, agent3State.Serialize()) + .SetState(_avatar3Address, avatar3State.Serialize()) + .SetState(_agent4Address, agent4State.Serialize()) + .SetState( + _avatar4Address.Derive(LegacyInventoryKey), + avatar4State.inventory.Serialize()) + .SetState( + _avatar4Address.Derive(LegacyWorldInformationKey), + avatar4State.worldInformation.Serialize()) + .SetState( + _avatar4Address.Derive(LegacyQuestListKey), + avatar4State.questList.Serialize()) + .SetState(_avatar4Address, avatar4State.SerializeV2()) + .SetState( + Addresses.GameConfig, + new GameConfigState(_sheets[nameof(GameConfigSheet)]).Serialize()); + + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.TestOutput(outputHelper) + .CreateLogger(); + } + + [Theory] + [InlineData(1, 1, false, 1, 5, 3)] + [InlineData(1, 1, false, 1, 5, 4)] + [InlineData(1, 1, false, 5, 5, 3)] + [InlineData(1, 1, true, 1, 5, 3)] + [InlineData(1, 1, false, 3, 5, 4)] + [InlineData(1, 2, false, 1, 5, 3)] + [InlineData(1, 2, true, 1, 5, 3)] + [InlineData(1, 3, false, 1, int.MaxValue, 3)] + [InlineData(1, 3, true, 1, int.MaxValue, 3)] + public void Execute_Success( + int championshipId, + int round, + bool isPurchased, + int ticket, + int arenaInterval, + int randomSeed) + { + Execute( + championshipId, + round, + isPurchased, + ticket, + arenaInterval, + randomSeed, + _agent1Address, + _avatar1Address, + _agent2Address, + _avatar2Address); + } + + [Fact] + public void Execute_Backward_Compatibility_Success() + { + Execute( + 1, + 2, + default, + 1, + 2, + default, + _agent2Address, + _avatar2Address, + _agent1Address, + _avatar1Address); + } + + [Fact] + public void Execute_InvalidAddressException() + { + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar1Address, + championshipId = 1, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_FailedLoadStateException() + { + var action = new BattleArena14 + { + myAvatarAddress = _avatar2Address, + enemyAvatarAddress = _avatar1Address, + championshipId = 1, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_SheetRowNotFoundException() + { + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = 9999999, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_ThisArenaIsClosedException() + { + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = 1, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + BlockIndex = 4480001, + })); + } + + [Fact] + public void Execute_ArenaParticipantsNotFoundException() + { + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = 1, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + BlockIndex = 1, + })); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Execute_AddressNotFoundInArenaParticipantsException(bool excludeMe) + { + const int championshipId = 1; + const int round = 1; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = excludeMe + ? JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random) + : JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => + action.Execute(new ActionContext + { + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + BlockIndex = 1, + })); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Execute_ValidateScoreDifferenceException(bool isSigner) + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaScoreAdr = ArenaScore.DeriveAddress( + isSigner + ? _avatar1Address + : _avatar2Address, roundData.ChampionshipId, + roundData.Round); + previousStates.TryGetArenaScore(arenaScoreAdr, out var arenaScore); + arenaScore.AddScore(900); + previousStates = previousStates.SetState(arenaScoreAdr, arenaScore.Serialize()); + + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_InsufficientBalanceException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(beforeInfo.Ticket); + previousStates = previousStates.SetState(arenaInfoAdr, beforeInfo.Serialize()); + + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_ExceedPlayCountException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 2, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_ExceedTicketPurchaseLimitException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(ArenaInformation.MaxTicketCount); + var max = roundData.MaxPurchaseCount; + for (var i = 0; i < max; i++) + { + beforeInfo.BuyTicket(roundData.MaxPurchaseCount); + } + + previousStates = previousStates.SetState(arenaInfoAdr, beforeInfo.Serialize()); + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, _agent1Address, price); + + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_ExceedTicketPurchaseLimitDuringIntervalException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(ArenaInformation.MaxTicketCount); + var max = roundData.MaxPurchaseCountWithInterval; + for (var i = 0; i < max; i++) + { + beforeInfo.BuyTicket(roundData.MaxPurchaseCount); + } + + var purchasedCountDuringInterval = arenaInfoAdr.Derive(BattleArena14.PurchasedCountKey); + previousStates = previousStates + .SetState(arenaInfoAdr, beforeInfo.Serialize()) + .SetState( + purchasedCountDuringInterval, + new Integer(beforeInfo.PurchasedTicketCount)); + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, _agent1Address, price); + + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_CoolDownBlockException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(ArenaInformation.MaxTicketCount); + var max = roundData.MaxPurchaseCountWithInterval; + previousStates = previousStates.SetState(arenaInfoAdr, beforeInfo.Serialize()); + for (var i = 0; i < max; i++) + { + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, _agent1Address, price); + beforeInfo.BuyTicket(roundData.MaxPurchaseCount); + } + + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + + var nextStates = action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + }); + + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex + 1, + PreviousState = nextStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Theory] + [InlineData(0, 30001, 1, 30001, typeof(DuplicatedRuneIdException))] + [InlineData(1, 10002, 1, 30001, typeof(DuplicatedRuneSlotIndexException))] + public void ExecuteDuplicatedException(int slotIndex, int runeId, int slotIndex2, int runeId2, Type exception) + { + long nextBlockIndex = 4; + int championshipId = 1; + int round = 1; + int ticket = 1; + int arenaInterval = 5; + int randomSeed = 3; + + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(_initialStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(randomSeed); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + var ncgCurrency = previousStates.GetGoldCurrency(); + previousStates = previousStates.MintAsset(context, _agent1Address, 99999 * ncgCurrency); + + var unlockRuneSlot = new UnlockRuneSlot() + { + AvatarAddress = _avatar1Address, + SlotIndex = 1, + }; + + previousStates = unlockRuneSlot.Execute(new ActionContext + { + BlockIndex = 1, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + }); + + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = ticket, + costumes = new List(), + equipments = new List(), + runeInfos = new List() + { + new RuneSlotInfo(slotIndex, runeId), + new RuneSlotInfo(slotIndex2, runeId2), + }, + }; + + var myScoreAdr = ArenaScore.DeriveAddress( + _avatar1Address, + championshipId, + round); + var enemyScoreAdr = ArenaScore.DeriveAddress( + _avatar2Address, + championshipId, + round); + if (!previousStates.TryGetArenaScore(myScoreAdr, out var beforeMyScore)) + { + throw new ArenaScoreNotFoundException($"myScoreAdr : {myScoreAdr}"); + } + + if (!previousStates.TryGetArenaScore(enemyScoreAdr, out var beforeEnemyScore)) + { + throw new ArenaScoreNotFoundException($"enemyScoreAdr : {enemyScoreAdr}"); + } + + Assert.True(previousStates.TryGetAvatarStateV2( + _agent1Address, + _avatar1Address, + out var previousMyAvatarState, + out _)); + Assert.Empty(previousMyAvatarState.inventory.Materials); + + var gameConfigState = SetArenaInterval(arenaInterval); + previousStates = previousStates.SetState(GameConfigState.Address, gameConfigState.Serialize()); + + var blockIndex = roundData.StartBlockIndex + nextBlockIndex; + + Assert.Throws(exception, () => action.Execute(new ActionContext + { + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = random.Seed, + Rehearsal = false, + BlockIndex = blockIndex, + })); + } + + [Fact] + public void Execute_ValidateDuplicateTicketPurchaseException() + { + const int championshipId = 1; + const int round = 1; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + if (roundData.ArenaType != ArenaType.OffSeason) + { + throw new InvalidSeasonException($"[{nameof(BattleArena14)}] This test is only for OffSeason. ArenaType : {roundData.ArenaType}"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(ArenaInformation.MaxTicketCount); + + var purchasedCountDuringInterval = arenaInfoAdr.Derive(BattleArena14.PurchasedCountKey); + previousStates = previousStates + .SetState(arenaInfoAdr, beforeInfo.Serialize()) + .SetState( + purchasedCountDuringInterval, + new Integer(beforeInfo.PurchasedTicketCount)); + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, _agent1Address, price); + + var action = new BattleArena14 + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 8, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + private static (AgentState AgentState, AvatarState AvatarState) GetAgentStateWithAvatarState( + IReadOnlyDictionary sheets, + TableSheets tableSheets, + Address rankingMapAddress, + int clearStageId) + { + var agentAddress = new PrivateKey().ToAddress(); + var agentState = new AgentState(agentAddress); + + var avatarAddress = agentAddress.Derive("avatar"); + var avatarState = new AvatarState( + avatarAddress, + agentAddress, + 0, + tableSheets.GetAvatarSheets(), + new GameConfigState(sheets[nameof(GameConfigSheet)]), + rankingMapAddress) + { + worldInformation = new WorldInformation( + 0, + tableSheets.WorldSheet, + clearStageId), + }; + agentState.avatarAddresses.Add(0, avatarAddress); + + return (agentState, avatarState); + } + + private void Execute( + int championshipId, + int round, + bool isPurchased, + int ticket, + int arenaInterval, + int randomSeed, + Address myAgentAddress, + Address myAvatarAddress, + Address enemyAgentAddress, + Address enemyAvatarAddress) + { + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(_initialStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(randomSeed); + previousStates = JoinArena( + context, + previousStates, + myAgentAddress, + myAvatarAddress, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + enemyAgentAddress, + enemyAvatarAddress, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(myAvatarAddress, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + if (isPurchased) + { + beforeInfo.UseTicket(beforeInfo.Ticket); + previousStates = previousStates.SetState(arenaInfoAdr, beforeInfo.Serialize()); + for (var i = 0; i < ticket; i++) + { + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, myAgentAddress, price); + beforeInfo.BuyTicket(roundData.MaxPurchaseCount); + } + } + + var action = new BattleArena14 + { + myAvatarAddress = myAvatarAddress, + enemyAvatarAddress = enemyAvatarAddress, + championshipId = championshipId, + round = round, + ticket = ticket, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var myScoreAdr = ArenaScore.DeriveAddress( + myAvatarAddress, + championshipId, + round); + var enemyScoreAdr = ArenaScore.DeriveAddress( + enemyAvatarAddress, + championshipId, + round); + if (!previousStates.TryGetArenaScore(myScoreAdr, out var beforeMyScore)) + { + throw new ArenaScoreNotFoundException($"myScoreAdr : {myScoreAdr}"); + } + + if (!previousStates.TryGetArenaScore(enemyScoreAdr, out var beforeEnemyScore)) + { + throw new ArenaScoreNotFoundException($"enemyScoreAdr : {enemyScoreAdr}"); + } + + Assert.True(previousStates.TryGetAvatarStateV2( + myAgentAddress, + myAvatarAddress, + out var previousMyAvatarState, + out _)); + Assert.Empty(previousMyAvatarState.inventory.Materials); + + var gameConfigState = SetArenaInterval(arenaInterval); + previousStates = previousStates.SetState(GameConfigState.Address, gameConfigState.Serialize()); + + var blockIndex = roundData.StartBlockIndex < arenaInterval + ? roundData.StartBlockIndex + : roundData.StartBlockIndex + arenaInterval; + var nextStates = action.Execute(new ActionContext + { + PreviousState = previousStates, + Signer = myAgentAddress, + RandomSeed = random.Seed, + Rehearsal = false, + BlockIndex = blockIndex, + }); + + if (!nextStates.TryGetArenaScore(myScoreAdr, out var myAfterScore)) + { + throw new ArenaScoreNotFoundException($"myScoreAdr : {myScoreAdr}"); + } + + if (!nextStates.TryGetArenaScore(enemyScoreAdr, out var enemyAfterScore)) + { + throw new ArenaScoreNotFoundException($"enemyScoreAdr : {enemyScoreAdr}"); + } + + if (!nextStates.TryGetArenaInformation(arenaInfoAdr, out var afterInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + var (myWinScore, myDefeatScore, enemyWinScore) = + ArenaHelper.GetScoresV1(beforeMyScore.Score, beforeEnemyScore.Score); + + var addMyScore = afterInfo.Win * myWinScore + afterInfo.Lose * myDefeatScore; + var addEnemyScore = afterInfo.Win * enemyWinScore; + var expectedMyScore = Math.Max( + beforeMyScore.Score + addMyScore, + ArenaScore.ArenaScoreDefault); + var expectedEnemyScore = Math.Max( + beforeEnemyScore.Score + addEnemyScore, + ArenaScore.ArenaScoreDefault); + + Assert.Equal(expectedMyScore, myAfterScore.Score); + Assert.Equal(expectedEnemyScore, enemyAfterScore.Score); + Assert.Equal( + isPurchased + ? 0 + : ArenaInformation.MaxTicketCount, + beforeInfo.Ticket); + Assert.Equal(0, beforeInfo.Win); + Assert.Equal(0, beforeInfo.Lose); + + var useTicket = Math.Min(ticket, beforeInfo.Ticket); + Assert.Equal(beforeInfo.Ticket - useTicket, afterInfo.Ticket); + Assert.Equal(ticket, afterInfo.Win + afterInfo.Lose); + + var balance = nextStates.GetBalance( + myAgentAddress, + nextStates.GetGoldCurrency()); + if (isPurchased) + { + Assert.Equal(ticket, afterInfo.PurchasedTicketCount); + } + + Assert.Equal(0, balance.RawValue); + + var avatarState = nextStates.GetAvatarStateV2(myAvatarAddress); + var medalCount = 0; + if (roundData.ArenaType != ArenaType.OffSeason) + { + var medalId = ArenaHelper.GetMedalItemId(championshipId, round); + avatarState.inventory.TryGetItem(medalId, out var medal); + if (afterInfo.Win > 0) + { + Assert.Equal(afterInfo.Win, medal.count); + } + else + { + Assert.Null(medal); + } + + medalCount = medal?.count ?? 0; + } + + var materialCount = avatarState.inventory.Materials.Count(); + var high = (ArenaHelper.GetRewardCount(beforeMyScore.Score) * ticket) + medalCount; + Assert.InRange(materialCount, 0, high); + } + + private IAccount JoinArena( + IActionContext context, + IAccount states, + Address signer, + Address avatarAddress, + long blockIndex, + int championshipId, + int round, + IRandom random) + { + var preCurrency = 1000 * _crystal; + states = states.MintAsset(context, signer, preCurrency); + + var action = new JoinArena1 + { + championshipId = championshipId, + round = round, + costumes = new List(), + equipments = new List(), + avatarAddress = avatarAddress, + }; + + states = action.Execute(new ActionContext + { + PreviousState = states, + Signer = signer, + RandomSeed = random.Seed, + Rehearsal = false, + BlockIndex = blockIndex, + }); + return states; + } + + private GameConfigState SetArenaInterval(int interval) + { + var gameConfigState = _initialStates.GetGameConfigState(); + var sheet = _tableSheets.GameConfigSheet; + foreach (var value in sheet.Values) + { + if (value.Key.Equals("battle_arena_interval")) + { + IReadOnlyList field = new[] + { + value.Key, + interval.ToString(), + }; + value.Set(field); + } + } + + gameConfigState.Set(sheet); + return gameConfigState; + } + } +} diff --git a/.Lib9c.Tests/Action/BattleArenaTest.cs b/.Lib9c.Tests/Action/BattleArenaTest.cs new file mode 100644 index 00000000000..e5b89c26ec3 --- /dev/null +++ b/.Lib9c.Tests/Action/BattleArenaTest.cs @@ -0,0 +1,1315 @@ +namespace Lib9c.Tests.Action +{ + using System; + using System.Collections.Generic; + 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.Arena; + using Nekoyume.Model; + using Nekoyume.Model.Arena; + using Nekoyume.Model.EnumType; + using Nekoyume.Model.Rune; + using Nekoyume.Model.State; + using Nekoyume.TableData; + using Serilog; + using Xunit; + using Xunit.Abstractions; + using static Lib9c.SerializeKeys; + + public class BattleArenaTest + { + private readonly Dictionary _sheets; + private readonly TableSheets _tableSheets; + + private readonly Address _agent1Address; + private readonly Address _agent2Address; + private readonly Address _agent3Address; + private readonly Address _agent4Address; + private readonly Address _avatar1Address; + private readonly Address _avatar2Address; + private readonly Address _avatar3Address; + private readonly Address _avatar4Address; + private readonly Currency _crystal; + private readonly Currency _ncg; + private IAccount _initialStates; + + public BattleArenaTest(ITestOutputHelper outputHelper) + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.TestOutput(outputHelper) + .CreateLogger(); + + _initialStates = new Account(MockState.Empty); + + _sheets = TableSheetsImporter.ImportSheets(); + foreach (var (key, value) in _sheets) + { + _initialStates = _initialStates.SetState( + Addresses.TableSheet.Derive(key), + value.Serialize()); + } + + _tableSheets = new TableSheets(_sheets); +#pragma warning disable CS0618 + // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1419 + _crystal = Currency.Legacy("CRYSTAL", 18, null); + _ncg = Currency.Legacy("NCG", 2, null); +#pragma warning restore CS0618 + var goldCurrencyState = new GoldCurrencyState(_ncg); + + var rankingMapAddress = new PrivateKey().ToAddress(); + var clearStageId = Math.Max( + _tableSheets.StageSheet.First?.Id ?? 1, + GameConfig.RequireClearedStageLevel.ActionsInRankingBoard); + + // account 1 + var (agent1State, avatar1State) = GetAgentStateWithAvatarState( + _sheets, + _tableSheets, + rankingMapAddress, + clearStageId); + + _agent1Address = agent1State.address; + _avatar1Address = avatar1State.address; + + // account 2 + var (agent2State, avatar2State) = GetAgentStateWithAvatarState( + _sheets, + _tableSheets, + rankingMapAddress, + clearStageId); + _agent2Address = agent2State.address; + _avatar2Address = avatar2State.address; + + // account 3 + var (agent3State, avatar3State) = GetAgentStateWithAvatarState( + _sheets, + _tableSheets, + rankingMapAddress, + 1); + _agent3Address = agent3State.address; + _avatar3Address = avatar3State.address; + + // account 4 + var (agent4State, avatar4State) = GetAgentStateWithAvatarState( + _sheets, + _tableSheets, + rankingMapAddress, + 1); + + _agent4Address = agent4State.address; + _avatar4Address = avatar4State.address; + + _initialStates = _initialStates + .SetState(Addresses.GoldCurrency, goldCurrencyState.Serialize()) + .SetState(_agent1Address, agent1State.Serialize()) + .SetState( + _avatar1Address.Derive(LegacyInventoryKey), + avatar1State.inventory.Serialize()) + .SetState( + _avatar1Address.Derive(LegacyWorldInformationKey), + avatar1State.worldInformation.Serialize()) + .SetState( + _avatar1Address.Derive(LegacyQuestListKey), + avatar1State.questList.Serialize()) + .SetState(_avatar1Address, avatar1State.SerializeV2()) + .SetState(_agent2Address, agent2State.Serialize()) + .SetState(_avatar2Address, avatar2State.Serialize()) + .SetState(_agent3Address, agent3State.Serialize()) + .SetState(_avatar3Address, avatar3State.Serialize()) + .SetState(_agent4Address, agent4State.Serialize()) + .SetState( + _avatar4Address.Derive(LegacyInventoryKey), + avatar4State.inventory.Serialize()) + .SetState( + _avatar4Address.Derive(LegacyWorldInformationKey), + avatar4State.worldInformation.Serialize()) + .SetState( + _avatar4Address.Derive(LegacyQuestListKey), + avatar4State.questList.Serialize()) + .SetState(_avatar4Address, avatar4State.SerializeV2()) + .SetState( + Addresses.GameConfig, + new GameConfigState(_sheets[nameof(GameConfigSheet)]).Serialize()); + + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.TestOutput(outputHelper) + .CreateLogger(); + } + + [Theory] + [InlineData(1, 1, false, 1, 5, 3)] + [InlineData(1, 1, false, 1, 5, 4)] + [InlineData(1, 1, false, 5, 5, 3)] + [InlineData(1, 1, true, 1, 5, 3)] + [InlineData(1, 1, false, 3, 5, 4)] + [InlineData(1, 2, false, 1, 5, 3)] + [InlineData(1, 2, true, 1, 5, 3)] + [InlineData(1, 3, false, 1, int.MaxValue, 3)] + [InlineData(1, 3, true, 1, int.MaxValue, 3)] + public void Execute_Success( + int championshipId, + int round, + bool isPurchased, + int ticket, + int arenaInterval, + int randomSeed) + { + Execute( + championshipId, + round, + isPurchased, + ticket, + arenaInterval, + randomSeed, + _agent1Address, + _avatar1Address, + _agent2Address, + _avatar2Address); + } + + [Fact] + public void Execute_Backward_Compatibility_Success() + { + Execute( + 1, + 2, + default, + 1, + 2, + default, + _agent2Address, + _avatar2Address, + _agent1Address, + _avatar1Address); + } + + [Fact] + public void Execute_InvalidAddressException() + { + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar1Address, + championshipId = 1, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_FailedLoadStateException() + { + var action = new BattleArena + { + myAvatarAddress = _avatar2Address, + enemyAvatarAddress = _avatar1Address, + championshipId = 1, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_SheetRowNotFoundException() + { + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = 9999999, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_ThisArenaIsClosedException() + { + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = 1, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + BlockIndex = 4480001, + })); + } + + [Fact] + public void Execute_ArenaParticipantsNotFoundException() + { + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = 1, + round = 1, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => action.Execute(new ActionContext + { + PreviousState = _initialStates, + Signer = _agent1Address, + RandomSeed = 0, + BlockIndex = 1, + })); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Execute_AddressNotFoundInArenaParticipantsException(bool excludeMe) + { + const int championshipId = 1; + const int round = 1; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = excludeMe + ? JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random) + : JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + Assert.Throws(() => + action.Execute(new ActionContext + { + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + BlockIndex = 1, + })); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Execute_ValidateScoreDifferenceException(bool isSigner) + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaScoreAdr = ArenaScore.DeriveAddress( + isSigner + ? _avatar1Address + : _avatar2Address, roundData.ChampionshipId, + roundData.Round); + previousStates.TryGetArenaScore(arenaScoreAdr, out var arenaScore); + arenaScore.AddScore(900); + previousStates = previousStates.SetState(arenaScoreAdr, arenaScore.Serialize()); + + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_InsufficientBalanceException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(beforeInfo.Ticket); + previousStates = previousStates.SetState(arenaInfoAdr, beforeInfo.Serialize()); + + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_ExceedPlayCountException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 2, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_ExceedTicketPurchaseLimitException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(ArenaInformation.MaxTicketCount); + var max = roundData.MaxPurchaseCount; + for (var i = 0; i < max; i++) + { + beforeInfo.BuyTicket(roundData.MaxPurchaseCount); + } + + previousStates = previousStates.SetState(arenaInfoAdr, beforeInfo.Serialize()); + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, _agent1Address, price); + + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_ExceedTicketPurchaseLimitDuringIntervalException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(ArenaInformation.MaxTicketCount); + var max = roundData.MaxPurchaseCountWithInterval; + for (var i = 0; i < max; i++) + { + beforeInfo.BuyTicket(roundData.MaxPurchaseCount); + } + + var purchasedCountDuringInterval = arenaInfoAdr.Derive(BattleArena.PurchasedCountKey); + previousStates = previousStates + .SetState(arenaInfoAdr, beforeInfo.Serialize()) + .SetState( + purchasedCountDuringInterval, + new Integer(beforeInfo.PurchasedTicketCount)); + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, _agent1Address, price); + + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Fact] + public void Execute_CoolDownBlockException() + { + const int championshipId = 1; + const int round = 2; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(ArenaInformation.MaxTicketCount); + var max = roundData.MaxPurchaseCountWithInterval; + previousStates = previousStates.SetState(arenaInfoAdr, beforeInfo.Serialize()); + for (var i = 0; i < max; i++) + { + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, _agent1Address, price); + beforeInfo.BuyTicket(roundData.MaxPurchaseCount); + } + + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 1, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + + var nextStates = action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + }); + + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex + 1, + PreviousState = nextStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + [Theory] + [InlineData(0, 30001, 1, 30001, typeof(DuplicatedRuneIdException))] + [InlineData(1, 10002, 1, 30001, typeof(DuplicatedRuneSlotIndexException))] + public void ExecuteDuplicatedException(int slotIndex, int runeId, int slotIndex2, int runeId2, Type exception) + { + long nextBlockIndex = 4; + int championshipId = 1; + int round = 1; + int ticket = 1; + int arenaInterval = 5; + int randomSeed = 3; + + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(_initialStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(randomSeed); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + var ncgCurrency = previousStates.GetGoldCurrency(); + previousStates = previousStates.MintAsset(context, _agent1Address, 99999 * ncgCurrency); + + var unlockRuneSlot = new UnlockRuneSlot() + { + AvatarAddress = _avatar1Address, + SlotIndex = 1, + }; + + previousStates = unlockRuneSlot.Execute(new ActionContext + { + BlockIndex = 1, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + }); + + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = ticket, + costumes = new List(), + equipments = new List(), + runeInfos = new List() + { + new RuneSlotInfo(slotIndex, runeId), + new RuneSlotInfo(slotIndex2, runeId2), + }, + }; + + var myScoreAdr = ArenaScore.DeriveAddress( + _avatar1Address, + championshipId, + round); + var enemyScoreAdr = ArenaScore.DeriveAddress( + _avatar2Address, + championshipId, + round); + if (!previousStates.TryGetArenaScore(myScoreAdr, out var beforeMyScore)) + { + throw new ArenaScoreNotFoundException($"myScoreAdr : {myScoreAdr}"); + } + + if (!previousStates.TryGetArenaScore(enemyScoreAdr, out var beforeEnemyScore)) + { + throw new ArenaScoreNotFoundException($"enemyScoreAdr : {enemyScoreAdr}"); + } + + Assert.True(previousStates.TryGetAvatarStateV2( + _agent1Address, + _avatar1Address, + out var previousMyAvatarState, + out _)); + Assert.Empty(previousMyAvatarState.inventory.Materials); + + var gameConfigState = SetArenaInterval(arenaInterval); + previousStates = previousStates.SetState(GameConfigState.Address, gameConfigState.Serialize()); + + var blockIndex = roundData.StartBlockIndex + nextBlockIndex; + + Assert.Throws(exception, () => action.Execute(new ActionContext + { + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = random.Seed, + Rehearsal = false, + BlockIndex = blockIndex, + })); + } + + [Fact] + public void Execute_ValidateDuplicateTicketPurchaseException() + { + const int championshipId = 1; + const int round = 1; + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(previousStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + if (roundData.ArenaType != ArenaType.OffSeason) + { + throw new InvalidSeasonException($"[{nameof(BattleArena)}] This test is only for OffSeason. ArenaType : {roundData.ArenaType}"); + } + + var random = new TestRandom(); + previousStates = JoinArena( + context, + previousStates, + _agent1Address, + _avatar1Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + _agent2Address, + _avatar2Address, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(_avatar1Address, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + beforeInfo.UseTicket(ArenaInformation.MaxTicketCount); + + var purchasedCountDuringInterval = arenaInfoAdr.Derive(BattleArena.PurchasedCountKey); + previousStates = previousStates + .SetState(arenaInfoAdr, beforeInfo.Serialize()) + .SetState( + purchasedCountDuringInterval, + new Integer(beforeInfo.PurchasedTicketCount)); + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, _agent1Address, price); + + var action = new BattleArena + { + myAvatarAddress = _avatar1Address, + enemyAvatarAddress = _avatar2Address, + championshipId = championshipId, + round = round, + ticket = 8, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var blockIndex = roundData.StartBlockIndex + 1; + Assert.Throws(() => action.Execute(new ActionContext + { + BlockIndex = blockIndex, + PreviousState = previousStates, + Signer = _agent1Address, + RandomSeed = 0, + })); + } + + private static (AgentState AgentState, AvatarState AvatarState) GetAgentStateWithAvatarState( + IReadOnlyDictionary sheets, + TableSheets tableSheets, + Address rankingMapAddress, + int clearStageId) + { + var agentAddress = new PrivateKey().ToAddress(); + var agentState = new AgentState(agentAddress); + + var avatarAddress = agentAddress.Derive("avatar"); + var avatarState = new AvatarState( + avatarAddress, + agentAddress, + 0, + tableSheets.GetAvatarSheets(), + new GameConfigState(sheets[nameof(GameConfigSheet)]), + rankingMapAddress) + { + worldInformation = new WorldInformation( + 0, + tableSheets.WorldSheet, + clearStageId), + }; + agentState.avatarAddresses.Add(0, avatarAddress); + + return (agentState, avatarState); + } + + private void Execute( + int championshipId, + int round, + bool isPurchased, + int ticket, + int arenaInterval, + int randomSeed, + Address myAgentAddress, + Address myAvatarAddress, + Address enemyAgentAddress, + Address enemyAvatarAddress) + { + var context = new ActionContext(); + var previousStates = _initialStates; + Assert.True(_initialStates.GetSheet().TryGetValue( + championshipId, + out var row)); + + if (!row.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena)}] ChampionshipId({row.ChampionshipId}) - round({round})"); + } + + var random = new TestRandom(randomSeed); + previousStates = JoinArena( + context, + previousStates, + myAgentAddress, + myAvatarAddress, + roundData.StartBlockIndex, + championshipId, + round, + random); + previousStates = JoinArena( + context, + previousStates, + enemyAgentAddress, + enemyAvatarAddress, + roundData.StartBlockIndex, + championshipId, + round, + random); + + var arenaInfoAdr = + ArenaInformation.DeriveAddress(myAvatarAddress, championshipId, round); + if (!previousStates.TryGetArenaInformation(arenaInfoAdr, out var beforeInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + if (isPurchased) + { + beforeInfo.UseTicket(beforeInfo.Ticket); + previousStates = previousStates.SetState(arenaInfoAdr, beforeInfo.Serialize()); + for (var i = 0; i < ticket; i++) + { + var price = ArenaHelper.GetTicketPrice( + roundData, + beforeInfo, + previousStates.GetGoldCurrency()); + previousStates = previousStates.MintAsset(context, myAgentAddress, price); + beforeInfo.BuyTicket(roundData.MaxPurchaseCount); + } + } + + var action = new BattleArena + { + myAvatarAddress = myAvatarAddress, + enemyAvatarAddress = enemyAvatarAddress, + championshipId = championshipId, + round = round, + ticket = ticket, + costumes = new List(), + equipments = new List(), + runeInfos = new List(), + }; + + var myScoreAdr = ArenaScore.DeriveAddress( + myAvatarAddress, + championshipId, + round); + var enemyScoreAdr = ArenaScore.DeriveAddress( + enemyAvatarAddress, + championshipId, + round); + if (!previousStates.TryGetArenaScore(myScoreAdr, out var beforeMyScore)) + { + throw new ArenaScoreNotFoundException($"myScoreAdr : {myScoreAdr}"); + } + + if (!previousStates.TryGetArenaScore(enemyScoreAdr, out var beforeEnemyScore)) + { + throw new ArenaScoreNotFoundException($"enemyScoreAdr : {enemyScoreAdr}"); + } + + Assert.True(previousStates.TryGetAvatarStateV2( + myAgentAddress, + myAvatarAddress, + out var previousMyAvatarState, + out _)); + Assert.Empty(previousMyAvatarState.inventory.Materials); + + var gameConfigState = SetArenaInterval(arenaInterval); + previousStates = previousStates.SetState(GameConfigState.Address, gameConfigState.Serialize()); + + var blockIndex = roundData.StartBlockIndex < arenaInterval + ? roundData.StartBlockIndex + : roundData.StartBlockIndex + arenaInterval; + var nextStates = action.Execute(new ActionContext + { + PreviousState = previousStates, + Signer = myAgentAddress, + RandomSeed = random.Seed, + Rehearsal = false, + BlockIndex = blockIndex, + }); + + if (!nextStates.TryGetArenaScore(myScoreAdr, out var myAfterScore)) + { + throw new ArenaScoreNotFoundException($"myScoreAdr : {myScoreAdr}"); + } + + if (!nextStates.TryGetArenaScore(enemyScoreAdr, out var enemyAfterScore)) + { + throw new ArenaScoreNotFoundException($"enemyScoreAdr : {enemyScoreAdr}"); + } + + if (!nextStates.TryGetArenaInformation(arenaInfoAdr, out var afterInfo)) + { + throw new ArenaInformationNotFoundException($"arenaInfoAdr : {arenaInfoAdr}"); + } + + var (myWinScore, myDefeatScore, enemyWinScore) = + ArenaHelper.GetScoresV1(beforeMyScore.Score, beforeEnemyScore.Score); + + var addMyScore = afterInfo.Win * myWinScore + afterInfo.Lose * myDefeatScore; + var addEnemyScore = afterInfo.Win * enemyWinScore; + var expectedMyScore = Math.Max( + beforeMyScore.Score + addMyScore, + ArenaScore.ArenaScoreDefault); + var expectedEnemyScore = Math.Max( + beforeEnemyScore.Score + addEnemyScore, + ArenaScore.ArenaScoreDefault); + + Assert.Equal(expectedMyScore, myAfterScore.Score); + Assert.Equal(expectedEnemyScore, enemyAfterScore.Score); + Assert.Equal( + isPurchased + ? 0 + : ArenaInformation.MaxTicketCount, + beforeInfo.Ticket); + Assert.Equal(0, beforeInfo.Win); + Assert.Equal(0, beforeInfo.Lose); + + var useTicket = Math.Min(ticket, beforeInfo.Ticket); + Assert.Equal(beforeInfo.Ticket - useTicket, afterInfo.Ticket); + Assert.Equal(ticket, afterInfo.Win + afterInfo.Lose); + + var balance = nextStates.GetBalance( + myAgentAddress, + nextStates.GetGoldCurrency()); + if (isPurchased) + { + Assert.Equal(ticket, afterInfo.PurchasedTicketCount); + } + + Assert.Equal(0, balance.RawValue); + + var avatarState = nextStates.GetAvatarStateV2(myAvatarAddress); + var medalCount = 0; + if (roundData.ArenaType != ArenaType.OffSeason) + { + var medalId = ArenaHelper.GetMedalItemId(championshipId, round); + avatarState.inventory.TryGetItem(medalId, out var medal); + if (afterInfo.Win > 0) + { + Assert.Equal(afterInfo.Win, medal.count); + } + else + { + Assert.Null(medal); + } + + medalCount = medal?.count ?? 0; + } + + var materialCount = avatarState.inventory.Materials.Count(); + var high = (ArenaHelper.GetRewardCount(beforeMyScore.Score) * ticket) + medalCount; + Assert.InRange(materialCount, 0, high); + } + + private IAccount JoinArena( + IActionContext context, + IAccount states, + Address signer, + Address avatarAddress, + long blockIndex, + int championshipId, + int round, + IRandom random) + { + var preCurrency = 1000 * _crystal; + states = states.MintAsset(context, signer, preCurrency); + + var action = new JoinArena1 + { + championshipId = championshipId, + round = round, + costumes = new List(), + equipments = new List(), + avatarAddress = avatarAddress, + }; + + states = action.Execute(new ActionContext + { + PreviousState = states, + Signer = signer, + RandomSeed = random.Seed, + Rehearsal = false, + BlockIndex = blockIndex, + }); + return states; + } + + private GameConfigState SetArenaInterval(int interval) + { + var gameConfigState = _initialStates.GetGameConfigState(); + var sheet = _tableSheets.GameConfigSheet; + foreach (var value in sheet.Values) + { + if (value.Key.Equals("battle_arena_interval")) + { + IReadOnlyList field = new[] + { + value.Key, + interval.ToString(), + }; + value.Set(field); + } + } + + gameConfigState.Set(sheet); + return gameConfigState; + } + } +} diff --git a/.Lib9c.Tests/Action/BurnAssetTest.cs b/.Lib9c.Tests/Action/BurnAssetTest.cs new file mode 100644 index 00000000000..a601665a381 --- /dev/null +++ b/.Lib9c.Tests/Action/BurnAssetTest.cs @@ -0,0 +1,230 @@ +namespace Lib9c.Tests.Action +{ + using System.Collections.Generic; + using System.Globalization; + using Bencodex.Types; + using Libplanet.Action.State; + using Libplanet.Crypto; + using Nekoyume.Action; + using Nekoyume.Exceptions; + using Xunit; + + public class BurnAssetTest + { + private readonly Address _signer; + + private readonly IAccount _prevState; + + public BurnAssetTest() + { + _signer = new PrivateKey().ToAddress(); + _prevState = new Account( + MockState.Empty + .SetBalance(_signer, Currencies.Crystal * 100) + .SetBalance( + _signer.Derive(string.Format( + CultureInfo.InvariantCulture, + CreateAvatar.DeriveFormat, + 1 + )), + Currencies.DailyRewardRune * 20 + ) + ); + } + + [Fact] + public void Constructor_Throws_MemoLengthOverflowException() + { + Assert.Throws( + () => new BurnAsset( + _signer, + Currencies.Crystal * 42, + "very long memo".PadRight(100, ' ') + ) + ); + } + + [Fact] + public void PlainValue() + { + var action = new BurnAsset( + _signer, + Currencies.Crystal * 100, + "memo" + ); + var expected = new Dictionary( + new KeyValuePair[] + { + new ( + (Text)"type_id", (Text)"burn_asset" + ), + new ( + (Text)"values", new List( + _signer.Bencoded, + (Currencies.Crystal * 100).Serialize(), + (Text)"memo" + ) + ), + } + ); + + Assert.Equal(expected, action.PlainValue); + } + + [Fact] + public void LoadPlainValue() + { + var bencoded = new Dictionary( + new KeyValuePair[] + { + new ( + (Text)"type_id", (Text)"burn_asset" + ), + new ( + (Text)"values", new List( + _signer.Bencoded, + (Currencies.Crystal * 100).Serialize(), + (Text)"memo" + ) + ), + } + ); + var action = new BurnAsset(); + action.LoadPlainValue(bencoded); + + Assert.Equal(Currencies.Crystal * 100, action.Amount); + Assert.Equal("memo", action.Memo); + } + + [Fact] + public void LoadPlainValue_Throws_MemoLengthOverflowException() + { + var bencoded = new Dictionary( + new KeyValuePair[] + { + new ( + (Text)"type_id", (Text)"burn_asset" + ), + new ( + (Text)"values", new List( + _signer.Bencoded, + (Currencies.Crystal * 100).Serialize(), + (Text)"very long memo".PadRight(100, ' ') + ) + ), + } + ); + var action = new BurnAsset(); + Assert.Throws( + () => action.LoadPlainValue(bencoded) + ); + } + + [Fact] + public void Execute() + { + IAccount prevState = _prevState; + + var action = new BurnAsset( + _signer, + Currencies.Crystal * 42, + "42" + ); + IAccount nextState = action.Execute( + new ActionContext() + { + PreviousState = prevState, + Signer = _signer, + Rehearsal = false, + BlockIndex = 1, + } + ); + + Assert.Equal( + Currencies.Crystal * (100 - 42), + nextState.GetBalance(_signer, Currencies.Crystal) + ); + } + + [Fact] + public void Execute_With_AvatarAddress() + { + IAccount prevState = _prevState; + Address avatarAddress = _signer.Derive( + string.Format( + CultureInfo.InvariantCulture, + CreateAvatar.DeriveFormat, + 1 + ) + ); + + var action = new BurnAsset( + avatarAddress, + Currencies.DailyRewardRune * 10, + "10" + ); + IAccount nextState = action.Execute( + new ActionContext() + { + PreviousState = prevState, + Signer = _signer, + Rehearsal = false, + BlockIndex = 1, + } + ); + + Assert.Equal( + Currencies.DailyRewardRune * (20 - 10), + nextState.GetBalance(avatarAddress, Currencies.DailyRewardRune) + ); + } + + [Fact] + public void Execute_Throws_InsufficientBalanceException() + { + IAccount prevState = _prevState; + + var action = new BurnAsset( + _signer, + Currencies.Crystal * 1000, + "1000" + ); + Assert.Throws(() => + { + action.Execute( + new ActionContext() + { + PreviousState = prevState, + Signer = _signer, + Rehearsal = false, + BlockIndex = 1, + } + ); + }); + } + + [Fact] + public void Execute_Throws_InvalidActionFieldException() + { + IAccount prevState = _prevState; + + var action = new BurnAsset( + default, // Wrong address + Currencies.Crystal * 1000, + "42" + ); + Assert.Throws(() => + { + action.Execute( + new ActionContext() + { + PreviousState = prevState, + Signer = _signer, + Rehearsal = false, + BlockIndex = 1, + } + ); + }); + } + } +} diff --git a/.Lib9c.Tests/Action/Buy10Test.cs b/.Lib9c.Tests/Action/Buy10Test.cs index b8a156412ba..3a3f5504198 100644 --- a/.Lib9c.Tests/Action/Buy10Test.cs +++ b/.Lib9c.Tests/Action/Buy10Test.cs @@ -768,55 +768,6 @@ public void Execute_ReconfigureFungibleItem(params OrderData[] orderDataList) } } - [Fact] - public void Rehearsal() - { - PurchaseInfo purchaseInfo = new PurchaseInfo( - _orderId, - default, - _sellerAgentAddress, - _sellerAvatarAddress, - ItemSubType.Weapon, - new FungibleAssetValue(_goldCurrencyState.Currency, 10, 0) - ); - - var action = new Buy10 - { - buyerAvatarAddress = _buyerAvatarAddress, - purchaseInfos = new[] { purchaseInfo }, - }; - - var updatedAddresses = new List
() - { - _sellerAgentAddress, - _sellerAvatarAddress, - _sellerAvatarAddress.Derive(LegacyInventoryKey), - _sellerAvatarAddress.Derive(LegacyWorldInformationKey), - _sellerAvatarAddress.Derive(LegacyQuestListKey), - OrderDigestListState.DeriveAddress(_sellerAvatarAddress), - _buyerAgentAddress, - _buyerAvatarAddress, - _buyerAvatarAddress.Derive(LegacyInventoryKey), - _buyerAvatarAddress.Derive(LegacyWorldInformationKey), - _buyerAvatarAddress.Derive(LegacyQuestListKey), - Addresses.GoldCurrency, - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, _orderId), - OrderReceipt.DeriveAddress(_orderId), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _buyerAgentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void Execute_With_Testbed() { diff --git a/.Lib9c.Tests/Action/Buy11Test.cs b/.Lib9c.Tests/Action/Buy11Test.cs index 9ff4dfe34c1..6a68862fb39 100644 --- a/.Lib9c.Tests/Action/Buy11Test.cs +++ b/.Lib9c.Tests/Action/Buy11Test.cs @@ -774,55 +774,6 @@ public void Execute_ReconfigureFungibleItem(params OrderData[] orderDataList) } } - [Fact] - public void Rehearsal() - { - PurchaseInfo purchaseInfo = new PurchaseInfo( - _orderId, - default, - _sellerAgentAddress, - _sellerAvatarAddress, - ItemSubType.Weapon, - new FungibleAssetValue(_goldCurrencyState.Currency, 10, 0) - ); - - var action = new Buy11 - { - buyerAvatarAddress = _buyerAvatarAddress, - purchaseInfos = new[] { purchaseInfo }, - }; - - var updatedAddresses = new List
() - { - _sellerAgentAddress, - _sellerAvatarAddress, - _sellerAvatarAddress.Derive(LegacyInventoryKey), - _sellerAvatarAddress.Derive(LegacyWorldInformationKey), - _sellerAvatarAddress.Derive(LegacyQuestListKey), - OrderDigestListState.DeriveAddress(_sellerAvatarAddress), - _buyerAgentAddress, - _buyerAvatarAddress, - _buyerAvatarAddress.Derive(LegacyInventoryKey), - _buyerAvatarAddress.Derive(LegacyWorldInformationKey), - _buyerAvatarAddress.Derive(LegacyQuestListKey), - Buy11.GetFeeStoreAddress(), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, _orderId), - OrderReceipt.DeriveAddress(_orderId), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _buyerAgentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void Execute_With_Testbed() { diff --git a/.Lib9c.Tests/Action/Buy8Test.cs b/.Lib9c.Tests/Action/Buy8Test.cs index fe13fbaad9c..f968b3815b7 100644 --- a/.Lib9c.Tests/Action/Buy8Test.cs +++ b/.Lib9c.Tests/Action/Buy8Test.cs @@ -550,55 +550,6 @@ public void Execute_ErrorCode(ErrorCodeMember errorCodeMember) } } - [Fact] - public void Rehearsal() - { - PurchaseInfo purchaseInfo = new PurchaseInfo( - _orderId, - default, - _sellerAgentAddress, - _sellerAvatarAddress, - ItemSubType.Weapon, - new FungibleAssetValue(_goldCurrencyState.Currency, 10, 0) - ); - - var action = new Buy8 - { - buyerAvatarAddress = _buyerAvatarAddress, - purchaseInfos = new[] { purchaseInfo }, - }; - - var updatedAddresses = new List
() - { - _sellerAgentAddress, - _sellerAvatarAddress, - _sellerAvatarAddress.Derive(LegacyInventoryKey), - _sellerAvatarAddress.Derive(LegacyWorldInformationKey), - _sellerAvatarAddress.Derive(LegacyQuestListKey), - OrderDigestListState.DeriveAddress(_sellerAvatarAddress), - _buyerAgentAddress, - _buyerAvatarAddress, - _buyerAvatarAddress.Derive(LegacyInventoryKey), - _buyerAvatarAddress.Derive(LegacyWorldInformationKey), - _buyerAvatarAddress.Derive(LegacyQuestListKey), - Addresses.GoldCurrency, - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, _orderId), - OrderReceipt.DeriveAddress(_orderId), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _buyerAgentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private (AvatarState AvatarState, AgentState AgentState) CreateAvatarState( Address agentAddress, Address avatarAddress) { diff --git a/.Lib9c.Tests/Action/Buy9Test.cs b/.Lib9c.Tests/Action/Buy9Test.cs index 9a11cefffc6..b0da3203848 100644 --- a/.Lib9c.Tests/Action/Buy9Test.cs +++ b/.Lib9c.Tests/Action/Buy9Test.cs @@ -649,55 +649,6 @@ public void Execute_ErrorCode(ErrorCodeMember errorCodeMember) } } - [Fact] - public void Rehearsal() - { - PurchaseInfo purchaseInfo = new PurchaseInfo( - _orderId, - default, - _sellerAgentAddress, - _sellerAvatarAddress, - ItemSubType.Weapon, - new FungibleAssetValue(_goldCurrencyState.Currency, 10, 0) - ); - - var action = new Buy9 - { - buyerAvatarAddress = _buyerAvatarAddress, - purchaseInfos = new[] { purchaseInfo }, - }; - - var updatedAddresses = new List
() - { - _sellerAgentAddress, - _sellerAvatarAddress, - _sellerAvatarAddress.Derive(LegacyInventoryKey), - _sellerAvatarAddress.Derive(LegacyWorldInformationKey), - _sellerAvatarAddress.Derive(LegacyQuestListKey), - OrderDigestListState.DeriveAddress(_sellerAvatarAddress), - _buyerAgentAddress, - _buyerAvatarAddress, - _buyerAvatarAddress.Derive(LegacyInventoryKey), - _buyerAvatarAddress.Derive(LegacyWorldInformationKey), - _buyerAvatarAddress.Derive(LegacyQuestListKey), - Addresses.GoldCurrency, - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, _orderId), - OrderReceipt.DeriveAddress(_orderId), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _buyerAgentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private (AvatarState AvatarState, AgentState AgentState) CreateAvatarState( Address agentAddress, Address avatarAddress) { diff --git a/.Lib9c.Tests/Action/ChargeActionPointTest.cs b/.Lib9c.Tests/Action/ChargeActionPointTest.cs index 37a8326ab08..c02d549f7f9 100644 --- a/.Lib9c.Tests/Action/ChargeActionPointTest.cs +++ b/.Lib9c.Tests/Action/ChargeActionPointTest.cs @@ -168,34 +168,5 @@ public void Execute_Throw_Exception(bool useAvatarAddress, bool useTradable, boo }) ); } - - [Fact] - public void Rehearsal() - { - var action = new ChargeActionPoint - { - avatarAddress = _avatarAddress, - }; - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/ClaimItemsTest.cs b/.Lib9c.Tests/Action/ClaimItemsTest.cs index 63843b55ce9..73ce1c4c232 100644 --- a/.Lib9c.Tests/Action/ClaimItemsTest.cs +++ b/.Lib9c.Tests/Action/ClaimItemsTest.cs @@ -2,13 +2,16 @@ namespace Lib9c.Tests.Action { using System; using System.Collections.Generic; + using System.Collections.Immutable; using System.Linq; + using Bencodex.Types; using Libplanet.Action.State; using Libplanet.Crypto; using Libplanet.Types.Assets; using Nekoyume; using Nekoyume.Action; using Nekoyume.Model; + using Nekoyume.Model.Mail; using Nekoyume.Model.State; using Serilog; using Xunit; @@ -20,8 +23,10 @@ public class ClaimItemsTest private readonly Address _signerAddress; private readonly TableSheets _tableSheets; - private readonly List _currencies; + private readonly List _itemCurrencies; + private readonly List _wrappedFavCurrencies; private readonly List _itemIds; + private readonly Currency _wrappedCrystalCurrency; public ClaimItemsTest(ITestOutputHelper outputHelper) { @@ -41,28 +46,49 @@ public ClaimItemsTest(ITestOutputHelper outputHelper) _tableSheets = new TableSheets(sheets); _itemIds = _tableSheets.CostumeItemSheet.Values.Take(3).Select(x => x.Id).ToList(); - _currencies = _itemIds.Select(id => Currency.Legacy($"Item_T_{id}", 0, minters: null)).ToList(); + _itemCurrencies = _itemIds.Select(id => Currencies.GetItemCurrency(id, true)).ToList(); + _wrappedFavCurrencies = new List(); + foreach (var currency in new[] { Currencies.Crystal, Currencies.StakeRune }) + { + var wrappedCurrency = Currencies.GetWrappedCurrency(currency); + _wrappedFavCurrencies.Add(wrappedCurrency); + if (currency.Ticker == "CRYSTAL") + { + _wrappedCrystalCurrency = wrappedCurrency; + } + } _signerAddress = new PrivateKey().ToAddress(); var context = new ActionContext(); _initialState = _initialState - .MintAsset(context, _signerAddress, _currencies[0] * 5) - .MintAsset(context, _signerAddress, _currencies[1] * 5) - .MintAsset(context, _signerAddress, _currencies[2] * 5); + .MintAsset(context, _signerAddress, _itemCurrencies[0] * 5) + .MintAsset(context, _signerAddress, _itemCurrencies[1] * 5) + .MintAsset(context, _signerAddress, _itemCurrencies[2] * 5) + .MintAsset(context, _signerAddress, _wrappedFavCurrencies[0] * 5) + .MintAsset(context, _signerAddress, _wrappedFavCurrencies[1] * 5); } - [Fact] - public void Serialize() + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Serialize(bool memoExist) { - var states = GenerateAvatar(_initialState, out var avatarAddress1); - GenerateAvatar(states, out var avatarAddress2); - - var action = new ClaimItems(new List<(Address, IReadOnlyList)> + var states = GenerateAvatar(_initialState, out var avatarAddress1, out _); + GenerateAvatar(states, out var avatarAddress2, out _); + string memo = memoExist ? "memo" : null; + var action = new ClaimItems( + new List<(Address, IReadOnlyList)> { - (avatarAddress1, new List { _currencies[0] * 1, _currencies[1] * 1 }), - (avatarAddress2, new List { _currencies[0] * 1 }), - }); + (avatarAddress1, new List { _itemCurrencies[0] * 1, _itemCurrencies[1] * 1 }), + (avatarAddress2, new List { _itemCurrencies[0] * 1 }), + }, + memo + ); + Assert.Equal(!memoExist, string.IsNullOrEmpty(action.Memo)); + Dictionary serialized = (Dictionary)action.PlainValue; + Dictionary values = (Dictionary)serialized["values"]; + Assert.Equal(memoExist, values.ContainsKey("m")); var deserialized = new ClaimItems(); deserialized.LoadPlainValue(action.PlainValue); @@ -72,12 +98,14 @@ public void Serialize() Assert.True(action.ClaimData[i].fungibleAssetValues .SequenceEqual(deserialized.ClaimData[i].fungibleAssetValues)); } + + Assert.Equal(action.Memo, deserialized.Memo); } [Fact] public void Execute_Throws_ArgumentException_TickerInvalid() { - var state = GenerateAvatar(_initialState, out var recipientAvatarAddress); + var state = GenerateAvatar(_initialState, out var recipientAvatarAddress, out _); var currency = Currencies.Crystal; var action = new ClaimItems(new List<(Address, IReadOnlyList)> @@ -97,9 +125,9 @@ public void Execute_Throws_ArgumentException_TickerInvalid() [Fact] public void Execute_Throws_WhenNotEnoughBalance() { - var state = GenerateAvatar(_initialState, out var recipientAvatarAddress); + var state = GenerateAvatar(_initialState, out var recipientAvatarAddress, out _); - var currency = _currencies.First(); + var currency = _itemCurrencies.First(); var action = new ClaimItems(new List<(Address, IReadOnlyList)> { (recipientAvatarAddress, new List { currency * 6 }), @@ -114,16 +142,36 @@ public void Execute_Throws_WhenNotEnoughBalance() })); } - [Fact] - public void Execute() + [Theory] + [InlineData("memo")] + [InlineData(null)] + public void Execute(string memo) { - var state = GenerateAvatar(_initialState, out var recipientAvatarAddress); + var state = GenerateAvatar(_initialState, out var recipientAvatarAddress, out var recipientAgentAddress); - var fungibleAssetValues = _currencies.Select(currency => currency * 1).ToList(); - var action = new ClaimItems(new List<(Address, IReadOnlyList)> + var avatarValues = _itemCurrencies.Select(currency => currency * 1).ToList(); + var agentValues = new List(); + foreach (var currency in _wrappedFavCurrencies) { - (recipientAvatarAddress, fungibleAssetValues), - }); + if (currency.Equals(_wrappedCrystalCurrency)) + { + agentValues.Add(1 * currency); + } + else + { + avatarValues.Add(1 * currency); + } + } + + var fungibleAssetValues = avatarValues.Concat(agentValues).ToList(); + + var action = new ClaimItems( + new List<(Address, IReadOnlyList)> + { + (recipientAvatarAddress, fungibleAssetValues), + }, + memo + ); var states = action.Execute(new ActionContext { PreviousState = state, @@ -132,27 +180,59 @@ public void Execute() RandomSeed = 0, }); + var avatarState = states.GetAvatarStateV2(recipientAvatarAddress); + var mail = Assert.IsType(avatarState.mailBox.Single()); + if (string.IsNullOrEmpty(memo)) + { + Assert.Null(mail.Memo); + } + else + { + Assert.Equal(memo, mail.Memo); + } + + Assert.Equal(0, mail.blockIndex); + Assert.Equal(0, mail.requiredBlockIndex); + var inventory = states.GetInventory(recipientAvatarAddress.Derive(SerializeKeys.LegacyInventoryKey)); foreach (var i in Enumerable.Range(0, 3)) { - Assert.Equal(_currencies[i] * 4, states.GetBalance(_signerAddress, _currencies[i])); + Assert.Equal(_itemCurrencies[i] * 4, states.GetBalance(_signerAddress, _itemCurrencies[i])); + var itemId = _itemIds[i]; Assert.Equal( 1, - inventory.Items.First(x => x.item.Id == _itemIds[i]).count); + inventory.Items.First(x => x.item.Id == itemId).count); + var mailItems = mail.Items.Single(m => m.id == itemId); + Assert.Equal(1, mailItems.count); + } + + for (int i = 0; i < _wrappedFavCurrencies.Count; i++) + { + var wrappedCurrency = _wrappedFavCurrencies[i]; + Assert.Equal(wrappedCurrency * 4, states.GetBalance(_signerAddress, wrappedCurrency)); + var currency = Currencies.GetUnwrappedCurrency(wrappedCurrency); + var recipientAddress = Currencies.SelectRecipientAddress( + currency, + recipientAgentAddress, + recipientAvatarAddress + ); + Assert.Equal(currency * 1, states.GetBalance(recipientAddress, currency)); + var mailFav = mail.FungibleAssetValues.Single(f => f.Currency.Equals(currency)); + Assert.Equal(currency * 1, mailFav); } } [Fact] public void Execute_WithMultipleRecipients() { - var state = GenerateAvatar(_initialState, out var recipientAvatarAddress1); - state = GenerateAvatar(state, out var recipientAvatarAddress2); + var state = GenerateAvatar(_initialState, out var recipientAvatarAddress1, out _); + state = GenerateAvatar(state, out var recipientAvatarAddress2, out _); var recipientAvatarAddresses = new List
{ recipientAvatarAddress1, recipientAvatarAddress2, }; - var fungibleAssetValues = _currencies.Select(currency => currency * 1).ToList(); + var fungibleAssetValues = _itemCurrencies.Select(currency => currency * 1).ToList(); var action = new ClaimItems(new List<(Address, IReadOnlyList)> { @@ -168,9 +248,9 @@ public void Execute_WithMultipleRecipients() RandomSeed = 0, }); - Assert.Equal(states.GetBalance(_signerAddress, _currencies[0]), _currencies[0] * 3); - Assert.Equal(states.GetBalance(_signerAddress, _currencies[1]), _currencies[1] * 3); - Assert.Equal(states.GetBalance(_signerAddress, _currencies[2]), _currencies[2] * 4); + Assert.Equal(states.GetBalance(_signerAddress, _itemCurrencies[0]), _itemCurrencies[0] * 3); + Assert.Equal(states.GetBalance(_signerAddress, _itemCurrencies[1]), _itemCurrencies[1] * 3); + Assert.Equal(states.GetBalance(_signerAddress, _itemCurrencies[2]), _itemCurrencies[2] * 4); var inventory1 = states.GetInventory(recipientAvatarAddress1.Derive(SerializeKeys.LegacyInventoryKey)); Assert.Equal(1, inventory1.Items.First(x => x.item.Id == _itemIds[0]).count); @@ -182,15 +262,73 @@ public void Execute_WithMultipleRecipients() Assert.Equal(1, inventory2.Items.First(x => x.item.Id == _itemIds[2]).count); } - private IAccount GenerateAvatar(IAccount state, out Address avatarAddress) + [Fact] + public void Execute_WithNonFungibleItem() { - var address = new PrivateKey().ToAddress(); - var agentState = new AgentState(address); - avatarAddress = address.Derive("avatar"); + const int nonFungibleitemId = 10232001; + const int itemCount = 5; + var currency = Currency.Legacy($"Item_T_{nonFungibleitemId}", 0, null); + + var state = GenerateAvatar(_initialState, out var recipientAvatarAddress1, out _); + state = state.MintAsset( + new ActionContext + { + PreviousState = state, + Signer = _signerAddress, + BlockIndex = 0, + RandomSeed = 0, + }, + _signerAddress, + currency * itemCount); + + var action = new ClaimItems(new List<(Address, IReadOnlyList)> + { + (recipientAvatarAddress1, new List { currency * itemCount, }), + }); + + var states = action.Execute(new ActionContext + { + PreviousState = state, + Signer = _signerAddress, + BlockIndex = 0, + RandomSeed = 0, + }); + + Assert.Equal(states.GetBalance(_signerAddress, currency), currency * 0); + + var inventory = states.GetInventory(recipientAvatarAddress1.Derive(SerializeKeys.LegacyInventoryKey)); + Assert.Equal(itemCount, inventory.Items.Count(x => x.item.Id == nonFungibleitemId)); + } + + [Fact] + public void Execute_WithIncorrectClaimData() + { + var fungibleAssetValues = _itemCurrencies.Select(currency => currency * 1).ToList(); + + var action = new ClaimItems(Enumerable.Repeat(0, 101) + .Select(_ => (new PrivateKey().ToAddress(), + (IReadOnlyList)fungibleAssetValues)) + .ToImmutableList()); + + Assert.Throws("ClaimData", () => + action.Execute(new ActionContext + { + PreviousState = _initialState, + Signer = _signerAddress, + BlockIndex = 0, + RandomSeed = 0, + })); + } + + private IAccount GenerateAvatar(IAccount state, out Address avatarAddress, out Address agentAddress) + { + agentAddress = new PrivateKey().ToAddress(); + var agentState = new AgentState(agentAddress); + avatarAddress = agentAddress.Derive("avatar"); var rankingMapAddress = new PrivateKey().ToAddress(); var avatarState = new AvatarState( avatarAddress, - address, + agentAddress, 0, _tableSheets.GetAvatarSheets(), new GameConfigState(), @@ -204,8 +342,16 @@ private IAccount GenerateAvatar(IAccount state, out Address avatarAddress) agentState.avatarAddresses[0] = avatarAddress; state = state - .SetState(address, agentState.Serialize()) - .SetState(avatarAddress, avatarState.Serialize()) + .SetState(agentAddress, agentState.Serialize()) + .SetState(avatarAddress, avatarState.SerializeV2()) + .SetState( + avatarAddress.Derive(SerializeKeys.LegacyWorldInformationKey), + avatarState.worldInformation.Serialize() + ) + .SetState( + avatarAddress.Derive(SerializeKeys.LegacyQuestListKey), + avatarState.questList.Serialize() + ) .SetState( avatarAddress.Derive(SerializeKeys.LegacyInventoryKey), avatarState.inventory.Serialize()); diff --git a/.Lib9c.Tests/Action/ClaimMonsterCollectionReward2Test.cs b/.Lib9c.Tests/Action/ClaimMonsterCollectionReward2Test.cs index 537170a4776..84de887a552 100644 --- a/.Lib9c.Tests/Action/ClaimMonsterCollectionReward2Test.cs +++ b/.Lib9c.Tests/Action/ClaimMonsterCollectionReward2Test.cs @@ -200,37 +200,6 @@ public void Execute_Throw_RequiredBlockIndexException() ); } - [Fact] - public void Rehearsal() - { - ClaimMonsterCollectionReward2 action = new ClaimMonsterCollectionReward2 - { - avatarAddress = _avatarAddress, - }; - - IAccount nextState = action.Execute(new ActionContext - { - PreviousState = new Account(MockState.Empty), - Signer = _signer, - BlockIndex = 0, - Rehearsal = true, - } - ); - - List
updatedAddresses = new List
- { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - MonsterCollectionState.DeriveAddress(_signer, 0), - MonsterCollectionState.DeriveAddress(_signer, 1), - MonsterCollectionState.DeriveAddress(_signer, 2), - MonsterCollectionState.DeriveAddress(_signer, 3), - }; - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private class ExecuteFixture : IEnumerable { private readonly List _data = new List diff --git a/.Lib9c.Tests/Action/ClaimMonsterCollectionRewardTest.cs b/.Lib9c.Tests/Action/ClaimMonsterCollectionRewardTest.cs index 010c6004433..69a0eee0195 100644 --- a/.Lib9c.Tests/Action/ClaimMonsterCollectionRewardTest.cs +++ b/.Lib9c.Tests/Action/ClaimMonsterCollectionRewardTest.cs @@ -182,32 +182,6 @@ public void Execute_Throw_RequiredBlockIndexException() ); } - [Fact] - public void Rehearsal() - { - IAccount nextState = _action.Execute(new ActionContext - { - PreviousState = new Account(MockState.Empty), - Signer = _signer, - BlockIndex = 0, - Rehearsal = true, - } - ); - - List
updatedAddresses = new List
- { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - MonsterCollectionState.DeriveAddress(_signer, 0), - MonsterCollectionState.DeriveAddress(_signer, 1), - MonsterCollectionState.DeriveAddress(_signer, 2), - MonsterCollectionState.DeriveAddress(_signer, 3), - }; - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private class ExecuteFixture : IEnumerable { private readonly List _data = new List diff --git a/.Lib9c.Tests/Action/CombinationEquipment10Test.cs b/.Lib9c.Tests/Action/CombinationEquipment10Test.cs index c5707b6c44e..b354f207bc8 100644 --- a/.Lib9c.Tests/Action/CombinationEquipment10Test.cs +++ b/.Lib9c.Tests/Action/CombinationEquipment10Test.cs @@ -115,48 +115,6 @@ public void Execute_Throw_InsufficientBalanceException(bool backward) backward, recipeId, subRecipeId, 0)); } - [Fact] - public void Rehearsal() - { - var action = new CombinationEquipment10 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - recipeId = 1, - subRecipeId = 255, - }; - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
- { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void AddAndUnlockOption() { diff --git a/.Lib9c.Tests/Action/CombinationEquipment11Test.cs b/.Lib9c.Tests/Action/CombinationEquipment11Test.cs index 90f766e7073..ce86353acf9 100644 --- a/.Lib9c.Tests/Action/CombinationEquipment11Test.cs +++ b/.Lib9c.Tests/Action/CombinationEquipment11Test.cs @@ -121,48 +121,6 @@ public void Execute_Throw_InsufficientBalanceException(bool backward) backward, recipeId, subRecipeId, 0)); } - [Fact] - public void Rehearsal() - { - var action = new CombinationEquipment11 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - recipeId = 1, - subRecipeId = 255, - }; - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
- { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - ItemEnhancement10.GetFeeStoreAddress(), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void AddAndUnlockOption() { diff --git a/.Lib9c.Tests/Action/CombinationEquipment6Test.cs b/.Lib9c.Tests/Action/CombinationEquipment6Test.cs index 58ae9a58d08..502efe37f11 100644 --- a/.Lib9c.Tests/Action/CombinationEquipment6Test.cs +++ b/.Lib9c.Tests/Action/CombinationEquipment6Test.cs @@ -229,48 +229,6 @@ public void ExecuteThrowInsufficientBalanceException() })); } - [Fact] - public void Rehearsal() - { - var action = new CombinationEquipment6 - { - AvatarAddress = _avatarAddress, - RecipeId = 1, - SlotIndex = 0, - SubRecipeId = 255, - }; - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
- { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void SelectOption() { diff --git a/.Lib9c.Tests/Action/CombinationEquipment7Test.cs b/.Lib9c.Tests/Action/CombinationEquipment7Test.cs index 6a075dd6bf3..79525888316 100644 --- a/.Lib9c.Tests/Action/CombinationEquipment7Test.cs +++ b/.Lib9c.Tests/Action/CombinationEquipment7Test.cs @@ -228,48 +228,6 @@ public void ExecuteThrowInsufficientBalanceException() })); } - [Fact] - public void Rehearsal() - { - var action = new CombinationEquipment7 - { - AvatarAddress = _avatarAddress, - RecipeId = 1, - SlotIndex = 0, - SubRecipeId = 255, - }; - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
- { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void SelectOption() { diff --git a/.Lib9c.Tests/Action/CombinationEquipment8Test.cs b/.Lib9c.Tests/Action/CombinationEquipment8Test.cs index 17fe93c6a5a..5479610e2f1 100644 --- a/.Lib9c.Tests/Action/CombinationEquipment8Test.cs +++ b/.Lib9c.Tests/Action/CombinationEquipment8Test.cs @@ -114,48 +114,6 @@ public void Execute_Throw_InsufficientBalanceException(bool backward) backward, recipeId, subRecipeId, 0)); } - [Fact] - public void Rehearsal() - { - var action = new CombinationEquipment8 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - recipeId = 1, - subRecipeId = 255, - }; - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
- { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void AddAndUnlockOption() { diff --git a/.Lib9c.Tests/Action/CombinationEquipment9Test.cs b/.Lib9c.Tests/Action/CombinationEquipment9Test.cs index cc975e9369f..3f4c19220b7 100644 --- a/.Lib9c.Tests/Action/CombinationEquipment9Test.cs +++ b/.Lib9c.Tests/Action/CombinationEquipment9Test.cs @@ -114,48 +114,6 @@ public void Execute_Throw_InsufficientBalanceException(bool backward) backward, recipeId, subRecipeId, 0)); } - [Fact] - public void Rehearsal() - { - var action = new CombinationEquipment9 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - recipeId = 1, - subRecipeId = 255, - }; - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
- { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void AddAndUnlockOption() { diff --git a/.Lib9c.Tests/Action/Coupons/IssueCouponsTest.cs b/.Lib9c.Tests/Action/Coupons/IssueCouponsTest.cs index 6d24341603b..4a2f2a5060d 100644 --- a/.Lib9c.Tests/Action/Coupons/IssueCouponsTest.cs +++ b/.Lib9c.Tests/Action/Coupons/IssueCouponsTest.cs @@ -69,24 +69,6 @@ public void Execute() }) .GetCouponWallet(CouponsFixture.AgentAddress1)); - Assert.Equal( - Bencodex.Types.Null.Value, - new IssueCoupons( - ImmutableDictionary.Empty - .Add(CouponsFixture.RewardSet1, 1) - .Add(CouponsFixture.RewardSet2, 2), - CouponsFixture.AgentAddress1) - .Execute( - new ActionContext - { - PreviousState = state, - Rehearsal = true, - RandomSeed = random.Seed, - BlockIndex = 0, - Signer = CouponsFixture.AgentAddress1, - }) - .GetState(CouponsFixture.AgentAddress1.Derive(SerializeKeys.CouponWalletKey))); - state = new IssueCoupons( ImmutableDictionary.Empty .Add(CouponsFixture.RewardSet1, 1) diff --git a/.Lib9c.Tests/Action/Coupons/RedeemCouponTest.cs b/.Lib9c.Tests/Action/Coupons/RedeemCouponTest.cs index 51332611710..812a174853d 100644 --- a/.Lib9c.Tests/Action/Coupons/RedeemCouponTest.cs +++ b/.Lib9c.Tests/Action/Coupons/RedeemCouponTest.cs @@ -141,40 +141,6 @@ public void Execute() .SetCouponWallet(CouponsFixture.AgentAddress1, agent1CouponWallet) .SetCouponWallet(CouponsFixture.AgentAddress2, agent2CouponWallet); - var rehearsedState = new RedeemCoupon(CouponsFixture.Guid1, agent1Avatar0Address) - .Execute( - new ActionContext - { - PreviousState = state, - Rehearsal = true, - Signer = CouponsFixture.AgentAddress1, - RandomSeed = random.Seed, - }); - - Assert.Equal( - ActionBase.MarkChanged, - rehearsedState.GetState(agent1Avatar0Address)); - - Assert.Equal( - ActionBase.MarkChanged, - rehearsedState.GetState( - agent1Avatar0Address.Derive(SerializeKeys.LegacyInventoryKey))); - - Assert.Equal( - ActionBase.MarkChanged, - rehearsedState.GetState( - agent1Avatar0Address.Derive(SerializeKeys.LegacyWorldInformationKey))); - - Assert.Equal( - ActionBase.MarkChanged, - rehearsedState.GetState( - agent1Avatar0Address.Derive(SerializeKeys.LegacyQuestListKey))); - - Assert.Equal( - ActionBase.MarkChanged, - rehearsedState.GetState( - CouponsFixture.AgentAddress1.Derive(SerializeKeys.CouponWalletKey))); - // can't redeem other person's coupon var expected = state.GetAvatarStateV2(agent1Avatar0Address); state = new RedeemCoupon(CouponsFixture.Guid3, agent1Avatar0Address) diff --git a/.Lib9c.Tests/Action/Coupons/TransferCouponsTest.cs b/.Lib9c.Tests/Action/Coupons/TransferCouponsTest.cs index fab6b8e805a..741ce778aa2 100644 --- a/.Lib9c.Tests/Action/Coupons/TransferCouponsTest.cs +++ b/.Lib9c.Tests/Action/Coupons/TransferCouponsTest.cs @@ -135,6 +135,7 @@ public void Execute() Rehearsal = false, })); + // multiple transfer state = state .SetCouponWallet( CouponsFixture.AgentAddress1, @@ -149,34 +150,6 @@ public void Execute() CouponsFixture.AgentAddress3, ImmutableDictionary.Empty); - var rehearsedState = new TransferCoupons( - ImmutableDictionary>.Empty - .Add(CouponsFixture.AgentAddress2, ImmutableHashSet.Empty - .Add(CouponsFixture.Guid1) - .Add(CouponsFixture.Guid2)) - .Add(CouponsFixture.AgentAddress3, ImmutableHashSet.Empty - .Add(CouponsFixture.Guid3))) - .Execute( - new ActionContext - { - PreviousState = state, - Signer = CouponsFixture.AgentAddress1, - Rehearsal = true, - }); - Assert.Equal( - ActionBase.MarkChanged, - rehearsedState.GetState( - CouponsFixture.AgentAddress1.Derive(SerializeKeys.CouponWalletKey))); - Assert.Equal( - ActionBase.MarkChanged, - rehearsedState.GetState( - CouponsFixture.AgentAddress2.Derive(SerializeKeys.CouponWalletKey))); - Assert.Equal( - ActionBase.MarkChanged, - rehearsedState.GetState( - CouponsFixture.AgentAddress3.Derive(SerializeKeys.CouponWalletKey))); - - // multiple transfer state = new TransferCoupons( ImmutableDictionary>.Empty .Add(CouponsFixture.AgentAddress2, ImmutableHashSet.Empty diff --git a/.Lib9c.Tests/Action/CreateAvatar0Test.cs b/.Lib9c.Tests/Action/CreateAvatar0Test.cs index 7251dd21694..28ba4f4b141 100644 --- a/.Lib9c.Tests/Action/CreateAvatar0Test.cs +++ b/.Lib9c.Tests/Action/CreateAvatar0Test.cs @@ -215,64 +215,6 @@ public void ExecuteThrowAvatarIndexAlreadyUsedException(int index) ); } - [Fact] - public void Rehearsal() - { - var agentAddress = default(Address); - var avatarAddress = agentAddress.Derive("avatar"); - - var action = new CreateAvatar0() - { - avatarAddress = avatarAddress, - index = 0, - hair = 0, - ear = 0, - lens = 0, - tail = 0, - name = "test", - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - Addresses.GoldCurrency, - Addresses.Ranking, - }; - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - updatedAddresses.Add(slotAddress); - } - - var state = new Account(MockState.Empty) - .SetState(Addresses.Ranking, new RankingState0().Serialize()) - .SetState(GoldCurrencyState.Address, gold.Serialize()); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal( - updatedAddresses.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void SerializeWithDotnetAPI() { diff --git a/.Lib9c.Tests/Action/CreateAvatar10Test.cs b/.Lib9c.Tests/Action/CreateAvatar10Test.cs index 49a3b0f64dc..2ee2d5cb539 100644 --- a/.Lib9c.Tests/Action/CreateAvatar10Test.cs +++ b/.Lib9c.Tests/Action/CreateAvatar10Test.cs @@ -230,71 +230,6 @@ public void ExecuteThrowAvatarIndexAlreadyUsedException(int index) ); } - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public void Rehearsal(int index) - { - var agentAddress = default(Address); - var avatarAddress = _agentAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CreateAvatar2.DeriveFormat, - index - ) - ); - - var action = new CreateAvatar10() - { - index = index, - hair = 0, - ear = 0, - lens = 0, - tail = 0, - name = "test", - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - avatarAddress.Derive(LegacyInventoryKey), - avatarAddress.Derive(LegacyQuestListKey), - avatarAddress.Derive(LegacyWorldInformationKey), - }; - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - updatedAddresses.Add(slotAddress); - } - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal( - updatedAddresses.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void Serialize_With_DotnetAPI() { diff --git a/.Lib9c.Tests/Action/CreateAvatar2Test.cs b/.Lib9c.Tests/Action/CreateAvatar2Test.cs index 639b71e0a89..91ccc159722 100644 --- a/.Lib9c.Tests/Action/CreateAvatar2Test.cs +++ b/.Lib9c.Tests/Action/CreateAvatar2Test.cs @@ -230,72 +230,6 @@ public void ExecuteThrowAvatarIndexAlreadyUsedException(int index) ); } - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public void Rehearsal(int index) - { - var agentAddress = default(Address); - var avatarAddress = _agentAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CreateAvatar2.DeriveFormat, - index - ) - ); - - var action = new CreateAvatar2() - { - index = index, - hair = 0, - ear = 0, - lens = 0, - tail = 0, - name = "test", - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - Addresses.GoldCurrency, - Addresses.Ranking, - }; - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - updatedAddresses.Add(slotAddress); - } - - var state = new Account(MockState.Empty) - .SetState(Addresses.Ranking, new RankingState0().Serialize()) - .SetState(GoldCurrencyState.Address, gold.Serialize()); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal( - updatedAddresses.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void SerializeWithDotnetAPI() { diff --git a/.Lib9c.Tests/Action/CreateAvatar3Test.cs b/.Lib9c.Tests/Action/CreateAvatar3Test.cs index 974cedc017c..b136d04258a 100644 --- a/.Lib9c.Tests/Action/CreateAvatar3Test.cs +++ b/.Lib9c.Tests/Action/CreateAvatar3Test.cs @@ -232,75 +232,6 @@ public void ExecuteThrowAvatarIndexAlreadyUsedException(int index) ); } - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public void Rehearsal(int index) - { - var agentAddress = default(Address); - var avatarAddress = _agentAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CreateAvatar3.DeriveFormat, - index - ) - ); - - var action = new CreateAvatar3() - { - index = index, - hair = 0, - ear = 0, - lens = 0, - tail = 0, - name = "test", - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - Addresses.GoldCurrency, - Addresses.Ranking, - avatarAddress.Derive(LegacyInventoryKey), - avatarAddress.Derive(LegacyQuestListKey), - avatarAddress.Derive(LegacyWorldInformationKey), - }; - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - updatedAddresses.Add(slotAddress); - } - - var state = new Account(MockState.Empty) - .SetState(Addresses.Ranking, new RankingState0().Serialize()) - .SetState(GoldCurrencyState.Address, gold.Serialize()); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal( - updatedAddresses.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void Serialize_With_DotnetAPI() { diff --git a/.Lib9c.Tests/Action/CreateAvatar6Test.cs b/.Lib9c.Tests/Action/CreateAvatar6Test.cs index 97c1c04029a..5909bfca91f 100644 --- a/.Lib9c.Tests/Action/CreateAvatar6Test.cs +++ b/.Lib9c.Tests/Action/CreateAvatar6Test.cs @@ -232,75 +232,6 @@ public void ExecuteThrowAvatarIndexAlreadyUsedException(int index) ); } - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public void Rehearsal(int index) - { - var agentAddress = default(Address); - var avatarAddress = _agentAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CreateAvatar2.DeriveFormat, - index - ) - ); - - var action = new CreateAvatar6() - { - index = index, - hair = 0, - ear = 0, - lens = 0, - tail = 0, - name = "test", - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - Addresses.GoldCurrency, - Addresses.Ranking, - avatarAddress.Derive(LegacyInventoryKey), - avatarAddress.Derive(LegacyQuestListKey), - avatarAddress.Derive(LegacyWorldInformationKey), - }; - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - updatedAddresses.Add(slotAddress); - } - - var state = new Account(MockState.Empty) - .SetState(Addresses.Ranking, new RankingState0().Serialize()) - .SetState(GoldCurrencyState.Address, gold.Serialize()); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal( - updatedAddresses.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void Serialize_With_DotnetAPI() { diff --git a/.Lib9c.Tests/Action/CreateAvatar7Test.cs b/.Lib9c.Tests/Action/CreateAvatar7Test.cs index a0f92fdf6d4..39fb3a22776 100644 --- a/.Lib9c.Tests/Action/CreateAvatar7Test.cs +++ b/.Lib9c.Tests/Action/CreateAvatar7Test.cs @@ -213,71 +213,6 @@ public void ExecuteThrowAvatarIndexAlreadyUsedException(int index) ); } - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public void Rehearsal(int index) - { - var agentAddress = default(Address); - var avatarAddress = _agentAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CreateAvatar2.DeriveFormat, - index - ) - ); - - var action = new CreateAvatar7() - { - index = index, - hair = 0, - ear = 0, - lens = 0, - tail = 0, - name = "test", - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - avatarAddress.Derive(LegacyInventoryKey), - avatarAddress.Derive(LegacyQuestListKey), - avatarAddress.Derive(LegacyWorldInformationKey), - }; - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - updatedAddresses.Add(slotAddress); - } - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal( - updatedAddresses.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void Serialize_With_DotnetAPI() { diff --git a/.Lib9c.Tests/Action/CreateAvatar8Test.cs b/.Lib9c.Tests/Action/CreateAvatar8Test.cs index c8d8fba49c2..4d484beeb0e 100644 --- a/.Lib9c.Tests/Action/CreateAvatar8Test.cs +++ b/.Lib9c.Tests/Action/CreateAvatar8Test.cs @@ -212,71 +212,6 @@ public void ExecuteThrowAvatarIndexAlreadyUsedException(int index) ); } - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public void Rehearsal(int index) - { - var agentAddress = default(Address); - var avatarAddress = _agentAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CreateAvatar2.DeriveFormat, - index - ) - ); - - var action = new CreateAvatar8() - { - index = index, - hair = 0, - ear = 0, - lens = 0, - tail = 0, - name = "test", - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - avatarAddress.Derive(LegacyInventoryKey), - avatarAddress.Derive(LegacyQuestListKey), - avatarAddress.Derive(LegacyWorldInformationKey), - }; - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - updatedAddresses.Add(slotAddress); - } - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal( - updatedAddresses.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void Serialize_With_DotnetAPI() { diff --git a/.Lib9c.Tests/Action/CreateAvatar9Test.cs b/.Lib9c.Tests/Action/CreateAvatar9Test.cs index 32e9d10dc8f..fb2da046426 100644 --- a/.Lib9c.Tests/Action/CreateAvatar9Test.cs +++ b/.Lib9c.Tests/Action/CreateAvatar9Test.cs @@ -239,71 +239,6 @@ public void ExecuteThrowAvatarIndexAlreadyUsedException(int index) ); } - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public void Rehearsal(int index) - { - var agentAddress = default(Address); - var avatarAddress = _agentAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CreateAvatar2.DeriveFormat, - index - ) - ); - - var action = new CreateAvatar9() - { - index = index, - hair = 0, - ear = 0, - lens = 0, - tail = 0, - name = "test", - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - avatarAddress.Derive(LegacyInventoryKey), - avatarAddress.Derive(LegacyQuestListKey), - avatarAddress.Derive(LegacyWorldInformationKey), - }; - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - updatedAddresses.Add(slotAddress); - } - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal( - updatedAddresses.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } - [Fact] public void Serialize_With_DotnetAPI() { diff --git a/.Lib9c.Tests/Action/CreatePendingActivationTest.cs b/.Lib9c.Tests/Action/CreatePendingActivationTest.cs index df64cc87dc3..9ae2a4f8689 100644 --- a/.Lib9c.Tests/Action/CreatePendingActivationTest.cs +++ b/.Lib9c.Tests/Action/CreatePendingActivationTest.cs @@ -71,29 +71,5 @@ public void CheckPermission() }) ); } - - [Fact] - public void Rehearsal() - { - var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; - var pubKey = new PublicKey( - ByteUtil.ParseHex("02ed49dbe0f2c34d9dff8335d6dd9097f7a3ef17dfb5f048382eebc7f451a50aa1") - ); - var pendingActivation = new PendingActivationState(nonce, pubKey); - var action = new CreatePendingActivation(pendingActivation); - IAccount nextState = action.Execute( - new ActionContext() - { - BlockIndex = 101, - Signer = default, - Rehearsal = true, - PreviousState = new Account(MockState.Empty), - } - ); - Assert.Equal( - ImmutableHashSet.Create(pendingActivation.address), - nextState.Delta.UpdatedAddresses - ); - } } } diff --git a/.Lib9c.Tests/Action/DailyReward4Test.cs b/.Lib9c.Tests/Action/DailyReward4Test.cs index b428880f4e4..4fa13eb6e79 100644 --- a/.Lib9c.Tests/Action/DailyReward4Test.cs +++ b/.Lib9c.Tests/Action/DailyReward4Test.cs @@ -118,33 +118,5 @@ public void ExecuteThrowFailedLoadStateException() }) ); } - - [Fact] - public void Rehearsal() - { - var action = new DailyReward4 - { - avatarAddress = _avatarAddress, - }; - - var nextState = action.Execute(new ActionContext - { - BlockIndex = 0, - PreviousState = new Account(MockState.Empty), - RandomSeed = 0, - Rehearsal = true, - Signer = _agentAddress, - }); - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/DailyReward5Test.cs b/.Lib9c.Tests/Action/DailyReward5Test.cs index 2a43430b377..6aed7de0332 100644 --- a/.Lib9c.Tests/Action/DailyReward5Test.cs +++ b/.Lib9c.Tests/Action/DailyReward5Test.cs @@ -58,31 +58,6 @@ public DailyReward5Test(ITestOutputHelper outputHelper) .SetState(_avatarAddress, avatarState.Serialize()); } - [Fact] - public void Rehearsal() - { - var action = new DailyReward5 - { - avatarAddress = _avatarAddress, - }; - - var nextState = action.Execute(new ActionContext - { - BlockIndex = 0, - PreviousState = new Account(MockState.Empty), - RandomSeed = 0, - Rehearsal = true, - Signer = _agentAddress, - }); - - var updatedAddresses = new List
- { - _avatarAddress, - }; - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(1)] [InlineData(2)] @@ -100,7 +75,7 @@ public void Execute(int avatarStateSerializedVersion) break; } - var nextState = ExecuteInternal(previousStates, 2040); + var nextState = ExecuteInternal(previousStates, 2448); var nextGameConfigState = nextState.GetGameConfigState(); var nextAvatarState = avatarStateSerializedVersion switch { @@ -122,11 +97,11 @@ public void Execute_Throw_FailedLoadStateException() => [Theory] [InlineData(0, 0, true)] - [InlineData(0, 2039, true)] - [InlineData(0, 2040, false)] - [InlineData(2040, 2040, true)] - [InlineData(2040, 2040 + 2039, true)] - [InlineData(2040, 2040 + 2040, false)] + [InlineData(0, 2447, true)] + [InlineData(0, 2448, false)] + [InlineData(2448, 2448, true)] + [InlineData(2448, 2448 + 2447, true)] + [InlineData(2448, 2448 + 2448, false)] public void Execute_Throw_RequiredBlockIndexException( long dailyRewardReceivedIndex, long executeBlockIndex, diff --git a/.Lib9c.Tests/Action/DailyReward6Test.cs b/.Lib9c.Tests/Action/DailyReward6Test.cs index 97bd4659140..66f986a564d 100644 --- a/.Lib9c.Tests/Action/DailyReward6Test.cs +++ b/.Lib9c.Tests/Action/DailyReward6Test.cs @@ -60,34 +60,6 @@ public DailyReward6Test(ITestOutputHelper outputHelper) .SetState(_avatarAddress, avatarState.Serialize()); } - [Fact] - public void Rehearsal() - { - var action = new DailyReward6 - { - avatarAddress = _avatarAddress, - }; - - var nextState = action.Execute(new ActionContext - { - BlockIndex = 0, - PreviousState = new Account(MockState.Empty), - RandomSeed = 0, - Rehearsal = true, - Signer = _agentAddress, - }); - - var updatedAddresses = new List
- { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(1)] [InlineData(2)] @@ -105,7 +77,7 @@ public void Execute(int avatarStateSerializedVersion) break; } - var nextState = ExecuteInternal(previousStates, 2040); + var nextState = ExecuteInternal(previousStates, 2448); var nextGameConfigState = nextState.GetGameConfigState(); var nextAvatarState = nextState.GetAvatarStateV2(_avatarAddress); Assert.NotNull(nextAvatarState); @@ -125,11 +97,11 @@ public void Execute_Throw_FailedLoadStateException() => [Theory] [InlineData(0, 0, true)] - [InlineData(0, 2039, true)] - [InlineData(0, 2040, false)] - [InlineData(2040, 2040, true)] - [InlineData(2040, 2040 + 2039, true)] - [InlineData(2040, 2040 + 2040, false)] + [InlineData(0, 2447, true)] + [InlineData(0, 2448, false)] + [InlineData(2448, 2448, true)] + [InlineData(2448, 2448 + 2447, true)] + [InlineData(2448, 2448 + 2448, false)] public void Execute_Throw_RequiredBlockIndexException( long dailyRewardReceivedIndex, long executeBlockIndex, diff --git a/.Lib9c.Tests/Action/DailyRewardTest.cs b/.Lib9c.Tests/Action/DailyRewardTest.cs index 8c00f14f11f..ab1c275c27b 100644 --- a/.Lib9c.Tests/Action/DailyRewardTest.cs +++ b/.Lib9c.Tests/Action/DailyRewardTest.cs @@ -58,27 +58,6 @@ public DailyRewardTest(ITestOutputHelper outputHelper) .SetState(_avatarAddress, avatarState.Serialize()); } - [Fact] - public void Rehearsal() - { - var action = new DailyReward - { - avatarAddress = _avatarAddress, - }; - - var nextState = action.Execute(new ActionContext - { - BlockIndex = 0, - PreviousState = new Account(MockState.Empty), - RandomSeed = 0, - Rehearsal = true, - Signer = _agentAddress, - }); - - var updatedAddress = Assert.Single(nextState.Delta.UpdatedAddresses); - Assert.Equal(_avatarAddress, updatedAddress); - } - [Theory] [InlineData(true)] [InlineData(false)] @@ -96,7 +75,7 @@ public void Execute(bool legacy) break; } - var nextState = ExecuteInternal(previousStates, 2040); + var nextState = ExecuteInternal(previousStates, 2448); var nextGameConfigState = nextState.GetGameConfigState(); nextState.TryGetAvatarStateV2(_agentAddress, _avatarAddress, out var nextAvatarState, out var migrationRequired); Assert.Equal(legacy, migrationRequired); @@ -117,11 +96,11 @@ public void Execute_Throw_FailedLoadStateException() => [Theory] [InlineData(0, 0, true)] - [InlineData(0, 2039, true)] - [InlineData(0, 2040, false)] - [InlineData(2040, 2040, true)] - [InlineData(2040, 2040 + 2039, true)] - [InlineData(2040, 2040 + 2040, false)] + [InlineData(0, 2447, true)] + [InlineData(0, 2448, false)] + [InlineData(2448, 2448, true)] + [InlineData(2448, 2448 + 2447, true)] + [InlineData(2448, 2448 + 2448, false)] public void Execute_Throw_RequiredBlockIndexException( long dailyRewardReceivedIndex, long executeBlockIndex, diff --git a/.Lib9c.Tests/Action/Garages/BulkUnloadFromGaragesTest.cs b/.Lib9c.Tests/Action/Garages/BulkUnloadFromGaragesTest.cs new file mode 100644 index 00000000000..c74da7e7ef0 --- /dev/null +++ b/.Lib9c.Tests/Action/Garages/BulkUnloadFromGaragesTest.cs @@ -0,0 +1,245 @@ +#nullable enable + +namespace Lib9c.Tests.Action.Garages +{ + using System.Collections.Generic; + using System.Linq; + using System.Security.Cryptography; + using Bencodex.Types; + using Lib9c.Tests.Util; + using Libplanet.Action.State; + using Libplanet.Common; + using Libplanet.Crypto; + using Libplanet.Types.Assets; + using Nekoyume; + using Nekoyume.Action; + using Nekoyume.Action.Garages; + using Nekoyume.Model.Garages; + using Nekoyume.Model.Item; + using Nekoyume.Model.Mail; + using Xunit; + + public class BulkUnloadFromGaragesTest + { + private const int AvatarIndex = 0; + + private static readonly Address AgentAddress = new PrivateKey().ToAddress(); + + private static readonly Address AvatarAddress = + Addresses.GetAvatarAddress(AgentAddress, AvatarIndex); + + private readonly TableSheets _tableSheets; + private readonly Currency _ncg; + private readonly IAccount _previousStates; + + public BulkUnloadFromGaragesTest() + { + var initializeStates = InitializeUtil.InitializeStates( + agentAddr: AgentAddress, + avatarIndex: AvatarIndex); + _tableSheets = initializeStates.tableSheets; + _previousStates = initializeStates.initialStatesWithAvatarStateV2; + _ncg = initializeStates.initialStatesWithAvatarStateV2.GetGoldCurrency(); + } + + public static IEnumerable Get_Sample_PlainValue() + { + var avatarAddress = Addresses.GetAvatarAddress(AgentAddress, AvatarIndex); + var fungibleAssetValues = GetFungibleAssetValues(AgentAddress, avatarAddress) + as IEnumerable<(Address balanceAddr, FungibleAssetValue value)>; + var hex = string.Join( + string.Empty, + Enumerable.Range(0, 64).Select(i => (i % 10).ToString())); + IEnumerable<(HashDigest fungibleId, int count)> fungibleIdAndCounts = new[] + { + (HashDigest.FromString(hex), 1), + (HashDigest.FromString(hex), int.MaxValue), + }; + + yield return new object[] + { + (avatarAddress, fungibleAssetValues, fungibleIdAndCounts, memo: "memo"), + }; + } + + [Theory] + [MemberData(nameof(Get_Sample_PlainValue))] + public void Serialize( + ( + Address recipientAvatarAddress, + IEnumerable<(Address balanceAddress, FungibleAssetValue value)>? + fungibleAssetValues, + IEnumerable<(HashDigest fungibleId, int count)>? fungibleIdAndCounts, + string? memo) unloadData) + { + var actions = new[] + { + new BulkUnloadFromGarages(), + new BulkUnloadFromGarages(new[] { unloadData }), + }; + + foreach (var action in actions) + { + var serialized = action.PlainValue; + var deserialized = new BulkUnloadFromGarages(); + deserialized.LoadPlainValue(serialized); + + Assert.Equal(action.UnloadData.Count, deserialized.UnloadData.Count); + Assert.Equal(serialized, deserialized.PlainValue); + + for (var i = 0; i < action.UnloadData.Count; i++) + { + var deserializedData = deserialized.UnloadData[i]; + var actionData = action.UnloadData[i]; + + Assert.Equal( + actionData.recipientAvatarAddress, + deserializedData.recipientAvatarAddress); + Assert.True( + actionData.fungibleAssetValues?.SequenceEqual(deserializedData + .fungibleAssetValues!) + ?? deserializedData.fungibleAssetValues is null); + Assert.True( + actionData.fungibleIdAndCounts?.SequenceEqual(deserializedData + .fungibleIdAndCounts!) + ?? deserializedData.fungibleIdAndCounts is null); + Assert.Equal(actionData.memo, deserializedData.memo); + } + } + } + + [Fact] + public void Execute_Success() + { + const long blockIndex = 0L; + var (states, unloadDataEnumerable) = RegisterPlainValue(_previousStates); + var action = new BulkUnloadFromGarages(new[] { unloadDataEnumerable }); + states = action.Execute(new ActionContext + { + Signer = AgentAddress, + BlockIndex = blockIndex, + Rehearsal = false, + PreviousState = states, + RandomSeed = new TestRandom().Seed, + }); + + // Test fungibleAssetValues + var unloadData = action.UnloadData.ToArray(); + var garageBalanceAddress = Addresses.GetGarageBalanceAddress(AgentAddress); + if (unloadData[0].fungibleAssetValues is { } fungibleAssetValues) + { + foreach (var (balanceAddress, value) in fungibleAssetValues) + { + Assert.Equal(value, states.GetBalance(balanceAddress, value.Currency)); + Assert.Equal( + value.Currency * 0, + states.GetBalance(garageBalanceAddress, value.Currency)); + } + } + + // Test fungibleItems + if (unloadData[0].fungibleIdAndCounts is { } fungibleIdAndCounts) + { + var inventoryAddress = unloadData[0].recipientAvatarAddress + .Derive(SerializeKeys.LegacyInventoryKey); + var inventory = states.GetInventory(inventoryAddress); + + foreach (var (fungibleId, count) in fungibleIdAndCounts) + { + var garageAddress = Addresses.GetGarageAddress(AgentAddress, fungibleId); + Assert.Equal(0, new FungibleItemGarage(states.GetState(garageAddress)).Count); + Assert.True(inventory.HasFungibleItem(fungibleId, blockIndex: 0, count)); + } + } + + // Test Mailing + var avatarDict = (Dictionary)states.GetState(unloadData[0].recipientAvatarAddress)!; + var mailBox = new MailBox((List)avatarDict[SerializeKeys.MailBoxKey]); + Assert.Single(mailBox); + + var mail = Assert.IsType(mailBox.First()); + Assert.Equal(blockIndex, mail.blockIndex); + Assert.Equal(blockIndex, mail.requiredBlockIndex); + Assert.True(action.UnloadData[0].fungibleAssetValues?.SequenceEqual(mail.FungibleAssetValues!) ?? + mail.FungibleAssetValues is null); + Assert.True(action.UnloadData[0].fungibleIdAndCounts?.SequenceEqual(mail.FungibleIdAndCounts!) ?? + mail.FungibleIdAndCounts is null); + Assert.Equal(action.UnloadData[0].memo, mail.Memo); + } + + private static (Address balanceAddr, FungibleAssetValue value)[] + GetFungibleAssetValues( + Address agentAddr, + Address avatarAddr) + { + return CurrenciesTest.GetSampleCurrencies() + .Select(objects => (FungibleAssetValue)objects[0]) + .Where(fav => fav.Sign > 0) + .Select(fav => + { + if (Currencies.IsRuneTicker(fav.Currency.Ticker) || + Currencies.IsSoulstoneTicker(fav.Currency.Ticker)) + { + return (avatarAddr, fav); + } + + return (agentAddr, fav); + }) + .ToArray(); + } + + private (IAccount states, ( + Address recipientAvatarAddress, + IEnumerable<(Address balanceAddress, FungibleAssetValue value)>? fungibleAssetValues, + IEnumerable<(HashDigest fungibleId, int count)>? fungibleIdAndCounts, + string? memo)) + RegisterPlainValue(IAccount previousStates) + { + var states = previousStates; + + var recipientAvatarAddress = AvatarAddress; + var fungibleAssetValues = GetFungibleAssetValues(AgentAddress, AvatarAddress); + var fungibleItemAndCounts = _tableSheets.MaterialItemSheet.OrderedList! + .Take(3) + .Select(ItemFactory.CreateMaterial) + .Select((material, index) => + { + var garageAddress = + Addresses.GetGarageAddress(AgentAddress, material.FungibleId); + var count = index + 1; + var garage = new FungibleItemGarage(material, count); + states = states.SetState(garageAddress, garage.Serialize()); + return (FungibleItem: (IFungibleItem)material, count); + }) + .ToArray(); + var fungibleItemIdAndCounts = fungibleItemAndCounts + .Select(tuple => (fungibleId: tuple.FungibleItem.FungibleId, tuple.count)) + .ToArray(); + + var actionContext = new ActionContext { Signer = Addresses.Admin }; + var garageBalanceAddress = Addresses.GetGarageBalanceAddress(AgentAddress); + foreach (var (_, value) in fungibleAssetValues) + { + if (value.Currency.Equals(_ncg)) + { + states = states.TransferAsset( + actionContext, + Addresses.Admin, + garageBalanceAddress, + value); + } + else + { + states = states.MintAsset( + actionContext, + garageBalanceAddress, + value); + } + } + + return ( + states, + (recipientAvatarAddress, fungibleAssetValues, fungibleItemIdAndCounts, "memo")); + } + } +} diff --git a/.Lib9c.Tests/Action/HackAndSlash0Test.cs b/.Lib9c.Tests/Action/HackAndSlash0Test.cs index 76da9db97ed..6c64e632a41 100644 --- a/.Lib9c.Tests/Action/HackAndSlash0Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash0Test.cs @@ -567,42 +567,6 @@ public void ExecuteThrowNotEnoughActionPointException() SerializeException(exec); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash0() - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - avatarAddress = _avatarAddress, - WeeklyArenaAddress = _weeklyArenaState.address, - RankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _weeklyArenaState.address, - _rankingMapAddress, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void SerializeWithDotnetAPI() { diff --git a/.Lib9c.Tests/Action/HackAndSlash10Test.cs b/.Lib9c.Tests/Action/HackAndSlash10Test.cs index 6e8f371f6b3..a05f433b14c 100644 --- a/.Lib9c.Tests/Action/HackAndSlash10Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash10Test.cs @@ -1102,44 +1102,6 @@ x.item is IFungibleItem ownedFungibleItem && Assert.InRange(totalCount, totalMin, totalMax); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash10 - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - playCount = 1, - avatarAddress = _avatarAddress, - rankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _rankingMapAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private static void SerializeException(Exception exec) where T : Exception { diff --git a/.Lib9c.Tests/Action/HackAndSlash11Test.cs b/.Lib9c.Tests/Action/HackAndSlash11Test.cs index 9887b3cf9b7..136de735b07 100644 --- a/.Lib9c.Tests/Action/HackAndSlash11Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash11Test.cs @@ -1048,42 +1048,6 @@ x.item is IFungibleItem ownedFungibleItem && Assert.InRange(totalCount, totalMin, totalMax); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash11 - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - playCount = 1, - avatarAddress = _avatarAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private static void SerializeException(Exception exec) where T : Exception { diff --git a/.Lib9c.Tests/Action/HackAndSlash12Test.cs b/.Lib9c.Tests/Action/HackAndSlash12Test.cs index 0b81fb66c64..95c9fe5f39c 100644 --- a/.Lib9c.Tests/Action/HackAndSlash12Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash12Test.cs @@ -1044,42 +1044,6 @@ x.item is IFungibleItem ownedFungibleItem && Assert.InRange(totalCount, totalMin, totalMax); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash12 - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - playCount = 1, - avatarAddress = _avatarAddress, - }; - - var updatedAddresses = new List
- { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private static void SerializeException(Exception exec) where T : Exception { diff --git a/.Lib9c.Tests/Action/HackAndSlash13Test.cs b/.Lib9c.Tests/Action/HackAndSlash13Test.cs index 049c39f8a17..11948443689 100644 --- a/.Lib9c.Tests/Action/HackAndSlash13Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash13Test.cs @@ -1083,41 +1083,6 @@ x.item is IFungibleItem ownedFungibleItem && Assert.InRange(totalCount, totalMin, totalMax); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash13 - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - avatarAddress = _avatarAddress, - }; - - var updatedAddresses = new List
- { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private static void SerializeException(Exception exec) where T : Exception { diff --git a/.Lib9c.Tests/Action/HackAndSlash2Test.cs b/.Lib9c.Tests/Action/HackAndSlash2Test.cs index b3a70bd2cf7..cc18f27730e 100644 --- a/.Lib9c.Tests/Action/HackAndSlash2Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash2Test.cs @@ -576,42 +576,6 @@ public void ExecuteThrowNotEnoughActionPointException() SerializeException(exec); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash2() - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - avatarAddress = _avatarAddress, - WeeklyArenaAddress = _weeklyArenaState.address, - RankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _weeklyArenaState.address, - _rankingMapAddress, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void SerializeWithDotnetAPI() { diff --git a/.Lib9c.Tests/Action/HackAndSlash6Test.cs b/.Lib9c.Tests/Action/HackAndSlash6Test.cs index fc05276a556..b104abcfd75 100644 --- a/.Lib9c.Tests/Action/HackAndSlash6Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash6Test.cs @@ -786,45 +786,6 @@ public void ExecuteThrowNotEnoughActionPointException() SerializeException(exec); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash6 - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - avatarAddress = _avatarAddress, - WeeklyArenaAddress = _weeklyArenaState.address, - RankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _weeklyArenaState.address, - _rankingMapAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private static void SerializeException(Exception exec) where T : Exception { diff --git a/.Lib9c.Tests/Action/HackAndSlash7Test.cs b/.Lib9c.Tests/Action/HackAndSlash7Test.cs index cf656faddc3..02504967324 100644 --- a/.Lib9c.Tests/Action/HackAndSlash7Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash7Test.cs @@ -849,45 +849,6 @@ public void ExecuteThrowNotEnoughActionPointException() SerializeException(exec); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash7 - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - avatarAddress = _avatarAddress, - WeeklyArenaAddress = _weeklyArenaState.address, - RankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _weeklyArenaState.address, - _rankingMapAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private static void SerializeException(Exception exec) where T : Exception { diff --git a/.Lib9c.Tests/Action/HackAndSlash8Test.cs b/.Lib9c.Tests/Action/HackAndSlash8Test.cs index 38ff5fcae7b..034c6e71db0 100644 --- a/.Lib9c.Tests/Action/HackAndSlash8Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash8Test.cs @@ -832,43 +832,6 @@ public void ExecuteThrowNotEnoughActionPointException() SerializeException(exec); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash8 - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - avatarAddress = _avatarAddress, - rankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _rankingMapAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private static void SerializeException(Exception exec) where T : Exception { diff --git a/.Lib9c.Tests/Action/HackAndSlash9Test.cs b/.Lib9c.Tests/Action/HackAndSlash9Test.cs index 4081e2deeae..18ba2738db4 100644 --- a/.Lib9c.Tests/Action/HackAndSlash9Test.cs +++ b/.Lib9c.Tests/Action/HackAndSlash9Test.cs @@ -1125,44 +1125,6 @@ x.item is IFungibleItem ownedFungibleItem && Assert.InRange(totalCount, totalMin, totalMax); } - [Fact] - public void Rehearsal() - { - var action = new HackAndSlash9 - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - playCount = 1, - avatarAddress = _avatarAddress, - rankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _rankingMapAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - private static void SerializeException(Exception exec) where T : Exception { diff --git a/.Lib9c.Tests/Action/InitializeStatesTest.cs b/.Lib9c.Tests/Action/InitializeStatesTest.cs index bc0aa0d383b..37f4eba0cf7 100644 --- a/.Lib9c.Tests/Action/InitializeStatesTest.cs +++ b/.Lib9c.Tests/Action/InitializeStatesTest.cs @@ -1,5 +1,6 @@ namespace Lib9c.Tests.Action { + using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -285,5 +286,86 @@ public void ExecuteWithoutAdminState() Assert.Null(genesisState.GetState(Addresses.Admin)); } + + [Fact] + public void ExecuteWithoutInitialSupply() + { + var gameConfigState = new GameConfigState(_sheets[nameof(GameConfigSheet)]); + var redeemCodeListSheet = new RedeemCodeListSheet(); + redeemCodeListSheet.Set(_sheets[nameof(RedeemCodeListSheet)]); + var goldDistributions = Array.Empty(); + var minterKey = new PrivateKey(); +#pragma warning disable CS0618 + // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 + var ncg = Currency.Legacy("NCG", 2, null); +#pragma warning restore CS0618 + var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; + var privateKey = new PrivateKey(); + + var action = new InitializeStates( + rankingState: new RankingState0(), + shopState: new ShopState(), + tableSheets: _sheets, + gameConfigState: gameConfigState, + redeemCodeState: new RedeemCodeState(redeemCodeListSheet), + adminAddressState: null, + activatedAccountsState: new ActivatedAccountsState(ImmutableHashSet
.Empty), + goldCurrencyState: new GoldCurrencyState(ncg, 0), + goldDistributions: goldDistributions, + pendingActivationStates: Array.Empty() + ); + + var genesisState = action.Execute(new ActionContext() + { + BlockIndex = 0, + Miner = default, + Signer = minterKey.ToAddress(), + PreviousState = new Account(MockState.Empty), + }); + + Assert.Equal(0 * ncg, genesisState.GetBalance(GoldCurrencyState.Address, ncg)); + } + + [Fact] + public void ExecuteWithAssetMinters() + { + var gameConfigState = new GameConfigState(_sheets[nameof(GameConfigSheet)]); + var redeemCodeListSheet = new RedeemCodeListSheet(); + redeemCodeListSheet.Set(_sheets[nameof(RedeemCodeListSheet)]); + var goldDistributionCsvPath = GoldDistributionTest.CreateFixtureCsvFile(); + var goldDistributions = GoldDistribution.LoadInDescendingEndBlockOrder(goldDistributionCsvPath); + var minterKey = new PrivateKey(); +#pragma warning disable CS0618 + // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 + var ncg = Currency.Legacy("NCG", 2, minterKey.ToAddress()); +#pragma warning restore CS0618 + var nonce = new byte[] { 0x00, 0x01, 0x02, 0x03 }; + var adminAddress = new Address("F9A15F870701268Bd7bBeA6502eB15F4997f32f9"); + + var action = new InitializeStates( + rankingState: new RankingState0(), + shopState: new ShopState(), + tableSheets: _sheets, + gameConfigState: gameConfigState, + redeemCodeState: new RedeemCodeState(redeemCodeListSheet), + adminAddressState: new AdminState(adminAddress, 1500000), + activatedAccountsState: new ActivatedAccountsState(ImmutableHashSet
.Empty.Add(adminAddress)), + goldCurrencyState: new GoldCurrencyState(ncg), + goldDistributions: goldDistributions, + pendingActivationStates: Array.Empty(), + assetMinters: new[] { default(Address) }.ToHashSet() + ); + + var genesisState = action.Execute(new ActionContext() + { + BlockIndex = 0, + Miner = default, + Signer = minterKey.ToAddress(), + PreviousState = new Account(MockState.Empty), + }); + + var assetMinters = Assert.IsType(genesisState.GetState(Addresses.AssetMinters)); + Assert.Contains(default(Address).Serialize(), assetMinters); + } } } diff --git a/.Lib9c.Tests/Action/IssueTokensFromGarageTest.cs b/.Lib9c.Tests/Action/IssueTokensFromGarageTest.cs new file mode 100644 index 00000000000..0fc86f13e3c --- /dev/null +++ b/.Lib9c.Tests/Action/IssueTokensFromGarageTest.cs @@ -0,0 +1,152 @@ +namespace Lib9c.Tests +{ + using System.Collections.Generic; + using System.Linq; + using System.Security.Cryptography; + using Bencodex.Types; + using Lib9c.Tests.Action; + using Libplanet.Action.State; + using Libplanet.Common; + using Libplanet.Crypto; + using Libplanet.Types.Assets; + using Nekoyume; + using Nekoyume.Action; + using Nekoyume.Model; + using Nekoyume.Model.Garages; + using Nekoyume.Model.Item; + using Nekoyume.Model.State; + using Xunit; + + public class IssueTokensFromGarageTest + { + // {Id: 100000, Grade: 1, ItemType: Material, ItemSubType: NormalMaterial, ElementalType: Normal, ItemId: baa2081d3b485ef2906c95a3965531ec750a74cfaefe91d0c3061865608b426c} + private static readonly HashDigest SampleFungibleId = + HashDigest.FromString("baa2081d3b485ef2906c95a3965531ec750a74cfaefe91d0c3061865608b426c"); + + private readonly IAccount _prevState; + private readonly TableSheets _tableSheets; + private readonly Address _signer; + + public IssueTokensFromGarageTest() + { + _signer = new PrivateKey().ToAddress(); + var sheets = TableSheetsImporter.ImportSheets(); + _tableSheets = new TableSheets(sheets); + + var garageBalanceAddr = Addresses.GetGarageBalanceAddress(_signer); + _prevState = new Account( + MockState.Empty + .SetBalance(garageBalanceAddr, Currencies.Crystal * 1000) + ); + + IEnumerable materials = _tableSheets.MaterialItemSheet.OrderedList! + .Take(3) + .Select(ItemFactory.CreateMaterial); + foreach (Material material in materials) + { + var garageAddr = Addresses.GetGarageAddress(_signer, material.FungibleId); + var garage = new FungibleItemGarage(material, 1000); + _prevState = _prevState.SetState(garageAddr, garage.Serialize()); + } + + foreach (var (key, value) in sheets) + { + _prevState = _prevState.SetState(Addresses.TableSheet.Derive(key), value.Serialize()); + } + } + + [Fact] + public void PlainValue() + { + var specs = new List() + { + IssueTokensFromGarage.Spec.FromFungibleAssetValue(Currencies.Crystal * 1000), + IssueTokensFromGarage.Spec.FromFungibleItemValue(new FungibleItemValue(SampleFungibleId, 42)), + }; + + var action = new IssueTokensFromGarage(specs); + Dictionary expected = Dictionary.Empty + .Add("type_id", "issue_tokens_from_garage") + .Add("values", List.Empty + .Add(new List((Currencies.Crystal * 1000).Serialize(), default(Null))) + .Add(new List(default(Null), new FungibleItemValue(SampleFungibleId, 42).Serialize()))); + Assert.Equal( + expected, + action.PlainValue + ); + } + + [Fact] + public void LoadPlainValue() + { + Dictionary encoded = Dictionary.Empty + .Add("type_id", "issue_tokens_from_garage") + .Add("values", List.Empty + .Add(new List((Currencies.Crystal * 1000).Serialize(), default(Null))) + .Add(new List(default(Null), new FungibleItemValue(SampleFungibleId, 42).Serialize()))); + var action = new IssueTokensFromGarage(); + action.LoadPlainValue(encoded); + var expected = new List() + { + IssueTokensFromGarage.Spec.FromFungibleAssetValue(Currencies.Crystal * 1000), + IssueTokensFromGarage.Spec.FromFungibleItemValue(new FungibleItemValue(SampleFungibleId, 42)), + }; + + Assert.Equal(expected, action.Specs); + } + + [Fact] + public void Execute_With_FungibleAssetValue() + { + var action = new IssueTokensFromGarage(new[] + { + IssueTokensFromGarage.Spec.FromFungibleAssetValue(Currencies.Crystal * 42), + }); + + IAccount nextState = action.Execute( + new ActionContext() + { + PreviousState = _prevState, + Signer = _signer, + Rehearsal = false, + BlockIndex = 42, + } + ); + + var wrappedCrystal = Currencies.GetWrappedCurrency(Currencies.Crystal); + + Assert.Equal(wrappedCrystal * 42, nextState.GetBalance(_signer, wrappedCrystal)); + Assert.Equal( + Currencies.Crystal * (1000 - 42), + nextState.GetBalance( + Addresses.GetGarageBalanceAddress(_signer), + Currencies.Crystal + ) + ); + } + + [Fact] + public void Execute_With_FungibleItemValue() + { + var action = new IssueTokensFromGarage(new[] + { + IssueTokensFromGarage.Spec.FromFungibleItemValue(new FungibleItemValue(SampleFungibleId, 42)), + }); + + var nextState = action.Execute( + new ActionContext() + { + PreviousState = _prevState, + Signer = _signer, + Rehearsal = false, + BlockIndex = 42, + } + ); + + Currency itemCurrency = Currency.Legacy("Item_NT_100000", 0, null); + var garageAddr = Addresses.GetGarageAddress(_signer, SampleFungibleId); + Assert.Equal(itemCurrency * 42, nextState.GetBalance(_signer, itemCurrency)); + Assert.Equal(1000 - 42, new FungibleItemGarage(nextState.GetState(garageAddr)).Count); + } + } +} diff --git a/.Lib9c.Tests/Action/ItemEnhancement0Test.cs b/.Lib9c.Tests/Action/ItemEnhancement0Test.cs index 0a984a61dfd..c727b0d247f 100644 --- a/.Lib9c.Tests/Action/ItemEnhancement0Test.cs +++ b/.Lib9c.Tests/Action/ItemEnhancement0Test.cs @@ -473,49 +473,5 @@ public void ResultModelDeterministic() Assert.Equal(result.Serialize(), result2.Serialize()); } - - [Fact] - public void Rehearsal() - { - var agentAddress = default(Address); - var avatarAddress = agentAddress.Derive("avatar"); - var slotAddress = - avatarAddress.Derive(string.Format(CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, 0)); - - var action = new ItemEnhancement0() - { - itemId = default, - materialIds = new[] { Guid.NewGuid() }, - avatarAddress = avatarAddress, - slotIndex = 0, - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - slotAddress, - Addresses.GoldCurrency, - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty) - .SetState(GoldCurrencyState.Address, gold.Serialize()); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/ItemEnhancement10Test.cs b/.Lib9c.Tests/Action/ItemEnhancement10Test.cs index fa4858986d2..7b999275841 100644 --- a/.Lib9c.Tests/Action/ItemEnhancement10Test.cs +++ b/.Lib9c.Tests/Action/ItemEnhancement10Test.cs @@ -197,48 +197,6 @@ public void Execute(int level, int expectedGold, bool backward) Assert.Equal(costRow.Cost, slotResult.gold); } - [Fact] - public void Rehearsal() - { - var action = new ItemEnhancement10() - { - itemId = default, - materialId = default, - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - ItemEnhancement10.GetFeeStoreAddress(), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void Execute_ActionObsoletedException() { diff --git a/.Lib9c.Tests/Action/ItemEnhancement2Test.cs b/.Lib9c.Tests/Action/ItemEnhancement2Test.cs index 6fb8fd0268d..d7f6c9864d9 100644 --- a/.Lib9c.Tests/Action/ItemEnhancement2Test.cs +++ b/.Lib9c.Tests/Action/ItemEnhancement2Test.cs @@ -438,49 +438,5 @@ public void ResultModelDeterministic() Assert.Equal(result.Serialize(), result2.Serialize()); } - - [Fact] - public void Rehearsal() - { - var agentAddress = default(Address); - var avatarAddress = agentAddress.Derive("avatar"); - var slotAddress = - avatarAddress.Derive(string.Format(CultureInfo.InvariantCulture, CombinationSlotState.DeriveFormat, 0)); - - var action = new ItemEnhancement2() - { - itemId = default, - materialId = Guid.NewGuid(), - avatarAddress = avatarAddress, - slotIndex = 0, - }; - -#pragma warning disable CS0618 - // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var gold = new GoldCurrencyState(Currency.Legacy("NCG", 2, null)); -#pragma warning restore CS0618 - - var updatedAddresses = new List
() - { - agentAddress, - avatarAddress, - slotAddress, - Addresses.GoldCurrency, - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty) - .SetState(GoldCurrencyState.Address, gold.Serialize()); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/ItemEnhancement7Test.cs b/.Lib9c.Tests/Action/ItemEnhancement7Test.cs index 54c3426fca0..ba9891dc3db 100644 --- a/.Lib9c.Tests/Action/ItemEnhancement7Test.cs +++ b/.Lib9c.Tests/Action/ItemEnhancement7Test.cs @@ -165,47 +165,5 @@ public void Execute(int level, int expectedLevel, int expectedGold, bool backwar Assert.Equal(costRow.Cost, slotResult.gold); } - - [Fact] - public void Rehearsal() - { - var action = new ItemEnhancement7() - { - itemId = default, - materialId = default, - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/ItemEnhancement8Test.cs b/.Lib9c.Tests/Action/ItemEnhancement8Test.cs index f46c0044b29..a6dea2ac170 100644 --- a/.Lib9c.Tests/Action/ItemEnhancement8Test.cs +++ b/.Lib9c.Tests/Action/ItemEnhancement8Test.cs @@ -165,47 +165,5 @@ public void Execute(int level, int expectedLevel, int expectedGold, bool backwar Assert.Equal(costRow.Cost, slotResult.gold); } - - [Fact] - public void Rehearsal() - { - var action = new ItemEnhancement8 - { - itemId = default, - materialId = default, - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/ItemEnhancement9Test.cs b/.Lib9c.Tests/Action/ItemEnhancement9Test.cs index 70c29fdd2c6..a6005c80eb1 100644 --- a/.Lib9c.Tests/Action/ItemEnhancement9Test.cs +++ b/.Lib9c.Tests/Action/ItemEnhancement9Test.cs @@ -190,47 +190,5 @@ public void Execute(int level, int expectedGold, bool backward) Assert.Equal(preItemUsable.ItemId, resultEquipment.ItemId); Assert.Equal(costRow.Cost, slotResult.gold); } - - [Fact] - public void Rehearsal() - { - var action = new ItemEnhancement9() - { - itemId = default, - materialId = default, - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - slotAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.Blacksmith, - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/MimisbrunnrBattle4Test.cs b/.Lib9c.Tests/Action/MimisbrunnrBattle4Test.cs index 6e0f8333bae..16dbecae072 100644 --- a/.Lib9c.Tests/Action/MimisbrunnrBattle4Test.cs +++ b/.Lib9c.Tests/Action/MimisbrunnrBattle4Test.cs @@ -585,43 +585,5 @@ public void ExecuteEquippableItemValidation() RandomSeed = 0, }); } - - [Fact] - public void Rehearsal() - { - var action = new MimisbrunnrBattle4() - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - avatarAddress = _avatarAddress, - WeeklyArenaAddress = _weeklyArenaState.address, - RankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _avatarAddress, - _weeklyArenaState.address, - _rankingMapAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/MimisbrunnrBattle5Test.cs b/.Lib9c.Tests/Action/MimisbrunnrBattle5Test.cs index 813f264458c..1e0dbf0ad97 100644 --- a/.Lib9c.Tests/Action/MimisbrunnrBattle5Test.cs +++ b/.Lib9c.Tests/Action/MimisbrunnrBattle5Test.cs @@ -570,42 +570,5 @@ public void ExecuteEquippableItemValidation() RandomSeed = 0, }); } - - [Fact] - public void Rehearsal() - { - var action = new MimisbrunnrBattle5() - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - avatarAddress = _avatarAddress, - rankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _rankingMapAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/MimisbrunnrBattle6Test.cs b/.Lib9c.Tests/Action/MimisbrunnrBattle6Test.cs index 6888047b80f..0a07bcdcb92 100644 --- a/.Lib9c.Tests/Action/MimisbrunnrBattle6Test.cs +++ b/.Lib9c.Tests/Action/MimisbrunnrBattle6Test.cs @@ -728,43 +728,5 @@ x.item is IFungibleItem ownedFungibleItem && var totalCount = rewardItem.Sum(x => x.count); Assert.InRange(totalCount, totalMin, totalMax); } - - [Fact] - public void Rehearsal() - { - var action = new MimisbrunnrBattle6() - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - playCount = 1, - avatarAddress = _avatarAddress, - rankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _rankingMapAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/MimisbrunnrBattle7Test.cs b/.Lib9c.Tests/Action/MimisbrunnrBattle7Test.cs index 1ca49ae271f..1eae59601a2 100644 --- a/.Lib9c.Tests/Action/MimisbrunnrBattle7Test.cs +++ b/.Lib9c.Tests/Action/MimisbrunnrBattle7Test.cs @@ -728,43 +728,5 @@ x.item is IFungibleItem ownedFungibleItem && var totalCount = rewardItem.Sum(x => x.count); Assert.InRange(totalCount, totalMin, totalMax); } - - [Fact] - public void Rehearsal() - { - var action = new MimisbrunnrBattle7() - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - playCount = 1, - avatarAddress = _avatarAddress, - rankingMapAddress = _rankingMapAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _rankingMapAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/MimisbrunnrBattle8Test.cs b/.Lib9c.Tests/Action/MimisbrunnrBattle8Test.cs index 1f4b48fb8da..5f1a32d5d47 100644 --- a/.Lib9c.Tests/Action/MimisbrunnrBattle8Test.cs +++ b/.Lib9c.Tests/Action/MimisbrunnrBattle8Test.cs @@ -679,41 +679,5 @@ x.item is IFungibleItem ownedFungibleItem && var totalCount = rewardItem.Sum(x => x.count); Assert.InRange(totalCount, totalMin, totalMax); } - - [Fact] - public void Rehearsal() - { - var action = new MimisbrunnrBattle8() - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - playCount = 1, - avatarAddress = _avatarAddress, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/MimisbrunnrBattle9Test.cs b/.Lib9c.Tests/Action/MimisbrunnrBattle9Test.cs index 7dd4502673a..519be580bf8 100644 --- a/.Lib9c.Tests/Action/MimisbrunnrBattle9Test.cs +++ b/.Lib9c.Tests/Action/MimisbrunnrBattle9Test.cs @@ -730,41 +730,5 @@ x.item is IFungibleItem && var totalCount = rewardItem.Sum(x => x.count); Assert.InRange(totalCount, totalMin, totalMax); } - - [Fact] - public void Rehearsal() - { - var action = new MimisbrunnrBattle9 - { - costumes = new List(), - equipments = new List(), - foods = new List(), - worldId = 1, - stageId = 1, - playCount = 1, - avatarAddress = _avatarAddress, - }; - - var updatedAddresses = new List
- { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/MintAssetsTest.cs b/.Lib9c.Tests/Action/MintAssetsTest.cs new file mode 100644 index 00000000000..469f3c4a2ca --- /dev/null +++ b/.Lib9c.Tests/Action/MintAssetsTest.cs @@ -0,0 +1,316 @@ +namespace Lib9c.Tests.Action +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Security.Cryptography; + using Bencodex.Types; + using Libplanet.Action.State; + using Libplanet.Common; + using Libplanet.Crypto; + using Libplanet.Types.Assets; + using Nekoyume; + using Nekoyume.Action; + using Nekoyume.Model; + using Nekoyume.Model.Item; + using Nekoyume.Model.Mail; + using Nekoyume.Model.State; + using Xunit; + + public class MintAssetsTest + { + private readonly Address _adminAddress; + private readonly ISet
_minters; + private readonly Currency _ncgCurrency; + private readonly IAccount _prevState; + + private readonly TableSheets _tableSheets; + + public MintAssetsTest() + { + _adminAddress = new PrivateKey().ToAddress(); + _ncgCurrency = Currency.Legacy("NCG", 2, null); + _minters = new HashSet
+ { + new PrivateKey().ToAddress(), + new PrivateKey().ToAddress(), + new PrivateKey().ToAddress(), + }; + _prevState = new Account( + MockState.Empty + .SetState(AdminState.Address, new AdminState(_adminAddress, 100).Serialize()) + .SetState(Addresses.AssetMinters, new List(_minters.Select(m => m.Serialize()))) + ); + + var sheets = TableSheetsImporter.ImportSheets(); + foreach (var (key, value) in sheets) + { + _prevState = _prevState.SetState(Addresses.TableSheet.Derive(key), value.Serialize()); + } + + _tableSheets = new TableSheets(sheets); + } + + [Fact] + public void PlainValue() + { + var r = new List() + { + new (default, _ncgCurrency * 100, null), + new (new Address("0x47d082a115c63e7b58b1532d20e631538eafadde"), _ncgCurrency * 1000, null), + }; + var act = new MintAssets(r, null); + var expected = Dictionary.Empty + .Add("type_id", "mint_assets") + .Add("values", List.Empty + .Add(Null.Value) + .Add(new List(default(Address).Bencoded, (_ncgCurrency * 100).Serialize(), default(Null))) + .Add(new List(new Address("0x47d082a115c63e7b58b1532d20e631538eafadde").Bencoded, (_ncgCurrency * 1000).Serialize(), default(Null)))); + Assert.Equal( + expected, + act.PlainValue + ); + + var act2 = new MintAssets(r, "memo"); + var expected2 = Dictionary.Empty + .Add("type_id", "mint_assets") + .Add("values", List.Empty + .Add((Text)"memo") + .Add(new List(default(Address).Bencoded, (_ncgCurrency * 100).Serialize(), default(Null))) + .Add(new List(new Address("0x47d082a115c63e7b58b1532d20e631538eafadde").Bencoded, (_ncgCurrency * 1000).Serialize(), default(Null)))); + Assert.Equal( + expected2, + act2.PlainValue + ); + } + + [Fact] + public void LoadPlainValue() + { + var pv = Dictionary.Empty + .Add("type_id", "mint_assets") + .Add("values", List.Empty + .Add(default(Null)) + .Add(new List(default(Address).Bencoded, (_ncgCurrency * 100).Serialize(), default(Null))) + .Add(new List(new Address("0x47d082a115c63e7b58b1532d20e631538eafadde").Bencoded, (_ncgCurrency * 1000).Serialize(), default(Null)))); + var act = new MintAssets(); + act.LoadPlainValue(pv); + + var expected = new List() + { + new (default, _ncgCurrency * 100, null), + new (new Address("0x47d082a115c63e7b58b1532d20e631538eafadde"), _ncgCurrency * 1000, null), + }; + Assert.Equal(expected, act.MintSpecs); + Assert.Null(act.Memo); + + var pv2 = Dictionary.Empty + .Add("type_id", "mint_assets") + .Add("values", List.Empty + .Add((Text)"memo") + .Add(new List(default(Address).Bencoded, (_ncgCurrency * 100).Serialize(), default(Null))) + .Add(new List(new Address("0x47d082a115c63e7b58b1532d20e631538eafadde").Bencoded, (_ncgCurrency * 1000).Serialize(), default(Null)))); + var act2 = new MintAssets(); + act2.LoadPlainValue(pv2); + Assert.Equal("memo", act2.Memo); + } + + [Fact] + public void Execute_With_FungibleAssetValue() + { + var action = new MintAssets( + new List() + { + new (default, _ncgCurrency * 100, null), + new (new Address("0x47d082a115c63e7b58b1532d20e631538eafadde"), _ncgCurrency * 1000, null), + }, + null + ); + IAccount nextState = action.Execute( + new ActionContext() + { + PreviousState = _prevState, + Signer = _minters.First(), + Rehearsal = false, + BlockIndex = 1, + } + ); + + Assert.Equal( + _ncgCurrency * 100, + nextState.GetBalance(default, _ncgCurrency) + ); + Assert.Equal( + _ncgCurrency * 1000, + nextState.GetBalance(new Address("0x47d082a115c63e7b58b1532d20e631538eafadde"), _ncgCurrency) + ); + } + + [Fact] + public void Execute_With_FungibleItemValue() + { + IAccount prevState = GenerateAvatar(_prevState, out Address avatarAddress); + HashDigest fungibleId = HashDigest.FromString( + "7f5d25371e58c0f3d5a33511450f73c2e0fa4fac32a92e1cbe64d3bf2fef6328" + ); + + var action = new MintAssets( + new List() + { + new ( + avatarAddress, + null, + new FungibleItemValue(fungibleId, 42) + ), + }, + "Execute_With_FungibleItemValue" + ); + IAccount nextState = action.Execute( + new ActionContext() + { + PreviousState = prevState, + Signer = _minters.First(), + Rehearsal = false, + BlockIndex = 1, + } + ); + + var inventory = nextState.GetInventory(avatarAddress.Derive(SerializeKeys.LegacyInventoryKey)); + Assert.Contains(inventory.Items, i => i.count == 42 && i.item is Material m && m.FungibleId.Equals(fungibleId)); + + var avatarDict = Assert.IsType(nextState.GetState(avatarAddress)); + var mailBox = new MailBox((List)avatarDict[SerializeKeys.MailBoxKey]); + Assert.Single(mailBox); + var mail = Assert.IsType(mailBox.First()); + Assert.Equal(new[] { (fungibleId, 42) }, mail.FungibleIdAndCounts); + Assert.Equal(action.Memo, mail.Memo); + } + + [Fact] + public void Execute_With_Mixed() + { + IAccount prevState = GenerateAvatar(_prevState, out Address avatarAddress); + HashDigest fungibleId = HashDigest.FromString( + "7f5d25371e58c0f3d5a33511450f73c2e0fa4fac32a92e1cbe64d3bf2fef6328" + ); + + var action = new MintAssets( + new List() + { + new (new Address("0x47d082a115c63e7b58b1532d20e631538eafadde"), _ncgCurrency * 1000, null), + new ( + avatarAddress, + Currencies.StakeRune * 123, + null + ), + new ( + avatarAddress, + null, + new FungibleItemValue(fungibleId, 42) + ), + }, + "Execute_With_FungibleItemValue" + ); + IAccount nextState = action.Execute( + new ActionContext() + { + PreviousState = prevState, + Signer = _minters.First(), + Rehearsal = false, + BlockIndex = 1, + } + ); + + var inventory = nextState.GetInventory(avatarAddress.Derive(SerializeKeys.LegacyInventoryKey)); + Assert.Contains(inventory.Items, i => i.count == 42 && i.item is Material m && m.FungibleId.Equals(fungibleId)); + + var avatarDict = Assert.IsType(nextState.GetState(avatarAddress)); + var mailBox = new MailBox((List)avatarDict[SerializeKeys.MailBoxKey]); + Assert.Single(mailBox); + var mail = Assert.IsType(mailBox.First()); + Assert.Equal(new[] { (fungibleId, 42) }, mail.FungibleIdAndCounts); + Assert.Equal(new[] { (avatarAddress, Currencies.StakeRune * 123) }, mail.FungibleAssetValues); + Assert.Equal(action.Memo, mail.Memo); + } + + [Fact] + public void Execute_Throws_InvalidMinterException() + { + var action = new MintAssets( + new List() + { + new (default, _ncgCurrency * 100, null), + new (new Address("0x47d082a115c63e7b58b1532d20e631538eafadde"), _ncgCurrency * 1000, null), + }, + null + ); + + // Allows admin + _ = action.Execute( + new ActionContext() + { + PreviousState = _prevState, + Signer = _adminAddress, + Rehearsal = false, + BlockIndex = 1, + } + ); + + // Allows minters + foreach (Address m in _minters) + { + _ = action.Execute( + new ActionContext() + { + PreviousState = _prevState, + Signer = m, + Rehearsal = false, + BlockIndex = 1, + } + ); + } + + // Denies others + Assert.Throws(() => action.Execute( + new ActionContext() + { + PreviousState = _prevState, + Signer = default, + Rehearsal = false, + BlockIndex = 1, + } + )); + } + + private IAccount GenerateAvatar(IAccount state, out Address avatarAddress) + { + var address = new PrivateKey().ToAddress(); + var agentState = new AgentState(address); + avatarAddress = address.Derive("avatar"); + var rankingMapAddress = new PrivateKey().ToAddress(); + var avatarState = new AvatarState( + avatarAddress, + address, + 0, + _tableSheets.GetAvatarSheets(), + new GameConfigState(), + rankingMapAddress) + { + worldInformation = new WorldInformation( + 0, + _tableSheets.WorldSheet, + GameConfig.RequireClearedStageLevel.ActionsInShop), + }; + agentState.avatarAddresses[0] = avatarAddress; + + state = state + .SetState(address, agentState.Serialize()) + .SetState(avatarAddress, avatarState.SerializeV2()) + .SetState( + avatarAddress.Derive(SerializeKeys.LegacyInventoryKey), + avatarState.inventory.Serialize()); + + return state; + } + } +} diff --git a/.Lib9c.Tests/Action/MonsterCollect0Test.cs b/.Lib9c.Tests/Action/MonsterCollect0Test.cs index f342f3ac91e..77adb0f4ede 100644 --- a/.Lib9c.Tests/Action/MonsterCollect0Test.cs +++ b/.Lib9c.Tests/Action/MonsterCollect0Test.cs @@ -226,30 +226,5 @@ public void Execute_Throw_InvalidLevelException(int prevLevel, int level) BlockIndex = 1, })); } - - [Fact] - public void Rehearsal() - { - Address collectionAddress = MonsterCollectionState0.DeriveAddress(_signer, 1); - MonsterCollect0 action = new MonsterCollect0 - { - level = 1, - collectionRound = 1, - }; - IAccount nextState = action.Execute(new ActionContext - { - PreviousState = new Account(MockState.Empty), - Signer = _signer, - Rehearsal = true, - }); - - List
updatedAddresses = new List
() - { - _signer, - collectionAddress, - }; - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/MonsterCollect2Test.cs b/.Lib9c.Tests/Action/MonsterCollect2Test.cs index cd752b522f6..66626e5a27b 100644 --- a/.Lib9c.Tests/Action/MonsterCollect2Test.cs +++ b/.Lib9c.Tests/Action/MonsterCollect2Test.cs @@ -154,31 +154,5 @@ public void Execute_Throw_InsufficientBalanceException() BlockIndex = 1, })); } - - [Fact] - public void Rehearsal() - { - var action = new MonsterCollect2 - { - level = 1, - }; - IAccount nextState = action.Execute(new ActionContext - { - PreviousState = new Account(MockState.Empty), - Signer = _signer, - Rehearsal = true, - }); - - List
updatedAddresses = new List
() - { - _signer, - MonsterCollectionState.DeriveAddress(_signer, 0), - MonsterCollectionState.DeriveAddress(_signer, 1), - MonsterCollectionState.DeriveAddress(_signer, 2), - MonsterCollectionState.DeriveAddress(_signer, 3), - }; - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/MonsterCollectTest.cs b/.Lib9c.Tests/Action/MonsterCollectTest.cs index be48e0f9a62..d728a494195 100644 --- a/.Lib9c.Tests/Action/MonsterCollectTest.cs +++ b/.Lib9c.Tests/Action/MonsterCollectTest.cs @@ -175,31 +175,5 @@ public void Execute_Throw_InvalidOperationException() BlockIndex = 1, })); } - - [Fact] - public void Rehearsal() - { - MonsterCollect action = new MonsterCollect - { - level = 1, - }; - IAccount nextState = action.Execute(new ActionContext - { - PreviousState = new Account(MockState.Empty), - Signer = _signer, - Rehearsal = true, - }); - - List
updatedAddresses = new List
() - { - _signer, - MonsterCollectionState.DeriveAddress(_signer, 0), - MonsterCollectionState.DeriveAddress(_signer, 1), - MonsterCollectionState.DeriveAddress(_signer, 2), - MonsterCollectionState.DeriveAddress(_signer, 3), - }; - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/Raid5Test.cs b/.Lib9c.Tests/Action/Raid5Test.cs index 9edb82739df..23d14f445b4 100644 --- a/.Lib9c.Tests/Action/Raid5Test.cs +++ b/.Lib9c.Tests/Action/Raid5Test.cs @@ -44,7 +44,7 @@ public Raid5Test() [InlineData(null, true, true, true, false, 0, 0L, false, false, 0, false, false, false, 5, false, 0, 10002, 1, 30001)] [InlineData(null, true, true, true, false, 0, 0L, false, false, 0, false, false, false, 5, true, 0, 10002, 1, 30001)] // Refill by interval. - [InlineData(null, true, true, false, true, 0, -8640, false, false, 0, false, false, false, 5, true, 0, 10002, 1, 30001)] + [InlineData(null, true, true, false, true, 0, -10368, false, false, 0, false, false, false, 5, true, 0, 10002, 1, 30001)] // Refill by NCG. [InlineData(null, true, true, false, true, 0, 200L, true, true, 0, false, false, false, 5, true, 0, 10002, 1, 30001)] [InlineData(null, true, true, false, true, 0, 200L, true, true, 1, false, false, false, 5, true, 0, 10002, 1, 30001)] diff --git a/.Lib9c.Tests/Action/Raid6Test.cs b/.Lib9c.Tests/Action/Raid6Test.cs index 50c1cba896e..6b4c1871987 100644 --- a/.Lib9c.Tests/Action/Raid6Test.cs +++ b/.Lib9c.Tests/Action/Raid6Test.cs @@ -44,7 +44,7 @@ public Raid6Test() [InlineData(null, true, true, true, false, 0, 0L, false, false, 0, false, false, false, 5, false, 0, 10002, 1, 30001)] [InlineData(null, true, true, true, false, 0, 0L, false, false, 0, false, false, false, 5, true, 0, 10002, 1, 30001)] // Refill by interval. - [InlineData(null, true, true, false, true, 0, -8640, false, false, 0, false, false, false, 5, true, 0, 10002, 1, 30001)] + [InlineData(null, true, true, false, true, 0, -10368, false, false, 0, false, false, false, 5, true, 0, 10002, 1, 30001)] // Refill by NCG. [InlineData(null, true, true, false, true, 0, 200L, true, true, 0, false, false, false, 5, true, 0, 10002, 1, 30001)] [InlineData(null, true, true, false, true, 0, 200L, true, true, 1, false, false, false, 5, true, 0, 10002, 1, 30001)] diff --git a/.Lib9c.Tests/Action/RankingBattle10Test.cs b/.Lib9c.Tests/Action/RankingBattle10Test.cs index 0a9b613ae22..e142848af91 100644 --- a/.Lib9c.Tests/Action/RankingBattle10Test.cs +++ b/.Lib9c.Tests/Action/RankingBattle10Test.cs @@ -456,40 +456,6 @@ public void ExecuteThrowNotEnoughWeeklyArenaChallengeCountException() }); } - [Fact] - public void Rehearsal() - { - var action = new RankingBattle10 - { - avatarAddress = _avatar1Address, - enemyAddress = _avatar2Address, - weeklyArenaAddress = _weeklyArenaAddress, - costumeIds = new List(), - equipmentIds = new List(), - }; - - var updatedAddresses = new List
- { - _avatar1Address, - _weeklyArenaAddress, - _avatar1Address.Derive(LegacyInventoryKey), - _avatar1Address.Derive(LegacyWorldInformationKey), - _avatar1Address.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agent1Address, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(ItemSubType.Weapon, GameConfig.MaxEquipmentSlotCount.Weapon)] [InlineData(ItemSubType.Armor, GameConfig.MaxEquipmentSlotCount.Armor)] diff --git a/.Lib9c.Tests/Action/RankingBattle11Test.cs b/.Lib9c.Tests/Action/RankingBattle11Test.cs index 05930913ec6..112d594f6f6 100644 --- a/.Lib9c.Tests/Action/RankingBattle11Test.cs +++ b/.Lib9c.Tests/Action/RankingBattle11Test.cs @@ -658,40 +658,6 @@ public void Execute_Throw_NotEnoughAvatarLevelException(int avatarLevel) } } - [Fact] - public void Rehearsal() - { - var action = new RankingBattle11 - { - avatarAddress = _avatar1Address, - enemyAddress = _avatar2Address, - weeklyArenaAddress = _weeklyArenaAddress, - costumeIds = new List(), - equipmentIds = new List(), - }; - - var updatedAddresses = new List
- { - _avatar1Address, - _weeklyArenaAddress, - _avatar1Address.Derive(LegacyInventoryKey), - _avatar1Address.Derive(LegacyWorldInformationKey), - _avatar1Address.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext - { - PreviousState = state, - Signer = _agent1Address, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(ItemSubType.Weapon, GameConfig.MaxEquipmentSlotCount.Weapon)] [InlineData(ItemSubType.Armor, GameConfig.MaxEquipmentSlotCount.Armor)] diff --git a/.Lib9c.Tests/Action/RankingBattle5Test.cs b/.Lib9c.Tests/Action/RankingBattle5Test.cs index 3dc4255b8b3..31eb8a4b63d 100644 --- a/.Lib9c.Tests/Action/RankingBattle5Test.cs +++ b/.Lib9c.Tests/Action/RankingBattle5Test.cs @@ -420,41 +420,6 @@ public void ExecuteThrowNotEnoughWeeklyArenaChallengeCountException() }); } - [Fact] - public void Rehearsal() - { - var action = new RankingBattle5 - { - AvatarAddress = _avatar1Address, - EnemyAddress = _avatar2Address, - WeeklyArenaAddress = _weeklyArenaAddress, - costumeIds = new List(), - equipmentIds = new List(), - consumableIds = new List(), - }; - - var updatedAddresses = new List
() - { - _avatar1Address, - _weeklyArenaAddress, - _avatar1Address.Derive(LegacyInventoryKey), - _avatar1Address.Derive(LegacyWorldInformationKey), - _avatar1Address.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agent1Address, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void SerializeWithDotnetAPI() { diff --git a/.Lib9c.Tests/Action/RankingBattle6Test.cs b/.Lib9c.Tests/Action/RankingBattle6Test.cs index 6cefff07b33..870870629dc 100644 --- a/.Lib9c.Tests/Action/RankingBattle6Test.cs +++ b/.Lib9c.Tests/Action/RankingBattle6Test.cs @@ -420,41 +420,6 @@ public void ExecuteThrowNotEnoughWeeklyArenaChallengeCountException() }); } - [Fact] - public void Rehearsal() - { - var action = new RankingBattle6 - { - avatarAddress = _avatar1Address, - enemyAddress = _avatar2Address, - weeklyArenaAddress = _weeklyArenaAddress, - costumeIds = new List(), - equipmentIds = new List(), - consumableIds = new List(), - }; - - var updatedAddresses = new List
() - { - _avatar1Address, - _weeklyArenaAddress, - _avatar1Address.Derive(LegacyInventoryKey), - _avatar1Address.Derive(LegacyWorldInformationKey), - _avatar1Address.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agent1Address, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void SerializeWithDotnetAPI() { diff --git a/.Lib9c.Tests/Action/RankingBattle7Test.cs b/.Lib9c.Tests/Action/RankingBattle7Test.cs index f893b4deedd..6a28b39206c 100644 --- a/.Lib9c.Tests/Action/RankingBattle7Test.cs +++ b/.Lib9c.Tests/Action/RankingBattle7Test.cs @@ -420,41 +420,6 @@ public void ExecuteThrowNotEnoughWeeklyArenaChallengeCountException() }); } - [Fact] - public void Rehearsal() - { - var action = new RankingBattle7 - { - avatarAddress = _avatar1Address, - enemyAddress = _avatar2Address, - weeklyArenaAddress = _weeklyArenaAddress, - costumeIds = new List(), - equipmentIds = new List(), - consumableIds = new List(), - }; - - var updatedAddresses = new List
() - { - _avatar1Address, - _weeklyArenaAddress, - _avatar1Address.Derive(LegacyInventoryKey), - _avatar1Address.Derive(LegacyWorldInformationKey), - _avatar1Address.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agent1Address, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void SerializeWithDotnetAPI() { diff --git a/.Lib9c.Tests/Action/RankingBattle8Test.cs b/.Lib9c.Tests/Action/RankingBattle8Test.cs index aa01036a0fd..f8c710ad085 100644 --- a/.Lib9c.Tests/Action/RankingBattle8Test.cs +++ b/.Lib9c.Tests/Action/RankingBattle8Test.cs @@ -457,41 +457,6 @@ public void ExecuteThrowNotEnoughWeeklyArenaChallengeCountException() }); } - [Fact] - public void Rehearsal() - { - var action = new RankingBattle8 - { - avatarAddress = _avatar1Address, - enemyAddress = _avatar2Address, - weeklyArenaAddress = _weeklyArenaAddress, - costumeIds = new List(), - equipmentIds = new List(), - consumableIds = new List(), - }; - - var updatedAddresses = new List
() - { - _avatar1Address, - _weeklyArenaAddress, - _avatar1Address.Derive(LegacyInventoryKey), - _avatar1Address.Derive(LegacyWorldInformationKey), - _avatar1Address.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agent1Address, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(ItemSubType.Weapon, GameConfig.MaxEquipmentSlotCount.Weapon)] [InlineData(ItemSubType.Armor, GameConfig.MaxEquipmentSlotCount.Armor)] diff --git a/.Lib9c.Tests/Action/RankingBattle9Test.cs b/.Lib9c.Tests/Action/RankingBattle9Test.cs index 28ab7acfba5..181bf157cea 100644 --- a/.Lib9c.Tests/Action/RankingBattle9Test.cs +++ b/.Lib9c.Tests/Action/RankingBattle9Test.cs @@ -457,41 +457,6 @@ public void ExecuteThrowNotEnoughWeeklyArenaChallengeCountException() }); } - [Fact] - public void Rehearsal() - { - var action = new RankingBattle9 - { - avatarAddress = _avatar1Address, - enemyAddress = _avatar2Address, - weeklyArenaAddress = _weeklyArenaAddress, - costumeIds = new List(), - equipmentIds = new List(), - consumableIds = new List(), - }; - - var updatedAddresses = new List
() - { - _avatar1Address, - _weeklyArenaAddress, - _avatar1Address.Derive(LegacyInventoryKey), - _avatar1Address.Derive(LegacyWorldInformationKey), - _avatar1Address.Derive(LegacyQuestListKey), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agent1Address, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(ItemSubType.Weapon, GameConfig.MaxEquipmentSlotCount.Weapon)] [InlineData(ItemSubType.Armor, GameConfig.MaxEquipmentSlotCount.Armor)] diff --git a/.Lib9c.Tests/Action/RapidCombination4Test.cs b/.Lib9c.Tests/Action/RapidCombination4Test.cs index 674c12439b4..ad00e974e88 100644 --- a/.Lib9c.Tests/Action/RapidCombination4Test.cs +++ b/.Lib9c.Tests/Action/RapidCombination4Test.cs @@ -362,45 +362,6 @@ public void Execute_Throw_NotEnoughMaterialException(int materialCount, int trad })); } - [Fact] - public void Rehearsal() - { - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - slotAddress, - }; - - var state = new Account(MockState.Empty); - - var action = new RapidCombination4 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(null)] [InlineData(1)] diff --git a/.Lib9c.Tests/Action/RapidCombination5Test.cs b/.Lib9c.Tests/Action/RapidCombination5Test.cs index 8fdf14d6528..74d435df673 100644 --- a/.Lib9c.Tests/Action/RapidCombination5Test.cs +++ b/.Lib9c.Tests/Action/RapidCombination5Test.cs @@ -362,45 +362,6 @@ public void Execute_Throw_NotEnoughMaterialException(int materialCount, int trad })); } - [Fact] - public void Rehearsal() - { - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - slotAddress, - }; - - var state = new Account(MockState.Empty); - - var action = new RapidCombination5 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(null)] [InlineData(1)] diff --git a/.Lib9c.Tests/Action/RapidCombination6Test.cs b/.Lib9c.Tests/Action/RapidCombination6Test.cs index 104a8efa286..8661ecc2ae7 100644 --- a/.Lib9c.Tests/Action/RapidCombination6Test.cs +++ b/.Lib9c.Tests/Action/RapidCombination6Test.cs @@ -364,45 +364,6 @@ public void Execute_Throw_NotEnoughMaterialException(int materialCount, int trad })); } - [Fact] - public void Rehearsal() - { - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - slotAddress, - }; - - var state = new Account(MockState.Empty); - - var action = new RapidCombination6 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(null)] [InlineData(1)] diff --git a/.Lib9c.Tests/Action/RapidCombination7Test.cs b/.Lib9c.Tests/Action/RapidCombination7Test.cs index 3af440cf51e..4b3e410f8f1 100644 --- a/.Lib9c.Tests/Action/RapidCombination7Test.cs +++ b/.Lib9c.Tests/Action/RapidCombination7Test.cs @@ -364,45 +364,6 @@ public void Execute_Throw_NotEnoughMaterialException(int materialCount, int trad })); } - [Fact] - public void Rehearsal() - { - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - slotAddress, - }; - - var state = new Account(MockState.Empty); - - var action = new RapidCombination7 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(null)] [InlineData(1)] diff --git a/.Lib9c.Tests/Action/RapidCombination8Test.cs b/.Lib9c.Tests/Action/RapidCombination8Test.cs index a7a1a1545c0..e7b0bf69c55 100644 --- a/.Lib9c.Tests/Action/RapidCombination8Test.cs +++ b/.Lib9c.Tests/Action/RapidCombination8Test.cs @@ -366,45 +366,6 @@ public void Execute_Throw_NotEnoughMaterialException(int materialCount, int trad })); } - [Fact] - public void Rehearsal() - { - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - slotAddress, - }; - - var state = new Account(MockState.Empty); - - var action = new RapidCombination8 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(null)] [InlineData(1)] diff --git a/.Lib9c.Tests/Action/RapidCombination9Test.cs b/.Lib9c.Tests/Action/RapidCombination9Test.cs index 23be0d54265..feed6308f10 100644 --- a/.Lib9c.Tests/Action/RapidCombination9Test.cs +++ b/.Lib9c.Tests/Action/RapidCombination9Test.cs @@ -381,45 +381,6 @@ public void Execute_Throw_NotEnoughMaterialException(int materialCount, int trad })); } - [Fact] - public void Rehearsal() - { - var slotAddress = _avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - 0 - ) - ); - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - slotAddress, - }; - - var state = new Account(MockState.Empty); - - var action = new RapidCombination9 - { - avatarAddress = _avatarAddress, - slotIndex = 0, - }; - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Theory] [InlineData(null)] [InlineData(1)] diff --git a/.Lib9c.Tests/Action/RedeemCode0Test.cs b/.Lib9c.Tests/Action/RedeemCode0Test.cs index 366fea6497f..1e3cb7bb37b 100644 --- a/.Lib9c.Tests/Action/RedeemCode0Test.cs +++ b/.Lib9c.Tests/Action/RedeemCode0Test.cs @@ -112,28 +112,5 @@ public void Execute() nextRedeemCodeState.Redeem(redeemCode.Code, redeemCode.AvatarAddress); }); } - - [Fact] - public void Rehearsal() - { - var redeemCode = new RedeemCode0( - string.Empty, - _avatarAddress - ); - - IAccount nextState = redeemCode.Execute(new ActionContext() - { - BlockIndex = 1, - Miner = default, - PreviousState = new Account(MockState.Empty), - Rehearsal = true, - Signer = _agentAddress, - }); - - Assert.Equal( - nextState.Delta.UpdatedAddresses, - new[] { _avatarAddress, _agentAddress, RedeemCodeState.Address, GoldCurrencyState.Address }.ToImmutableHashSet() - ); - } } } diff --git a/.Lib9c.Tests/Action/RedeemCodeTest.cs b/.Lib9c.Tests/Action/RedeemCodeTest.cs index f3efda7057b..63a732fa1e7 100644 --- a/.Lib9c.Tests/Action/RedeemCodeTest.cs +++ b/.Lib9c.Tests/Action/RedeemCodeTest.cs @@ -127,37 +127,5 @@ public void Execute(bool backward) nextRedeemCodeState.Redeem(redeemCode.Code, redeemCode.AvatarAddress); }); } - - [Fact] - public void Rehearsal() - { - var redeemCode = new RedeemCode( - string.Empty, - _avatarAddress - ); - - IAccount nextState = redeemCode.Execute(new ActionContext() - { - BlockIndex = 1, - Miner = default, - PreviousState = new Account(MockState.Empty), - Rehearsal = true, - Signer = _agentAddress, - }); - - Assert.Equal( - new[] - { - _avatarAddress, - _agentAddress, - RedeemCodeState.Address, - GoldCurrencyState.Address, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - }.ToImmutableHashSet(), - nextState.Delta.UpdatedAddresses - ); - } } } diff --git a/.Lib9c.Tests/Action/RewardGoldTest.cs b/.Lib9c.Tests/Action/RewardGoldTest.cs index dd515ca590b..0563c25aa4e 100644 --- a/.Lib9c.Tests/Action/RewardGoldTest.cs +++ b/.Lib9c.Tests/Action/RewardGoldTest.cs @@ -582,5 +582,32 @@ public void TransferMead(int patronMead, int balance) Assert.Equal(0 * Currencies.Mead, nextState.GetBalance(patronAddress, Currencies.Mead)); Assert.Equal(balance * Currencies.Mead, nextState.GetBalance(agentAddress, Currencies.Mead)); } + + [Fact] + public void NoRewardWhenEmptySupply() + { + var weekly = new WeeklyArenaState(0); + var gameConfigState = new GameConfigState(); + gameConfigState.Set(_tableSheets.GameConfigSheet); + + var currency = Currency.Legacy("NCG", 2, null); + IAccount states = new Account(MockState.Empty) + .SetState(GoldCurrencyState.Address, new GoldCurrencyState(currency, 0).Serialize()) + .SetState(weekly.address, weekly.Serialize()) + .SetState(Addresses.GoldDistribution, new List()) + .SetState(gameConfigState.address, gameConfigState.Serialize()); + var action = new RewardGold(); + + IAccount nextState = action.Execute( + new ActionContext() + { + BlockIndex = 42, + PreviousState = states, + Miner = default, + } + ); + + Assert.Equal(0 * currency, nextState.GetBalance(default, currency)); + } } } diff --git a/.Lib9c.Tests/Action/Scenario/AuraScenarioTest.cs b/.Lib9c.Tests/Action/Scenario/AuraScenarioTest.cs index 8acd074e2f1..86f14af051e 100644 --- a/.Lib9c.Tests/Action/Scenario/AuraScenarioTest.cs +++ b/.Lib9c.Tests/Action/Scenario/AuraScenarioTest.cs @@ -252,7 +252,7 @@ public void Arena() }); var avatarState = prevState.GetAvatarStateV2(avatarAddress); var enemyAvatarState = prevState.GetAvatarStateV2(enemyAvatarAddress); - var simulator = new ArenaSimulator(new TestRandom()); + var simulator = new ArenaSimulator(new TestRandom(), 10); var myArenaPlayerDigest = new ArenaPlayerDigest( avatarState, battle.equipments, @@ -276,7 +276,7 @@ public void Arena() foreach (var spawn in log.OfType()) { ArenaCharacter character = spawn.Character; - Assert.Equal(100, character.HIT); + Assert.Equal(400, character.HIT); Assert.Equal(11, character.CRI); } @@ -366,7 +366,7 @@ private void Assert_Player(AvatarState avatarState, IAccount state, Address avat var row = _tableSheets.CharacterSheet[player.CharacterId]; Assert.Null(player.aura); Assert.NotNull(equippedPlayer.aura); - Assert.Equal(player.HIT + 10 + (int)(row.LvHIT * diffLevel), equippedPlayer.HIT); + Assert.Equal(player.HIT + 310 + (int)(row.LvHIT * diffLevel), equippedPlayer.HIT); Assert.Equal(player.CRI + 1, equippedPlayer.CRI); } diff --git a/.Lib9c.Tests/Action/Sell10Test.cs b/.Lib9c.Tests/Action/Sell10Test.cs index a52c45926e8..16819ff0466 100644 --- a/.Lib9c.Tests/Action/Sell10Test.cs +++ b/.Lib9c.Tests/Action/Sell10Test.cs @@ -413,46 +413,5 @@ public void Execute_Throw_DuplicateOrderIdException() RandomSeed = 0, })); } - - [Fact] - public void Rehearsal() - { - Guid tradableId = Guid.NewGuid(); - Guid orderId = Guid.NewGuid(); - var action = new Sell10 - { - sellerAvatarAddress = _avatarAddress, - tradableId = tradableId, - count = 1, - price = _currency * ProductPrice, - itemSubType = ItemSubType.Weapon, - orderId = orderId, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.GetItemAddress(tradableId), - Order.DeriveAddress(orderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, orderId), - OrderDigestListState.DeriveAddress(_avatarAddress), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/Sell11Test.cs b/.Lib9c.Tests/Action/Sell11Test.cs index b6dba510386..3fa8503515b 100644 --- a/.Lib9c.Tests/Action/Sell11Test.cs +++ b/.Lib9c.Tests/Action/Sell11Test.cs @@ -461,46 +461,5 @@ public void Execute_Throw_DuplicateOrderIdException() RandomSeed = 0, })); } - - [Fact] - public void Rehearsal() - { - Guid tradableId = Guid.NewGuid(); - Guid orderId = Guid.NewGuid(); - var action = new Sell11 - { - sellerAvatarAddress = _avatarAddress, - tradableId = tradableId, - count = 1, - price = _currency * ProductPrice, - itemSubType = ItemSubType.Weapon, - orderId = orderId, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.GetItemAddress(tradableId), - Order.DeriveAddress(orderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, orderId), - OrderDigestListState.DeriveAddress(_avatarAddress), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/Sell7Test.cs b/.Lib9c.Tests/Action/Sell7Test.cs index 35dc1b1eb55..8db0beadec7 100644 --- a/.Lib9c.Tests/Action/Sell7Test.cs +++ b/.Lib9c.Tests/Action/Sell7Test.cs @@ -436,46 +436,5 @@ public void Execute_Throw_DuplicateOrderIdException() RandomSeed = 0, })); } - - [Fact] - public void Rehearsal() - { - Guid tradableId = Guid.NewGuid(); - Guid orderId = Guid.NewGuid(); - var action = new Sell7 - { - sellerAvatarAddress = _avatarAddress, - tradableId = tradableId, - count = 1, - price = _currency * ProductPrice, - itemSubType = ItemSubType.Weapon, - orderId = orderId, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.GetItemAddress(tradableId), - Order.DeriveAddress(orderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, orderId), - OrderDigestListState.DeriveAddress(_avatarAddress), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/Sell8Test.cs b/.Lib9c.Tests/Action/Sell8Test.cs index 3d7b876a14f..04299495e2c 100644 --- a/.Lib9c.Tests/Action/Sell8Test.cs +++ b/.Lib9c.Tests/Action/Sell8Test.cs @@ -429,46 +429,5 @@ public void Execute_Throw_DuplicateOrderIdException() RandomSeed = 0, })); } - - [Fact] - public void Rehearsal() - { - Guid tradableId = Guid.NewGuid(); - Guid orderId = Guid.NewGuid(); - var action = new Sell8 - { - sellerAvatarAddress = _avatarAddress, - tradableId = tradableId, - count = 1, - price = _currency * ProductPrice, - itemSubType = ItemSubType.Weapon, - orderId = orderId, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.GetItemAddress(tradableId), - Order.DeriveAddress(orderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, orderId), - OrderDigestListState.DeriveAddress(_avatarAddress), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/Sell9Test.cs b/.Lib9c.Tests/Action/Sell9Test.cs index ffd3f315e66..295387c8d3a 100644 --- a/.Lib9c.Tests/Action/Sell9Test.cs +++ b/.Lib9c.Tests/Action/Sell9Test.cs @@ -413,46 +413,5 @@ public void Execute_Throw_DuplicateOrderIdException() RandomSeed = 0, })); } - - [Fact] - public void Rehearsal() - { - Guid tradableId = Guid.NewGuid(); - Guid orderId = Guid.NewGuid(); - var action = new Sell9 - { - sellerAvatarAddress = _avatarAddress, - tradableId = tradableId, - count = 1, - price = _currency * ProductPrice, - itemSubType = ItemSubType.Weapon, - orderId = orderId, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.GetItemAddress(tradableId), - Order.DeriveAddress(orderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, orderId), - OrderDigestListState.DeriveAddress(_avatarAddress), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/SellCancellation7Test.cs b/.Lib9c.Tests/Action/SellCancellation7Test.cs index bc8ea89e6ad..e7ff546836d 100644 --- a/.Lib9c.Tests/Action/SellCancellation7Test.cs +++ b/.Lib9c.Tests/Action/SellCancellation7Test.cs @@ -452,41 +452,6 @@ public void Execute_Throw_InvalidAddressException(bool useAgentAddress, bool use ); } - [Fact] - public void Rehearsal() - { - var action = new SellCancellation7() - { - sellerAvatarAddress = _avatarAddress, - orderId = default, - itemSubType = ItemSubType.Weapon, - tradableId = default, - }; - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, default(Guid)), - OrderDigestListState.DeriveAddress(_avatarAddress), - Addresses.GetItemAddress(default), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void PlainValue() { diff --git a/.Lib9c.Tests/Action/SellCancellation8Test.cs b/.Lib9c.Tests/Action/SellCancellation8Test.cs index ac2c9376976..f44991a04de 100644 --- a/.Lib9c.Tests/Action/SellCancellation8Test.cs +++ b/.Lib9c.Tests/Action/SellCancellation8Test.cs @@ -473,41 +473,6 @@ public void Execute_Throw_InvalidAddressException(bool useAgentAddress, bool use ); } - [Fact] - public void Rehearsal() - { - var action = new SellCancellation8() - { - sellerAvatarAddress = _avatarAddress, - orderId = default, - itemSubType = ItemSubType.Weapon, - tradableId = default, - }; - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, default(Guid)), - OrderDigestListState.DeriveAddress(_avatarAddress), - Addresses.GetItemAddress(default), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void PlainValue() { diff --git a/.Lib9c.Tests/Action/SellCancellationTest.cs b/.Lib9c.Tests/Action/SellCancellationTest.cs index 8d78836f141..97c76c61705 100644 --- a/.Lib9c.Tests/Action/SellCancellationTest.cs +++ b/.Lib9c.Tests/Action/SellCancellationTest.cs @@ -508,41 +508,6 @@ public void Execute_Throw_InvalidAddressException(bool useAgentAddress, bool use ); } - [Fact] - public void Rehearsal() - { - var action = new SellCancellation() - { - sellerAvatarAddress = _avatarAddress, - orderId = default, - itemSubType = ItemSubType.Weapon, - tradableId = default, - }; - - var updatedAddresses = new List
() - { - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, default(Guid)), - OrderDigestListState.DeriveAddress(_avatarAddress), - Addresses.GetItemAddress(default), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } - [Fact] public void PlainValue() { diff --git a/.Lib9c.Tests/Action/SellTest.cs b/.Lib9c.Tests/Action/SellTest.cs index 7aaea10de4b..22255b68fd1 100644 --- a/.Lib9c.Tests/Action/SellTest.cs +++ b/.Lib9c.Tests/Action/SellTest.cs @@ -460,46 +460,5 @@ public void Execute_Throw_DuplicateOrderIdException() RandomSeed = 0, })); } - - [Fact] - public void Rehearsal() - { - Guid tradableId = Guid.NewGuid(); - Guid orderId = Guid.NewGuid(); - var action = new Sell - { - sellerAvatarAddress = _avatarAddress, - tradableId = tradableId, - count = 1, - price = _currency * ProductPrice, - itemSubType = ItemSubType.Weapon, - orderId = orderId, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.GetItemAddress(tradableId), - Order.DeriveAddress(orderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, orderId), - OrderDigestListState.DeriveAddress(_avatarAddress), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/Summon/AuraSummonTest.cs b/.Lib9c.Tests/Action/Summon/AuraSummonTest.cs index e06648fe289..547aa528adf 100644 --- a/.Lib9c.Tests/Action/Summon/AuraSummonTest.cs +++ b/.Lib9c.Tests/Action/Summon/AuraSummonTest.cs @@ -4,6 +4,7 @@ namespace Lib9c.Tests.Action.Summon using System.Collections.Generic; using System.Data; using System.Linq; + using Lib9c.Tests.Fixtures.TableCSV.Summon; using Libplanet.Action.State; using Libplanet.Crypto; using Libplanet.Types.Assets; @@ -12,16 +13,17 @@ namespace Lib9c.Tests.Action.Summon using Nekoyume.Action.Exceptions; using Nekoyume.Model.Item; using Nekoyume.Model.State; + using Nekoyume.TableData.Summon; using Xunit; using static SerializeKeys; public class AuraSummonTest { - private readonly TableSheets _tableSheets; private readonly Address _agentAddress; private readonly Address _avatarAddress; private readonly AvatarState _avatarState; private readonly Currency _currency; + private TableSheets _tableSheets; private IAccount _initialState; public AuraSummonTest() @@ -79,15 +81,53 @@ public AuraSummonTest() } } + [Theory] + [InlineData("V1", 10001)] + [InlineData("V1", 10002)] + [InlineData("V2", 10001)] + [InlineData("V2", 10002)] + public void CumulativeRatio(string version, int groupId) + { + var sheets = TableSheetsImporter.ImportSheets(); + if (version == "V1") + { + sheets[nameof(SummonSheet)] = SummonSheetFixtures.V1; + } + else + { + sheets[nameof(SummonSheet)] = SummonSheetFixtures.V2; + } + + _tableSheets = new TableSheets(sheets); + var sheet = _tableSheets.SummonSheet; + + var targetRow = sheet.OrderedList.First(r => r.GroupId == groupId); + + for (var i = 1; i <= SummonSheet.Row.MaxRecipeCount; i++) + { + var sum = 0; + for (var j = 0; j < i; j++) + { + if (j < targetRow.Recipes.Count) + { + sum += targetRow.Recipes[j].Item2; + } + } + + Assert.Equal(sum, targetRow.CumulativeRatio(i)); + } + } + [Theory] // success first group - [InlineData(10001, 1, 800201, 1, 1, new[] { 10610000 }, null)] - [InlineData(10001, 2, 800201, 2, 54, new[] { 10620000, 10630000 }, null)] + [InlineData("V1", 10001, 1, 800201, 1, 1, new[] { 10610000 }, null)] + [InlineData("V1", 10001, 2, 800201, 2, 54, new[] { 10620000, 10630000 }, null)] // success second group - [InlineData(10002, 1, 600201, 1, 1, new[] { 10620001 }, null)] - [InlineData(10002, 2, 600201, 2, 4, new[] { 10620001, 10630001 }, null)] + [InlineData("V1", 10002, 1, 600201, 1, 1, new[] { 10620001 }, null)] + [InlineData("V1", 10002, 2, 600201, 2, 4, new[] { 10620001, 10630001 }, null)] // Nine plus zero [InlineData( + "V1", 10001, 9, 800201, @@ -97,6 +137,7 @@ public AuraSummonTest() null )] [InlineData( + "V1", 10002, 9, 600201, @@ -107,6 +148,7 @@ public AuraSummonTest() )] // Ten plus one [InlineData( + "V1", 10001, 10, 800201, @@ -116,6 +158,7 @@ public AuraSummonTest() null )] [InlineData( + "V1", 10002, 10, 600201, @@ -125,13 +168,16 @@ public AuraSummonTest() null )] // fail by invalid group - [InlineData(100003, 1, null, 0, 0, new int[] { }, typeof(RowNotInTableException))] + [InlineData("V1", 100003, 1, null, 0, 0, new int[] { }, typeof(RowNotInTableException))] // fail by not enough material - [InlineData(10001, 1, 800201, 0, 0, new int[] { }, typeof(NotEnoughMaterialException))] - [InlineData(10001, 2, 800201, 0, 0, new int[] { }, typeof(NotEnoughMaterialException))] + [InlineData("V1", 10001, 1, 800201, 0, 0, new int[] { }, typeof(NotEnoughMaterialException))] + [InlineData("V1", 10001, 2, 800201, 0, 0, new int[] { }, typeof(NotEnoughMaterialException))] // Fail by exceeding summon limit - [InlineData(10001, 11, 800201, 22, 1, new int[] { }, typeof(InvalidSummonCountException))] + [InlineData("V1", 10001, 11, 800201, 22, 1, new int[] { }, typeof(InvalidSummonCountException))] + // 15 recipes + [InlineData("V2", 10002, 1, 600201, 1, 5341, new[] { 10650006 }, null)] public void Execute( + string version, int groupId, int summonCount, int? materialId, @@ -143,6 +189,10 @@ Type expectedExc { var random = new TestRandom(seed); var state = _initialState; + state = state.SetState( + Addresses.TableSheet.Derive(nameof(SummonSheet)), + version == "V1" ? SummonSheetFixtures.V1.Serialize() : SummonSheetFixtures.V2.Serialize() + ); if (!(materialId is null)) { diff --git a/.Lib9c.Tests/Action/TransferAsset2Test.cs b/.Lib9c.Tests/Action/TransferAsset2Test.cs index b72d090c978..e3257f6ce7d 100644 --- a/.Lib9c.Tests/Action/TransferAsset2Test.cs +++ b/.Lib9c.Tests/Action/TransferAsset2Test.cs @@ -254,35 +254,6 @@ public void ExecuteWithUnactivatedRecipient() Assert.Equal(_recipient, ex.Recipient); } - [Fact] - public void Rehearsal() - { - var action = new TransferAsset2( - sender: _sender, - recipient: _recipient, - amount: _currency * 100 - ); - - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - _sender, - _recipient - ), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item1).ToImmutableHashSet() - ); - Assert.Equal( - new[] { _currency }, - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item2).ToImmutableHashSet()); - } - [Theory] [InlineData(null)] [InlineData("Nine Chronicles")] diff --git a/.Lib9c.Tests/Action/TransferAsset3Test.cs b/.Lib9c.Tests/Action/TransferAsset3Test.cs index 8ee2eed3048..00e49e17d9e 100644 --- a/.Lib9c.Tests/Action/TransferAsset3Test.cs +++ b/.Lib9c.Tests/Action/TransferAsset3Test.cs @@ -277,35 +277,6 @@ public void ExecuteWithUnactivatedRecipient() Assert.Equal(_recipient, ex.Recipient); } - [Fact] - public void Rehearsal() - { - var action = new TransferAsset3( - sender: _sender, - recipient: _recipient, - amount: _currency * 100 - ); - - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - _sender, - _recipient - ), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item1).ToImmutableHashSet() - ); - Assert.Equal( - new[] { _currency }, - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item2).ToImmutableHashSet()); - } - [Theory] [InlineData(null)] [InlineData("Nine Chronicles")] diff --git a/.Lib9c.Tests/Action/TransferAsset4Test.cs b/.Lib9c.Tests/Action/TransferAsset4Test.cs index 528bac61bc5..089638deef6 100644 --- a/.Lib9c.Tests/Action/TransferAsset4Test.cs +++ b/.Lib9c.Tests/Action/TransferAsset4Test.cs @@ -197,36 +197,6 @@ public void Execute_Throw_InvalidTransferMinterException(bool minterAsSender) Assert.Equal(_recipient, ex.Recipient); } - [Fact] - public void Rehearsal() - { - var action = new TransferAsset4( - sender: _sender, - recipient: _recipient, - amount: _currency * 100 - ); - - var context = new ActionContext(); - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty).MintAsset(context, _sender, Currencies.Mead * 1), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - _sender, - _recipient - ), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item1).ToImmutableHashSet() - ); - Assert.Equal( - new[] { _currency, Currencies.Mead, }.ToImmutableHashSet(), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item2).ToImmutableHashSet()); - } - [Theory] [InlineData(null)] [InlineData("Nine Chronicles")] diff --git a/.Lib9c.Tests/Action/TransferAssetTest.cs b/.Lib9c.Tests/Action/TransferAssetTest.cs index b2a2a52f879..9b8ed9a1f17 100644 --- a/.Lib9c.Tests/Action/TransferAssetTest.cs +++ b/.Lib9c.Tests/Action/TransferAssetTest.cs @@ -200,36 +200,6 @@ public void Execute_Throw_InvalidTransferMinterException(bool minterAsSender) Assert.Equal(_recipient, ex.Recipient); } - [Fact] - public void Rehearsal() - { - var action = new TransferAsset( - sender: _sender, - recipient: _recipient, - amount: _currency * 100 - ); - - var context = new ActionContext(); - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty).MintAsset(context, _sender, Currencies.Mead * 1), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - _sender, - _recipient - ), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item1).ToImmutableHashSet() - ); - Assert.Equal( - new[] { _currency, Currencies.Mead, }.ToImmutableHashSet(), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item2).ToImmutableHashSet()); - } - [Theory] [InlineData(null)] [InlineData("Nine Chronicles")] diff --git a/.Lib9c.Tests/Action/TransferAssetTest0.cs b/.Lib9c.Tests/Action/TransferAssetTest0.cs index 049a7b56829..791fd24ff2b 100644 --- a/.Lib9c.Tests/Action/TransferAssetTest0.cs +++ b/.Lib9c.Tests/Action/TransferAssetTest0.cs @@ -223,35 +223,6 @@ public void ExecuteWithMinterAsRecipient() Assert.Equal(_recipient, ex.Recipient); } - [Fact] - public void Rehearsal() - { - var action = new TransferAsset0( - sender: _sender, - recipient: _recipient, - amount: _currency * 100 - ); - - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - _sender, - _recipient - ), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item1).ToImmutableHashSet() - ); - Assert.Equal( - new[] { _currency }, - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item2).ToImmutableHashSet()); - } - [Theory] [InlineData(null)] [InlineData("Nine Chronicles")] diff --git a/.Lib9c.Tests/Action/TransferAssets0Test.cs b/.Lib9c.Tests/Action/TransferAssets0Test.cs index 12b0268ed7f..66d9189372b 100644 --- a/.Lib9c.Tests/Action/TransferAssets0Test.cs +++ b/.Lib9c.Tests/Action/TransferAssets0Test.cs @@ -311,37 +311,6 @@ public void ExecuteWithUnactivatedRecipient() Assert.Equal(_recipient, ex.Recipient); } - [Fact] - public void Rehearsal() - { - var action = new TransferAssets0( - sender: _sender, - new List<(Address, FungibleAssetValue)> - { - (_recipient, _currency * 100), - } - ); - - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - _sender, - _recipient - ), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item1).ToImmutableHashSet() - ); - Assert.Equal( - new[] { _currency }, - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item2).ToImmutableHashSet()); - } - [Theory] [InlineData(null)] [InlineData("Nine Chronicles")] diff --git a/.Lib9c.Tests/Action/TransferAssets2Test.cs b/.Lib9c.Tests/Action/TransferAssets2Test.cs index f8a55370be9..0573f405012 100644 --- a/.Lib9c.Tests/Action/TransferAssets2Test.cs +++ b/.Lib9c.Tests/Action/TransferAssets2Test.cs @@ -221,37 +221,6 @@ public void Execute_Throw_InvalidTransferMinterException() Assert.Equal(_recipient, ex.Recipient); } - [Fact] - public void Rehearsal() - { - var action = new TransferAssets2( - sender: _sender, - new List<(Address, FungibleAssetValue)> - { - (_recipient, _currency * 100), - } - ); - - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - _sender, - _recipient - ), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item1).ToImmutableHashSet() - ); - Assert.Equal( - new[] { _currency }, - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item2).ToImmutableHashSet()); - } - [Theory] [InlineData(null)] [InlineData("Nine Chronicles")] diff --git a/.Lib9c.Tests/Action/TransferAssetsTest.cs b/.Lib9c.Tests/Action/TransferAssetsTest.cs index 9387ea87be6..89757df3dea 100644 --- a/.Lib9c.Tests/Action/TransferAssetsTest.cs +++ b/.Lib9c.Tests/Action/TransferAssetsTest.cs @@ -223,37 +223,6 @@ public void Execute_Throw_InvalidTransferMinterException() Assert.Equal(_recipient, ex.Recipient); } - [Fact] - public void Rehearsal() - { - var action = new TransferAssets( - sender: _sender, - new List<(Address, FungibleAssetValue)> - { - (_recipient, _currency * 100), - } - ); - - IAccount nextState = action.Execute(new ActionContext() - { - PreviousState = new Account(MockState.Empty), - Signer = default, - Rehearsal = true, - BlockIndex = 1, - }); - - Assert.Equal( - ImmutableHashSet.Create( - _sender, - _recipient - ), - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item1).ToImmutableHashSet() - ); - Assert.Equal( - new[] { _currency }, - nextState.Delta.UpdatedFungibleAssets.Select(pair => pair.Item2).ToImmutableHashSet()); - } - [Theory] [InlineData(null)] [InlineData("Nine Chronicles")] diff --git a/.Lib9c.Tests/Action/UpdateSell0Test.cs b/.Lib9c.Tests/Action/UpdateSell0Test.cs index 56f4be7bafb..e3f2e647801 100644 --- a/.Lib9c.Tests/Action/UpdateSell0Test.cs +++ b/.Lib9c.Tests/Action/UpdateSell0Test.cs @@ -334,49 +334,5 @@ public void Execute_Throw_NotEnoughClearedStageLevelException() Signer = _agentAddress, })); } - - [Fact] - public void Rehearsal() - { - var tradableId = Guid.NewGuid(); - var orderId = Guid.NewGuid(); - var updateSellOrderId = Guid.NewGuid(); - var action = new UpdateSell0 - { - orderId = orderId, - updateSellOrderId = updateSellOrderId, - tradableId = tradableId, - sellerAvatarAddress = _avatarAddress, - itemSubType = ItemSubType.Weapon, - price = _currency * ProductPrice, - count = 1, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.GetItemAddress(tradableId), - Order.DeriveAddress(updateSellOrderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, orderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, updateSellOrderId), - OrderDigestListState.DeriveAddress(_avatarAddress), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/Action/UpdateSell2Test.cs b/.Lib9c.Tests/Action/UpdateSell2Test.cs index 6c4103521a9..d6161ae5e99 100644 --- a/.Lib9c.Tests/Action/UpdateSell2Test.cs +++ b/.Lib9c.Tests/Action/UpdateSell2Test.cs @@ -315,49 +315,5 @@ public void Execute_Throw_NotEnoughClearedStageLevelException() Signer = _agentAddress, })); } - - [Fact] - public void Rehearsal() - { - var tradableId = Guid.NewGuid(); - var orderId = Guid.NewGuid(); - var updateSellOrderId = Guid.NewGuid(); - var action = new UpdateSell2 - { - orderId = orderId, - updateSellOrderId = updateSellOrderId, - tradableId = tradableId, - sellerAvatarAddress = _avatarAddress, - itemSubType = ItemSubType.Weapon, - price = _currency * ProductPrice, - count = 1, - }; - - var updatedAddresses = new List
() - { - _agentAddress, - _avatarAddress, - _avatarAddress.Derive(LegacyInventoryKey), - _avatarAddress.Derive(LegacyWorldInformationKey), - _avatarAddress.Derive(LegacyQuestListKey), - Addresses.GetItemAddress(tradableId), - Order.DeriveAddress(updateSellOrderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, orderId), - ShardedShopStateV2.DeriveAddress(ItemSubType.Weapon, updateSellOrderId), - OrderDigestListState.DeriveAddress(_avatarAddress), - }; - - var state = new Account(MockState.Empty); - - var nextState = action.Execute(new ActionContext() - { - PreviousState = state, - Signer = _agentAddress, - BlockIndex = 0, - Rehearsal = true, - }); - - Assert.Equal(updatedAddresses.ToImmutableHashSet(), nextState.Delta.UpdatedAddresses); - } } } diff --git a/.Lib9c.Tests/CurrenciesTest.cs b/.Lib9c.Tests/CurrenciesTest.cs index 4ecd9902a6d..88adb36deb5 100644 --- a/.Lib9c.Tests/CurrenciesTest.cs +++ b/.Lib9c.Tests/CurrenciesTest.cs @@ -5,6 +5,7 @@ namespace Lib9c.Tests using System.Collections.Generic; using System.Linq; using System.Numerics; + using Libplanet.Crypto; using Libplanet.Types.Assets; using Nekoyume.TableData; using Xunit; @@ -200,5 +201,17 @@ public void GetSoulStones_With_Sheet_Throws_ArgumentNullException() { Assert.Throws(() => Currencies.GetSoulStones((PetSheet?)null)); } + + [Fact] + public void SelectRecipientAddress() + { + var agentAddress = new PrivateKey().ToAddress(); + var avatarAddress = new PrivateKey().ToAddress(); + Assert.Equal(agentAddress, Currencies.SelectRecipientAddress(Currencies.Crystal, agentAddress, avatarAddress)); + Assert.Equal(agentAddress, Currencies.SelectRecipientAddress(Currencies.Garage, agentAddress, avatarAddress)); + Assert.Equal(agentAddress, Currencies.SelectRecipientAddress(Currencies.Mead, agentAddress, avatarAddress)); + Assert.Equal(agentAddress, Currencies.SelectRecipientAddress(Currency.Legacy("NCG", decimalPlaces: 2, minter: new PrivateKey().ToAddress()), agentAddress, avatarAddress)); + Assert.Equal(avatarAddress, Currencies.SelectRecipientAddress(Currencies.DailyRewardRune, agentAddress, avatarAddress)); + } } } diff --git a/.Lib9c.Tests/Fixtures/TableCSV/Summon/SummonSheetFixtures.cs b/.Lib9c.Tests/Fixtures/TableCSV/Summon/SummonSheetFixtures.cs new file mode 100644 index 00000000000..0c9338e61dc --- /dev/null +++ b/.Lib9c.Tests/Fixtures/TableCSV/Summon/SummonSheetFixtures.cs @@ -0,0 +1,15 @@ +namespace Lib9c.Tests.Fixtures.TableCSV.Summon +{ + public class SummonSheetFixtures + { + public const string V1 = + @"groupID,cost_material,cost_material_count,cost_ncg,recipe1ID,recipe1ratio,recipe2ID,recipe2ratio,recipe3ID,recipe3ratio,recipe4ID,recipe4ratio,recipe5ID,recipe5ratio,recipe6ID,recipe6ratio +10001,800201,10,0,171,70,172,29,173,1,,,,,, +10002,600201,20,0,174,6500,175,2940,176,510,177,45,178,5,,"; + + public const string V2 = + @"groupID,cost_material,cost_material_count,cost_ncg,recipe1ID,recipe1ratio,recipe2ID,recipe2ratio,recipe3ID,recipe3ratio,recipe4ID,recipe4ratio,recipe5ID,recipe5ratio,recipe6ID,recipe6ratio,recipe7ID,recipe7ratio,recipe8ID,recipe8ratio,recipe9ID,recipe9ratio,recipe10ID,recipe10ratio,recipe11ID,recipe11ratio,recipe12ID,recipe12ratio,recipe13ID,recipe13ratio,recipe14ID,recipe14ratio,recipe15ID,recipe15ratio +10001,800201,10,0,171,70,172,29,173,1,,,,,,,,,,,,,,,,,,,,,,,, +10002,600201,20,0,174,6500,175,2940,176,510,177,45,178,5,179,6500,180,2940,181,510,182,45,183,5,184,6500,185,2940,186,510,187,45,188,5"; + } +} diff --git a/.Lib9c.Tests/Model/ArenaSimulatorTest.cs b/.Lib9c.Tests/Model/ArenaSimulatorTest.cs index 99c7a1e0b5f..84ed1a2627a 100644 --- a/.Lib9c.Tests/Model/ArenaSimulatorTest.cs +++ b/.Lib9c.Tests/Model/ArenaSimulatorTest.cs @@ -50,7 +50,7 @@ public ArenaSimulatorTest() [Fact] public void Simulate() { - var simulator = new ArenaSimulator(_random); + var simulator = new ArenaSimulator(_random, 10); var myDigest = new ArenaPlayerDigest(_avatarState1, _arenaAvatarState1); var enemyDigest = new ArenaPlayerDigest(_avatarState2, _arenaAvatarState2); var arenaSheets = _tableSheets.GetArenaSimulatorSheets(); @@ -90,5 +90,35 @@ public void Simulate() Assert.False(deadCharacter.IsEnemy); } } + + [Theory] + [InlineData(10)] + [InlineData(5)] + [InlineData(null)] + public void HpIncreasingModifier(int? modifier) + { + var simulator = modifier.HasValue ? new ArenaSimulator(_random, modifier.Value) : new ArenaSimulator(_random); + var myDigest = new ArenaPlayerDigest(_avatarState1, _arenaAvatarState1); + var enemyDigest = new ArenaPlayerDigest(_avatarState2, _arenaAvatarState2); + var arenaSheets = _tableSheets.GetArenaSimulatorSheets(); + var log = simulator.Simulate(myDigest, enemyDigest, arenaSheets); + var expectedHpModifier = modifier ?? 2; + + Assert.Equal(_random, simulator.Random); + Assert.Equal(expectedHpModifier, simulator.HpModifier); + + var turn = log.Events.OfType().Count(); + Assert.Equal(simulator.Turn, turn); + + var players = log.Events + .OfType() + .Select(p => p.Character) + .ToList(); + Assert.Equal(2, players.Count); + foreach (var player in players) + { + Assert.Equal(player.Stats.BaseHP * expectedHpModifier, player.CurrentHP); + } + } } } diff --git a/.Lib9c.Tests/Model/PlayerTest.cs b/.Lib9c.Tests/Model/PlayerTest.cs index ed7ad2c100e..f0d4ce02c93 100644 --- a/.Lib9c.Tests/Model/PlayerTest.cs +++ b/.Lib9c.Tests/Model/PlayerTest.cs @@ -305,21 +305,21 @@ public void GetExp() ); player.SetCostumeStat(_tableSheets.CostumeStatSheet); - Assert.Equal(600, player.HP); - Assert.Equal(600, player.CurrentHP); + Assert.Equal(27290, player.HP); + Assert.Equal(27290, player.CurrentHP); Assert.Equal(1, player.Level); player.CurrentHP -= 10; - Assert.Equal(590, player.CurrentHP); + Assert.Equal(27280, player.CurrentHP); var requiredExp = _tableSheets.CharacterLevelSheet[1].ExpNeed; player.GetExp2(requiredExp); Assert.Equal(2, player.Level); - Assert.Equal(612, player.HP); - Assert.Equal(590, player.CurrentHP); + Assert.Equal(27302, player.HP); + Assert.Equal(27280, player.CurrentHP); } [Theory] diff --git a/.Lib9c.Tests/Model/Skill/BuffFactoryTest.cs b/.Lib9c.Tests/Model/Skill/BuffFactoryTest.cs new file mode 100644 index 00000000000..59ad85b541f --- /dev/null +++ b/.Lib9c.Tests/Model/Skill/BuffFactoryTest.cs @@ -0,0 +1,92 @@ +namespace Lib9c.Tests.Model.Skill +{ + using System.Collections.Generic; + using Lib9c.Tests.Action; + using Nekoyume.Arena; + using Nekoyume.Model; + using Nekoyume.Model.Buff; + using Nekoyume.Model.Item; + using Nekoyume.Model.Skill; + using Nekoyume.Model.Stat; + using Nekoyume.Model.State; + using Xunit; + + public class BuffFactoryTest + { + private readonly TableSheets _tableSheets; + private readonly AvatarState _avatarState; + + public BuffFactoryTest() + { + _tableSheets = new TableSheets(TableSheetsImporter.ImportSheets()); + var gameConfigState = new GameConfigState(); + _avatarState = new AvatarState( + default, + default, + 0, + _tableSheets.GetAvatarSheets(), + gameConfigState, + default); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void GetBuffs_Arena(bool setExtraValueBuffBeforeGetBuffs) + { + // Aegis aura atk down + var skillId = 210012; + var skillRow = _tableSheets.SkillSheet[skillId]; + var skill = SkillFactory.GetForArena(skillRow, 10, 100, 0, StatType.NONE); + var simulator = new ArenaSimulator(new TestRandom(), 10); + var digest = new ArenaPlayerDigest( + _avatarState, + new List(), + new List(), + new List() + ); + var arenaSheets = _tableSheets.GetArenaSimulatorSheets(); + var challenger = new ArenaCharacter( + simulator, + digest, + arenaSheets, + simulator.HpModifier, + setExtraValueBuffBeforeGetBuffs: setExtraValueBuffBeforeGetBuffs); + var buffs = BuffFactory.GetBuffs( + challenger.Stats, + skill, + _tableSheets.SkillBuffSheet, + _tableSheets.StatBuffSheet, + _tableSheets.SkillActionBuffSheet, + _tableSheets.ActionBuffSheet, + setExtraValueBuffBeforeGetBuffs + ); + var buff = Assert.IsType(Assert.Single(buffs)); + Assert.Equal(buff.CustomField is not null, setExtraValueBuffBeforeGetBuffs); + } + + [Fact] + public void GetBuffs() + { + var player = new Player( + level: 1, + _tableSheets.CharacterSheet, + _tableSheets.CharacterLevelSheet, + _tableSheets.EquipmentItemSetEffectSheet); + // Aegis aura atk down + var skillId = 210012; + var skillRow = _tableSheets.SkillSheet[skillId]; + var skill = SkillFactory.Get(skillRow, 10, 100, 0, StatType.NONE); + var buffs = BuffFactory.GetBuffs( + player.Stats, + skill, + _tableSheets.SkillBuffSheet, + _tableSheets.StatBuffSheet, + _tableSheets.SkillActionBuffSheet, + _tableSheets.ActionBuffSheet + ); + var buff = Assert.IsType(Assert.Single(buffs)); + Assert.NotNull(buff.CustomField); + } + } +} diff --git a/.Lib9c.Tests/Model/State/GoldCurrencyStateTest.cs b/.Lib9c.Tests/Model/State/GoldCurrencyStateTest.cs index 1b5d90b8188..db03bbb89fc 100644 --- a/.Lib9c.Tests/Model/State/GoldCurrencyStateTest.cs +++ b/.Lib9c.Tests/Model/State/GoldCurrencyStateTest.cs @@ -22,6 +22,7 @@ public void Serialize() GoldCurrencyState deserialized = new GoldCurrencyState(serialized); Assert.Equal(currency.Hash, deserialized.Currency.Hash); + Assert.Equal(1000000000, deserialized.InitialSupply); } [Fact] @@ -42,5 +43,20 @@ public void SerializeWithDotnetAPI() Assert.Equal(currency.Hash, deserialized.Currency.Hash); } + + [Fact] + public void SerializeWithInitialSupply() + { + #pragma warning disable CS0618 + // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 + var currency = Currency.Legacy("NCG", 2, default(Address)); +#pragma warning restore CS0618 + var state = new GoldCurrencyState(currency, 0L); + var serialized = (Dictionary)state.Serialize(); + GoldCurrencyState deserialized = new GoldCurrencyState(serialized); + + Assert.Equal(currency.Hash, deserialized.Currency.Hash); + Assert.Equal(0, deserialized.InitialSupply); + } } } diff --git a/.Lib9c.Tests/Policy/BlockPolicySourceTest.cs b/.Lib9c.Tests/Policy/BlockPolicySourceTest.cs new file mode 100644 index 00000000000..e9e039ba630 --- /dev/null +++ b/.Lib9c.Tests/Policy/BlockPolicySourceTest.cs @@ -0,0 +1,85 @@ +namespace Lib9c.Tests.Policy +{ + using Bencodex.Types; + using Libplanet.Action; + using Libplanet.Action.Loader; + using Libplanet.Action.State; + using Libplanet.Crypto; + using Libplanet.Types.Blocks; + using Libplanet.Types.Tx; + using Nekoyume; + using Nekoyume.Action; + using Nekoyume.Action.Loader; + using Nekoyume.Blockchain.Policy; + using Xunit; + + public class BlockPolicySourceTest + { + private static readonly BlockHash OdinGenesisHash = BlockHash.FromString( + "4582250d0da33b06779a8475d283d5dd210c683b9b999d74d03fac4f58fa6bce" + ); + + private static readonly BlockHash HeimdallGenesisHash = BlockHash.FromString( + "ade4c29773fe83c1a51da6a667a5a26f08848155674637d43fe636b94a320514" + ); + + [Fact] + public void IsObsolete() + { + var transferAsset0 = new TransferAsset0(default, default, Currencies.Crystal * 0); + var odinTx = Transaction.Create( + 0, + new PrivateKey(), + OdinGenesisHash, + new[] { transferAsset0.PlainValue } + ); + var heimdallTx = Transaction.Create( + 0, + new PrivateKey(), + HeimdallGenesisHash, + new[] { transferAsset0.PlainValue } + ); + var ncActionLoader = new NCActionLoader(); + + Assert.False(BlockPolicySource.IsObsolete(odinTx, ncActionLoader, 1)); + Assert.True(BlockPolicySource.IsObsolete(odinTx, ncActionLoader, 7_000_700)); + Assert.True(BlockPolicySource.IsObsolete(heimdallTx, ncActionLoader, 1)); + + var odinTx2 = Transaction.Create( + 0, + new PrivateKey(), + OdinGenesisHash, + new[] { Dictionary.Empty } + ); + var heimdallTx2 = Transaction.Create( + 0, + new PrivateKey(), + HeimdallGenesisHash, + new[] { Dictionary.Empty } + ); + var newActionLoader = new SingleActionLoader(typeof(NewAction)); + + Assert.False(BlockPolicySource.IsObsolete(odinTx2, newActionLoader, 1)); + Assert.False(BlockPolicySource.IsObsolete(odinTx2, newActionLoader, 50)); + Assert.True(BlockPolicySource.IsObsolete(odinTx2, newActionLoader, 103)); // Due to +2 offset for odin bug + Assert.False(BlockPolicySource.IsObsolete(heimdallTx2, newActionLoader, 1)); + Assert.True(BlockPolicySource.IsObsolete(heimdallTx2, newActionLoader, 51)); + } + + [ActionObsolete(Planet.Odin, 100)] + [ActionObsolete(Planet.Heimdall, 50)] + private class NewAction : IAction + { + public IValue PlainValue => (Bencodex.Types.Integer)42; + + public IAccount Execute(IActionContext context) + { + throw new System.NotImplementedException(); + } + + public void LoadPlainValue(IValue plainValue) + { + } + } + } +} diff --git a/Lib9c.Abstractions/IBulkUnloadFromGaragesV1.cs b/Lib9c.Abstractions/IBulkUnloadFromGaragesV1.cs new file mode 100644 index 00000000000..d0cdb5c9b78 --- /dev/null +++ b/Lib9c.Abstractions/IBulkUnloadFromGaragesV1.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using Libplanet.Common; +using Libplanet.Crypto; +using Libplanet.Types.Assets; + +namespace Lib9c.Abstractions +{ + public interface IBulkUnloadFromGaragesV1 + { + public IReadOnlyList<( + Address recipientAvatarAddress, + IOrderedEnumerable<(Address balanceAddress, FungibleAssetValue value)>? + fungibleAssetValues, + IOrderedEnumerable<(HashDigest fungibleId, int count)>? fungibleIdAndCounts, + string? memo)> UnloadData { get; } + } +} diff --git a/Lib9c.DevExtensions/Action/Craft/UnlockCraftAction.cs b/Lib9c.DevExtensions/Action/Craft/UnlockCraftAction.cs index 8adf7f651ab..9e37655d7a2 100644 --- a/Lib9c.DevExtensions/Action/Craft/UnlockCraftAction.cs +++ b/Lib9c.DevExtensions/Action/Craft/UnlockCraftAction.cs @@ -26,11 +26,6 @@ public class UnlockCraftAction : GameAction public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; int targetStage; diff --git a/Lib9c.DevExtensions/Action/Craft/UnlockRecipe.cs b/Lib9c.DevExtensions/Action/Craft/UnlockRecipe.cs index e02549225d4..b00bb21735c 100644 --- a/Lib9c.DevExtensions/Action/Craft/UnlockRecipe.cs +++ b/Lib9c.DevExtensions/Action/Craft/UnlockRecipe.cs @@ -21,11 +21,6 @@ public class UnlockRecipe : GameAction public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; var recipeIdList = List.Empty; for (var i = 1; i <= TargetStage; i++) diff --git a/Lib9c.DevExtensions/Action/CreateArenaDummy.cs b/Lib9c.DevExtensions/Action/CreateArenaDummy.cs index ea46bcccaf4..ef74b1a7835 100644 --- a/Lib9c.DevExtensions/Action/CreateArenaDummy.cs +++ b/Lib9c.DevExtensions/Action/CreateArenaDummy.cs @@ -57,10 +57,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } for (var i = 0; i < accountCount; i++) { diff --git a/Lib9c.DevExtensions/Action/CreateOrReplaceAvatar.cs b/Lib9c.DevExtensions/Action/CreateOrReplaceAvatar.cs index 40036f080ac..0b6e8df3c93 100644 --- a/Lib9c.DevExtensions/Action/CreateOrReplaceAvatar.cs +++ b/Lib9c.DevExtensions/Action/CreateOrReplaceAvatar.cs @@ -367,11 +367,6 @@ public CreateOrReplaceAvatar( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var random = context.GetRandom(); return Execute( context.PreviousState, diff --git a/Lib9c.DevExtensions/Action/CreateTestbed.cs b/Lib9c.DevExtensions/Action/CreateTestbed.cs index 36b95400216..da77b7f9422 100644 --- a/Lib9c.DevExtensions/Action/CreateTestbed.cs +++ b/Lib9c.DevExtensions/Action/CreateTestbed.cs @@ -94,43 +94,6 @@ public override IAccount Execute(IActionContext context) var questListAddress = avatarAddress.Derive(LegacyQuestListKey); var orderReceiptAddress = OrderDigestListState.DeriveAddress(avatarAddress); - if (context.Rehearsal) - { - states = states.SetState(agentAddress, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format(CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, i)); - states = states.SetState(slotAddress, MarkChanged); - } - - states = states.SetState(avatarAddress, MarkChanged) - .SetState(Addresses.Ranking, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged); - - for (var i = 0; i < sellData.Items.Length; i++) - { - var itemAddress = Addresses.GetItemAddress(addedItemInfos[i].TradableId); - var orderAddress = Order.DeriveAddress(addedItemInfos[i].OrderId); - var shopAddress = ShardedShopStateV2.DeriveAddress( - sellData.Items[i].ItemSubType, - addedItemInfos[i].OrderId); - - states = states.SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .MarkBalanceChanged( - context, GoldCurrencyMock, agentAddress, GoldCurrencyState.Address) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(orderAddress, MarkChanged) - .SetState(shopAddress, MarkChanged); - } - return states; - } - // Create Agent and avatar var existingAgentState = states.GetAgentState(agentAddress); var agentState = existingAgentState ?? new AgentState(agentAddress); diff --git a/Lib9c.DevExtensions/Action/FaucetCurrency.cs b/Lib9c.DevExtensions/Action/FaucetCurrency.cs index f3fe300fa55..06331a99831 100644 --- a/Lib9c.DevExtensions/Action/FaucetCurrency.cs +++ b/Lib9c.DevExtensions/Action/FaucetCurrency.cs @@ -23,11 +23,6 @@ public class FaucetCurrency : GameAction, IFaucetCurrency public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; if (FaucetNcg > 0) { diff --git a/Lib9c.DevExtensions/Action/FaucetRune.cs b/Lib9c.DevExtensions/Action/FaucetRune.cs index c913d0d38f7..ad90cf1331a 100644 --- a/Lib9c.DevExtensions/Action/FaucetRune.cs +++ b/Lib9c.DevExtensions/Action/FaucetRune.cs @@ -25,11 +25,6 @@ public class FaucetRune : GameAction, IFaucetRune public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; if (!(FaucetRuneInfos is null)) { diff --git a/Lib9c.DevExtensions/Action/ManipulateState.cs b/Lib9c.DevExtensions/Action/ManipulateState.cs index b746bf4ccf3..5388497127e 100644 --- a/Lib9c.DevExtensions/Action/ManipulateState.cs +++ b/Lib9c.DevExtensions/Action/ManipulateState.cs @@ -47,11 +47,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - return Execute(context, context.PreviousState, StateList, BalanceList); } diff --git a/Lib9c.DevExtensions/Action/Stage/ClearStage.cs b/Lib9c.DevExtensions/Action/Stage/ClearStage.cs index 62d68b23656..41b8f7dfc51 100644 --- a/Lib9c.DevExtensions/Action/Stage/ClearStage.cs +++ b/Lib9c.DevExtensions/Action/Stage/ClearStage.cs @@ -23,11 +23,6 @@ public class ClearStage : GameAction public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; var worldInformation = new WorldInformation( context.BlockIndex, diff --git a/Lib9c.Policy/Policy/BlockPolicySource.Utils.cs b/Lib9c.Policy/Policy/BlockPolicySource.Utils.cs index a39e43934f5..c48e4151dc9 100644 --- a/Lib9c.Policy/Policy/BlockPolicySource.Utils.cs +++ b/Lib9c.Policy/Policy/BlockPolicySource.Utils.cs @@ -46,16 +46,23 @@ long blockIndex } else { + Planet? planet = transaction.DeterminePlanet(); try { - // Comparison with ObsoleteIndex + 2 is intended to have backward - // compatibility with a bugged original implementation. return rawActions .Select(rawAction => actionLoader.LoadAction(blockIndex, rawAction)) .Select(action => action.GetType()) - .Any(actionType => - actionType.GetCustomAttribute(false) is { } attribute && - attribute.ObsoleteIndex + 2 <= blockIndex); + .Any(t => + { + if (planet is { } planetNotNull) + { + return t.GetCustomAttributes(false) + .IsObsolete(planetNotNull, blockIndex); + } + + // Exempt obsoleting check against unknown planet + return false; + }); } catch (Exception) { diff --git a/Lib9c.Policy/Policy/BlockPolicySource.cs b/Lib9c.Policy/Policy/BlockPolicySource.cs index 49d105b4b24..28df6ce2ec4 100644 --- a/Lib9c.Policy/Policy/BlockPolicySource.cs +++ b/Lib9c.Policy/Policy/BlockPolicySource.cs @@ -30,7 +30,7 @@ namespace Nekoyume.Blockchain.Policy { public partial class BlockPolicySource { - public const int MaxTransactionsPerBlock = 100; + public const int MaxTransactionsPerBlock = 200; public static readonly TimeSpan BlockInterval = TimeSpan.FromSeconds(8); diff --git a/Lib9c.Utils/BlockHelper.cs b/Lib9c.Utils/BlockHelper.cs index fca6e936f9e..4a3a80333bc 100644 --- a/Lib9c.Utils/BlockHelper.cs +++ b/Lib9c.Utils/BlockHelper.cs @@ -19,7 +19,6 @@ using Nekoyume.Blockchain.Policy; using Nekoyume.Model.State; using Nekoyume.TableData; -using Serilog; namespace Nekoyume { @@ -29,15 +28,17 @@ public static Block ProposeGenesisBlock( IDictionary tableSheets, GoldDistribution[] goldDistributions, PendingActivationState[] pendingActivationStates, - AdminState adminState = null, - AuthorizedMinersState authorizedMinersState = null, - IImmutableSet
activatedAccounts = null, - Dictionary initialValidators = null, + AdminState? adminState = null, + AuthorizedMinersState? authorizedMinersState = null, + IImmutableSet
? activatedAccounts = null, + Dictionary? initialValidators = null, bool isActivateAdminAddress = false, - IEnumerable credits = null, - PrivateKey privateKey = null, + IEnumerable? credits = null, + PrivateKey? privateKey = null, DateTimeOffset? timestamp = null, - IEnumerable actionBases = null + IEnumerable? actionBases = null, + Currency? goldCurrency = null, + ISet
? assetMinters = null ) { if (!tableSheets.TryGetValue(nameof(GameConfigSheet), out var csv)) @@ -48,18 +49,14 @@ public static Block ProposeGenesisBlock( var redeemCodeListSheet = new RedeemCodeListSheet(); redeemCodeListSheet.Set(tableSheets[nameof(RedeemCodeListSheet)]); - if (privateKey is null) - { - privateKey = new PrivateKey(); - } - + privateKey ??= new PrivateKey(); initialValidators ??= new Dictionary(); - + activatedAccounts ??= ImmutableHashSet
.Empty; #pragma warning disable CS0618 // Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319 - var ncg = Currency.Legacy("NCG", 2, privateKey.ToAddress()); + goldCurrency ??= Currency.Legacy("NCG", 2, privateKey.ToAddress()); #pragma warning restore CS0618 - activatedAccounts = activatedAccounts ?? ImmutableHashSet
.Empty; + var initialStatesAction = new InitializeStates ( rankingState: new RankingState0(), @@ -69,14 +66,15 @@ public static Block ProposeGenesisBlock( redeemCodeState: new RedeemCodeState(redeemCodeListSheet), adminAddressState: adminState, activatedAccountsState: new ActivatedAccountsState( - isActivateAdminAddress && !(adminState is null) + isActivateAdminAddress && !(adminState is null) // Can't use 'not pattern' due to Unity ? activatedAccounts.Add(adminState.AdminAddress) : activatedAccounts), - goldCurrencyState: new GoldCurrencyState(ncg), + goldCurrencyState: new GoldCurrencyState(goldCurrency.Value), goldDistributions: goldDistributions, pendingActivationStates: pendingActivationStates, authorizedMinersState: authorizedMinersState, - creditsState: credits is null ? null : new CreditsState(credits) + creditsState: credits is null ? null : new CreditsState(credits), + assetMinters: assetMinters ); List actions = new List { diff --git a/Lib9c/Action/AccountStateDeltaExtensions.cs b/Lib9c/Action/AccountStateDeltaExtensions.cs index 3d1b9c7be7b..a60aff3966b 100644 --- a/Lib9c/Action/AccountStateDeltaExtensions.cs +++ b/Lib9c/Action/AccountStateDeltaExtensions.cs @@ -19,31 +19,6 @@ namespace Nekoyume.Action { public static class AccountStateDeltaExtensions { - public static IAccount MarkBalanceChanged( - this IAccount states, - IActionContext context, - Currency currency, - params Address[] accounts - ) - { - if (accounts.Length == 1) - { - return states.MintAsset(context, accounts[0], currency * 1); - } - else if (accounts.Length < 1) - { - return states; - } - - for (int i = 1; i < accounts.Length; i++) - { - states = states.TransferAsset(context, accounts[i - 1], accounts[i], currency * 1, true); - } - - return states; - } - - public static IAccount SetWorldBossKillReward( this IAccount states, IActionContext context, @@ -99,15 +74,9 @@ public static IAccount SetWorldBossKillReward( public static IAccount SetCouponWallet( this IAccount states, Address agentAddress, - IImmutableDictionary couponWallet, - bool rehearsal = false) + IImmutableDictionary couponWallet) { Address walletAddress = agentAddress.Derive(CouponWalletKey); - if (rehearsal) - { - return states.SetState(walletAddress, ActionBase.MarkChanged); - } - IValue serializedWallet = new Bencodex.Types.List( couponWallet.Values.OrderBy(c => c.Id).Select(v => v.Serialize()) ); diff --git a/Lib9c/Action/ActionBase.cs b/Lib9c/Action/ActionBase.cs index 2c7a6206e31..abb671d5ae0 100644 --- a/Lib9c/Action/ActionBase.cs +++ b/Lib9c/Action/ActionBase.cs @@ -22,8 +22,6 @@ namespace Nekoyume.Action [Serializable] public abstract class ActionBase : IAction { - public static readonly IValue MarkChanged = Null.Value; - // FIXME GoldCurrencyState 에 정의된 것과 다른데 괜찮을지 점검해봐야 합니다. protected static readonly Currency GoldCurrencyMock = new Currency(); diff --git a/Lib9c/Action/ActionBaseExtensions.cs b/Lib9c/Action/ActionBaseExtensions.cs deleted file mode 100644 index 1eae92aaec9..00000000000 --- a/Lib9c/Action/ActionBaseExtensions.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Numerics; -using System.Security.Cryptography; -using Bencodex.Types; -using Libplanet.Action; -using Libplanet.Action.State; -using Libplanet.Common; -using Libplanet.Crypto; -using Libplanet.Store.Trie; -using Libplanet.Types.Assets; -using Libplanet.Types.Blocks; -using Libplanet.Types.Consensus; -using Libplanet.Types.Tx; - -namespace Nekoyume.Action -{ - public static class ActionBaseExtensions - { - public static IImmutableSet
CalculateUpdateAddresses(this IEnumerable actions) - { - IImmutableSet
addresses = ImmutableHashSet
.Empty; - IActionContext rehearsalContext = new RehearsalActionContext(); - - foreach (ActionBase action in actions) - { - try - { - IAccount nextStates = action.Execute(rehearsalContext); - addresses = addresses.Union(nextStates.Delta.UpdatedAddresses); - } - catch (NotSupportedException) - { - // Ignore updated addresses from incompatible actions - } - } - - return addresses; - } - - private class RehearsalActionContext : IActionContext - { - public BlockHash? GenesisHash => default; - - public Address Signer => default; - - public TxId? TxId => default; - - public Address Miner => default; - - public long BlockIndex => default; - - public int BlockProtocolVersion => default; - - public bool Rehearsal => true; - - public IAccount PreviousState => new AddressTraceStateDelta(); - - public int RandomSeed => default; - - public HashDigest? PreviousStateRootHash => default; - - public bool BlockAction => default; - - public void UseGas(long gas) - { - // pass - } - - public IRandom GetRandom() => null; - - public long GasUsed() => 0; - - public long GasLimit() => 0; - } - - private class AddressTraceStateDelta : IAccount - { - private AddressTraceDelta _delta; - - public AddressTraceStateDelta() - : this(new AddressTraceDelta()) - { - } - - public AddressTraceStateDelta(AddressTraceDelta delta) - { - _delta = delta; - } - - public ITrie Trie => throw new NotSupportedException(); - - public IAccountDelta Delta => _delta; - - public IImmutableSet
UpdatedAddresses => _delta.UpdatedAddresses; - - public IImmutableSet
StateUpdatedAddresses => _delta.StateUpdatedAddresses; - - public IImmutableSet<(Address, Currency)> UpdatedFungibleAssets => - Delta.UpdatedFungibleAssets; - - public IImmutableSet<(Address, Currency)> TotalUpdatedFungibleAssets => - throw new NotSupportedException(); - - public IImmutableSet UpdatedTotalSupplyCurrencies - => Delta.UpdatedTotalSupplyCurrencies; - - public IAccount BurnAsset(IActionContext context, Address owner, FungibleAssetValue value) - { - return new AddressTraceStateDelta( - new AddressTraceDelta(Delta.UpdatedAddresses.Union(new [] { owner }))); - } - - public FungibleAssetValue GetBalance(Address address, Currency currency) - { - throw new NotSupportedException(); - } - - public IValue GetState(Address address) - { - throw new NotSupportedException(); - } - - public IReadOnlyList GetStates(IReadOnlyList
addresses) - { - throw new NotSupportedException(); - } - - public FungibleAssetValue GetTotalSupply(Currency currency) - { - throw new NotSupportedException(); - } - - public IAccount MintAsset(IActionContext context, Address recipient, FungibleAssetValue value) - { - return new AddressTraceStateDelta( - new AddressTraceDelta(Delta.UpdatedAddresses.Union(new[] { recipient }))); - } - - public IAccount SetState(Address address, IValue state) - { - return new AddressTraceStateDelta( - new AddressTraceDelta(Delta.UpdatedAddresses.Union(new[] { address }))); - } - - public IAccount TransferAsset( - IActionContext context, - Address sender, - Address recipient, - FungibleAssetValue value, - bool allowNegativeBalance = false - ) - { - return new AddressTraceStateDelta( - new AddressTraceDelta(Delta.UpdatedAddresses.Union(new[] { sender, recipient }))); - } - - public ValidatorSet GetValidatorSet() => throw new NotSupportedException(); - - public IAccount SetValidator(Validator validator) - { - throw new NotSupportedException(); - } - - public class AddressTraceDelta : IAccountDelta - { - private IImmutableSet
_updatedAddresses; - - public AddressTraceDelta() - : this(ImmutableHashSet
.Empty) - { - } - - public AddressTraceDelta(IImmutableSet
updatedAddresses) - { - _updatedAddresses = updatedAddresses; - } - - public IImmutableSet
UpdatedAddresses => _updatedAddresses; - public IImmutableSet
StateUpdatedAddresses => _updatedAddresses; - public IImmutableDictionary States => throw new NotSupportedException(); - public IImmutableSet
FungibleUpdatedAddresses => _updatedAddresses; - public IImmutableSet<(Address, Currency)> UpdatedFungibleAssets => throw new NotSupportedException(); - public IImmutableDictionary<(Address, Currency), BigInteger> Fungibles => throw new NotSupportedException(); - public IImmutableSet UpdatedTotalSupplyCurrencies => throw new NotSupportedException(); - public IImmutableDictionary TotalSupplies => throw new NotSupportedException(); - public ValidatorSet ValidatorSet => throw new NotSupportedException(); - } - } - } -} diff --git a/Lib9c/Action/ActionObsoleteAttribute.cs b/Lib9c/Action/ActionObsoleteAttribute.cs index 53990e9dd7e..5aaa4d3d42f 100644 --- a/Lib9c/Action/ActionObsoleteAttribute.cs +++ b/Lib9c/Action/ActionObsoleteAttribute.cs @@ -14,14 +14,27 @@ namespace Nekoyume.Action /// starting from + 2. /// /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class ActionObsoleteAttribute : Attribute { public ActionObsoleteAttribute(long obsoleteIndex) + : this(null, obsoleteIndex) { + } + + public ActionObsoleteAttribute(Planet planet, long obsoleteIndex) + : this((Planet?)planet, obsoleteIndex) + { + } + + private ActionObsoleteAttribute(Planet? planet, long obsoleteIndex) + { + AffectedPlanet = planet; ObsoleteIndex = obsoleteIndex; } public readonly long ObsoleteIndex; + + public readonly Planet? AffectedPlanet; } } diff --git a/Lib9c/Action/ActionObsoleteAttributeExtension.cs b/Lib9c/Action/ActionObsoleteAttributeExtension.cs new file mode 100644 index 00000000000..44e3de07392 --- /dev/null +++ b/Lib9c/Action/ActionObsoleteAttributeExtension.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; +using Nekoyume.Action; + +namespace Nekoyume +{ + public static class ActionObsoleteAttributeExtension + { + public static bool IsObsolete( + this IEnumerable attrs, + Planet planet, + long blockIndex + ) + { + // it means that action had been obsoleted in the single planet era. + // in that case, check index in Odin only, rest should be obsoleted. + if (attrs.Count() == 1) + { + if (planet != Planet.Odin) + { + return true; + } + + // Comparison with ObsoleteIndex + 2 is intended to have backward compatibility with + // a bugged original implementation. + return attrs.Single().ObsoleteIndex + 2 <= blockIndex; + } + + return attrs.Any(attr => (attr.AffectedPlanet == Planet.Odin ? attr.ObsoleteIndex + 2 : attr.ObsoleteIndex) <= blockIndex && attr.AffectedPlanet == planet); + } + } +} diff --git a/Lib9c/Action/ActivateAccount.cs b/Lib9c/Action/ActivateAccount.cs index d9e16e98a76..9e916e403e8 100644 --- a/Lib9c/Action/ActivateAccount.cs +++ b/Lib9c/Action/ActivateAccount.cs @@ -49,12 +49,6 @@ public override IAccount Execute(IActionContext context) IAccount state = context.PreviousState; Address activatedAddress = context.Signer.Derive(ActivationKey.DeriveKey); - if (context.Rehearsal) - { - return state - .SetState(activatedAddress, MarkChanged) - .SetState(PendingAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); if (!(state.GetState(activatedAddress) is null)) diff --git a/Lib9c/Action/ActivateAccount0.cs b/Lib9c/Action/ActivateAccount0.cs index c43341b823f..9f2640a22dd 100644 --- a/Lib9c/Action/ActivateAccount0.cs +++ b/Lib9c/Action/ActivateAccount0.cs @@ -47,13 +47,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IAccount state = context.PreviousState; - if (context.Rehearsal) - { - return state - .SetState(ActivatedAccountsState.Address, MarkChanged) - .SetState(PendingAddress, MarkChanged); - } - CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); if (!state.TryGetState(ActivatedAccountsState.Address, out Dictionary accountsAsDict)) diff --git a/Lib9c/Action/AddActivatedAccount.cs b/Lib9c/Action/AddActivatedAccount.cs index 962866ab9c6..cc71cfca8b6 100644 --- a/Lib9c/Action/AddActivatedAccount.cs +++ b/Lib9c/Action/AddActivatedAccount.cs @@ -43,12 +43,6 @@ public override IAccount Execute(IActionContext context) IAccount state = context.PreviousState; var address = Address.Derive(ActivationKey.DeriveKey); - if (context.Rehearsal) - { - return state - .SetState(address, MarkChanged); - } - CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); if (!(state.GetState(address) is null)) { diff --git a/Lib9c/Action/AddActivatedAccount0.cs b/Lib9c/Action/AddActivatedAccount0.cs index 3bb8a12e804..161e857687e 100644 --- a/Lib9c/Action/AddActivatedAccount0.cs +++ b/Lib9c/Action/AddActivatedAccount0.cs @@ -41,12 +41,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IAccount state = context.PreviousState; - if (context.Rehearsal) - { - return state - .SetState(ActivatedAccountsState.Address, MarkChanged); - } - if (!state.TryGetState(ActivatedAccountsState.Address, out Dictionary accountsAsDict)) { throw new ActivatedAccountsDoesNotExistsException(); diff --git a/Lib9c/Action/AddRedeemCode.cs b/Lib9c/Action/AddRedeemCode.cs index 6c4a0ae816d..1e81fcc3b71 100644 --- a/Lib9c/Action/AddRedeemCode.cs +++ b/Lib9c/Action/AddRedeemCode.cs @@ -21,11 +21,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states - .SetState(Addresses.RedeemCode, MarkChanged); - } CheckPermission(context); diff --git a/Lib9c/Action/AuraSummon.cs b/Lib9c/Action/AuraSummon.cs index f1e6fb614d8..f4c423c130c 100644 --- a/Lib9c/Action/AuraSummon.cs +++ b/Lib9c/Action/AuraSummon.cs @@ -87,33 +87,17 @@ long blockIndex } var result = new List<(int, Equipment)>(); - int recipeId; for (var i = 0; i < summonCount; i++) { - var recipeValue = random.Next(1, summonRow.CumulativeRecipe6Ratio + 1); - if (recipeValue <= summonRow.CumulativeRecipe1Ratio) + var recipeId = 0; + var targetRatio = random.Next(1, summonRow.TotalRatio() + 1); + for (var j = 1; j <= SummonSheet.Row.MaxRecipeCount; j++) { - recipeId = summonRow.Recipes[0].Item1; - } - else if (recipeValue <= summonRow.CumulativeRecipe2Ratio) - { - recipeId = summonRow.Recipes[1].Item1; - } - else if (recipeValue <= summonRow.CumulativeRecipe3Ratio) - { - recipeId = summonRow.Recipes[2].Item1; - } - else if (recipeValue <= summonRow.CumulativeRecipe4Ratio) - { - recipeId = summonRow.Recipes[3].Item1; - } - else if (recipeValue <= summonRow.CumulativeRecipe5Ratio) - { - recipeId = summonRow.Recipes[4].Item1; - } - else - { - recipeId = summonRow.Recipes[5].Item1; + if (targetRatio <= summonRow.CumulativeRatio(j)) + { + recipeId = summonRow.Recipes[j - 1].Item1; + break; + } } // Validate RecipeId @@ -123,7 +107,8 @@ long blockIndex throw new SheetRowNotFoundException( addressesHex, nameof(EquipmentItemRecipeSheet), - recipeId); + recipeId + ); } // Validate Recipe ResultEquipmentId @@ -181,11 +166,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug($"{addressesHex} AuraSummon Exec. Started."); diff --git a/Lib9c/Action/BattleArena.cs b/Lib9c/Action/BattleArena.cs index 442af4d66b3..11f7d2fe51c 100644 --- a/Lib9c/Action/BattleArena.cs +++ b/Lib9c/Action/BattleArena.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -24,13 +24,15 @@ namespace Nekoyume.Action { /// - /// Hard forked at https://github.com/planetarium/lib9c/pull/2195 + /// Introduce at https://github.com/planetarium/lib9c/pull/2229 + /// Changed at https://github.com/planetarium/lib9c/pull/2242 /// [Serializable] - [ActionType("battle_arena14")] + [ActionType("battle_arena15")] public class BattleArena : GameAction, IBattleArenaV1 { public const string PurchasedCountKey = "purchased_count_during_interval"; + public const int HpIncreasingModifier = 5; public Address myAvatarAddress; public Address enemyAvatarAddress; public int championshipId; @@ -90,11 +92,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex( context, myAvatarAddress, @@ -377,11 +374,12 @@ public override IAccount Execute(IActionContext context) var random = context.GetRandom(); for (var i = 0; i < ticket; i++) { - var simulator = new ArenaSimulator(random); + var simulator = new ArenaSimulator(random, HpIncreasingModifier); var log = simulator.Simulate( myArenaPlayerDigest, enemyArenaPlayerDigest, - arenaSheets); + arenaSheets, + true); if (log.Result.Equals(ArenaLog.ArenaResult.Win)) { winCount++; diff --git a/Lib9c/Action/BattleArena1.cs b/Lib9c/Action/BattleArena1.cs index 1a80652e7e4..2259256f267 100644 --- a/Lib9c/Action/BattleArena1.cs +++ b/Lib9c/Action/BattleArena1.cs @@ -88,10 +88,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100290ObsoleteIndex, context); diff --git a/Lib9c/Action/BattleArena10.cs b/Lib9c/Action/BattleArena10.cs index 9c40c0467bf..082f8a71ccb 100644 --- a/Lib9c/Action/BattleArena10.cs +++ b/Lib9c/Action/BattleArena10.cs @@ -93,11 +93,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex( context, myAvatarAddress, diff --git a/Lib9c/Action/BattleArena11.cs b/Lib9c/Action/BattleArena11.cs index 817bf1c2885..aa5a7182a0d 100644 --- a/Lib9c/Action/BattleArena11.cs +++ b/Lib9c/Action/BattleArena11.cs @@ -91,11 +91,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex( context, myAvatarAddress, diff --git a/Lib9c/Action/BattleArena12.cs b/Lib9c/Action/BattleArena12.cs index 6c743297796..14ff41e2bd5 100644 --- a/Lib9c/Action/BattleArena12.cs +++ b/Lib9c/Action/BattleArena12.cs @@ -91,10 +91,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200070ObsoleteIndex, context); if (championshipId == 6 && round >= 2 || championshipId > 6) diff --git a/Lib9c/Action/BattleArena13.cs b/Lib9c/Action/BattleArena13.cs index 544b9e0b8f8..0349f968cf2 100644 --- a/Lib9c/Action/BattleArena13.cs +++ b/Lib9c/Action/BattleArena13.cs @@ -92,11 +92,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); var states = context.PreviousState; var random = context.GetRandom(); - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex( context, myAvatarAddress, diff --git a/Lib9c/Action/BattleArena14.cs b/Lib9c/Action/BattleArena14.cs new file mode 100644 index 00000000000..e5b67347a97 --- /dev/null +++ b/Lib9c/Action/BattleArena14.cs @@ -0,0 +1,447 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Bencodex.Types; +using Lib9c.Abstractions; +using Libplanet.Action; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Nekoyume.Arena; +using Nekoyume.Battle; +using Nekoyume.Extensions; +using Nekoyume.Helper; +using Nekoyume.Model; +using Nekoyume.Model.Arena; +using Nekoyume.Model.BattleStatus.Arena; +using Nekoyume.Model.EnumType; +using Nekoyume.Model.Item; +using Nekoyume.Model.State; +using Nekoyume.TableData; +using Serilog; +using static Lib9c.SerializeKeys; + +namespace Nekoyume.Action +{ + /// + /// Hard forked at https://github.com/planetarium/lib9c/pull/2195 + /// + [Serializable] + [ActionType("battle_arena14")] + public class BattleArena14 : GameAction, IBattleArenaV1 + { + public const string PurchasedCountKey = "purchased_count_during_interval"; + public Address myAvatarAddress; + public Address enemyAvatarAddress; + public int championshipId; + public int round; + public int ticket; + + public List costumes; + public List equipments; + public List runeInfos; + + Address IBattleArenaV1.MyAvatarAddress => myAvatarAddress; + + Address IBattleArenaV1.EnemyAvatarAddress => enemyAvatarAddress; + + int IBattleArenaV1.ChampionshipId => championshipId; + + int IBattleArenaV1.Round => round; + + int IBattleArenaV1.Ticket => ticket; + + IEnumerable IBattleArenaV1.Costumes => costumes; + + IEnumerable IBattleArenaV1.Equipments => equipments; + + IEnumerable IBattleArenaV1.RuneSlotInfos => runeInfos + .Select(x => x.Serialize()); + + protected override IImmutableDictionary PlainValueInternal => + new Dictionary() + { + [MyAvatarAddressKey] = myAvatarAddress.Serialize(), + [EnemyAvatarAddressKey] = enemyAvatarAddress.Serialize(), + [ChampionshipIdKey] = championshipId.Serialize(), + [RoundKey] = round.Serialize(), + [TicketKey] = ticket.Serialize(), + [CostumesKey] = new List(costumes + .OrderBy(element => element).Select(e => e.Serialize())), + [EquipmentsKey] = new List(equipments + .OrderBy(element => element).Select(e => e.Serialize())), + [RuneInfos] = runeInfos.OrderBy(x => x.SlotIndex).Select(x=> x.Serialize()).Serialize(), + }.ToImmutableDictionary(); + + protected override void LoadPlainValueInternal( + IImmutableDictionary plainValue) + { + myAvatarAddress = plainValue[MyAvatarAddressKey].ToAddress(); + enemyAvatarAddress = plainValue[EnemyAvatarAddressKey].ToAddress(); + championshipId = plainValue[ChampionshipIdKey].ToInteger(); + round = plainValue[RoundKey].ToInteger(); + ticket = plainValue[TicketKey].ToInteger(); + costumes = ((List)plainValue[CostumesKey]).Select(e => e.ToGuid()).ToList(); + equipments = ((List)plainValue[EquipmentsKey]).Select(e => e.ToGuid()).ToList(); + runeInfos = plainValue[RuneInfos].ToList(x => new RuneSlotInfo((List)x)); + } + + public override IAccount Execute(IActionContext context) + { + context.UseGas(1); + var states = context.PreviousState; + var addressesHex = GetSignerAndOtherAddressesHex( + context, + myAvatarAddress, + enemyAvatarAddress); + + var started = DateTimeOffset.UtcNow; + Log.Debug("{AddressesHex}BattleArena exec started", addressesHex); + if (myAvatarAddress.Equals(enemyAvatarAddress)) + { + throw new InvalidAddressException( + $"{addressesHex}Aborted as the signer tried to battle for themselves."); + } + + if (!states.TryGetAvatarStateV2( + context.Signer, + myAvatarAddress, + out var avatarState, + out var migrationRequired)) + { + throw new FailedLoadStateException( + $"{addressesHex}Aborted as the avatar state of the signer was failed to load."); + } + + var sheets = states.GetSheets( + containArenaSimulatorSheets: true, + sheetTypes: new[] + { + typeof(ArenaSheet), + typeof(ItemRequirementSheet), + typeof(EquipmentItemRecipeSheet), + typeof(EquipmentItemSubRecipeSheetV2), + typeof(EquipmentItemOptionSheet), + typeof(MaterialItemSheet), + typeof(RuneListSheet), + }); + + var gameConfigState = states.GetGameConfigState(); + avatarState.ValidEquipmentAndCostumeV2(costumes, equipments, + sheets.GetSheet(), + sheets.GetSheet(), + sheets.GetSheet(), + sheets.GetSheet(), + context.BlockIndex, addressesHex, gameConfigState); + + // update rune slot + var runeSlotStateAddress = RuneSlotState.DeriveAddress(myAvatarAddress, BattleType.Arena); + var runeSlotState = states.TryGetState(runeSlotStateAddress, out List rawRuneSlotState) + ? new RuneSlotState(rawRuneSlotState) + : new RuneSlotState(BattleType.Arena); + var runeListSheet = sheets.GetSheet(); + runeSlotState.UpdateSlot(runeInfos, runeListSheet); + states = states.SetState(runeSlotStateAddress, runeSlotState.Serialize()); + + // update item slot + var itemSlotStateAddress = ItemSlotState.DeriveAddress(myAvatarAddress, BattleType.Arena); + var itemSlotState = states.TryGetState(itemSlotStateAddress, out List rawItemSlotState) + ? new ItemSlotState(rawItemSlotState) + : new ItemSlotState(BattleType.Arena); + itemSlotState.UpdateEquipment(equipments); + itemSlotState.UpdateCostumes(costumes); + states = states.SetState(itemSlotStateAddress, itemSlotState.Serialize()); + + var arenaSheet = sheets.GetSheet(); + if (!arenaSheet.TryGetValue(championshipId, out var arenaRow)) + { + throw new SheetRowNotFoundException(nameof(ArenaSheet), + $"championship Id : {championshipId}"); + } + + if (!arenaRow.TryGetRound(round, out var roundData)) + { + throw new RoundNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({arenaRow.ChampionshipId}) - " + + $"round({round})"); + } + + if (!roundData.IsTheRoundOpened(context.BlockIndex)) + { + throw new ThisArenaIsClosedException( + $"{nameof(BattleArena14)} : block index({context.BlockIndex}) - " + + $"championshipId({roundData.ChampionshipId}) - round({roundData.Round})"); + } + + var arenaParticipantsAdr = + ArenaParticipants.DeriveAddress(roundData.ChampionshipId, roundData.Round); + if (!states.TryGetArenaParticipants(arenaParticipantsAdr, out var arenaParticipants)) + { + throw new ArenaParticipantsNotFoundException( + $"[{nameof(BattleArena14)}] ChampionshipId({roundData.ChampionshipId}) - " + + $"round({roundData.Round})"); + } + + if (!arenaParticipants.AvatarAddresses.Contains(myAvatarAddress)) + { + throw new AddressNotFoundInArenaParticipantsException( + $"[{nameof(BattleArena14)}] my avatar address : {myAvatarAddress}"); + } + + if (!arenaParticipants.AvatarAddresses.Contains(enemyAvatarAddress)) + { + throw new AddressNotFoundInArenaParticipantsException( + $"[{nameof(BattleArena14)}] enemy avatar address : {enemyAvatarAddress}"); + } + + var myArenaAvatarStateAdr = ArenaAvatarState.DeriveAddress(myAvatarAddress); + if (!states.TryGetArenaAvatarState(myArenaAvatarStateAdr, out var myArenaAvatarState)) + { + throw new ArenaAvatarStateNotFoundException( + $"[{nameof(BattleArena14)}] my avatar address : {myAvatarAddress}"); + } + + var battleArenaInterval = roundData.ArenaType == ArenaType.OffSeason + ? 1 + : gameConfigState.BattleArenaInterval; + if (context.BlockIndex - myArenaAvatarState.LastBattleBlockIndex < battleArenaInterval) + { + throw new CoolDownBlockException( + $"[{nameof(BattleArena14)}] LastBattleBlockIndex : " + + $"{myArenaAvatarState.LastBattleBlockIndex} " + + $"CurrentBlockIndex : {context.BlockIndex}"); + } + + var enemyArenaAvatarStateAdr = ArenaAvatarState.DeriveAddress(enemyAvatarAddress); + if (!states.TryGetArenaAvatarState( + enemyArenaAvatarStateAdr, + out var enemyArenaAvatarState)) + { + throw new ArenaAvatarStateNotFoundException( + $"[{nameof(BattleArena14)}] enemy avatar address : {enemyAvatarAddress}"); + } + + var myArenaScoreAdr = ArenaScore.DeriveAddress( + myAvatarAddress, + roundData.ChampionshipId, + roundData.Round); + if (!states.TryGetArenaScore(myArenaScoreAdr, out var myArenaScore)) + { + throw new ArenaScoreNotFoundException( + $"[{nameof(BattleArena14)}] my avatar address : {myAvatarAddress}" + + $" - ChampionshipId({roundData.ChampionshipId}) - round({roundData.Round})"); + } + + var enemyArenaScoreAdr = ArenaScore.DeriveAddress( + enemyAvatarAddress, + roundData.ChampionshipId, + roundData.Round); + if (!states.TryGetArenaScore(enemyArenaScoreAdr, out var enemyArenaScore)) + { + throw new ArenaScoreNotFoundException( + $"[{nameof(BattleArena14)}] enemy avatar address : {enemyAvatarAddress}" + + $" - ChampionshipId({roundData.ChampionshipId}) - round({roundData.Round})"); + } + + var arenaInformationAdr = ArenaInformation.DeriveAddress( + myAvatarAddress, + roundData.ChampionshipId, + roundData.Round); + if (!states.TryGetArenaInformation(arenaInformationAdr, out var arenaInformation)) + { + throw new ArenaInformationNotFoundException( + $"[{nameof(BattleArena14)}] my avatar address : {myAvatarAddress}" + + $" - ChampionshipId({roundData.ChampionshipId}) - round({roundData.Round})"); + } + + if (!ArenaHelper.ValidateScoreDifference( + ArenaHelper.ScoreLimits, + roundData.ArenaType, + myArenaScore.Score, + enemyArenaScore.Score)) + { + var scoreDiff = enemyArenaScore.Score - myArenaScore.Score; + throw new ValidateScoreDifferenceException( + $"[{nameof(BattleArena14)}] Arena Type({roundData.ArenaType}) : " + + $"enemyScore({enemyArenaScore.Score}) - myScore({myArenaScore.Score}) = " + + $"diff({scoreDiff})"); + } + + var dailyArenaInterval = gameConfigState.DailyArenaInterval; + var currentTicketResetCount = ArenaHelper.GetCurrentTicketResetCount( + context.BlockIndex, roundData.StartBlockIndex, dailyArenaInterval); + var purchasedCountAddr = arenaInformation.Address.Derive(PurchasedCountKey); + if (!states.TryGetState(purchasedCountAddr, out Integer purchasedCountDuringInterval)) + { + purchasedCountDuringInterval = 0; + } + + if (arenaInformation.TicketResetCount < currentTicketResetCount) + { + arenaInformation.ResetTicket(currentTicketResetCount); + purchasedCountDuringInterval = 0; + states = states.SetState(purchasedCountAddr, purchasedCountDuringInterval); + } + + if (roundData.ArenaType != ArenaType.OffSeason && ticket > 1) + { + throw new ExceedPlayCountException($"[{nameof(BattleArena14)}] " + + $"ticket : {ticket} / arenaType : " + + $"{roundData.ArenaType}"); + } + + if (arenaInformation.Ticket > 0) + { + arenaInformation.UseTicket(ticket); + } + else if (ticket > 1) + { + throw new TicketPurchaseLimitExceedException( + $"[{nameof(ArenaInformation)}] tickets to buy : {ticket}"); + } + else + { + var arenaAdr = + ArenaHelper.DeriveArenaAddress(roundData.ChampionshipId, roundData.Round); + var goldCurrency = states.GetGoldCurrency(); + var ticketBalance = + ArenaHelper.GetTicketPrice(roundData, arenaInformation, goldCurrency); + arenaInformation.BuyTicket(roundData.MaxPurchaseCount); + if (purchasedCountDuringInterval >= roundData.MaxPurchaseCountWithInterval) + { + throw new ExceedTicketPurchaseLimitDuringIntervalException( + $"[{nameof(ArenaInformation)}] PurchasedTicketCount({purchasedCountDuringInterval}) >= MAX({{max}})"); + } + + purchasedCountDuringInterval++; + states = states + .TransferAsset(context, context.Signer, arenaAdr, ticketBalance) + .SetState(purchasedCountAddr, purchasedCountDuringInterval); + } + + // update arena avatar state + myArenaAvatarState.UpdateEquipment(equipments); + myArenaAvatarState.UpdateCostumes(costumes); + myArenaAvatarState.LastBattleBlockIndex = context.BlockIndex; + var runeStates = new List(); + foreach (var address in runeInfos.Select(info => RuneState.DeriveAddress(myAvatarAddress, info.RuneId))) + { + if (states.TryGetState(address, out List rawRuneState)) + { + runeStates.Add(new RuneState(rawRuneState)); + } + } + + // get enemy equipped items + var enemyItemSlotStateAddress = ItemSlotState.DeriveAddress(enemyAvatarAddress, BattleType.Arena); + var enemyItemSlotState = states.TryGetState(enemyItemSlotStateAddress, out List rawEnemyItemSlotState) + ? new ItemSlotState(rawEnemyItemSlotState) + : new ItemSlotState(BattleType.Arena); + var enemyRuneSlotStateAddress = RuneSlotState.DeriveAddress(enemyAvatarAddress, BattleType.Arena); + var enemyRuneSlotState = states.TryGetState(enemyRuneSlotStateAddress, out List enemyRawRuneSlotState) + ? new RuneSlotState(enemyRawRuneSlotState) + : new RuneSlotState(BattleType.Arena); + + var enemyRuneStates = new List(); + var enemyRuneSlotInfos = enemyRuneSlotState.GetEquippedRuneSlotInfos(); + foreach (var address in enemyRuneSlotInfos.Select(info => RuneState.DeriveAddress(enemyAvatarAddress, info.RuneId))) + { + if (states.TryGetState(address, out List rawRuneState)) + { + enemyRuneStates.Add(new RuneState(rawRuneState)); + } + } + + // simulate + var enemyAvatarState = states.GetEnemyAvatarState(enemyAvatarAddress); + var myArenaPlayerDigest = new ArenaPlayerDigest( + avatarState, + equipments, + costumes, + runeStates); + var enemyArenaPlayerDigest = new ArenaPlayerDigest( + enemyAvatarState, + enemyItemSlotState.Equipments, + enemyItemSlotState.Costumes, + enemyRuneStates); + var previousMyScore = myArenaScore.Score; + var arenaSheets = sheets.GetArenaSimulatorSheets(); + var winCount = 0; + var defeatCount = 0; + var rewards = new List(); + var random = context.GetRandom(); + for (var i = 0; i < ticket; i++) + { + var simulator = new ArenaSimulator(random); + var log = simulator.Simulate( + myArenaPlayerDigest, + enemyArenaPlayerDigest, + arenaSheets); + if (log.Result.Equals(ArenaLog.ArenaResult.Win)) + { + winCount++; + } + else + { + defeatCount++; + } + + var reward = RewardSelector.Select( + random, + sheets.GetSheet(), + sheets.GetSheet(), + myArenaPlayerDigest.Level, + maxCount: ArenaHelper.GetRewardCount(previousMyScore)); + rewards.AddRange(reward); + } + + // add reward + foreach (var itemBase in rewards.OrderBy(x => x.Id)) + { + avatarState.inventory.AddItem(itemBase); + } + + // add medal + if (roundData.ArenaType != ArenaType.OffSeason && winCount > 0) + { + var materialSheet = sheets.GetSheet(); + var medal = ArenaHelper.GetMedal( + roundData.ChampionshipId, + roundData.Round, + materialSheet); + avatarState.inventory.AddItem(medal, count: winCount); + } + + // update record + var (myWinScore, myDefeatScore, enemyWinScore) = + ArenaHelper.GetScores(previousMyScore, enemyArenaScore.Score); + var myScore = (myWinScore * winCount) + (myDefeatScore * defeatCount); + myArenaScore.AddScore(myScore); + enemyArenaScore.AddScore(enemyWinScore * winCount); + arenaInformation.UpdateRecord(winCount, defeatCount); + + if (migrationRequired) + { + states = states + .SetState(myAvatarAddress, avatarState.SerializeV2()) + .SetState( + myAvatarAddress.Derive(LegacyWorldInformationKey), + avatarState.worldInformation.Serialize()) + .SetState( + myAvatarAddress.Derive(LegacyQuestListKey), + avatarState.questList.Serialize()); + } + + var ended = DateTimeOffset.UtcNow; + Log.Debug("{AddressesHex}BattleArena Total Executed Time: {Elapsed}", addressesHex, ended - started); + return states + .SetState(myArenaAvatarStateAdr, myArenaAvatarState.Serialize()) + .SetState(myArenaScoreAdr, myArenaScore.Serialize()) + .SetState(enemyArenaScoreAdr, enemyArenaScore.Serialize()) + .SetState(arenaInformationAdr, arenaInformation.Serialize()) + .SetState( + myAvatarAddress.Derive(LegacyInventoryKey), + avatarState.inventory.Serialize()); + } + } +} diff --git a/Lib9c/Action/BattleArena2.cs b/Lib9c/Action/BattleArena2.cs index 7e2bb48e2c1..6d690bbacd6 100644 --- a/Lib9c/Action/BattleArena2.cs +++ b/Lib9c/Action/BattleArena2.cs @@ -87,10 +87,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100290ObsoleteIndex, context); diff --git a/Lib9c/Action/BattleArena3.cs b/Lib9c/Action/BattleArena3.cs index b0898715c76..df8ddb80d37 100644 --- a/Lib9c/Action/BattleArena3.cs +++ b/Lib9c/Action/BattleArena3.cs @@ -87,10 +87,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100290ObsoleteIndex, context); diff --git a/Lib9c/Action/BattleArena4.cs b/Lib9c/Action/BattleArena4.cs index 905012c8f92..1d6e9b1433d 100644 --- a/Lib9c/Action/BattleArena4.cs +++ b/Lib9c/Action/BattleArena4.cs @@ -87,10 +87,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100320ObsoleteIndex, context); diff --git a/Lib9c/Action/BattleArena5.cs b/Lib9c/Action/BattleArena5.cs index b68211ba8c0..a36ffd61a0f 100644 --- a/Lib9c/Action/BattleArena5.cs +++ b/Lib9c/Action/BattleArena5.cs @@ -88,10 +88,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100320ObsoleteIndex, context); diff --git a/Lib9c/Action/BattleArena6.cs b/Lib9c/Action/BattleArena6.cs index 5aecca65948..35ca737097e 100644 --- a/Lib9c/Action/BattleArena6.cs +++ b/Lib9c/Action/BattleArena6.cs @@ -89,10 +89,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } if (championshipId > 2) { diff --git a/Lib9c/Action/BattleArena7.cs b/Lib9c/Action/BattleArena7.cs index bc048bfea61..3ce88492458 100644 --- a/Lib9c/Action/BattleArena7.cs +++ b/Lib9c/Action/BattleArena7.cs @@ -95,10 +95,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100360ObsoleteIndex, context); diff --git a/Lib9c/Action/BattleArena8.cs b/Lib9c/Action/BattleArena8.cs index 0ce0b288162..a60080b5cf5 100644 --- a/Lib9c/Action/BattleArena8.cs +++ b/Lib9c/Action/BattleArena8.cs @@ -97,10 +97,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex( diff --git a/Lib9c/Action/BattleArena9.cs b/Lib9c/Action/BattleArena9.cs index 4c92f0fe30b..02b9d6171a5 100644 --- a/Lib9c/Action/BattleArena9.cs +++ b/Lib9c/Action/BattleArena9.cs @@ -96,10 +96,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } var addressesHex = GetSignerAndOtherAddressesHex( context, diff --git a/Lib9c/Action/BattleGrandFinale.cs b/Lib9c/Action/BattleGrandFinale.cs index db1abd02d9d..56e5ae31eee 100644 --- a/Lib9c/Action/BattleGrandFinale.cs +++ b/Lib9c/Action/BattleGrandFinale.cs @@ -81,11 +81,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex( context, myAvatarAddress, diff --git a/Lib9c/Action/BattleGrandFinale1.cs b/Lib9c/Action/BattleGrandFinale1.cs index fb300d663d7..bc94a48bb15 100644 --- a/Lib9c/Action/BattleGrandFinale1.cs +++ b/Lib9c/Action/BattleGrandFinale1.cs @@ -80,10 +80,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex( diff --git a/Lib9c/Action/BattleGrandFinale2.cs b/Lib9c/Action/BattleGrandFinale2.cs index 524c890776f..17214b3fb07 100644 --- a/Lib9c/Action/BattleGrandFinale2.cs +++ b/Lib9c/Action/BattleGrandFinale2.cs @@ -81,11 +81,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex( context, myAvatarAddress, diff --git a/Lib9c/Action/BurnAsset.cs b/Lib9c/Action/BurnAsset.cs new file mode 100644 index 00000000000..4fcc719d608 --- /dev/null +++ b/Lib9c/Action/BurnAsset.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using Bencodex.Types; +using Libplanet.Action; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Libplanet.Types.Assets; +using Nekoyume.Exceptions; +using Nekoyume.Model.State; + +namespace Nekoyume.Action +{ + [ActionType(TypeIdentifier)] + public class BurnAsset : ActionBase + { + private const int MemoMaxLength = 80; + public const string TypeIdentifier = "burn_asset"; + + private string _memo; + + public BurnAsset() + { + } + + public BurnAsset(Address owner, FungibleAssetValue amount, string memo) + { + Owner = owner; + Amount = amount; + Memo = memo; + } + + public override IAccount Execute(IActionContext context) + { + context.UseGas(1); + + IAccount state = context.PreviousState; + + if (!Addresses.CheckAgentHasPermissionOnBalanceAddr(context.Signer, Owner)) + { + throw new InvalidActionFieldException( + actionType: TypeIdentifier, + addressesHex: context.Signer.ToHex(), + fieldName: nameof(Owner), + message: $"context.Signer doesn't own {Owner}" + ); + } + + return state.BurnAsset(context, Owner, Amount); + } + + public override void LoadPlainValue(IValue plainValue) + { + var asDict = (Dictionary)plainValue; + var values = (List)asDict["values"]; + + Owner = values[0].ToAddress(); + Amount = values[1].ToFungibleAssetValue(); + Memo = (Text)values[2]; + } + + public override IValue PlainValue => + new Dictionary( + new[] + { + new KeyValuePair( + (Text)"type_id", + (Text)TypeIdentifier + ), + new KeyValuePair( + (Text)"values", + new List( + Owner.Serialize(), + Amount.Serialize(), + (Text)Memo + ) + ), + } + ); + + public FungibleAssetValue Amount { get; private set; } + + public string Memo { + get => _memo; + private set + { + if (value.Length >= MemoMaxLength) { + string msg = $"The length of the memo, {value.Length}, is overflowed than " + + $"the max length, {MemoMaxLength}."; + + throw new MemoLengthOverflowException(msg); + } + + _memo = value; + } + } + + public Address Owner { get; private set; } + + } +} diff --git a/Lib9c/Action/Buy.cs b/Lib9c/Action/Buy.cs index 74718f5c5e0..633c171c00b 100644 --- a/Lib9c/Action/Buy.cs +++ b/Lib9c/Action/Buy.cs @@ -72,11 +72,6 @@ public override IAccount Execute(IActionContext context) var buyerInventoryAddress = buyerAvatarAddress.Derive(LegacyInventoryKey); var buyerWorldInformationAddress = buyerAvatarAddress.Derive(LegacyWorldInformationKey); var buyerQuestListAddress = buyerAvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, buyerAvatarAddress); var sw = new Stopwatch(); diff --git a/Lib9c/Action/Buy0.cs b/Lib9c/Action/Buy0.cs index b3cc8865eef..81f3c6cb5eb 100644 --- a/Lib9c/Action/Buy0.cs +++ b/Lib9c/Action/Buy0.cs @@ -56,20 +56,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - sellerAgentAddress, - GoldCurrencyState.Address); - return states.SetState(ShopState.Address, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Buy10.cs b/Lib9c/Action/Buy10.cs index b3671edbb59..ff9132eecf6 100644 --- a/Lib9c/Action/Buy10.cs +++ b/Lib9c/Action/Buy10.cs @@ -67,41 +67,6 @@ public override IAccount Execute(IActionContext context) var buyerInventoryAddress = buyerAvatarAddress.Derive(LegacyInventoryKey); var buyerWorldInformationAddress = buyerAvatarAddress.Derive(LegacyWorldInformationKey); var buyerQuestListAddress = buyerAvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - foreach (var purchaseInfo in purchaseInfos) - { - var sellerAvatarAddress = purchaseInfo.SellerAvatarAddress; - var sellerInventoryAddress = sellerAvatarAddress.Derive(LegacyInventoryKey); - var sellerWorldInformationAddress = sellerAvatarAddress.Derive(LegacyWorldInformationKey); - var sellerQuestListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); - Address shardedShopAddress = - ShardedShopStateV2.DeriveAddress(purchaseInfo.ItemSubType, purchaseInfo.OrderId); - Address orderReceiptAddress = OrderReceipt.DeriveAddress(purchaseInfo.OrderId); - Address digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - states = states - .SetState(shardedShopAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged) - .SetState(sellerInventoryAddress, MarkChanged) - .SetState(sellerWorldInformationAddress, MarkChanged) - .SetState(sellerQuestListAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(digestListAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - purchaseInfo.SellerAgentAddress, - GoldCurrencyState.Address); - } - - return states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(buyerInventoryAddress, MarkChanged) - .SetState(buyerWorldInformationAddress, MarkChanged) - .SetState(buyerQuestListAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100220ObsoleteIndex, context); diff --git a/Lib9c/Action/Buy11.cs b/Lib9c/Action/Buy11.cs index 594d830a752..b93382a6542 100644 --- a/Lib9c/Action/Buy11.cs +++ b/Lib9c/Action/Buy11.cs @@ -72,41 +72,6 @@ public override IAccount Execute(IActionContext context) var buyerInventoryAddress = buyerAvatarAddress.Derive(LegacyInventoryKey); var buyerWorldInformationAddress = buyerAvatarAddress.Derive(LegacyWorldInformationKey); var buyerQuestListAddress = buyerAvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - foreach (var purchaseInfo in purchaseInfos) - { - var sellerAvatarAddress = purchaseInfo.SellerAvatarAddress; - var sellerInventoryAddress = sellerAvatarAddress.Derive(LegacyInventoryKey); - var sellerWorldInformationAddress = sellerAvatarAddress.Derive(LegacyWorldInformationKey); - var sellerQuestListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); - Address shardedShopAddress = - ShardedShopStateV2.DeriveAddress(purchaseInfo.ItemSubType, purchaseInfo.OrderId); - Address orderReceiptAddress = OrderReceipt.DeriveAddress(purchaseInfo.OrderId); - Address digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - states = states - .SetState(shardedShopAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged) - .SetState(sellerInventoryAddress, MarkChanged) - .SetState(sellerWorldInformationAddress, MarkChanged) - .SetState(sellerQuestListAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(digestListAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - purchaseInfo.SellerAgentAddress, - GetFeeStoreAddress()); - } - - return states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(buyerInventoryAddress, MarkChanged) - .SetState(buyerWorldInformationAddress, MarkChanged) - .SetState(buyerQuestListAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var arenaSheetAddress = Addresses.GetSheetAddress(); diff --git a/Lib9c/Action/Buy2.cs b/Lib9c/Action/Buy2.cs index 5d5d7431f6a..1ea99d5a0f7 100644 --- a/Lib9c/Action/Buy2.cs +++ b/Lib9c/Action/Buy2.cs @@ -57,20 +57,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - sellerAgentAddress, - GoldCurrencyState.Address); - return states.SetState(ShopState.Address, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Buy3.cs b/Lib9c/Action/Buy3.cs index 4b565389717..043e7c2d38a 100644 --- a/Lib9c/Action/Buy3.cs +++ b/Lib9c/Action/Buy3.cs @@ -55,20 +55,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - sellerAgentAddress, - GoldCurrencyState.Address); - return states.SetState(ShopState.Address, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Buy4.cs b/Lib9c/Action/Buy4.cs index 8d9330e4208..03f032a7c49 100644 --- a/Lib9c/Action/Buy4.cs +++ b/Lib9c/Action/Buy4.cs @@ -55,20 +55,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - sellerAgentAddress, - GoldCurrencyState.Address); - return states.SetState(ShopState.Address, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Buy5.cs b/Lib9c/Action/Buy5.cs index 82ffe31310e..c3629de24d7 100644 --- a/Lib9c/Action/Buy5.cs +++ b/Lib9c/Action/Buy5.cs @@ -60,27 +60,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - foreach (var purchaseInfo in purchaseInfos) - { - Address shardedShopAddress = - ShardedShopState.DeriveAddress(purchaseInfo.itemSubType, purchaseInfo.productId); - states = states - .SetState(shardedShopAddress, MarkChanged) - .SetState(purchaseInfo.sellerAvatarAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - purchaseInfo.sellerAgentAddress, - GoldCurrencyState.Address); - } - return states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(Addresses.Shop, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Buy6.cs b/Lib9c/Action/Buy6.cs index d9bdcf79695..09ac72ca498 100644 --- a/Lib9c/Action/Buy6.cs +++ b/Lib9c/Action/Buy6.cs @@ -60,27 +60,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - foreach (var purchaseInfo in purchaseInfos) - { - Address shardedShopAddress = - ShardedShopState.DeriveAddress(purchaseInfo.itemSubType, purchaseInfo.productId); - states = states - .SetState(shardedShopAddress, MarkChanged) - .SetState(purchaseInfo.sellerAvatarAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - purchaseInfo.sellerAgentAddress, - GoldCurrencyState.Address); - } - return states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(Addresses.Shop, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Buy7.cs b/Lib9c/Action/Buy7.cs index b61f3b955bd..f7269e9afc0 100644 --- a/Lib9c/Action/Buy7.cs +++ b/Lib9c/Action/Buy7.cs @@ -199,27 +199,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - foreach (var purchaseInfo in purchaseInfos) - { - Address shardedShopAddress = - ShardedShopState.DeriveAddress(purchaseInfo.itemSubType, purchaseInfo.productId); - states = states - .SetState(shardedShopAddress, MarkChanged) - .SetState(purchaseInfo.sellerAvatarAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - purchaseInfo.sellerAgentAddress, - GoldCurrencyState.Address); - } - return states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(Addresses.Shop, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Buy8.cs b/Lib9c/Action/Buy8.cs index e007b2a3d8c..d3342bbd838 100644 --- a/Lib9c/Action/Buy8.cs +++ b/Lib9c/Action/Buy8.cs @@ -68,41 +68,6 @@ public override IAccount Execute(IActionContext context) var buyerInventoryAddress = buyerAvatarAddress.Derive(LegacyInventoryKey); var buyerWorldInformationAddress = buyerAvatarAddress.Derive(LegacyWorldInformationKey); var buyerQuestListAddress = buyerAvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - foreach (var purchaseInfo in purchaseInfos) - { - var sellerAvatarAddress = purchaseInfo.SellerAvatarAddress; - var sellerInventoryAddress = sellerAvatarAddress.Derive(LegacyInventoryKey); - var sellerWorldInformationAddress = sellerAvatarAddress.Derive(LegacyWorldInformationKey); - var sellerQuestListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); - Address shardedShopAddress = - ShardedShopStateV2.DeriveAddress(purchaseInfo.ItemSubType, purchaseInfo.OrderId); - Address orderReceiptAddress = OrderReceipt.DeriveAddress(purchaseInfo.OrderId); - Address digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - states = states - .SetState(shardedShopAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged) - .SetState(sellerInventoryAddress, MarkChanged) - .SetState(sellerWorldInformationAddress, MarkChanged) - .SetState(sellerQuestListAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(digestListAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - purchaseInfo.SellerAgentAddress, - GoldCurrencyState.Address); - } - - return states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(buyerInventoryAddress, MarkChanged) - .SetState(buyerWorldInformationAddress, MarkChanged) - .SetState(buyerQuestListAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Buy9.cs b/Lib9c/Action/Buy9.cs index adfde17cab2..73aee188883 100644 --- a/Lib9c/Action/Buy9.cs +++ b/Lib9c/Action/Buy9.cs @@ -68,41 +68,6 @@ public override IAccount Execute(IActionContext context) var buyerInventoryAddress = buyerAvatarAddress.Derive(LegacyInventoryKey); var buyerWorldInformationAddress = buyerAvatarAddress.Derive(LegacyWorldInformationKey); var buyerQuestListAddress = buyerAvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - foreach (var purchaseInfo in purchaseInfos) - { - var sellerAvatarAddress = purchaseInfo.SellerAvatarAddress; - var sellerInventoryAddress = sellerAvatarAddress.Derive(LegacyInventoryKey); - var sellerWorldInformationAddress = sellerAvatarAddress.Derive(LegacyWorldInformationKey); - var sellerQuestListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); - Address shardedShopAddress = - ShardedShopStateV2.DeriveAddress(purchaseInfo.ItemSubType, purchaseInfo.OrderId); - Address orderReceiptAddress = OrderReceipt.DeriveAddress(purchaseInfo.OrderId); - Address digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - states = states - .SetState(shardedShopAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged) - .SetState(sellerInventoryAddress, MarkChanged) - .SetState(sellerWorldInformationAddress, MarkChanged) - .SetState(sellerQuestListAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(digestListAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - purchaseInfo.SellerAgentAddress, - GoldCurrencyState.Address); - } - - return states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(buyerInventoryAddress, MarkChanged) - .SetState(buyerWorldInformationAddress, MarkChanged) - .SetState(buyerQuestListAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/BuyMultiple.cs b/Lib9c/Action/BuyMultiple.cs index cbcdcec2bb4..a60001c8823 100644 --- a/Lib9c/Action/BuyMultiple.cs +++ b/Lib9c/Action/BuyMultiple.cs @@ -222,29 +222,6 @@ public override IAccount Execute(IActionContext context) IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states - .SetState(buyerAvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged); - - foreach (var info in purchaseInfos) - { - var sellerAgentAddress = info.sellerAgentAddress; - var sellerAvatarAddress = info.sellerAvatarAddress; - - states = states.SetState(sellerAvatarAddress, MarkChanged) - .MarkBalanceChanged( - ctx, - GoldCurrencyMock, - ctx.Signer, - sellerAgentAddress, - GoldCurrencyState.Address); - } - - return states.SetState(ShopState.Address, MarkChanged); - } - CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); var availableInfos = purchaseInfos.Where(p => !(p is null)); diff --git a/Lib9c/Action/BuyProduct.cs b/Lib9c/Action/BuyProduct.cs index 0793833d552..3ee300f2567 100644 --- a/Lib9c/Action/BuyProduct.cs +++ b/Lib9c/Action/BuyProduct.cs @@ -34,10 +34,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } var sw = new Stopwatch(); sw.Start(); diff --git a/Lib9c/Action/BuyProduct0.cs b/Lib9c/Action/BuyProduct0.cs index 45c17f03ab7..5a660d1ebee 100644 --- a/Lib9c/Action/BuyProduct0.cs +++ b/Lib9c/Action/BuyProduct0.cs @@ -35,10 +35,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } var sw = new Stopwatch(); sw.Start(); diff --git a/Lib9c/Action/BuyProduct2.cs b/Lib9c/Action/BuyProduct2.cs index 49fede92b30..0031ed0d08b 100644 --- a/Lib9c/Action/BuyProduct2.cs +++ b/Lib9c/Action/BuyProduct2.cs @@ -35,10 +35,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } var sw = new Stopwatch(); sw.Start(); diff --git a/Lib9c/Action/CancelMonsterCollect.cs b/Lib9c/Action/CancelMonsterCollect.cs index 8f22c04ad28..519582874f7 100644 --- a/Lib9c/Action/CancelMonsterCollect.cs +++ b/Lib9c/Action/CancelMonsterCollect.cs @@ -37,12 +37,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IAccount states = context.PreviousState; Address collectionAddress = MonsterCollectionState0.DeriveAddress(context.Signer, collectRound); - if (context.Rehearsal) - { - return states - .SetState(collectionAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, collectionAddress, context.Signer); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CancelProductRegistration.cs b/Lib9c/Action/CancelProductRegistration.cs index 5ccd1c61e49..5462cc6ea29 100644 --- a/Lib9c/Action/CancelProductRegistration.cs +++ b/Lib9c/Action/CancelProductRegistration.cs @@ -29,10 +29,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } if (!ProductInfos.Any()) { @@ -71,11 +67,11 @@ public override IAccount Execute(IActionContext context) { // cancel order before product registered case. var marketState = states.TryGetState(Addresses.Market, out List rawMarketList) - ? new MarketState(rawMarketList) - : new MarketState(); + ? rawMarketList + : List.Empty; productsState = new ProductsState(); - marketState.AvatarAddresses.Add(AvatarAddress); - states = states.SetState(Addresses.Market, marketState.Serialize()); + marketState = marketState.Add(AvatarAddress.Serialize()); + states = states.SetState(Addresses.Market, marketState); } var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); foreach (var productInfo in ProductInfos) diff --git a/Lib9c/Action/CancelProductRegistration0.cs b/Lib9c/Action/CancelProductRegistration0.cs index 65601d2b396..e913e91e943 100644 --- a/Lib9c/Action/CancelProductRegistration0.cs +++ b/Lib9c/Action/CancelProductRegistration0.cs @@ -30,10 +30,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } if (!ProductInfos.Any()) { @@ -79,11 +75,11 @@ public override IAccount Execute(IActionContext context) { // cancel order before product registered case. var marketState = states.TryGetState(Addresses.Market, out List rawMarketList) - ? new MarketState(rawMarketList) - : new MarketState(); + ? rawMarketList + : List.Empty; productsState = new ProductsState(); - marketState.AvatarAddresses.Add(AvatarAddress); - states = states.SetState(Addresses.Market, marketState.Serialize()); + marketState = marketState.Add(AvatarAddress.Serialize()); + states = states.SetState(Addresses.Market, marketState); } var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); foreach (var productInfo in ProductInfos) diff --git a/Lib9c/Action/ChargeActionPoint.cs b/Lib9c/Action/ChargeActionPoint.cs index fb9b92f5bbb..49e8811d3b3 100644 --- a/Lib9c/Action/ChargeActionPoint.cs +++ b/Lib9c/Action/ChargeActionPoint.cs @@ -38,16 +38,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - - if (context.Rehearsal) - { - return states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(avatarAddress, MarkChanged); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}ChargeActionPoint exec started", addressesHex); diff --git a/Lib9c/Action/ChargeActionPoint0.cs b/Lib9c/Action/ChargeActionPoint0.cs index 736a5a9be56..2b1be05e6ba 100644 --- a/Lib9c/Action/ChargeActionPoint0.cs +++ b/Lib9c/Action/ChargeActionPoint0.cs @@ -28,10 +28,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states.SetState(avatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ChargeActionPoint2.cs b/Lib9c/Action/ChargeActionPoint2.cs index 9c27aa9b092..3bfceed1281 100644 --- a/Lib9c/Action/ChargeActionPoint2.cs +++ b/Lib9c/Action/ChargeActionPoint2.cs @@ -27,10 +27,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states.SetState(avatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ClaimItems.cs b/Lib9c/Action/ClaimItems.cs index 77b49eb49e5..f4b06be2d3a 100644 --- a/Lib9c/Action/ClaimItems.cs +++ b/Lib9c/Action/ClaimItems.cs @@ -3,12 +3,14 @@ using System.Collections.Immutable; using System.Linq; using Bencodex.Types; +using Lib9c; using Libplanet.Action; using Libplanet.Action.State; using Libplanet.Crypto; using Libplanet.Types.Assets; using Nekoyume.Extensions; using Nekoyume.Model.Item; +using Nekoyume.Model.Mail; using Nekoyume.Model.State; using Nekoyume.TableData; using static Lib9c.SerializeKeys; @@ -19,26 +21,40 @@ namespace Nekoyume.Action public class ClaimItems : GameAction, IClaimItems { private const string ActionTypeText = "claim_items"; + private const int MaxClaimDataCount = 100; public IReadOnlyList<(Address address, IReadOnlyList fungibleAssetValues)> ClaimData { get; private set; } + public string Memo; public ClaimItems() { } - public ClaimItems(IReadOnlyList<(Address, IReadOnlyList)> claimData) + public ClaimItems(IReadOnlyList<(Address, IReadOnlyList)> claimData, string memo = null) { ClaimData = claimData; + Memo = memo; } protected override IImmutableDictionary PlainValueInternal => - ImmutableDictionary.Empty + GetPlainValueInternal(); + + private IImmutableDictionary GetPlainValueInternal() + { + var dict = ImmutableDictionary.Empty .Add(ClaimDataKey, ClaimData.Aggregate(List.Empty, (list, tuple) => { var serializedFungibleAssetValues = tuple.fungibleAssetValues.Select(x => x.Serialize()).Serialize(); return list.Add(new List(tuple.address.Bencoded, serializedFungibleAssetValues)); })); + if (!string.IsNullOrEmpty(Memo)) + { + dict = dict.Add(MemoKey, Memo.Serialize()); + } + + return dict; + } protected override void LoadPlainValueInternal( IImmutableDictionary plainValue) @@ -51,12 +67,31 @@ protected override void LoadPlainValueInternal( new Address(pair[0]), pair[1].ToList(x => x.ToFungibleAssetValue()) as IReadOnlyList); }).ToList(); + if (plainValue.ContainsKey(MemoKey)) + { + if (plainValue[MemoKey] is Text t && !string.IsNullOrEmpty(t)) + { + Memo = t; + } + else + { + throw new ArgumentException(nameof(PlainValue)); + } + } } public override IAccount Execute(IActionContext context) { context.UseGas(1); + if (ClaimData.Count > MaxClaimDataCount) + { + throw new ArgumentOutOfRangeException( + nameof(ClaimData), + ClaimData.Count, + $"ClaimData should be less than {MaxClaimDataCount}"); + } + var states = context.PreviousState; var random = context.GetRandom(); var itemSheet = states.GetSheets(containItemSheet: true).GetItemSheet(); @@ -65,44 +100,74 @@ public override IAccount Execute(IActionContext context) { var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var inventory = states.GetInventory(inventoryAddress) - ?? throw new FailedLoadStateException( - ActionTypeText, - GetSignerAndOtherAddressesHex(context, inventoryAddress), - typeof(Inventory), - inventoryAddress); + ?? throw new FailedLoadStateException( + ActionTypeText, + GetSignerAndOtherAddressesHex(context, inventoryAddress), + typeof(Inventory), + inventoryAddress); + if (!states.TryGetState(avatarAddress, out Dictionary avatarDict)) + { + throw new FailedLoadStateException(avatarAddress, typeof(AvatarState)); + } + var agentAddress = avatarDict[AgentAddressKey].ToAddress(); + var favs = new List(); + var items = new List<(int id, int count)>(); foreach (var fungibleAssetValue in fungibleAssetValues) { - if (fungibleAssetValue.Currency.DecimalPlaces != 0) + var tokenCurrency = fungibleAssetValue.Currency; + if (Currencies.IsWrappedCurrency(tokenCurrency)) { - throw new ArgumentException( - $"DecimalPlaces of fungibleAssetValue for claimItems are not 0: {fungibleAssetValue.Currency.Ticker}"); + var currency = Currencies.GetUnwrappedCurrency(tokenCurrency); + var recipientAddress = + Currencies.SelectRecipientAddress(currency, agentAddress, + avatarAddress); + var fav = FungibleAssetValue.FromRawValue(currency, fungibleAssetValue.RawValue); + states = states + .BurnAsset(context, context.Signer, fungibleAssetValue) + .MintAsset(context, recipientAddress, fav); + favs.Add(fav); } - - var parsedTicker = fungibleAssetValue.Currency.Ticker.Split("_"); - if (parsedTicker.Length != 3 - || parsedTicker[0] != "Item" - || (parsedTicker[1] != "NT" && parsedTicker[1] != "T") - || !int.TryParse(parsedTicker[2], out var itemId)) + else { - throw new ArgumentException( - $"Format of Amount currency's ticker is invalid"); + (bool tradable, int itemId) = Currencies.ParseItemCurrency(tokenCurrency); + states = states.BurnAsset(context, context.Signer, fungibleAssetValue); + var item = itemSheet[itemId] switch + { + MaterialItemSheet.Row materialRow => tradable + ? ItemFactory.CreateTradableMaterial(materialRow) + : ItemFactory.CreateMaterial(materialRow), + var itemRow => ItemFactory.CreateItem(itemRow, random) + }; + + // FIXME: This is an implementation bug in the Inventory class, + // but we'll deal with it temporarily here. + // If Pluggable AEV ever becomes a reality, + // it's only right that this is fixed in Inventory. + var itemCount = (int)fungibleAssetValue.RawValue; + if (item is INonFungibleItem) + { + foreach (var _ in Enumerable.Range(0, itemCount)) + { + inventory.AddItem(item, 1); + } + } + else + { + inventory.AddItem(item, itemCount); + } + items.Add((item.Id, itemCount)); } - - states = states.BurnAsset(context, context.Signer, fungibleAssetValue); - - var item = itemSheet[itemId] switch - { - MaterialItemSheet.Row materialRow => parsedTicker[1] == "T" - ? ItemFactory.CreateTradableMaterial(materialRow) - : ItemFactory.CreateMaterial(materialRow), - var itemRow => ItemFactory.CreateItem(itemRow, random) - }; - - inventory.AddItem(item, (int)fungibleAssetValue.RawValue); } - states = states.SetState(inventoryAddress, inventory.Serialize()); + var mailBox = new MailBox((List)avatarDict[MailBoxKey]); + var mail = new ClaimItemsMail(context.BlockIndex, random.GenerateRandomGuid(), context.BlockIndex, favs, items, Memo); + mailBox.Add(mail); + mailBox.CleanUp(); + avatarDict = avatarDict.SetItem(MailBoxKey, mailBox.Serialize()); + states = states + .SetState(inventoryAddress, inventory.Serialize()) + .SetState(avatarAddress, avatarDict); } return states; diff --git a/Lib9c/Action/ClaimMonsterCollectionReward.cs b/Lib9c/Action/ClaimMonsterCollectionReward.cs index 85bfb70c3c5..7abf842e7b9 100644 --- a/Lib9c/Action/ClaimMonsterCollectionReward.cs +++ b/Lib9c/Action/ClaimMonsterCollectionReward.cs @@ -47,19 +47,6 @@ public static IAccount Claim(IActionContext context, Address avatarAddress, stri var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}ClaimMonsterCollection exec started", addressesHex); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 0), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 1), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 2), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 3), MarkChanged); - } - if (!states.TryGetAgentAvatarStatesV2(context.Signer, avatarAddress, out AgentState agentState, out AvatarState avatarState, out _)) { throw new FailedLoadStateException($"Aborted as the avatar state of the signer failed to load."); diff --git a/Lib9c/Action/ClaimMonsterCollectionReward0.cs b/Lib9c/Action/ClaimMonsterCollectionReward0.cs index b82cfd089f0..52692d5a4b9 100644 --- a/Lib9c/Action/ClaimMonsterCollectionReward0.cs +++ b/Lib9c/Action/ClaimMonsterCollectionReward0.cs @@ -32,14 +32,6 @@ public override IAccount Execute(IActionContext context) IAccount states = context.PreviousState; Address collectionAddress = MonsterCollectionState0.DeriveAddress(context.Signer, collectionRound); - if (context.Rehearsal) - { - return states - .SetState(context.Signer, MarkChanged) - .SetState(avatarAddress, MarkChanged) - .SetState(collectionAddress, MarkChanged); - } - CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); if (!states.TryGetAgentAvatarStates(context.Signer, avatarAddress, out AgentState agentState, out AvatarState avatarState)) diff --git a/Lib9c/Action/ClaimMonsterCollectionReward2.cs b/Lib9c/Action/ClaimMonsterCollectionReward2.cs index fbe7ba910ad..00d2ef36039 100644 --- a/Lib9c/Action/ClaimMonsterCollectionReward2.cs +++ b/Lib9c/Action/ClaimMonsterCollectionReward2.cs @@ -33,19 +33,6 @@ public override IAccount Execute(IActionContext context) Address worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); Address questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 0), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 1), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 2), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 3), MarkChanged); - } - CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); if (!states.TryGetAgentAvatarStatesV2(context.Signer, avatarAddress, out AgentState agentState, out AvatarState avatarState, out _)) diff --git a/Lib9c/Action/ClaimRaidReward.cs b/Lib9c/Action/ClaimRaidReward.cs index 0df5dee0e85..eca61523643 100644 --- a/Lib9c/Action/ClaimRaidReward.cs +++ b/Lib9c/Action/ClaimRaidReward.cs @@ -37,10 +37,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; diff --git a/Lib9c/Action/ClaimStakeReward.cs b/Lib9c/Action/ClaimStakeReward.cs index 6cff524dd78..84b8d3bb50d 100644 --- a/Lib9c/Action/ClaimStakeReward.cs +++ b/Lib9c/Action/ClaimStakeReward.cs @@ -53,11 +53,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var stakeStateAddr = StakeState.DeriveAddress(context.Signer); diff --git a/Lib9c/Action/ClaimStakeReward2.cs b/Lib9c/Action/ClaimStakeReward2.cs index 4f1478a6cd8..53dc346a1fc 100644 --- a/Lib9c/Action/ClaimStakeReward2.cs +++ b/Lib9c/Action/ClaimStakeReward2.cs @@ -38,10 +38,6 @@ public ClaimStakeReward2() public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } var states = context.PreviousState; CheckObsolete(ObsoletedIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); diff --git a/Lib9c/Action/ClaimStakeReward3.cs b/Lib9c/Action/ClaimStakeReward3.cs index 8f4e22c109c..d70517af595 100644 --- a/Lib9c/Action/ClaimStakeReward3.cs +++ b/Lib9c/Action/ClaimStakeReward3.cs @@ -169,10 +169,6 @@ private IAccount ProcessReward( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } CheckActionAvailable(ClaimStakeReward2.ObsoletedIndex, context); CheckObsolete(ObsoleteBlockIndex, context); diff --git a/Lib9c/Action/ClaimStakeReward4.cs b/Lib9c/Action/ClaimStakeReward4.cs index fc3b176b45c..b308bfe3d22 100644 --- a/Lib9c/Action/ClaimStakeReward4.cs +++ b/Lib9c/Action/ClaimStakeReward4.cs @@ -127,11 +127,6 @@ public override IAccount Execute(IActionContext context) { CheckObsolete(ObsoleteBlockIndex, context); context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); if (!states.TryGetStakeState(context.Signer, out var stakeState)) diff --git a/Lib9c/Action/ClaimStakeReward5.cs b/Lib9c/Action/ClaimStakeReward5.cs index 7b067813c1a..e9c25f8303e 100644 --- a/Lib9c/Action/ClaimStakeReward5.cs +++ b/Lib9c/Action/ClaimStakeReward5.cs @@ -127,11 +127,6 @@ public override IAccount Execute(IActionContext context) { CheckObsolete(ObsoleteBlockIndex, context); context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); if (!states.TryGetStakeState(context.Signer, out var stakeState)) diff --git a/Lib9c/Action/ClaimStakeReward6.cs b/Lib9c/Action/ClaimStakeReward6.cs index 01138a3d4a9..0cd05be353a 100644 --- a/Lib9c/Action/ClaimStakeReward6.cs +++ b/Lib9c/Action/ClaimStakeReward6.cs @@ -202,11 +202,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); if (!states.TryGetStakeState(context.Signer, out var stakeState)) diff --git a/Lib9c/Action/ClaimStakeReward7.cs b/Lib9c/Action/ClaimStakeReward7.cs index c14f31636e5..a69f215ab7b 100644 --- a/Lib9c/Action/ClaimStakeReward7.cs +++ b/Lib9c/Action/ClaimStakeReward7.cs @@ -203,11 +203,6 @@ public override IAccount Execute(IActionContext context) { CheckObsolete(ObsoleteBlockIndex, context); context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); if (!states.TryGetStakeState(context.Signer, out var stakeState)) diff --git a/Lib9c/Action/ClaimStakeReward8.cs b/Lib9c/Action/ClaimStakeReward8.cs index 335d4065fda..3c8f08503a8 100644 --- a/Lib9c/Action/ClaimStakeReward8.cs +++ b/Lib9c/Action/ClaimStakeReward8.cs @@ -202,11 +202,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var states = context.PreviousState; var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); if (!states.TryGetStakeState(context.Signer, out var stakeState)) diff --git a/Lib9c/Action/ClaimWordBossKillReward.cs b/Lib9c/Action/ClaimWordBossKillReward.cs index 3fb56aa21ed..8e1e3df28ff 100644 --- a/Lib9c/Action/ClaimWordBossKillReward.cs +++ b/Lib9c/Action/ClaimWordBossKillReward.cs @@ -27,10 +27,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } Dictionary sheets = states.GetSheets(sheetTypes: new [] { typeof(WorldBossCharacterSheet), diff --git a/Lib9c/Action/CombinationConsumable.cs b/Lib9c/Action/CombinationConsumable.cs index 37d1a1ba969..f272ff0ff29 100644 --- a/Lib9c/Action/CombinationConsumable.cs +++ b/Lib9c/Action/CombinationConsumable.cs @@ -70,16 +70,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(context.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; diff --git a/Lib9c/Action/CombinationConsumable0.cs b/Lib9c/Action/CombinationConsumable0.cs index 9ef362b1263..8e0af591f1c 100644 --- a/Lib9c/Action/CombinationConsumable0.cs +++ b/Lib9c/Action/CombinationConsumable0.cs @@ -79,13 +79,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationConsumable2.cs b/Lib9c/Action/CombinationConsumable2.cs index e8b9f65501c..a05ee7422d8 100644 --- a/Lib9c/Action/CombinationConsumable2.cs +++ b/Lib9c/Action/CombinationConsumable2.cs @@ -79,13 +79,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationConsumable3.cs b/Lib9c/Action/CombinationConsumable3.cs index 01d4b2d35f9..9a86b85513c 100644 --- a/Lib9c/Action/CombinationConsumable3.cs +++ b/Lib9c/Action/CombinationConsumable3.cs @@ -79,13 +79,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationConsumable4.cs b/Lib9c/Action/CombinationConsumable4.cs index e1b9e2823ed..41eb8191baf 100644 --- a/Lib9c/Action/CombinationConsumable4.cs +++ b/Lib9c/Action/CombinationConsumable4.cs @@ -79,13 +79,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationConsumable5.cs b/Lib9c/Action/CombinationConsumable5.cs index c74b8e0481c..114633f3fe9 100644 --- a/Lib9c/Action/CombinationConsumable5.cs +++ b/Lib9c/Action/CombinationConsumable5.cs @@ -117,13 +117,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationConsumable6.cs b/Lib9c/Action/CombinationConsumable6.cs index 2335e584174..3ce1493bf56 100644 --- a/Lib9c/Action/CombinationConsumable6.cs +++ b/Lib9c/Action/CombinationConsumable6.cs @@ -78,16 +78,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationConsumable7.cs b/Lib9c/Action/CombinationConsumable7.cs index f5d7cd8569f..faeaae310f4 100644 --- a/Lib9c/Action/CombinationConsumable7.cs +++ b/Lib9c/Action/CombinationConsumable7.cs @@ -79,16 +79,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationConsumable8.cs b/Lib9c/Action/CombinationConsumable8.cs index dbe673e17b4..3260fc42280 100644 --- a/Lib9c/Action/CombinationConsumable8.cs +++ b/Lib9c/Action/CombinationConsumable8.cs @@ -74,16 +74,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(context.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; diff --git a/Lib9c/Action/CombinationEquipment.cs b/Lib9c/Action/CombinationEquipment.cs index 1812f35b0ee..c9053fbd0fd 100644 --- a/Lib9c/Action/CombinationEquipment.cs +++ b/Lib9c/Action/CombinationEquipment.cs @@ -97,10 +97,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; diff --git a/Lib9c/Action/CombinationEquipment0.cs b/Lib9c/Action/CombinationEquipment0.cs index 34d430919a7..a02f40ca6be 100644 --- a/Lib9c/Action/CombinationEquipment0.cs +++ b/Lib9c/Action/CombinationEquipment0.cs @@ -49,14 +49,6 @@ public override IAccount Execute(IActionContext context) SlotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment10.cs b/Lib9c/Action/CombinationEquipment10.cs index 6e863121f6e..47935703280 100644 --- a/Lib9c/Action/CombinationEquipment10.cs +++ b/Lib9c/Action/CombinationEquipment10.cs @@ -74,17 +74,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(context.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V100220ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment11.cs b/Lib9c/Action/CombinationEquipment11.cs index 60f7355f8e2..e8a7f0b0c1f 100644 --- a/Lib9c/Action/CombinationEquipment11.cs +++ b/Lib9c/Action/CombinationEquipment11.cs @@ -75,17 +75,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(context.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, ItemEnhancement10.GetFeeStoreAddress()); - } CheckObsolete(ActionObsoleteConfig.V100270ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment12.cs b/Lib9c/Action/CombinationEquipment12.cs index 7c95e62fe62..bb72fb2b853 100644 --- a/Lib9c/Action/CombinationEquipment12.cs +++ b/Lib9c/Action/CombinationEquipment12.cs @@ -83,10 +83,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment13.cs b/Lib9c/Action/CombinationEquipment13.cs index 4d0210aa40f..ea4eaeb514d 100644 --- a/Lib9c/Action/CombinationEquipment13.cs +++ b/Lib9c/Action/CombinationEquipment13.cs @@ -91,10 +91,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100282ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment14.cs b/Lib9c/Action/CombinationEquipment14.cs index b38d35b5b2b..51d248b6fa9 100644 --- a/Lib9c/Action/CombinationEquipment14.cs +++ b/Lib9c/Action/CombinationEquipment14.cs @@ -92,10 +92,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/CombinationEquipment15.cs b/Lib9c/Action/CombinationEquipment15.cs index 1ffa3681558..cc626d52961 100644 --- a/Lib9c/Action/CombinationEquipment15.cs +++ b/Lib9c/Action/CombinationEquipment15.cs @@ -92,10 +92,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/CombinationEquipment16.cs b/Lib9c/Action/CombinationEquipment16.cs index a2068fd7bf8..31ac61e9e7d 100644 --- a/Lib9c/Action/CombinationEquipment16.cs +++ b/Lib9c/Action/CombinationEquipment16.cs @@ -99,10 +99,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; diff --git a/Lib9c/Action/CombinationEquipment2.cs b/Lib9c/Action/CombinationEquipment2.cs index 2c18b7c1c45..c8c343ab233 100644 --- a/Lib9c/Action/CombinationEquipment2.cs +++ b/Lib9c/Action/CombinationEquipment2.cs @@ -49,14 +49,6 @@ public override IAccount Execute(IActionContext context) SlotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment3.cs b/Lib9c/Action/CombinationEquipment3.cs index 3d02d227445..f50da4718f9 100644 --- a/Lib9c/Action/CombinationEquipment3.cs +++ b/Lib9c/Action/CombinationEquipment3.cs @@ -49,14 +49,6 @@ public override IAccount Execute(IActionContext context) SlotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment4.cs b/Lib9c/Action/CombinationEquipment4.cs index cccb637d86c..de5a1f8ef18 100644 --- a/Lib9c/Action/CombinationEquipment4.cs +++ b/Lib9c/Action/CombinationEquipment4.cs @@ -49,14 +49,6 @@ public override IAccount Execute(IActionContext context) SlotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment5.cs b/Lib9c/Action/CombinationEquipment5.cs index 076e0ff05eb..c7dff1e535e 100644 --- a/Lib9c/Action/CombinationEquipment5.cs +++ b/Lib9c/Action/CombinationEquipment5.cs @@ -49,14 +49,6 @@ public override IAccount Execute(IActionContext context) SlotIndex ) ); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment6.cs b/Lib9c/Action/CombinationEquipment6.cs index d9a9c952cf1..f564c99f325 100644 --- a/Lib9c/Action/CombinationEquipment6.cs +++ b/Lib9c/Action/CombinationEquipment6.cs @@ -53,17 +53,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment7.cs b/Lib9c/Action/CombinationEquipment7.cs index e3cdf129013..98dd8b4c919 100644 --- a/Lib9c/Action/CombinationEquipment7.cs +++ b/Lib9c/Action/CombinationEquipment7.cs @@ -52,17 +52,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment8.cs b/Lib9c/Action/CombinationEquipment8.cs index 0844814a03f..226f11ac493 100644 --- a/Lib9c/Action/CombinationEquipment8.cs +++ b/Lib9c/Action/CombinationEquipment8.cs @@ -74,17 +74,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(context.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V100086ObsoleteIndex, context); diff --git a/Lib9c/Action/CombinationEquipment9.cs b/Lib9c/Action/CombinationEquipment9.cs index 79cd08f4f71..54e2d682dcc 100644 --- a/Lib9c/Action/CombinationEquipment9.cs +++ b/Lib9c/Action/CombinationEquipment9.cs @@ -74,17 +74,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged) - .SetState(context.Signer, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, BlacksmithAddress); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/Coupons/IssueCoupons.cs b/Lib9c/Action/Coupons/IssueCoupons.cs index e3c8aca247e..1e26c9014b4 100644 --- a/Lib9c/Action/Coupons/IssueCoupons.cs +++ b/Lib9c/Action/Coupons/IssueCoupons.cs @@ -31,13 +31,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states.SetCouponWallet( - Recipient, - ImmutableDictionary.Create(), - rehearsal: true); - } CheckPermission(context); diff --git a/Lib9c/Action/Coupons/RedeemCoupon.cs b/Lib9c/Action/Coupons/RedeemCoupon.cs index 334fffe0760..9e101450152 100644 --- a/Lib9c/Action/Coupons/RedeemCoupon.cs +++ b/Lib9c/Action/Coupons/RedeemCoupon.cs @@ -36,18 +36,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetCouponWallet( - context.Signer, - ImmutableDictionary.Create(), - rehearsal: true); - } if (!states.TryGetAvatarStateV2( context.Signer, diff --git a/Lib9c/Action/Coupons/TransferCoupons.cs b/Lib9c/Action/Coupons/TransferCoupons.cs index d51f35f328a..9771f666ef5 100644 --- a/Lib9c/Action/Coupons/TransferCoupons.cs +++ b/Lib9c/Action/Coupons/TransferCoupons.cs @@ -55,10 +55,10 @@ public override IAccount Execute(IActionContext context) recipientWallet = recipientWallet.Add(id, coupon); } - states = states.SetCouponWallet(recipient, recipientWallet, context.Rehearsal); + states = states.SetCouponWallet(recipient, recipientWallet); } - states = states.SetCouponWallet(context.Signer, signerWallet, context.Rehearsal); + states = states.SetCouponWallet(context.Signer, signerWallet); return states; } diff --git a/Lib9c/Action/CreateAvatar.cs b/Lib9c/Action/CreateAvatar.cs index ade2861fdbd..e49ff608e6a 100644 --- a/Lib9c/Action/CreateAvatar.cs +++ b/Lib9c/Action/CreateAvatar.cs @@ -81,28 +81,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, signer); - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/CreateAvatar0.cs b/Lib9c/Action/CreateAvatar0.cs index b5528a7dfac..38a38f44a17 100644 --- a/Lib9c/Action/CreateAvatar0.cs +++ b/Lib9c/Action/CreateAvatar0.cs @@ -75,26 +75,6 @@ public override IAccount Execute(IActionContext context) IActionContext ctx = context; var random = ctx.GetRandom(); var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(ctx.Signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(Addresses.Ranking, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, GoldCurrencyState.Address, context.Signer); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CreateAvatar10.cs b/Lib9c/Action/CreateAvatar10.cs index f9ab62f43b3..92da416a38e 100644 --- a/Lib9c/Action/CreateAvatar10.cs +++ b/Lib9c/Action/CreateAvatar10.cs @@ -82,28 +82,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, signer); - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/CreateAvatar2.cs b/Lib9c/Action/CreateAvatar2.cs index fa03444c080..7e53d31c4c6 100644 --- a/Lib9c/Action/CreateAvatar2.cs +++ b/Lib9c/Action/CreateAvatar2.cs @@ -72,26 +72,6 @@ public override IAccount Execute(IActionContext context) index ) ); - if (ctx.Rehearsal) - { - states = states.SetState(ctx.Signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(Addresses.Ranking, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, GoldCurrencyState.Address, context.Signer); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CreateAvatar3.cs b/Lib9c/Action/CreateAvatar3.cs index 76ed5c35044..8fe7191b0fc 100644 --- a/Lib9c/Action/CreateAvatar3.cs +++ b/Lib9c/Action/CreateAvatar3.cs @@ -71,29 +71,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(ctx.Signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(Addresses.Ranking, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, GoldCurrencyState.Address, context.Signer); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/CreateAvatar4.cs b/Lib9c/Action/CreateAvatar4.cs index c76e613825b..01520dd17e2 100644 --- a/Lib9c/Action/CreateAvatar4.cs +++ b/Lib9c/Action/CreateAvatar4.cs @@ -71,29 +71,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(ctx.Signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(Addresses.Ranking, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, GoldCurrencyState.Address, context.Signer); - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/CreateAvatar5.cs b/Lib9c/Action/CreateAvatar5.cs index d86a825077d..a5773f4f664 100644 --- a/Lib9c/Action/CreateAvatar5.cs +++ b/Lib9c/Action/CreateAvatar5.cs @@ -71,29 +71,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(ctx.Signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(Addresses.Ranking, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, GoldCurrencyState.Address, context.Signer); - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/CreateAvatar6.cs b/Lib9c/Action/CreateAvatar6.cs index 819f00185e5..78371b44326 100644 --- a/Lib9c/Action/CreateAvatar6.cs +++ b/Lib9c/Action/CreateAvatar6.cs @@ -71,29 +71,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(ctx.Signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(Addresses.Ranking, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, GoldCurrencyState.Address, context.Signer); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/CreateAvatar7.cs b/Lib9c/Action/CreateAvatar7.cs index 1abcab28627..502ec936e98 100644 --- a/Lib9c/Action/CreateAvatar7.cs +++ b/Lib9c/Action/CreateAvatar7.cs @@ -75,27 +75,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(ctx.Signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/CreateAvatar8.cs b/Lib9c/Action/CreateAvatar8.cs index 1fb99849ad6..54c5f872379 100644 --- a/Lib9c/Action/CreateAvatar8.cs +++ b/Lib9c/Action/CreateAvatar8.cs @@ -83,28 +83,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, signer); - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/CreateAvatar9.cs b/Lib9c/Action/CreateAvatar9.cs index 0ce97c4b6ba..9c8ebda7e90 100644 --- a/Lib9c/Action/CreateAvatar9.cs +++ b/Lib9c/Action/CreateAvatar9.cs @@ -82,28 +82,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(signer, MarkChanged); - for (var i = 0; i < AvatarState.CombinationSlotCapacity; i++) - { - var slotAddress = avatarAddress.Derive( - string.Format( - CultureInfo.InvariantCulture, - CombinationSlotState.DeriveFormat, - i - ) - ); - states = states.SetState(slotAddress, MarkChanged); - } - - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, signer); - } var itemSheetAddress = Addresses.GetSheetAddress(); var favSheetAddress = Addresses.GetSheetAddress(); diff --git a/Lib9c/Action/CreatePendingActivation.cs b/Lib9c/Action/CreatePendingActivation.cs index 1d9c3d3f651..efd4617853c 100644 --- a/Lib9c/Action/CreatePendingActivation.cs +++ b/Lib9c/Action/CreatePendingActivation.cs @@ -45,10 +45,6 @@ public CreatePendingActivation(PendingActivationState activationKey) public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState.SetState(PendingActivation.address, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); CheckPermission(context); diff --git a/Lib9c/Action/DailyReward.cs b/Lib9c/Action/DailyReward.cs index 3e43a887581..3a3513a9e45 100644 --- a/Lib9c/Action/DailyReward.cs +++ b/Lib9c/Action/DailyReward.cs @@ -32,13 +32,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, avatarAddress); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}DailyReward exec started", addressesHex); diff --git a/Lib9c/Action/DailyReward0.cs b/Lib9c/Action/DailyReward0.cs index 857329972c2..7c0bd82384e 100644 --- a/Lib9c/Action/DailyReward0.cs +++ b/Lib9c/Action/DailyReward0.cs @@ -25,10 +25,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - return states.SetState(avatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/DailyReward2.cs b/Lib9c/Action/DailyReward2.cs index 2297d8b718d..ab85458936e 100644 --- a/Lib9c/Action/DailyReward2.cs +++ b/Lib9c/Action/DailyReward2.cs @@ -32,10 +32,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - return states.SetState(avatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/DailyReward3.cs b/Lib9c/Action/DailyReward3.cs index ccf4f5c7c43..dc11297689f 100644 --- a/Lib9c/Action/DailyReward3.cs +++ b/Lib9c/Action/DailyReward3.cs @@ -31,10 +31,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - return states.SetState(avatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/DailyReward4.cs b/Lib9c/Action/DailyReward4.cs index 824c6014e2d..606a88db929 100644 --- a/Lib9c/Action/DailyReward4.cs +++ b/Lib9c/Action/DailyReward4.cs @@ -35,14 +35,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(avatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/DailyReward5.cs b/Lib9c/Action/DailyReward5.cs index 2b2fd9e7e8e..b0600691888 100644 --- a/Lib9c/Action/DailyReward5.cs +++ b/Lib9c/Action/DailyReward5.cs @@ -26,10 +26,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states.SetState(avatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/DailyReward6.cs b/Lib9c/Action/DailyReward6.cs index 7fad85616dd..37cef1a0ebd 100644 --- a/Lib9c/Action/DailyReward6.cs +++ b/Lib9c/Action/DailyReward6.cs @@ -36,15 +36,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, avatarAddress); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/EventConsumableItemCrafts.cs b/Lib9c/Action/EventConsumableItemCrafts.cs index 3be87289a3f..d07f8e07f42 100644 --- a/Lib9c/Action/EventConsumableItemCrafts.cs +++ b/Lib9c/Action/EventConsumableItemCrafts.cs @@ -83,11 +83,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Verbose( diff --git a/Lib9c/Action/EventConsumableItemCrafts0.cs b/Lib9c/Action/EventConsumableItemCrafts0.cs index c8d86ac9f90..dbc6987ebe5 100644 --- a/Lib9c/Action/EventConsumableItemCrafts0.cs +++ b/Lib9c/Action/EventConsumableItemCrafts0.cs @@ -82,11 +82,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); var states = context.PreviousState; var random = context.GetRandom(); - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Verbose( diff --git a/Lib9c/Action/EventDungeonBattle.cs b/Lib9c/Action/EventDungeonBattle.cs index ec984be1384..ddb71e8348c 100644 --- a/Lib9c/Action/EventDungeonBattle.cs +++ b/Lib9c/Action/EventDungeonBattle.cs @@ -119,11 +119,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Verbose( diff --git a/Lib9c/Action/EventDungeonBattleV1.cs b/Lib9c/Action/EventDungeonBattleV1.cs index e63f5ba9833..1cc9401927e 100644 --- a/Lib9c/Action/EventDungeonBattleV1.cs +++ b/Lib9c/Action/EventDungeonBattleV1.cs @@ -113,10 +113,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); diff --git a/Lib9c/Action/EventDungeonBattleV2.cs b/Lib9c/Action/EventDungeonBattleV2.cs index 447e9a17bad..6e459479f6a 100644 --- a/Lib9c/Action/EventDungeonBattleV2.cs +++ b/Lib9c/Action/EventDungeonBattleV2.cs @@ -113,10 +113,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100340ObsoleteIndex, context); diff --git a/Lib9c/Action/EventDungeonBattleV3.cs b/Lib9c/Action/EventDungeonBattleV3.cs index cb355470db3..df141596568 100644 --- a/Lib9c/Action/EventDungeonBattleV3.cs +++ b/Lib9c/Action/EventDungeonBattleV3.cs @@ -121,10 +121,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100360ObsoleteIndex, context); diff --git a/Lib9c/Action/EventDungeonBattleV4.cs b/Lib9c/Action/EventDungeonBattleV4.cs index 369657190f9..b852a2cbb9a 100644 --- a/Lib9c/Action/EventDungeonBattleV4.cs +++ b/Lib9c/Action/EventDungeonBattleV4.cs @@ -120,11 +120,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Verbose( diff --git a/Lib9c/Action/EventDungeonBattleV5.cs b/Lib9c/Action/EventDungeonBattleV5.cs index 5065a78dde1..58bb32109c3 100644 --- a/Lib9c/Action/EventDungeonBattleV5.cs +++ b/Lib9c/Action/EventDungeonBattleV5.cs @@ -121,11 +121,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); var states = context.PreviousState; var random = context.GetRandom(); - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Verbose( diff --git a/Lib9c/Action/EventMaterialItemCrafts.cs b/Lib9c/Action/EventMaterialItemCrafts.cs index 0e39c381a7f..882e21a887a 100644 --- a/Lib9c/Action/EventMaterialItemCrafts.cs +++ b/Lib9c/Action/EventMaterialItemCrafts.cs @@ -91,11 +91,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug( diff --git a/Lib9c/Action/EventMaterialItemCrafts0.cs b/Lib9c/Action/EventMaterialItemCrafts0.cs index e703804145a..89092de361d 100644 --- a/Lib9c/Action/EventMaterialItemCrafts0.cs +++ b/Lib9c/Action/EventMaterialItemCrafts0.cs @@ -89,11 +89,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug( diff --git a/Lib9c/Action/Garages/BulkUnloadFromGarages.cs b/Lib9c/Action/Garages/BulkUnloadFromGarages.cs new file mode 100644 index 00000000000..d6d6f5fcc6b --- /dev/null +++ b/Lib9c/Action/Garages/BulkUnloadFromGarages.cs @@ -0,0 +1,274 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Security.Cryptography; +using Bencodex.Types; +using Lib9c; +using Lib9c.Abstractions; +using Libplanet.Action; +using Libplanet.Action.State; +using Libplanet.Common; +using Libplanet.Crypto; +using Libplanet.Types.Assets; +using Nekoyume.Exceptions; +using Nekoyume.Model.Item; +using Nekoyume.Model.Mail; +using Nekoyume.Model.State; + +namespace Nekoyume.Action.Garages +{ + [ActionType("bulk_unload_from_garages")] + public class BulkUnloadFromGarages : GameAction, IBulkUnloadFromGaragesV1, IAction + { + public IReadOnlyList<( + Address recipientAvatarAddress, + IOrderedEnumerable<(Address balanceAddress, FungibleAssetValue value)>? + fungibleAssetValues, + IOrderedEnumerable<(HashDigest fungibleId, int count)>? fungibleIdAndCounts, + string? memo)> + UnloadData { get; private set; } + + public BulkUnloadFromGarages() + { + UnloadData = new List<( + Address recipientAvatarAddress, + IOrderedEnumerable<(Address balanceAddress, FungibleAssetValue value)>? + fungibleAssetValues, + IOrderedEnumerable<(HashDigest fungibleId, int count)>? + fungibleIdAndCounts, string? memo)>(); + } + + public BulkUnloadFromGarages( + IReadOnlyList<( + Address recipientAvatarAddress, + IEnumerable<(Address balanceAddress, FungibleAssetValue value)>? + fungibleAssetValues, + IEnumerable<(HashDigest fungibleId, int count)>? fungibleIdAndCounts, + string? memo)> unloadData) + { + UnloadData = unloadData.Select(data => ( + data.recipientAvatarAddress, + GarageUtils.MergeAndSort(data.fungibleAssetValues), + GarageUtils.MergeAndSort(data.fungibleIdAndCounts), + data.memo)).ToImmutableList(); + } + + protected override IImmutableDictionary PlainValueInternal => + new Dictionary + { + { + "l", + new List(UnloadData.Select(data => + new List(data.recipientAvatarAddress.Serialize(), + SerializeFungibleAssetValues(data.fungibleAssetValues), + SerializeFungibleIdAndCounts(data.fungibleIdAndCounts), + string.IsNullOrEmpty(data.memo) ? Null.Value : (Text)data.memo))) + } + }.ToImmutableDictionary(); + + protected override void LoadPlainValueInternal( + IImmutableDictionary plainValue) + { + var serialized = plainValue["l"]; + if (serialized is null or Null) + { + throw new ArgumentNullException(nameof(serialized)); + } + + if (serialized is not List list) + { + throw new ArgumentException( + $"The type of {nameof(serialized)} must be bencodex list."); + } + + UnloadData = list.Select(rawValue => + { + var value = rawValue as List + ?? throw new ArgumentException( + $"The type of {nameof(rawValue)} must be bencodex list."); + var recipientAvatarAddress = value[0].ToAddress(); + var fungibleAssetValues = + GarageUtils.MergeAndSort( + (value[1] as List)?.Select(raw => + { + var fungibleAssetValue = (List)raw; + return (fungibleAssetValue[0].ToAddress(), + fungibleAssetValue[1].ToFungibleAssetValue()); + })); + var fungibleIdAndCounts = + GarageUtils.MergeAndSort( + (value[2] as List)?.Select(raw => + { + var fungibleIdAndCount = (List)raw; + return ( + fungibleIdAndCount[0].ToItemId(), + (int)((Integer)fungibleIdAndCount[1]).Value); + })); + var memo = value[3].Kind == ValueKind.Null + ? null + : (string)(Text)value[3]; + + return (recipientAvatarAddress, fungibleAssetValues, fungibleIdAndCounts, memo); + }).ToList(); + } + + public override IAccount Execute(IActionContext context) + { + context.UseGas(1); + + var states = context.PreviousState; + if (context.Rehearsal) return states; + + // validate + var addressesHex = GetSignerAndOtherAddressesHex(context); + foreach (var unloadData in UnloadData) + { + if (unloadData.fungibleAssetValues is null && + unloadData.fungibleIdAndCounts is null) + { + throw new InvalidActionFieldException( + $"[{addressesHex}] Either FungibleAssetValues or FungibleIdAndCounts must be set."); + } + + if (unloadData.fungibleAssetValues?.Any(fav => fav.value.Sign <= 0) ?? false) + { + throw new InvalidActionFieldException( + $"[{addressesHex}] FungibleAssetValue.Sign must be positive"); + } + + if (unloadData.fungibleIdAndCounts?.Any(tuple => tuple.count <= 0) ?? false) + { + var invalid = unloadData.fungibleIdAndCounts.First(tuple => tuple.count < 0); + throw new InvalidActionFieldException( + $"[{addressesHex}] Count of fungible id must be positive. {invalid.fungibleId}, {invalid.count}"); + } + } + + // Execution + foreach (var ( + recipientAvatarAddress, + fungibleAssetValues, + fungibleIdAndCounts, + memo) + in UnloadData) + { + if (fungibleAssetValues is not null) + states = TransferFungibleAssetValues(context, states, fungibleAssetValues); + if (fungibleIdAndCounts is not null) + states = TransferFungibleItems(states, context.Signer, recipientAvatarAddress, + fungibleIdAndCounts); + } + + // Mailing + var random = context.GetRandom(); + states = BulkSendMail(context.BlockIndex, random, states); + + return states; + } + + private IAccount TransferFungibleAssetValues( + IActionContext context, + IAccount states, + IEnumerable<(Address balanceAddress, FungibleAssetValue value)> fungibleAssetValues) + { + var garageBalanceAddress = Addresses.GetGarageBalanceAddress(context.Signer); + foreach (var (balanceAddress, value) in fungibleAssetValues) + { + states = states.TransferAsset(context, garageBalanceAddress, balanceAddress, value); + } + + return states; + } + + private IAccount TransferFungibleItems( + IAccount states, + Address signer, + Address recipientAvatarAddress, + IEnumerable<(HashDigest fungibleId, int count)> fungibleIdAndCounts) + { + var inventoryAddress = recipientAvatarAddress.Derive(SerializeKeys.LegacyInventoryKey); + var inventory = states.GetInventory(inventoryAddress); + + var fungibleItemTuples = GarageUtils.WithGarageTuples( + signer, + states, + fungibleIdAndCounts); + foreach (var (_, count, garageAddress, garage) in fungibleItemTuples) + { + garage.Unload(count); + inventory.AddFungibleItem((ItemBase)garage.Item, count); + states = states.SetState(garageAddress, garage.Serialize()); + } + + return states.SetState(inventoryAddress, inventory.Serialize()); + } + + private IAccount BulkSendMail( + long blockIndex, + IRandom random, + IAccount states) + { + foreach (var tuple in UnloadData) + { + var ( + recipientAvatarAddress, + fungibleAssetValues, + fungibleIdAndCounts, + memo) = tuple; + var avatarValue = states.GetState(recipientAvatarAddress); + if (!(avatarValue is Dictionary avatarDict)) + { + throw new FailedLoadStateException(recipientAvatarAddress, typeof(AvatarState)); + } + + if (!avatarDict.ContainsKey(SerializeKeys.MailBoxKey)) + { + throw new KeyNotFoundException( + $"Dictionary key is not found: {SerializeKeys.MailBoxKey}"); + } + + var mailBox = new MailBox((List)avatarDict[SerializeKeys.MailBoxKey]) + { + new UnloadFromMyGaragesRecipientMail( + blockIndex, + random.GenerateRandomGuid(), + blockIndex, + fungibleAssetValues, + fungibleIdAndCounts, + memo) + }; + mailBox.CleanUp(); + avatarDict = avatarDict.SetItem(SerializeKeys.MailBoxKey, mailBox.Serialize()); + + return states.SetState(recipientAvatarAddress, avatarDict); + } + + return states; + } + + private static IValue SerializeFungibleAssetValues( + IOrderedEnumerable<(Address balanceAddress, FungibleAssetValue value)>? + fungibleAssetValues) + { + if (fungibleAssetValues is null) return Null.Value; + + return new List( + fungibleAssetValues.Select(tuple => new List( + tuple.balanceAddress.Serialize(), + tuple.value.Serialize()))); + } + + private static IValue SerializeFungibleIdAndCounts( + IOrderedEnumerable<(HashDigest fungibleId, int count)>? fungibleIdAndCounts) + { + if (fungibleIdAndCounts is null) return Null.Value; + + return new List( + fungibleIdAndCounts.Select(tuple => new List( + tuple.fungibleId.Serialize(), + (Integer)tuple.count))); + } + } +} diff --git a/Lib9c/Action/Garages/DeliverToOthersGarages.cs b/Lib9c/Action/Garages/DeliverToOthersGarages.cs index 28787beaff2..32b830ac635 100644 --- a/Lib9c/Action/Garages/DeliverToOthersGarages.cs +++ b/Lib9c/Action/Garages/DeliverToOthersGarages.cs @@ -165,11 +165,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var state = context.PreviousState; - if (context.Rehearsal) - { - return state; - } - var addressesHex = GetSignerAndOtherAddressesHex(context); ValidateFields(addressesHex); state = SendBalances(context, state); diff --git a/Lib9c/Action/Garages/LoadIntoMyGarages.cs b/Lib9c/Action/Garages/LoadIntoMyGarages.cs index 7c61522a317..71d68511c75 100644 --- a/Lib9c/Action/Garages/LoadIntoMyGarages.cs +++ b/Lib9c/Action/Garages/LoadIntoMyGarages.cs @@ -127,11 +127,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var state = context.PreviousState; - if (context.Rehearsal) - { - return state; - } - var addressesHex = GetSignerAndOtherAddressesHex(context); ValidateFields(context.Signer, addressesHex); diff --git a/Lib9c/Action/Garages/UnloadFromMyGarages.cs b/Lib9c/Action/Garages/UnloadFromMyGarages.cs index 2c1ca799ab7..961967afa00 100644 --- a/Lib9c/Action/Garages/UnloadFromMyGarages.cs +++ b/Lib9c/Action/Garages/UnloadFromMyGarages.cs @@ -122,11 +122,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var state = context.PreviousState; - if (context.Rehearsal) - { - return state; - } - var addressesHex = GetSignerAndOtherAddressesHex(context); ValidateFields(addressesHex); state = TransferFungibleAssetValues(context, state); diff --git a/Lib9c/Action/Grinding.cs b/Lib9c/Action/Grinding.cs index 39d994b0884..61c68d73a27 100644 --- a/Lib9c/Action/Grinding.cs +++ b/Lib9c/Action/Grinding.cs @@ -41,23 +41,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = EquipmentIds.Aggregate(states, - (current, guid) => - current.SetState(Addresses.GetItemAddress(guid), MarkChanged)); - return states - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 0), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 1), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 2), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 3), MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}Grinding exec started", addressesHex); diff --git a/Lib9c/Action/Grinding0.cs b/Lib9c/Action/Grinding0.cs index f6986523135..37a8233d3e9 100644 --- a/Lib9c/Action/Grinding0.cs +++ b/Lib9c/Action/Grinding0.cs @@ -41,23 +41,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = EquipmentIds.Aggregate(states, - (current, guid) => - current.SetState(Addresses.GetItemAddress(guid), MarkChanged)); - return states - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 0), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 1), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 2), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 3), MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}Grinding exec started", addressesHex); diff --git a/Lib9c/Action/HackAndSlash.cs b/Lib9c/Action/HackAndSlash.cs index 50e87a35fc4..c5323c991fd 100644 --- a/Lib9c/Action/HackAndSlash.cs +++ b/Lib9c/Action/HackAndSlash.cs @@ -99,11 +99,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - var random = context.GetRandom(); return Execute( context.PreviousState, diff --git a/Lib9c/Action/HackAndSlash0.cs b/Lib9c/Action/HackAndSlash0.cs index bcee7219d94..2d3999cb6b4 100644 --- a/Lib9c/Action/HackAndSlash0.cs +++ b/Lib9c/Action/HackAndSlash0.cs @@ -75,13 +75,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states.SetState(WeeklyArenaAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash10.cs b/Lib9c/Action/HackAndSlash10.cs index 86a08916f4c..e3af1088a5e 100644 --- a/Lib9c/Action/HackAndSlash10.cs +++ b/Lib9c/Action/HackAndSlash10.cs @@ -76,16 +76,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(rankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100170ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash11.cs b/Lib9c/Action/HackAndSlash11.cs index 914717cb5bd..606c2e44969 100644 --- a/Lib9c/Action/HackAndSlash11.cs +++ b/Lib9c/Action/HackAndSlash11.cs @@ -71,15 +71,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100190ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash12.cs b/Lib9c/Action/HackAndSlash12.cs index 061e1ed3d6b..f34d2784b0a 100644 --- a/Lib9c/Action/HackAndSlash12.cs +++ b/Lib9c/Action/HackAndSlash12.cs @@ -71,15 +71,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100260ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash13.cs b/Lib9c/Action/HackAndSlash13.cs index 55c41f5407f..ef9f37c91c4 100644 --- a/Lib9c/Action/HackAndSlash13.cs +++ b/Lib9c/Action/HackAndSlash13.cs @@ -75,15 +75,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ObsoletedBlockIndex, context); diff --git a/Lib9c/Action/HackAndSlash14.cs b/Lib9c/Action/HackAndSlash14.cs index 29f8334625c..ba8561c01a6 100644 --- a/Lib9c/Action/HackAndSlash14.cs +++ b/Lib9c/Action/HackAndSlash14.cs @@ -93,10 +93,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states; - } CheckObsolete(ObsoletedBlockIndex, context); diff --git a/Lib9c/Action/HackAndSlash16.cs b/Lib9c/Action/HackAndSlash16.cs index b74e061ddc0..f5f07c092ad 100644 --- a/Lib9c/Action/HackAndSlash16.cs +++ b/Lib9c/Action/HackAndSlash16.cs @@ -91,11 +91,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } - CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var random = context.GetRandom(); diff --git a/Lib9c/Action/HackAndSlash17.cs b/Lib9c/Action/HackAndSlash17.cs index c610ee77775..a8c6a0391a5 100644 --- a/Lib9c/Action/HackAndSlash17.cs +++ b/Lib9c/Action/HackAndSlash17.cs @@ -89,10 +89,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var random = context.GetRandom(); diff --git a/Lib9c/Action/HackAndSlash18.cs b/Lib9c/Action/HackAndSlash18.cs index 03ffcaf9ad0..ff7dc42b6a8 100644 --- a/Lib9c/Action/HackAndSlash18.cs +++ b/Lib9c/Action/HackAndSlash18.cs @@ -89,10 +89,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } CheckObsolete(ActionObsoleteConfig.V100340ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash19.cs b/Lib9c/Action/HackAndSlash19.cs index c319f24f401..e8f7c6944ad 100644 --- a/Lib9c/Action/HackAndSlash19.cs +++ b/Lib9c/Action/HackAndSlash19.cs @@ -94,10 +94,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } CheckObsolete(ActionObsoleteConfig.V100360ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash2.cs b/Lib9c/Action/HackAndSlash2.cs index 5152fdcf57e..7212d8cfc65 100644 --- a/Lib9c/Action/HackAndSlash2.cs +++ b/Lib9c/Action/HackAndSlash2.cs @@ -73,13 +73,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states.SetState(WeeklyArenaAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash20.cs b/Lib9c/Action/HackAndSlash20.cs index 1e72e7ce0b7..c159e321d59 100644 --- a/Lib9c/Action/HackAndSlash20.cs +++ b/Lib9c/Action/HackAndSlash20.cs @@ -101,10 +101,6 @@ protected override void LoadPlainValueInternal( public override IAccount Execute(IActionContext context) { context.UseGas(1); - if (context.Rehearsal) - { - return context.PreviousState; - } var random = context.GetRandom(); return Execute( diff --git a/Lib9c/Action/HackAndSlash21.cs b/Lib9c/Action/HackAndSlash21.cs index 9926128ec64..53f142d4ecd 100644 --- a/Lib9c/Action/HackAndSlash21.cs +++ b/Lib9c/Action/HackAndSlash21.cs @@ -101,10 +101,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var random = context.GetRandom(); - if (context.Rehearsal) - { - return context.PreviousState; - } return Execute( context.PreviousState, diff --git a/Lib9c/Action/HackAndSlash3.cs b/Lib9c/Action/HackAndSlash3.cs index 32e7b581255..c2e9eb94f80 100644 --- a/Lib9c/Action/HackAndSlash3.cs +++ b/Lib9c/Action/HackAndSlash3.cs @@ -73,13 +73,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states.SetState(WeeklyArenaAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash4.cs b/Lib9c/Action/HackAndSlash4.cs index 4b8804d496a..35a1ab97eab 100644 --- a/Lib9c/Action/HackAndSlash4.cs +++ b/Lib9c/Action/HackAndSlash4.cs @@ -73,13 +73,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states.SetState(WeeklyArenaAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash5.cs b/Lib9c/Action/HackAndSlash5.cs index 49e2d1efed8..ed94cf05f72 100644 --- a/Lib9c/Action/HackAndSlash5.cs +++ b/Lib9c/Action/HackAndSlash5.cs @@ -73,13 +73,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states.SetState(WeeklyArenaAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash6.cs b/Lib9c/Action/HackAndSlash6.cs index 6de84e46588..e32933b2fdd 100644 --- a/Lib9c/Action/HackAndSlash6.cs +++ b/Lib9c/Action/HackAndSlash6.cs @@ -77,17 +77,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states.SetState(WeeklyArenaAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash7.cs b/Lib9c/Action/HackAndSlash7.cs index 92a0ac6e210..bed7b64ed09 100644 --- a/Lib9c/Action/HackAndSlash7.cs +++ b/Lib9c/Action/HackAndSlash7.cs @@ -76,17 +76,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states.SetState(WeeklyArenaAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash8.cs b/Lib9c/Action/HackAndSlash8.cs index e01238e463f..7310211c6d8 100644 --- a/Lib9c/Action/HackAndSlash8.cs +++ b/Lib9c/Action/HackAndSlash8.cs @@ -72,16 +72,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(rankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100081ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlash9.cs b/Lib9c/Action/HackAndSlash9.cs index 11f7b0daf96..2801e507cb4 100644 --- a/Lib9c/Action/HackAndSlash9.cs +++ b/Lib9c/Action/HackAndSlash9.cs @@ -76,16 +76,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(rankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100086ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlashSweep.cs b/Lib9c/Action/HackAndSlashSweep.cs index 5bc3c94ef4e..a9834e14718 100644 --- a/Lib9c/Action/HackAndSlashSweep.cs +++ b/Lib9c/Action/HackAndSlashSweep.cs @@ -78,11 +78,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}HackAndSlashSweep exec started", addressesHex); diff --git a/Lib9c/Action/HackAndSlashSweep1.cs b/Lib9c/Action/HackAndSlashSweep1.cs index bea3a829c59..7e1b94bcde7 100644 --- a/Lib9c/Action/HackAndSlashSweep1.cs +++ b/Lib9c/Action/HackAndSlashSweep1.cs @@ -59,14 +59,6 @@ public override IAccount Execute(IActionContext context) var states = context.PreviousState; var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(inventoryAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(avatarAddress, MarkChanged) - .SetState(context.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100193ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlashSweep2.cs b/Lib9c/Action/HackAndSlashSweep2.cs index f44a11bedcc..f8b1268d960 100644 --- a/Lib9c/Action/HackAndSlashSweep2.cs +++ b/Lib9c/Action/HackAndSlashSweep2.cs @@ -59,14 +59,6 @@ public override IAccount Execute(IActionContext context) var states = context.PreviousState; var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(inventoryAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(avatarAddress, MarkChanged) - .SetState(context.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100200ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlashSweep3.cs b/Lib9c/Action/HackAndSlashSweep3.cs index 4b7f9b81a81..b6a50937c1c 100644 --- a/Lib9c/Action/HackAndSlashSweep3.cs +++ b/Lib9c/Action/HackAndSlashSweep3.cs @@ -75,14 +75,6 @@ public override IAccount Execute(IActionContext context) var states = context.PreviousState; var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(inventoryAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(avatarAddress, MarkChanged) - .SetState(context.Signer, MarkChanged); - } var arenaSheetAddress = Addresses.GetSheetAddress(); var arenaSheetState = states.GetState(arenaSheetAddress); diff --git a/Lib9c/Action/HackAndSlashSweep4.cs b/Lib9c/Action/HackAndSlashSweep4.cs index 5df83a6ba5b..4607ef7f24b 100644 --- a/Lib9c/Action/HackAndSlashSweep4.cs +++ b/Lib9c/Action/HackAndSlashSweep4.cs @@ -75,14 +75,6 @@ public override IAccount Execute(IActionContext context) var states = context.PreviousState; var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(inventoryAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(avatarAddress, MarkChanged) - .SetState(context.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100300ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlashSweep5.cs b/Lib9c/Action/HackAndSlashSweep5.cs index d6096596132..9a5fc2a81ae 100644 --- a/Lib9c/Action/HackAndSlashSweep5.cs +++ b/Lib9c/Action/HackAndSlashSweep5.cs @@ -74,10 +74,6 @@ public override IAccount Execute(IActionContext context) var states = context.PreviousState; var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100300ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlashSweep6.cs b/Lib9c/Action/HackAndSlashSweep6.cs index fdfbb7b7c6c..ed76cbea25a 100644 --- a/Lib9c/Action/HackAndSlashSweep6.cs +++ b/Lib9c/Action/HackAndSlashSweep6.cs @@ -74,10 +74,6 @@ public override IAccount Execute(IActionContext context) var states = context.PreviousState; var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/HackAndSlashSweep7.cs b/Lib9c/Action/HackAndSlashSweep7.cs index 9815e6af143..f243f8a141e 100644 --- a/Lib9c/Action/HackAndSlashSweep7.cs +++ b/Lib9c/Action/HackAndSlashSweep7.cs @@ -73,10 +73,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100340ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlashSweep8.cs b/Lib9c/Action/HackAndSlashSweep8.cs index e089d214164..db7a93bfa1d 100644 --- a/Lib9c/Action/HackAndSlashSweep8.cs +++ b/Lib9c/Action/HackAndSlashSweep8.cs @@ -79,10 +79,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100360ObsoleteIndex, context); diff --git a/Lib9c/Action/HackAndSlashSweep9.cs b/Lib9c/Action/HackAndSlashSweep9.cs index 1edec100113..963b806db01 100644 --- a/Lib9c/Action/HackAndSlashSweep9.cs +++ b/Lib9c/Action/HackAndSlashSweep9.cs @@ -80,10 +80,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); var states = context.PreviousState; var random = context.GetRandom(); - if (context.Rehearsal) - { - return states; - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; diff --git a/Lib9c/Action/InitializeStates.cs b/Lib9c/Action/InitializeStates.cs index 3cc1c5c7e67..a5e53ae3e7b 100644 --- a/Lib9c/Action/InitializeStates.cs +++ b/Lib9c/Action/InitializeStates.cs @@ -7,6 +7,7 @@ using Libplanet.Action; using Libplanet.Action.State; using Nekoyume.Model.State; +using Libplanet.Crypto; namespace Nekoyume.Action { @@ -53,6 +54,8 @@ public class InitializeStates : GameAction, IInitializeStatesV1 // This property can contain null: public Dictionary Credits { get; set; } + public ISet
AssetMinters { get; set; } + Dictionary IInitializeStatesV1.Ranking => Ranking; Dictionary IInitializeStatesV1.Shop => Shop; Dictionary IInitializeStatesV1.TableSheets => TableSheets; @@ -82,7 +85,8 @@ public InitializeStates( PendingActivationState[] pendingActivationStates, AdminState adminAddressState = null, AuthorizedMinersState authorizedMinersState = null, - CreditsState creditsState = null) + CreditsState creditsState = null, + ISet
assetMinters = null) { Ranking = (Dictionary)rankingState.Serialize(); Shop = (Dictionary)shopState.Serialize(); @@ -104,6 +108,11 @@ public InitializeStates( { Credits = (Dictionary)creditsState.Serialize(); } + + if (!(assetMinters is null)) + { + AssetMinters = assetMinters; + } } public override IAccount Execute(IActionContext context) @@ -114,37 +123,6 @@ public override IAccount Execute(IActionContext context) var weeklyArenaState = new WeeklyArenaState(0); var rankingState = new RankingState0(Ranking); - if (ctx.Rehearsal) - { - states = states.SetState(RankingState0.Address, MarkChanged); - states = states.SetState(ShopState.Address, MarkChanged); -#pragma warning disable LAA1002 - states = TableSheets - .Aggregate(states, (current, pair) => - current.SetState(Addresses.TableSheet.Derive(pair.Key), MarkChanged)); - states = rankingState.RankingMap - .Aggregate(states, (current, pair) => - current.SetState(pair.Key, MarkChanged)); -#pragma warning restore LAA1002 - states = states.SetState(weeklyArenaState.address, MarkChanged); - states = states.SetState(GameConfigState.Address, MarkChanged); - states = states.SetState(RedeemCodeState.Address, MarkChanged); - states = states.SetState(AdminState.Address, MarkChanged); - states = states.SetState(ActivatedAccountsState.Address, MarkChanged); - states = states.SetState(GoldCurrencyState.Address, MarkChanged); - states = states.SetState(Addresses.GoldDistribution, MarkChanged); - foreach (var rawPending in PendingActivations) - { - states = states.SetState( - new PendingActivationState((Dictionary)rawPending).address, - MarkChanged - ); - } - - states = states.SetState(AuthorizedMinersState.Address, MarkChanged); - states = states.SetState(CreditsState.Address, MarkChanged); - return states; - } if (ctx.BlockIndex != 0) { @@ -195,8 +173,24 @@ public override IAccount Execute(IActionContext context) states = states.SetState(CreditsState.Address, Credits); } - var currency = new GoldCurrencyState(GoldCurrency).Currency; - states = states.MintAsset(ctx, GoldCurrencyState.Address, currency * 1000000000); + var currencyState = new GoldCurrencyState(GoldCurrency); + if (currencyState.InitialSupply > 0) + { + states = states.MintAsset( + ctx, + GoldCurrencyState.Address, + currencyState.Currency * currencyState.InitialSupply + ); + } + + if (AssetMinters is { }) + { + states = states.SetState( + Addresses.AssetMinters, + new List(AssetMinters.Select(addr => addr.Serialize())) + ); + } + return states; } @@ -235,6 +229,11 @@ protected override IImmutableDictionary PlainValueInternal rv = rv.Add("credits_state", Credits); } + if (!(AssetMinters is null)) + { + rv = rv.Add("asset_minters", new List(AssetMinters.Select(addr => addr.Serialize()))); + } + return rv; } } @@ -269,6 +268,11 @@ protected override void LoadPlainValueInternal(IImmutableDictionary addr.ToAddress()).ToHashSet(); + } } } } diff --git a/Lib9c/Action/InvalidMinterException.cs b/Lib9c/Action/InvalidMinterException.cs new file mode 100644 index 00000000000..cf70e667844 --- /dev/null +++ b/Lib9c/Action/InvalidMinterException.cs @@ -0,0 +1,38 @@ +#nullable enable + +using System; +using System.Runtime.Serialization; +using Libplanet.Crypto; +using Libplanet.Common.Serialization; + +namespace Nekoyume.Action +{ + [Serializable] + public class InvalidMinterException : Exception + { + private Address _signer; + + public InvalidMinterException() + { + } + + + public InvalidMinterException(Address signer) + { + _signer = signer; + } + + protected InvalidMinterException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + _signer = new Address(info.GetValue(nameof(_signer))); + } + + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + + info.AddValue(nameof(_signer), _signer.ToByteArray()); + } + } +} diff --git a/Lib9c/Action/IssueTokensFromGarage.cs b/Lib9c/Action/IssueTokensFromGarage.cs new file mode 100644 index 00000000000..b5ea8ba2835 --- /dev/null +++ b/Lib9c/Action/IssueTokensFromGarage.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Bencodex.Types; +using Lib9c; +using Libplanet.Action; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Libplanet.Types.Assets; +using Nekoyume.Action.Garages; +using Nekoyume.Model; +using Nekoyume.Model.Item; +using Nekoyume.Model.State; +using Org.BouncyCastle.Asn1.Esf; + +namespace Nekoyume.Action +{ + [ActionType(TypeIdentifier)] + public class IssueTokensFromGarage : ActionBase + { + public const string TypeIdentifier = "issue_tokens_from_garage"; + + public IssueTokensFromGarage() + { + } + + public IssueTokensFromGarage(IEnumerable specs) + { + Specs = specs.ToList(); + } + + public override IValue PlainValue => + new Dictionary( + new[] + { + new KeyValuePair((Text)"type_id", (Text)TypeIdentifier), + new KeyValuePair( + (Text)"values", + Specs is { } + ? new List(Specs.Select(s => s.Serialize())) + : Null.Value + ) + } + ); + + public IEnumerable Specs { get; private set; } + + public override IAccount Execute(IActionContext context) + { + context.UseGas(1); + + if (Specs is null) + { + throw new InvalidOperationException(); + } + + IAccount state = context.PreviousState; + Address garageBalanceAddress = Addresses.GetGarageBalanceAddress(context.Signer); + + foreach (var (assets, items) in Specs) + { + if (assets is { } assetsNotNull) + { + state = state.BurnAsset( + context, + garageBalanceAddress, + assetsNotNull + ); + Currency wrappedCurrency = Currencies.GetWrappedCurrency(assetsNotNull.Currency); + state = state.MintAsset( + context, + context.Signer, + FungibleAssetValue.FromRawValue(wrappedCurrency, assetsNotNull.RawValue) + ); + } + + if (items is { } itemsNotNull) + { + var tuples = GarageUtils.WithGarageTuples( + context.Signer, + state, + new[] { (itemsNotNull.Id, itemsNotNull.Count) } + ); + foreach (var (_, count, garageAddr, garage) in tuples) + { + if (garage.Item is Material material) + { + garage.Unload(count); + state = state.SetState(garageAddr, garage.Serialize()); + var currency = Currencies.GetItemCurrency(material.Id, false); + state = state.MintAsset( + context, + context.Signer, + currency * count + ); + } + } + } + } + + return state; + } + + public override void LoadPlainValue(IValue plainValue) + { + var asDict = (Dictionary)plainValue; + Specs = ((List)asDict["values"]).Select(v => + { + return new Spec((List)v); + }).ToList(); + } + + public readonly struct Spec + { + public Spec(List bencoded) + : this( + bencoded[0] is List rawAssets ? rawAssets.ToFungibleAssetValue() : null, + bencoded[1] is List rawItems ? new FungibleItemValue(rawItems) : null + ) + { + } + + private Spec(FungibleAssetValue? assets, FungibleItemValue? items) + { + Assets = assets; + Items = items; + } + + public static Spec FromFungibleAssetValue(FungibleAssetValue assets) => + new(assets, null); + + public static Spec FromFungibleItemValue(FungibleItemValue items) => + new(null, items); + + public IValue Serialize() => new List( + Assets?.Serialize() ?? Null.Value, + Items?.Serialize() ?? Null.Value + ); + + internal void Deconstruct( + out FungibleAssetValue? assets, + out FungibleItemValue? items + ) + { + assets = Assets; + items = Items; + } + + public FungibleAssetValue? Assets { get; } + + public FungibleItemValue? Items { get; } + } + } +} diff --git a/Lib9c/Action/ItemEnhancement.cs b/Lib9c/Action/ItemEnhancement.cs index da9d121dd84..0b042ca0144 100644 --- a/Lib9c/Action/ItemEnhancement.cs +++ b/Lib9c/Action/ItemEnhancement.cs @@ -77,11 +77,6 @@ public override IAccount Execute(IActionContext context) var ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - return states; - } - // Collect addresses var slotAddress = avatarAddress.Derive( string.Format( diff --git a/Lib9c/Action/ItemEnhancement0.cs b/Lib9c/Action/ItemEnhancement0.cs index dd9550daa41..42f91ff0327 100644 --- a/Lib9c/Action/ItemEnhancement0.cs +++ b/Lib9c/Action/ItemEnhancement0.cs @@ -50,13 +50,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress) - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ItemEnhancement10.cs b/Lib9c/Action/ItemEnhancement10.cs index d6662e3cb7b..b217ccb2925 100644 --- a/Lib9c/Action/ItemEnhancement10.cs +++ b/Lib9c/Action/ItemEnhancement10.cs @@ -134,16 +134,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, GetFeeStoreAddress()) - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var arenaSheetAddress = Addresses.GetSheetAddress(); diff --git a/Lib9c/Action/ItemEnhancement11.cs b/Lib9c/Action/ItemEnhancement11.cs index 689689254c6..af87fa08e5d 100644 --- a/Lib9c/Action/ItemEnhancement11.cs +++ b/Lib9c/Action/ItemEnhancement11.cs @@ -137,11 +137,6 @@ public override IAccount Execute(IActionContext context) var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states; - } - var costSheetV3Address = Addresses.GetSheetAddress(); var sheetState = states.GetState(costSheetV3Address); if (sheetState != null) diff --git a/Lib9c/Action/ItemEnhancement12.cs b/Lib9c/Action/ItemEnhancement12.cs index 56c18f4e26d..f7d64164395 100644 --- a/Lib9c/Action/ItemEnhancement12.cs +++ b/Lib9c/Action/ItemEnhancement12.cs @@ -133,11 +133,6 @@ public override IAccount Execute(IActionContext context) var ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - return states; - } - // Collect addresses var slotAddress = avatarAddress.Derive( string.Format( diff --git a/Lib9c/Action/ItemEnhancement13.cs b/Lib9c/Action/ItemEnhancement13.cs index 241e3347bba..9d7fa89cbb6 100644 --- a/Lib9c/Action/ItemEnhancement13.cs +++ b/Lib9c/Action/ItemEnhancement13.cs @@ -134,11 +134,6 @@ public override IAccount Execute(IActionContext context) var states = ctx.PreviousState; var random = context.GetRandom(); - if (ctx.Rehearsal) - { - return states; - } - // Collect addresses var slotAddress = avatarAddress.Derive( string.Format( diff --git a/Lib9c/Action/ItemEnhancement2.cs b/Lib9c/Action/ItemEnhancement2.cs index d92288eeb39..4f51c548301 100644 --- a/Lib9c/Action/ItemEnhancement2.cs +++ b/Lib9c/Action/ItemEnhancement2.cs @@ -50,13 +50,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress) - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ItemEnhancement3.cs b/Lib9c/Action/ItemEnhancement3.cs index a97526733f1..5835b47fdb0 100644 --- a/Lib9c/Action/ItemEnhancement3.cs +++ b/Lib9c/Action/ItemEnhancement3.cs @@ -50,13 +50,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress) - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ItemEnhancement4.cs b/Lib9c/Action/ItemEnhancement4.cs index c3178a55a36..a3485318739 100644 --- a/Lib9c/Action/ItemEnhancement4.cs +++ b/Lib9c/Action/ItemEnhancement4.cs @@ -48,13 +48,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress) - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ItemEnhancement5.cs b/Lib9c/Action/ItemEnhancement5.cs index 490943c600d..746bc49b33c 100644 --- a/Lib9c/Action/ItemEnhancement5.cs +++ b/Lib9c/Action/ItemEnhancement5.cs @@ -48,13 +48,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress) - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ItemEnhancement6.cs b/Lib9c/Action/ItemEnhancement6.cs index aa294d28e52..74c25a2240f 100644 --- a/Lib9c/Action/ItemEnhancement6.cs +++ b/Lib9c/Action/ItemEnhancement6.cs @@ -50,13 +50,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress) - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ItemEnhancement7.cs b/Lib9c/Action/ItemEnhancement7.cs index c11a28d4b1f..0281b0fde18 100644 --- a/Lib9c/Action/ItemEnhancement7.cs +++ b/Lib9c/Action/ItemEnhancement7.cs @@ -90,16 +90,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress) - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ItemEnhancement8.cs b/Lib9c/Action/ItemEnhancement8.cs index 10132619224..33c89d53aa6 100644 --- a/Lib9c/Action/ItemEnhancement8.cs +++ b/Lib9c/Action/ItemEnhancement8.cs @@ -54,16 +54,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress) - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/ItemEnhancement9.cs b/Lib9c/Action/ItemEnhancement9.cs index 838a87d8e21..d0caf06bfc2 100644 --- a/Lib9c/Action/ItemEnhancement9.cs +++ b/Lib9c/Action/ItemEnhancement9.cs @@ -130,16 +130,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, BlacksmithAddress) - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100220ObsoleteIndex, context); diff --git a/Lib9c/Action/JoinArena.cs b/Lib9c/Action/JoinArena.cs index 9be265d12de..fa03c5726c4 100644 --- a/Lib9c/Action/JoinArena.cs +++ b/Lib9c/Action/JoinArena.cs @@ -70,11 +70,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}JoinArena exec started", addressesHex); diff --git a/Lib9c/Action/JoinArena1.cs b/Lib9c/Action/JoinArena1.cs index 3e6228a7d13..0b27ba1fb9b 100644 --- a/Lib9c/Action/JoinArena1.cs +++ b/Lib9c/Action/JoinArena1.cs @@ -65,10 +65,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } if (championshipId > 2) { diff --git a/Lib9c/Action/JoinArena2.cs b/Lib9c/Action/JoinArena2.cs index 6f4b7ec28dc..f7eae1b27d7 100644 --- a/Lib9c/Action/JoinArena2.cs +++ b/Lib9c/Action/JoinArena2.cs @@ -71,10 +71,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100360ObsoleteIndex, context); diff --git a/Lib9c/Action/JoinArena3.cs b/Lib9c/Action/JoinArena3.cs index 6616e27cd21..5e5184d6101 100644 --- a/Lib9c/Action/JoinArena3.cs +++ b/Lib9c/Action/JoinArena3.cs @@ -71,11 +71,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}JoinArena exec started", addressesHex); diff --git a/Lib9c/Action/MigrationActivatedAccountsState.cs b/Lib9c/Action/MigrationActivatedAccountsState.cs index df6739e5e4c..98ee40e5a96 100644 --- a/Lib9c/Action/MigrationActivatedAccountsState.cs +++ b/Lib9c/Action/MigrationActivatedAccountsState.cs @@ -22,10 +22,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states.SetState(Nekoyume.Addresses.ActivatedAccount, MarkChanged); - } CheckPermission(context); diff --git a/Lib9c/Action/MigrationAvatarState.cs b/Lib9c/Action/MigrationAvatarState.cs index 2e4a45474ce..33c969ebb2a 100644 --- a/Lib9c/Action/MigrationAvatarState.cs +++ b/Lib9c/Action/MigrationAvatarState.cs @@ -26,10 +26,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckPermission(context); diff --git a/Lib9c/Action/MigrationLegacyShop.cs b/Lib9c/Action/MigrationLegacyShop.cs index 74ecbc303d8..81a4a20d922 100644 --- a/Lib9c/Action/MigrationLegacyShop.cs +++ b/Lib9c/Action/MigrationLegacyShop.cs @@ -30,19 +30,6 @@ public override IAccount Execute(IActionContext context) var states = context.PreviousState; var sellerAvatarAddresses = _avatarAddressesHex.Select(a => new Address(a)).ToList(); - if (context.Rehearsal) - { - foreach (var avatarAddress in sellerAvatarAddresses) - { - var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(avatarAddress, MarkChanged); - } - - return states.SetState(Addresses.Shop, MarkChanged); - } - CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); CheckPermission(context); diff --git a/Lib9c/Action/MigrationLegacyShop0.cs b/Lib9c/Action/MigrationLegacyShop0.cs index a38fa660a42..283ff9a8ebb 100644 --- a/Lib9c/Action/MigrationLegacyShop0.cs +++ b/Lib9c/Action/MigrationLegacyShop0.cs @@ -23,14 +23,6 @@ public override IAccount Execute(IActionContext context) var states = context.PreviousState; var sellerAvatarAddresses = _avatarAddressesHex.Select(a => new Address(a)).ToList(); - if (context.Rehearsal) - { - states = sellerAvatarAddresses.Aggregate(states, - (current, sellerAvatarAddress) => current.SetState(sellerAvatarAddress, MarkChanged)); - - return states.SetState(Addresses.Shop, MarkChanged); - } - CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); CheckPermission(context); diff --git a/Lib9c/Action/MimisbrunnrBattle.cs b/Lib9c/Action/MimisbrunnrBattle.cs index 131262f6c57..1569effa054 100644 --- a/Lib9c/Action/MimisbrunnrBattle.cs +++ b/Lib9c/Action/MimisbrunnrBattle.cs @@ -85,10 +85,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); diff --git a/Lib9c/Action/MimisbrunnrBattle0.cs b/Lib9c/Action/MimisbrunnrBattle0.cs index fad076b425b..49ecdfe3cc2 100644 --- a/Lib9c/Action/MimisbrunnrBattle0.cs +++ b/Lib9c/Action/MimisbrunnrBattle0.cs @@ -74,12 +74,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - return states.SetState(WeeklyArenaAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/MimisbrunnrBattle10.cs b/Lib9c/Action/MimisbrunnrBattle10.cs index c56c05227b6..a5341726603 100644 --- a/Lib9c/Action/MimisbrunnrBattle10.cs +++ b/Lib9c/Action/MimisbrunnrBattle10.cs @@ -76,10 +76,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/MimisbrunnrBattle11.cs b/Lib9c/Action/MimisbrunnrBattle11.cs index 17253ea84a1..dcfede31df8 100644 --- a/Lib9c/Action/MimisbrunnrBattle11.cs +++ b/Lib9c/Action/MimisbrunnrBattle11.cs @@ -85,10 +85,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100360ObsoleteIndex, context); diff --git a/Lib9c/Action/MimisbrunnrBattle12.cs b/Lib9c/Action/MimisbrunnrBattle12.cs index 2c22b0b86e8..1aa7d4f0819 100644 --- a/Lib9c/Action/MimisbrunnrBattle12.cs +++ b/Lib9c/Action/MimisbrunnrBattle12.cs @@ -86,10 +86,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states; - } var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var sw = new Stopwatch(); diff --git a/Lib9c/Action/MimisbrunnrBattle2.cs b/Lib9c/Action/MimisbrunnrBattle2.cs index 66bbb6241e7..1c5f70dd7ac 100644 --- a/Lib9c/Action/MimisbrunnrBattle2.cs +++ b/Lib9c/Action/MimisbrunnrBattle2.cs @@ -74,12 +74,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - return states.SetState(WeeklyArenaAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/MimisbrunnrBattle3.cs b/Lib9c/Action/MimisbrunnrBattle3.cs index b9e4f0bae60..28e4a7ee307 100644 --- a/Lib9c/Action/MimisbrunnrBattle3.cs +++ b/Lib9c/Action/MimisbrunnrBattle3.cs @@ -74,12 +74,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - return states.SetState(WeeklyArenaAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/MimisbrunnrBattle4.cs b/Lib9c/Action/MimisbrunnrBattle4.cs index 9ca20fb5137..495fbcf1b6e 100644 --- a/Lib9c/Action/MimisbrunnrBattle4.cs +++ b/Lib9c/Action/MimisbrunnrBattle4.cs @@ -76,16 +76,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(RankingMapAddress, MarkChanged); - states = states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(WeeklyArenaAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/MimisbrunnrBattle5.cs b/Lib9c/Action/MimisbrunnrBattle5.cs index 4179f76609a..030a7d058a9 100644 --- a/Lib9c/Action/MimisbrunnrBattle5.cs +++ b/Lib9c/Action/MimisbrunnrBattle5.cs @@ -70,16 +70,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(rankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100083ObsoleteIndex, context); diff --git a/Lib9c/Action/MimisbrunnrBattle6.cs b/Lib9c/Action/MimisbrunnrBattle6.cs index fbbb9d8e2a1..9792d22ff37 100644 --- a/Lib9c/Action/MimisbrunnrBattle6.cs +++ b/Lib9c/Action/MimisbrunnrBattle6.cs @@ -74,16 +74,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(rankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100086ObsoleteIndex, context); diff --git a/Lib9c/Action/MimisbrunnrBattle7.cs b/Lib9c/Action/MimisbrunnrBattle7.cs index 366b51f1d70..d5fbba984d5 100644 --- a/Lib9c/Action/MimisbrunnrBattle7.cs +++ b/Lib9c/Action/MimisbrunnrBattle7.cs @@ -74,16 +74,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(rankingMapAddress, MarkChanged); - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100170ObsoleteIndex, context); diff --git a/Lib9c/Action/MimisbrunnrBattle8.cs b/Lib9c/Action/MimisbrunnrBattle8.cs index e11a3f79653..aa9f3f16d17 100644 --- a/Lib9c/Action/MimisbrunnrBattle8.cs +++ b/Lib9c/Action/MimisbrunnrBattle8.cs @@ -76,15 +76,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ObsoletedBlockIndex, context); diff --git a/Lib9c/Action/MimisbrunnrBattle9.cs b/Lib9c/Action/MimisbrunnrBattle9.cs index 17fb1a5a481..3e6cc2a2101 100644 --- a/Lib9c/Action/MimisbrunnrBattle9.cs +++ b/Lib9c/Action/MimisbrunnrBattle9.cs @@ -75,15 +75,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - states = states.SetState(avatarAddress, MarkChanged); - states = states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100340ObsoleteIndex, context); diff --git a/Lib9c/Action/MintAssets.cs b/Lib9c/Action/MintAssets.cs new file mode 100644 index 00000000000..ceedc8f433d --- /dev/null +++ b/Lib9c/Action/MintAssets.cs @@ -0,0 +1,231 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Linq; +using Bencodex.Types; +using Lib9c; +using Libplanet.Action; +using Libplanet.Action.State; +using Libplanet.Crypto; +using Libplanet.Types.Assets; +using Nekoyume.Model; +using Nekoyume.Model.Item; +using Nekoyume.Model.Mail; +using Nekoyume.Model.State; +using Nekoyume.TableData; + +namespace Nekoyume.Action +{ + [ActionType(TypeIdentifier)] + public class MintAssets : ActionBase + { + public const string TypeIdentifier = "mint_assets"; + + public MintAssets() + { + } + + public MintAssets(IEnumerable specs, string? memo) + { + MintSpecs = specs.ToList(); + Memo = memo; + } + + public override IAccount Execute(IActionContext context) + { + context.UseGas(1); + + if (MintSpecs is null) + { + throw new InvalidOperationException(); + } + + IAccount state = context.PreviousState; + HashSet
allowed = new(); + + if (state.TryGetState(Addresses.Admin, out Dictionary rawDict)) + { + allowed.Add(new AdminState(rawDict).AdminAddress); + } + + if (state.TryGetState(Addresses.AssetMinters, out List minters)) + { + allowed.UnionWith(minters.Select(m => m.ToAddress())); + } + + if (!allowed.Contains(context.Signer)) + { + throw new InvalidMinterException(context.Signer); + } + + Dictionary, List)> mailRecords = new(); + + foreach (var (recipient, assets, items) in MintSpecs) + { + if (!mailRecords.TryGetValue(recipient, out var records)) + { + mailRecords[recipient] = records = new( + new List(), + new List() + ); + } + + (List favs, List fivs) = records; + + if (assets is { } assetsNotNull) + { + state = state.MintAsset(context, recipient, assetsNotNull); + favs.Add(assetsNotNull); + } + + if (items is { } itemsNotNull) + { + Address inventoryAddr = recipient.Derive(SerializeKeys.LegacyInventoryKey); + Inventory inventory = state.GetInventory(inventoryAddr); + MaterialItemSheet itemSheet = state.GetSheet(); + if (itemSheet is null || itemSheet.OrderedList is null) + { + throw new InvalidOperationException(); + } + + foreach (MaterialItemSheet.Row row in itemSheet.OrderedList) + { + if (row.ItemId.Equals(itemsNotNull.Id)) + { + Material item = ItemFactory.CreateMaterial(row); + inventory.AddFungibleItem(item, itemsNotNull.Count); + } + } + + state = state.SetState(inventoryAddr, inventory.Serialize()); + fivs.Add(itemsNotNull); + } + } + + IRandom rng = context.GetRandom(); + foreach (var recipient in mailRecords.Keys) + { + if ( + state.GetState(recipient) is Dictionary dict && + dict.TryGetValue((Text)SerializeKeys.MailBoxKey, out IValue rawMailBox) + ) + { + var mailBox = new MailBox((List)rawMailBox); + (List favs, List fivs) = mailRecords[recipient]; + mailBox.Add( + new UnloadFromMyGaragesRecipientMail( + context.BlockIndex, + rng.GenerateRandomGuid(), + context.BlockIndex, + favs.Select(v => (recipient, v)), + fivs.Select(v => (v.Id, v.Count)), + Memo + ) + ); + mailBox.CleanUp(); + dict = dict.SetItem(SerializeKeys.MailBoxKey, mailBox.Serialize()); + state = state.SetState(recipient, dict); + } + } + + return state; + } + + public override void LoadPlainValue(IValue plainValue) + { + var asDict = (Dictionary)plainValue; + var asList = (List)asDict["values"]; + + if (asList[0] is Text memo) + { + Memo = memo; + } + else + { + Memo = null; + } + + MintSpecs = asList.Skip(1).Select(v => + { + return new MintSpec((List)v); + }).ToList(); + } + + public override IValue PlainValue + { + get + { + var values = new List + { + Memo is { } memoNotNull ? (Text)memoNotNull : Null.Value + }; + if (MintSpecs is { } mintSpecsNotNull) + { + values.AddRange(mintSpecsNotNull.Select(s => s.Serialize())); + } + + return new Dictionary( + new[] + { + new KeyValuePair((Text)"type_id", (Text)TypeIdentifier), + new KeyValuePair((Text)"values", new List(values)) + } + ); + } + } + + public List? MintSpecs + { + get; + private set; + } + + public string? Memo { get; private set; } + + public readonly struct MintSpec + { + public MintSpec(List bencoded) + : this( + bencoded[0].ToAddress(), + bencoded[1] is List rawAssets ? rawAssets.ToFungibleAssetValue() : null, + bencoded[2] is List rawItems ? new FungibleItemValue(rawItems) : null + ) + { + } + + public MintSpec( + Address recipient, + FungibleAssetValue? assets, + FungibleItemValue? items + ) + { + Recipient = recipient; + Assets = assets; + Items = items; + } + + public IValue Serialize() => new List( + Recipient.Serialize(), + Assets?.Serialize() ?? Null.Value, + Items?.Serialize() ?? Null.Value + ); + + internal void Deconstruct( + out Address recipient, + out FungibleAssetValue? assets, + out FungibleItemValue? items + ) + { + recipient = Recipient; + assets = Assets; + items = Items; + } + + public Address Recipient { get; } + public FungibleAssetValue? Assets { get; } + public FungibleItemValue? Items { get; } + + } + } +} diff --git a/Lib9c/Action/MonsterCollect.cs b/Lib9c/Action/MonsterCollect.cs index 5ebf4d83c9d..3f5235a1668 100644 --- a/Lib9c/Action/MonsterCollect.cs +++ b/Lib9c/Action/MonsterCollect.cs @@ -31,20 +31,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 0), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 1), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 2), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 3), MarkChanged) - .SetState(context.Signer, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 0)) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 1)) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 2)) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 3)); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, context.Signer); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}MonsterCollect exec started", addressesHex); diff --git a/Lib9c/Action/MonsterCollect0.cs b/Lib9c/Action/MonsterCollect0.cs index 9e5ac8b2d86..a0c57dd0370 100644 --- a/Lib9c/Action/MonsterCollect0.cs +++ b/Lib9c/Action/MonsterCollect0.cs @@ -29,13 +29,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IAccount states = context.PreviousState; Address monsterCollectionAddress = MonsterCollectionState0.DeriveAddress(context.Signer, collectionRound); - if (context.Rehearsal) - { - return states - .SetState(monsterCollectionAddress, MarkChanged) - .SetState(context.Signer, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, monsterCollectionAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/MonsterCollect2.cs b/Lib9c/Action/MonsterCollect2.cs index a1765fb60f0..999df1ad86b 100644 --- a/Lib9c/Action/MonsterCollect2.cs +++ b/Lib9c/Action/MonsterCollect2.cs @@ -26,19 +26,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 0), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 1), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 2), MarkChanged) - .SetState(MonsterCollectionState.DeriveAddress(context.Signer, 3), MarkChanged) - .SetState(context.Signer, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 0)) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 1)) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 2)) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, MonsterCollectionState.DeriveAddress(context.Signer, 3)); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/PatchTableSheet.cs b/Lib9c/Action/PatchTableSheet.cs index 4ac1a61c44b..4b6a187fde9 100644 --- a/Lib9c/Action/PatchTableSheet.cs +++ b/Lib9c/Action/PatchTableSheet.cs @@ -43,13 +43,6 @@ public override IAccount Execute(IActionContext context) IActionContext ctx = context; var states = ctx.PreviousState; var sheetAddress = Addresses.TableSheet.Derive(TableName); - if (ctx.Rehearsal) - { - return states - .SetState(sheetAddress, MarkChanged) - .SetState(GameConfigState.Address, MarkChanged); - } - var addressesHex = GetSignerAndOtherAddressesHex(context); #if !LIB9C_DEV_EXTENSIONS && !UNITY_EDITOR diff --git a/Lib9c/Action/PetEnhancement.cs b/Lib9c/Action/PetEnhancement.cs index 4299ef0d2b3..d82e4d841f8 100644 --- a/Lib9c/Action/PetEnhancement.cs +++ b/Lib9c/Action/PetEnhancement.cs @@ -43,11 +43,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addresses = GetSignerAndOtherAddressesHex(context, AvatarAddress); // NOTE: The `AvatarAddress` must contained in `Signer`'s `AgentState.avatarAddresses`. if (!Addresses.CheckAvatarAddrIsContainedInAgent(context.Signer, AvatarAddress)) diff --git a/Lib9c/Action/PrepareRewardAssets.cs b/Lib9c/Action/PrepareRewardAssets.cs index c5d2499cbd9..017e94e6330 100644 --- a/Lib9c/Action/PrepareRewardAssets.cs +++ b/Lib9c/Action/PrepareRewardAssets.cs @@ -46,13 +46,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - foreach (var asset in Assets) - { - return states.MarkBalanceChanged(context, asset.Currency, RewardPoolAddress); - } - } CheckPermission(context); diff --git a/Lib9c/Action/Raid.cs b/Lib9c/Action/Raid.cs index 097252d1b31..f28daa0ca61 100644 --- a/Lib9c/Action/Raid.cs +++ b/Lib9c/Action/Raid.cs @@ -46,11 +46,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressHex}Raid exec started", addressHex); diff --git a/Lib9c/Action/Raid1.cs b/Lib9c/Action/Raid1.cs index d141be667ba..6bc5454a27c 100644 --- a/Lib9c/Action/Raid1.cs +++ b/Lib9c/Action/Raid1.cs @@ -39,10 +39,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100360ObsoleteIndex, context); diff --git a/Lib9c/Action/Raid2.cs b/Lib9c/Action/Raid2.cs index 93be5d89256..ca7d54e13c9 100644 --- a/Lib9c/Action/Raid2.cs +++ b/Lib9c/Action/Raid2.cs @@ -43,10 +43,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100340ObsoleteIndex, context); diff --git a/Lib9c/Action/Raid3.cs b/Lib9c/Action/Raid3.cs index 147a32495ee..5cd945daa03 100644 --- a/Lib9c/Action/Raid3.cs +++ b/Lib9c/Action/Raid3.cs @@ -47,10 +47,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100360ObsoleteIndex, context); diff --git a/Lib9c/Action/Raid4.cs b/Lib9c/Action/Raid4.cs index d39f221364c..beb72d1b191 100644 --- a/Lib9c/Action/Raid4.cs +++ b/Lib9c/Action/Raid4.cs @@ -48,11 +48,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressHex}Raid exec started", addressHex); diff --git a/Lib9c/Action/Raid5.cs b/Lib9c/Action/Raid5.cs index 53277bd8590..04b6f16c6f3 100644 --- a/Lib9c/Action/Raid5.cs +++ b/Lib9c/Action/Raid5.cs @@ -47,11 +47,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var addressHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressHex}Raid exec started", addressHex); diff --git a/Lib9c/Action/Raid6.cs b/Lib9c/Action/Raid6.cs index 9085c3fe0da..a98e1af7abc 100644 --- a/Lib9c/Action/Raid6.cs +++ b/Lib9c/Action/Raid6.cs @@ -48,11 +48,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IAccount states = context.PreviousState; var random = context.GetRandom(); - if (context.Rehearsal) - { - return states; - } - var addressHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressHex}Raid exec started", addressHex); diff --git a/Lib9c/Action/RankingBattle.cs b/Lib9c/Action/RankingBattle.cs index d443c944dbc..c8d73f7fcb6 100644 --- a/Lib9c/Action/RankingBattle.cs +++ b/Lib9c/Action/RankingBattle.cs @@ -52,15 +52,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(weeklyArenaAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress, enemyAddress); diff --git a/Lib9c/Action/RankingBattle0.cs b/Lib9c/Action/RankingBattle0.cs index c84b9ea7b2b..2775bc6f9f1 100644 --- a/Lib9c/Action/RankingBattle0.cs +++ b/Lib9c/Action/RankingBattle0.cs @@ -44,14 +44,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - return states.SetState(ctx.Signer, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(WeeklyArenaAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, WeeklyArenaAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RankingBattle10.cs b/Lib9c/Action/RankingBattle10.cs index 3322a0f5656..f8fcd863d78 100644 --- a/Lib9c/Action/RankingBattle10.cs +++ b/Lib9c/Action/RankingBattle10.cs @@ -50,15 +50,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(weeklyArenaAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100190ObsoleteIndex, ctx); diff --git a/Lib9c/Action/RankingBattle11.cs b/Lib9c/Action/RankingBattle11.cs index 693cd025c2a..0f9c0b8989b 100644 --- a/Lib9c/Action/RankingBattle11.cs +++ b/Lib9c/Action/RankingBattle11.cs @@ -58,15 +58,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(weeklyArenaAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); // Avoid InvalidBlockStateRootHashException diff --git a/Lib9c/Action/RankingBattle2.cs b/Lib9c/Action/RankingBattle2.cs index 81e1d2d3a8f..06bca02454c 100644 --- a/Lib9c/Action/RankingBattle2.cs +++ b/Lib9c/Action/RankingBattle2.cs @@ -45,14 +45,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - return states.SetState(ctx.Signer, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(WeeklyArenaAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, WeeklyArenaAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RankingBattle3.cs b/Lib9c/Action/RankingBattle3.cs index 2089d594cdf..d70f189e8c6 100644 --- a/Lib9c/Action/RankingBattle3.cs +++ b/Lib9c/Action/RankingBattle3.cs @@ -45,14 +45,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - return states.SetState(ctx.Signer, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(WeeklyArenaAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, WeeklyArenaAddress); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RankingBattle4.cs b/Lib9c/Action/RankingBattle4.cs index 33662ffcd83..39525b5566b 100644 --- a/Lib9c/Action/RankingBattle4.cs +++ b/Lib9c/Action/RankingBattle4.cs @@ -45,14 +45,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - return states.SetState(ctx.Signer, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(WeeklyArenaAddress, MarkChanged) - .SetState(ctx.Signer, MarkChanged) - .MarkBalanceChanged(ctx, GoldCurrencyMock, ctx.Signer, WeeklyArenaAddress); - } // Avoid InvalidBlockStateRootHashException if (ctx.BlockIndex == 680341 && Id.Equals(new Guid("df37dbd8-5703-4dff-918b-ad22ee4c34c6"))) diff --git a/Lib9c/Action/RankingBattle5.cs b/Lib9c/Action/RankingBattle5.cs index c8d2f3d5f8a..9288cd2a297 100644 --- a/Lib9c/Action/RankingBattle5.cs +++ b/Lib9c/Action/RankingBattle5.cs @@ -49,15 +49,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(AvatarAddress, MarkChanged) - .SetState(WeeklyArenaAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RankingBattle6.cs b/Lib9c/Action/RankingBattle6.cs index 9f6d9114854..e77fa29109a 100644 --- a/Lib9c/Action/RankingBattle6.cs +++ b/Lib9c/Action/RankingBattle6.cs @@ -48,15 +48,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(weeklyArenaAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, ctx); diff --git a/Lib9c/Action/RankingBattle7.cs b/Lib9c/Action/RankingBattle7.cs index 4714ba87c51..1cf7a51d756 100644 --- a/Lib9c/Action/RankingBattle7.cs +++ b/Lib9c/Action/RankingBattle7.cs @@ -48,15 +48,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(weeklyArenaAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100086ObsoleteIndex, context); diff --git a/Lib9c/Action/RankingBattle8.cs b/Lib9c/Action/RankingBattle8.cs index 12d6385148a..b29e5df390f 100644 --- a/Lib9c/Action/RankingBattle8.cs +++ b/Lib9c/Action/RankingBattle8.cs @@ -51,15 +51,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(weeklyArenaAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100089ObsoleteIndex, context); diff --git a/Lib9c/Action/RankingBattle9.cs b/Lib9c/Action/RankingBattle9.cs index ed91901c47b..91c840b2acc 100644 --- a/Lib9c/Action/RankingBattle9.cs +++ b/Lib9c/Action/RankingBattle9.cs @@ -51,15 +51,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (ctx.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(weeklyArenaAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100093ObsoleteIndex, context); diff --git a/Lib9c/Action/RapidCombination.cs b/Lib9c/Action/RapidCombination.cs index e24a3a3a311..35006d2cba9 100644 --- a/Lib9c/Action/RapidCombination.cs +++ b/Lib9c/Action/RapidCombination.cs @@ -46,16 +46,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}RapidCombination exec started", addressesHex); diff --git a/Lib9c/Action/RapidCombination0.cs b/Lib9c/Action/RapidCombination0.cs index 69963e53b14..59f3ee5e07c 100644 --- a/Lib9c/Action/RapidCombination0.cs +++ b/Lib9c/Action/RapidCombination0.cs @@ -61,12 +61,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RapidCombination2.cs b/Lib9c/Action/RapidCombination2.cs index 88a618347eb..4c9b8f57a63 100644 --- a/Lib9c/Action/RapidCombination2.cs +++ b/Lib9c/Action/RapidCombination2.cs @@ -36,12 +36,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RapidCombination3.cs b/Lib9c/Action/RapidCombination3.cs index 1240e5b05a1..f851ab8036b 100644 --- a/Lib9c/Action/RapidCombination3.cs +++ b/Lib9c/Action/RapidCombination3.cs @@ -36,12 +36,6 @@ public override IAccount Execute(IActionContext context) slotIndex ) ); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RapidCombination4.cs b/Lib9c/Action/RapidCombination4.cs index db5dacf7782..f968fe7c6fb 100644 --- a/Lib9c/Action/RapidCombination4.cs +++ b/Lib9c/Action/RapidCombination4.cs @@ -40,15 +40,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RapidCombination5.cs b/Lib9c/Action/RapidCombination5.cs index 151c244022f..02122248cdb 100644 --- a/Lib9c/Action/RapidCombination5.cs +++ b/Lib9c/Action/RapidCombination5.cs @@ -67,15 +67,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100083ObsoleteIndex, context); diff --git a/Lib9c/Action/RapidCombination6.cs b/Lib9c/Action/RapidCombination6.cs index 3ef020308c5..b2edda19ca4 100644 --- a/Lib9c/Action/RapidCombination6.cs +++ b/Lib9c/Action/RapidCombination6.cs @@ -46,15 +46,7 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } + CheckObsolete(ActionObsoleteConfig.V100310ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/RapidCombination7.cs b/Lib9c/Action/RapidCombination7.cs index 664be118ce6..0d1e4bcc094 100644 --- a/Lib9c/Action/RapidCombination7.cs +++ b/Lib9c/Action/RapidCombination7.cs @@ -44,15 +44,7 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } + CheckObsolete(ActionObsoleteConfig.V100310ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/RapidCombination8.cs b/Lib9c/Action/RapidCombination8.cs index b8fb61d3889..f8a5b90441d 100644 --- a/Lib9c/Action/RapidCombination8.cs +++ b/Lib9c/Action/RapidCombination8.cs @@ -45,15 +45,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); diff --git a/Lib9c/Action/RapidCombination9.cs b/Lib9c/Action/RapidCombination9.cs index 478a81dbd31..07950d0f94f 100644 --- a/Lib9c/Action/RapidCombination9.cs +++ b/Lib9c/Action/RapidCombination9.cs @@ -47,15 +47,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = avatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = avatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = avatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(avatarAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(slotAddress, MarkChanged); - } var addressesHex = GetSignerAndOtherAddressesHex(context, avatarAddress); var started = DateTimeOffset.UtcNow; diff --git a/Lib9c/Action/ReRegisterProduct.cs b/Lib9c/Action/ReRegisterProduct.cs index 43fc1581240..833dc24f918 100644 --- a/Lib9c/Action/ReRegisterProduct.cs +++ b/Lib9c/Action/ReRegisterProduct.cs @@ -28,10 +28,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } if (!ReRegisterInfos.Any()) { @@ -73,11 +69,11 @@ public override IAccount Execute(IActionContext context) else { var marketState = states.TryGetState(Addresses.Market, out List rawMarketList) - ? new MarketState(rawMarketList) - : new MarketState(); + ? rawMarketList + : List.Empty; productsState = new ProductsState(); - marketState.AvatarAddresses.Add(AvatarAddress); - states = states.SetState(Addresses.Market, marketState.Serialize()); + marketState = marketState.Add(AvatarAddress.Serialize()); + states = states.SetState(Addresses.Market, marketState); } var random = context.GetRandom(); diff --git a/Lib9c/Action/ReRegisterProduct0.cs b/Lib9c/Action/ReRegisterProduct0.cs index 60aa45e6f52..dabd435e5bb 100644 --- a/Lib9c/Action/ReRegisterProduct0.cs +++ b/Lib9c/Action/ReRegisterProduct0.cs @@ -28,10 +28,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } if (!ReRegisterInfos.Any()) { @@ -73,11 +69,11 @@ public override IAccount Execute(IActionContext context) else { var marketState = states.TryGetState(Addresses.Market, out List rawMarketList) - ? new MarketState(rawMarketList) - : new MarketState(); + ? rawMarketList + : List.Empty; productsState = new ProductsState(); - marketState.AvatarAddresses.Add(AvatarAddress); - states = states.SetState(Addresses.Market, marketState.Serialize()); + marketState = marketState.Add(AvatarAddress.Serialize()); + states = states.SetState(Addresses.Market, marketState); } var random = context.GetRandom(); diff --git a/Lib9c/Action/RedeemCode.cs b/Lib9c/Action/RedeemCode.cs index d9eb1222063..c1ea1bddc2d 100644 --- a/Lib9c/Action/RedeemCode.cs +++ b/Lib9c/Action/RedeemCode.cs @@ -48,19 +48,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(RedeemCodeState.Address, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(context.Signer, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, GoldCurrencyState.Address) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}RedeemCode exec started", addressesHex); diff --git a/Lib9c/Action/RedeemCode0.cs b/Lib9c/Action/RedeemCode0.cs index 1976866c3e9..3cbea4423d7 100644 --- a/Lib9c/Action/RedeemCode0.cs +++ b/Lib9c/Action/RedeemCode0.cs @@ -40,15 +40,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - states = states.SetState(RedeemCodeState.Address, MarkChanged); - states = states.SetState(AvatarAddress, MarkChanged); - states = states.SetState(context.Signer, MarkChanged); - states = states.MarkBalanceChanged(context, GoldCurrencyMock, GoldCurrencyState.Address); - states = states.MarkBalanceChanged(context, GoldCurrencyMock, context.Signer); - return states; - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RedeemCode2.cs b/Lib9c/Action/RedeemCode2.cs index 83421670404..35a64cabe0e 100644 --- a/Lib9c/Action/RedeemCode2.cs +++ b/Lib9c/Action/RedeemCode2.cs @@ -44,18 +44,6 @@ public override IAccount Execute(IActionContext context) var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var worldInformationAddress = AvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); - if (context.Rehearsal) - { - return states - .SetState(RedeemCodeState.Address, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(context.Signer, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, GoldCurrencyState.Address) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/RegisterProduct.cs b/Lib9c/Action/RegisterProduct.cs index 41c1730a223..b07b51ee662 100644 --- a/Lib9c/Action/RegisterProduct.cs +++ b/Lib9c/Action/RegisterProduct.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using Bencodex.Types; using Libplanet.Action; @@ -12,6 +13,7 @@ using Nekoyume.Model.Market; using Nekoyume.Model.State; using Nekoyume.TableData; +using Serilog; using static Lib9c.SerializeKeys; namespace Nekoyume.Action @@ -27,13 +29,12 @@ public class RegisterProduct : GameAction public override IAccount Execute(IActionContext context) { + var sw = new Stopwatch(); + context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } + sw.Start(); if (!RegisterInfos.Any()) { throw new ListEmptyException("RegisterInfos was empty"); @@ -58,7 +59,17 @@ public override IAccount Execute(IActionContext context) throw new FailedLoadStateException("failed to load avatar state."); } + sw.Stop(); + Log.Debug("{Source} {Process} from #{BlockIndex}: {Elapsed}", + nameof(RegisterProduct), "Get States And Validate", context.BlockIndex, sw.Elapsed.TotalMilliseconds); + + sw.Restart(); avatarState.UseAp(CostAp, ChargeAp, states.GetSheet(), context.BlockIndex, states.GetGameConfigState()); + sw.Stop(); + Log.Debug("{Source} {Process} from #{BlockIndex}: {Elapsed}", + nameof(RegisterProduct), "UseAp", context.BlockIndex, sw.Elapsed.TotalMilliseconds); + + sw.Restart(); var productsStateAddress = ProductsState.DeriveAddress(AvatarAddress); ProductsState productsState; if (states.TryGetState(productsStateAddress, out List rawProducts)) @@ -69,18 +80,26 @@ public override IAccount Execute(IActionContext context) { productsState = new ProductsState(); var marketState = states.TryGetState(Addresses.Market, out List rawMarketList) - ? new MarketState(rawMarketList) - : new MarketState(); - marketState.AvatarAddresses.Add(AvatarAddress); - states = states.SetState(Addresses.Market, marketState.Serialize()); + ? rawMarketList + : List.Empty; + marketState = marketState.Add(AvatarAddress.Serialize()); + states = states.SetState(Addresses.Market, marketState); } + sw.Stop(); + Log.Debug("{Source} {Process} from #{BlockIndex}: {Elapsed}", + nameof(RegisterProduct), "Get productsState", context.BlockIndex, sw.Elapsed.TotalMilliseconds); + sw.Restart(); var random = context.GetRandom(); foreach (var info in RegisterInfos.OrderBy(r => r.Type).ThenBy(r => r.Price)) { states = Register(context, info, avatarState, productsState, states, random); } + sw.Stop(); + Log.Debug("{Source} {Process} from #{BlockIndex}: {Elapsed}, ProductCount: {ProductCount}", + nameof(RegisterProduct), "Register Infos", context.BlockIndex, sw.Elapsed.TotalMilliseconds, RegisterInfos.Count()); + sw.Restart(); states = states .SetState(AvatarAddress.Derive(LegacyInventoryKey), avatarState.inventory.Serialize()) .SetState(AvatarAddress, avatarState.SerializeV2()) @@ -91,6 +110,9 @@ public override IAccount Execute(IActionContext context) .SetState(AvatarAddress.Derive(LegacyQuestListKey), avatarState.questList.Serialize()) .SetState(AvatarAddress.Derive(LegacyWorldInformationKey), avatarState.worldInformation.Serialize()); } + sw.Stop(); + Log.Debug("{Source} {Process} from #{BlockIndex}: {Elapsed}", + nameof(RegisterProduct), "Set States", context.BlockIndex, sw.Elapsed.TotalMilliseconds); return states; } diff --git a/Lib9c/Action/RegisterProduct0.cs b/Lib9c/Action/RegisterProduct0.cs index b3ffeeab31e..72c3e028c88 100644 --- a/Lib9c/Action/RegisterProduct0.cs +++ b/Lib9c/Action/RegisterProduct0.cs @@ -30,10 +30,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } if (!RegisterInfos.Any()) { @@ -80,10 +76,10 @@ public override IAccount Execute(IActionContext context) { productsState = new ProductsState(); var marketState = states.TryGetState(Addresses.Market, out List rawMarketList) - ? new MarketState(rawMarketList) - : new MarketState(); - marketState.AvatarAddresses.Add(AvatarAddress); - states = states.SetState(Addresses.Market, marketState.Serialize()); + ? rawMarketList + : List.Empty; + marketState = marketState.Add(AvatarAddress.Serialize()); + states = states.SetState(Addresses.Market, marketState); } var random = context.GetRandom(); diff --git a/Lib9c/Action/RegisterProduct2.cs b/Lib9c/Action/RegisterProduct2.cs index ebe4cc3d194..d349536579c 100644 --- a/Lib9c/Action/RegisterProduct2.cs +++ b/Lib9c/Action/RegisterProduct2.cs @@ -31,10 +31,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); var states = context.PreviousState; var random = context.GetRandom(); - if (context.Rehearsal) - { - return states; - } if (!RegisterInfos.Any()) { @@ -81,10 +77,10 @@ public override IAccount Execute(IActionContext context) { productsState = new ProductsState(); var marketState = states.TryGetState(Addresses.Market, out List rawMarketList) - ? new MarketState(rawMarketList) - : new MarketState(); - marketState.AvatarAddresses.Add(AvatarAddress); - states = states.SetState(Addresses.Market, marketState.Serialize()); + ? rawMarketList + : List.Empty; + marketState = marketState.Add(AvatarAddress.Serialize()); + states = states.SetState(Addresses.Market, marketState); } foreach (var info in RegisterInfos.OrderBy(r => r.Type).ThenBy(r => r.Price)) { diff --git a/Lib9c/Action/RenewAdminState.cs b/Lib9c/Action/RenewAdminState.cs index 47bb6c69fc2..fdc0833b54c 100644 --- a/Lib9c/Action/RenewAdminState.cs +++ b/Lib9c/Action/RenewAdminState.cs @@ -36,11 +36,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states - .SetState(Addresses.Admin, MarkChanged); - } if (TryGetAdminState(context, out AdminState adminState)) { diff --git a/Lib9c/Action/RewardGold.cs b/Lib9c/Action/RewardGold.cs index c56c981a1d3..eeae940b862 100644 --- a/Lib9c/Action/RewardGold.cs +++ b/Lib9c/Action/RewardGold.cs @@ -63,14 +63,15 @@ public IAccount GenesisGoldDistribution(IActionContext ctx, IAccount states) var index = ctx.BlockIndex; Currency goldCurrency = states.GetGoldCurrency(); Address fund = GoldCurrencyState.Address; + FungibleAssetValue fundValue = states.GetBalance(fund, goldCurrency); foreach(GoldDistribution distribution in goldDistributions) { BigInteger amount = distribution.GetAmount(index); - if (amount <= 0) continue; + FungibleAssetValue fav = goldCurrency * amount; + if (amount <= 0 || fundValue < fav) continue; // We should divide by 100 for only mainnet distributions. // See also: https://github.com/planetarium/lib9c/pull/170#issuecomment-713380172 - FungibleAssetValue fav = goldCurrency * amount; var testAddresses = new HashSet
( new [] { @@ -289,7 +290,8 @@ public IAccount MinerReward(IActionContext ctx, IAccount states) FungibleAssetValue miningReward = defaultMiningReward.DivRem(countOfHalfLife, out FungibleAssetValue _); - if (miningReward >= FungibleAssetValue.Parse(currency, "1.25")) + var balance = states.GetBalance(GoldCurrencyState.Address, currency); + if (miningReward >= FungibleAssetValue.Parse(currency, "1.25") && balance >= miningReward) { states = states.TransferAsset( ctx, diff --git a/Lib9c/Action/RuneEnhancement.cs b/Lib9c/Action/RuneEnhancement.cs index 232eaba6271..966ff2c803f 100644 --- a/Lib9c/Action/RuneEnhancement.cs +++ b/Lib9c/Action/RuneEnhancement.cs @@ -47,10 +47,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } if (!states.TryGetAvatarStateV2(context.Signer, AvatarAddress, out _, out _)) { diff --git a/Lib9c/Action/RuneEnhancement0.cs b/Lib9c/Action/RuneEnhancement0.cs index b6ffcf007ac..d0bddcbb9a4 100644 --- a/Lib9c/Action/RuneEnhancement0.cs +++ b/Lib9c/Action/RuneEnhancement0.cs @@ -48,10 +48,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100360ObsoleteIndex, context); diff --git a/Lib9c/Action/SecureMiningReward.cs b/Lib9c/Action/SecureMiningReward.cs index 7d6ffd8463e..8ad9a82bcc6 100644 --- a/Lib9c/Action/SecureMiningReward.cs +++ b/Lib9c/Action/SecureMiningReward.cs @@ -59,14 +59,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); IAccount state = context.PreviousState; - if (context.Rehearsal) - { - return state.MarkBalanceChanged( - context, - NCG, - AuthorizedMiners.Add(Recipient).Add(Treasury).ToArray() - ); - } CheckPermission(context); diff --git a/Lib9c/Action/Sell.cs b/Lib9c/Action/Sell.cs index f157183821f..cbc68e523a8 100644 --- a/Lib9c/Action/Sell.cs +++ b/Lib9c/Action/Sell.cs @@ -72,19 +72,6 @@ public override IAccount Execute(IActionContext context) Address itemAddress = Addresses.GetItemAddress(tradableId); Address orderAddress = Order.DeriveAddress(orderId); Address orderReceiptAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states - .SetState(context.Signer, MarkChanged) - .SetState(shopAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(orderAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); if (!(states.GetState(Addresses.Market) is null)) diff --git a/Lib9c/Action/Sell0.cs b/Lib9c/Action/Sell0.cs index e5e3365376c..9b39a0c8ecf 100644 --- a/Lib9c/Action/Sell0.cs +++ b/Lib9c/Action/Sell0.cs @@ -46,12 +46,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(ShopState.Address, MarkChanged); - states = states.SetState(sellerAvatarAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Sell10.cs b/Lib9c/Action/Sell10.cs index 3045d3bbdac..6302f25cbf1 100644 --- a/Lib9c/Action/Sell10.cs +++ b/Lib9c/Action/Sell10.cs @@ -73,19 +73,6 @@ public override IAccount Execute(IActionContext context) Address itemAddress = Addresses.GetItemAddress(tradableId); Address orderAddress = Order.DeriveAddress(orderId); Address orderReceiptAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states - .SetState(context.Signer, MarkChanged) - .SetState(shopAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(orderAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100300ObsoleteIndex, context); diff --git a/Lib9c/Action/Sell11.cs b/Lib9c/Action/Sell11.cs index 8b1772d06a3..982abaa0d25 100644 --- a/Lib9c/Action/Sell11.cs +++ b/Lib9c/Action/Sell11.cs @@ -72,19 +72,6 @@ public override IAccount Execute(IActionContext context) Address itemAddress = Addresses.GetItemAddress(tradableId); Address orderAddress = Order.DeriveAddress(orderId); Address orderReceiptAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states - .SetState(context.Signer, MarkChanged) - .SetState(shopAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(orderAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100351ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, sellerAvatarAddress); diff --git a/Lib9c/Action/Sell2.cs b/Lib9c/Action/Sell2.cs index a803364f529..39c042bb4a8 100644 --- a/Lib9c/Action/Sell2.cs +++ b/Lib9c/Action/Sell2.cs @@ -47,12 +47,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(ShopState.Address, MarkChanged); - states = states.SetState(sellerAvatarAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Sell3.cs b/Lib9c/Action/Sell3.cs index 915cf54eb39..bd5344c30aa 100644 --- a/Lib9c/Action/Sell3.cs +++ b/Lib9c/Action/Sell3.cs @@ -47,12 +47,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(ShopState.Address, MarkChanged); - states = states.SetState(sellerAvatarAddress, MarkChanged); - return states.SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Sell4.cs b/Lib9c/Action/Sell4.cs index aed2c6dcab9..bac95c98a8a 100644 --- a/Lib9c/Action/Sell4.cs +++ b/Lib9c/Action/Sell4.cs @@ -54,15 +54,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(sellerAvatarAddress, MarkChanged); - states = ShardedShopState.AddressKeys.Aggregate(states, - (current, addressKey) => - current.SetState(ShardedShopState.DeriveAddress(itemSubType, addressKey), MarkChanged)); - return states - .SetState(ctx.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Sell5.cs b/Lib9c/Action/Sell5.cs index 8522389158f..d6825f5594b 100644 --- a/Lib9c/Action/Sell5.cs +++ b/Lib9c/Action/Sell5.cs @@ -63,16 +63,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - states = states.SetState(sellerAvatarAddress, MarkChanged); - states = ShardedShopState.AddressKeys.Aggregate( - states, - (current, addressKey) => current.SetState( - ShardedShopState.DeriveAddress(itemSubType, addressKey), - MarkChanged)); - return states.SetState(context.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Sell6.cs b/Lib9c/Action/Sell6.cs index c277ca86424..bd6c2f22da8 100644 --- a/Lib9c/Action/Sell6.cs +++ b/Lib9c/Action/Sell6.cs @@ -62,16 +62,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - states = states.SetState(sellerAvatarAddress, MarkChanged); - states = ShardedShopState.AddressKeys.Aggregate( - states, - (current, addressKey) => current.SetState( - ShardedShopState.DeriveAddress(itemSubType, addressKey), - MarkChanged)); - return states.SetState(context.Signer, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Sell7.cs b/Lib9c/Action/Sell7.cs index d872721e5b8..f438a90489f 100644 --- a/Lib9c/Action/Sell7.cs +++ b/Lib9c/Action/Sell7.cs @@ -70,19 +70,6 @@ public override IAccount Execute(IActionContext context) Address itemAddress = Addresses.GetItemAddress(tradableId); Address orderAddress = Order.DeriveAddress(orderId); Address orderReceiptAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states - .SetState(context.Signer, MarkChanged) - .SetState(shopAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(orderAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Sell8.cs b/Lib9c/Action/Sell8.cs index fc682aadf15..eb45c4b79ca 100644 --- a/Lib9c/Action/Sell8.cs +++ b/Lib9c/Action/Sell8.cs @@ -70,19 +70,6 @@ public override IAccount Execute(IActionContext context) Address itemAddress = Addresses.GetItemAddress(tradableId); Address orderAddress = Order.DeriveAddress(orderId); Address orderReceiptAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states - .SetState(context.Signer, MarkChanged) - .SetState(shopAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(orderAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Sell9.cs b/Lib9c/Action/Sell9.cs index 64a270e0c62..69c0cc4ad6b 100644 --- a/Lib9c/Action/Sell9.cs +++ b/Lib9c/Action/Sell9.cs @@ -69,19 +69,6 @@ public override IAccount Execute(IActionContext context) Address itemAddress = Addresses.GetItemAddress(tradableId); Address orderAddress = Order.DeriveAddress(orderId); Address orderReceiptAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states - .SetState(context.Signer, MarkChanged) - .SetState(shopAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(orderAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/SellCancellation.cs b/Lib9c/Action/SellCancellation.cs index b8f85edc11c..39681828b9d 100644 --- a/Lib9c/Action/SellCancellation.cs +++ b/Lib9c/Action/SellCancellation.cs @@ -98,18 +98,6 @@ public override IAccount Execute(IActionContext context) var questListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); var digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); var itemAddress = Addresses.GetItemAddress(tradableId); - if (context.Rehearsal) - { - states = states.SetState(shardedShopAddress, MarkChanged); - return states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(digestListAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, sellerAvatarAddress); if (!states.TryGetAvatarStateV2(context.Signer, sellerAvatarAddress, out var avatarState, out _)) diff --git a/Lib9c/Action/SellCancellation0.cs b/Lib9c/Action/SellCancellation0.cs index 9a280388957..7414dd1a549 100644 --- a/Lib9c/Action/SellCancellation0.cs +++ b/Lib9c/Action/SellCancellation0.cs @@ -44,11 +44,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(ShopState.Address, MarkChanged); - return states.SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/SellCancellation2.cs b/Lib9c/Action/SellCancellation2.cs index befb7a492f6..ea0782bf688 100644 --- a/Lib9c/Action/SellCancellation2.cs +++ b/Lib9c/Action/SellCancellation2.cs @@ -44,11 +44,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(ShopState.Address, MarkChanged); - return states.SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/SellCancellation3.cs b/Lib9c/Action/SellCancellation3.cs index 8bd5e03a9b6..f15ca9adda0 100644 --- a/Lib9c/Action/SellCancellation3.cs +++ b/Lib9c/Action/SellCancellation3.cs @@ -44,11 +44,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(ShopState.Address, MarkChanged); - return states.SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/SellCancellation4.cs b/Lib9c/Action/SellCancellation4.cs index 11d93e4f161..9dbb415d277 100644 --- a/Lib9c/Action/SellCancellation4.cs +++ b/Lib9c/Action/SellCancellation4.cs @@ -44,11 +44,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); IActionContext ctx = context; var states = ctx.PreviousState; - if (ctx.Rehearsal) - { - states = states.SetState(ShopState.Address, MarkChanged); - return states.SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/SellCancellation5.cs b/Lib9c/Action/SellCancellation5.cs index 710a3a4b74f..80928c21885 100644 --- a/Lib9c/Action/SellCancellation5.cs +++ b/Lib9c/Action/SellCancellation5.cs @@ -51,13 +51,6 @@ public override IAccount Execute(IActionContext context) IActionContext ctx = context; var states = ctx.PreviousState; Address shardedShopAddress = ShardedShopState.DeriveAddress(itemSubType, productId); - if (ctx.Rehearsal) - { - states = states.SetState(shardedShopAddress, MarkChanged); - return states - .SetState(Addresses.Shop, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/SellCancellation6.cs b/Lib9c/Action/SellCancellation6.cs index c275c47dff6..c9593a13995 100644 --- a/Lib9c/Action/SellCancellation6.cs +++ b/Lib9c/Action/SellCancellation6.cs @@ -52,13 +52,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(1); var states = context.PreviousState; var shardedShopAddress = ShardedShopState.DeriveAddress(itemSubType, productId); - if (context.Rehearsal) - { - states = states.SetState(shardedShopAddress, MarkChanged); - return states - .SetState(Addresses.Shop, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/SellCancellation7.cs b/Lib9c/Action/SellCancellation7.cs index 748591269a1..7132bf3aa27 100644 --- a/Lib9c/Action/SellCancellation7.cs +++ b/Lib9c/Action/SellCancellation7.cs @@ -92,17 +92,6 @@ public override IAccount Execute(IActionContext context) var questListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); var orderDigestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); var itemAddress = Addresses.GetItemAddress(tradableId); - if (context.Rehearsal) - { - states = states.SetState(shardedShopAddress, MarkChanged); - return states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(orderDigestListAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/SellCancellation8.cs b/Lib9c/Action/SellCancellation8.cs index e9205ca963e..3aeed53427a 100644 --- a/Lib9c/Action/SellCancellation8.cs +++ b/Lib9c/Action/SellCancellation8.cs @@ -92,17 +92,6 @@ public override IAccount Execute(IActionContext context) var questListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); var digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); var itemAddress = Addresses.GetItemAddress(tradableId); - if (context.Rehearsal) - { - states = states.SetState(shardedShopAddress, MarkChanged); - return states - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(digestListAddress, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/Stake.cs b/Lib9c/Action/Stake.cs index 03598da3958..731a96ac60d 100644 --- a/Lib9c/Action/Stake.cs +++ b/Lib9c/Action/Stake.cs @@ -60,16 +60,6 @@ public override IAccount Execute(IActionContext context) throw new MonsterCollectionExistingException(); } - if (context.Rehearsal) - { - return states.SetState(StakeState.DeriveAddress(context.Signer), MarkChanged) - .MarkBalanceChanged( - context, - GoldCurrencyMock, - context.Signer, - StakeState.DeriveAddress(context.Signer)); - } - // NOTE: When the amount is less than 0. if (Amount < 0) { diff --git a/Lib9c/Action/Stake0.cs b/Lib9c/Action/Stake0.cs index 9ef4eac6875..145a5b49ba6 100644 --- a/Lib9c/Action/Stake0.cs +++ b/Lib9c/Action/Stake0.cs @@ -57,16 +57,6 @@ public override IAccount Execute(IActionContext context) throw new MonsterCollectionExistingException(); } - if (context.Rehearsal) - { - return states.SetState(StakeState.DeriveAddress(context.Signer), MarkChanged) - .MarkBalanceChanged( - context, - GoldCurrencyMock, - context.Signer, - StakeState.DeriveAddress(context.Signer)); - } - CheckObsolete(ObsoleteIndex, context); if (Amount < 0) diff --git a/Lib9c/Action/Stake2.cs b/Lib9c/Action/Stake2.cs index 60764a53a07..8165a4a7a82 100644 --- a/Lib9c/Action/Stake2.cs +++ b/Lib9c/Action/Stake2.cs @@ -57,16 +57,6 @@ public override IAccount Execute(IActionContext context) throw new MonsterCollectionExistingException(); } - if (context.Rehearsal) - { - return states.SetState(StakeState.DeriveAddress(context.Signer), MarkChanged) - .MarkBalanceChanged( - context, - GoldCurrencyMock, - context.Signer, - StakeState.DeriveAddress(context.Signer)); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, context.Signer); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}Stake exec started", addressesHex); diff --git a/Lib9c/Action/TransferAsset.cs b/Lib9c/Action/TransferAsset.cs index 2859eaa862f..b6b4212d1d2 100644 --- a/Lib9c/Action/TransferAsset.cs +++ b/Lib9c/Action/TransferAsset.cs @@ -88,11 +88,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(4); Address signer = context.Signer; var state = context.PreviousState; - if (context.Rehearsal) - { - return state.MarkBalanceChanged(context, Amount.Currency, new[] {Sender, Recipient}); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, signer); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}TransferAsset5 exec started", addressesHex); diff --git a/Lib9c/Action/TransferAsset0.cs b/Lib9c/Action/TransferAsset0.cs index 6c4bbc29c00..3c6b0e72487 100644 --- a/Lib9c/Action/TransferAsset0.cs +++ b/Lib9c/Action/TransferAsset0.cs @@ -78,10 +78,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(4); var state = context.PreviousState; - if (context.Rehearsal) - { - return state.MarkBalanceChanged(context, Amount.Currency, new[] { Sender, Recipient }); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/TransferAsset2.cs b/Lib9c/Action/TransferAsset2.cs index bf465ccf503..8ccdf99b7ee 100644 --- a/Lib9c/Action/TransferAsset2.cs +++ b/Lib9c/Action/TransferAsset2.cs @@ -84,10 +84,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(4); var state = context.PreviousState; - if (context.Rehearsal) - { - return state.MarkBalanceChanged(context, Amount.Currency, new[] { Sender, Recipient }); - } CheckObsolete(TransferAsset3.CrystalTransferringRestrictionStartIndex - 1, context); var addressesHex = GetSignerAndOtherAddressesHex(context, context.Signer); diff --git a/Lib9c/Action/TransferAsset3.cs b/Lib9c/Action/TransferAsset3.cs index a679bcec1c6..1f43d17c0f1 100644 --- a/Lib9c/Action/TransferAsset3.cs +++ b/Lib9c/Action/TransferAsset3.cs @@ -97,10 +97,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(4); var state = context.PreviousState; - if (context.Rehearsal) - { - return state.MarkBalanceChanged(context, Amount.Currency, new[] { Sender, Recipient }); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, context.Signer); diff --git a/Lib9c/Action/TransferAsset4.cs b/Lib9c/Action/TransferAsset4.cs index 18cf7feeb56..0f8bc34a4fd 100644 --- a/Lib9c/Action/TransferAsset4.cs +++ b/Lib9c/Action/TransferAsset4.cs @@ -89,10 +89,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(4); Address signer = context.Signer; var state = context.PreviousState; - if (context.Rehearsal) - { - return state.MarkBalanceChanged(context, Amount.Currency, new[] {Sender, Recipient}); - } var addressesHex = GetSignerAndOtherAddressesHex(context, signer); var started = DateTimeOffset.UtcNow; diff --git a/Lib9c/Action/TransferAssets.cs b/Lib9c/Action/TransferAssets.cs index 5247d35e274..15ea73cd009 100644 --- a/Lib9c/Action/TransferAssets.cs +++ b/Lib9c/Action/TransferAssets.cs @@ -83,10 +83,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(4); var state = context.PreviousState; - if (context.Rehearsal) - { - return Recipients.Aggregate(state, (current, t) => current.MarkBalanceChanged(context, t.amount.Currency, new[] {Sender, t.recipient})); - } if (Recipients.Count > RecipientsCapacity) { diff --git a/Lib9c/Action/TransferAssets0.cs b/Lib9c/Action/TransferAssets0.cs index e3fb49f138a..641c1070d5e 100644 --- a/Lib9c/Action/TransferAssets0.cs +++ b/Lib9c/Action/TransferAssets0.cs @@ -83,10 +83,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(4); var state = context.PreviousState; - if (context.Rehearsal) - { - return Recipients.Aggregate(state, (current, t) => current.MarkBalanceChanged(context, t.amount.Currency, new[] {Sender, t.recipient})); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); if (Recipients.Count > RecipientsCapacity) diff --git a/Lib9c/Action/TransferAssets2.cs b/Lib9c/Action/TransferAssets2.cs index 2fac24362d3..b86c6a137ca 100644 --- a/Lib9c/Action/TransferAssets2.cs +++ b/Lib9c/Action/TransferAssets2.cs @@ -85,10 +85,6 @@ public override IAccount Execute(IActionContext context) context.UseGas(4); var state = context.PreviousState; CheckObsolete(ActionObsoleteConfig.V200090ObsoleteIndex, context); - if (context.Rehearsal) - { - return Recipients.Aggregate(state, (current, t) => current.MarkBalanceChanged(context, t.amount.Currency, new[] {Sender, t.recipient})); - } if (Recipients.Count > RecipientsCapacity) { diff --git a/Lib9c/Action/UnlockEquipmentRecipe.cs b/Lib9c/Action/UnlockEquipmentRecipe.cs index 6035f025e03..cc7fab4ddbd 100644 --- a/Lib9c/Action/UnlockEquipmentRecipe.cs +++ b/Lib9c/Action/UnlockEquipmentRecipe.cs @@ -36,17 +36,6 @@ public override IAccount Execute(IActionContext context) var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var unlockedRecipeIdsAddress = AvatarAddress.Derive("recipe_ids"); - if (context.Rehearsal) - { - return states - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(unlockedRecipeIdsAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, Addresses.UnlockEquipmentRecipe); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}UnlockEquipmentRecipe exec started", addressesHex); diff --git a/Lib9c/Action/UnlockEquipmentRecipe1.cs b/Lib9c/Action/UnlockEquipmentRecipe1.cs index 95ff4993a7e..140822a7f6a 100644 --- a/Lib9c/Action/UnlockEquipmentRecipe1.cs +++ b/Lib9c/Action/UnlockEquipmentRecipe1.cs @@ -37,16 +37,6 @@ public override IAccount Execute(IActionContext context) var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var unlockedRecipeIdsAddress = AvatarAddress.Derive("recipe_ids"); - if (context.Rehearsal) - { - return states - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .SetState(unlockedRecipeIdsAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, Addresses.UnlockEquipmentRecipe); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); diff --git a/Lib9c/Action/UnlockRuneSlot.cs b/Lib9c/Action/UnlockRuneSlot.cs index 679503b3c38..1350193de32 100644 --- a/Lib9c/Action/UnlockRuneSlot.cs +++ b/Lib9c/Action/UnlockRuneSlot.cs @@ -44,11 +44,6 @@ public override IAccount Execute(IActionContext context) { context.UseGas(1); var states = context.PreviousState; - if (context.Rehearsal) - { - return states; - } - var sheets = states.GetSheets( sheetTypes: new[] { diff --git a/Lib9c/Action/UnlockWorld.cs b/Lib9c/Action/UnlockWorld.cs index f99b815c304..050c4db174b 100644 --- a/Lib9c/Action/UnlockWorld.cs +++ b/Lib9c/Action/UnlockWorld.cs @@ -37,16 +37,6 @@ public override IAccount Execute(IActionContext context) var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var unlockedWorldIdsAddress = AvatarAddress.Derive("world_ids"); - if (context.Rehearsal) - { - return states - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, Addresses.UnlockWorld); - } - var addressesHex = GetSignerAndOtherAddressesHex(context, AvatarAddress); var started = DateTimeOffset.UtcNow; Log.Debug("{AddressesHex}UnlockWorld exec started", addressesHex); diff --git a/Lib9c/Action/UnlockWorld1.cs b/Lib9c/Action/UnlockWorld1.cs index f53f2a12335..0aa816c5a3c 100644 --- a/Lib9c/Action/UnlockWorld1.cs +++ b/Lib9c/Action/UnlockWorld1.cs @@ -33,15 +33,6 @@ public override IAccount Execute(IActionContext context) var questListAddress = AvatarAddress.Derive(LegacyQuestListKey); var inventoryAddress = AvatarAddress.Derive(LegacyInventoryKey); var unlockedWorldIdsAddress = AvatarAddress.Derive("world_ids"); - if (context.Rehearsal) - { - return states - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(AvatarAddress, MarkChanged) - .MarkBalanceChanged(context, GoldCurrencyMock, context.Signer, Addresses.UnlockWorld); - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); if (!WorldIds.Any() || WorldIds.Any(i => i < 2 || i == GameConfig.MimisbrunnrWorldId)) diff --git a/Lib9c/Action/UpdateSell.cs b/Lib9c/Action/UpdateSell.cs index 3acb49c6fc8..c0d7852701d 100644 --- a/Lib9c/Action/UpdateSell.cs +++ b/Lib9c/Action/UpdateSell.cs @@ -59,10 +59,6 @@ public override IAccount Execute(IActionContext context) var worldInformationAddress = sellerAvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); var digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V200030ObsoleteIndex, context); if (!(states.GetState(Addresses.Market) is null)) diff --git a/Lib9c/Action/UpdateSell0.cs b/Lib9c/Action/UpdateSell0.cs index 4b53ccff828..74ecaa4fa6c 100644 --- a/Lib9c/Action/UpdateSell0.cs +++ b/Lib9c/Action/UpdateSell0.cs @@ -77,20 +77,6 @@ public override IAccount Execute(IActionContext context) var updateSellOrderAddress = Order.DeriveAddress(updateSellOrderId); var itemAddress = Addresses.GetItemAddress(tradableId); var orderReceiptAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states - .SetState(context.Signer, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(shopAddress, MarkChanged) - .SetState(updateSellShopAddress, MarkChanged) - .SetState(updateSellOrderAddress, MarkChanged) - .SetState(orderReceiptAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100080ObsoleteIndex, context); diff --git a/Lib9c/Action/UpdateSell2.cs b/Lib9c/Action/UpdateSell2.cs index 7bae25a70bd..49e45acde44 100644 --- a/Lib9c/Action/UpdateSell2.cs +++ b/Lib9c/Action/UpdateSell2.cs @@ -81,20 +81,6 @@ public override IAccount Execute(IActionContext context) var updateSellOrderAddress = Order.DeriveAddress(updateSellOrderId); var itemAddress = Addresses.GetItemAddress(tradableId); var digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states - .SetState(context.Signer, MarkChanged) - .SetState(itemAddress, MarkChanged) - .SetState(digestListAddress, MarkChanged) - .SetState(shopAddress, MarkChanged) - .SetState(updateSellShopAddress, MarkChanged) - .SetState(updateSellOrderAddress, MarkChanged) - .SetState(inventoryAddress, MarkChanged) - .SetState(worldInformationAddress, MarkChanged) - .SetState(questListAddress, MarkChanged) - .SetState(sellerAvatarAddress, MarkChanged); - } CheckObsolete(ActionObsoleteConfig.V100270ObsoleteIndex, context); diff --git a/Lib9c/Action/UpdateSell3.cs b/Lib9c/Action/UpdateSell3.cs index 31d4fcacb18..036caa0c55a 100644 --- a/Lib9c/Action/UpdateSell3.cs +++ b/Lib9c/Action/UpdateSell3.cs @@ -60,10 +60,6 @@ public override IAccount Execute(IActionContext context) var worldInformationAddress = sellerAvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); var digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100320ObsoleteIndex, context); diff --git a/Lib9c/Action/UpdateSell4.cs b/Lib9c/Action/UpdateSell4.cs index 2b615c85691..1b6ccb10140 100644 --- a/Lib9c/Action/UpdateSell4.cs +++ b/Lib9c/Action/UpdateSell4.cs @@ -61,10 +61,6 @@ public override IAccount Execute(IActionContext context) var worldInformationAddress = sellerAvatarAddress.Derive(LegacyWorldInformationKey); var questListAddress = sellerAvatarAddress.Derive(LegacyQuestListKey); var digestListAddress = OrderDigestListState.DeriveAddress(sellerAvatarAddress); - if (context.Rehearsal) - { - return states; - } CheckObsolete(ActionObsoleteConfig.V100351ObsoleteIndex, context); diff --git a/Lib9c/Addresses.cs b/Lib9c/Addresses.cs index 34850f9f791..4ce1b8e4857 100644 --- a/Lib9c/Addresses.cs +++ b/Lib9c/Addresses.cs @@ -38,6 +38,7 @@ public static class Addresses public static readonly Address Rune = new Address("0000000000000000000000000000000000000016"); public static readonly Address Market = new Address("0000000000000000000000000000000000000017"); public static readonly Address GarageWallet = new Address("0000000000000000000000000000000000000018"); + public static readonly Address AssetMinters = new Address("0000000000000000000000000000000000000019"); public static Address GetSheetAddress() where T : ISheet => GetSheetAddress(typeof(T).Name); diff --git a/Lib9c/Arena/ArenaSimulator.cs b/Lib9c/Arena/ArenaSimulator.cs index c4ed5be0866..720627d23c4 100644 --- a/Lib9c/Arena/ArenaSimulator.cs +++ b/Lib9c/Arena/ArenaSimulator.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Libplanet.Action; @@ -9,7 +10,7 @@ namespace Nekoyume.Arena { /// - /// Introduced at https://github.com/planetarium/lib9c/pull/1930 + /// Changed at https://github.com/planetarium/lib9c/pull/2229 /// public class ArenaSimulator : IArenaSimulator { @@ -19,20 +20,23 @@ public class ArenaSimulator : IArenaSimulator public IRandom Random { get; } public int Turn { get; private set; } public ArenaLog Log { get; private set; } + public int HpModifier { get; } - public ArenaSimulator(IRandom random) + public ArenaSimulator(IRandom random, int hpModifier = 2) { Random = random; Turn = 1; + HpModifier = hpModifier; } public ArenaLog Simulate( ArenaPlayerDigest challenger, ArenaPlayerDigest enemy, - ArenaSimulatorSheets sheets) + ArenaSimulatorSheets sheets, + bool setExtraValueBuffBeforeGetBuffs = false) { Log = new ArenaLog(); - var players = SpawnPlayers(this, challenger, enemy, sheets, Log); + var players = SpawnPlayers(this, challenger, enemy, sheets, Log, setExtraValueBuffBeforeGetBuffs); Turn = 1; while (true) @@ -94,15 +98,20 @@ private static (ArenaCharacter, ArenaLog.ArenaResult) GetBattleResult( return (player, player.IsEnemy ? ArenaLog.ArenaResult.Win : ArenaLog.ArenaResult.Lose); } - private static SimplePriorityQueue SpawnPlayers( ArenaSimulator simulator, ArenaPlayerDigest challengerDigest, ArenaPlayerDigest enemyDigest, ArenaSimulatorSheets simulatorSheets, - ArenaLog log) + ArenaLog log, + bool setExtraValueBuffBeforeGetBuffs = false) { - var challenger = new ArenaCharacter(simulator, challengerDigest, simulatorSheets); + var challenger = new ArenaCharacter( + simulator, + challengerDigest, + simulatorSheets, + simulator.HpModifier, + setExtraValueBuffBeforeGetBuffs: setExtraValueBuffBeforeGetBuffs); if (challengerDigest.Runes != null) { challenger.SetRune( @@ -111,7 +120,13 @@ private static SimplePriorityQueue SpawnPlayers( simulatorSheets.SkillSheet); } - var enemy = new ArenaCharacter(simulator, enemyDigest, simulatorSheets, true); + var enemy = new ArenaCharacter( + simulator, + enemyDigest, + simulatorSheets, + simulator.HpModifier, + isEnemy: true, + setExtraValueBuffBeforeGetBuffs: setExtraValueBuffBeforeGetBuffs); if (enemyDigest.Runes != null) { enemy.SetRune( diff --git a/Lib9c/Currencies.cs b/Lib9c/Currencies.cs index 88358f80675..bfb81f6a273 100644 --- a/Lib9c/Currencies.cs +++ b/Lib9c/Currencies.cs @@ -3,6 +3,7 @@ using System; using System.Globalization; using System.Linq; +using Libplanet.Crypto; using Libplanet.Types.Assets; using Nekoyume.TableData; @@ -135,5 +136,67 @@ public static IOrderedEnumerable GetSoulStones(PetSheet? sheet) => .Select(row => row.SoulStoneTicker) .Select(GetSoulStone) .OrderBy(soulStone => soulStone.Hash.GetHashCode()); + + public static Address SelectRecipientAddress(Currency currency, Address agentAddress, + Address avatarAddress) + { + var agentCurrencies = new[] + { + Crystal, + Garage, + Mead, + }; + return agentCurrencies.Contains(currency) || currency.Ticker == "NCG" ? agentAddress : avatarAddress; + } + + public static Currency GetWrappedCurrency(Currency currency) + { + return Currency.Legacy($"FAV__{currency.Ticker}", currency.DecimalPlaces, minters: null); + } + + public static bool IsWrappedCurrency(Currency currency) + { + return currency.Ticker.StartsWith("FAV"); + } + + public static Currency GetUnwrappedCurrency(Currency currency) + { + if (!IsWrappedCurrency(currency)) + { + throw new ArgumentException("{Ticker} is not wrapped currency", currency.Ticker); + } + + var wrappedTicker = currency.Ticker; + var parsedTicker = wrappedTicker.Split("__"); + var ticker = parsedTicker[1]; + return GetMinterlessCurrency(ticker); + } + + public static (bool tradable, int itemId) ParseItemCurrency(Currency currency) + { + if (currency.DecimalPlaces != 0) + { + throw new ArgumentException( + $"DecimalPlaces of currency are not 0: {currency.Ticker}"); + } + + var parsedTicker = currency.Ticker.Split("_"); + if (parsedTicker.Length != 3 + || parsedTicker[0] != "Item" + || (parsedTicker[1] != "NT" && parsedTicker[1] != "T") + || !int.TryParse(parsedTicker[2], out var itemId)) + { + throw new ArgumentException( + $"Format of Amount currency's ticker is invalid"); + } + + return (parsedTicker[1] == "T", itemId); + } + + public static Currency GetItemCurrency(int itemId, bool tradable) + { + var type = tradable ? "T" : "NT"; + return Currency.Legacy($"Item_{type}_{itemId}", decimalPlaces: 0, minters: null); + } } } diff --git a/Lib9c/Model/Buff/BuffFactory.cs b/Lib9c/Model/Buff/BuffFactory.cs index 9914e0dd94c..760b828e8ff 100644 --- a/Lib9c/Model/Buff/BuffFactory.cs +++ b/Lib9c/Model/Buff/BuffFactory.cs @@ -47,15 +47,16 @@ public static IList GetBuffs( SkillBuffSheet skillBuffSheet, StatBuffSheet statBuffSheet, SkillActionBuffSheet skillActionBuffSheet, - ActionBuffSheet actionBuffSheet) + ActionBuffSheet actionBuffSheet, + bool hasExtraValueBuff = false) { var buffs = new List(); // If ReferencedStatType exists, // buff value = original value + (referenced stat * (SkillRow.StatPowerRatio / 10000)) - var extraValueBuff = - skill is BuffSkill && - (skill.Power > 0 || skill.ReferencedStatType != StatType.NONE); + var extraValueBuff = hasExtraValueBuff || + (skill is BuffSkill && + (skill.Power > 0 || skill.ReferencedStatType != StatType.NONE)); if (skillBuffSheet.TryGetValue(skill.SkillRow.Id, out var skillStatBuffRow)) { @@ -76,7 +77,7 @@ skill is BuffSkill && var multiplier = skill.StatPowerRatio / 10000m; additionalValue += (int)Math.Round(statMap.GetStat(skill.ReferencedStatType) * multiplier); } - + customField = new SkillCustomField() { BuffDuration = buffRow.Duration, diff --git a/Lib9c/Model/Character/ArenaCharacter.cs b/Lib9c/Model/Character/ArenaCharacter.cs index d487336ea39..53ab676d17d 100644 --- a/Lib9c/Model/Character/ArenaCharacter.cs +++ b/Lib9c/Model/Character/ArenaCharacter.cs @@ -14,9 +14,11 @@ using Nekoyume.Model.Elemental; using Nekoyume.Model.Item; using Nekoyume.Model.Skill; +using Nekoyume.Model.Skill.Arena; using Nekoyume.Model.Stat; using Nekoyume.Model.State; using Nekoyume.TableData; +using ArenaSkill = Nekoyume.Model.BattleStatus.Arena.ArenaSkill; namespace Nekoyume.Model { @@ -51,6 +53,8 @@ public class ArenaCharacter : ICloneable public int CharacterId { get; } public bool IsEnemy { get; } + private bool _setExtraValueBuffBeforeGetBuffs = false; + private int _currentHP; public int CurrentHP @@ -85,6 +89,7 @@ public int Level public object Clone() => new ArenaCharacter(this); + [Obsolete("It using at ArenaSimulatorV1.")] public ArenaCharacter( ArenaSimulatorV1 simulator, ArenaPlayerDigest digest, @@ -107,7 +112,7 @@ public ArenaCharacter( _actionBuffSheet = sheets.ActionBuffSheet; _simulator = simulator; - Stats = GetStat( + Stats = GetStatV1( digest, row, sheets.EquipmentItemSetEffectSheet, @@ -139,7 +144,7 @@ public ArenaCharacter( _actionBuffSheet = sheets.ActionBuffSheet; _simulator = simulator; - Stats = GetStat( + Stats = GetStatV1( digest, row, sheets.EquipmentItemSetEffectSheet, @@ -149,6 +154,42 @@ public ArenaCharacter( ResetCurrentHP(); } + public ArenaCharacter( + IArenaSimulator simulator, + ArenaPlayerDigest digest, + ArenaSimulatorSheets sheets, + int hpModifier, + bool isEnemy = false, + bool setExtraValueBuffBeforeGetBuffs = false) + { + OffensiveElementalType = GetElementalType(digest.Equipments, ItemSubType.Weapon); + DefenseElementalType = GetElementalType(digest.Equipments, ItemSubType.Armor); + var row = CharacterRow(digest.CharacterId, sheets); + SizeType = row?.SizeType ?? SizeType.S; + RunSpeed = row?.RunSpeed ?? 1f; + AttackRange = row?.AttackRange ?? 1f; + CharacterId = digest.CharacterId; + IsEnemy = isEnemy; + _setExtraValueBuffBeforeGetBuffs = setExtraValueBuffBeforeGetBuffs; + + _skillSheet = sheets.SkillSheet; + _skillBuffSheet = sheets.SkillBuffSheet; + _statBuffSheet = sheets.StatBuffSheet; + _skillActionBuffSheet = sheets.SkillActionBuffSheet; + _actionBuffSheet = sheets.ActionBuffSheet; + + _simulator = simulator; + Stats = GetStat( + digest, + row, + sheets.EquipmentItemSetEffectSheet, + sheets.CostumeStatSheet, + hpModifier); + _skills = GetSkills(digest.Equipments, sheets.SkillSheet); + _attackCountMax = AttackCountHelper.GetCountMax(digest.Level); + ResetCurrentHP(); + } + private ArenaCharacter(ArenaCharacter value) { Id = value.Id; @@ -216,6 +257,33 @@ protected void ResetCurrentHP() } private static CharacterStats GetStat( + ArenaPlayerDigest digest, + CharacterSheet.Row characterRow, + EquipmentItemSetEffectSheet equipmentItemSetEffectSheet, + CostumeStatSheet costumeStatSheet, + int hpModifier) + { + var stats = new CharacterStats(characterRow, digest.Level) + { + IsArenaCharacter = true, + HpIncreasingModifier = hpModifier + }; + stats.SetEquipments(digest.Equipments, equipmentItemSetEffectSheet); + + var options = new List(); + foreach (var itemId in digest.Costumes.Select(costume => costume.Id)) + { + if (TryGetStats(costumeStatSheet, itemId, out var option)) + { + options.AddRange(option); + } + } + + stats.SetOption(options); + return stats; + } + + private static CharacterStats GetStatV1( ArenaPlayerDigest digest, CharacterSheet.Row characterRow, EquipmentItemSetEffectSheet equipmentItemSetEffectSheet, @@ -623,7 +691,12 @@ private BattleStatus.Arena.ArenaSkill UseSkill() _skillBuffSheet, _statBuffSheet, _skillActionBuffSheet, - _actionBuffSheet) + _actionBuffSheet, + _setExtraValueBuffBeforeGetBuffs && + selectedSkill is ArenaBuffSkill && + (selectedSkill.Power > 0 || + selectedSkill.ReferencedStatType != + StatType.NONE)) ); if (!_skillSheet.TryGetValue(selectedSkill.SkillRow.Id, out var row)) diff --git a/Lib9c/Model/FungibleItemValue.cs b/Lib9c/Model/FungibleItemValue.cs new file mode 100644 index 00000000000..30779794df7 --- /dev/null +++ b/Lib9c/Model/FungibleItemValue.cs @@ -0,0 +1,32 @@ +using System.Security.Cryptography; +using Bencodex.Types; +using Libplanet.Common; +using Nekoyume.Model.State; + +namespace Nekoyume.Model +{ + public readonly struct FungibleItemValue + { + public FungibleItemValue(List bencoded) + : this( + new HashDigest((Binary)bencoded[0]), + (Integer)bencoded[1] + ) + { + } + + public FungibleItemValue(HashDigest id, int count) + { + Id = id; + Count = count; + } + + public IValue Serialize() + { + return new List(Id.Serialize(), (Integer)Count); + } + + public HashDigest Id { get; } + public int Count { get; } + } +} diff --git a/Lib9c/Model/Mail/ClaimItemsMail.cs b/Lib9c/Model/Mail/ClaimItemsMail.cs new file mode 100644 index 00000000000..b3988b05443 --- /dev/null +++ b/Lib9c/Model/Mail/ClaimItemsMail.cs @@ -0,0 +1,79 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Bencodex.Types; +using Libplanet.Types.Assets; +using Nekoyume.Model.State; + +namespace Nekoyume.Model.Mail +{ + public class ClaimItemsMail : Mail + { + public override MailType MailType => MailType.Auction; + + public List FungibleAssetValues = new List(); + public List<(int id, int count)> Items = new List<(int id, int count)>(); + public string Memo; + + public ClaimItemsMail(long blockIndex, Guid id, long requiredBlockIndex, + List fungibleAssetValues, List<(int id, int count)> items, + string memo) : base(blockIndex, id, requiredBlockIndex) + { + FungibleAssetValues = fungibleAssetValues; + Items = items; + Memo = memo; + } + + public ClaimItemsMail(Dictionary serialized) : base(serialized) + { + if (serialized.ContainsKey("f")) + { + FungibleAssetValues = serialized["f"].ToList(StateExtensions.ToFungibleAssetValue); + } + + if (serialized.ContainsKey("i")) + { + Items = serialized["i"].ToList<(int, int)>(v => + { + var list = (List) v; + return ((Integer)list[0], (Integer)list[1]); + }); + } + + if (serialized.ContainsKey("m")) + { + Memo = (Text) serialized["m"]; + } + } + + public override void Read(IMail mail) + { + mail.Read(this); + } + + protected override string TypeId => nameof(ClaimItemsMail); + + public override IValue Serialize() + { + var dict = (Dictionary)base.Serialize(); + if (FungibleAssetValues.Any()) + { + dict = dict.SetItem("f", new List(FungibleAssetValues.Select(f => f.Serialize()))); + } + + if (Items.Any()) + { + dict = dict.SetItem("i", + new List(Items.Select(tuple => List.Empty.Add(tuple.id).Add(tuple.count)))); + } + + if (!string.IsNullOrEmpty(Memo)) + { + dict = dict.SetItem("m", Memo); + } + + return dict; + } + + } +} diff --git a/Lib9c/Model/Mail/IMail.cs b/Lib9c/Model/Mail/IMail.cs index 4ad564b6377..dbb883c7a7d 100644 --- a/Lib9c/Model/Mail/IMail.cs +++ b/Lib9c/Model/Mail/IMail.cs @@ -19,5 +19,6 @@ public interface IMail void Read(ProductSellerMail productSellerMail); void Read(ProductCancelMail productCancelMail); void Read(UnloadFromMyGaragesRecipientMail unloadFromMyGaragesRecipientMail); + void Read(ClaimItemsMail claimItemsMail); } } diff --git a/Lib9c/Model/Mail/Mail.cs b/Lib9c/Model/Mail/Mail.cs index dc89848477c..a44f6285807 100644 --- a/Lib9c/Model/Mail/Mail.cs +++ b/Lib9c/Model/Mail/Mail.cs @@ -40,6 +40,7 @@ public abstract class Mail : IState [nameof(ProductCancelMail)] = d => new ProductCancelMail(d), [nameof(UnloadFromMyGaragesRecipientMail)] = d => new UnloadFromMyGaragesRecipientMail(d), + [nameof(ClaimItemsMail)] = d => new ClaimItemsMail(d), }; public Guid id; diff --git a/Lib9c/Model/Stat/CharacterStats.cs b/Lib9c/Model/Stat/CharacterStats.cs index 52845374693..1e1c28041e4 100644 --- a/Lib9c/Model/Stat/CharacterStats.cs +++ b/Lib9c/Model/Stat/CharacterStats.cs @@ -69,6 +69,7 @@ public class CharacterStats : Stats, IBaseAndAdditionalStats, ICloneable public int AdditionalThorn => Thorn - _baseStats.Thorn; public bool IsArenaCharacter { private get; set; } = false; + public int HpIncreasingModifier { private get; set; } = 2; private readonly Dictionary MinimumStatValues = new Dictionary() @@ -106,7 +107,7 @@ public CharacterStats(WorldBossCharacterSheet.WaveStatData stat) _baseStats.Set(stats); SetStats(stat.Level); } - + public CharacterStats(CharacterStats value) : base(value) { _row = value._row; @@ -355,7 +356,7 @@ public void SetOption(IEnumerable statModifiers) public void IncreaseHpForArena() { var originalHP = _statMap[StatType.HP]; - _statMap[StatType.HP].SetBaseValue(Math.Max(0, originalHP.TotalValueAsInt * 2)); + _statMap[StatType.HP].SetBaseValue(Math.Max(0, originalHP.TotalValueAsInt * HpIncreasingModifier)); } private void UpdateBaseStats() diff --git a/Lib9c/Model/State/GoldCurrencyState.cs b/Lib9c/Model/State/GoldCurrencyState.cs index 65c426ce325..7b0c70a4116 100644 --- a/Lib9c/Model/State/GoldCurrencyState.cs +++ b/Lib9c/Model/State/GoldCurrencyState.cs @@ -12,20 +12,38 @@ namespace Nekoyume.Model.State [Serializable] public class GoldCurrencyState : State, ISerializable { + public const long DEFAULT_INITIAL_SUPPLY = 1000000000; + public static readonly Address Address = Addresses.GoldCurrency; public Currency Currency { get; private set; } + public long InitialSupply { get; private set; } + public GoldCurrencyState(Currency currency) + : this(currency, DEFAULT_INITIAL_SUPPLY) + { + } + + public GoldCurrencyState(Currency currency, long initialSupply) : base(Address) { Currency = currency; + InitialSupply = initialSupply; } public GoldCurrencyState(Dictionary serialized) : base(serialized) { Currency = CurrencyExtensions.Deserialize((Dictionary) serialized["currency"]); + if (serialized.TryGetValue((Text)"initialSupply", out IValue rawInitialSupply)) + { + InitialSupply = (Integer)rawInitialSupply; + } + else + { + InitialSupply = DEFAULT_INITIAL_SUPPLY; + } } protected GoldCurrencyState(SerializationInfo info, StreamingContext context) @@ -39,6 +57,11 @@ public override IValue Serialize() { [(Text)"currency"] = CurrencyExtensions.Serialize(Currency) }; + + if (InitialSupply != DEFAULT_INITIAL_SUPPLY) + { + values.Add((Text)"initialSupply", (Integer)InitialSupply); + } #pragma warning disable LAA1002 return new Dictionary(values.Union((Dictionary)base.Serialize())); #pragma warning restore LAA1002 diff --git a/Lib9c/Planet.cs b/Lib9c/Planet.cs new file mode 100644 index 00000000000..edb994ba25a --- /dev/null +++ b/Lib9c/Planet.cs @@ -0,0 +1,11 @@ +using System; + +namespace Nekoyume +{ + public enum Planet : byte + { + Odin, + Heimdall, + Idun, + } +} diff --git a/Lib9c/PlanetExtension.cs b/Lib9c/PlanetExtension.cs new file mode 100644 index 00000000000..55c1fa88855 --- /dev/null +++ b/Lib9c/PlanetExtension.cs @@ -0,0 +1,40 @@ +using Libplanet.Types.Blocks; +using Libplanet.Types.Tx; + +namespace Nekoyume +{ + public static class PlanetExtension + { + private static readonly BlockHash OdinGenesisHash = BlockHash.FromString( + "4582250d0da33b06779a8475d283d5dd210c683b9b999d74d03fac4f58fa6bce" + ); + + // FIXME should be changed after Heimdall/Idun mainnet launches + private static readonly BlockHash HeimdallGenesisHash = BlockHash.FromString( + "ade4c29773fe83c1a51da6a667a5a26f08848155674637d43fe636b94a320514" + ); + + private static readonly BlockHash IdunGenesisHash = BlockHash.FromString( + "209b22087045ec834f01249c8661c2734cea41ccc5d8c9a273a4c8c0521d22ec" + ); + + public static Planet? DeterminePlanet(this ITransaction tx) + { + // TODO Replace planet detection to using transaction payload instead. + if (tx.GenesisHash.Equals(OdinGenesisHash)) + { + return Planet.Odin; + } + if (tx.GenesisHash.Equals(HeimdallGenesisHash)) + { + return Planet.Heimdall; + } + if (tx.GenesisHash.Equals(IdunGenesisHash)) + { + return Planet.Idun; + } + + return null; + } + } +} diff --git a/Lib9c/SerializeKeys.cs b/Lib9c/SerializeKeys.cs index b7cd9dda831..0bef9b1b8ec 100644 --- a/Lib9c/SerializeKeys.cs +++ b/Lib9c/SerializeKeys.cs @@ -177,5 +177,6 @@ public static class SerializeKeys // ClaimItems public const string ClaimDataKey = "cd"; + public const string MemoKey = "m"; } } diff --git a/Lib9c/TableCSV/Arena/ArenaSheet.csv b/Lib9c/TableCSV/Arena/ArenaSheet.csv index effe98fb7b5..75d927a79cd 100644 --- a/Lib9c/TableCSV/Arena/ArenaSheet.csv +++ b/Lib9c/TableCSV/Arena/ArenaSheet.csv @@ -41,25 +41,25 @@ id,round,arena_type,start_block_index,end_block_index,required_medal_count,entra 6,6,Championship,8119601,8220400,160,2,100,40,40,8 7,1,OffSeason,8220401,8341360,0,0,5,2,40,8 7,2,Season,8341361,8462320,0,1,50,20,40,8 -7,3,OffSeason,8462321,8583280,0,0,5,2,40,8 -7,4,Season,8583281,8704240,0,1,50,20,40,8 -7,5,OffSeason,8704241,8825200,0,0,5,2,40,8 -7,6,Championship,8825201,8946160,160,2,100,40,40,8 -8,1,OffSeason,8946161,9067120,0,0,5,2,40,8 -8,2,Season,9067121,9188080,0,1,50,20,40,8 -8,3,OffSeason,9188081,9309040,0,0,5,2,40,8 -8,4,Season,9309041,9430000,0,1,50,20,40,8 -8,5,OffSeason,9430001,9550960,0,0,5,2,40,8 -8,6,Championship,9550961,9671920,160,2,100,40,40,8 -9,1,OffSeason,9671921,9792880,0,0,5,2,40,8 -9,2,Season,9792881,9913840,0,1,50,20,40,8 -9,3,OffSeason,9913841,10034800,0,0,5,2,40,8 -9,4,Season,10034801,10155760,0,1,50,20,40,8 -9,5,OffSeason,10155761,10276720,0,0,5,2,40,8 -9,6,Championship,10276721,10397680,160,2,100,40,40,8 -10,1,OffSeason,10397681,10518640,0,0,5,2,40,8 -10,2,Season,10518641,10639600,0,1,50,20,40,8 -10,3,OffSeason,10639601,10760560,0,0,5,2,40,8 -10,4,Season,10760561,10881520,0,1,50,20,40,8 -10,5,OffSeason,10881521,11002480,0,0,5,2,40,8 -10,6,Championship,11002481,11123440,160,2,100,40,40,8 +7,3,OffSeason,8462321,8607472,0,0,5,2,40,8 +7,4,Season,8607473,8752624,0,1,50,20,40,8 +7,5,OffSeason,8752625,8897776,0,0,5,2,40,8 +7,6,Championship,8897777,9042928,160,2,100,40,40,8 +8,1,OffSeason,9042929,9188080,0,0,5,2,40,8 +8,2,Season,9188081,9333232,0,1,50,20,40,8 +8,3,OffSeason,9333233,9478384,0,0,5,2,40,8 +8,4,Season,9478385,9623536,0,1,50,20,40,8 +8,5,OffSeason,9623537,9768688,0,0,5,2,40,8 +8,6,Championship,9768689,9913840,160,2,100,40,40,8 +9,1,OffSeason,9913841,10058992,0,0,5,2,40,8 +9,2,Season,10058993,10204144,0,1,50,20,40,8 +9,3,OffSeason,10204145,10349296,0,0,5,2,40,8 +9,4,Season,10349297,10494448,0,1,50,20,40,8 +9,5,OffSeason,10494449,10639600,0,0,5,2,40,8 +9,6,Championship,10639601,10784752,160,2,100,40,40,8 +10,1,OffSeason,10784753,10929904,0,0,5,2,40,8 +10,2,Season,10929905,11075056,0,1,50,20,40,8 +10,3,OffSeason,11075057,11220208,0,0,5,2,40,8 +10,4,Season,11220209,11365360,0,1,50,20,40,8 +10,5,OffSeason,11365361,11510512,0,0,5,2,40,8 +10,6,Championship,11510513,11655664,160,2,100,40,40,8 \ No newline at end of file diff --git a/Lib9c/TableCSV/Cost/EnhancementCostSheetV3.csv b/Lib9c/TableCSV/Cost/EnhancementCostSheetV3.csv index eb9c29e652f..a44dc19e948 100644 --- a/Lib9c/TableCSV/Cost/EnhancementCostSheetV3.csv +++ b/Lib9c/TableCSV/Cost/EnhancementCostSheetV3.csv @@ -593,8 +593,8 @@ id,item_sub_type,grade,level,cost,exp,required_block,base_stat_growth_min,base_s 592,Aura,4,4,0,64000,1,1000,1100,1000,1100,0,0,0,0 593,Aura,4,5,0,128000,1,1500,1600,1500,1600,0,0,0,0 594,Aura,4,6,0,256000,1,2000,2100,2000,2100,3000,3100,800,900 -595,Aura,4,7,0,512000,1,1800,1900,1800,1900,0,0,0,0 -596,Aura,4,8,0,1024000,1,1600,1700,1600,1700,0,0,0,0 +595,Aura,4,7,0,512000,1,1800,1900,1800,1900,1500,1600,200,200 +596,Aura,4,8,0,1024000,1,1600,1700,1600,1700,1500,1600,200,200 597,Aura,4,9,0,2048000,1,1400,1500,1400,1500,3000,3100,800,900 598,Aura,4,10,0,4096000,1,1200,1300,1200,1300,1200,1300,200,200 599,Aura,4,11,0,8192000,1,1000,1100,1000,1100,1200,1300,200,200 @@ -613,10 +613,10 @@ id,item_sub_type,grade,level,cost,exp,required_block,base_stat_growth_min,base_s 612,Aura,5,3,0,196520,1,900,1000,900,1000,3600,3700,800,900 613,Aura,5,4,0,334084,1,1000,1100,1000,1100,0,0,0,0 614,Aura,5,5,0,567942,1,1500,1600,1500,1600,0,0,0,0 -615,Aura,5,6,0,965501,1,2000,2100,2000,2100,3600,3700,800,900 -616,Aura,5,7,0,1641351,1,1800,1900,1800,1900,0,0,0,0 -617,Aura,5,8,0,2790296,1,1600,1700,1600,1700,0,0,0,0 -618,Aura,5,9,0,4743503,1,1400,1500,1400,1500,3600,3700,800,900 +615,Aura,5,6,0,965501,1,2000,2100,2000,2100,5000,5100,800,900 +616,Aura,5,7,0,1641351,1,1800,1900,1800,1900,2000,2100,200,200 +617,Aura,5,8,0,2790296,1,1600,1700,1600,1700,2000,2100,200,200 +618,Aura,5,9,0,4743503,1,1400,1500,1400,1500,5000,5100,800,900 619,Aura,5,10,0,8063955,1,1200,1300,1200,1300,1500,1600,200,200 620,Aura,5,11,0,13708723,1,1000,1100,1000,1100,1500,1600,200,200 621,Aura,5,12,0,23304829,1,1000,1100,1000,1100,1500,1600,200,200 diff --git a/Lib9c/TableCSV/CreateAvatarItemSheet.csv b/Lib9c/TableCSV/CreateAvatarItemSheet.csv index cc1fdf1bc08..9ac5a428db9 100644 --- a/Lib9c/TableCSV/CreateAvatarItemSheet.csv +++ b/Lib9c/TableCSV/CreateAvatarItemSheet.csv @@ -2,3 +2,4 @@ ItemId,Count 10110000,1 10210000,1 303000,2 +10610000,1 \ No newline at end of file diff --git a/Lib9c/TableCSV/Crystal/CrystalEquipmentGrindingSheet.csv b/Lib9c/TableCSV/Crystal/CrystalEquipmentGrindingSheet.csv index 6e2ec099c8f..d5ff0ca2e34 100644 --- a/Lib9c/TableCSV/Crystal/CrystalEquipmentGrindingSheet.csv +++ b/Lib9c/TableCSV/Crystal/CrystalEquipmentGrindingSheet.csv @@ -181,4 +181,15 @@ id,enchant_base_id,gain_crystal 10630001,10630001,2000000 10640001,10640001,10000000 10650001,10650001,20000000 -10650002,10650002,20000000 \ No newline at end of file +10650002,10650002,20000000 +10130002,10130002,1000 +10620002,10620002,1000000 +10630002,10630002,2000000 +10640002,10640002,10000000 +10650003,10650003,20000000 +10650004,10650004,20000000 +10620003,10620003,1000000 +10630003,10630003,2000000 +10640003,10640003,10000000 +10650005,10650005,20000000 +10650006,10650006,20000000 \ No newline at end of file diff --git a/Lib9c/TableCSV/GameConfigSheet.csv b/Lib9c/TableCSV/GameConfigSheet.csv index f6029b8f147..374d3f0322f 100644 --- a/Lib9c/TableCSV/GameConfigSheet.csv +++ b/Lib9c/TableCSV/GameConfigSheet.csv @@ -1,15 +1,15 @@ key,value hourglass_per_block,3 action_point_max,120 -daily_reward_interval,2040 -daily_arena_interval,6048 +daily_reward_interval,2448 +daily_arena_interval,7258 weekly_arena_interval,56000 required_appraise_block,0 battle_arena_interval,4 rune_stat_slot_unlock_cost,100 rune_skill_slot_unlock_cost,1000 daily_rune_reward_amount,1 -daily_worldboss_interval,8640 +daily_worldboss_interval,10368 worldboss_required_interval,5 stake_regular_fixed_reward_sheet_v2_start_block_index,1 stake_regular_reward_sheet_v2_start_block_index,1 diff --git a/Lib9c/TableCSV/Item/CostumeItemSheet.csv b/Lib9c/TableCSV/Item/CostumeItemSheet.csv index c37c84bbf20..ce4d97d8fa0 100644 --- a/Lib9c/TableCSV/Item/CostumeItemSheet.csv +++ b/Lib9c/TableCSV/Item/CostumeItemSheet.csv @@ -40,6 +40,16 @@ _spine_resource_path,`Title`: ``,,,, 40300008,흰털 파란색 귀,EarCostume,1,Normal, 40300009,흰털 회색 귀,EarCostume,1,Normal, 40300010,흰털 파란 유령 귀,EarCostume,1,Normal, +40300011,사바나 무늬 귀,EarCostume,1,Normal, +40300012,얼룩 무늬 귀,EarCostume,1,Normal, +40300013,야광 분홍 귀,EarCostume,1,Normal, +40300014,야광 청색 귀,EarCostume,1,Normal, +40300015,야광 노랑 귀,EarCostume,1,Normal, +40300016,야광 흰색 귀,EarCostume,1,Normal, +40300017,야광 녹색 귀,EarCostume,1,Normal, +40300018,야광 보라 귀,EarCostume,1,Normal, +40300019,검은 털 귀,EarCostume,1,Normal, +40300020,어두운 보라색 귀,EarCostume,1,Normal, 40400001,빨간색 눈,EyeCostume,1,Normal, 40400002,파란색 눈,EyeCostume,1,Normal, 40400003,초록색 눈,EyeCostume,1,Normal, @@ -56,6 +66,16 @@ _spine_resource_path,`Title`: ``,,,, 40500008,파란색 꼬리,TailCostume,1,Normal, 40500009,회색 꼬리,TailCostume,1,Normal, 40500010,파란 유령 꼬리,TailCostume,1,Normal, +40500011,사바나 무늬 꼬리,TailCostume,1,Normal, +40500012,얼룩 무늬 꼬리,TailCostume,1,Normal, +40500013,야광 분홍 꼬리,TailCostume,1,Normal, +40500014,야광 청색 꼬리,TailCostume,1,Normal, +40500015,야광 노랑 꼬리,TailCostume,1,Normal, +40500016,야광 흰색 꼬리,TailCostume,1,Normal, +40500017,야광 녹색 꼬리,TailCostume,1,Normal, +40500018,야광 보라 꼬리,TailCostume,1,Normal, +40500019,검은 털 꼬리,TailCostume,1,Normal, +40500020,어두운 보라색 꼬리,TailCostume,1,Normal, 49900001,전설의 모험가,Title,4,Normal, 49900002,최초의 전사,Title,5,Normal, 49900003,Yggdrasil Champion,Title,5,Normal, @@ -66,4 +86,5 @@ _spine_resource_path,`Title`: ``,,,, 49900008,Championship 2 Ranker,Title,5,Normal, 49900009,2022 Grand Finale,Title,3,Normal, 49900010,Championship 4 Ranker,Title,5,Normal, -49900011,Great Adventurer 1,Title,5,Normal, \ No newline at end of file +49900011,Great Adventurer 1,Title,5,Normal, +49900012,Championship 6 Ranker,Title,5,Normal, \ No newline at end of file diff --git a/Lib9c/TableCSV/Item/CostumeStatSheet.csv b/Lib9c/TableCSV/Item/CostumeStatSheet.csv index 51973ce9153..8cec7718b20 100644 --- a/Lib9c/TableCSV/Item/CostumeStatSheet.csv +++ b/Lib9c/TableCSV/Item/CostumeStatSheet.csv @@ -1,40 +1,41 @@ id,costume_id,stat_type,stat -1,40100000,ATK,30 -2,40100001,DEF,15 -3,40100002,HIT,135 -4,40100003,ATK,60 -5,40100003,HIT,135 -6,40100005,ATK,35 -7,40100006,ATK,55 -8,40100006,SPD,100 -9,49900001,HP,300 -10,49900002,HP,450 -11,49900003,HP,450 -12,49900003,DEF,20 -13,49900004,ATK,40 -14,49900005,ATK,80 -15,49900005,HIT,150 -16,49900006,HIT,120 -17,40100007,DEF,10 -18,40100007,HIT,150 -19,40100009,SPD,80 -20,40100009,ATK,65 -21,40100008,ATK,35 -22,49900007,HP,5000 -23,49900008,DEF,320 -24,40100010,ATK,530 -25,49900009,HIT,1210 -26,40100011,HP,8550 -27,49900010,ATK,500 -28,40100013,ATK,150 -29,40100013,HIT,490 -30,40100014,ATK,150 -31,40100014,SPD,465 -32,40100015,SPD,400 -33,40100015,ATK,105 -34,40100016,HIT,730 -35,40100017,DEF,300 -36,40100017,ATK,105 +1,40100000,ATK,1829 +2,40100001,DEF,1205 +3,40100002,HIT,3009 +4,40100003,ATK,1019 +5,40100003,HIT,1504 +6,40100005,ATK,1829 +7,40100006,ATK,1121 +8,40100006,SPD,1399 +9,49900001,HP,26990 +10,49900002,HP,31041 +11,49900003,HP,15520 +12,49900003,DEF,596 +13,49900004,ATK,1394 +14,49900005,ATK,802 +15,49900005,HIT,1183 +16,49900006,HIT,874 +17,40100007,DEF,910 +18,40100007,HIT,1203 +19,40100009,SPD,1223 +20,40100009,ATK,1244 +21,40100008,ATK,1829 +22,49900007,HP,31041 +23,49900008,DEF,1193 +24,40100010,ATK,2039 +25,49900009,HIT,1749 +26,40100011,HP,39456 +27,49900010,ATK,2367 +28,40100013,ATK,972 +29,40100013,HIT,956 +30,40100014,ATK,972 +31,40100014,SPD,988 +32,40100015,SPD,1482 +33,40100015,ATK,648 +34,40100016,HIT,2391 +35,40100017,DEF,680 +36,40100017,ATK,914 37,40100019,HP,26040 38,40100019,SPD,1368 39,49900011,DEF,1908 +40,49900012,HP,34145 \ No newline at end of file diff --git a/Lib9c/TableCSV/Item/EquipmentItemOptionSheet.csv b/Lib9c/TableCSV/Item/EquipmentItemOptionSheet.csv index f377428d79b..2af253154e2 100644 --- a/Lib9c/TableCSV/Item/EquipmentItemOptionSheet.csv +++ b/Lib9c/TableCSV/Item/EquipmentItemOptionSheet.csv @@ -1811,7 +1811,7 @@ id,stat_type,stat_min,stat_max,skill_id,skill_damage_min,skill_damage_max,skill_ 1055400032,ATK,1859,2359,,,,,,,, 1055400033,SPD,14965,19711,,,,,,,, 1055400034,,,,220008,0,0,9,9,1800,1900,SPD -1061000011,HIT,440,650,,,,,,,, +1061000011,HIT,140,350,,,,,,,, 1061000012,SPD,320,480,,,,,,,, 1061000013,,,,240006,20,20,30,30,,, 1062000011,HIT,900,1350,,,,,,,, @@ -1839,4 +1839,34 @@ id,stat_type,stat_min,stat_max,skill_id,skill_damage_min,skill_damage_max,skill_ 1065000121,ATK,5700,5700,,,,,,,, 1065000122,HP,23200,23200,,,,,,,, 1065000123,DEF,1830,1830,,,,,,,, -1065000124,,,,230007,800,800,30,30,,, \ No newline at end of file +1065000124,,,,230007,800,800,30,30,,, +1062000211,HP,2971,4456,,,,,,,, +1062000212,SPD,107,160,,,,,,,, +1062000213,,,,210012,10,10,30,30,,, +1063000211,HP,8102,12153,,,,,,,, +1063000212,SPD,214,320,,,,,,,, +1063000213,,,,210012,10,10,30,30,,, +1064000211,HP,29707,44560,,,,,,,, +1064000212,SPD,1806,2708,,,,,,,, +1064000213,,,,210012,25,25,30,30,,, +1065000311,HP,64814,97221,,,,,,,, +1065000312,SPD,4258,6387,,,,,,,, +1065000313,,,,210012,40,40,30,30,,, +1065000411,HP,97321,97321,,,,,,,, +1065000412,SPD,6487,6487,,,,,,,, +1065000413,,,,210012,40,40,30,30,,, +1062000311,ATK,154,231,,,,,,,, +1062000312,DEF,52,78,,,,,,,, +1062000313,,,,110008,0,0,30,30,9000,9000,ATK +1063000311,ATK,420,629,,,,,,,, +1063000312,DEF,104,156,,,,,,,, +1063000313,,,,110008,0,0,30,30,9000,9000,ATK +1064000311,ATK,1536,2303,,,,,,,, +1064000312,DEF,881,1321,,,,,,,, +1064000313,,,,110008,0,0,30,30,15000,15000,ATK +1065000511,ATK,3350,5025,,,,,,,, +1065000512,DEF,2078,3116,,,,,,,, +1065000513,,,,110008,0,0,30,30,25000,25000,ATK +1065000611,ATK,5125,5125,,,,,,,, +1065000612,DEF,3216,3216,,,,,,,, +1065000613,,,,110008,0,0,30,30,25000,25000,ATK \ No newline at end of file diff --git a/Lib9c/TableCSV/Item/EquipmentItemRecipeSheet.csv b/Lib9c/TableCSV/Item/EquipmentItemRecipeSheet.csv index 6b4f0831d01..370dda67239 100644 --- a/Lib9c/TableCSV/Item/EquipmentItemRecipeSheet.csv +++ b/Lib9c/TableCSV/Item/EquipmentItemRecipeSheet.csv @@ -4,15 +4,15 @@ id,result_equipment_id,material_id,material_count,required_action_point,required 6,10120000,303001,4,0,0,37,27,376,377,,8,Weapon 10,10124000,303001,24,0,0,7155,174,22,23,,22560,Weapon 14,10133000,303002,27,0,0,9807,190,31,32,,41040,Weapon -15,10134000,303002,47,0,0,21585,204,34,35,,167040,Weapon +15,10134000,303002,47,0,0,11585,204,34,35,,167040,Weapon 18,10132001,303002,21,0,0,5190,154,40,41,,32040,Weapon -19,10133001,303002,61,0,0,28050,220,43,44,,216180,Weapon -20,10134001,303002,73,0,0,34302,236,46,47,,495900,Weapon -21,10140000,303003,250,0,0,40000,299,101400001,101400002,,1404000,Weapon -22,10141000,303003,120,0,0,20000,255,101410001,101410002,,1532100,Weapon -23,10142000,303003,120,0,0,24000,265,101420001,101420002,,1532100,Weapon -24,10143000,303003,180,0,0,28000,277,101430001,101430002,,1532100,Weapon -25,10144000,303003,180,0,0,32000,290,101440001,101440002,,1532100,Weapon +19,10133001,303002,61,0,0,18050,220,43,44,,216180,Weapon +20,10134001,303002,73,0,0,24302,236,46,47,,495900,Weapon +21,10140000,303003,250,0,0,25000,299,101400001,101400002,,1404000,Weapon +22,10141000,303003,120,0,0,10000,255,101410001,101410002,,1532100,Weapon +23,10142000,303003,120,0,0,14000,265,101420001,101420002,,1532100,Weapon +24,10143000,303003,180,0,0,18000,277,101430001,101430002,,1532100,Weapon +25,10144000,303003,180,0,0,22000,290,101440001,101440002,,1532100,Weapon 26,10150000,303004,360,0,0,3000,330,101500001,101500002,,500000,Weapon 27,10151000,303004,360,0,0,3000,305,101510001,101510002,,500000,Weapon 28,10152000,303004,360,0,0,3000,305,101520001,101520002,101520003,500000,Weapon @@ -22,17 +22,17 @@ id,result_equipment_id,material_id,material_count,required_action_point,required 46,10214000,303100,14,0,0,1076,108,106,107,,742,Armor 49,10222000,303101,7,0,0,120,45,112,113,,11,Armor 51,10224000,303101,26,0,0,8361,182,118,119,,23920,Armor -55,10233000,303102,40,0,0,18426,201,127,128,,140400,Armor -56,10234000,303102,52,0,0,23991,208,130,131,,182520,Armor +55,10233000,303102,40,0,0,10426,201,127,128,,140400,Armor +56,10234000,303102,52,0,0,13991,208,130,131,,182520,Armor 57,10230001,303102,20,0,0,1824,146,409,410,,9600,Armor 58,10231001,303102,22,0,0,5463,158,133,134,,33000,Armor 59,10232001,303102,23,0,0,6189,166,136,137,,35040,Armor -60,10233001,303102,67,0,0,31056,228,139,140,,455400,Armor -62,10240000,303103,250,0,0,40000,294,102400001,102400002,,1166700,Armor -63,10241000,303103,120,0,0,20000,261,102410001,102410002,,1173660,Armor -64,10242000,303103,120,0,0,24000,270,102420001,102420002,,1188720,Armor -65,10243000,303103,180,0,0,28000,280,102430001,102430002,,1345500,Armor -66,10244000,303103,180,0,0,32000,287,102440001,102440002,,1345500,Armor +60,10233001,303102,67,0,0,11056,228,139,140,,455400,Armor +62,10240000,303103,250,0,0,25000,294,102400001,102400002,,1166700,Armor +63,10241000,303103,120,0,0,10000,261,102410001,102410002,,1173660,Armor +64,10242000,303103,120,0,0,14000,270,102420001,102420002,,1188720,Armor +65,10243000,303103,180,0,0,18000,280,102430001,102430002,,1345500,Armor +66,10244000,303103,180,0,0,22000,287,102440001,102440002,,1345500,Armor 67,10250001,303104,360,0,0,3000,335,102500011,102500012,,500000,Armor 68,10251001,303104,360,0,0,3000,315,102510011,102510012,,500000,Armor 69,10252001,303104,360,0,0,3000,315,102520011,102520012,102520013,1000000,Armor @@ -40,39 +40,39 @@ id,result_equipment_id,material_id,material_count,required_action_point,required 71,10254001,303104,360,0,0,3000,335,102540011,102540012,102540013,1000000,Armor 87,10314000,303200,18,0,0,1560,134,202,203,,954,Belt 91,10323000,303201,22,0,0,5796,162,211,212,,2992,Belt -92,10324000,303201,45,0,0,20472,203,214,215,,122220,Belt +92,10324000,303201,45,0,0,10472,203,214,215,,122220,Belt 94,10331000,303202,11,0,0,410,90,217,218,,387,Belt -97,10334000,303202,150,0,0,30000,251,226,227,,737100,Belt -101,10343000,303203,76,0,0,36015,240,235,236,,1128600,Belt -103,10350000,303203,250,0,0,40000,296,103500001,103500002,,4177800,Belt -104,10351000,303203,120,0,0,20000,260,103510001,103510002,,4347000,Belt -105,10352000,303203,120,0,0,24000,269,103520001,103520002,,4395600,Belt -106,10353000,303203,180,0,0,28000,278,103530001,103530002,,4441500,Belt -107,10354000,303203,180,0,0,32000,287,103540001,103540002,,4638900,Belt +97,10334000,303202,150,0,0,20000,251,226,227,,737100,Belt +101,10343000,303203,76,0,0,26015,240,235,236,,1128600,Belt +103,10350000,303203,250,0,0,25000,296,103500001,103500002,,4177800,Belt +104,10351000,303203,120,0,0,10000,260,103510001,103510002,,4347000,Belt +105,10352000,303203,120,0,0,14000,269,103520001,103520002,,4395600,Belt +106,10353000,303203,180,0,0,18000,278,103530001,103530002,,4441500,Belt +107,10354000,303203,180,0,0,22000,287,103540001,103540002,,4638900,Belt 111,10413000,303300,15,0,0,368,84,259,260,,32,Necklace 116,10423000,303301,25,0,0,7728,178,271,272,,3472,Necklace -117,10424000,303301,150,0,0,19419,202,274,275,,116880,Necklace -121,10433000,303302,55,0,0,25284,212,283,284,,195120,Necklace -122,10434000,303302,70,0,0,32649,232,286,287,,472500,Necklace +117,10424000,303301,150,0,0,13419,202,274,275,,116880,Necklace +121,10433000,303302,55,0,0,15284,212,283,284,,195120,Necklace +122,10434000,303302,70,0,0,22649,232,286,287,,472500,Necklace 123,10440000,303303,77,0,0,9093,249,451,452,,729000,Necklace -128,10450000,303303,250,0,0,40000,293,104500001,104500002,,4361400,Necklace -129,10451000,303303,120,0,0,20000,255,104510001,104510002,,4536000,Necklace -130,10452000,303303,120,0,0,24000,264,104520001,104520002,,4584600,Necklace -131,10453000,303303,180,0,0,28000,274,104530001,104530002,,4630500,Necklace -132,10454000,303303,180,0,0,32000,284,104540001,104540002,,4889100,Necklace +128,10450000,303303,250,0,0,25000,293,104500001,104500002,,4361400,Necklace +129,10451000,303303,120,0,0,10000,255,104510001,104510002,,4536000,Necklace +130,10452000,303303,120,0,0,14000,264,104520001,104520002,,4584600,Necklace +131,10453000,303303,180,0,0,18000,274,104530001,104530002,,4630500,Necklace +132,10454000,303303,180,0,0,22000,284,104540001,104540002,,4889100,Necklace 133,10510000,303400,2,0,0,5,17,457,458,,1,Ring 137,10514000,303400,24,0,0,6642,170,322,323,,2544,Ring 139,10521000,303401,9,0,0,195,57,325,326,,22,Ring -141,10523000,303401,28,0,0,17493,198,331,332,,3808,Ring -142,10524000,303401,49,0,0,22758,205,334,335,,132900,Ring +141,10523000,303401,28,0,0,10493,198,331,332,,3808,Ring +142,10524000,303401,49,0,0,12758,205,334,335,,132900,Ring 144,10531000,303402,16,0,0,1278,120,337,338,,5568,Ring -146,10533000,303402,64,0,0,29523,224,343,344,,748800,Ring -147,10534000,303402,76,0,0,36075,243,346,347,,889200,Ring -148,10540000,303403,250,0,0,40000,298,105400001,105400002,,1170000,Ring -149,10541000,303403,120,0,0,20000,258,105410001,105410002,,1160400,Ring -150,10542000,303403,120,0,0,24000,268,105420001,105420002,,1160760,Ring -151,10543000,303403,180,0,0,28000,275,105430001,105430002,,1340700,Ring -152,10544000,303403,180,0,0,32000,285,105440001,105440002,,1340700,Ring +146,10533000,303402,64,0,0,19523,224,343,344,,748800,Ring +147,10534000,303402,76,0,0,26075,243,346,347,,889200,Ring +148,10540000,303403,250,0,0,25000,298,105400001,105400002,,1170000,Ring +149,10541000,303403,120,0,0,10000,258,105410001,105410002,,1160400,Ring +150,10542000,303403,120,0,0,14000,268,105420001,105420002,,1160760,Ring +151,10543000,303403,180,0,0,18000,275,105430001,105430002,,1340700,Ring +152,10544000,303403,180,0,0,22000,285,105440001,105440002,,1340700,Ring 153,10550000,303404,360,0,0,3000,340,105500001,105500002,,500000,Ring 154,10551000,303404,360,0,0,3000,325,105510001,105510002,,500000,Ring 155,10552000,303404,360,0,0,3000,325,105520001,105520002,105520003,1000000,Ring @@ -98,4 +98,14 @@ id,result_equipment_id,material_id,material_count,required_action_point,required 175,10630001,0,0,0,0,10000000,999,106300011,,,0,Aura 176,10640001,0,0,0,0,10000000,999,106400011,,,0,Aura 177,10650001,0,0,0,0,10000000,999,106500011,,,0,Aura -178,10650002,0,0,0,0,10000000,999,106500021,,,0,Aura \ No newline at end of file +178,10650002,0,0,0,0,10000000,999,106500021,,,0,Aura +179,10620002,0,0,0,0,10000000,999,106200021,,,0,Aura +180,10630002,0,0,0,0,10000000,999,106300021,,,0,Aura +181,10640002,0,0,0,0,10000000,999,106400021,,,0,Aura +182,10650003,0,0,0,0,10000000,999,106500031,,,0,Aura +183,10650004,0,0,0,0,10000000,999,106500041,,,0,Aura +184,10620003,0,0,0,0,10000000,999,106200031,,,0,Aura +185,10630003,0,0,0,0,10000000,999,106300031,,,0,Aura +186,10640003,0,0,0,0,10000000,999,106400031,,,0,Aura +187,10650005,0,0,0,0,10000000,999,106500051,,,0,Aura +188,10650006,0,0,0,0,10000000,999,106500061,,,0,Aura \ No newline at end of file diff --git a/Lib9c/TableCSV/Item/EquipmentItemSheet.csv b/Lib9c/TableCSV/Item/EquipmentItemSheet.csv index 496eddb9889..4185e739455 100644 --- a/Lib9c/TableCSV/Item/EquipmentItemSheet.csv +++ b/Lib9c/TableCSV/Item/EquipmentItemSheet.csv @@ -1,184 +1,195 @@ id,_name,item_sub_type,grade,elemental_type,set_id,stat_type,stat_value,attack_range,spine_resource_path,exp 10100000,Wooden Club,Weapon,0,Normal,0,ATK,1,2,10100000,10 -10110000,Long Sword,Weapon,1,Normal,1,ATK,11,2,10110000,1 -10111000,Long Sword,Weapon,1,Fire,2,ATK,14,2,10111000,1 -10112000,Long Sword,Weapon,1,Water,3,ATK,17,2,10112000,1 -10113000,Long Sword,Weapon,1,Land,4,ATK,55,2,10113000,6 -10114000,Long Sword,Weapon,1,Wind,5,ATK,136,2,10114000,7 -10120000,Gladiator Sword,Weapon,2,Normal,6,ATK,31,2,10120000,14 -10121000,Gladiator Sword,Weapon,2,Fire,7,ATK,32,2,10121000,18 -10122000,Gladiator Sword,Weapon,2,Water,8,ATK,38,2,10122000,117 -10123000,Gladiator Sword,Weapon,2,Land,9,ATK,152,2,10123000,139 -10124000,Gladiator Sword,Weapon,2,Wind,10,ATK,327,2,10124000,150 -10130000,Black Crow Sword,Weapon,3,Normal,11,ATK,78,2,10130000,90 -10131000,Black Crow Sword,Weapon,3,Fire,12,ATK,81,2,10131000,150 -10132000,Black Crow Sword,Weapon,3,Water,13,ATK,92,2,10132000,1191 -10133000,Black Crow Sword,Weapon,3,Land,14,ATK,354,2,10133000,2074 -10134000,Black Crow Sword,Weapon,3,Wind,15,ATK,693,2,10134000,2288 -10130001,Heavy Sword,Weapon,3,Normal,11,ATK,170,2,10130001,1611 -10131001,Heavy Sword,Weapon,3,Fire,12,ATK,179,2,10131001,2931 -10132001,Heavy Sword,Weapon,3,Water,13,ATK,196,2,10132001,3000 -10133001,Heavy Sword,Weapon,3,Land,14,ATK,908,2,10133001,3000 -10134001,Heavy Sword,Weapon,3,Wind,15,ATK,967,2,10134001,3000 -10140000,War Sword,Weapon,4,Normal,11,ATK,3094,2,10140000,60000 -10141000,War Sword,Weapon,4,Fire,12,ATK,1934,2,10141000,60000 -10142000,War Sword,Weapon,4,Water,13,ATK,2224,2,10142000,80000 -10143000,War Sword,Weapon,4,Land,14,ATK,2514,2,10143000,80000 -10144000,War Sword,Weapon,4,Wind,15,ATK,2804,2,10144000,120000 -10150000,Dainsleif,Weapon,5,Normal,16,ATK,6063,2,10150000,2000000 -10151000,Dainsleif,Weapon,5,Fire,17,ATK,4331,2,10151000,1500000 -10152000,Dainsleif,Weapon,5,Water,18,ATK,4331,2,10152000,1500000 -10153000,Dainsleif,Weapon,5,Land,19,ATK,6063,2,10153000,2000000 -10154000,Dainsleif,Weapon,5,Wind,20,ATK,6063,2,10154000,2000000 -10140001,Asgardian Sword,Weapon,5,Normal,11,ATK,765,2,10140001,1 -10141001,Asgardian Sword,Weapon,5,Fire,12,ATK,782,2,10141001,1 -10142001,Asgardian Sword,Weapon,5,Water,13,ATK,798,2,10142001,1 -10143001,Asgardian Sword,Weapon,5,Land,14,ATK,1221,2,10143001,1 -10144001,Asgardian Sword,Weapon,5,Wind,15,ATK,1525,2,10144001,1 -10150001,Surt's Sword,Weapon,5,Normal,16,ATK,2157,2,10150001,1 -10151001,Surt's Sword,Weapon,5,Fire,17,ATK,2190,2,10151001,1 -10152001,Surt's Sword,Weapon,5,Water,18,ATK,2223,2,10152001,1 -10153001,Surt's Sword,Weapon,5,Land,19,ATK,3390,2,10153001,1 -10154001,Surt's Sword,Weapon,5,Wind,20,ATK,4219,2,10154001,1 -10155000,Valkyrie’s Sword,Weapon,5,Normal,15,ATK,2902,2,10155000,1 -10200000,Ragged Clothes,Armor,0,Normal,0,HP,30,2,Character/Player/10200000,10 -10210000,Casual Clothes,Armor,1,Normal,1,HP,180,2,Character/Player/10210000,1 -10211000,Casual Clothes,Armor,1,Fire,2,HP,222,2,Character/Player/10211000,1 -10212000,Casual Clothes,Armor,1,Water,3,HP,288,2,Character/Player/10212000,2 -10213000,Casual Clothes,Armor,1,Land,4,HP,915,2,Character/Player/10213000,4 -10214000,Casual Clothes,Armor,1,Wind,5,HP,2182,2,Character/Player/10214000,5 -10220000,Leather Clothes,Armor,2,Normal,6,HP,531,2,Character/Player/10220000,10 -10221000,Leather Clothes,Armor,2,Fire,7,HP,549,2,Character/Player/10221000,120 -10222000,Leather Clothes,Armor,2,Water,8,HP,621,2,Character/Player/10222000,150 -10223000,Leather Clothes,Armor,2,Land,9,HP,2431,2,Character/Player/10223000,150 -10224000,Leather Clothes,Armor,2,Wind,10,HP,5109,2,Character/Player/10224000,150 -10230000,Black Crow Armor,Armor,3,Normal,11,HP,1337,2,Character/Player/10230000,130 -10231000,Black Crow Armor,Armor,3,Fire,12,HP,1418,2,Character/Player/10231000,132 -10232000,Black Crow Armor,Armor,3,Water,13,HP,1580,2,Character/Player/10232000,1300 -10233000,Black Crow Armor,Armor,3,Land,14,HP,8370,2,Character/Player/10233000,2000 -10234000,Black Crow Armor,Armor,3,Wind,15,HP,10571,2,Character/Player/10234000,2000 -10230001,Hermes' Clothes,Armor,3,Normal,11,HP,2811,2,Character/Player/10230001,1700 -10231001,Hermes' Clothes,Armor,3,Fire,12,HP,3009,2,Character/Player/10231001,3000 -10232001,Hermes' Clothes,Armor,3,Water,13,HP,3141,2,Character/Player/10232001,3000 -10233001,Hermes' Clothes,Armor,3,Land,14,HP,11482,2,Character/Player/10233001,3000 -10234001,Hermes' Clothes,Armor,3,Wind,15,HP,12302,2,Character/Player/10234001,3000 -10240000,War Armor,Armor,4,Normal,11,HP,34446,2,Character/Player/10240000,60000 -10241000,War Armor,Armor,4,Fire,12,HP,24604,2,Character/Player/10241000,60000 -10242000,War Armor,Armor,4,Water,13,HP,27064,2,Character/Player/10242000,80000 -10243000,War Armor,Armor,4,Land,14,HP,29525,2,Character/Player/10243000,80000 -10244000,War Armor,Armor,4,Wind,15,HP,31985,2,Character/Player/10244000,120000 -10250001,Ancient Armor,Armor,5,Normal,11,HP,67513,2,Character/Player/10250001,2000000 -10251001,Ancient Armor,Armor,5,Fire,12,HP,48224,2,Character/Player/10251001,1500000 -10252001,Ancient Armor,Armor,5,Water,13,HP,48224,2,Character/Player/10252001,1500000 -10253001,Ancient Armor,Armor,5,Land,14,HP,67513,2,Character/Player/10253001,2000000 -10254001,Ancient Armor,Armor,5,Wind,15,HP,67513,2,Character/Player/10254001,2000000 -10250000,Legendary Armor,Armor,5,Normal,11,HP,15550,2,Character/Player/10250000,1 -10251000,Legendary Armor,Armor,5,Fire,12,HP,15848,2,Character/Player/10251000,1 -10252000,Legendary Armor,Armor,5,Water,13,HP,16146,2,Character/Player/10252000,1 -10253000,Legendary Armor,Armor,5,Land,14,HP,24665,2,Character/Player/10253000,1 -10254000,Legendary Armor,Armor,5,Wind,15,HP,30823,2,Character/Player/10254000,1 -10240001,Asgardian Armor,Armor,5,Normal,11,HP,10358,2,Character/Player/10240001,1 -10241001,Asgardian Armor,Armor,5,Fire,12,HP,10571,2,Character/Player/10241001,1 -10242001,Asgardian Armor,Armor,5,Water,13,HP,10783,2,Character/Player/10242001,1 -10243001,Asgardian Armor,Armor,5,Land,14,HP,16494,2,Character/Player/10243001,1 -10244001,Asgardian Armor,Armor,5,Wind,15,HP,20647,2,Character/Player/10244001,1 -10255000,Heavenly Cat,Armor,5,Normal,11,HP,42856,2,Character/Player/10235000,1 -10310000,Basic Belt,Belt,1,Normal,1,SPD,46,2,10310000,1 -10311000,Basic Belt,Belt,1,Fire,2,SPD,62,2,10311000,2 -10312000,Basic Belt,Belt,1,Water,3,SPD,69,2,10312000,3 -10313000,Basic Belt,Belt,1,Land,4,SPD,239,2,10313000,8 -10314000,Basic Belt,Belt,1,Wind,5,SPD,610,2,10314000,8 -10320000,Leather Belt,Belt,2,Normal,6,SPD,137,2,10320000,16 -10321000,Leather Belt,Belt,2,Fire,7,SPD,141,2,10321000,20 -10322000,Leather Belt,Belt,2,Water,8,SPD,166,2,10322000,150 -10323000,Leather Belt,Belt,2,Land,9,SPD,718,2,10323000,150 -10324000,Leather Belt,Belt,2,Wind,10,SPD,1314,2,10324000,150 -10330000,Solid Belt,Belt,3,Normal,11,SPD,350,2,10330000,72 -10331000,Solid Belt,Belt,3,Fire,12,SPD,359,2,10331000,112 -10332000,Solid Belt,Belt,3,Water,13,SPD,425,2,10332000,3000 -10333000,Solid Belt,Belt,3,Land,14,SPD,1701,2,10333000,3000 -10334000,Solid Belt,Belt,3,Wind,15,SPD,2883,2,10334000,2000 -10340000,War Belt,Belt,4,Normal,11,SPD,1215,2,10340000,8000 -10341000,War Belt,Belt,4,Fire,12,SPD,1262,2,10341000,50000 -10342000,War Belt,Belt,4,Water,13,SPD,2292,2,10342000,50000 -10343000,War Belt,Belt,4,Land,14,SPD,2292,2,10343000,50000 -10344000,War Belt,Belt,4,Wind,15,SPD,2292,2,10344000,27500 -10350000,Legendary Belt,Belt,4,Normal,11,SPD,7334,2,10350000,60000 -10351000,Legendary Belt,Belt,4,Fire,12,SPD,4584,2,10351000,60000 -10352000,Legendary Belt,Belt,4,Water,13,SPD,5272,2,10352000,80000 -10353000,Legendary Belt,Belt,4,Land,14,SPD,5959,2,10353000,80000 -10354000,Legendary Belt,Belt,4,Wind,15,SPD,6647,2,10354000,100000 -10410000,Thin Necklace,Necklace,1,Normal,1,HIT,70,0,10410000,1 -10411000,Thin Necklace,Necklace,1,Fire,2,HIT,81,0,10411000,2 -10412000,Thin Necklace,Necklace,1,Water,3,HIT,99,0,10412000,3 -10413000,Thin Necklace,Necklace,1,Land,4,HIT,357,0,10413000,5 -10414000,Thin Necklace,Necklace,1,Wind,5,HIT,863,0,10414000,7 -10420000,Guardian Necklace,Necklace,2,Normal,6,HIT,192,0,10420000,25 -10421000,Guardian Necklace,Necklace,2,Fire,7,HIT,197,0,10421000,32 -10422000,Guardian Necklace,Necklace,2,Water,8,HIT,230,0,10422000,150 -10423000,Guardian Necklace,Necklace,2,Land,9,HIT,1002,0,10423000,150 -10424000,Guardian Necklace,Necklace,2,Wind,10,HIT,1682,0,10424000,150 -10430000,Mana Necklace,Necklace,3,Normal,11,HIT,510,0,10430000,150 -10431000,Mana Necklace,Necklace,3,Fire,12,HIT,522,0,10431000,250 -10432000,Mana Necklace,Necklace,3,Water,13,HIT,608,0,10432000,3000 -10433000,Mana Necklace,Necklace,3,Land,14,HIT,2151,0,10433000,3000 -10434000,Mana Necklace,Necklace,3,Wind,15,HIT,2333,0,10434000,3000 -10440000,Warrior's Necklace,Necklace,4,Normal,11,HIT,2031,0,10440000,30000 -10441000,Warrior's Necklace,Necklace,4,Fire,12,HIT,3047,0,10441000,60000 -10442000,Warrior's Necklace,Necklace,4,Water,13,HIT,3047,0,10442000,60000 -10443000,Warrior's Necklace,Necklace,4,Land,14,HIT,3047,0,10443000,60000 -10444000,Warrior's Necklace,Necklace,4,Wind,15,HIT,3047,0,10444000,60000 -10450000,Legendary Necklace,Necklace,4,Normal,11,HIT,7466,0,10450000,50000 -10451000,Legendary Necklace,Necklace,4,Fire,12,HIT,4666,0,10451000,50000 -10452000,Legendary Necklace,Necklace,4,Water,13,HIT,5366,0,10452000,80000 -10453000,Legendary Necklace,Necklace,4,Land,14,HIT,6066,0,10453000,80000 -10454000,Legendary Necklace,Necklace,4,Wind,15,HIT,6766,0,10454000,100000 -10510000,Thin Ring,Ring,1,Normal,1,DEF,8,0,10510000,1 -10511000,Thin Ring,Ring,1,Fire,2,DEF,9,0,10511000,2 -10512000,Thin Ring,Ring,1,Water,3,DEF,11,0,10512000,3 -10513000,Thin Ring,Ring,1,Land,4,DEF,44,0,10513000,5 -10514000,Thin Ring,Ring,1,Wind,5,DEF,107,0,10514000,7 -10520000,Guardian Ring,Ring,2,Normal,6,DEF,23,0,10520000,25 -10521000,Guardian Ring,Ring,2,Fire,7,DEF,24,0,10521000,32 -10522000,Guardian Ring,Ring,2,Water,8,DEF,29,0,10522000,150 -10523000,Guardian Ring,Ring,2,Land,9,DEF,122,0,10523000,150 -10524000,Guardian Ring,Ring,2,Wind,10,DEF,189,0,10524000,150 -10530000,Mana Ring,Ring,3,Normal,11,DEF,63,0,10530000,50 -10531000,Mana Ring,Ring,3,Fire,12,DEF,65,0,10531000,100 -10532000,Mana Ring,Ring,3,Water,13,DEF,74,0,10532000,1000 -10533000,Mana Ring,Ring,3,Land,14,DEF,251,0,10533000,3000 -10534000,Mana Ring,Ring,3,Wind,15,DEF,270,0,10534000,3000 -10540000,Warrior's Ring,Ring,4,Normal,11,DEF,864,0,10540000,50000 -10541000,Warrior's Ring,Ring,4,Fire,12,DEF,540,0,10541000,50000 -10542000,Warrior's Ring,Ring,4,Water,13,DEF,621,0,10542000,80000 -10543000,Warrior's Ring,Ring,4,Land,14,DEF,702,0,10543000,80000 -10544000,Warrior's Ring,Ring,4,Wind,15,DEF,783,0,10544000,100000 -10550000,Ancient Ring,Ring,5,Normal,11,DEF,1946,0,10550000,2000000 -10551000,Ancient Ring,Ring,5,Fire,12,DEF,1209,0,10551000,1500000 -10552000,Ancient Ring,Ring,5,Water,13,DEF,1209,0,10552000,1500000 -10553000,Ancient Ring,Ring,5,Land,14,DEF,1946,0,10553000,2000000 -10554000,Ancient Ring,Ring,5,Wind,15,DEF,1946,0,10554000,2000000 -11320000,Blue Sapphire Belt,Belt,2,Normal,6,SPD,176,2,11320000,1 -11420000,Blue Sapphire Necklace,Necklace,2,Normal,6,HIT,227,0,11420000,1 -11520000,Blue Sapphire Ring,Ring,2,Normal,6,DEF,50,0,11520000,1 +10110000,Long Sword,Weapon,1,Normal,1,ATK,11,2,10110000,5 +10111000,Long Sword,Weapon,1,Fire,2,ATK,14,2,10111000,5 +10112000,Long Sword,Weapon,1,Water,3,ATK,17,2,10112000,5 +10113000,Long Sword,Weapon,1,Land,4,ATK,55,2,10113000,8 +10114000,Long Sword,Weapon,1,Wind,5,ATK,136,2,10114000,9 +10120000,Gladiator Sword,Weapon,2,Normal,6,ATK,31,2,10120000,100 +10121000,Gladiator Sword,Weapon,2,Fire,7,ATK,32,2,10121000,100 +10122000,Gladiator Sword,Weapon,2,Water,8,ATK,38,2,10122000,141 +10123000,Gladiator Sword,Weapon,2,Land,9,ATK,152,2,10123000,167 +10124000,Gladiator Sword,Weapon,2,Wind,10,ATK,327,2,10124000,180 +10130000,Black Crow Sword,Weapon,3,Normal,11,ATK,78,2,10130000,500 +10131000,Black Crow Sword,Weapon,3,Fire,12,ATK,81,2,10131000,700 +10132000,Black Crow Sword,Weapon,3,Water,13,ATK,92,2,10132000,1430 +10133000,Black Crow Sword,Weapon,3,Land,14,ATK,354,2,10133000,2489 +10134000,Black Crow Sword,Weapon,3,Wind,15,ATK,693,2,10134000,2746 +10130001,Heavy Sword,Weapon,3,Normal,11,ATK,170,2,10130001,1934 +10131001,Heavy Sword,Weapon,3,Fire,12,ATK,179,2,10131001,3518 +10132001,Heavy Sword,Weapon,3,Water,13,ATK,196,2,10132001,3600 +10133001,Heavy Sword,Weapon,3,Land,14,ATK,908,2,10133001,3600 +10134001,Heavy Sword,Weapon,3,Wind,15,ATK,967,2,10134001,3600 +10140000,War Sword,Weapon,4,Normal,11,ATK,3094,2,10140000,75000 +10141000,War Sword,Weapon,4,Fire,12,ATK,1934,2,10141000,75000 +10142000,War Sword,Weapon,4,Water,13,ATK,2224,2,10142000,96000 +10143000,War Sword,Weapon,4,Land,14,ATK,2514,2,10143000,96000 +10144000,War Sword,Weapon,4,Wind,15,ATK,2804,2,10144000,144000 +10150000,Dainsleif,Weapon,5,Normal,16,ATK,6063,2,10150000,2400000 +10151000,Dainsleif,Weapon,5,Fire,17,ATK,4331,2,10151000,1800000 +10152000,Dainsleif,Weapon,5,Water,18,ATK,4331,2,10152000,1800000 +10153000,Dainsleif,Weapon,5,Land,19,ATK,6063,2,10153000,2400000 +10154000,Dainsleif,Weapon,5,Wind,20,ATK,6063,2,10154000,2400000 +10140001,Asgardian Sword,Weapon,5,Normal,11,ATK,765,2,10140001,2 +10141001,Asgardian Sword,Weapon,5,Fire,12,ATK,782,2,10141001,2 +10142001,Asgardian Sword,Weapon,5,Water,13,ATK,798,2,10142001,2 +10143001,Asgardian Sword,Weapon,5,Land,14,ATK,1221,2,10143001,2 +10144001,Asgardian Sword,Weapon,5,Wind,15,ATK,1525,2,10144001,2 +10150001,Surt's Sword,Weapon,5,Normal,16,ATK,2157,2,10150001,2 +10151001,Surt's Sword,Weapon,5,Fire,17,ATK,2190,2,10151001,2 +10152001,Surt's Sword,Weapon,5,Water,18,ATK,2223,2,10152001,2 +10153001,Surt's Sword,Weapon,5,Land,19,ATK,3390,2,10153001,2 +10154001,Surt's Sword,Weapon,5,Wind,20,ATK,4219,2,10154001,2 +10155000,Valkyrie’s Sword,Weapon,5,Normal,15,ATK,2902,2,10155000,2 +10200000,Ragged Clothes,Armor,0,Normal,0,HP,30,2,Character/Player/10200000,12 +10210000,Casual Clothes,Armor,1,Normal,1,HP,180,2,Character/Player/10210000,5 +10211000,Casual Clothes,Armor,1,Fire,2,HP,222,2,Character/Player/10211000,5 +10212000,Casual Clothes,Armor,1,Water,3,HP,288,2,Character/Player/10212000,5 +10213000,Casual Clothes,Armor,1,Land,4,HP,915,2,Character/Player/10213000,6 +10214000,Casual Clothes,Armor,1,Wind,5,HP,2182,2,Character/Player/10214000,8 +10220000,Leather Clothes,Armor,2,Normal,6,HP,531,2,Character/Player/10220000,100 +10221000,Leather Clothes,Armor,2,Fire,7,HP,549,2,Character/Player/10221000,144 +10222000,Leather Clothes,Armor,2,Water,8,HP,621,2,Character/Player/10222000,180 +10223000,Leather Clothes,Armor,2,Land,9,HP,2431,2,Character/Player/10223000,180 +10224000,Leather Clothes,Armor,2,Wind,10,HP,5109,2,Character/Player/10224000,180 +10230000,Black Crow Armor,Armor,3,Normal,11,HP,1337,2,Character/Player/10230000,500 +10231000,Black Crow Armor,Armor,3,Fire,12,HP,1418,2,Character/Player/10231000,700 +10232000,Black Crow Armor,Armor,3,Water,13,HP,1580,2,Character/Player/10232000,1560 +10233000,Black Crow Armor,Armor,3,Land,14,HP,8370,2,Character/Player/10233000,2400 +10234000,Black Crow Armor,Armor,3,Wind,15,HP,10571,2,Character/Player/10234000,2400 +10230001,Hermes' Clothes,Armor,3,Normal,11,HP,2811,2,Character/Player/10230001,2040 +10231001,Hermes' Clothes,Armor,3,Fire,12,HP,3009,2,Character/Player/10231001,3600 +10232001,Hermes' Clothes,Armor,3,Water,13,HP,3141,2,Character/Player/10232001,3600 +10233001,Hermes' Clothes,Armor,3,Land,14,HP,11482,2,Character/Player/10233001,3600 +10234001,Hermes' Clothes,Armor,3,Wind,15,HP,12302,2,Character/Player/10234001,3600 +10240000,War Armor,Armor,4,Normal,11,HP,34446,2,Character/Player/10240000,75000 +10241000,War Armor,Armor,4,Fire,12,HP,24604,2,Character/Player/10241000,75000 +10242000,War Armor,Armor,4,Water,13,HP,27064,2,Character/Player/10242000,96000 +10243000,War Armor,Armor,4,Land,14,HP,29525,2,Character/Player/10243000,96000 +10244000,War Armor,Armor,4,Wind,15,HP,31985,2,Character/Player/10244000,144000 +10250001,Ancient Armor,Armor,5,Normal,11,HP,67513,2,Character/Player/10250001,2400000 +10251001,Ancient Armor,Armor,5,Fire,12,HP,48224,2,Character/Player/10251001,1800000 +10252001,Ancient Armor,Armor,5,Water,13,HP,48224,2,Character/Player/10252001,1800000 +10253001,Ancient Armor,Armor,5,Land,14,HP,67513,2,Character/Player/10253001,2400000 +10254001,Ancient Armor,Armor,5,Wind,15,HP,67513,2,Character/Player/10254001,2400000 +10250000,Legendary Armor,Armor,5,Normal,11,HP,15550,2,Character/Player/10250000,2 +10251000,Legendary Armor,Armor,5,Fire,12,HP,15848,2,Character/Player/10251000,2 +10252000,Legendary Armor,Armor,5,Water,13,HP,16146,2,Character/Player/10252000,2 +10253000,Legendary Armor,Armor,5,Land,14,HP,24665,2,Character/Player/10253000,2 +10254000,Legendary Armor,Armor,5,Wind,15,HP,30823,2,Character/Player/10254000,2 +10240001,Asgardian Armor,Armor,5,Normal,11,HP,10358,2,Character/Player/10240001,2 +10241001,Asgardian Armor,Armor,5,Fire,12,HP,10571,2,Character/Player/10241001,2 +10242001,Asgardian Armor,Armor,5,Water,13,HP,10783,2,Character/Player/10242001,2 +10243001,Asgardian Armor,Armor,5,Land,14,HP,16494,2,Character/Player/10243001,2 +10244001,Asgardian Armor,Armor,5,Wind,15,HP,20647,2,Character/Player/10244001,2 +10255000,Heavenly Cat,Armor,5,Normal,11,HP,42856,2,Character/Player/10235000,2 +10310000,Basic Belt,Belt,1,Normal,1,SPD,46,2,10310000,5 +10311000,Basic Belt,Belt,1,Fire,2,SPD,62,2,10311000,6 +10312000,Basic Belt,Belt,1,Water,3,SPD,69,2,10312000,8 +10313000,Basic Belt,Belt,1,Land,4,SPD,239,2,10313000,10 +10314000,Basic Belt,Belt,1,Wind,5,SPD,610,2,10314000,10 +10320000,Leather Belt,Belt,2,Normal,6,SPD,137,2,10320000,100 +10321000,Leather Belt,Belt,2,Fire,7,SPD,141,2,10321000,100 +10322000,Leather Belt,Belt,2,Water,8,SPD,166,2,10322000,180 +10323000,Leather Belt,Belt,2,Land,9,SPD,718,2,10323000,180 +10324000,Leather Belt,Belt,2,Wind,10,SPD,1314,2,10324000,180 +10330000,Solid Belt,Belt,3,Normal,11,SPD,350,2,10330000,500 +10331000,Solid Belt,Belt,3,Fire,12,SPD,359,2,10331000,700 +10332000,Solid Belt,Belt,3,Water,13,SPD,425,2,10332000,3600 +10333000,Solid Belt,Belt,3,Land,14,SPD,1701,2,10333000,3600 +10334000,Solid Belt,Belt,3,Wind,15,SPD,2883,2,10334000,2400 +10340000,War Belt,Belt,4,Normal,11,SPD,1215,2,10340000,9600 +10341000,War Belt,Belt,4,Fire,12,SPD,1262,2,10341000,60000 +10342000,War Belt,Belt,4,Water,13,SPD,2292,2,10342000,60000 +10343000,War Belt,Belt,4,Land,14,SPD,2292,2,10343000,60000 +10344000,War Belt,Belt,4,Wind,15,SPD,2292,2,10344000,33000 +10350000,Legendary Belt,Belt,4,Normal,11,SPD,7334,2,10350000,75000 +10351000,Legendary Belt,Belt,4,Fire,12,SPD,4584,2,10351000,75000 +10352000,Legendary Belt,Belt,4,Water,13,SPD,5272,2,10352000,96000 +10353000,Legendary Belt,Belt,4,Land,14,SPD,5959,2,10353000,96000 +10354000,Legendary Belt,Belt,4,Wind,15,SPD,6647,2,10354000,120000 +10410000,Thin Necklace,Necklace,1,Normal,1,HIT,70,0,10410000,5 +10411000,Thin Necklace,Necklace,1,Fire,2,HIT,81,0,10411000,5 +10412000,Thin Necklace,Necklace,1,Water,3,HIT,99,0,10412000,5 +10413000,Thin Necklace,Necklace,1,Land,4,HIT,357,0,10413000,8 +10414000,Thin Necklace,Necklace,1,Wind,5,HIT,863,0,10414000,10 +10420000,Guardian Necklace,Necklace,2,Normal,6,HIT,192,0,10420000,100 +10421000,Guardian Necklace,Necklace,2,Fire,7,HIT,197,0,10421000,100 +10422000,Guardian Necklace,Necklace,2,Water,8,HIT,230,0,10422000,180 +10423000,Guardian Necklace,Necklace,2,Land,9,HIT,1002,0,10423000,180 +10424000,Guardian Necklace,Necklace,2,Wind,10,HIT,1682,0,10424000,180 +10430000,Mana Necklace,Necklace,3,Normal,11,HIT,510,0,10430000,180 +10431000,Mana Necklace,Necklace,3,Fire,12,HIT,522,0,10431000,300 +10432000,Mana Necklace,Necklace,3,Water,13,HIT,608,0,10432000,3600 +10433000,Mana Necklace,Necklace,3,Land,14,HIT,2151,0,10433000,3600 +10434000,Mana Necklace,Necklace,3,Wind,15,HIT,2333,0,10434000,3600 +10440000,Warrior's Necklace,Necklace,4,Normal,11,HIT,2031,0,10440000,50000 +10441000,Warrior's Necklace,Necklace,4,Fire,12,HIT,3047,0,10441000,75000 +10442000,Warrior's Necklace,Necklace,4,Water,13,HIT,3047,0,10442000,75000 +10443000,Warrior's Necklace,Necklace,4,Land,14,HIT,3047,0,10443000,75000 +10444000,Warrior's Necklace,Necklace,4,Wind,15,HIT,3047,0,10444000,75000 +10450000,Legendary Necklace,Necklace,4,Normal,11,HIT,7466,0,10450000,60000 +10451000,Legendary Necklace,Necklace,4,Fire,12,HIT,4666,0,10451000,60000 +10452000,Legendary Necklace,Necklace,4,Water,13,HIT,5366,0,10452000,96000 +10453000,Legendary Necklace,Necklace,4,Land,14,HIT,6066,0,10453000,96000 +10454000,Legendary Necklace,Necklace,4,Wind,15,HIT,6766,0,10454000,120000 +10510000,Thin Ring,Ring,1,Normal,1,DEF,8,0,10510000,5 +10511000,Thin Ring,Ring,1,Fire,2,DEF,9,0,10511000,5 +10512000,Thin Ring,Ring,1,Water,3,DEF,11,0,10512000,5 +10513000,Thin Ring,Ring,1,Land,4,DEF,44,0,10513000,8 +10514000,Thin Ring,Ring,1,Wind,5,DEF,107,0,10514000,10 +10520000,Guardian Ring,Ring,2,Normal,6,DEF,23,0,10520000,100 +10521000,Guardian Ring,Ring,2,Fire,7,DEF,24,0,10521000,100 +10522000,Guardian Ring,Ring,2,Water,8,DEF,29,0,10522000,180 +10523000,Guardian Ring,Ring,2,Land,9,DEF,122,0,10523000,180 +10524000,Guardian Ring,Ring,2,Wind,10,DEF,189,0,10524000,180 +10530000,Mana Ring,Ring,3,Normal,11,DEF,63,0,10530000,500 +10531000,Mana Ring,Ring,3,Fire,12,DEF,65,0,10531000,700 +10532000,Mana Ring,Ring,3,Water,13,DEF,74,0,10532000,1200 +10533000,Mana Ring,Ring,3,Land,14,DEF,251,0,10533000,3600 +10534000,Mana Ring,Ring,3,Wind,15,DEF,270,0,10534000,3600 +10540000,Warrior's Ring,Ring,4,Normal,11,DEF,864,0,10540000,60000 +10541000,Warrior's Ring,Ring,4,Fire,12,DEF,540,0,10541000,60000 +10542000,Warrior's Ring,Ring,4,Water,13,DEF,621,0,10542000,96000 +10543000,Warrior's Ring,Ring,4,Land,14,DEF,702,0,10543000,96000 +10544000,Warrior's Ring,Ring,4,Wind,15,DEF,783,0,10544000,120000 +10550000,Ancient Ring,Ring,5,Normal,11,DEF,1946,0,10550000,2400000 +10551000,Ancient Ring,Ring,5,Fire,12,DEF,1209,0,10551000,1800000 +10552000,Ancient Ring,Ring,5,Water,13,DEF,1209,0,10552000,1800000 +10553000,Ancient Ring,Ring,5,Land,14,DEF,1946,0,10553000,2400000 +10554000,Ancient Ring,Ring,5,Wind,15,DEF,1946,0,10554000,2400000 +11320000,Blue Sapphire Belt,Belt,2,Normal,6,SPD,176,2,11320000,2 +11420000,Blue Sapphire Necklace,Necklace,2,Normal,6,HIT,227,0,11420000,2 +11520000,Blue Sapphire Ring,Ring,2,Normal,6,DEF,50,0,11520000,2 12001001,Special Crystal Belt,Belt,2,Normal,0,ATK,1,0,12001001,1 12001002,Special Crystal Necklace,Necklace,3,Normal,1,ATK,1,0,12001002,1 12001003,Special Crystal Ring,Ring,4,Normal,2,ATK,1,0,12001003,1 -10350001,Ancient Belt,Belt,5,Normal,15,SPD,14373,2,10350001,2000000 -10351001,Ancient Belt,Belt,5,Fire,15,SPD,10267,2,10351001,1500000 -10352001,Ancient Belt,Belt,5,Water,15,SPD,10267,2,10352001,1500000 -10353001,Ancient Belt,Belt,5,Land,15,SPD,14373,2,10353001,2000000 -10354001,Ancient Belt,Belt,5,Wind,15,SPD,14373,2,10354001,2000000 -10450001,Ancient Necklace,Necklace,5,Normal,15,HIT,15363,0,10450001,2000000 -10451001,Ancient Necklace,Necklace,5,Fire,15,HIT,10452,0,10451001,1500000 -10452001,Ancient Necklace,Necklace,5,Water,15,HIT,10452,0,10452001,1500000 -10453001,Ancient Necklace,Necklace,5,Land,15,HIT,15363,0,10453001,2000000 -10454001,Ancient Necklace,Necklace,5,Wind,15,HIT,15363,0,10454001,2000000 -10610000,Nimble Aura,Aura,1,Normal,0,HIT,10,0,10610000,1 -10620000,Nimble Aura,Aura,2,Normal,0,HIT,10,0,10610000,20 -10630000,Nimble Aura,Aura,3,Normal,0,HIT,10,0,10610000,400 -10620001,Beast Aura,Aura,2,Normal,0,ATK,10,0,10620001,20 -10630001,Beast Aura,Aura,3,Normal,0,ATK,10,0,10620001,400 -10640001,Beast Aura,Aura,4,Normal,0,ATK,10,0,10620001,4000 -10650001,Beast Aura,Aura,5,Normal,0,ATK,10,0,10620001,40000 -10650002,Lord's Beast Aura,Aura,5,Normal,0,ATK,10,0,10620001,40000 \ No newline at end of file +10350001,Ancient Belt,Belt,5,Normal,15,SPD,14373,2,10350001,2400000 +10351001,Ancient Belt,Belt,5,Fire,15,SPD,10267,2,10351001,1800000 +10352001,Ancient Belt,Belt,5,Water,15,SPD,10267,2,10352001,1800000 +10353001,Ancient Belt,Belt,5,Land,15,SPD,14373,2,10353001,2400000 +10354001,Ancient Belt,Belt,5,Wind,15,SPD,14373,2,10354001,2400000 +10450001,Ancient Necklace,Necklace,5,Normal,15,HIT,15363,0,10450001,2400000 +10451001,Ancient Necklace,Necklace,5,Fire,15,HIT,10452,0,10451001,1800000 +10452001,Ancient Necklace,Necklace,5,Water,15,HIT,10452,0,10452001,1800000 +10453001,Ancient Necklace,Necklace,5,Land,15,HIT,15363,0,10453001,2400000 +10454001,Ancient Necklace,Necklace,5,Wind,15,HIT,15363,0,10454001,2400000 +10610000,Nimble Aura,Aura,1,Normal,0,HIT,310,0,10610000,2 +10620000,Nimble Aura,Aura,2,Normal,0,HIT,10,0,10610000,40 +10630000,Nimble Aura,Aura,3,Normal,0,HIT,10,0,10610000,600 +10620001,Beast Aura,Aura,2,Normal,0,ATK,10,0,10620001,40 +10630001,Beast Aura,Aura,3,Normal,0,ATK,10,0,10620001,600 +10640001,Beast Aura,Aura,4,Normal,0,ATK,10,0,10620001,6000 +10650001,Beast Aura,Aura,5,Normal,0,ATK,10,0,10620001,60000 +10650002,Lord's Beast Aura,Aura,5,Normal,0,ATK,10,0,10620001,60000 +10130002,Classic Sword,Weapon,3,Normal,0,ATK,50,2,10130000,100 +10620002,Aegis Aura,Aura,2,Normal,0,HP,10,0,10620001,40 +10630002,Aegis Aura,Aura,3,Normal,0,HP,10,0,10620001,600 +10640002,Aegis Aura,Aura,4,Normal,0,HP,10,0,10620001,6000 +10650003,Aegis Aura,Aura,5,Normal,0,HP,10,0,10620001,60000 +10650004,Lord's Aegis Aura,Aura,5,Normal,0,HP,10,0,10620001,60000 +10620003,Barrage Aura,Aura,2,Normal,0,ATK,10,0,10620001,40 +10630003,Barrage Aura,Aura,3,Normal,0,ATK,10,0,10620001,600 +10640003,Barrage Aura,Aura,4,Normal,0,ATK,10,0,10620001,6000 +10650005,Barrage Aura,Aura,5,Normal,0,ATK,10,0,10620001,60000 +10650006,Lord's Barrage Aura,Aura,5,Normal,0,ATK,10,0,10620001,60000 \ No newline at end of file diff --git a/Lib9c/TableCSV/Item/EquipmentItemSubRecipeSheetV2.csv b/Lib9c/TableCSV/Item/EquipmentItemSubRecipeSheetV2.csv index 8797fa37068..cc444268b94 100644 --- a/Lib9c/TableCSV/Item/EquipmentItemSubRecipeSheetV2.csv +++ b/Lib9c/TableCSV/Item/EquipmentItemSubRecipeSheetV2.csv @@ -501,4 +501,14 @@ ID,required_action_point,required_gold,required_block_index,material_id,material 106300011,0,0,1,,,,,,,1063000111,10000,0,1063000112,10000,0,1063000113,10000,0,1063000114,10000,0,FALSE,1 106400011,0,0,1,,,,,,,1064000111,10000,0,1064000112,10000,0,1064000113,10000,0,1064000114,10000,0,FALSE,1 106500011,0,0,1,,,,,,,1065000111,10000,0,1065000112,10000,0,1065000113,10000,0,1065000114,10000,0,FALSE,1 -106500021,0,0,1,,,,,,,1065000121,10000,0,1065000122,10000,0,1065000123,10000,0,1065000124,10000,0,FALSE,1 \ No newline at end of file +106500021,0,0,1,,,,,,,1065000121,10000,0,1065000122,10000,0,1065000123,10000,0,1065000124,10000,0,FALSE,1 +106200021,0,0,1,,,,,,,1062000211,10000,0,1062000212,10000,0,1062000213,10000,0,,,,FALSE,1 +106300021,0,0,1,,,,,,,1063000211,10000,0,1063000212,10000,0,1063000213,10000,0,,,,FALSE,1 +106400021,0,0,1,,,,,,,1064000211,10000,0,1064000212,10000,0,1064000213,10000,0,,,,FALSE,1 +106500031,0,0,1,,,,,,,1065000311,10000,0,1065000312,10000,0,1065000313,10000,0,,,,FALSE,1 +106500041,0,0,1,,,,,,,1065000411,10000,0,1065000412,10000,0,1065000413,10000,0,,,,FALSE,1 +106200031,0,0,1,,,,,,,1062000311,10000,0,1062000312,10000,0,1062000313,10000,0,,,,FALSE,1 +106300031,0,0,1,,,,,,,1063000311,10000,0,1063000312,10000,0,1063000313,10000,0,,,,FALSE,1 +106400031,0,0,1,,,,,,,1064000311,10000,0,1064000312,10000,0,1064000313,10000,0,,,,FALSE,1 +106500051,0,0,1,,,,,,,1065000511,10000,0,1065000512,10000,0,1065000513,10000,0,,,,FALSE,1 +106500061,0,0,1,,,,,,,1065000611,10000,0,1065000612,10000,0,1065000613,10000,0,,,,FALSE,1 \ No newline at end of file diff --git a/Lib9c/TableCSV/Item/ItemRequirementSheet.csv b/Lib9c/TableCSV/Item/ItemRequirementSheet.csv index f9e1c88a5c8..0d17abc6c64 100644 --- a/Lib9c/TableCSV/Item/ItemRequirementSheet.csv +++ b/Lib9c/TableCSV/Item/ItemRequirementSheet.csv @@ -196,7 +196,7 @@ item_id,level,mimislevel 40100011,1,1 40100013,1,1 40100014,1,1 -40100015,10,10 +40100015,31,31 40100016,1,1 40100017,1,1 40100019,1,1 @@ -289,4 +289,16 @@ item_id,level,mimislevel 400000,1,1 900104,1,1 900105,1,1 -900106,1,1 \ No newline at end of file +900106,1,1 +10130002,1,1 +49900012,1,1 +10620002,1,1 +10630002,1,1 +10640002,1,1 +10650003,1,1 +10650004,1,1 +10620003,1,1 +10630003,1,1 +10640003,1,1 +10650005,1,1 +10650006,1,1 \ No newline at end of file diff --git a/Lib9c/TableCSV/Item/MaterialItemSheet.csv b/Lib9c/TableCSV/Item/MaterialItemSheet.csv index 767b9339756..ce007dc802b 100644 --- a/Lib9c/TableCSV/Item/MaterialItemSheet.csv +++ b/Lib9c/TableCSV/Item/MaterialItemSheet.csv @@ -39,6 +39,7 @@ id,_name,item_sub_type,grade,elemental_type 800108,Aurora_Powder,FoodMaterial,3,Normal 800109,Fluffy_Marshmallow,FoodMaterial,4,Normal 800201,Silver Dust,FoodMaterial,4,Normal +800202,Golden Meat,FoodMaterial,4,Normal 303000,녹슨 칼,EquipmentMaterial,1,Normal 303001,버려진 검,EquipmentMaterial,2,Normal 303002,단단한 검,EquipmentMaterial,3,Normal @@ -175,12 +176,13 @@ id,_name,item_sub_type,grade,elemental_type 700002,아레나 시즌2 메달,NormalMaterial,5,Normal 700003,아레나 시즌3 메달,NormalMaterial,5,Normal 700004,아레나 시즌4 메달,NormalMaterial,5,Normal -700005,아레나 시즌5 메달,NormalMaterial,5,Normal +700005,시즌 1 메달 (헤임달용),NormalMaterial,5,Normal 700006,아레나 시즌6 메달,NormalMaterial,5,Normal -700007,아레나 시즌7 메달,NormalMaterial,5,Normal +700007,시즌 2 메달 (헤임달용),NormalMaterial,5,Normal 700008,아레나 시즌8 메달,NormalMaterial,5,Normal -700009,아레나 시즌9 메달,NormalMaterial,5,Normal +700009,시즌 3 메달 (헤임달용),NormalMaterial,5,Normal 700010,아레나 시즌10 메달,NormalMaterial,5,Normal +700011,챔피언 쉽 0 메달 (헤임달용),NormalMaterial,5,Normal 700102,시즌 3 메달,NormalMaterial,5,Normal 700104,시즌 4 메달,NormalMaterial,5,Normal 700106,시즌 5 메달,NormalMaterial,5,Normal diff --git a/Lib9c/TableCSV/Quest/QuestItemRewardSheet.csv b/Lib9c/TableCSV/Quest/QuestItemRewardSheet.csv index 1f2fae97879..21e1c409f97 100644 --- a/Lib9c/TableCSV/Quest/QuestItemRewardSheet.csv +++ b/Lib9c/TableCSV/Quest/QuestItemRewardSheet.csv @@ -35,6 +35,9 @@ id,item_id,count 36,400000,40 37,400000,80 38,800201,20 +39,400000,50 +40,400000,200 +41,400000,500 101,303000,3 102,303001,4 103,303002,6 diff --git a/Lib9c/TableCSV/Quest/QuestRewardSheet.csv b/Lib9c/TableCSV/Quest/QuestRewardSheet.csv index f17b8d0d0ec..053bedfb4e2 100644 --- a/Lib9c/TableCSV/Quest/QuestRewardSheet.csv +++ b/Lib9c/TableCSV/Quest/QuestRewardSheet.csv @@ -49,11 +49,15 @@ id,reward_id 35,32 36,33 37,34 +37,39 38,36 39,37 39,21 40,36 40,38 +41,39 +42,40 +43,41 101,101 102,102 103,103 diff --git a/Lib9c/TableCSV/Quest/WorldQuestSheet.csv b/Lib9c/TableCSV/Quest/WorldQuestSheet.csv index ea4d511fcb8..9feb9124982 100644 --- a/Lib9c/TableCSV/Quest/WorldQuestSheet.csv +++ b/Lib9c/TableCSV/Quest/WorldQuestSheet.csv @@ -149,203 +149,203 @@ id,goal,quest_reward_id 100148,148,24 100149,149,25 100150,150,36 -100151,151,24 -100152,152,24 -100153,153,24 -100154,154,24 -100155,155,24 -100156,156,24 -100157,157,24 -100158,158,24 -100159,159,24 -100160,160,24 -100161,161,24 -100162,162,24 -100163,163,24 -100164,164,24 -100165,165,24 -100166,166,24 -100167,167,24 -100168,168,24 -100169,169,24 -100170,170,24 -100171,171,24 -100172,172,24 -100173,173,24 -100174,174,24 -100175,175,24 -100176,176,24 -100177,177,24 -100178,178,24 -100179,179,24 -100180,180,24 -100181,181,24 -100182,182,24 -100183,183,24 -100184,184,24 -100185,185,24 -100186,186,24 -100187,187,24 -100188,188,24 -100189,189,24 -100190,190,24 -100191,191,24 -100192,192,24 -100193,193,24 -100194,194,24 -100195,195,24 -100196,196,24 -100197,197,24 -100198,198,24 -100199,199,24 +100151,151,41 +100152,152,41 +100153,153,41 +100154,154,41 +100155,155,41 +100156,156,41 +100157,157,41 +100158,158,41 +100159,159,41 +100160,160,41 +100161,161,41 +100162,162,41 +100163,163,41 +100164,164,41 +100165,165,41 +100166,166,41 +100167,167,41 +100168,168,41 +100169,169,41 +100170,170,41 +100171,171,41 +100172,172,41 +100173,173,41 +100174,174,41 +100175,175,41 +100176,176,41 +100177,177,41 +100178,178,41 +100179,179,41 +100180,180,41 +100181,181,41 +100182,182,41 +100183,183,41 +100184,184,41 +100185,185,41 +100186,186,41 +100187,187,41 +100188,188,41 +100189,189,41 +100190,190,41 +100191,191,41 +100192,192,41 +100193,193,41 +100194,194,41 +100195,195,41 +100196,196,41 +100197,197,41 +100198,198,41 +100199,199,41 100200,200,37 -100201,201,24 -100202,202,24 -100203,203,24 -100204,204,24 -100205,205,24 -100206,206,24 -100207,207,24 -100208,208,24 -100209,209,24 -100210,210,24 -100211,211,24 -100212,212,24 -100213,213,24 -100214,214,24 -100215,215,24 -100216,216,24 -100217,217,24 -100218,218,24 -100219,219,24 -100220,220,24 -100221,221,24 -100222,222,24 -100223,223,24 -100224,224,24 -100225,225,24 -100226,226,24 -100227,227,24 -100228,228,24 -100229,229,24 -100230,230,24 -100231,231,24 -100232,232,24 -100233,233,24 -100234,234,24 -100235,235,24 -100236,236,24 -100237,237,24 -100238,238,24 -100239,239,24 -100240,240,24 -100241,241,24 -100242,242,24 -100243,243,24 -100244,244,24 -100245,245,24 -100246,246,24 -100247,247,24 -100248,248,24 -100249,249,24 -100250,250,24 -100251,251,24 -100252,252,24 -100253,253,24 -100254,254,24 -100255,255,24 -100256,256,24 -100257,257,24 -100258,258,24 -100259,259,24 -100260,260,24 -100261,261,24 -100262,262,24 -100263,263,24 -100264,264,24 -100265,265,24 -100266,266,24 -100267,267,24 -100268,268,24 -100269,269,24 -100270,270,24 -100271,271,24 -100272,272,24 -100273,273,24 -100274,274,24 -100275,275,24 -100276,276,24 -100277,277,24 -100278,278,24 -100279,279,24 -100280,280,24 -100281,281,24 -100282,282,24 -100283,283,24 -100284,284,24 -100285,285,24 -100286,286,24 -100287,287,24 -100288,288,24 -100289,289,24 -100290,290,24 -100291,291,24 -100292,292,24 -100293,293,24 -100294,294,24 -100295,295,24 -100296,296,24 -100297,297,24 -100298,298,24 -100299,299,24 -100300,300,24 -100301,301,24 -100302,302,24 -100303,303,24 -100304,304,24 -100305,305,24 -100306,306,24 -100307,307,24 -100308,308,24 -100309,309,24 -100310,310,24 -100311,311,24 -100312,312,24 -100313,313,24 -100314,314,24 -100315,315,24 -100316,316,24 -100317,317,24 -100318,318,24 -100319,319,24 -100320,320,24 -100321,321,24 -100322,322,24 -100323,323,24 -100324,324,24 -100325,325,24 -100326,326,24 -100327,327,24 -100328,328,24 -100329,329,24 -100330,330,24 -100331,331,24 -100332,332,24 -100333,333,24 -100334,334,24 -100335,335,24 -100336,336,24 -100337,337,24 -100338,338,24 -100339,339,24 -100340,340,24 -100341,341,24 -100342,342,24 -100343,343,24 -100344,344,24 -100345,345,24 -100346,346,24 -100347,347,24 -100348,348,24 -100349,349,24 -100350,350,24 \ No newline at end of file +100201,201,42 +100202,202,42 +100203,203,42 +100204,204,42 +100205,205,42 +100206,206,42 +100207,207,42 +100208,208,42 +100209,209,42 +100210,210,42 +100211,211,42 +100212,212,42 +100213,213,42 +100214,214,42 +100215,215,42 +100216,216,42 +100217,217,42 +100218,218,42 +100219,219,42 +100220,220,42 +100221,221,42 +100222,222,42 +100223,223,42 +100224,224,42 +100225,225,42 +100226,226,42 +100227,227,42 +100228,228,42 +100229,229,42 +100230,230,42 +100231,231,42 +100232,232,42 +100233,233,42 +100234,234,42 +100235,235,42 +100236,236,42 +100237,237,42 +100238,238,42 +100239,239,42 +100240,240,42 +100241,241,42 +100242,242,42 +100243,243,42 +100244,244,42 +100245,245,42 +100246,246,42 +100247,247,42 +100248,248,42 +100249,249,42 +100250,250,42 +100251,251,43 +100252,252,43 +100253,253,43 +100254,254,43 +100255,255,43 +100256,256,43 +100257,257,43 +100258,258,43 +100259,259,43 +100260,260,43 +100261,261,43 +100262,262,43 +100263,263,43 +100264,264,43 +100265,265,43 +100266,266,43 +100267,267,43 +100268,268,43 +100269,269,43 +100270,270,43 +100271,271,43 +100272,272,43 +100273,273,43 +100274,274,43 +100275,275,43 +100276,276,43 +100277,277,43 +100278,278,43 +100279,279,43 +100280,280,43 +100281,281,43 +100282,282,43 +100283,283,43 +100284,284,43 +100285,285,43 +100286,286,43 +100287,287,43 +100288,288,43 +100289,289,43 +100290,290,43 +100291,291,43 +100292,292,43 +100293,293,43 +100294,294,43 +100295,295,43 +100296,296,43 +100297,297,43 +100298,298,43 +100299,299,43 +100300,300,43 +100301,301,43 +100302,302,43 +100303,303,43 +100304,304,43 +100305,305,43 +100306,306,43 +100307,307,43 +100308,308,43 +100309,309,43 +100310,310,43 +100311,311,43 +100312,312,43 +100313,313,43 +100314,314,43 +100315,315,43 +100316,316,43 +100317,317,43 +100318,318,43 +100319,319,43 +100320,320,43 +100321,321,43 +100322,322,43 +100323,323,43 +100324,324,43 +100325,325,43 +100326,326,43 +100327,327,43 +100328,328,43 +100329,329,43 +100330,330,43 +100331,331,43 +100332,332,43 +100333,333,43 +100334,334,43 +100335,335,43 +100336,336,43 +100337,337,43 +100338,338,43 +100339,339,43 +100340,340,43 +100341,341,43 +100342,342,43 +100343,343,43 +100344,344,43 +100345,345,43 +100346,346,43 +100347,347,43 +100348,348,43 +100349,349,43 +100350,350,43 \ No newline at end of file diff --git a/Lib9c/TableCSV/RedeemRewardSheet.csv b/Lib9c/TableCSV/RedeemRewardSheet.csv index 3e5a416eafd..ccd2c72597f 100644 --- a/Lib9c/TableCSV/RedeemRewardSheet.csv +++ b/Lib9c/TableCSV/RedeemRewardSheet.csv @@ -40,4 +40,6 @@ id,type,qty,item_id 25,Item,1,40100011 26,Item,1,49900010 27,Item,1,40100013 -28,Item,1,40100014 \ No newline at end of file +28,Item,1,40100014 +29,Item,1,40100019 +30,Item,1,49900012 \ No newline at end of file diff --git a/Lib9c/TableCSV/Rune/RuneOptionSheet.csv b/Lib9c/TableCSV/Rune/RuneOptionSheet.csv index 0b9abc84020..27e37bbf164 100644 --- a/Lib9c/TableCSV/Rune/RuneOptionSheet.csv +++ b/Lib9c/TableCSV/Rune/RuneOptionSheet.csv @@ -1,7 +1,7 @@ rune_id,_name,level,total_cp,stat_type_1,value_1,value_type_1,stat_type_2,value_2,value_type_2,stat_type_3,value_3,value_type3,skillId,cooldown,chance,skill_value,skill_stat_ratio,skill_value_type,stat_reference_type,buff_duration -30001,Adventurer's Rune,1,714,HP,1020,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -30001,Adventurer's Rune,2,728,HP,1040,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -30001,Adventurer's Rune,3,742,HP,1060,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +30001,Adventurer's Rune,1,364,HP,520,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +30001,Adventurer's Rune,2,504,HP,720,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +30001,Adventurer's Rune,3,644,HP,920,Add,NONE,0,Add,NONE,0,Add,,,,,,,, 30001,Adventurer's Rune,4,756,HP,1080,Add,NONE,0,Add,NONE,0,Add,,,,,,,, 30001,Adventurer's Rune,5,770,HP,1100,Add,NONE,0,Add,NONE,0,Add,,,,,,,, 30001,Adventurer's Rune,6,784,HP,1120,Add,NONE,0,Add,NONE,0,Add,,,,,,,, @@ -299,906 +299,906 @@ rune_id,_name,level,total_cp,stat_type_1,value_1,value_type_1,stat_type_2,value_ 30001,Adventurer's Rune,298,4872,HP,6960,Add,NONE,0,Add,NONE,0,Add,,,,,,,, 30001,Adventurer's Rune,299,4886,HP,6980,Add,NONE,0,Add,NONE,0,Add,,,,,,,, 30001,Adventurer's Rune,300,4900,HP,7000,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,1,770,HP,1099,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,2,917,HP,1309,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,3,1064,HP,1519,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,4,1211,HP,1729,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,5,1358,HP,1939,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,6,1505,HP,2149,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,7,1652,HP,2359,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,8,1799,HP,2569,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,9,1946,HP,2779,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,10,2093,HP,2989,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,11,2240,HP,3199,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,12,2387,HP,3409,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,13,2534,HP,3619,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,14,2681,HP,3829,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,15,2828,HP,4039,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,16,2975,HP,4249,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,17,3122,HP,4459,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,18,3269,HP,4669,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,19,3416,HP,4879,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,20,3563,HP,5089,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,21,3710,HP,5299,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,22,3857,HP,5509,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,23,4004,HP,5719,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,24,4151,HP,5929,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,25,4298,HP,6139,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,26,4445,HP,6349,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,27,4592,HP,6559,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,28,4739,HP,6769,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,29,4886,HP,6979,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,30,5033,HP,7189,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,31,5180,HP,7399,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,32,5327,HP,7609,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,33,5474,HP,7819,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,34,5621,HP,8029,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,35,5768,HP,8239,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,36,5916,HP,8451,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,37,6065,HP,8663,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,38,6213,HP,8875,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,39,6361,HP,9087,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,40,6510,HP,9299,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,41,6658,HP,9511,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,42,6807,HP,9723,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,43,6955,HP,9935,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,44,7103,HP,10147,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,45,7252,HP,10359,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,46,7400,HP,10571,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,47,7549,HP,10783,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,48,7697,HP,10995,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,49,7845,HP,11207,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,50,7994,HP,11419,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,51,8142,HP,11631,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,52,8291,HP,11843,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,53,8439,HP,12055,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,54,8587,HP,12267,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,55,8736,HP,12479,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,56,8884,HP,12691,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,57,9033,HP,12903,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,58,9181,HP,13115,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,59,9329,HP,13327,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,60,9478,HP,13539,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,61,9626,HP,13751,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,62,9775,HP,13963,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,63,9923,HP,14175,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,64,10071,HP,14387,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,65,10220,HP,14599,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,66,10368,HP,14811,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,67,10517,HP,15023,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,68,10665,HP,15235,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,69,10813,HP,15447,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,70,10962,HP,15659,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,71,11110,HP,15871,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,72,11259,HP,16083,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,73,11407,HP,16295,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,74,11555,HP,16507,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,75,11704,HP,16719,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,76,11852,HP,16931,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,77,12001,HP,17143,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,78,12149,HP,17355,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,79,12297,HP,17567,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,80,12446,HP,17779,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,81,12646,HP,18065,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,82,12846,HP,18351,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,83,13046,HP,18637,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,84,13247,HP,18923,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,85,13447,HP,19209,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,86,13647,HP,19495,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,87,13847,HP,19781,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,88,14047,HP,20067,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,89,14248,HP,20353,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,90,14448,HP,20639,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,91,14648,HP,20925,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,92,14848,HP,21211,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,93,15048,HP,21497,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,94,15249,HP,21783,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,95,15449,HP,22069,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,96,15649,HP,22355,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,97,15849,HP,22641,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,98,16049,HP,22927,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,99,16250,HP,23213,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,100,16450,HP,23499,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,101,16650,HP,23785,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,102,16850,HP,24071,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,103,17050,HP,24357,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,104,17251,HP,24643,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,105,17451,HP,24929,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,106,17651,HP,25215,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,107,17851,HP,25501,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,108,18051,HP,25787,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,109,18252,HP,26073,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,110,18452,HP,26359,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,111,18652,HP,26645,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,112,18852,HP,26931,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,113,19052,HP,27217,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,114,19253,HP,27503,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,115,19453,HP,27789,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,116,19653,HP,28075,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,117,19853,HP,28361,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,118,20053,HP,28647,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,119,20254,HP,28933,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,120,20454,HP,29219,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,121,20654,HP,29505,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,122,20854,HP,29791,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,123,21054,HP,30077,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,124,21255,HP,30363,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,125,21455,HP,30649,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,126,21655,HP,30935,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,127,21855,HP,31221,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,128,22055,HP,31507,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,129,22256,HP,31793,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,130,22456,HP,32079,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,131,22656,HP,32365,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,132,22856,HP,32651,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,133,23056,HP,32937,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,134,23257,HP,33223,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,135,23457,HP,33509,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,136,23802,HP,34002,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,137,24147,HP,34495,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,138,24492,HP,34988,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,139,24837,HP,35481,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,140,25182,HP,35974,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,141,25527,HP,36467,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,142,25872,HP,36960,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,143,26218,HP,37453,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,144,26563,HP,37946,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,145,26908,HP,38439,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,146,27253,HP,38932,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,147,27598,HP,39425,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,148,27943,HP,39918,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,149,28288,HP,40411,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,150,28633,HP,40904,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,151,28978,HP,41397,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,152,29323,HP,41890,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,153,29669,HP,42383,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,154,30014,HP,42876,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,155,30359,HP,43369,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,156,30704,HP,43862,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,157,31049,HP,44355,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,158,31394,HP,44848,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,159,31739,HP,45341,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,160,32084,HP,45834,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,161,32429,HP,46327,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,162,32774,HP,46820,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,163,33120,HP,47313,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,164,33465,HP,47806,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,165,33810,HP,48299,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,166,34155,HP,48792,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,167,34500,HP,49285,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,168,34845,HP,49778,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,169,35190,HP,50271,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,170,35535,HP,50764,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,171,35880,HP,51257,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,172,36225,HP,51750,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,173,36571,HP,52243,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,174,36916,HP,52736,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,175,37261,HP,53229,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,176,37606,HP,53722,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,177,37951,HP,54215,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,178,38296,HP,54708,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,179,38641,HP,55201,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,180,38986,HP,55694,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,181,39331,HP,56187,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,182,39676,HP,56680,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,183,40022,HP,57173,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,184,40367,HP,57666,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,185,40712,HP,58159,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,186,41057,HP,58652,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,187,41402,HP,59145,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,188,41747,HP,59638,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,189,42092,HP,60131,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,190,42437,HP,60624,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,191,42782,HP,61117,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,192,43127,HP,61610,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,193,43473,HP,62103,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,194,43818,HP,62596,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,195,44163,HP,63089,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,196,44508,HP,63582,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,197,44853,HP,64075,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,198,45198,HP,64568,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,199,45543,HP,65061,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,200,45888,HP,65554,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,201,46233,HP,66047,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,202,46578,HP,66540,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,203,46924,HP,67033,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,204,47269,HP,67526,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,205,47614,HP,68019,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,206,47959,HP,68512,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,207,48304,HP,69005,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,208,48649,HP,69498,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,209,48994,HP,69991,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,210,49339,HP,70484,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,211,49738,HP,71053,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,212,50136,HP,71622,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,213,50534,HP,72191,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,214,50932,HP,72760,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,215,51331,HP,73329,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,216,51729,HP,73898,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,217,52127,HP,74467,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,218,52526,HP,75036,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,219,52924,HP,75605,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,220,53322,HP,76174,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,221,53721,HP,76743,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,222,54119,HP,77312,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,223,54517,HP,77881,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,224,54915,HP,78450,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,225,55314,HP,79019,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,226,55712,HP,79588,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,227,56110,HP,80157,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,228,56509,HP,80726,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,229,56907,HP,81295,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,230,57305,HP,81864,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,231,57704,HP,82433,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,232,58102,HP,83002,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,233,58500,HP,83571,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,234,58898,HP,84140,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,235,59297,HP,84709,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,236,59695,HP,85278,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,237,60093,HP,85847,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,238,60492,HP,86416,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,239,60890,HP,86985,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,240,61288,HP,87554,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,241,61687,HP,88123,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,242,62085,HP,88692,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,243,62483,HP,89261,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,244,62881,HP,89830,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,245,63280,HP,90399,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,246,63678,HP,90968,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,247,64076,HP,91537,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,248,64475,HP,92106,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,249,64873,HP,92675,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,250,65271,HP,93244,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,251,65670,HP,93813,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,252,66068,HP,94382,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,253,66466,HP,94951,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,254,66864,HP,95520,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,255,67263,HP,96089,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,256,67661,HP,96658,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,257,68059,HP,97227,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,258,68458,HP,97796,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,259,68856,HP,98365,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,260,69254,HP,98934,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,261,69653,HP,99503,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,262,70051,HP,100072,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,263,70449,HP,100641,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,264,70847,HP,101210,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,265,71246,HP,101779,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,266,71644,HP,102348,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,267,72042,HP,102917,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,268,72441,HP,103486,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,269,72839,HP,104055,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,270,73237,HP,104624,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,271,73636,HP,105193,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,272,74034,HP,105762,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,273,74432,HP,106331,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,274,74830,HP,106900,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,275,75229,HP,107469,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,276,75627,HP,108038,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,277,76025,HP,108607,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,278,76424,HP,109176,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,279,76822,HP,109745,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,280,77220,HP,110314,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,281,77619,HP,110883,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,282,78017,HP,111452,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,283,78415,HP,112021,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,284,78813,HP,112590,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,285,79212,HP,113159,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,286,79610,HP,113728,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,287,80008,HP,114297,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,288,80407,HP,114866,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,289,80805,HP,115435,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,290,81203,HP,116004,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,291,81602,HP,116573,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,292,82000,HP,117142,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,293,82398,HP,117711,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,294,82796,HP,118280,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,295,83195,HP,118849,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,296,83593,HP,119418,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,297,83991,HP,119987,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,298,84390,HP,120556,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,299,84788,HP,121125,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10001,Fenrir HP Rune,300,85186,HP,121694,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,1,704,ATK,67,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,2,830,ATK,79,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,3,956,ATK,91,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,4,1082,ATK,103,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,5,1208,ATK,115,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,6,1334,ATK,127,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,7,1460,ATK,139,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,8,1586,ATK,151,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,9,1712,ATK,163,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,10,1838,ATK,175,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,11,1964,ATK,187,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,12,2090,ATK,199,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,13,2216,ATK,211,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,14,2342,ATK,223,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,15,2468,ATK,235,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,16,2594,ATK,247,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,17,2720,ATK,259,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,18,2846,ATK,271,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,19,2972,ATK,283,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,20,3098,ATK,295,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,21,3224,ATK,307,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,22,3350,ATK,319,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,23,3476,ATK,331,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,24,3602,ATK,343,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,25,3728,ATK,355,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,26,3854,ATK,367,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,27,3980,ATK,379,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,28,4106,ATK,391,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,29,4232,ATK,403,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,30,4358,ATK,415,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,31,4484,ATK,427,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,32,4610,ATK,439,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,33,4736,ATK,451,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,34,4862,ATK,463,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,35,4988,ATK,475,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,36,5124,ATK,488,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,37,5261,ATK,501,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,38,5397,ATK,514,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,39,5534,ATK,527,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,40,5670,ATK,540,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,41,5807,ATK,553,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,42,5943,ATK,566,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,43,6080,ATK,579,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,44,6216,ATK,592,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,45,6353,ATK,605,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,46,6489,ATK,618,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,47,6626,ATK,631,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,48,6762,ATK,644,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,49,6899,ATK,657,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,50,7035,ATK,670,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,51,7172,ATK,683,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,52,7308,ATK,696,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,53,7445,ATK,709,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,54,7581,ATK,722,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,55,7718,ATK,735,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,56,7854,ATK,748,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,57,7991,ATK,761,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,58,8127,ATK,774,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,59,8264,ATK,787,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,60,8400,ATK,800,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,61,8537,ATK,813,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,62,8673,ATK,826,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,63,8810,ATK,839,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,64,8946,ATK,852,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,65,9083,ATK,865,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,66,9219,ATK,878,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,67,9356,ATK,891,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,68,9492,ATK,904,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,69,9629,ATK,917,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,70,9765,ATK,930,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,71,9902,ATK,943,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,72,10038,ATK,956,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,73,10175,ATK,969,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,74,10311,ATK,982,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,75,10448,ATK,995,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,76,10584,ATK,1008,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,77,10721,ATK,1021,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,78,10857,ATK,1034,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,79,10994,ATK,1047,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,80,11130,ATK,1060,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,81,11298,ATK,1076,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,82,11466,ATK,1092,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,83,11634,ATK,1108,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,84,11802,ATK,1124,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,85,11970,ATK,1140,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,86,12138,ATK,1156,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,87,12306,ATK,1172,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,88,12474,ATK,1188,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,89,12642,ATK,1204,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,90,12810,ATK,1220,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,91,12978,ATK,1236,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,92,13146,ATK,1252,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,93,13314,ATK,1268,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,94,13482,ATK,1284,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,95,13650,ATK,1300,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,96,13818,ATK,1316,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,97,13986,ATK,1332,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,98,14154,ATK,1348,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,99,14322,ATK,1364,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,100,14490,ATK,1380,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,101,14658,ATK,1396,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,102,14826,ATK,1412,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,103,14994,ATK,1428,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,104,15162,ATK,1444,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,105,15330,ATK,1460,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,106,15498,ATK,1476,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,107,15666,ATK,1492,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,108,15834,ATK,1508,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,109,16002,ATK,1524,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,110,16170,ATK,1540,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,111,16338,ATK,1556,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,112,16506,ATK,1572,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,113,16674,ATK,1588,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,114,16842,ATK,1604,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,115,17010,ATK,1620,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,116,17178,ATK,1636,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,117,17346,ATK,1652,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,118,17514,ATK,1668,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,119,17682,ATK,1684,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,120,17850,ATK,1700,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,121,18018,ATK,1716,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,122,18186,ATK,1732,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,123,18354,ATK,1748,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,124,18522,ATK,1764,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,125,18690,ATK,1780,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,126,18858,ATK,1796,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,127,19026,ATK,1812,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,128,19194,ATK,1828,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,129,19362,ATK,1844,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,130,19530,ATK,1860,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,131,19698,ATK,1876,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,132,19866,ATK,1892,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,133,20034,ATK,1908,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,134,20202,ATK,1924,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,135,20370,ATK,1940,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,136,20696,ATK,1971,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,137,21021,ATK,2002,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,138,21347,ATK,2033,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,139,21672,ATK,2064,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,140,21998,ATK,2095,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,141,22323,ATK,2126,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,142,22649,ATK,2157,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,143,22974,ATK,2188,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,144,23300,ATK,2219,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,145,23625,ATK,2250,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,146,23951,ATK,2281,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,147,24276,ATK,2312,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,148,24602,ATK,2343,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,149,24927,ATK,2374,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,150,25253,ATK,2405,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,151,25578,ATK,2436,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,152,25904,ATK,2467,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,153,26229,ATK,2498,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,154,26555,ATK,2529,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,155,26880,ATK,2560,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,156,27206,ATK,2591,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,157,27531,ATK,2622,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,158,27857,ATK,2653,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,159,28182,ATK,2684,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,160,28508,ATK,2715,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,161,28833,ATK,2746,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,162,29159,ATK,2777,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,163,29484,ATK,2808,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,164,29810,ATK,2839,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,165,30135,ATK,2870,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,166,30461,ATK,2901,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,167,30786,ATK,2932,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,168,31112,ATK,2963,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,169,31437,ATK,2994,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,170,31763,ATK,3025,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,171,32088,ATK,3056,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,172,32414,ATK,3087,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,173,32739,ATK,3118,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,174,33065,ATK,3149,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,175,33390,ATK,3180,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,176,33716,ATK,3211,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,177,34041,ATK,3242,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,178,34367,ATK,3273,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,179,34692,ATK,3304,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,180,35018,ATK,3335,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,181,35343,ATK,3366,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,182,35669,ATK,3397,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,183,35994,ATK,3428,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,184,36320,ATK,3459,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,185,36645,ATK,3490,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,186,36971,ATK,3521,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,187,37296,ATK,3552,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,188,37622,ATK,3583,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,189,37947,ATK,3614,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,190,38273,ATK,3645,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,191,38598,ATK,3676,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,192,38924,ATK,3707,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,193,39249,ATK,3738,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,194,39575,ATK,3769,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,195,39900,ATK,3800,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,196,40226,ATK,3831,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,197,40551,ATK,3862,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,198,40877,ATK,3893,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,199,41202,ATK,3924,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,200,41528,ATK,3955,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,201,41853,ATK,3986,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,202,42179,ATK,4017,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,203,42504,ATK,4048,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,204,42830,ATK,4079,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,205,43155,ATK,4110,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,206,43481,ATK,4141,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,207,43806,ATK,4172,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,208,44132,ATK,4203,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,209,44457,ATK,4234,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,210,44783,ATK,4265,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,211,45213,ATK,4306,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,212,45644,ATK,4347,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,213,46074,ATK,4388,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,214,46505,ATK,4429,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,215,46935,ATK,4470,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,216,47366,ATK,4511,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,217,47796,ATK,4552,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,218,48227,ATK,4593,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,219,48657,ATK,4634,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,220,49088,ATK,4675,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,221,49518,ATK,4716,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,222,49949,ATK,4757,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,223,50379,ATK,4798,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,224,50810,ATK,4839,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,225,51240,ATK,4880,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,226,51671,ATK,4921,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,227,52101,ATK,4962,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,228,52532,ATK,5003,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,229,52962,ATK,5044,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,230,53393,ATK,5085,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,231,53823,ATK,5126,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,232,54254,ATK,5167,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,233,54684,ATK,5208,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,234,55115,ATK,5249,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,235,55545,ATK,5290,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,236,55976,ATK,5331,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,237,56406,ATK,5372,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,238,56837,ATK,5413,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,239,57267,ATK,5454,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,240,57698,ATK,5495,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,241,58128,ATK,5536,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,242,58559,ATK,5577,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,243,58989,ATK,5618,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,244,59420,ATK,5659,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,245,59850,ATK,5700,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,246,60281,ATK,5741,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,247,60711,ATK,5782,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,248,61142,ATK,5823,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,249,61572,ATK,5864,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,250,62003,ATK,5905,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,251,62433,ATK,5946,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,252,62864,ATK,5987,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,253,63294,ATK,6028,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,254,63725,ATK,6069,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,255,64155,ATK,6110,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,256,64586,ATK,6151,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,257,65016,ATK,6192,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,258,65447,ATK,6233,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,259,65877,ATK,6274,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,260,66308,ATK,6315,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,261,66738,ATK,6356,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,262,67169,ATK,6397,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,263,67599,ATK,6438,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,264,68030,ATK,6479,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,265,68460,ATK,6520,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,266,68891,ATK,6561,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,267,69321,ATK,6602,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,268,69752,ATK,6643,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,269,70182,ATK,6684,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,270,70613,ATK,6725,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,271,71043,ATK,6766,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,272,71474,ATK,6807,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,273,71904,ATK,6848,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,274,72335,ATK,6889,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,275,72765,ATK,6930,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,276,73196,ATK,6971,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,277,73626,ATK,7012,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,278,74057,ATK,7053,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,279,74487,ATK,7094,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,280,74918,ATK,7135,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,281,75348,ATK,7176,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,282,75779,ATK,7217,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,283,76209,ATK,7258,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,284,76640,ATK,7299,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,285,77070,ATK,7340,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,286,77501,ATK,7381,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,287,77931,ATK,7422,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,288,78362,ATK,7463,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,289,78792,ATK,7504,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,290,79223,ATK,7545,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,291,79653,ATK,7586,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,292,80084,ATK,7627,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,293,80514,ATK,7668,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,294,80945,ATK,7709,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,295,81375,ATK,7750,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,296,81806,ATK,7791,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,297,82236,ATK,7832,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,298,82667,ATK,7873,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,299,83097,ATK,7914,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10002,Fenrir ATK Rune,300,83528,ATK,7955,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10003,Fenrir Bleeding Rune,1,1111,ATK,92,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,2,1232,ATK,102,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,3,1353,ATK,112,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,4,1474,ATK,122,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,5,1594,ATK,132,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,6,1715,ATK,142,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,7,1836,ATK,152,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,8,1957,ATK,162,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,9,2077,ATK,172,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,10,2198,ATK,182,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,11,2319,ATK,192,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,12,2440,ATK,202,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,13,2560,ATK,212,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,14,2681,ATK,222,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,15,2802,ATK,232,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,16,2923,ATK,242,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,17,3043,ATK,252,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,18,3164,ATK,262,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,19,3285,ATK,272,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,20,3406,ATK,282,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,21,3526,ATK,292,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,22,3647,ATK,302,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,23,3768,ATK,312,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,24,3889,ATK,322,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,25,4009,ATK,332,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,26,4130,ATK,342,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,27,4251,ATK,352,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,28,4372,ATK,362,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,29,4492,ATK,372,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,30,4613,ATK,382,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,31,4734,ATK,392,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,32,4855,ATK,402,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,33,4975,ATK,412,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,34,5096,ATK,422,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,35,5217,ATK,432,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,36,5350,ATK,443,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,37,5483,ATK,454,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,38,5615,ATK,465,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,39,5748,ATK,476,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,40,5881,ATK,487,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,41,6014,ATK,498,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,42,6147,ATK,509,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,43,6279,ATK,520,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,44,6412,ATK,531,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,45,6545,ATK,542,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,46,6678,ATK,553,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,47,6811,ATK,564,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,48,6944,ATK,575,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,49,7076,ATK,586,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,50,7209,ATK,597,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,51,7342,ATK,608,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,52,7475,ATK,619,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,53,7608,ATK,630,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,54,7741,ATK,641,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,55,7873,ATK,652,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,56,8006,ATK,663,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,57,8139,ATK,674,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,58,8272,ATK,685,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,59,8405,ATK,696,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,60,8538,ATK,707,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,61,8670,ATK,718,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,62,8803,ATK,729,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,63,8936,ATK,740,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,64,9069,ATK,751,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,65,9202,ATK,762,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,66,9334,ATK,773,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,67,9467,ATK,784,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,68,9600,ATK,795,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,69,9733,ATK,806,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,70,9866,ATK,817,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,71,9999,ATK,828,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,72,10131,ATK,839,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,73,10264,ATK,850,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,74,10397,ATK,861,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,75,10530,ATK,872,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,76,10663,ATK,883,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,77,10796,ATK,894,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,78,10928,ATK,905,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,79,11061,ATK,916,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,80,11194,ATK,927,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,81,11363,ATK,941,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,82,11532,ATK,955,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,83,11701,ATK,969,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,84,11870,ATK,983,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,85,12039,ATK,997,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,86,12208,ATK,1011,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,87,12377,ATK,1025,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,88,12546,ATK,1039,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,89,12715,ATK,1053,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,90,12885,ATK,1067,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,91,13054,ATK,1081,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,92,13223,ATK,1095,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,93,13392,ATK,1109,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,94,13561,ATK,1123,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,95,13730,ATK,1137,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,96,13899,ATK,1151,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,97,14068,ATK,1165,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,98,14237,ATK,1179,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,99,14406,ATK,1193,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,100,14575,ATK,1207,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,101,14744,ATK,1221,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,102,14913,ATK,1235,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,103,15082,ATK,1249,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,104,15251,ATK,1263,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,105,15420,ATK,1277,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,106,15589,ATK,1291,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,107,15758,ATK,1305,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,108,15927,ATK,1319,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,109,16096,ATK,1333,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,110,16266,ATK,1347,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,111,16435,ATK,1361,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,112,16604,ATK,1375,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,113,16773,ATK,1389,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,114,16942,ATK,1403,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,115,17111,ATK,1417,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,116,17280,ATK,1431,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,117,17449,ATK,1445,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,118,17618,ATK,1459,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,119,17787,ATK,1473,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,120,17956,ATK,1487,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,121,18125,ATK,1501,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,122,18294,ATK,1515,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,123,18463,ATK,1529,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,124,18632,ATK,1543,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,125,18801,ATK,1557,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,126,18970,ATK,1571,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,127,19139,ATK,1585,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,128,19308,ATK,1599,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,129,19477,ATK,1613,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,130,19647,ATK,1627,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,131,19816,ATK,1641,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,132,19985,ATK,1655,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,133,20154,ATK,1669,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,134,20323,ATK,1683,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,135,20492,ATK,1697,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,136,20806,ATK,1723,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,137,21120,ATK,1749,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,138,21434,ATK,1775,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,139,21748,ATK,1801,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,140,22062,ATK,1827,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,141,22375,ATK,1853,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,142,22689,ATK,1879,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,143,23003,ATK,1905,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,144,23317,ATK,1931,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,145,23631,ATK,1957,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,146,23945,ATK,1983,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,147,24259,ATK,2009,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,148,24573,ATK,2035,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,149,24887,ATK,2061,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,150,25201,ATK,2087,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,151,25515,ATK,2113,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,152,25829,ATK,2139,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,153,26143,ATK,2165,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,154,26457,ATK,2191,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,155,26771,ATK,2217,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,156,27085,ATK,2243,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,157,27399,ATK,2269,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,158,27713,ATK,2295,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,159,28027,ATK,2321,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,160,28341,ATK,2347,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,161,28654,ATK,2373,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,162,28968,ATK,2399,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,163,29282,ATK,2425,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,164,29596,ATK,2451,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,165,29910,ATK,2477,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,166,30224,ATK,2503,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,167,30538,ATK,2529,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,168,30852,ATK,2555,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,169,31166,ATK,2581,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,170,31480,ATK,2607,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,171,31794,ATK,2633,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,172,32108,ATK,2659,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,173,32422,ATK,2685,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,174,32736,ATK,2711,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,175,33050,ATK,2737,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,176,33364,ATK,2763,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,177,33678,ATK,2789,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,178,33992,ATK,2815,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,179,34306,ATK,2841,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,180,34620,ATK,2867,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,181,34933,ATK,2893,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,182,35247,ATK,2919,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,183,35561,ATK,2945,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,184,35875,ATK,2971,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,185,36189,ATK,2997,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,186,36503,ATK,3023,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,187,36817,ATK,3049,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,188,37131,ATK,3075,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,189,37445,ATK,3101,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,190,37759,ATK,3127,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,191,38073,ATK,3153,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,192,38387,ATK,3179,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,193,38701,ATK,3205,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,194,39015,ATK,3231,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,195,39329,ATK,3257,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,196,39643,ATK,3283,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,197,39957,ATK,3309,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,198,40271,ATK,3335,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,199,40585,ATK,3361,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,200,40899,ATK,3387,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,201,41212,ATK,3413,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,202,41526,ATK,3439,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,203,41840,ATK,3465,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,204,42154,ATK,3491,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,205,42468,ATK,3517,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,206,42782,ATK,3543,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,207,43096,ATK,3569,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,208,43410,ATK,3595,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,209,43724,ATK,3621,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,210,44038,ATK,3647,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,211,44449,ATK,3681,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,212,44859,ATK,3715,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,213,45270,ATK,3749,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,214,45680,ATK,3783,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,215,46091,ATK,3817,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,216,46501,ATK,3851,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,217,46912,ATK,3885,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,218,47322,ATK,3919,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,219,47733,ATK,3953,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,220,48144,ATK,3987,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,221,48554,ATK,4021,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,222,48965,ATK,4055,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,223,49375,ATK,4089,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,224,49786,ATK,4123,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,225,50196,ATK,4157,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,226,50607,ATK,4191,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,227,51017,ATK,4225,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,228,51428,ATK,4259,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,229,51838,ATK,4293,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,230,52249,ATK,4327,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,231,52660,ATK,4361,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,232,53070,ATK,4395,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,233,53481,ATK,4429,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,234,53891,ATK,4463,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,235,54302,ATK,4497,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,236,54712,ATK,4531,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,237,55123,ATK,4565,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,238,55533,ATK,4599,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,239,55944,ATK,4633,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,240,56355,ATK,4667,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,241,56765,ATK,4701,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,242,57176,ATK,4735,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,243,57586,ATK,4769,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,244,57997,ATK,4803,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,245,58407,ATK,4837,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,246,58818,ATK,4871,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,247,59228,ATK,4905,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,248,59639,ATK,4939,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,249,60049,ATK,4973,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,250,60460,ATK,5007,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,251,60871,ATK,5041,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,252,61281,ATK,5075,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,253,61692,ATK,5109,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,254,62102,ATK,5143,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,255,62513,ATK,5177,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,256,62923,ATK,5211,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,257,63334,ATK,5245,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,258,63744,ATK,5279,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,259,64155,ATK,5313,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,260,64566,ATK,5347,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,261,64976,ATK,5381,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,262,65387,ATK,5415,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,263,65797,ATK,5449,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,264,66208,ATK,5483,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,265,66618,ATK,5517,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,266,67029,ATK,5551,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,267,67439,ATK,5585,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,268,67850,ATK,5619,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,269,68260,ATK,5653,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,270,68671,ATK,5687,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,271,69082,ATK,5721,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,272,69492,ATK,5755,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,273,69903,ATK,5789,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,274,70313,ATK,5823,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,275,70724,ATK,5857,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,276,71134,ATK,5891,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,277,71545,ATK,5925,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,278,71955,ATK,5959,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,279,72366,ATK,5993,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,280,72777,ATK,6027,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,281,73187,ATK,6061,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,282,73598,ATK,6095,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,283,74008,ATK,6129,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,284,74419,ATK,6163,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,285,74829,ATK,6197,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,286,75240,ATK,6231,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,287,75650,ATK,6265,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,288,76061,ATK,6299,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,289,76471,ATK,6333,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,290,76882,ATK,6367,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,291,77293,ATK,6401,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,292,77703,ATK,6435,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,293,78114,ATK,6469,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,294,78524,ATK,6503,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,295,78935,ATK,6537,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,296,79345,ATK,6571,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,297,79756,ATK,6605,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,298,80166,ATK,6639,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,299,80577,ATK,6673,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 -10003,Fenrir Bleeding Rune,300,80988,ATK,6707,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.49,Percentage,ATK,Caster,10 +10001,Fenrir HP Rune,1,864,HP,1234,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,2,1043,HP,1489,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,3,1221,HP,1744,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,4,1400,HP,1999,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,5,1578,HP,2254,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,6,1757,HP,2509,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,7,1935,HP,2764,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,8,2114,HP,3019,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,9,2292,HP,3274,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,10,2471,HP,3529,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,11,2649,HP,3784,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,12,2828,HP,4039,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,13,3006,HP,4294,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,14,3185,HP,4549,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,15,3363,HP,4804,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,16,3542,HP,5059,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,17,3720,HP,5314,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,18,3899,HP,5569,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,19,4077,HP,5824,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,20,4256,HP,6079,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,21,4434,HP,6334,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,22,4613,HP,6589,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,23,4791,HP,6844,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,24,4970,HP,7099,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,25,5148,HP,7354,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,26,5327,HP,7609,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,27,5505,HP,7864,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,28,5684,HP,8119,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,29,5862,HP,8374,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,30,6041,HP,8629,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,31,6219,HP,8884,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,32,6398,HP,9139,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,33,6576,HP,9394,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,34,6755,HP,9649,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,35,6933,HP,9904,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,36,7112,HP,10159,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,37,7290,HP,10414,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,38,7469,HP,10669,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,39,7647,HP,10924,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,40,7826,HP,11179,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,41,8004,HP,11434,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,42,8183,HP,11689,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,43,8361,HP,11944,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,44,8540,HP,12199,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,45,8718,HP,12454,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,46,8897,HP,12709,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,47,9075,HP,12964,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,48,9254,HP,13219,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,49,9432,HP,13474,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,50,9611,HP,13729,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,51,9799,HP,13998,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,52,9987,HP,14267,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,53,10176,HP,14536,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,54,10364,HP,14805,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,55,10552,HP,15074,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,56,10741,HP,15343,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,57,10929,HP,15612,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,58,11117,HP,15881,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,59,11305,HP,16150,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,60,11494,HP,16419,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,61,11682,HP,16688,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,62,11870,HP,16957,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,63,12059,HP,17226,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,64,12247,HP,17495,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,65,12435,HP,17764,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,66,12624,HP,18033,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,67,12812,HP,18302,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,68,13000,HP,18571,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,69,13188,HP,18840,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,70,13377,HP,19109,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,71,13565,HP,19378,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,72,13753,HP,19647,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,73,13942,HP,19916,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,74,14130,HP,20185,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,75,14318,HP,20454,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,76,14507,HP,20723,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,77,14695,HP,20992,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,78,14883,HP,21261,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,79,15071,HP,21530,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,80,15260,HP,21799,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,81,15448,HP,22068,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,82,15636,HP,22337,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,83,15825,HP,22606,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,84,16013,HP,22875,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,85,16201,HP,23144,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,86,16390,HP,23413,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,87,16578,HP,23682,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,88,16766,HP,23951,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,89,16954,HP,24220,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,90,17143,HP,24489,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,91,17331,HP,24758,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,92,17519,HP,25027,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,93,17708,HP,25296,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,94,17896,HP,25565,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,95,18084,HP,25834,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,96,18273,HP,26103,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,97,18461,HP,26372,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,98,18649,HP,26641,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,99,18837,HP,26910,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,100,19026,HP,27179,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,101,19264,HP,27520,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,102,19503,HP,27861,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,103,19742,HP,28202,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,104,19981,HP,28543,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,105,20219,HP,28884,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,106,20458,HP,29225,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,107,20697,HP,29566,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,108,20935,HP,29907,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,109,21174,HP,30248,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,110,21413,HP,30589,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,111,21651,HP,30930,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,112,21890,HP,31271,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,113,22129,HP,31612,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,114,22368,HP,31953,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,115,22606,HP,32294,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,116,22845,HP,32635,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,117,23084,HP,32976,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,118,23322,HP,33317,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,119,23561,HP,33658,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,120,23800,HP,33999,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,121,24038,HP,34340,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,122,24277,HP,34681,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,123,24516,HP,35022,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,124,24755,HP,35363,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,125,24993,HP,35704,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,126,25232,HP,36045,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,127,25471,HP,36386,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,128,25709,HP,36727,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,129,25948,HP,37068,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,130,26187,HP,37409,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,131,26425,HP,37750,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,132,26664,HP,38091,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,133,26903,HP,38432,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,134,27142,HP,38773,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,135,27380,HP,39114,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,136,27619,HP,39455,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,137,27858,HP,39796,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,138,28096,HP,40137,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,139,28335,HP,40478,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,140,28574,HP,40819,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,141,28812,HP,41160,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,142,29051,HP,41501,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,143,29290,HP,41842,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,144,29529,HP,42183,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,145,29767,HP,42524,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,146,30006,HP,42865,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,147,30245,HP,43206,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,148,30483,HP,43547,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,149,30722,HP,43888,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,150,30961,HP,44229,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,151,32233,HP,46046,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,152,33505,HP,47863,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,153,34776,HP,49680,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,154,36048,HP,51497,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,155,37320,HP,53314,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,156,38592,HP,55131,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,157,39864,HP,56948,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,158,41136,HP,58765,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,159,42408,HP,60582,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,160,43680,HP,62399,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,161,44952,HP,64216,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,162,46224,HP,66033,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,163,47495,HP,67850,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,164,48767,HP,69667,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,165,50039,HP,71484,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,166,51311,HP,73301,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,167,52583,HP,75118,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,168,53855,HP,76935,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,169,55127,HP,78752,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,170,56399,HP,80569,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,171,57671,HP,82386,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,172,58943,HP,84203,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,173,60214,HP,86020,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,174,61486,HP,87837,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,175,62758,HP,89654,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,176,64030,HP,91471,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,177,65302,HP,93288,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,178,66574,HP,95105,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,179,67846,HP,96922,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,180,69118,HP,98739,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,181,70390,HP,100556,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,182,71662,HP,102373,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,183,72933,HP,104190,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,184,74205,HP,106007,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,185,75477,HP,107824,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,186,76749,HP,109641,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,187,78021,HP,111458,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,188,79293,HP,113275,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,189,80565,HP,115092,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,190,81837,HP,116909,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,191,83109,HP,118726,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,192,84381,HP,120543,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,193,85652,HP,122360,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,194,86924,HP,124177,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,195,88196,HP,125994,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,196,89468,HP,127811,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,197,90740,HP,129628,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,198,92012,HP,131445,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,199,93284,HP,133262,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,200,94556,HP,135079,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,201,96465,HP,137806,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,202,98374,HP,140533,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,203,100282,HP,143260,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,204,102191,HP,145987,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,205,104100,HP,148714,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,206,106009,HP,151441,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,207,107918,HP,154168,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,208,109827,HP,156895,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,209,111736,HP,159622,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,210,113645,HP,162349,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,211,115554,HP,165076,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,212,117463,HP,167803,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,213,119371,HP,170530,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,214,121280,HP,173257,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,215,123189,HP,175984,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,216,125098,HP,178711,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,217,127007,HP,181438,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,218,128916,HP,184165,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,219,130825,HP,186892,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,220,132734,HP,189619,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,221,134643,HP,192346,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,222,136552,HP,195073,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,223,138460,HP,197800,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,224,140369,HP,200527,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,225,142278,HP,203254,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,226,144187,HP,205981,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,227,146096,HP,208708,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,228,148005,HP,211435,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,229,149914,HP,214162,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,230,151823,HP,216889,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,231,153732,HP,219616,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,232,155641,HP,222343,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,233,157549,HP,225070,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,234,159458,HP,227797,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,235,161367,HP,230524,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,236,163276,HP,233251,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,237,165185,HP,235978,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,238,167094,HP,238705,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,239,169003,HP,241432,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,240,170912,HP,244159,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,241,172821,HP,246886,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,242,174730,HP,249613,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,243,176638,HP,252340,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,244,178547,HP,255067,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,245,180456,HP,257794,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,246,182365,HP,260521,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,247,184274,HP,263248,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,248,186183,HP,265975,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,249,188092,HP,268702,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,250,190001,HP,271429,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,251,192062,HP,274374,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,252,194124,HP,277319,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,253,196185,HP,280264,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,254,198247,HP,283209,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,255,200308,HP,286154,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,256,202370,HP,289099,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,257,204431,HP,292044,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,258,206493,HP,294989,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,259,208554,HP,297934,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,260,210616,HP,300879,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,261,212677,HP,303824,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,262,214739,HP,306769,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,263,216800,HP,309714,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,264,218862,HP,312659,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,265,220923,HP,315604,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,266,222985,HP,318549,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,267,225046,HP,321494,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,268,227108,HP,324439,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,269,229169,HP,327384,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,270,231231,HP,330329,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,271,233292,HP,333274,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,272,235354,HP,336219,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,273,237415,HP,339164,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,274,239477,HP,342109,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,275,241538,HP,345054,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,276,243600,HP,347999,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,277,245661,HP,350944,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,278,247723,HP,353889,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,279,249784,HP,356834,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,280,251846,HP,359779,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,281,253907,HP,362724,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,282,255969,HP,365669,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,283,258030,HP,368614,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,284,260092,HP,371559,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,285,262153,HP,374504,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,286,264215,HP,377449,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,287,266276,HP,380394,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,288,268338,HP,383339,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,289,270399,HP,386284,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,290,272461,HP,389229,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,291,274522,HP,392174,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,292,276584,HP,395119,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,293,278645,HP,398064,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,294,280707,HP,401009,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,295,282768,HP,403954,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,296,284830,HP,406899,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,297,286891,HP,409844,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,298,288953,HP,412789,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,299,291014,HP,415734,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10001,Fenrir HP Rune,300,293076,HP,418679,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,1,2468,ATK,235,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,2,2657,ATK,253,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,3,2846,ATK,271,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,4,3035,ATK,289,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,5,3224,ATK,307,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,6,3413,ATK,325,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,7,3602,ATK,343,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,8,3791,ATK,361,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,9,3980,ATK,379,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,10,4169,ATK,397,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,11,4358,ATK,415,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,12,4547,ATK,433,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,13,4736,ATK,451,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,14,4925,ATK,469,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,15,5114,ATK,487,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,16,5303,ATK,505,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,17,5492,ATK,523,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,18,5681,ATK,541,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,19,5870,ATK,559,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,20,6059,ATK,577,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,21,6248,ATK,595,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,22,6437,ATK,613,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,23,6626,ATK,631,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,24,6815,ATK,649,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,25,7004,ATK,667,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,26,7193,ATK,685,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,27,7382,ATK,703,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,28,7571,ATK,721,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,29,7760,ATK,739,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,30,7949,ATK,757,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,31,8138,ATK,775,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,32,8327,ATK,793,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,33,8516,ATK,811,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,34,8705,ATK,829,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,35,8894,ATK,847,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,36,9083,ATK,865,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,37,9272,ATK,883,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,38,9461,ATK,901,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,39,9650,ATK,919,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,40,9839,ATK,937,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,41,10028,ATK,955,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,42,10217,ATK,973,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,43,10406,ATK,991,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,44,10595,ATK,1009,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,45,10784,ATK,1027,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,46,10973,ATK,1045,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,47,11162,ATK,1063,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,48,11351,ATK,1081,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,49,11540,ATK,1099,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,50,11729,ATK,1117,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,51,12002,ATK,1143,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,52,12275,ATK,1169,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,53,12548,ATK,1195,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,54,12821,ATK,1221,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,55,13094,ATK,1247,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,56,13367,ATK,1273,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,57,13640,ATK,1299,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,58,13913,ATK,1325,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,59,14186,ATK,1351,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,60,14459,ATK,1377,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,61,14732,ATK,1403,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,62,15005,ATK,1429,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,63,15278,ATK,1455,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,64,15551,ATK,1481,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,65,15824,ATK,1507,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,66,16097,ATK,1533,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,67,16370,ATK,1559,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,68,16643,ATK,1585,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,69,16916,ATK,1611,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,70,17189,ATK,1637,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,71,17462,ATK,1663,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,72,17735,ATK,1689,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,73,18008,ATK,1715,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,74,18281,ATK,1741,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,75,18554,ATK,1767,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,76,18827,ATK,1793,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,77,19100,ATK,1819,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,78,19373,ATK,1845,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,79,19646,ATK,1871,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,80,19919,ATK,1897,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,81,20192,ATK,1923,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,82,20465,ATK,1949,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,83,20738,ATK,1975,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,84,21011,ATK,2001,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,85,21284,ATK,2027,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,86,21557,ATK,2053,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,87,21830,ATK,2079,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,88,22103,ATK,2105,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,89,22376,ATK,2131,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,90,22649,ATK,2157,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,91,22922,ATK,2183,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,92,23195,ATK,2209,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,93,23468,ATK,2235,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,94,23741,ATK,2261,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,95,24014,ATK,2287,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,96,24287,ATK,2313,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,97,24560,ATK,2339,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,98,24833,ATK,2365,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,99,25106,ATK,2391,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,100,25379,ATK,2417,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,101,25820,ATK,2459,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,102,26261,ATK,2501,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,103,26702,ATK,2543,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,104,27143,ATK,2585,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,105,27584,ATK,2627,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,106,28025,ATK,2669,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,107,28466,ATK,2711,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,108,28907,ATK,2753,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,109,29348,ATK,2795,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,110,29789,ATK,2837,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,111,30230,ATK,2879,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,112,30671,ATK,2921,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,113,31112,ATK,2963,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,114,31553,ATK,3005,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,115,31994,ATK,3047,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,116,32435,ATK,3089,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,117,32876,ATK,3131,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,118,33317,ATK,3173,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,119,33758,ATK,3215,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,120,34199,ATK,3257,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,121,34640,ATK,3299,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,122,35081,ATK,3341,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,123,35522,ATK,3383,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,124,35963,ATK,3425,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,125,36404,ATK,3467,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,126,36845,ATK,3509,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,127,37286,ATK,3551,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,128,37727,ATK,3593,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,129,38168,ATK,3635,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,130,38609,ATK,3677,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,131,39050,ATK,3719,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,132,39491,ATK,3761,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,133,39932,ATK,3803,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,134,40373,ATK,3845,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,135,40814,ATK,3887,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,136,41255,ATK,3929,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,137,41696,ATK,3971,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,138,42137,ATK,4013,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,139,42578,ATK,4055,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,140,43019,ATK,4097,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,141,43460,ATK,4139,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,142,43901,ATK,4181,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,143,44342,ATK,4223,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,144,44783,ATK,4265,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,145,45224,ATK,4307,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,146,45665,ATK,4349,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,147,46106,ATK,4391,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,148,46547,ATK,4433,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,149,46988,ATK,4475,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,150,47429,ATK,4517,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,151,48122,ATK,4583,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,152,48815,ATK,4649,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,153,49508,ATK,4715,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,154,50201,ATK,4781,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,155,50894,ATK,4847,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,156,51587,ATK,4913,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,157,52280,ATK,4979,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,158,52973,ATK,5045,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,159,53666,ATK,5111,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,160,54359,ATK,5177,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,161,55052,ATK,5243,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,162,55745,ATK,5309,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,163,56438,ATK,5375,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,164,57131,ATK,5441,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,165,57824,ATK,5507,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,166,58517,ATK,5573,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,167,59210,ATK,5639,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,168,59903,ATK,5705,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,169,60596,ATK,5771,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,170,61289,ATK,5837,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,171,61982,ATK,5903,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,172,62675,ATK,5969,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,173,63368,ATK,6035,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,174,64061,ATK,6101,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,175,64754,ATK,6167,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,176,65447,ATK,6233,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,177,66140,ATK,6299,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,178,66833,ATK,6365,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,179,67526,ATK,6431,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,180,68219,ATK,6497,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,181,68912,ATK,6563,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,182,69605,ATK,6629,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,183,70298,ATK,6695,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,184,70991,ATK,6761,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,185,71684,ATK,6827,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,186,72377,ATK,6893,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,187,73070,ATK,6959,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,188,73763,ATK,7025,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,189,74456,ATK,7091,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,190,75149,ATK,7157,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,191,75842,ATK,7223,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,192,76535,ATK,7289,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,193,77228,ATK,7355,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,194,77921,ATK,7421,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,195,78614,ATK,7487,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,196,79307,ATK,7553,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,197,80000,ATK,7619,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,198,80693,ATK,7685,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,199,81386,ATK,7751,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,200,82079,ATK,7817,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,201,82919,ATK,7897,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,202,83759,ATK,7977,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,203,84599,ATK,8057,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,204,85439,ATK,8137,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,205,86279,ATK,8217,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,206,87119,ATK,8297,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,207,87959,ATK,8377,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,208,88799,ATK,8457,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,209,89639,ATK,8537,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,210,90479,ATK,8617,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,211,91319,ATK,8697,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,212,92159,ATK,8777,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,213,92999,ATK,8857,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,214,93839,ATK,8937,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,215,94679,ATK,9017,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,216,95519,ATK,9097,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,217,96359,ATK,9177,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,218,97199,ATK,9257,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,219,98039,ATK,9337,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,220,98879,ATK,9417,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,221,99719,ATK,9497,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,222,100559,ATK,9577,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,223,101399,ATK,9657,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,224,102239,ATK,9737,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,225,103079,ATK,9817,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,226,103919,ATK,9897,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,227,104759,ATK,9977,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,228,105599,ATK,10057,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,229,106439,ATK,10137,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,230,107279,ATK,10217,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,231,108119,ATK,10297,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,232,108959,ATK,10377,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,233,109799,ATK,10457,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,234,110639,ATK,10537,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,235,111479,ATK,10617,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,236,112319,ATK,10697,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,237,113159,ATK,10777,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,238,113999,ATK,10857,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,239,114839,ATK,10937,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,240,115679,ATK,11017,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,241,116519,ATK,11097,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,242,117359,ATK,11177,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,243,118199,ATK,11257,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,244,119039,ATK,11337,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,245,119879,ATK,11417,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,246,120719,ATK,11497,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,247,121559,ATK,11577,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,248,122399,ATK,11657,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,249,123239,ATK,11737,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,250,124079,ATK,11817,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,251,125318,ATK,11935,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,252,126557,ATK,12053,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,253,127796,ATK,12171,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,254,129035,ATK,12289,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,255,130274,ATK,12407,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,256,131513,ATK,12525,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,257,132752,ATK,12643,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,258,133991,ATK,12761,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,259,135230,ATK,12879,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,260,136469,ATK,12997,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,261,137708,ATK,13115,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,262,138947,ATK,13233,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,263,140186,ATK,13351,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,264,141425,ATK,13469,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,265,142664,ATK,13587,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,266,143903,ATK,13705,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,267,145142,ATK,13823,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,268,146381,ATK,13941,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,269,147620,ATK,14059,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,270,148859,ATK,14177,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,271,150098,ATK,14295,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,272,151337,ATK,14413,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,273,152576,ATK,14531,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,274,153815,ATK,14649,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,275,155054,ATK,14767,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,276,156293,ATK,14885,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,277,157532,ATK,15003,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,278,158771,ATK,15121,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,279,160010,ATK,15239,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,280,161249,ATK,15357,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,281,162488,ATK,15475,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,282,163727,ATK,15593,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,283,164966,ATK,15711,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,284,166205,ATK,15829,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,285,167444,ATK,15947,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,286,168683,ATK,16065,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,287,169922,ATK,16183,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,288,171161,ATK,16301,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,289,172400,ATK,16419,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,290,173639,ATK,16537,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,291,174878,ATK,16655,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,292,176117,ATK,16773,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,293,177356,ATK,16891,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,294,178595,ATK,17009,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,295,179834,ATK,17127,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,296,181073,ATK,17245,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,297,182312,ATK,17363,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,298,183551,ATK,17481,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,299,184790,ATK,17599,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10002,Fenrir ATK Rune,300,186029,ATK,17717,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10003,Fenrir Bleeding Rune,1,3756,ATK,311,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,2,3925,ATK,325,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,3,4094,ATK,339,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,4,4263,ATK,353,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,5,4432,ATK,367,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,6,4601,ATK,381,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,7,4770,ATK,395,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,8,4939,ATK,409,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,9,5108,ATK,423,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,10,5277,ATK,437,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,11,5446,ATK,451,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,12,5615,ATK,465,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,13,5784,ATK,479,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,14,5953,ATK,493,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.26,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,15,6123,ATK,507,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,16,6292,ATK,521,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,17,6461,ATK,535,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,18,6630,ATK,549,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,19,6799,ATK,563,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,20,6968,ATK,577,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,21,7137,ATK,591,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,22,7306,ATK,605,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,23,7475,ATK,619,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,24,7644,ATK,633,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.52,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,25,7813,ATK,647,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,26,7982,ATK,661,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,27,8151,ATK,675,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,28,8320,ATK,689,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,29,8489,ATK,703,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.65,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,30,8658,ATK,717,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,31,8827,ATK,731,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,32,8996,ATK,745,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,33,9165,ATK,759,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,34,9334,ATK,773,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.78,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,35,9504,ATK,787,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,36,9673,ATK,801,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,37,9842,ATK,815,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,38,10011,ATK,829,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,39,10180,ATK,843,Add,NONE,0,Add,NONE,0,Add,600001,10,20,1.91,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,40,10349,ATK,857,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,41,10518,ATK,871,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,42,10687,ATK,885,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,43,10856,ATK,899,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,44,11025,ATK,913,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.01,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,45,11194,ATK,927,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,46,11363,ATK,941,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,47,11532,ATK,955,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,48,11701,ATK,969,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,49,11870,ATK,983,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,50,12039,ATK,997,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,51,12281,ATK,1017,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,52,12522,ATK,1037,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,53,12764,ATK,1057,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,54,13005,ATK,1077,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,55,13247,ATK,1097,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,56,13488,ATK,1117,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,57,13730,ATK,1137,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,58,13971,ATK,1157,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,59,14213,ATK,1177,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.31,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,60,14454,ATK,1197,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,61,14696,ATK,1217,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,62,14937,ATK,1237,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,63,15179,ATK,1257,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,64,15420,ATK,1277,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,65,15662,ATK,1297,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,66,15903,ATK,1317,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,67,16145,ATK,1337,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,68,16386,ATK,1357,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,69,16628,ATK,1377,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.51,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,70,16869,ATK,1397,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,71,17111,ATK,1417,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,72,17352,ATK,1437,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,73,17594,ATK,1457,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,74,17835,ATK,1477,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,75,18077,ATK,1497,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,76,18318,ATK,1517,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,77,18560,ATK,1537,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,78,18801,ATK,1557,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,79,19043,ATK,1577,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.71,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,80,19284,ATK,1597,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,81,19526,ATK,1617,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,82,19767,ATK,1637,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,83,20009,ATK,1657,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,84,20250,ATK,1677,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,85,20492,ATK,1697,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,86,20733,ATK,1717,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,87,20975,ATK,1737,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,88,21216,ATK,1757,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,89,21458,ATK,1777,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,90,21699,ATK,1797,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,91,21941,ATK,1817,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,92,22182,ATK,1837,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,93,22424,ATK,1857,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,94,22665,ATK,1877,Add,NONE,0,Add,NONE,0,Add,600001,10,20,2.97,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,95,22907,ATK,1897,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,96,23148,ATK,1917,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,97,23390,ATK,1937,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,98,23631,ATK,1957,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,99,23873,ATK,1977,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,100,24114,ATK,1997,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,101,24501,ATK,2029,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,102,24887,ATK,2061,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,103,25273,ATK,2093,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,104,25660,ATK,2125,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.13,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,105,26046,ATK,2157,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,106,26433,ATK,2189,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,107,26819,ATK,2221,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,108,27205,ATK,2253,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,109,27592,ATK,2285,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.21,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,110,27978,ATK,2317,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,111,28365,ATK,2349,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,112,28751,ATK,2381,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,113,29137,ATK,2413,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,114,29524,ATK,2445,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,115,29910,ATK,2477,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,116,30297,ATK,2509,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,117,30683,ATK,2541,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,118,31069,ATK,2573,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,119,31456,ATK,2605,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.37,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,120,31842,ATK,2637,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,121,32229,ATK,2669,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,122,32615,ATK,2701,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,123,33001,ATK,2733,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,124,33388,ATK,2765,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.45,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,125,33774,ATK,2797,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,126,34161,ATK,2829,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,127,34547,ATK,2861,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,128,34933,ATK,2893,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,129,35320,ATK,2925,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,130,35706,ATK,2957,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,131,36093,ATK,2989,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,132,36479,ATK,3021,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,133,36865,ATK,3053,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,134,37252,ATK,3085,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.61,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,135,37638,ATK,3117,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,136,38025,ATK,3149,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,137,38411,ATK,3181,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,138,38797,ATK,3213,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,139,39184,ATK,3245,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,140,39570,ATK,3277,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,141,39957,ATK,3309,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,142,40343,ATK,3341,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,143,40729,ATK,3373,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,144,41116,ATK,3405,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.75,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,145,41502,ATK,3437,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,146,41889,ATK,3469,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,147,42275,ATK,3501,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,148,42661,ATK,3533,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,149,43048,ATK,3565,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.81,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,150,43434,ATK,3597,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,151,44038,ATK,3647,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,152,44642,ATK,3697,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,153,45246,ATK,3747,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,154,45849,ATK,3797,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.87,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,155,46453,ATK,3847,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,156,47057,ATK,3897,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,157,47661,ATK,3947,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,158,48264,ATK,3997,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,159,48868,ATK,4047,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.93,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,160,49472,ATK,4097,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,161,50076,ATK,4147,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,162,50679,ATK,4197,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,163,51283,ATK,4247,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,164,51887,ATK,4297,Add,NONE,0,Add,NONE,0,Add,600001,10,20,3.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,165,52491,ATK,4347,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,166,53094,ATK,4397,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,167,53698,ATK,4447,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,168,54302,ATK,4497,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,169,54906,ATK,4547,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.05,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,170,55509,ATK,4597,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,171,56113,ATK,4647,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,172,56717,ATK,4697,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,173,57321,ATK,4747,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,174,57924,ATK,4797,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.11,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,175,58528,ATK,4847,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,176,59132,ATK,4897,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,177,59736,ATK,4947,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,178,60339,ATK,4997,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,179,60943,ATK,5047,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.17,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,180,61547,ATK,5097,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,181,62151,ATK,5147,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,182,62754,ATK,5197,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,183,63358,ATK,5247,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,184,63962,ATK,5297,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.23,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,185,64566,ATK,5347,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,186,65169,ATK,5397,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,187,65773,ATK,5447,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,188,66377,ATK,5497,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,189,66981,ATK,5547,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,190,67584,ATK,5597,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,191,68188,ATK,5647,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,192,68792,ATK,5697,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,193,69396,ATK,5747,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,194,69999,ATK,5797,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.35,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,195,70603,ATK,5847,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,196,71207,ATK,5897,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,197,71811,ATK,5947,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,198,72414,ATK,5997,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,199,73018,ATK,6047,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.41,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,200,73622,ATK,6097,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,201,74346,ATK,6157,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,202,75071,ATK,6217,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,203,75795,ATK,6277,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,204,76520,ATK,6337,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.47,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,205,77244,ATK,6397,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,206,77969,ATK,6457,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,207,78693,ATK,6517,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,208,79418,ATK,6577,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,209,80142,ATK,6637,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.53,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,210,80867,ATK,6697,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,211,81591,ATK,6757,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,212,82316,ATK,6817,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,213,83040,ATK,6877,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,214,83765,ATK,6937,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.59,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,215,84489,ATK,6997,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,216,85214,ATK,7057,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,217,85938,ATK,7117,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,218,86663,ATK,7177,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,219,87387,ATK,7237,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.64,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,220,88112,ATK,7297,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,221,88836,ATK,7357,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,222,89561,ATK,7417,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,223,90285,ATK,7477,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,224,91010,ATK,7537,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.69,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,225,91734,ATK,7597,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,226,92459,ATK,7657,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,227,93183,ATK,7717,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,228,93908,ATK,7777,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,229,94632,ATK,7837,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.74,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,230,95357,ATK,7897,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,231,96081,ATK,7957,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,232,96806,ATK,8017,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,233,97530,ATK,8077,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,234,98255,ATK,8137,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.79,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,235,98979,ATK,8197,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,236,99704,ATK,8257,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,237,100428,ATK,8317,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,238,101153,ATK,8377,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,239,101877,ATK,8437,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.84,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,240,102602,ATK,8497,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,241,103326,ATK,8557,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,242,104051,ATK,8617,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,243,104775,ATK,8677,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,244,105500,ATK,8737,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.89,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,245,106224,ATK,8797,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,246,106949,ATK,8857,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,247,107673,ATK,8917,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,248,108398,ATK,8977,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,249,109122,ATK,9037,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.94,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,250,109847,ATK,9097,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,251,110921,ATK,9186,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,252,111996,ATK,9275,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,253,113071,ATK,9364,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,254,114145,ATK,9453,Add,NONE,0,Add,NONE,0,Add,600001,10,20,4.99,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,255,115220,ATK,9542,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,256,116295,ATK,9631,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,257,117369,ATK,9720,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,258,118444,ATK,9809,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,259,119519,ATK,9898,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.04,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,260,120594,ATK,9987,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,261,121668,ATK,10076,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,262,122743,ATK,10165,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,263,123818,ATK,10254,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,264,124892,ATK,10343,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.09,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,265,125967,ATK,10432,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,266,127042,ATK,10521,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,267,128116,ATK,10610,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,268,129191,ATK,10699,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,269,130266,ATK,10788,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.14,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,270,131340,ATK,10877,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,271,132415,ATK,10966,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,272,133490,ATK,11055,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,273,134564,ATK,11144,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,274,135639,ATK,11233,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.19,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,275,136714,ATK,11322,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,276,137788,ATK,11411,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,277,138863,ATK,11500,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,278,139938,ATK,11589,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,279,141012,ATK,11678,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.24,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,280,142087,ATK,11767,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,281,143162,ATK,11856,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,282,144236,ATK,11945,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,283,145311,ATK,12034,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,284,146386,ATK,12123,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.29,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,285,147460,ATK,12212,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,286,148535,ATK,12301,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,287,149610,ATK,12390,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,288,150684,ATK,12479,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,289,151759,ATK,12568,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.34,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,290,152834,ATK,12657,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,291,153908,ATK,12746,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,292,154983,ATK,12835,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,293,156058,ATK,12924,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,294,157132,ATK,13013,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.39,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,295,158207,ATK,13102,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,296,159282,ATK,13191,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,297,160356,ATK,13280,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,298,161431,ATK,13369,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,299,162506,ATK,13458,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.44,Percentage,ATK,Caster,10 +10003,Fenrir Bleeding Rune,300,163581,ATK,13547,Add,NONE,0,Add,NONE,0,Add,600001,10,20,5.49,Percentage,ATK,Caster,10 10011,Saehrimnir Rune 1,1,807,HIT,269,Add,NONE,0,Add,NONE,0,Add,,,,,,,, 10011,Saehrimnir Rune 1,2,912,HIT,304,Add,NONE,0,Add,NONE,0,Add,,,,,,,, 10011,Saehrimnir Rune 1,3,1017,HIT,339,Add,NONE,0,Add,NONE,0,Add,,,,,,,, @@ -1499,903 +1499,903 @@ rune_id,_name,level,total_cp,stat_type_1,value_1,value_type_1,stat_type_2,value_ 10011,Saehrimnir Rune 1,298,84411,HIT,28137,Add,NONE,0,Add,NONE,0,Add,,,,,,,, 10011,Saehrimnir Rune 1,299,85044,HIT,28348,Add,NONE,0,Add,NONE,0,Add,,,,,,,, 10011,Saehrimnir Rune 1,300,85677,HIT,28559,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,1,609,DEF,58,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,2,746,DEF,71,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,3,882,DEF,84,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,4,1019,DEF,97,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,5,1155,DEF,110,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,6,1292,DEF,123,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,7,1428,DEF,136,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,8,1565,DEF,149,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,9,1701,DEF,162,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,10,1838,DEF,175,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,11,1974,DEF,188,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,12,2111,DEF,201,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,13,2247,DEF,214,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,14,2384,DEF,227,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,15,2520,DEF,240,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,16,2657,DEF,253,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,17,2793,DEF,266,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,18,2930,DEF,279,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,19,3066,DEF,292,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,20,3203,DEF,305,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,21,3339,DEF,318,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,22,3476,DEF,331,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,23,3612,DEF,344,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,24,3749,DEF,357,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,25,3885,DEF,370,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,26,4022,DEF,383,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,27,4158,DEF,396,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,28,4295,DEF,409,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,29,4431,DEF,422,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,30,4568,DEF,435,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,31,4704,DEF,448,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,32,4841,DEF,461,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,33,4977,DEF,474,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,34,5114,DEF,487,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,35,5250,DEF,500,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,36,5397,DEF,514,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,37,5544,DEF,528,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,38,5691,DEF,542,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,39,5838,DEF,556,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,40,5985,DEF,570,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,41,6132,DEF,584,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,42,6279,DEF,598,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,43,6426,DEF,612,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,44,6573,DEF,626,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,45,6720,DEF,640,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,46,6867,DEF,654,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,47,7014,DEF,668,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,48,7161,DEF,682,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,49,7308,DEF,696,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,50,7455,DEF,710,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,51,7602,DEF,724,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,52,7749,DEF,738,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,53,7896,DEF,752,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,54,8043,DEF,766,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,55,8190,DEF,780,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,56,8337,DEF,794,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,57,8484,DEF,808,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,58,8631,DEF,822,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,59,8778,DEF,836,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,60,8925,DEF,850,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,61,9072,DEF,864,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,62,9219,DEF,878,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,63,9366,DEF,892,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,64,9513,DEF,906,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,65,9660,DEF,920,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,66,9807,DEF,934,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,67,9954,DEF,948,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,68,10101,DEF,962,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,69,10248,DEF,976,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,70,10395,DEF,990,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,71,10542,DEF,1004,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,72,10689,DEF,1018,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,73,10836,DEF,1032,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,74,10983,DEF,1046,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,75,11130,DEF,1060,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,76,11277,DEF,1074,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,77,11424,DEF,1088,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,78,11571,DEF,1102,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,79,11718,DEF,1116,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,80,11865,DEF,1130,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,81,12044,DEF,1147,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,82,12222,DEF,1164,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,83,12401,DEF,1181,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,84,12579,DEF,1198,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,85,12758,DEF,1215,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,86,12936,DEF,1232,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,87,13115,DEF,1249,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,88,13293,DEF,1266,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,89,13472,DEF,1283,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,90,13650,DEF,1300,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,91,13829,DEF,1317,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,92,14007,DEF,1334,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,93,14186,DEF,1351,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,94,14364,DEF,1368,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,95,14543,DEF,1385,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,96,14721,DEF,1402,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,97,14900,DEF,1419,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,98,15078,DEF,1436,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,99,15257,DEF,1453,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,100,15435,DEF,1470,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,101,15614,DEF,1487,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,102,15792,DEF,1504,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,103,15971,DEF,1521,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,104,16149,DEF,1538,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,105,16328,DEF,1555,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,106,16506,DEF,1572,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,107,16685,DEF,1589,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,108,16863,DEF,1606,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,109,17042,DEF,1623,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,110,17220,DEF,1640,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,111,17399,DEF,1657,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,112,17577,DEF,1674,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,113,17756,DEF,1691,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,114,17934,DEF,1708,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,115,18113,DEF,1725,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,116,18291,DEF,1742,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,117,18470,DEF,1759,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,118,18648,DEF,1776,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,119,18827,DEF,1793,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,120,19005,DEF,1810,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,121,19184,DEF,1827,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,122,19362,DEF,1844,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,123,19541,DEF,1861,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,124,19719,DEF,1878,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,125,19898,DEF,1895,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,126,20076,DEF,1912,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,127,20255,DEF,1929,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,128,20433,DEF,1946,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,129,20612,DEF,1963,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,130,20790,DEF,1980,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,131,20969,DEF,1997,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,132,21147,DEF,2014,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,133,21326,DEF,2031,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,134,21504,DEF,2048,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,135,21683,DEF,2065,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,136,21872,DEF,2083,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,137,22061,DEF,2101,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,138,22250,DEF,2119,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,139,22439,DEF,2137,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,140,22628,DEF,2155,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,141,22817,DEF,2173,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,142,23006,DEF,2191,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,143,23195,DEF,2209,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,144,23384,DEF,2227,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,145,23573,DEF,2245,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,146,23762,DEF,2263,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,147,23951,DEF,2281,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,148,24140,DEF,2299,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,149,24329,DEF,2317,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,150,24518,DEF,2335,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,151,24707,DEF,2353,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,152,24896,DEF,2371,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,153,25085,DEF,2389,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,154,25274,DEF,2407,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,155,25463,DEF,2425,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,156,25652,DEF,2443,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,157,25841,DEF,2461,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,158,26030,DEF,2479,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,159,26219,DEF,2497,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,160,26408,DEF,2515,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,161,26597,DEF,2533,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,162,26786,DEF,2551,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,163,26975,DEF,2569,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,164,27164,DEF,2587,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,165,27353,DEF,2605,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,166,27542,DEF,2623,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,167,27731,DEF,2641,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,168,27920,DEF,2659,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,169,28109,DEF,2677,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,170,28298,DEF,2695,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,171,28487,DEF,2713,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,172,28676,DEF,2731,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,173,28865,DEF,2749,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,174,29054,DEF,2767,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,175,29243,DEF,2785,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,176,29432,DEF,2803,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,177,29621,DEF,2821,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,178,29810,DEF,2839,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,179,29999,DEF,2857,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,180,30188,DEF,2875,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,181,30377,DEF,2893,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,182,30566,DEF,2911,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,183,30755,DEF,2929,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,184,30944,DEF,2947,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,185,31133,DEF,2965,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,186,31322,DEF,2983,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,187,31511,DEF,3001,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,188,31700,DEF,3019,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,189,31889,DEF,3037,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,190,32078,DEF,3055,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,191,32267,DEF,3073,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,192,32456,DEF,3091,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,193,32645,DEF,3109,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,194,32834,DEF,3127,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,195,33023,DEF,3145,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,196,33212,DEF,3163,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,197,33401,DEF,3181,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,198,33590,DEF,3199,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,199,33779,DEF,3217,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,200,33968,DEF,3235,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,201,34157,DEF,3253,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,202,34346,DEF,3271,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,203,34535,DEF,3289,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,204,34724,DEF,3307,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,205,34913,DEF,3325,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,206,35102,DEF,3343,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,207,35291,DEF,3361,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,208,35480,DEF,3379,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,209,35669,DEF,3397,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,210,35858,DEF,3415,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,211,36330,DEF,3460,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,212,36803,DEF,3505,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,213,37275,DEF,3550,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,214,37748,DEF,3595,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,215,38220,DEF,3640,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,216,38693,DEF,3685,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,217,39165,DEF,3730,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,218,39638,DEF,3775,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,219,40110,DEF,3820,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,220,40583,DEF,3865,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,221,41055,DEF,3910,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,222,41528,DEF,3955,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,223,42000,DEF,4000,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,224,42473,DEF,4045,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,225,42945,DEF,4090,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,226,43418,DEF,4135,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,227,43890,DEF,4180,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,228,44363,DEF,4225,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,229,44835,DEF,4270,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,230,45308,DEF,4315,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,231,45780,DEF,4360,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,232,46253,DEF,4405,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,233,46725,DEF,4450,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,234,47198,DEF,4495,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,235,47670,DEF,4540,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,236,48143,DEF,4585,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,237,48615,DEF,4630,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,238,49088,DEF,4675,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,239,49560,DEF,4720,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,240,50033,DEF,4765,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,241,50505,DEF,4810,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,242,50978,DEF,4855,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,243,51450,DEF,4900,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,244,51923,DEF,4945,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,245,52395,DEF,4990,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,246,52868,DEF,5035,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,247,53340,DEF,5080,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,248,53813,DEF,5125,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,249,54285,DEF,5170,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,250,54758,DEF,5215,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,251,55230,DEF,5260,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,252,55703,DEF,5305,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,253,56175,DEF,5350,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,254,56648,DEF,5395,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,255,57120,DEF,5440,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,256,57593,DEF,5485,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,257,58065,DEF,5530,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,258,58538,DEF,5575,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,259,59010,DEF,5620,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,260,59483,DEF,5665,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,261,59955,DEF,5710,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,262,60428,DEF,5755,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,263,60900,DEF,5800,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,264,61373,DEF,5845,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,265,61845,DEF,5890,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,266,62318,DEF,5935,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,267,62790,DEF,5980,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,268,63263,DEF,6025,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,269,63735,DEF,6070,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,270,64208,DEF,6115,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,271,64680,DEF,6160,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,272,65153,DEF,6205,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,273,65625,DEF,6250,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,274,66098,DEF,6295,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,275,66570,DEF,6340,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,276,67043,DEF,6385,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,277,67515,DEF,6430,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,278,67988,DEF,6475,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,279,68460,DEF,6520,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,280,68933,DEF,6565,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,281,69405,DEF,6610,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,282,69878,DEF,6655,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,283,70350,DEF,6700,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,284,70823,DEF,6745,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,285,71295,DEF,6790,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,286,71768,DEF,6835,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,287,72240,DEF,6880,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,288,72713,DEF,6925,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,289,73185,DEF,6970,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,290,73658,DEF,7015,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,291,74130,DEF,7060,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,292,74603,DEF,7105,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,293,75075,DEF,7150,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,294,75548,DEF,7195,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,295,76020,DEF,7240,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,296,76493,DEF,7285,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,297,76965,DEF,7330,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,298,77438,DEF,7375,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,299,77910,DEF,7420,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10012,Saehrimnir Rune 2,300,78383,DEF,7465,Add,NONE,0,Add,NONE,0,Add,,,,,,,, -10013,Saehrimnir Rune 3,1,1255,HP,1558,Add,NONE,0,Add,NONE,0,Add,700003,14,20,5250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,2,1382,HP,1716,Add,NONE,0,Add,NONE,0,Add,700003,14,20,5500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,3,1509,HP,1874,Add,NONE,0,Add,NONE,0,Add,700003,14,20,5750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,4,1636,HP,2032,Add,NONE,0,Add,NONE,0,Add,700003,14,20,6000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,5,1763,HP,2190,Add,NONE,0,Add,NONE,0,Add,700003,14,20,6250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,6,1891,HP,2348,Add,NONE,0,Add,NONE,0,Add,700003,14,20,6500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,7,2018,HP,2506,Add,NONE,0,Add,NONE,0,Add,700003,14,20,6750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,8,2145,HP,2664,Add,NONE,0,Add,NONE,0,Add,700003,14,20,7000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,9,2272,HP,2822,Add,NONE,0,Add,NONE,0,Add,700003,14,20,7250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,10,2399,HP,2980,Add,NONE,0,Add,NONE,0,Add,700003,14,20,7500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,11,2527,HP,3138,Add,NONE,0,Add,NONE,0,Add,700003,14,20,7750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,12,2654,HP,3296,Add,NONE,0,Add,NONE,0,Add,700003,14,20,8000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,13,2781,HP,3454,Add,NONE,0,Add,NONE,0,Add,700003,14,20,8250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,14,2908,HP,3612,Add,NONE,0,Add,NONE,0,Add,700003,14,20,8500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,15,3035,HP,3770,Add,NONE,0,Add,NONE,0,Add,700003,14,20,8750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,16,3163,HP,3928,Add,NONE,0,Add,NONE,0,Add,700003,14,20,9000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,17,3290,HP,4086,Add,NONE,0,Add,NONE,0,Add,700003,14,20,9250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,18,3417,HP,4244,Add,NONE,0,Add,NONE,0,Add,700003,14,20,9500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,19,3544,HP,4402,Add,NONE,0,Add,NONE,0,Add,700003,14,20,9750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,20,3671,HP,4560,Add,NONE,0,Add,NONE,0,Add,700003,14,20,10000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,21,3798,HP,4718,Add,NONE,0,Add,NONE,0,Add,700003,14,20,10250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,22,3926,HP,4876,Add,NONE,0,Add,NONE,0,Add,700003,14,20,10500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,23,4053,HP,5034,Add,NONE,0,Add,NONE,0,Add,700003,14,20,10750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,24,4180,HP,5192,Add,NONE,0,Add,NONE,0,Add,700003,14,20,11000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,25,4307,HP,5350,Add,NONE,0,Add,NONE,0,Add,700003,14,20,11250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,26,4434,HP,5508,Add,NONE,0,Add,NONE,0,Add,700003,14,20,11500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,27,4562,HP,5666,Add,NONE,0,Add,NONE,0,Add,700003,14,20,11750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,28,4689,HP,5824,Add,NONE,0,Add,NONE,0,Add,700003,14,20,12000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,29,4816,HP,5982,Add,NONE,0,Add,NONE,0,Add,700003,14,20,12250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,30,4943,HP,6140,Add,NONE,0,Add,NONE,0,Add,700003,14,20,12500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,31,5070,HP,6298,Add,NONE,0,Add,NONE,0,Add,700003,14,20,12750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,32,5198,HP,6456,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,33,5325,HP,6614,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,34,5452,HP,6772,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,35,5579,HP,6930,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,36,5707,HP,7089,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,37,5835,HP,7248,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,38,5963,HP,7407,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,39,6091,HP,7566,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,40,6219,HP,7725,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,41,6347,HP,7884,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,42,6475,HP,8043,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,43,6603,HP,8202,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,44,6731,HP,8361,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,45,6859,HP,8520,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,46,6987,HP,8679,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,47,7115,HP,8838,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,48,7243,HP,8997,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,49,7371,HP,9156,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,50,7499,HP,9315,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,51,7627,HP,9474,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,52,7755,HP,9633,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,53,7883,HP,9792,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,54,8011,HP,9951,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,55,8139,HP,10110,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,56,8267,HP,10269,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,57,8395,HP,10428,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,58,8523,HP,10587,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,59,8651,HP,10746,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,60,8779,HP,10905,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,61,8907,HP,11064,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,62,9035,HP,11223,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,63,9163,HP,11382,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,64,9291,HP,11541,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,65,9419,HP,11700,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,66,9547,HP,11859,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,67,9675,HP,12018,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,68,9803,HP,12177,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,69,9931,HP,12336,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,70,10059,HP,12495,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,71,10187,HP,12654,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,72,10315,HP,12813,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,73,10443,HP,12972,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,74,10571,HP,13131,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,75,10699,HP,13290,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,76,10827,HP,13449,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,77,10955,HP,13608,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,78,11083,HP,13767,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,79,11211,HP,13926,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,80,11339,HP,14085,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,81,11496,HP,14280,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,82,11653,HP,14475,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23050,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,83,11810,HP,14670,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,84,11967,HP,14865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,85,12124,HP,15060,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,86,12281,HP,15255,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23650,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,87,12438,HP,15450,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,88,12595,HP,15645,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,89,12752,HP,15840,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,90,12909,HP,16035,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,91,13066,HP,16230,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,92,13223,HP,16425,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,93,13380,HP,16620,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,94,13537,HP,16815,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24850,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,95,13694,HP,17010,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,96,13851,HP,17205,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,97,14007,HP,17400,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,98,14164,HP,17595,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25450,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,99,14321,HP,17790,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,100,14478,HP,17985,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,101,14635,HP,18180,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,102,14792,HP,18375,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26050,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,103,14949,HP,18570,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,104,15106,HP,18765,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,105,15263,HP,18960,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,106,15420,HP,19155,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26650,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,107,15577,HP,19350,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,108,15734,HP,19545,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,109,15891,HP,19740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,110,16048,HP,19935,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,111,16205,HP,20130,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,112,16362,HP,20325,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,113,16519,HP,20520,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,114,16676,HP,20715,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27850,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,115,16833,HP,20910,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,116,16990,HP,21105,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,117,17147,HP,21300,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,118,17304,HP,21495,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28450,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,119,17461,HP,21690,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,120,17618,HP,21885,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,121,17775,HP,22080,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,122,17932,HP,22275,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29050,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,123,18089,HP,22470,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,124,18246,HP,22665,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,125,18403,HP,22860,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,126,18560,HP,23055,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29650,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,127,18717,HP,23250,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,128,18874,HP,23445,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,129,19031,HP,23640,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,130,19188,HP,23835,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,131,19345,HP,24030,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,132,19502,HP,24225,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,133,19659,HP,24420,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,134,19816,HP,24615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30850,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,135,19973,HP,24810,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,136,20232,HP,25132,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,137,20491,HP,25454,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,138,20750,HP,25776,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,139,21009,HP,26098,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,140,21269,HP,26420,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,141,21528,HP,26742,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,142,21787,HP,27064,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,143,22046,HP,27386,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,144,22305,HP,27708,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,145,22565,HP,28030,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,146,22824,HP,28352,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,147,23083,HP,28674,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,148,23342,HP,28996,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,149,23601,HP,29318,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,150,23861,HP,29640,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,151,24120,HP,29962,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,152,24379,HP,30284,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,153,24638,HP,30606,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,154,24898,HP,30928,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,155,25157,HP,31250,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,156,25416,HP,31572,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,157,25675,HP,31894,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,158,25934,HP,32216,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,159,26194,HP,32538,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,160,26453,HP,32860,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,161,26712,HP,33182,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,162,26971,HP,33504,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,163,27230,HP,33826,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,164,27490,HP,34148,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,165,27749,HP,34470,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,166,28008,HP,34792,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,167,28267,HP,35114,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,168,28526,HP,35436,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,169,28786,HP,35758,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,170,29045,HP,36080,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,171,29304,HP,36402,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,172,29563,HP,36724,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,173,29823,HP,37046,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,174,30082,HP,37368,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,175,30341,HP,37690,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,176,30600,HP,38012,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,177,30859,HP,38334,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,178,31119,HP,38656,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,179,31378,HP,38978,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,180,31637,HP,39300,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,181,31896,HP,39622,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,182,32155,HP,39944,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,183,32415,HP,40266,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,184,32674,HP,40588,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,185,32933,HP,40910,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,186,33192,HP,41232,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,187,33451,HP,41554,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,188,33711,HP,41876,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,189,33970,HP,42198,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,190,34229,HP,42520,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,191,34488,HP,42842,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,192,34748,HP,43164,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,193,35007,HP,43486,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,194,35266,HP,43808,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,195,35525,HP,44130,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,196,35784,HP,44452,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,197,36044,HP,44774,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,198,36303,HP,45096,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,199,36562,HP,45418,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,200,36821,HP,45740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,201,37080,HP,46062,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,202,37340,HP,46384,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,203,37599,HP,46706,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,204,37858,HP,47028,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,205,38117,HP,47350,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,206,38376,HP,47672,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,207,38636,HP,47994,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,208,38895,HP,48316,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,209,39154,HP,48638,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,210,39413,HP,48960,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,211,39700,HP,49316,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,212,39986,HP,49672,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,213,40273,HP,50028,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38650,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,214,40560,HP,50384,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,215,40846,HP,50740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,216,41133,HP,51096,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,217,41419,HP,51452,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38850,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,218,41706,HP,51808,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,219,41993,HP,52164,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,220,42279,HP,52520,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,221,42566,HP,52876,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39050,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,222,42852,HP,53232,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,223,43139,HP,53588,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,224,43425,HP,53944,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,225,43712,HP,54300,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,226,43999,HP,54656,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,227,44285,HP,55012,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,228,44572,HP,55368,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,229,44858,HP,55724,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39450,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,230,45145,HP,56080,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,231,45431,HP,56436,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,232,45718,HP,56792,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,233,46005,HP,57148,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39650,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,234,46291,HP,57504,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,235,46578,HP,57860,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,236,46864,HP,58216,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,237,47151,HP,58572,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39850,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,238,47438,HP,58928,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,239,47724,HP,59284,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,240,48011,HP,59640,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,241,48297,HP,59996,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40050,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,242,48584,HP,60352,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,243,48870,HP,60708,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,244,49157,HP,61064,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,245,49444,HP,61420,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,246,49730,HP,61776,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,247,50017,HP,62132,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,248,50303,HP,62488,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,249,50590,HP,62844,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40450,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,250,50876,HP,63200,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,251,51163,HP,63556,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,252,51450,HP,63912,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,253,51736,HP,64268,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40650,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,254,52023,HP,64624,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,255,52309,HP,64980,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,256,52596,HP,65336,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,257,52883,HP,65692,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40850,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,258,53169,HP,66048,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,259,53456,HP,66404,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,260,53742,HP,66760,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,261,54029,HP,67116,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41050,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,262,54315,HP,67472,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,263,54602,HP,67828,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,264,54889,HP,68184,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,265,55175,HP,68540,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,266,55462,HP,68896,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,267,55748,HP,69252,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,268,56035,HP,69608,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,269,56322,HP,69964,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41450,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,270,56608,HP,70320,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,271,56895,HP,70676,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,272,57181,HP,71032,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,273,57468,HP,71388,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41650,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,274,57754,HP,71744,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,275,58041,HP,72100,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,276,58328,HP,72456,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,277,58614,HP,72812,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41850,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,278,58901,HP,73168,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,279,59187,HP,73524,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,280,59474,HP,73880,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42000,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,281,59760,HP,74236,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42050,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,282,60047,HP,74592,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42100,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,283,60334,HP,74948,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42150,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,284,60620,HP,75304,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42200,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,285,60907,HP,75660,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42250,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,286,61193,HP,76016,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42300,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,287,61480,HP,76372,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42350,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,288,61767,HP,76728,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42400,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,289,62053,HP,77084,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42450,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,290,62340,HP,77440,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42500,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,291,62626,HP,77796,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42550,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,292,62913,HP,78152,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42600,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,293,63199,HP,78508,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42650,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,294,63486,HP,78864,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42700,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,295,63773,HP,79220,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42750,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,296,64059,HP,79576,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42800,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,297,64346,HP,79932,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42850,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,298,64632,HP,80288,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42900,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,299,64919,HP,80644,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42950,Add,NONE,Caster,8 -10013,Saehrimnir Rune 3,300,65205,HP,81000,Add,NONE,0,Add,NONE,0,Add,700003,14,20,43000,Add,NONE,Caster,8 -20001,Golden leaf Rune,1,3109,HIT,642,Add,ATK,74,Add,NONE,0,Add,700002,16,30,1535,Add,NONE,Caster,12 -20001,Golden leaf Rune,2,3357,HIT,686,Add,ATK,82,Add,NONE,0,Add,700002,16,30,1570,Add,NONE,Caster,12 -20001,Golden leaf Rune,3,3606,HIT,730,Add,ATK,90,Add,NONE,0,Add,700002,16,30,1605,Add,NONE,Caster,12 -20001,Golden leaf Rune,4,3854,HIT,774,Add,ATK,98,Add,NONE,0,Add,700002,16,30,1640,Add,NONE,Caster,12 -20001,Golden leaf Rune,5,4103,HIT,818,Add,ATK,106,Add,NONE,0,Add,700002,16,30,1675,Add,NONE,Caster,12 -20001,Golden leaf Rune,6,4351,HIT,862,Add,ATK,114,Add,NONE,0,Add,700002,16,30,1710,Add,NONE,Caster,12 -20001,Golden leaf Rune,7,4599,HIT,906,Add,ATK,122,Add,NONE,0,Add,700002,16,30,1745,Add,NONE,Caster,12 -20001,Golden leaf Rune,8,4848,HIT,950,Add,ATK,130,Add,NONE,0,Add,700002,16,30,1780,Add,NONE,Caster,12 -20001,Golden leaf Rune,9,5096,HIT,994,Add,ATK,138,Add,NONE,0,Add,700002,16,30,1815,Add,NONE,Caster,12 -20001,Golden leaf Rune,10,5345,HIT,1038,Add,ATK,146,Add,NONE,0,Add,700002,16,30,1850,Add,NONE,Caster,12 -20001,Golden leaf Rune,11,5593,HIT,1082,Add,ATK,154,Add,NONE,0,Add,700002,16,30,1885,Add,NONE,Caster,12 -20001,Golden leaf Rune,12,5841,HIT,1126,Add,ATK,162,Add,NONE,0,Add,700002,16,30,1920,Add,NONE,Caster,12 -20001,Golden leaf Rune,13,6090,HIT,1170,Add,ATK,170,Add,NONE,0,Add,700002,16,30,1955,Add,NONE,Caster,12 -20001,Golden leaf Rune,14,6338,HIT,1214,Add,ATK,178,Add,NONE,0,Add,700002,16,30,1990,Add,NONE,Caster,12 -20001,Golden leaf Rune,15,6587,HIT,1258,Add,ATK,186,Add,NONE,0,Add,700002,16,30,2025,Add,NONE,Caster,12 -20001,Golden leaf Rune,16,6835,HIT,1302,Add,ATK,194,Add,NONE,0,Add,700002,16,30,2060,Add,NONE,Caster,12 -20001,Golden leaf Rune,17,7083,HIT,1346,Add,ATK,202,Add,NONE,0,Add,700002,16,30,2095,Add,NONE,Caster,12 -20001,Golden leaf Rune,18,7332,HIT,1390,Add,ATK,210,Add,NONE,0,Add,700002,16,30,2130,Add,NONE,Caster,12 -20001,Golden leaf Rune,19,7580,HIT,1434,Add,ATK,218,Add,NONE,0,Add,700002,16,30,2165,Add,NONE,Caster,12 -20001,Golden leaf Rune,20,7829,HIT,1478,Add,ATK,226,Add,NONE,0,Add,700002,16,30,2200,Add,NONE,Caster,12 -20001,Golden leaf Rune,21,8077,HIT,1522,Add,ATK,234,Add,NONE,0,Add,700002,16,30,2235,Add,NONE,Caster,12 -20001,Golden leaf Rune,22,8325,HIT,1566,Add,ATK,242,Add,NONE,0,Add,700002,16,30,2270,Add,NONE,Caster,12 -20001,Golden leaf Rune,23,8574,HIT,1610,Add,ATK,250,Add,NONE,0,Add,700002,16,30,2305,Add,NONE,Caster,12 -20001,Golden leaf Rune,24,8822,HIT,1654,Add,ATK,258,Add,NONE,0,Add,700002,16,30,2340,Add,NONE,Caster,12 -20001,Golden leaf Rune,25,9071,HIT,1698,Add,ATK,266,Add,NONE,0,Add,700002,16,30,2375,Add,NONE,Caster,12 -20001,Golden leaf Rune,26,9319,HIT,1742,Add,ATK,274,Add,NONE,0,Add,700002,16,30,2410,Add,NONE,Caster,12 -20001,Golden leaf Rune,27,9567,HIT,1786,Add,ATK,282,Add,NONE,0,Add,700002,16,30,2445,Add,NONE,Caster,12 -20001,Golden leaf Rune,28,9816,HIT,1830,Add,ATK,290,Add,NONE,0,Add,700002,16,30,2480,Add,NONE,Caster,12 -20001,Golden leaf Rune,29,10064,HIT,1874,Add,ATK,298,Add,NONE,0,Add,700002,16,30,2515,Add,NONE,Caster,12 -20001,Golden leaf Rune,30,10313,HIT,1918,Add,ATK,306,Add,NONE,0,Add,700002,16,30,2550,Add,NONE,Caster,12 -20001,Golden leaf Rune,31,10561,HIT,1962,Add,ATK,314,Add,NONE,0,Add,700002,16,30,2585,Add,NONE,Caster,12 -20001,Golden leaf Rune,32,10809,HIT,2006,Add,ATK,322,Add,NONE,0,Add,700002,16,30,2620,Add,NONE,Caster,12 -20001,Golden leaf Rune,33,11058,HIT,2050,Add,ATK,330,Add,NONE,0,Add,700002,16,30,2655,Add,NONE,Caster,12 -20001,Golden leaf Rune,34,11306,HIT,2094,Add,ATK,338,Add,NONE,0,Add,700002,16,30,2690,Add,NONE,Caster,12 -20001,Golden leaf Rune,35,11555,HIT,2138,Add,ATK,346,Add,NONE,0,Add,700002,16,30,2725,Add,NONE,Caster,12 -20001,Golden leaf Rune,36,11818,HIT,2183,Add,ATK,355,Add,NONE,0,Add,700002,16,30,2753,Add,NONE,Caster,12 -20001,Golden leaf Rune,37,12082,HIT,2228,Add,ATK,364,Add,NONE,0,Add,700002,16,30,2781,Add,NONE,Caster,12 -20001,Golden leaf Rune,38,12346,HIT,2273,Add,ATK,373,Add,NONE,0,Add,700002,16,30,2809,Add,NONE,Caster,12 -20001,Golden leaf Rune,39,12610,HIT,2318,Add,ATK,382,Add,NONE,0,Add,700002,16,30,2837,Add,NONE,Caster,12 -20001,Golden leaf Rune,40,12874,HIT,2363,Add,ATK,391,Add,NONE,0,Add,700002,16,30,2865,Add,NONE,Caster,12 -20001,Golden leaf Rune,41,13138,HIT,2408,Add,ATK,400,Add,NONE,0,Add,700002,16,30,2893,Add,NONE,Caster,12 -20001,Golden leaf Rune,42,13402,HIT,2453,Add,ATK,409,Add,NONE,0,Add,700002,16,30,2921,Add,NONE,Caster,12 -20001,Golden leaf Rune,43,13666,HIT,2498,Add,ATK,418,Add,NONE,0,Add,700002,16,30,2949,Add,NONE,Caster,12 -20001,Golden leaf Rune,44,13930,HIT,2543,Add,ATK,427,Add,NONE,0,Add,700002,16,30,2977,Add,NONE,Caster,12 -20001,Golden leaf Rune,45,14194,HIT,2588,Add,ATK,436,Add,NONE,0,Add,700002,16,30,3005,Add,NONE,Caster,12 -20001,Golden leaf Rune,46,14458,HIT,2633,Add,ATK,445,Add,NONE,0,Add,700002,16,30,3033,Add,NONE,Caster,12 -20001,Golden leaf Rune,47,14722,HIT,2678,Add,ATK,454,Add,NONE,0,Add,700002,16,30,3061,Add,NONE,Caster,12 -20001,Golden leaf Rune,48,14986,HIT,2723,Add,ATK,463,Add,NONE,0,Add,700002,16,30,3089,Add,NONE,Caster,12 -20001,Golden leaf Rune,49,15249,HIT,2768,Add,ATK,472,Add,NONE,0,Add,700002,16,30,3117,Add,NONE,Caster,12 -20001,Golden leaf Rune,50,15513,HIT,2813,Add,ATK,481,Add,NONE,0,Add,700002,16,30,3145,Add,NONE,Caster,12 -20001,Golden leaf Rune,51,15777,HIT,2858,Add,ATK,490,Add,NONE,0,Add,700002,16,30,3173,Add,NONE,Caster,12 -20001,Golden leaf Rune,52,16041,HIT,2903,Add,ATK,499,Add,NONE,0,Add,700002,16,30,3201,Add,NONE,Caster,12 -20001,Golden leaf Rune,53,16305,HIT,2948,Add,ATK,508,Add,NONE,0,Add,700002,16,30,3229,Add,NONE,Caster,12 -20001,Golden leaf Rune,54,16569,HIT,2993,Add,ATK,517,Add,NONE,0,Add,700002,16,30,3257,Add,NONE,Caster,12 -20001,Golden leaf Rune,55,16833,HIT,3038,Add,ATK,526,Add,NONE,0,Add,700002,16,30,3285,Add,NONE,Caster,12 -20001,Golden leaf Rune,56,17097,HIT,3083,Add,ATK,535,Add,NONE,0,Add,700002,16,30,3313,Add,NONE,Caster,12 -20001,Golden leaf Rune,57,17361,HIT,3128,Add,ATK,544,Add,NONE,0,Add,700002,16,30,3341,Add,NONE,Caster,12 -20001,Golden leaf Rune,58,17625,HIT,3173,Add,ATK,553,Add,NONE,0,Add,700002,16,30,3369,Add,NONE,Caster,12 -20001,Golden leaf Rune,59,17889,HIT,3218,Add,ATK,562,Add,NONE,0,Add,700002,16,30,3397,Add,NONE,Caster,12 -20001,Golden leaf Rune,60,18153,HIT,3263,Add,ATK,571,Add,NONE,0,Add,700002,16,30,3425,Add,NONE,Caster,12 -20001,Golden leaf Rune,61,18417,HIT,3308,Add,ATK,580,Add,NONE,0,Add,700002,16,30,3453,Add,NONE,Caster,12 -20001,Golden leaf Rune,62,18681,HIT,3353,Add,ATK,589,Add,NONE,0,Add,700002,16,30,3481,Add,NONE,Caster,12 -20001,Golden leaf Rune,63,18944,HIT,3398,Add,ATK,598,Add,NONE,0,Add,700002,16,30,3509,Add,NONE,Caster,12 -20001,Golden leaf Rune,64,19208,HIT,3443,Add,ATK,607,Add,NONE,0,Add,700002,16,30,3537,Add,NONE,Caster,12 -20001,Golden leaf Rune,65,19472,HIT,3488,Add,ATK,616,Add,NONE,0,Add,700002,16,30,3565,Add,NONE,Caster,12 -20001,Golden leaf Rune,66,19736,HIT,3533,Add,ATK,625,Add,NONE,0,Add,700002,16,30,3593,Add,NONE,Caster,12 -20001,Golden leaf Rune,67,20000,HIT,3578,Add,ATK,634,Add,NONE,0,Add,700002,16,30,3621,Add,NONE,Caster,12 -20001,Golden leaf Rune,68,20264,HIT,3623,Add,ATK,643,Add,NONE,0,Add,700002,16,30,3649,Add,NONE,Caster,12 -20001,Golden leaf Rune,69,20528,HIT,3668,Add,ATK,652,Add,NONE,0,Add,700002,16,30,3677,Add,NONE,Caster,12 -20001,Golden leaf Rune,70,20792,HIT,3713,Add,ATK,661,Add,NONE,0,Add,700002,16,30,3705,Add,NONE,Caster,12 -20001,Golden leaf Rune,71,21056,HIT,3758,Add,ATK,670,Add,NONE,0,Add,700002,16,30,3733,Add,NONE,Caster,12 -20001,Golden leaf Rune,72,21320,HIT,3803,Add,ATK,679,Add,NONE,0,Add,700002,16,30,3761,Add,NONE,Caster,12 -20001,Golden leaf Rune,73,21584,HIT,3848,Add,ATK,688,Add,NONE,0,Add,700002,16,30,3789,Add,NONE,Caster,12 -20001,Golden leaf Rune,74,21848,HIT,3893,Add,ATK,697,Add,NONE,0,Add,700002,16,30,3817,Add,NONE,Caster,12 -20001,Golden leaf Rune,75,22112,HIT,3938,Add,ATK,706,Add,NONE,0,Add,700002,16,30,3845,Add,NONE,Caster,12 -20001,Golden leaf Rune,76,22375,HIT,3983,Add,ATK,715,Add,NONE,0,Add,700002,16,30,3873,Add,NONE,Caster,12 -20001,Golden leaf Rune,77,22639,HIT,4028,Add,ATK,724,Add,NONE,0,Add,700002,16,30,3901,Add,NONE,Caster,12 -20001,Golden leaf Rune,78,22903,HIT,4073,Add,ATK,733,Add,NONE,0,Add,700002,16,30,3929,Add,NONE,Caster,12 -20001,Golden leaf Rune,79,23167,HIT,4118,Add,ATK,742,Add,NONE,0,Add,700002,16,30,3957,Add,NONE,Caster,12 -20001,Golden leaf Rune,80,23431,HIT,4163,Add,ATK,751,Add,NONE,0,Add,700002,16,30,3985,Add,NONE,Caster,12 -20001,Golden leaf Rune,81,23747,HIT,4216,Add,ATK,762,Add,NONE,0,Add,700002,16,30,4005,Add,NONE,Caster,12 -20001,Golden leaf Rune,82,24063,HIT,4269,Add,ATK,773,Add,NONE,0,Add,700002,16,30,4025,Add,NONE,Caster,12 -20001,Golden leaf Rune,83,24378,HIT,4322,Add,ATK,784,Add,NONE,0,Add,700002,16,30,4045,Add,NONE,Caster,12 -20001,Golden leaf Rune,84,24694,HIT,4375,Add,ATK,795,Add,NONE,0,Add,700002,16,30,4065,Add,NONE,Caster,12 -20001,Golden leaf Rune,85,25010,HIT,4428,Add,ATK,806,Add,NONE,0,Add,700002,16,30,4085,Add,NONE,Caster,12 -20001,Golden leaf Rune,86,25325,HIT,4481,Add,ATK,817,Add,NONE,0,Add,700002,16,30,4105,Add,NONE,Caster,12 -20001,Golden leaf Rune,87,25641,HIT,4534,Add,ATK,828,Add,NONE,0,Add,700002,16,30,4125,Add,NONE,Caster,12 -20001,Golden leaf Rune,88,25957,HIT,4587,Add,ATK,839,Add,NONE,0,Add,700002,16,30,4145,Add,NONE,Caster,12 -20001,Golden leaf Rune,89,26272,HIT,4640,Add,ATK,850,Add,NONE,0,Add,700002,16,30,4165,Add,NONE,Caster,12 -20001,Golden leaf Rune,90,26588,HIT,4693,Add,ATK,861,Add,NONE,0,Add,700002,16,30,4185,Add,NONE,Caster,12 -20001,Golden leaf Rune,91,26904,HIT,4746,Add,ATK,872,Add,NONE,0,Add,700002,16,30,4205,Add,NONE,Caster,12 -20001,Golden leaf Rune,92,27219,HIT,4799,Add,ATK,883,Add,NONE,0,Add,700002,16,30,4225,Add,NONE,Caster,12 -20001,Golden leaf Rune,93,27535,HIT,4852,Add,ATK,894,Add,NONE,0,Add,700002,16,30,4245,Add,NONE,Caster,12 -20001,Golden leaf Rune,94,27851,HIT,4905,Add,ATK,905,Add,NONE,0,Add,700002,16,30,4265,Add,NONE,Caster,12 -20001,Golden leaf Rune,95,28166,HIT,4958,Add,ATK,916,Add,NONE,0,Add,700002,16,30,4285,Add,NONE,Caster,12 -20001,Golden leaf Rune,96,28482,HIT,5011,Add,ATK,927,Add,NONE,0,Add,700002,16,30,4305,Add,NONE,Caster,12 -20001,Golden leaf Rune,97,28798,HIT,5064,Add,ATK,938,Add,NONE,0,Add,700002,16,30,4325,Add,NONE,Caster,12 -20001,Golden leaf Rune,98,29113,HIT,5117,Add,ATK,949,Add,NONE,0,Add,700002,16,30,4345,Add,NONE,Caster,12 -20001,Golden leaf Rune,99,29429,HIT,5170,Add,ATK,960,Add,NONE,0,Add,700002,16,30,4365,Add,NONE,Caster,12 -20001,Golden leaf Rune,100,29745,HIT,5223,Add,ATK,971,Add,NONE,0,Add,700002,16,30,4385,Add,NONE,Caster,12 -20001,Golden leaf Rune,101,30060,HIT,5276,Add,ATK,982,Add,NONE,0,Add,700002,16,30,4405,Add,NONE,Caster,12 -20001,Golden leaf Rune,102,30376,HIT,5329,Add,ATK,993,Add,NONE,0,Add,700002,16,30,4425,Add,NONE,Caster,12 -20001,Golden leaf Rune,103,30692,HIT,5382,Add,ATK,1004,Add,NONE,0,Add,700002,16,30,4445,Add,NONE,Caster,12 -20001,Golden leaf Rune,104,31007,HIT,5435,Add,ATK,1015,Add,NONE,0,Add,700002,16,30,4465,Add,NONE,Caster,12 -20001,Golden leaf Rune,105,31323,HIT,5488,Add,ATK,1026,Add,NONE,0,Add,700002,16,30,4485,Add,NONE,Caster,12 -20001,Golden leaf Rune,106,31639,HIT,5541,Add,ATK,1037,Add,NONE,0,Add,700002,16,30,4505,Add,NONE,Caster,12 -20001,Golden leaf Rune,107,31954,HIT,5594,Add,ATK,1048,Add,NONE,0,Add,700002,16,30,4525,Add,NONE,Caster,12 -20001,Golden leaf Rune,108,32270,HIT,5647,Add,ATK,1059,Add,NONE,0,Add,700002,16,30,4545,Add,NONE,Caster,12 -20001,Golden leaf Rune,109,32586,HIT,5700,Add,ATK,1070,Add,NONE,0,Add,700002,16,30,4565,Add,NONE,Caster,12 -20001,Golden leaf Rune,110,32901,HIT,5753,Add,ATK,1081,Add,NONE,0,Add,700002,16,30,4585,Add,NONE,Caster,12 -20001,Golden leaf Rune,111,33217,HIT,5806,Add,ATK,1092,Add,NONE,0,Add,700002,16,30,4605,Add,NONE,Caster,12 -20001,Golden leaf Rune,112,33533,HIT,5859,Add,ATK,1103,Add,NONE,0,Add,700002,16,30,4625,Add,NONE,Caster,12 -20001,Golden leaf Rune,113,33848,HIT,5912,Add,ATK,1114,Add,NONE,0,Add,700002,16,30,4645,Add,NONE,Caster,12 -20001,Golden leaf Rune,114,34164,HIT,5965,Add,ATK,1125,Add,NONE,0,Add,700002,16,30,4665,Add,NONE,Caster,12 -20001,Golden leaf Rune,115,34480,HIT,6018,Add,ATK,1136,Add,NONE,0,Add,700002,16,30,4685,Add,NONE,Caster,12 -20001,Golden leaf Rune,116,34795,HIT,6071,Add,ATK,1147,Add,NONE,0,Add,700002,16,30,4705,Add,NONE,Caster,12 -20001,Golden leaf Rune,117,35111,HIT,6124,Add,ATK,1158,Add,NONE,0,Add,700002,16,30,4725,Add,NONE,Caster,12 -20001,Golden leaf Rune,118,35427,HIT,6177,Add,ATK,1169,Add,NONE,0,Add,700002,16,30,4745,Add,NONE,Caster,12 -20001,Golden leaf Rune,119,35742,HIT,6230,Add,ATK,1180,Add,NONE,0,Add,700002,16,30,4765,Add,NONE,Caster,12 -20001,Golden leaf Rune,120,36058,HIT,6283,Add,ATK,1191,Add,NONE,0,Add,700002,16,30,4785,Add,NONE,Caster,12 -20001,Golden leaf Rune,121,36374,HIT,6336,Add,ATK,1202,Add,NONE,0,Add,700002,16,30,4805,Add,NONE,Caster,12 -20001,Golden leaf Rune,122,36690,HIT,6389,Add,ATK,1213,Add,NONE,0,Add,700002,16,30,4825,Add,NONE,Caster,12 -20001,Golden leaf Rune,123,37005,HIT,6442,Add,ATK,1224,Add,NONE,0,Add,700002,16,30,4845,Add,NONE,Caster,12 -20001,Golden leaf Rune,124,37321,HIT,6495,Add,ATK,1235,Add,NONE,0,Add,700002,16,30,4865,Add,NONE,Caster,12 -20001,Golden leaf Rune,125,37637,HIT,6548,Add,ATK,1246,Add,NONE,0,Add,700002,16,30,4885,Add,NONE,Caster,12 -20001,Golden leaf Rune,126,37952,HIT,6601,Add,ATK,1257,Add,NONE,0,Add,700002,16,30,4905,Add,NONE,Caster,12 -20001,Golden leaf Rune,127,38268,HIT,6654,Add,ATK,1268,Add,NONE,0,Add,700002,16,30,4925,Add,NONE,Caster,12 -20001,Golden leaf Rune,128,38584,HIT,6707,Add,ATK,1279,Add,NONE,0,Add,700002,16,30,4945,Add,NONE,Caster,12 -20001,Golden leaf Rune,129,38899,HIT,6760,Add,ATK,1290,Add,NONE,0,Add,700002,16,30,4965,Add,NONE,Caster,12 -20001,Golden leaf Rune,130,39215,HIT,6813,Add,ATK,1301,Add,NONE,0,Add,700002,16,30,4985,Add,NONE,Caster,12 -20001,Golden leaf Rune,131,39531,HIT,6866,Add,ATK,1312,Add,NONE,0,Add,700002,16,30,5005,Add,NONE,Caster,12 -20001,Golden leaf Rune,132,39846,HIT,6919,Add,ATK,1323,Add,NONE,0,Add,700002,16,30,5025,Add,NONE,Caster,12 -20001,Golden leaf Rune,133,40162,HIT,6972,Add,ATK,1334,Add,NONE,0,Add,700002,16,30,5045,Add,NONE,Caster,12 -20001,Golden leaf Rune,134,40478,HIT,7025,Add,ATK,1345,Add,NONE,0,Add,700002,16,30,5065,Add,NONE,Caster,12 -20001,Golden leaf Rune,135,40793,HIT,7078,Add,ATK,1356,Add,NONE,0,Add,700002,16,30,5085,Add,NONE,Caster,12 -20001,Golden leaf Rune,136,41285,HIT,7147,Add,ATK,1377,Add,NONE,0,Add,700002,16,30,5099,Add,NONE,Caster,12 -20001,Golden leaf Rune,137,41777,HIT,7216,Add,ATK,1398,Add,NONE,0,Add,700002,16,30,5113,Add,NONE,Caster,12 -20001,Golden leaf Rune,138,42268,HIT,7285,Add,ATK,1419,Add,NONE,0,Add,700002,16,30,5127,Add,NONE,Caster,12 -20001,Golden leaf Rune,139,42760,HIT,7354,Add,ATK,1440,Add,NONE,0,Add,700002,16,30,5141,Add,NONE,Caster,12 -20001,Golden leaf Rune,140,43251,HIT,7423,Add,ATK,1461,Add,NONE,0,Add,700002,16,30,5155,Add,NONE,Caster,12 -20001,Golden leaf Rune,141,43743,HIT,7492,Add,ATK,1482,Add,NONE,0,Add,700002,16,30,5169,Add,NONE,Caster,12 -20001,Golden leaf Rune,142,44235,HIT,7561,Add,ATK,1503,Add,NONE,0,Add,700002,16,30,5183,Add,NONE,Caster,12 -20001,Golden leaf Rune,143,44726,HIT,7630,Add,ATK,1524,Add,NONE,0,Add,700002,16,30,5197,Add,NONE,Caster,12 -20001,Golden leaf Rune,144,45218,HIT,7699,Add,ATK,1545,Add,NONE,0,Add,700002,16,30,5211,Add,NONE,Caster,12 -20001,Golden leaf Rune,145,45710,HIT,7768,Add,ATK,1566,Add,NONE,0,Add,700002,16,30,5225,Add,NONE,Caster,12 -20001,Golden leaf Rune,146,46201,HIT,7837,Add,ATK,1587,Add,NONE,0,Add,700002,16,30,5239,Add,NONE,Caster,12 -20001,Golden leaf Rune,147,46693,HIT,7906,Add,ATK,1608,Add,NONE,0,Add,700002,16,30,5253,Add,NONE,Caster,12 -20001,Golden leaf Rune,148,47184,HIT,7975,Add,ATK,1629,Add,NONE,0,Add,700002,16,30,5267,Add,NONE,Caster,12 -20001,Golden leaf Rune,149,47676,HIT,8044,Add,ATK,1650,Add,NONE,0,Add,700002,16,30,5281,Add,NONE,Caster,12 -20001,Golden leaf Rune,150,48168,HIT,8113,Add,ATK,1671,Add,NONE,0,Add,700002,16,30,5295,Add,NONE,Caster,12 -20001,Golden leaf Rune,151,48659,HIT,8182,Add,ATK,1692,Add,NONE,0,Add,700002,16,30,5309,Add,NONE,Caster,12 -20001,Golden leaf Rune,152,49151,HIT,8251,Add,ATK,1713,Add,NONE,0,Add,700002,16,30,5323,Add,NONE,Caster,12 -20001,Golden leaf Rune,153,49643,HIT,8320,Add,ATK,1734,Add,NONE,0,Add,700002,16,30,5337,Add,NONE,Caster,12 -20001,Golden leaf Rune,154,50134,HIT,8389,Add,ATK,1755,Add,NONE,0,Add,700002,16,30,5351,Add,NONE,Caster,12 -20001,Golden leaf Rune,155,50626,HIT,8458,Add,ATK,1776,Add,NONE,0,Add,700002,16,30,5365,Add,NONE,Caster,12 -20001,Golden leaf Rune,156,51117,HIT,8527,Add,ATK,1797,Add,NONE,0,Add,700002,16,30,5379,Add,NONE,Caster,12 -20001,Golden leaf Rune,157,51609,HIT,8596,Add,ATK,1818,Add,NONE,0,Add,700002,16,30,5393,Add,NONE,Caster,12 -20001,Golden leaf Rune,158,52101,HIT,8665,Add,ATK,1839,Add,NONE,0,Add,700002,16,30,5407,Add,NONE,Caster,12 -20001,Golden leaf Rune,159,52592,HIT,8734,Add,ATK,1860,Add,NONE,0,Add,700002,16,30,5421,Add,NONE,Caster,12 -20001,Golden leaf Rune,160,53084,HIT,8803,Add,ATK,1881,Add,NONE,0,Add,700002,16,30,5435,Add,NONE,Caster,12 -20001,Golden leaf Rune,161,53576,HIT,8872,Add,ATK,1902,Add,NONE,0,Add,700002,16,30,5449,Add,NONE,Caster,12 -20001,Golden leaf Rune,162,54067,HIT,8941,Add,ATK,1923,Add,NONE,0,Add,700002,16,30,5463,Add,NONE,Caster,12 -20001,Golden leaf Rune,163,54559,HIT,9010,Add,ATK,1944,Add,NONE,0,Add,700002,16,30,5477,Add,NONE,Caster,12 -20001,Golden leaf Rune,164,55050,HIT,9079,Add,ATK,1965,Add,NONE,0,Add,700002,16,30,5491,Add,NONE,Caster,12 -20001,Golden leaf Rune,165,55542,HIT,9148,Add,ATK,1986,Add,NONE,0,Add,700002,16,30,5505,Add,NONE,Caster,12 -20001,Golden leaf Rune,166,56034,HIT,9217,Add,ATK,2007,Add,NONE,0,Add,700002,16,30,5519,Add,NONE,Caster,12 -20001,Golden leaf Rune,167,56525,HIT,9286,Add,ATK,2028,Add,NONE,0,Add,700002,16,30,5533,Add,NONE,Caster,12 -20001,Golden leaf Rune,168,57017,HIT,9355,Add,ATK,2049,Add,NONE,0,Add,700002,16,30,5547,Add,NONE,Caster,12 -20001,Golden leaf Rune,169,57509,HIT,9424,Add,ATK,2070,Add,NONE,0,Add,700002,16,30,5561,Add,NONE,Caster,12 -20001,Golden leaf Rune,170,58000,HIT,9493,Add,ATK,2091,Add,NONE,0,Add,700002,16,30,5575,Add,NONE,Caster,12 -20001,Golden leaf Rune,171,58492,HIT,9562,Add,ATK,2112,Add,NONE,0,Add,700002,16,30,5589,Add,NONE,Caster,12 -20001,Golden leaf Rune,172,58983,HIT,9631,Add,ATK,2133,Add,NONE,0,Add,700002,16,30,5603,Add,NONE,Caster,12 -20001,Golden leaf Rune,173,59475,HIT,9700,Add,ATK,2154,Add,NONE,0,Add,700002,16,30,5617,Add,NONE,Caster,12 -20001,Golden leaf Rune,174,59967,HIT,9769,Add,ATK,2175,Add,NONE,0,Add,700002,16,30,5631,Add,NONE,Caster,12 -20001,Golden leaf Rune,175,60458,HIT,9838,Add,ATK,2196,Add,NONE,0,Add,700002,16,30,5645,Add,NONE,Caster,12 -20001,Golden leaf Rune,176,60950,HIT,9907,Add,ATK,2217,Add,NONE,0,Add,700002,16,30,5659,Add,NONE,Caster,12 -20001,Golden leaf Rune,177,61442,HIT,9976,Add,ATK,2238,Add,NONE,0,Add,700002,16,30,5673,Add,NONE,Caster,12 -20001,Golden leaf Rune,178,61933,HIT,10045,Add,ATK,2259,Add,NONE,0,Add,700002,16,30,5687,Add,NONE,Caster,12 -20001,Golden leaf Rune,179,62425,HIT,10114,Add,ATK,2280,Add,NONE,0,Add,700002,16,30,5701,Add,NONE,Caster,12 -20001,Golden leaf Rune,180,62916,HIT,10183,Add,ATK,2301,Add,NONE,0,Add,700002,16,30,5715,Add,NONE,Caster,12 -20001,Golden leaf Rune,181,63408,HIT,10252,Add,ATK,2322,Add,NONE,0,Add,700002,16,30,5729,Add,NONE,Caster,12 -20001,Golden leaf Rune,182,63900,HIT,10321,Add,ATK,2343,Add,NONE,0,Add,700002,16,30,5743,Add,NONE,Caster,12 -20001,Golden leaf Rune,183,64391,HIT,10390,Add,ATK,2364,Add,NONE,0,Add,700002,16,30,5757,Add,NONE,Caster,12 -20001,Golden leaf Rune,184,64883,HIT,10459,Add,ATK,2385,Add,NONE,0,Add,700002,16,30,5771,Add,NONE,Caster,12 -20001,Golden leaf Rune,185,65375,HIT,10528,Add,ATK,2406,Add,NONE,0,Add,700002,16,30,5785,Add,NONE,Caster,12 -20001,Golden leaf Rune,186,65866,HIT,10597,Add,ATK,2427,Add,NONE,0,Add,700002,16,30,5799,Add,NONE,Caster,12 -20001,Golden leaf Rune,187,66358,HIT,10666,Add,ATK,2448,Add,NONE,0,Add,700002,16,30,5813,Add,NONE,Caster,12 -20001,Golden leaf Rune,188,66849,HIT,10735,Add,ATK,2469,Add,NONE,0,Add,700002,16,30,5827,Add,NONE,Caster,12 -20001,Golden leaf Rune,189,67341,HIT,10804,Add,ATK,2490,Add,NONE,0,Add,700002,16,30,5841,Add,NONE,Caster,12 -20001,Golden leaf Rune,190,67833,HIT,10873,Add,ATK,2511,Add,NONE,0,Add,700002,16,30,5855,Add,NONE,Caster,12 -20001,Golden leaf Rune,191,68324,HIT,10942,Add,ATK,2532,Add,NONE,0,Add,700002,16,30,5869,Add,NONE,Caster,12 -20001,Golden leaf Rune,192,68816,HIT,11011,Add,ATK,2553,Add,NONE,0,Add,700002,16,30,5883,Add,NONE,Caster,12 -20001,Golden leaf Rune,193,69308,HIT,11080,Add,ATK,2574,Add,NONE,0,Add,700002,16,30,5897,Add,NONE,Caster,12 -20001,Golden leaf Rune,194,69799,HIT,11149,Add,ATK,2595,Add,NONE,0,Add,700002,16,30,5911,Add,NONE,Caster,12 -20001,Golden leaf Rune,195,70291,HIT,11218,Add,ATK,2616,Add,NONE,0,Add,700002,16,30,5925,Add,NONE,Caster,12 -20001,Golden leaf Rune,196,70782,HIT,11287,Add,ATK,2637,Add,NONE,0,Add,700002,16,30,5939,Add,NONE,Caster,12 -20001,Golden leaf Rune,197,71274,HIT,11356,Add,ATK,2658,Add,NONE,0,Add,700002,16,30,5953,Add,NONE,Caster,12 -20001,Golden leaf Rune,198,71766,HIT,11425,Add,ATK,2679,Add,NONE,0,Add,700002,16,30,5967,Add,NONE,Caster,12 -20001,Golden leaf Rune,199,72257,HIT,11494,Add,ATK,2700,Add,NONE,0,Add,700002,16,30,5981,Add,NONE,Caster,12 -20001,Golden leaf Rune,200,72749,HIT,11563,Add,ATK,2721,Add,NONE,0,Add,700002,16,30,5995,Add,NONE,Caster,12 -20001,Golden leaf Rune,201,73241,HIT,11632,Add,ATK,2742,Add,NONE,0,Add,700002,16,30,6009,Add,NONE,Caster,12 -20001,Golden leaf Rune,202,73732,HIT,11701,Add,ATK,2763,Add,NONE,0,Add,700002,16,30,6023,Add,NONE,Caster,12 -20001,Golden leaf Rune,203,74224,HIT,11770,Add,ATK,2784,Add,NONE,0,Add,700002,16,30,6037,Add,NONE,Caster,12 -20001,Golden leaf Rune,204,74715,HIT,11839,Add,ATK,2805,Add,NONE,0,Add,700002,16,30,6051,Add,NONE,Caster,12 -20001,Golden leaf Rune,205,75207,HIT,11908,Add,ATK,2826,Add,NONE,0,Add,700002,16,30,6065,Add,NONE,Caster,12 -20001,Golden leaf Rune,206,75699,HIT,11977,Add,ATK,2847,Add,NONE,0,Add,700002,16,30,6079,Add,NONE,Caster,12 -20001,Golden leaf Rune,207,76190,HIT,12046,Add,ATK,2868,Add,NONE,0,Add,700002,16,30,6093,Add,NONE,Caster,12 -20001,Golden leaf Rune,208,76682,HIT,12115,Add,ATK,2889,Add,NONE,0,Add,700002,16,30,6107,Add,NONE,Caster,12 -20001,Golden leaf Rune,209,77174,HIT,12184,Add,ATK,2910,Add,NONE,0,Add,700002,16,30,6121,Add,NONE,Caster,12 -20001,Golden leaf Rune,210,77665,HIT,12253,Add,ATK,2931,Add,NONE,0,Add,700002,16,30,6135,Add,NONE,Caster,12 -20001,Golden leaf Rune,211,78899,HIT,12516,Add,ATK,2958,Add,NONE,0,Add,700002,16,30,6145,Add,NONE,Caster,12 -20001,Golden leaf Rune,212,80132,HIT,12779,Add,ATK,2985,Add,NONE,0,Add,700002,16,30,6155,Add,NONE,Caster,12 -20001,Golden leaf Rune,213,81365,HIT,13042,Add,ATK,3012,Add,NONE,0,Add,700002,16,30,6165,Add,NONE,Caster,12 -20001,Golden leaf Rune,214,82599,HIT,13305,Add,ATK,3039,Add,NONE,0,Add,700002,16,30,6175,Add,NONE,Caster,12 -20001,Golden leaf Rune,215,83832,HIT,13568,Add,ATK,3066,Add,NONE,0,Add,700002,16,30,6185,Add,NONE,Caster,12 -20001,Golden leaf Rune,216,85065,HIT,13831,Add,ATK,3093,Add,NONE,0,Add,700002,16,30,6195,Add,NONE,Caster,12 -20001,Golden leaf Rune,217,86299,HIT,14094,Add,ATK,3120,Add,NONE,0,Add,700002,16,30,6205,Add,NONE,Caster,12 -20001,Golden leaf Rune,218,87532,HIT,14357,Add,ATK,3147,Add,NONE,0,Add,700002,16,30,6215,Add,NONE,Caster,12 -20001,Golden leaf Rune,219,88766,HIT,14620,Add,ATK,3174,Add,NONE,0,Add,700002,16,30,6225,Add,NONE,Caster,12 -20001,Golden leaf Rune,220,89999,HIT,14883,Add,ATK,3201,Add,NONE,0,Add,700002,16,30,6235,Add,NONE,Caster,12 -20001,Golden leaf Rune,221,91232,HIT,15146,Add,ATK,3228,Add,NONE,0,Add,700002,16,30,6245,Add,NONE,Caster,12 -20001,Golden leaf Rune,222,92466,HIT,15409,Add,ATK,3255,Add,NONE,0,Add,700002,16,30,6255,Add,NONE,Caster,12 -20001,Golden leaf Rune,223,93699,HIT,15672,Add,ATK,3282,Add,NONE,0,Add,700002,16,30,6265,Add,NONE,Caster,12 -20001,Golden leaf Rune,224,94932,HIT,15935,Add,ATK,3309,Add,NONE,0,Add,700002,16,30,6275,Add,NONE,Caster,12 -20001,Golden leaf Rune,225,96166,HIT,16198,Add,ATK,3336,Add,NONE,0,Add,700002,16,30,6285,Add,NONE,Caster,12 -20001,Golden leaf Rune,226,97399,HIT,16461,Add,ATK,3363,Add,NONE,0,Add,700002,16,30,6295,Add,NONE,Caster,12 -20001,Golden leaf Rune,227,98633,HIT,16724,Add,ATK,3390,Add,NONE,0,Add,700002,16,30,6305,Add,NONE,Caster,12 -20001,Golden leaf Rune,228,99866,HIT,16987,Add,ATK,3417,Add,NONE,0,Add,700002,16,30,6315,Add,NONE,Caster,12 -20001,Golden leaf Rune,229,101099,HIT,17250,Add,ATK,3444,Add,NONE,0,Add,700002,16,30,6325,Add,NONE,Caster,12 -20001,Golden leaf Rune,230,102333,HIT,17513,Add,ATK,3471,Add,NONE,0,Add,700002,16,30,6335,Add,NONE,Caster,12 -20001,Golden leaf Rune,231,103566,HIT,17776,Add,ATK,3498,Add,NONE,0,Add,700002,16,30,6345,Add,NONE,Caster,12 -20001,Golden leaf Rune,232,104799,HIT,18039,Add,ATK,3525,Add,NONE,0,Add,700002,16,30,6355,Add,NONE,Caster,12 -20001,Golden leaf Rune,233,106033,HIT,18302,Add,ATK,3552,Add,NONE,0,Add,700002,16,30,6365,Add,NONE,Caster,12 -20001,Golden leaf Rune,234,107266,HIT,18565,Add,ATK,3579,Add,NONE,0,Add,700002,16,30,6375,Add,NONE,Caster,12 -20001,Golden leaf Rune,235,108500,HIT,18828,Add,ATK,3606,Add,NONE,0,Add,700002,16,30,6385,Add,NONE,Caster,12 -20001,Golden leaf Rune,236,109733,HIT,19091,Add,ATK,3633,Add,NONE,0,Add,700002,16,30,6395,Add,NONE,Caster,12 -20001,Golden leaf Rune,237,110966,HIT,19354,Add,ATK,3660,Add,NONE,0,Add,700002,16,30,6405,Add,NONE,Caster,12 -20001,Golden leaf Rune,238,112200,HIT,19617,Add,ATK,3687,Add,NONE,0,Add,700002,16,30,6415,Add,NONE,Caster,12 -20001,Golden leaf Rune,239,113433,HIT,19880,Add,ATK,3714,Add,NONE,0,Add,700002,16,30,6425,Add,NONE,Caster,12 -20001,Golden leaf Rune,240,114666,HIT,20143,Add,ATK,3741,Add,NONE,0,Add,700002,16,30,6435,Add,NONE,Caster,12 -20001,Golden leaf Rune,241,115900,HIT,20406,Add,ATK,3768,Add,NONE,0,Add,700002,16,30,6445,Add,NONE,Caster,12 -20001,Golden leaf Rune,242,117133,HIT,20669,Add,ATK,3795,Add,NONE,0,Add,700002,16,30,6455,Add,NONE,Caster,12 -20001,Golden leaf Rune,243,118367,HIT,20932,Add,ATK,3822,Add,NONE,0,Add,700002,16,30,6465,Add,NONE,Caster,12 -20001,Golden leaf Rune,244,119600,HIT,21195,Add,ATK,3849,Add,NONE,0,Add,700002,16,30,6475,Add,NONE,Caster,12 -20001,Golden leaf Rune,245,120833,HIT,21458,Add,ATK,3876,Add,NONE,0,Add,700002,16,30,6485,Add,NONE,Caster,12 -20001,Golden leaf Rune,246,122067,HIT,21721,Add,ATK,3903,Add,NONE,0,Add,700002,16,30,6495,Add,NONE,Caster,12 -20001,Golden leaf Rune,247,123300,HIT,21984,Add,ATK,3930,Add,NONE,0,Add,700002,16,30,6505,Add,NONE,Caster,12 -20001,Golden leaf Rune,248,124533,HIT,22247,Add,ATK,3957,Add,NONE,0,Add,700002,16,30,6515,Add,NONE,Caster,12 -20001,Golden leaf Rune,249,125767,HIT,22510,Add,ATK,3984,Add,NONE,0,Add,700002,16,30,6525,Add,NONE,Caster,12 -20001,Golden leaf Rune,250,127000,HIT,22773,Add,ATK,4011,Add,NONE,0,Add,700002,16,30,6535,Add,NONE,Caster,12 -20001,Golden leaf Rune,251,128234,HIT,23036,Add,ATK,4038,Add,NONE,0,Add,700002,16,30,6545,Add,NONE,Caster,12 -20001,Golden leaf Rune,252,129467,HIT,23299,Add,ATK,4065,Add,NONE,0,Add,700002,16,30,6555,Add,NONE,Caster,12 -20001,Golden leaf Rune,253,130700,HIT,23562,Add,ATK,4092,Add,NONE,0,Add,700002,16,30,6565,Add,NONE,Caster,12 -20001,Golden leaf Rune,254,131934,HIT,23825,Add,ATK,4119,Add,NONE,0,Add,700002,16,30,6575,Add,NONE,Caster,12 -20001,Golden leaf Rune,255,133167,HIT,24088,Add,ATK,4146,Add,NONE,0,Add,700002,16,30,6585,Add,NONE,Caster,12 -20001,Golden leaf Rune,256,134400,HIT,24351,Add,ATK,4173,Add,NONE,0,Add,700002,16,30,6595,Add,NONE,Caster,12 -20001,Golden leaf Rune,257,135634,HIT,24614,Add,ATK,4200,Add,NONE,0,Add,700002,16,30,6605,Add,NONE,Caster,12 -20001,Golden leaf Rune,258,136867,HIT,24877,Add,ATK,4227,Add,NONE,0,Add,700002,16,30,6615,Add,NONE,Caster,12 -20001,Golden leaf Rune,259,138101,HIT,25140,Add,ATK,4254,Add,NONE,0,Add,700002,16,30,6625,Add,NONE,Caster,12 -20001,Golden leaf Rune,260,139334,HIT,25403,Add,ATK,4281,Add,NONE,0,Add,700002,16,30,6635,Add,NONE,Caster,12 -20001,Golden leaf Rune,261,140567,HIT,25666,Add,ATK,4308,Add,NONE,0,Add,700002,16,30,6645,Add,NONE,Caster,12 -20001,Golden leaf Rune,262,141801,HIT,25929,Add,ATK,4335,Add,NONE,0,Add,700002,16,30,6655,Add,NONE,Caster,12 -20001,Golden leaf Rune,263,143034,HIT,26192,Add,ATK,4362,Add,NONE,0,Add,700002,16,30,6665,Add,NONE,Caster,12 -20001,Golden leaf Rune,264,144267,HIT,26455,Add,ATK,4389,Add,NONE,0,Add,700002,16,30,6675,Add,NONE,Caster,12 -20001,Golden leaf Rune,265,145501,HIT,26718,Add,ATK,4416,Add,NONE,0,Add,700002,16,30,6685,Add,NONE,Caster,12 -20001,Golden leaf Rune,266,146734,HIT,26981,Add,ATK,4443,Add,NONE,0,Add,700002,16,30,6695,Add,NONE,Caster,12 -20001,Golden leaf Rune,267,147968,HIT,27244,Add,ATK,4470,Add,NONE,0,Add,700002,16,30,6705,Add,NONE,Caster,12 -20001,Golden leaf Rune,268,149201,HIT,27507,Add,ATK,4497,Add,NONE,0,Add,700002,16,30,6715,Add,NONE,Caster,12 -20001,Golden leaf Rune,269,150434,HIT,27770,Add,ATK,4524,Add,NONE,0,Add,700002,16,30,6725,Add,NONE,Caster,12 -20001,Golden leaf Rune,270,151668,HIT,28033,Add,ATK,4551,Add,NONE,0,Add,700002,16,30,6735,Add,NONE,Caster,12 -20001,Golden leaf Rune,271,152901,HIT,28296,Add,ATK,4578,Add,NONE,0,Add,700002,16,30,6745,Add,NONE,Caster,12 -20001,Golden leaf Rune,272,154134,HIT,28559,Add,ATK,4605,Add,NONE,0,Add,700002,16,30,6755,Add,NONE,Caster,12 -20001,Golden leaf Rune,273,155368,HIT,28822,Add,ATK,4632,Add,NONE,0,Add,700002,16,30,6765,Add,NONE,Caster,12 -20001,Golden leaf Rune,274,156601,HIT,29085,Add,ATK,4659,Add,NONE,0,Add,700002,16,30,6775,Add,NONE,Caster,12 -20001,Golden leaf Rune,275,157835,HIT,29348,Add,ATK,4686,Add,NONE,0,Add,700002,16,30,6785,Add,NONE,Caster,12 -20001,Golden leaf Rune,276,159068,HIT,29611,Add,ATK,4713,Add,NONE,0,Add,700002,16,30,6795,Add,NONE,Caster,12 -20001,Golden leaf Rune,277,160301,HIT,29874,Add,ATK,4740,Add,NONE,0,Add,700002,16,30,6805,Add,NONE,Caster,12 -20001,Golden leaf Rune,278,161535,HIT,30137,Add,ATK,4767,Add,NONE,0,Add,700002,16,30,6815,Add,NONE,Caster,12 -20001,Golden leaf Rune,279,162768,HIT,30400,Add,ATK,4794,Add,NONE,0,Add,700002,16,30,6825,Add,NONE,Caster,12 -20001,Golden leaf Rune,280,164001,HIT,30663,Add,ATK,4821,Add,NONE,0,Add,700002,16,30,6835,Add,NONE,Caster,12 -20001,Golden leaf Rune,281,165235,HIT,30926,Add,ATK,4848,Add,NONE,0,Add,700002,16,30,6845,Add,NONE,Caster,12 -20001,Golden leaf Rune,282,166468,HIT,31189,Add,ATK,4875,Add,NONE,0,Add,700002,16,30,6855,Add,NONE,Caster,12 -20001,Golden leaf Rune,283,167702,HIT,31452,Add,ATK,4902,Add,NONE,0,Add,700002,16,30,6865,Add,NONE,Caster,12 -20001,Golden leaf Rune,284,168935,HIT,31715,Add,ATK,4929,Add,NONE,0,Add,700002,16,30,6875,Add,NONE,Caster,12 -20001,Golden leaf Rune,285,170168,HIT,31978,Add,ATK,4956,Add,NONE,0,Add,700002,16,30,6885,Add,NONE,Caster,12 -20001,Golden leaf Rune,286,171402,HIT,32241,Add,ATK,4983,Add,NONE,0,Add,700002,16,30,6895,Add,NONE,Caster,12 -20001,Golden leaf Rune,287,172635,HIT,32504,Add,ATK,5010,Add,NONE,0,Add,700002,16,30,6905,Add,NONE,Caster,12 -20001,Golden leaf Rune,288,173868,HIT,32767,Add,ATK,5037,Add,NONE,0,Add,700002,16,30,6915,Add,NONE,Caster,12 -20001,Golden leaf Rune,289,175102,HIT,33030,Add,ATK,5064,Add,NONE,0,Add,700002,16,30,6925,Add,NONE,Caster,12 -20001,Golden leaf Rune,290,176335,HIT,33293,Add,ATK,5091,Add,NONE,0,Add,700002,16,30,6935,Add,NONE,Caster,12 -20001,Golden leaf Rune,291,177569,HIT,33556,Add,ATK,5118,Add,NONE,0,Add,700002,16,30,6945,Add,NONE,Caster,12 -20001,Golden leaf Rune,292,178802,HIT,33819,Add,ATK,5145,Add,NONE,0,Add,700002,16,30,6955,Add,NONE,Caster,12 -20001,Golden leaf Rune,293,180035,HIT,34082,Add,ATK,5172,Add,NONE,0,Add,700002,16,30,6965,Add,NONE,Caster,12 -20001,Golden leaf Rune,294,181269,HIT,34345,Add,ATK,5199,Add,NONE,0,Add,700002,16,30,6975,Add,NONE,Caster,12 -20001,Golden leaf Rune,295,182502,HIT,34608,Add,ATK,5226,Add,NONE,0,Add,700002,16,30,6985,Add,NONE,Caster,12 -20001,Golden leaf Rune,296,183735,HIT,34871,Add,ATK,5253,Add,NONE,0,Add,700002,16,30,6995,Add,NONE,Caster,12 -20001,Golden leaf Rune,297,184969,HIT,35134,Add,ATK,5280,Add,NONE,0,Add,700002,16,30,7005,Add,NONE,Caster,12 -20001,Golden leaf Rune,298,186202,HIT,35397,Add,ATK,5307,Add,NONE,0,Add,700002,16,30,7015,Add,NONE,Caster,12 -20001,Golden leaf Rune,299,187436,HIT,35660,Add,ATK,5334,Add,NONE,0,Add,700002,16,30,7025,Add,NONE,Caster,12 -20001,Golden leaf Rune,300,188669,HIT,35923,Add,ATK,5361,Add,NONE,0,Add,700002,16,30,7035,Add,NONE,Caster,12 \ No newline at end of file +10012,Saehrimnir Rune 2,1,1103,DEF,105,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,2,1386,DEF,132,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,3,1670,DEF,159,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,4,1953,DEF,186,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,5,2237,DEF,213,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,6,2520,DEF,240,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,7,2804,DEF,267,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,8,3087,DEF,294,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,9,3371,DEF,321,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,10,3654,DEF,348,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,11,3938,DEF,375,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,12,4221,DEF,402,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,13,4505,DEF,429,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,14,4788,DEF,456,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,15,5072,DEF,483,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,16,5355,DEF,510,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,17,5639,DEF,537,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,18,5922,DEF,564,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,19,6206,DEF,591,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,20,6489,DEF,618,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,21,6773,DEF,645,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,22,7056,DEF,672,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,23,7340,DEF,699,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,24,7623,DEF,726,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,25,7907,DEF,753,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,26,8190,DEF,780,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,27,8474,DEF,807,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,28,8757,DEF,834,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,29,9041,DEF,861,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,30,9324,DEF,888,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,31,9608,DEF,915,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,32,9891,DEF,942,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,33,10175,DEF,969,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,34,10458,DEF,996,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,35,10742,DEF,1023,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,36,11025,DEF,1050,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,37,11309,DEF,1077,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,38,11592,DEF,1104,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,39,11876,DEF,1131,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,40,12159,DEF,1158,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,41,12443,DEF,1185,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,42,12726,DEF,1212,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,43,13010,DEF,1239,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,44,13293,DEF,1266,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,45,13577,DEF,1293,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,46,13860,DEF,1320,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,47,14144,DEF,1347,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,48,14427,DEF,1374,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,49,14711,DEF,1401,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,50,14994,DEF,1428,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,51,15320,DEF,1459,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,52,15645,DEF,1490,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,53,15971,DEF,1521,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,54,16296,DEF,1552,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,55,16622,DEF,1583,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,56,16947,DEF,1614,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,57,17273,DEF,1645,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,58,17598,DEF,1676,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,59,17924,DEF,1707,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,60,18249,DEF,1738,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,61,18575,DEF,1769,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,62,18900,DEF,1800,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,63,19226,DEF,1831,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,64,19551,DEF,1862,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,65,19877,DEF,1893,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,66,20202,DEF,1924,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,67,20528,DEF,1955,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,68,20853,DEF,1986,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,69,21179,DEF,2017,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,70,21504,DEF,2048,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,71,21830,DEF,2079,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,72,22155,DEF,2110,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,73,22481,DEF,2141,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,74,22806,DEF,2172,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,75,23132,DEF,2203,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,76,23457,DEF,2234,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,77,23783,DEF,2265,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,78,24108,DEF,2296,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,79,24434,DEF,2327,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,80,24759,DEF,2358,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,81,25085,DEF,2389,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,82,25410,DEF,2420,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,83,25736,DEF,2451,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,84,26061,DEF,2482,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,85,26387,DEF,2513,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,86,26712,DEF,2544,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,87,27038,DEF,2575,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,88,27363,DEF,2606,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,89,27689,DEF,2637,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,90,28014,DEF,2668,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,91,28340,DEF,2699,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,92,28665,DEF,2730,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,93,28991,DEF,2761,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,94,29316,DEF,2792,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,95,29642,DEF,2823,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,96,29967,DEF,2854,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,97,30293,DEF,2885,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,98,30618,DEF,2916,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,99,30944,DEF,2947,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,100,31269,DEF,2978,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,101,31710,DEF,3020,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,102,32151,DEF,3062,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,103,32592,DEF,3104,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,104,33033,DEF,3146,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,105,33474,DEF,3188,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,106,33915,DEF,3230,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,107,34356,DEF,3272,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,108,34797,DEF,3314,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,109,35238,DEF,3356,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,110,35679,DEF,3398,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,111,36120,DEF,3440,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,112,36561,DEF,3482,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,113,37002,DEF,3524,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,114,37443,DEF,3566,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,115,37884,DEF,3608,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,116,38325,DEF,3650,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,117,38766,DEF,3692,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,118,39207,DEF,3734,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,119,39648,DEF,3776,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,120,40089,DEF,3818,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,121,40530,DEF,3860,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,122,40971,DEF,3902,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,123,41412,DEF,3944,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,124,41853,DEF,3986,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,125,42294,DEF,4028,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,126,42735,DEF,4070,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,127,43176,DEF,4112,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,128,43617,DEF,4154,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,129,44058,DEF,4196,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,130,44499,DEF,4238,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,131,44940,DEF,4280,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,132,45381,DEF,4322,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,133,45822,DEF,4364,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,134,46263,DEF,4406,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,135,46704,DEF,4448,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,136,47145,DEF,4490,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,137,47586,DEF,4532,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,138,48027,DEF,4574,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,139,48468,DEF,4616,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,140,48909,DEF,4658,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,141,49350,DEF,4700,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,142,49791,DEF,4742,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,143,50232,DEF,4784,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,144,50673,DEF,4826,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,145,51114,DEF,4868,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,146,51555,DEF,4910,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,147,51996,DEF,4952,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,148,52437,DEF,4994,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,149,52878,DEF,5036,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,150,53319,DEF,5078,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,151,53970,DEF,5140,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,152,54621,DEF,5202,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,153,55272,DEF,5264,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,154,55923,DEF,5326,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,155,56574,DEF,5388,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,156,57225,DEF,5450,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,157,57876,DEF,5512,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,158,58527,DEF,5574,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,159,59178,DEF,5636,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,160,59829,DEF,5698,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,161,60480,DEF,5760,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,162,61131,DEF,5822,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,163,61782,DEF,5884,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,164,62433,DEF,5946,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,165,63084,DEF,6008,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,166,63735,DEF,6070,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,167,64386,DEF,6132,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,168,65037,DEF,6194,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,169,65688,DEF,6256,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,170,66339,DEF,6318,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,171,66990,DEF,6380,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,172,67641,DEF,6442,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,173,68292,DEF,6504,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,174,68943,DEF,6566,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,175,69594,DEF,6628,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,176,70245,DEF,6690,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,177,70896,DEF,6752,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,178,71547,DEF,6814,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,179,72198,DEF,6876,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,180,72849,DEF,6938,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,181,73500,DEF,7000,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,182,74151,DEF,7062,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,183,74802,DEF,7124,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,184,75453,DEF,7186,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,185,76104,DEF,7248,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,186,76755,DEF,7310,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,187,77406,DEF,7372,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,188,78057,DEF,7434,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,189,78708,DEF,7496,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,190,79359,DEF,7558,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,191,80010,DEF,7620,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,192,80661,DEF,7682,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,193,81312,DEF,7744,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,194,81963,DEF,7806,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,195,82614,DEF,7868,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,196,83265,DEF,7930,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,197,83916,DEF,7992,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,198,84567,DEF,8054,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,199,85218,DEF,8116,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,200,85869,DEF,8178,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,201,86562,DEF,8244,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,202,87255,DEF,8310,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,203,87948,DEF,8376,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,204,88641,DEF,8442,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,205,89334,DEF,8508,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,206,90027,DEF,8574,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,207,90720,DEF,8640,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,208,91413,DEF,8706,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,209,92106,DEF,8772,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,210,92799,DEF,8838,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,211,93492,DEF,8904,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,212,94185,DEF,8970,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,213,94878,DEF,9036,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,214,95571,DEF,9102,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,215,96264,DEF,9168,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,216,96957,DEF,9234,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,217,97650,DEF,9300,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,218,98343,DEF,9366,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,219,99036,DEF,9432,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,220,99729,DEF,9498,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,221,100422,DEF,9564,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,222,101115,DEF,9630,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,223,101808,DEF,9696,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,224,102501,DEF,9762,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,225,103194,DEF,9828,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,226,103887,DEF,9894,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,227,104580,DEF,9960,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,228,105273,DEF,10026,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,229,105966,DEF,10092,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,230,106659,DEF,10158,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,231,107352,DEF,10224,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,232,108045,DEF,10290,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,233,108738,DEF,10356,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,234,109431,DEF,10422,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,235,110124,DEF,10488,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,236,110817,DEF,10554,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,237,111510,DEF,10620,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,238,112203,DEF,10686,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,239,112896,DEF,10752,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,240,113589,DEF,10818,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,241,114282,DEF,10884,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,242,114975,DEF,10950,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,243,115668,DEF,11016,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,244,116361,DEF,11082,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,245,117054,DEF,11148,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,246,117747,DEF,11214,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,247,118440,DEF,11280,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,248,119133,DEF,11346,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,249,119826,DEF,11412,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,250,120519,DEF,11478,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,251,121380,DEF,11560,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,252,122241,DEF,11642,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,253,123102,DEF,11724,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,254,123963,DEF,11806,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,255,124824,DEF,11888,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,256,125685,DEF,11970,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,257,126546,DEF,12052,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,258,127407,DEF,12134,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,259,128268,DEF,12216,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,260,129129,DEF,12298,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,261,129990,DEF,12380,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,262,130851,DEF,12462,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,263,131712,DEF,12544,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,264,132573,DEF,12626,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,265,133434,DEF,12708,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,266,134295,DEF,12790,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,267,135156,DEF,12872,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,268,136017,DEF,12954,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,269,136878,DEF,13036,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,270,137739,DEF,13118,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,271,138600,DEF,13200,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,272,139461,DEF,13282,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,273,140322,DEF,13364,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,274,141183,DEF,13446,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,275,142044,DEF,13528,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,276,142905,DEF,13610,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,277,143766,DEF,13692,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,278,144627,DEF,13774,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,279,145488,DEF,13856,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,280,146349,DEF,13938,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,281,147210,DEF,14020,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,282,148071,DEF,14102,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,283,148932,DEF,14184,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,284,149793,DEF,14266,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,285,150654,DEF,14348,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,286,151515,DEF,14430,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,287,152376,DEF,14512,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,288,153237,DEF,14594,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,289,154098,DEF,14676,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,290,154959,DEF,14758,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,291,155820,DEF,14840,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,292,156681,DEF,14922,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,293,157542,DEF,15004,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,294,158403,DEF,15086,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,295,159264,DEF,15168,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,296,160125,DEF,15250,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,297,160986,DEF,15332,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,298,161847,DEF,15414,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,299,162708,DEF,15496,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10012,Saehrimnir Rune 2,300,163569,DEF,15578,Add,NONE,0,Add,NONE,0,Add,,,,,,,, +10013,Saehrimnir Rune 3,1,1441,HP,1790,Add,NONE,0,Add,NONE,0,Add,700003,14,20,5250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,2,1582,HP,1965,Add,NONE,0,Add,NONE,0,Add,700003,14,20,5500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,3,1723,HP,2140,Add,NONE,0,Add,NONE,0,Add,700003,14,20,5750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,4,1864,HP,2315,Add,NONE,0,Add,NONE,0,Add,700003,14,20,6000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,5,2005,HP,2490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,6250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,6,2146,HP,2665,Add,NONE,0,Add,NONE,0,Add,700003,14,20,6500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,7,2287,HP,2840,Add,NONE,0,Add,NONE,0,Add,700003,14,20,6750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,8,2428,HP,3015,Add,NONE,0,Add,NONE,0,Add,700003,14,20,7000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,9,2568,HP,3190,Add,NONE,0,Add,NONE,0,Add,700003,14,20,7250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,10,2709,HP,3365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,7500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,11,2850,HP,3540,Add,NONE,0,Add,NONE,0,Add,700003,14,20,7750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,12,2991,HP,3715,Add,NONE,0,Add,NONE,0,Add,700003,14,20,8000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,13,3132,HP,3890,Add,NONE,0,Add,NONE,0,Add,700003,14,20,8250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,14,3273,HP,4065,Add,NONE,0,Add,NONE,0,Add,700003,14,20,8500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,15,3414,HP,4240,Add,NONE,0,Add,NONE,0,Add,700003,14,20,8750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,16,3555,HP,4415,Add,NONE,0,Add,NONE,0,Add,700003,14,20,9000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,17,3695,HP,4590,Add,NONE,0,Add,NONE,0,Add,700003,14,20,9250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,18,3836,HP,4765,Add,NONE,0,Add,NONE,0,Add,700003,14,20,9500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,19,3977,HP,4940,Add,NONE,0,Add,NONE,0,Add,700003,14,20,9750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,20,4118,HP,5115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,10000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,21,4259,HP,5290,Add,NONE,0,Add,NONE,0,Add,700003,14,20,10250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,22,4400,HP,5465,Add,NONE,0,Add,NONE,0,Add,700003,14,20,10500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,23,4541,HP,5640,Add,NONE,0,Add,NONE,0,Add,700003,14,20,10750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,24,4682,HP,5815,Add,NONE,0,Add,NONE,0,Add,700003,14,20,11000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,25,4822,HP,5990,Add,NONE,0,Add,NONE,0,Add,700003,14,20,11250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,26,4963,HP,6165,Add,NONE,0,Add,NONE,0,Add,700003,14,20,11500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,27,5104,HP,6340,Add,NONE,0,Add,NONE,0,Add,700003,14,20,11750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,28,5245,HP,6515,Add,NONE,0,Add,NONE,0,Add,700003,14,20,12000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,29,5386,HP,6690,Add,NONE,0,Add,NONE,0,Add,700003,14,20,12250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,30,5527,HP,6865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,12500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,31,5668,HP,7040,Add,NONE,0,Add,NONE,0,Add,700003,14,20,12750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,32,5809,HP,7215,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,33,5949,HP,7390,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,34,6090,HP,7565,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,35,6231,HP,7740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,36,6372,HP,7915,Add,NONE,0,Add,NONE,0,Add,700003,14,20,13950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,37,6513,HP,8090,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,38,6654,HP,8265,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,39,6795,HP,8440,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,40,6936,HP,8615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,41,7076,HP,8790,Add,NONE,0,Add,NONE,0,Add,700003,14,20,14950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,42,7217,HP,8965,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,43,7358,HP,9140,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,44,7499,HP,9315,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,45,7640,HP,9490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,46,7781,HP,9665,Add,NONE,0,Add,NONE,0,Add,700003,14,20,15950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,47,7922,HP,9840,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,48,8063,HP,10015,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,49,8203,HP,10190,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,50,8344,HP,10365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,51,8493,HP,10550,Add,NONE,0,Add,NONE,0,Add,700003,14,20,16950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,52,8642,HP,10735,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,53,8791,HP,10920,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,54,8940,HP,11105,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,55,9089,HP,11290,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,56,9238,HP,11475,Add,NONE,0,Add,NONE,0,Add,700003,14,20,17950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,57,9387,HP,11660,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,58,9536,HP,11845,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,59,9685,HP,12030,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,60,9834,HP,12215,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,61,9982,HP,12400,Add,NONE,0,Add,NONE,0,Add,700003,14,20,18950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,62,10131,HP,12585,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,63,10280,HP,12770,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,64,10429,HP,12955,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,65,10578,HP,13140,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,66,10727,HP,13325,Add,NONE,0,Add,NONE,0,Add,700003,14,20,19950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,67,10876,HP,13510,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,68,11025,HP,13695,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,69,11174,HP,13880,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,70,11323,HP,14065,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,71,11472,HP,14250,Add,NONE,0,Add,NONE,0,Add,700003,14,20,20950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,72,11621,HP,14435,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,73,11770,HP,14620,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,74,11919,HP,14805,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,75,12067,HP,14990,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,76,12216,HP,15175,Add,NONE,0,Add,NONE,0,Add,700003,14,20,21950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,77,12365,HP,15360,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,78,12514,HP,15545,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,79,12663,HP,15730,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,80,12812,HP,15915,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,81,12961,HP,16100,Add,NONE,0,Add,NONE,0,Add,700003,14,20,22900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,82,13110,HP,16285,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23050,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,83,13259,HP,16470,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,84,13408,HP,16655,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,85,13557,HP,16840,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,86,13706,HP,17025,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23650,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,87,13855,HP,17210,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,88,14003,HP,17395,Add,NONE,0,Add,NONE,0,Add,700003,14,20,23950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,89,14152,HP,17580,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,90,14301,HP,17765,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,91,14450,HP,17950,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,92,14599,HP,18135,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,93,14748,HP,18320,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,94,14897,HP,18505,Add,NONE,0,Add,NONE,0,Add,700003,14,20,24850,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,95,15046,HP,18690,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,96,15195,HP,18875,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,97,15344,HP,19060,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,98,15493,HP,19245,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25450,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,99,15642,HP,19430,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,100,15791,HP,19615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,101,15980,HP,19850,Add,NONE,0,Add,NONE,0,Add,700003,14,20,25900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,102,16169,HP,20085,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26050,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,103,16358,HP,20320,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,104,16547,HP,20555,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,105,16736,HP,20790,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,106,16926,HP,21025,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26650,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,107,17115,HP,21260,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,108,17304,HP,21495,Add,NONE,0,Add,NONE,0,Add,700003,14,20,26950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,109,17493,HP,21730,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,110,17682,HP,21965,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,111,17871,HP,22200,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,112,18061,HP,22435,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,113,18250,HP,22670,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,114,18439,HP,22905,Add,NONE,0,Add,NONE,0,Add,700003,14,20,27850,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,115,18628,HP,23140,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,116,18817,HP,23375,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,117,19007,HP,23610,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,118,19196,HP,23845,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28450,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,119,19385,HP,24080,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,120,19574,HP,24315,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,121,19763,HP,24550,Add,NONE,0,Add,NONE,0,Add,700003,14,20,28900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,122,19952,HP,24785,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29050,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,123,20142,HP,25020,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,124,20331,HP,25255,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,125,20520,HP,25490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,126,20709,HP,25725,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29650,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,127,20898,HP,25960,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,128,21087,HP,26195,Add,NONE,0,Add,NONE,0,Add,700003,14,20,29950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,129,21277,HP,26430,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,130,21466,HP,26665,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,131,21655,HP,26900,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,132,21844,HP,27135,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,133,22033,HP,27370,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,134,22223,HP,27605,Add,NONE,0,Add,NONE,0,Add,700003,14,20,30850,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,135,22412,HP,27840,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,136,22601,HP,28075,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,137,22790,HP,28310,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,138,22979,HP,28545,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,139,23168,HP,28780,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,140,23358,HP,29015,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,141,23547,HP,29250,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,142,23736,HP,29485,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,143,23925,HP,29720,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,144,24114,HP,29955,Add,NONE,0,Add,NONE,0,Add,700003,14,20,31900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,145,24303,HP,30190,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,146,24493,HP,30425,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,147,24682,HP,30660,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,148,24871,HP,30895,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,149,25060,HP,31130,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,150,25249,HP,31365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,151,26256,HP,32615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,152,27262,HP,33865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,153,28268,HP,35115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,154,29274,HP,36365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,32900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,155,30281,HP,37615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,156,31287,HP,38865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,157,32293,HP,40115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,158,33299,HP,41365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,159,34306,HP,42615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,160,35312,HP,43865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,161,36318,HP,45115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,162,37324,HP,46365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,163,38331,HP,47615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,164,39337,HP,48865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,33900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,165,40343,HP,50115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,166,41349,HP,51365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,167,42356,HP,52615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,168,43362,HP,53865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,169,44368,HP,55115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,170,45374,HP,56365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,171,46381,HP,57615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,172,47387,HP,58865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,173,48393,HP,60115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,174,49399,HP,61365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,34900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,175,50406,HP,62615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,176,51412,HP,63865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,177,52418,HP,65115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,178,53424,HP,66365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,179,54431,HP,67615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,180,55437,HP,68865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,181,56443,HP,70115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,182,57449,HP,71365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,183,58456,HP,72615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,184,59462,HP,73865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,35900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,185,60468,HP,75115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,186,61474,HP,76365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,187,62481,HP,77615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,188,63487,HP,78865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,189,64493,HP,80115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,190,65499,HP,81365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,191,66506,HP,82615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,192,67512,HP,83865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,193,68518,HP,85115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,194,69524,HP,86365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,36900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,195,70531,HP,87615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,196,71537,HP,88865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,197,72543,HP,90115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,198,73549,HP,91365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,199,74556,HP,92615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,200,75562,HP,93865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,201,77071,HP,95740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,202,78581,HP,97615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,203,80090,HP,99490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,204,81599,HP,101365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,37900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,205,83109,HP,103240,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,206,84618,HP,105115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,207,86127,HP,106990,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,208,87637,HP,108865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,209,89146,HP,110740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,210,90656,HP,112615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,211,92165,HP,114490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,212,93674,HP,116365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,213,95184,HP,118240,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38650,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,214,96693,HP,120115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,215,98202,HP,121990,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,216,99712,HP,123865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,217,101221,HP,125740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38850,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,218,102731,HP,127615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,219,104240,HP,129490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,38950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,220,105749,HP,131365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,221,107259,HP,133240,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39050,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,222,108768,HP,135115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,223,110277,HP,136990,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,224,111787,HP,138865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,225,113296,HP,140740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,226,114806,HP,142615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,227,116315,HP,144490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,228,117824,HP,146365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,229,119334,HP,148240,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39450,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,230,120843,HP,150115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,231,122352,HP,151990,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,232,123862,HP,153865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,233,125371,HP,155740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39650,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,234,126881,HP,157615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,235,128390,HP,159490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,236,129899,HP,161365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,237,131409,HP,163240,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39850,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,238,132918,HP,165115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,239,134427,HP,166990,Add,NONE,0,Add,NONE,0,Add,700003,14,20,39950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,240,135937,HP,168865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,241,137446,HP,170740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40050,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,242,138956,HP,172615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,243,140465,HP,174490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,244,141974,HP,176365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,245,143484,HP,178240,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,246,144993,HP,180115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,247,146502,HP,181990,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,248,148012,HP,183865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,249,149521,HP,185740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40450,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,250,151031,HP,187615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,251,152661,HP,189640,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,252,154291,HP,191665,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,253,155921,HP,193690,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40650,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,254,157551,HP,195715,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,255,159181,HP,197740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,256,160811,HP,199765,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,257,162441,HP,201790,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40850,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,258,164072,HP,203815,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,259,165702,HP,205840,Add,NONE,0,Add,NONE,0,Add,700003,14,20,40950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,260,167332,HP,207865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,261,168962,HP,209890,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41050,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,262,170592,HP,211915,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,263,172222,HP,213940,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,264,173852,HP,215965,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,265,175482,HP,217990,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,266,177113,HP,220015,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,267,178743,HP,222040,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,268,180373,HP,224065,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,269,182003,HP,226090,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41450,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,270,183633,HP,228115,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,271,185263,HP,230140,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,272,186893,HP,232165,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,273,188523,HP,234190,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41650,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,274,190154,HP,236215,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,275,191784,HP,238240,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,276,193414,HP,240265,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,277,195044,HP,242290,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41850,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,278,196674,HP,244315,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,279,198304,HP,246340,Add,NONE,0,Add,NONE,0,Add,700003,14,20,41950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,280,199934,HP,248365,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42000,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,281,201564,HP,250390,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42050,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,282,203195,HP,252415,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42100,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,283,204825,HP,254440,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42150,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,284,206455,HP,256465,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42200,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,285,208085,HP,258490,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42250,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,286,209715,HP,260515,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42300,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,287,211345,HP,262540,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42350,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,288,212975,HP,264565,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42400,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,289,214605,HP,266590,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42450,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,290,216236,HP,268615,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42500,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,291,217866,HP,270640,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42550,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,292,219496,HP,272665,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42600,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,293,221126,HP,274690,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42650,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,294,222756,HP,276715,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42700,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,295,224386,HP,278740,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42750,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,296,226016,HP,280765,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42800,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,297,227646,HP,282790,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42850,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,298,229277,HP,284815,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42900,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,299,230907,HP,286840,Add,NONE,0,Add,NONE,0,Add,700003,14,20,42950,Add,NONE,Caster,8 +10013,Saehrimnir Rune 3,300,232537,HP,288865,Add,NONE,0,Add,NONE,0,Add,700003,14,20,43000,Add,NONE,Caster,8 +20001,Golden leaf Rune,1,4743,HIT,661,Add,ATK,248,Add,NONE,0,Add,700002,16,30,1535,Add,NONE,Caster,12 +20001,Golden leaf Rune,2,5035,HIT,721,Add,ATK,259,Add,NONE,0,Add,700002,16,30,1570,Add,NONE,Caster,12 +20001,Golden leaf Rune,3,5326,HIT,781,Add,ATK,270,Add,NONE,0,Add,700002,16,30,1605,Add,NONE,Caster,12 +20001,Golden leaf Rune,4,5618,HIT,841,Add,ATK,281,Add,NONE,0,Add,700002,16,30,1640,Add,NONE,Caster,12 +20001,Golden leaf Rune,5,5910,HIT,901,Add,ATK,292,Add,NONE,0,Add,700002,16,30,1675,Add,NONE,Caster,12 +20001,Golden leaf Rune,6,6201,HIT,961,Add,ATK,303,Add,NONE,0,Add,700002,16,30,1710,Add,NONE,Caster,12 +20001,Golden leaf Rune,7,6493,HIT,1021,Add,ATK,314,Add,NONE,0,Add,700002,16,30,1745,Add,NONE,Caster,12 +20001,Golden leaf Rune,8,6784,HIT,1081,Add,ATK,325,Add,NONE,0,Add,700002,16,30,1780,Add,NONE,Caster,12 +20001,Golden leaf Rune,9,7076,HIT,1141,Add,ATK,336,Add,NONE,0,Add,700002,16,30,1815,Add,NONE,Caster,12 +20001,Golden leaf Rune,10,7367,HIT,1201,Add,ATK,347,Add,NONE,0,Add,700002,16,30,1850,Add,NONE,Caster,12 +20001,Golden leaf Rune,11,7659,HIT,1261,Add,ATK,358,Add,NONE,0,Add,700002,16,30,1885,Add,NONE,Caster,12 +20001,Golden leaf Rune,12,7950,HIT,1321,Add,ATK,369,Add,NONE,0,Add,700002,16,30,1920,Add,NONE,Caster,12 +20001,Golden leaf Rune,13,8242,HIT,1381,Add,ATK,380,Add,NONE,0,Add,700002,16,30,1955,Add,NONE,Caster,12 +20001,Golden leaf Rune,14,8533,HIT,1441,Add,ATK,391,Add,NONE,0,Add,700002,16,30,1990,Add,NONE,Caster,12 +20001,Golden leaf Rune,15,8825,HIT,1501,Add,ATK,402,Add,NONE,0,Add,700002,16,30,2025,Add,NONE,Caster,12 +20001,Golden leaf Rune,16,9116,HIT,1561,Add,ATK,413,Add,NONE,0,Add,700002,16,30,2060,Add,NONE,Caster,12 +20001,Golden leaf Rune,17,9408,HIT,1621,Add,ATK,424,Add,NONE,0,Add,700002,16,30,2095,Add,NONE,Caster,12 +20001,Golden leaf Rune,18,9699,HIT,1681,Add,ATK,435,Add,NONE,0,Add,700002,16,30,2130,Add,NONE,Caster,12 +20001,Golden leaf Rune,19,9991,HIT,1741,Add,ATK,446,Add,NONE,0,Add,700002,16,30,2165,Add,NONE,Caster,12 +20001,Golden leaf Rune,20,10282,HIT,1801,Add,ATK,457,Add,NONE,0,Add,700002,16,30,2200,Add,NONE,Caster,12 +20001,Golden leaf Rune,21,10574,HIT,1861,Add,ATK,468,Add,NONE,0,Add,700002,16,30,2235,Add,NONE,Caster,12 +20001,Golden leaf Rune,22,10865,HIT,1921,Add,ATK,479,Add,NONE,0,Add,700002,16,30,2270,Add,NONE,Caster,12 +20001,Golden leaf Rune,23,11157,HIT,1981,Add,ATK,490,Add,NONE,0,Add,700002,16,30,2305,Add,NONE,Caster,12 +20001,Golden leaf Rune,24,11449,HIT,2041,Add,ATK,501,Add,NONE,0,Add,700002,16,30,2340,Add,NONE,Caster,12 +20001,Golden leaf Rune,25,11740,HIT,2101,Add,ATK,512,Add,NONE,0,Add,700002,16,30,2375,Add,NONE,Caster,12 +20001,Golden leaf Rune,26,12032,HIT,2161,Add,ATK,523,Add,NONE,0,Add,700002,16,30,2410,Add,NONE,Caster,12 +20001,Golden leaf Rune,27,12323,HIT,2221,Add,ATK,534,Add,NONE,0,Add,700002,16,30,2445,Add,NONE,Caster,12 +20001,Golden leaf Rune,28,12615,HIT,2281,Add,ATK,545,Add,NONE,0,Add,700002,16,30,2480,Add,NONE,Caster,12 +20001,Golden leaf Rune,29,12906,HIT,2341,Add,ATK,556,Add,NONE,0,Add,700002,16,30,2515,Add,NONE,Caster,12 +20001,Golden leaf Rune,30,13198,HIT,2401,Add,ATK,567,Add,NONE,0,Add,700002,16,30,2550,Add,NONE,Caster,12 +20001,Golden leaf Rune,31,13489,HIT,2461,Add,ATK,578,Add,NONE,0,Add,700002,16,30,2585,Add,NONE,Caster,12 +20001,Golden leaf Rune,32,13781,HIT,2521,Add,ATK,589,Add,NONE,0,Add,700002,16,30,2620,Add,NONE,Caster,12 +20001,Golden leaf Rune,33,14072,HIT,2581,Add,ATK,600,Add,NONE,0,Add,700002,16,30,2655,Add,NONE,Caster,12 +20001,Golden leaf Rune,34,14364,HIT,2641,Add,ATK,611,Add,NONE,0,Add,700002,16,30,2690,Add,NONE,Caster,12 +20001,Golden leaf Rune,35,14655,HIT,2701,Add,ATK,622,Add,NONE,0,Add,700002,16,30,2725,Add,NONE,Caster,12 +20001,Golden leaf Rune,36,14947,HIT,2761,Add,ATK,633,Add,NONE,0,Add,700002,16,30,2753,Add,NONE,Caster,12 +20001,Golden leaf Rune,37,15238,HIT,2821,Add,ATK,644,Add,NONE,0,Add,700002,16,30,2781,Add,NONE,Caster,12 +20001,Golden leaf Rune,38,15530,HIT,2881,Add,ATK,655,Add,NONE,0,Add,700002,16,30,2809,Add,NONE,Caster,12 +20001,Golden leaf Rune,39,15821,HIT,2941,Add,ATK,666,Add,NONE,0,Add,700002,16,30,2837,Add,NONE,Caster,12 +20001,Golden leaf Rune,40,16113,HIT,3001,Add,ATK,677,Add,NONE,0,Add,700002,16,30,2865,Add,NONE,Caster,12 +20001,Golden leaf Rune,41,16404,HIT,3061,Add,ATK,688,Add,NONE,0,Add,700002,16,30,2893,Add,NONE,Caster,12 +20001,Golden leaf Rune,42,16696,HIT,3121,Add,ATK,699,Add,NONE,0,Add,700002,16,30,2921,Add,NONE,Caster,12 +20001,Golden leaf Rune,43,16987,HIT,3181,Add,ATK,710,Add,NONE,0,Add,700002,16,30,2949,Add,NONE,Caster,12 +20001,Golden leaf Rune,44,17279,HIT,3241,Add,ATK,721,Add,NONE,0,Add,700002,16,30,2977,Add,NONE,Caster,12 +20001,Golden leaf Rune,45,17571,HIT,3301,Add,ATK,732,Add,NONE,0,Add,700002,16,30,3005,Add,NONE,Caster,12 +20001,Golden leaf Rune,46,17862,HIT,3361,Add,ATK,743,Add,NONE,0,Add,700002,16,30,3033,Add,NONE,Caster,12 +20001,Golden leaf Rune,47,18154,HIT,3421,Add,ATK,754,Add,NONE,0,Add,700002,16,30,3061,Add,NONE,Caster,12 +20001,Golden leaf Rune,48,18445,HIT,3481,Add,ATK,765,Add,NONE,0,Add,700002,16,30,3089,Add,NONE,Caster,12 +20001,Golden leaf Rune,49,18737,HIT,3541,Add,ATK,776,Add,NONE,0,Add,700002,16,30,3117,Add,NONE,Caster,12 +20001,Golden leaf Rune,50,19028,HIT,3601,Add,ATK,787,Add,NONE,0,Add,700002,16,30,3145,Add,NONE,Caster,12 +20001,Golden leaf Rune,51,19470,HIT,3695,Add,ATK,803,Add,NONE,0,Add,700002,16,30,3173,Add,NONE,Caster,12 +20001,Golden leaf Rune,52,19912,HIT,3789,Add,ATK,819,Add,NONE,0,Add,700002,16,30,3201,Add,NONE,Caster,12 +20001,Golden leaf Rune,53,20354,HIT,3883,Add,ATK,835,Add,NONE,0,Add,700002,16,30,3229,Add,NONE,Caster,12 +20001,Golden leaf Rune,54,20795,HIT,3977,Add,ATK,851,Add,NONE,0,Add,700002,16,30,3257,Add,NONE,Caster,12 +20001,Golden leaf Rune,55,21237,HIT,4071,Add,ATK,867,Add,NONE,0,Add,700002,16,30,3285,Add,NONE,Caster,12 +20001,Golden leaf Rune,56,21679,HIT,4165,Add,ATK,883,Add,NONE,0,Add,700002,16,30,3313,Add,NONE,Caster,12 +20001,Golden leaf Rune,57,22121,HIT,4259,Add,ATK,899,Add,NONE,0,Add,700002,16,30,3341,Add,NONE,Caster,12 +20001,Golden leaf Rune,58,22563,HIT,4353,Add,ATK,915,Add,NONE,0,Add,700002,16,30,3369,Add,NONE,Caster,12 +20001,Golden leaf Rune,59,23005,HIT,4447,Add,ATK,931,Add,NONE,0,Add,700002,16,30,3397,Add,NONE,Caster,12 +20001,Golden leaf Rune,60,23446,HIT,4541,Add,ATK,947,Add,NONE,0,Add,700002,16,30,3425,Add,NONE,Caster,12 +20001,Golden leaf Rune,61,23888,HIT,4635,Add,ATK,963,Add,NONE,0,Add,700002,16,30,3453,Add,NONE,Caster,12 +20001,Golden leaf Rune,62,24330,HIT,4729,Add,ATK,979,Add,NONE,0,Add,700002,16,30,3481,Add,NONE,Caster,12 +20001,Golden leaf Rune,63,24772,HIT,4823,Add,ATK,995,Add,NONE,0,Add,700002,16,30,3509,Add,NONE,Caster,12 +20001,Golden leaf Rune,64,25214,HIT,4917,Add,ATK,1011,Add,NONE,0,Add,700002,16,30,3537,Add,NONE,Caster,12 +20001,Golden leaf Rune,65,25656,HIT,5011,Add,ATK,1027,Add,NONE,0,Add,700002,16,30,3565,Add,NONE,Caster,12 +20001,Golden leaf Rune,66,26097,HIT,5105,Add,ATK,1043,Add,NONE,0,Add,700002,16,30,3593,Add,NONE,Caster,12 +20001,Golden leaf Rune,67,26539,HIT,5199,Add,ATK,1059,Add,NONE,0,Add,700002,16,30,3621,Add,NONE,Caster,12 +20001,Golden leaf Rune,68,26981,HIT,5293,Add,ATK,1075,Add,NONE,0,Add,700002,16,30,3649,Add,NONE,Caster,12 +20001,Golden leaf Rune,69,27423,HIT,5387,Add,ATK,1091,Add,NONE,0,Add,700002,16,30,3677,Add,NONE,Caster,12 +20001,Golden leaf Rune,70,27865,HIT,5481,Add,ATK,1107,Add,NONE,0,Add,700002,16,30,3705,Add,NONE,Caster,12 +20001,Golden leaf Rune,71,28307,HIT,5575,Add,ATK,1123,Add,NONE,0,Add,700002,16,30,3733,Add,NONE,Caster,12 +20001,Golden leaf Rune,72,28748,HIT,5669,Add,ATK,1139,Add,NONE,0,Add,700002,16,30,3761,Add,NONE,Caster,12 +20001,Golden leaf Rune,73,29190,HIT,5763,Add,ATK,1155,Add,NONE,0,Add,700002,16,30,3789,Add,NONE,Caster,12 +20001,Golden leaf Rune,74,29632,HIT,5857,Add,ATK,1171,Add,NONE,0,Add,700002,16,30,3817,Add,NONE,Caster,12 +20001,Golden leaf Rune,75,30074,HIT,5951,Add,ATK,1187,Add,NONE,0,Add,700002,16,30,3845,Add,NONE,Caster,12 +20001,Golden leaf Rune,76,30516,HIT,6045,Add,ATK,1203,Add,NONE,0,Add,700002,16,30,3873,Add,NONE,Caster,12 +20001,Golden leaf Rune,77,30958,HIT,6139,Add,ATK,1219,Add,NONE,0,Add,700002,16,30,3901,Add,NONE,Caster,12 +20001,Golden leaf Rune,78,31399,HIT,6233,Add,ATK,1235,Add,NONE,0,Add,700002,16,30,3929,Add,NONE,Caster,12 +20001,Golden leaf Rune,79,31841,HIT,6327,Add,ATK,1251,Add,NONE,0,Add,700002,16,30,3957,Add,NONE,Caster,12 +20001,Golden leaf Rune,80,32283,HIT,6421,Add,ATK,1267,Add,NONE,0,Add,700002,16,30,3985,Add,NONE,Caster,12 +20001,Golden leaf Rune,81,32725,HIT,6515,Add,ATK,1283,Add,NONE,0,Add,700002,16,30,4005,Add,NONE,Caster,12 +20001,Golden leaf Rune,82,33167,HIT,6609,Add,ATK,1299,Add,NONE,0,Add,700002,16,30,4025,Add,NONE,Caster,12 +20001,Golden leaf Rune,83,33609,HIT,6703,Add,ATK,1315,Add,NONE,0,Add,700002,16,30,4045,Add,NONE,Caster,12 +20001,Golden leaf Rune,84,34050,HIT,6797,Add,ATK,1331,Add,NONE,0,Add,700002,16,30,4065,Add,NONE,Caster,12 +20001,Golden leaf Rune,85,34492,HIT,6891,Add,ATK,1347,Add,NONE,0,Add,700002,16,30,4085,Add,NONE,Caster,12 +20001,Golden leaf Rune,86,34934,HIT,6985,Add,ATK,1363,Add,NONE,0,Add,700002,16,30,4105,Add,NONE,Caster,12 +20001,Golden leaf Rune,87,35376,HIT,7079,Add,ATK,1379,Add,NONE,0,Add,700002,16,30,4125,Add,NONE,Caster,12 +20001,Golden leaf Rune,88,35818,HIT,7173,Add,ATK,1395,Add,NONE,0,Add,700002,16,30,4145,Add,NONE,Caster,12 +20001,Golden leaf Rune,89,36260,HIT,7267,Add,ATK,1411,Add,NONE,0,Add,700002,16,30,4165,Add,NONE,Caster,12 +20001,Golden leaf Rune,90,36701,HIT,7361,Add,ATK,1427,Add,NONE,0,Add,700002,16,30,4185,Add,NONE,Caster,12 +20001,Golden leaf Rune,91,37143,HIT,7455,Add,ATK,1443,Add,NONE,0,Add,700002,16,30,4205,Add,NONE,Caster,12 +20001,Golden leaf Rune,92,37585,HIT,7549,Add,ATK,1459,Add,NONE,0,Add,700002,16,30,4225,Add,NONE,Caster,12 +20001,Golden leaf Rune,93,38027,HIT,7643,Add,ATK,1475,Add,NONE,0,Add,700002,16,30,4245,Add,NONE,Caster,12 +20001,Golden leaf Rune,94,38469,HIT,7737,Add,ATK,1491,Add,NONE,0,Add,700002,16,30,4265,Add,NONE,Caster,12 +20001,Golden leaf Rune,95,38911,HIT,7831,Add,ATK,1507,Add,NONE,0,Add,700002,16,30,4285,Add,NONE,Caster,12 +20001,Golden leaf Rune,96,39352,HIT,7925,Add,ATK,1523,Add,NONE,0,Add,700002,16,30,4305,Add,NONE,Caster,12 +20001,Golden leaf Rune,97,39794,HIT,8019,Add,ATK,1539,Add,NONE,0,Add,700002,16,30,4325,Add,NONE,Caster,12 +20001,Golden leaf Rune,98,40236,HIT,8113,Add,ATK,1555,Add,NONE,0,Add,700002,16,30,4345,Add,NONE,Caster,12 +20001,Golden leaf Rune,99,40678,HIT,8207,Add,ATK,1571,Add,NONE,0,Add,700002,16,30,4365,Add,NONE,Caster,12 +20001,Golden leaf Rune,100,41120,HIT,8301,Add,ATK,1587,Add,NONE,0,Add,700002,16,30,4385,Add,NONE,Caster,12 +20001,Golden leaf Rune,101,41743,HIT,8418,Add,ATK,1613,Add,NONE,0,Add,700002,16,30,4405,Add,NONE,Caster,12 +20001,Golden leaf Rune,102,42366,HIT,8535,Add,ATK,1639,Add,NONE,0,Add,700002,16,30,4425,Add,NONE,Caster,12 +20001,Golden leaf Rune,103,42990,HIT,8652,Add,ATK,1665,Add,NONE,0,Add,700002,16,30,4445,Add,NONE,Caster,12 +20001,Golden leaf Rune,104,43613,HIT,8769,Add,ATK,1691,Add,NONE,0,Add,700002,16,30,4465,Add,NONE,Caster,12 +20001,Golden leaf Rune,105,44237,HIT,8886,Add,ATK,1717,Add,NONE,0,Add,700002,16,30,4485,Add,NONE,Caster,12 +20001,Golden leaf Rune,106,44860,HIT,9003,Add,ATK,1743,Add,NONE,0,Add,700002,16,30,4505,Add,NONE,Caster,12 +20001,Golden leaf Rune,107,45484,HIT,9120,Add,ATK,1769,Add,NONE,0,Add,700002,16,30,4525,Add,NONE,Caster,12 +20001,Golden leaf Rune,108,46107,HIT,9237,Add,ATK,1795,Add,NONE,0,Add,700002,16,30,4545,Add,NONE,Caster,12 +20001,Golden leaf Rune,109,46730,HIT,9354,Add,ATK,1821,Add,NONE,0,Add,700002,16,30,4565,Add,NONE,Caster,12 +20001,Golden leaf Rune,110,47354,HIT,9471,Add,ATK,1847,Add,NONE,0,Add,700002,16,30,4585,Add,NONE,Caster,12 +20001,Golden leaf Rune,111,47977,HIT,9588,Add,ATK,1873,Add,NONE,0,Add,700002,16,30,4605,Add,NONE,Caster,12 +20001,Golden leaf Rune,112,48601,HIT,9705,Add,ATK,1899,Add,NONE,0,Add,700002,16,30,4625,Add,NONE,Caster,12 +20001,Golden leaf Rune,113,49224,HIT,9822,Add,ATK,1925,Add,NONE,0,Add,700002,16,30,4645,Add,NONE,Caster,12 +20001,Golden leaf Rune,114,49847,HIT,9939,Add,ATK,1951,Add,NONE,0,Add,700002,16,30,4665,Add,NONE,Caster,12 +20001,Golden leaf Rune,115,50471,HIT,10056,Add,ATK,1977,Add,NONE,0,Add,700002,16,30,4685,Add,NONE,Caster,12 +20001,Golden leaf Rune,116,51094,HIT,10173,Add,ATK,2003,Add,NONE,0,Add,700002,16,30,4705,Add,NONE,Caster,12 +20001,Golden leaf Rune,117,51718,HIT,10290,Add,ATK,2029,Add,NONE,0,Add,700002,16,30,4725,Add,NONE,Caster,12 +20001,Golden leaf Rune,118,52341,HIT,10407,Add,ATK,2055,Add,NONE,0,Add,700002,16,30,4745,Add,NONE,Caster,12 +20001,Golden leaf Rune,119,52965,HIT,10524,Add,ATK,2081,Add,NONE,0,Add,700002,16,30,4765,Add,NONE,Caster,12 +20001,Golden leaf Rune,120,53588,HIT,10641,Add,ATK,2107,Add,NONE,0,Add,700002,16,30,4785,Add,NONE,Caster,12 +20001,Golden leaf Rune,121,54211,HIT,10758,Add,ATK,2133,Add,NONE,0,Add,700002,16,30,4805,Add,NONE,Caster,12 +20001,Golden leaf Rune,122,54835,HIT,10875,Add,ATK,2159,Add,NONE,0,Add,700002,16,30,4825,Add,NONE,Caster,12 +20001,Golden leaf Rune,123,55458,HIT,10992,Add,ATK,2185,Add,NONE,0,Add,700002,16,30,4845,Add,NONE,Caster,12 +20001,Golden leaf Rune,124,56082,HIT,11109,Add,ATK,2211,Add,NONE,0,Add,700002,16,30,4865,Add,NONE,Caster,12 +20001,Golden leaf Rune,125,56705,HIT,11226,Add,ATK,2237,Add,NONE,0,Add,700002,16,30,4885,Add,NONE,Caster,12 +20001,Golden leaf Rune,126,57328,HIT,11343,Add,ATK,2263,Add,NONE,0,Add,700002,16,30,4905,Add,NONE,Caster,12 +20001,Golden leaf Rune,127,57952,HIT,11460,Add,ATK,2289,Add,NONE,0,Add,700002,16,30,4925,Add,NONE,Caster,12 +20001,Golden leaf Rune,128,58575,HIT,11577,Add,ATK,2315,Add,NONE,0,Add,700002,16,30,4945,Add,NONE,Caster,12 +20001,Golden leaf Rune,129,59199,HIT,11694,Add,ATK,2341,Add,NONE,0,Add,700002,16,30,4965,Add,NONE,Caster,12 +20001,Golden leaf Rune,130,59822,HIT,11811,Add,ATK,2367,Add,NONE,0,Add,700002,16,30,4985,Add,NONE,Caster,12 +20001,Golden leaf Rune,131,60446,HIT,11928,Add,ATK,2393,Add,NONE,0,Add,700002,16,30,5005,Add,NONE,Caster,12 +20001,Golden leaf Rune,132,61069,HIT,12045,Add,ATK,2419,Add,NONE,0,Add,700002,16,30,5025,Add,NONE,Caster,12 +20001,Golden leaf Rune,133,61692,HIT,12162,Add,ATK,2445,Add,NONE,0,Add,700002,16,30,5045,Add,NONE,Caster,12 +20001,Golden leaf Rune,134,62316,HIT,12279,Add,ATK,2471,Add,NONE,0,Add,700002,16,30,5065,Add,NONE,Caster,12 +20001,Golden leaf Rune,135,62939,HIT,12396,Add,ATK,2497,Add,NONE,0,Add,700002,16,30,5085,Add,NONE,Caster,12 +20001,Golden leaf Rune,136,63563,HIT,12513,Add,ATK,2523,Add,NONE,0,Add,700002,16,30,5099,Add,NONE,Caster,12 +20001,Golden leaf Rune,137,64186,HIT,12630,Add,ATK,2549,Add,NONE,0,Add,700002,16,30,5113,Add,NONE,Caster,12 +20001,Golden leaf Rune,138,64809,HIT,12747,Add,ATK,2575,Add,NONE,0,Add,700002,16,30,5127,Add,NONE,Caster,12 +20001,Golden leaf Rune,139,65433,HIT,12864,Add,ATK,2601,Add,NONE,0,Add,700002,16,30,5141,Add,NONE,Caster,12 +20001,Golden leaf Rune,140,66056,HIT,12981,Add,ATK,2627,Add,NONE,0,Add,700002,16,30,5155,Add,NONE,Caster,12 +20001,Golden leaf Rune,141,66680,HIT,13098,Add,ATK,2653,Add,NONE,0,Add,700002,16,30,5169,Add,NONE,Caster,12 +20001,Golden leaf Rune,142,67303,HIT,13215,Add,ATK,2679,Add,NONE,0,Add,700002,16,30,5183,Add,NONE,Caster,12 +20001,Golden leaf Rune,143,67927,HIT,13332,Add,ATK,2705,Add,NONE,0,Add,700002,16,30,5197,Add,NONE,Caster,12 +20001,Golden leaf Rune,144,68550,HIT,13449,Add,ATK,2731,Add,NONE,0,Add,700002,16,30,5211,Add,NONE,Caster,12 +20001,Golden leaf Rune,145,69173,HIT,13566,Add,ATK,2757,Add,NONE,0,Add,700002,16,30,5225,Add,NONE,Caster,12 +20001,Golden leaf Rune,146,69797,HIT,13683,Add,ATK,2783,Add,NONE,0,Add,700002,16,30,5239,Add,NONE,Caster,12 +20001,Golden leaf Rune,147,70420,HIT,13800,Add,ATK,2809,Add,NONE,0,Add,700002,16,30,5253,Add,NONE,Caster,12 +20001,Golden leaf Rune,148,71044,HIT,13917,Add,ATK,2835,Add,NONE,0,Add,700002,16,30,5267,Add,NONE,Caster,12 +20001,Golden leaf Rune,149,71667,HIT,14034,Add,ATK,2861,Add,NONE,0,Add,700002,16,30,5281,Add,NONE,Caster,12 +20001,Golden leaf Rune,150,72290,HIT,14151,Add,ATK,2887,Add,NONE,0,Add,700002,16,30,5295,Add,NONE,Caster,12 +20001,Golden leaf Rune,151,73146,HIT,14292,Add,ATK,2927,Add,NONE,0,Add,700002,16,30,5309,Add,NONE,Caster,12 +20001,Golden leaf Rune,152,74002,HIT,14433,Add,ATK,2967,Add,NONE,0,Add,700002,16,30,5323,Add,NONE,Caster,12 +20001,Golden leaf Rune,153,74858,HIT,14574,Add,ATK,3007,Add,NONE,0,Add,700002,16,30,5337,Add,NONE,Caster,12 +20001,Golden leaf Rune,154,75714,HIT,14715,Add,ATK,3047,Add,NONE,0,Add,700002,16,30,5351,Add,NONE,Caster,12 +20001,Golden leaf Rune,155,76570,HIT,14856,Add,ATK,3087,Add,NONE,0,Add,700002,16,30,5365,Add,NONE,Caster,12 +20001,Golden leaf Rune,156,77426,HIT,14997,Add,ATK,3127,Add,NONE,0,Add,700002,16,30,5379,Add,NONE,Caster,12 +20001,Golden leaf Rune,157,78282,HIT,15138,Add,ATK,3167,Add,NONE,0,Add,700002,16,30,5393,Add,NONE,Caster,12 +20001,Golden leaf Rune,158,79138,HIT,15279,Add,ATK,3207,Add,NONE,0,Add,700002,16,30,5407,Add,NONE,Caster,12 +20001,Golden leaf Rune,159,79994,HIT,15420,Add,ATK,3247,Add,NONE,0,Add,700002,16,30,5421,Add,NONE,Caster,12 +20001,Golden leaf Rune,160,80850,HIT,15561,Add,ATK,3287,Add,NONE,0,Add,700002,16,30,5435,Add,NONE,Caster,12 +20001,Golden leaf Rune,161,81706,HIT,15702,Add,ATK,3327,Add,NONE,0,Add,700002,16,30,5449,Add,NONE,Caster,12 +20001,Golden leaf Rune,162,82562,HIT,15843,Add,ATK,3367,Add,NONE,0,Add,700002,16,30,5463,Add,NONE,Caster,12 +20001,Golden leaf Rune,163,83418,HIT,15984,Add,ATK,3407,Add,NONE,0,Add,700002,16,30,5477,Add,NONE,Caster,12 +20001,Golden leaf Rune,164,84274,HIT,16125,Add,ATK,3447,Add,NONE,0,Add,700002,16,30,5491,Add,NONE,Caster,12 +20001,Golden leaf Rune,165,85130,HIT,16266,Add,ATK,3487,Add,NONE,0,Add,700002,16,30,5505,Add,NONE,Caster,12 +20001,Golden leaf Rune,166,85986,HIT,16407,Add,ATK,3527,Add,NONE,0,Add,700002,16,30,5519,Add,NONE,Caster,12 +20001,Golden leaf Rune,167,86841,HIT,16548,Add,ATK,3567,Add,NONE,0,Add,700002,16,30,5533,Add,NONE,Caster,12 +20001,Golden leaf Rune,168,87697,HIT,16689,Add,ATK,3607,Add,NONE,0,Add,700002,16,30,5547,Add,NONE,Caster,12 +20001,Golden leaf Rune,169,88553,HIT,16830,Add,ATK,3647,Add,NONE,0,Add,700002,16,30,5561,Add,NONE,Caster,12 +20001,Golden leaf Rune,170,89409,HIT,16971,Add,ATK,3687,Add,NONE,0,Add,700002,16,30,5575,Add,NONE,Caster,12 +20001,Golden leaf Rune,171,90265,HIT,17112,Add,ATK,3727,Add,NONE,0,Add,700002,16,30,5589,Add,NONE,Caster,12 +20001,Golden leaf Rune,172,91121,HIT,17253,Add,ATK,3767,Add,NONE,0,Add,700002,16,30,5603,Add,NONE,Caster,12 +20001,Golden leaf Rune,173,91977,HIT,17394,Add,ATK,3807,Add,NONE,0,Add,700002,16,30,5617,Add,NONE,Caster,12 +20001,Golden leaf Rune,174,92833,HIT,17535,Add,ATK,3847,Add,NONE,0,Add,700002,16,30,5631,Add,NONE,Caster,12 +20001,Golden leaf Rune,175,93689,HIT,17676,Add,ATK,3887,Add,NONE,0,Add,700002,16,30,5645,Add,NONE,Caster,12 +20001,Golden leaf Rune,176,94545,HIT,17817,Add,ATK,3927,Add,NONE,0,Add,700002,16,30,5659,Add,NONE,Caster,12 +20001,Golden leaf Rune,177,95401,HIT,17958,Add,ATK,3967,Add,NONE,0,Add,700002,16,30,5673,Add,NONE,Caster,12 +20001,Golden leaf Rune,178,96257,HIT,18099,Add,ATK,4007,Add,NONE,0,Add,700002,16,30,5687,Add,NONE,Caster,12 +20001,Golden leaf Rune,179,97113,HIT,18240,Add,ATK,4047,Add,NONE,0,Add,700002,16,30,5701,Add,NONE,Caster,12 +20001,Golden leaf Rune,180,97969,HIT,18381,Add,ATK,4087,Add,NONE,0,Add,700002,16,30,5715,Add,NONE,Caster,12 +20001,Golden leaf Rune,181,98825,HIT,18522,Add,ATK,4127,Add,NONE,0,Add,700002,16,30,5729,Add,NONE,Caster,12 +20001,Golden leaf Rune,182,99681,HIT,18663,Add,ATK,4167,Add,NONE,0,Add,700002,16,30,5743,Add,NONE,Caster,12 +20001,Golden leaf Rune,183,100537,HIT,18804,Add,ATK,4207,Add,NONE,0,Add,700002,16,30,5757,Add,NONE,Caster,12 +20001,Golden leaf Rune,184,101393,HIT,18945,Add,ATK,4247,Add,NONE,0,Add,700002,16,30,5771,Add,NONE,Caster,12 +20001,Golden leaf Rune,185,102248,HIT,19086,Add,ATK,4287,Add,NONE,0,Add,700002,16,30,5785,Add,NONE,Caster,12 +20001,Golden leaf Rune,186,103104,HIT,19227,Add,ATK,4327,Add,NONE,0,Add,700002,16,30,5799,Add,NONE,Caster,12 +20001,Golden leaf Rune,187,103960,HIT,19368,Add,ATK,4367,Add,NONE,0,Add,700002,16,30,5813,Add,NONE,Caster,12 +20001,Golden leaf Rune,188,104816,HIT,19509,Add,ATK,4407,Add,NONE,0,Add,700002,16,30,5827,Add,NONE,Caster,12 +20001,Golden leaf Rune,189,105672,HIT,19650,Add,ATK,4447,Add,NONE,0,Add,700002,16,30,5841,Add,NONE,Caster,12 +20001,Golden leaf Rune,190,106528,HIT,19791,Add,ATK,4487,Add,NONE,0,Add,700002,16,30,5855,Add,NONE,Caster,12 +20001,Golden leaf Rune,191,107384,HIT,19932,Add,ATK,4527,Add,NONE,0,Add,700002,16,30,5869,Add,NONE,Caster,12 +20001,Golden leaf Rune,192,108240,HIT,20073,Add,ATK,4567,Add,NONE,0,Add,700002,16,30,5883,Add,NONE,Caster,12 +20001,Golden leaf Rune,193,109096,HIT,20214,Add,ATK,4607,Add,NONE,0,Add,700002,16,30,5897,Add,NONE,Caster,12 +20001,Golden leaf Rune,194,109952,HIT,20355,Add,ATK,4647,Add,NONE,0,Add,700002,16,30,5911,Add,NONE,Caster,12 +20001,Golden leaf Rune,195,110808,HIT,20496,Add,ATK,4687,Add,NONE,0,Add,700002,16,30,5925,Add,NONE,Caster,12 +20001,Golden leaf Rune,196,111664,HIT,20637,Add,ATK,4727,Add,NONE,0,Add,700002,16,30,5939,Add,NONE,Caster,12 +20001,Golden leaf Rune,197,112520,HIT,20778,Add,ATK,4767,Add,NONE,0,Add,700002,16,30,5953,Add,NONE,Caster,12 +20001,Golden leaf Rune,198,113376,HIT,20919,Add,ATK,4807,Add,NONE,0,Add,700002,16,30,5967,Add,NONE,Caster,12 +20001,Golden leaf Rune,199,114232,HIT,21060,Add,ATK,4847,Add,NONE,0,Add,700002,16,30,5981,Add,NONE,Caster,12 +20001,Golden leaf Rune,200,115088,HIT,21201,Add,ATK,4887,Add,NONE,0,Add,700002,16,30,5995,Add,NONE,Caster,12 +20001,Golden leaf Rune,201,116061,HIT,21350,Add,ATK,4935,Add,NONE,0,Add,700002,16,30,6009,Add,NONE,Caster,12 +20001,Golden leaf Rune,202,117035,HIT,21499,Add,ATK,4983,Add,NONE,0,Add,700002,16,30,6023,Add,NONE,Caster,12 +20001,Golden leaf Rune,203,118009,HIT,21648,Add,ATK,5031,Add,NONE,0,Add,700002,16,30,6037,Add,NONE,Caster,12 +20001,Golden leaf Rune,204,118982,HIT,21797,Add,ATK,5079,Add,NONE,0,Add,700002,16,30,6051,Add,NONE,Caster,12 +20001,Golden leaf Rune,205,119956,HIT,21946,Add,ATK,5127,Add,NONE,0,Add,700002,16,30,6065,Add,NONE,Caster,12 +20001,Golden leaf Rune,206,120930,HIT,22095,Add,ATK,5175,Add,NONE,0,Add,700002,16,30,6079,Add,NONE,Caster,12 +20001,Golden leaf Rune,207,121904,HIT,22244,Add,ATK,5223,Add,NONE,0,Add,700002,16,30,6093,Add,NONE,Caster,12 +20001,Golden leaf Rune,208,122877,HIT,22393,Add,ATK,5271,Add,NONE,0,Add,700002,16,30,6107,Add,NONE,Caster,12 +20001,Golden leaf Rune,209,123851,HIT,22542,Add,ATK,5319,Add,NONE,0,Add,700002,16,30,6121,Add,NONE,Caster,12 +20001,Golden leaf Rune,210,124825,HIT,22691,Add,ATK,5367,Add,NONE,0,Add,700002,16,30,6135,Add,NONE,Caster,12 +20001,Golden leaf Rune,211,125798,HIT,22840,Add,ATK,5415,Add,NONE,0,Add,700002,16,30,6145,Add,NONE,Caster,12 +20001,Golden leaf Rune,212,126772,HIT,22989,Add,ATK,5463,Add,NONE,0,Add,700002,16,30,6155,Add,NONE,Caster,12 +20001,Golden leaf Rune,213,127746,HIT,23138,Add,ATK,5511,Add,NONE,0,Add,700002,16,30,6165,Add,NONE,Caster,12 +20001,Golden leaf Rune,214,128720,HIT,23287,Add,ATK,5559,Add,NONE,0,Add,700002,16,30,6175,Add,NONE,Caster,12 +20001,Golden leaf Rune,215,129693,HIT,23436,Add,ATK,5607,Add,NONE,0,Add,700002,16,30,6185,Add,NONE,Caster,12 +20001,Golden leaf Rune,216,130667,HIT,23585,Add,ATK,5655,Add,NONE,0,Add,700002,16,30,6195,Add,NONE,Caster,12 +20001,Golden leaf Rune,217,131641,HIT,23734,Add,ATK,5703,Add,NONE,0,Add,700002,16,30,6205,Add,NONE,Caster,12 +20001,Golden leaf Rune,218,132614,HIT,23883,Add,ATK,5751,Add,NONE,0,Add,700002,16,30,6215,Add,NONE,Caster,12 +20001,Golden leaf Rune,219,133588,HIT,24032,Add,ATK,5799,Add,NONE,0,Add,700002,16,30,6225,Add,NONE,Caster,12 +20001,Golden leaf Rune,220,134562,HIT,24181,Add,ATK,5847,Add,NONE,0,Add,700002,16,30,6235,Add,NONE,Caster,12 +20001,Golden leaf Rune,221,135535,HIT,24330,Add,ATK,5895,Add,NONE,0,Add,700002,16,30,6245,Add,NONE,Caster,12 +20001,Golden leaf Rune,222,136509,HIT,24479,Add,ATK,5943,Add,NONE,0,Add,700002,16,30,6255,Add,NONE,Caster,12 +20001,Golden leaf Rune,223,137483,HIT,24628,Add,ATK,5991,Add,NONE,0,Add,700002,16,30,6265,Add,NONE,Caster,12 +20001,Golden leaf Rune,224,138457,HIT,24777,Add,ATK,6039,Add,NONE,0,Add,700002,16,30,6275,Add,NONE,Caster,12 +20001,Golden leaf Rune,225,139430,HIT,24926,Add,ATK,6087,Add,NONE,0,Add,700002,16,30,6285,Add,NONE,Caster,12 +20001,Golden leaf Rune,226,140404,HIT,25075,Add,ATK,6135,Add,NONE,0,Add,700002,16,30,6295,Add,NONE,Caster,12 +20001,Golden leaf Rune,227,141378,HIT,25224,Add,ATK,6183,Add,NONE,0,Add,700002,16,30,6305,Add,NONE,Caster,12 +20001,Golden leaf Rune,228,142351,HIT,25373,Add,ATK,6231,Add,NONE,0,Add,700002,16,30,6315,Add,NONE,Caster,12 +20001,Golden leaf Rune,229,143325,HIT,25522,Add,ATK,6279,Add,NONE,0,Add,700002,16,30,6325,Add,NONE,Caster,12 +20001,Golden leaf Rune,230,144299,HIT,25671,Add,ATK,6327,Add,NONE,0,Add,700002,16,30,6335,Add,NONE,Caster,12 +20001,Golden leaf Rune,231,145273,HIT,25820,Add,ATK,6375,Add,NONE,0,Add,700002,16,30,6345,Add,NONE,Caster,12 +20001,Golden leaf Rune,232,146246,HIT,25969,Add,ATK,6423,Add,NONE,0,Add,700002,16,30,6355,Add,NONE,Caster,12 +20001,Golden leaf Rune,233,147220,HIT,26118,Add,ATK,6471,Add,NONE,0,Add,700002,16,30,6365,Add,NONE,Caster,12 +20001,Golden leaf Rune,234,148194,HIT,26267,Add,ATK,6519,Add,NONE,0,Add,700002,16,30,6375,Add,NONE,Caster,12 +20001,Golden leaf Rune,235,149167,HIT,26416,Add,ATK,6567,Add,NONE,0,Add,700002,16,30,6385,Add,NONE,Caster,12 +20001,Golden leaf Rune,236,150141,HIT,26565,Add,ATK,6615,Add,NONE,0,Add,700002,16,30,6395,Add,NONE,Caster,12 +20001,Golden leaf Rune,237,151115,HIT,26714,Add,ATK,6663,Add,NONE,0,Add,700002,16,30,6405,Add,NONE,Caster,12 +20001,Golden leaf Rune,238,152088,HIT,26863,Add,ATK,6711,Add,NONE,0,Add,700002,16,30,6415,Add,NONE,Caster,12 +20001,Golden leaf Rune,239,153062,HIT,27012,Add,ATK,6759,Add,NONE,0,Add,700002,16,30,6425,Add,NONE,Caster,12 +20001,Golden leaf Rune,240,154036,HIT,27161,Add,ATK,6807,Add,NONE,0,Add,700002,16,30,6435,Add,NONE,Caster,12 +20001,Golden leaf Rune,241,155010,HIT,27310,Add,ATK,6855,Add,NONE,0,Add,700002,16,30,6445,Add,NONE,Caster,12 +20001,Golden leaf Rune,242,155983,HIT,27459,Add,ATK,6903,Add,NONE,0,Add,700002,16,30,6455,Add,NONE,Caster,12 +20001,Golden leaf Rune,243,156957,HIT,27608,Add,ATK,6951,Add,NONE,0,Add,700002,16,30,6465,Add,NONE,Caster,12 +20001,Golden leaf Rune,244,157931,HIT,27757,Add,ATK,6999,Add,NONE,0,Add,700002,16,30,6475,Add,NONE,Caster,12 +20001,Golden leaf Rune,245,158904,HIT,27906,Add,ATK,7047,Add,NONE,0,Add,700002,16,30,6485,Add,NONE,Caster,12 +20001,Golden leaf Rune,246,159878,HIT,28055,Add,ATK,7095,Add,NONE,0,Add,700002,16,30,6495,Add,NONE,Caster,12 +20001,Golden leaf Rune,247,160852,HIT,28204,Add,ATK,7143,Add,NONE,0,Add,700002,16,30,6505,Add,NONE,Caster,12 +20001,Golden leaf Rune,248,161826,HIT,28353,Add,ATK,7191,Add,NONE,0,Add,700002,16,30,6515,Add,NONE,Caster,12 +20001,Golden leaf Rune,249,162799,HIT,28502,Add,ATK,7239,Add,NONE,0,Add,700002,16,30,6525,Add,NONE,Caster,12 +20001,Golden leaf Rune,250,163773,HIT,28651,Add,ATK,7287,Add,NONE,0,Add,700002,16,30,6535,Add,NONE,Caster,12 +20001,Golden leaf Rune,251,165053,HIT,28811,Add,ATK,7358,Add,NONE,0,Add,700002,16,30,6545,Add,NONE,Caster,12 +20001,Golden leaf Rune,252,166334,HIT,28971,Add,ATK,7429,Add,NONE,0,Add,700002,16,30,6555,Add,NONE,Caster,12 +20001,Golden leaf Rune,253,167614,HIT,29131,Add,ATK,7500,Add,NONE,0,Add,700002,16,30,6565,Add,NONE,Caster,12 +20001,Golden leaf Rune,254,168895,HIT,29291,Add,ATK,7571,Add,NONE,0,Add,700002,16,30,6575,Add,NONE,Caster,12 +20001,Golden leaf Rune,255,170176,HIT,29451,Add,ATK,7642,Add,NONE,0,Add,700002,16,30,6585,Add,NONE,Caster,12 +20001,Golden leaf Rune,256,171456,HIT,29611,Add,ATK,7713,Add,NONE,0,Add,700002,16,30,6595,Add,NONE,Caster,12 +20001,Golden leaf Rune,257,172737,HIT,29771,Add,ATK,7784,Add,NONE,0,Add,700002,16,30,6605,Add,NONE,Caster,12 +20001,Golden leaf Rune,258,174017,HIT,29931,Add,ATK,7855,Add,NONE,0,Add,700002,16,30,6615,Add,NONE,Caster,12 +20001,Golden leaf Rune,259,175298,HIT,30091,Add,ATK,7926,Add,NONE,0,Add,700002,16,30,6625,Add,NONE,Caster,12 +20001,Golden leaf Rune,260,176578,HIT,30251,Add,ATK,7997,Add,NONE,0,Add,700002,16,30,6635,Add,NONE,Caster,12 +20001,Golden leaf Rune,261,177859,HIT,30411,Add,ATK,8068,Add,NONE,0,Add,700002,16,30,6645,Add,NONE,Caster,12 +20001,Golden leaf Rune,262,179139,HIT,30571,Add,ATK,8139,Add,NONE,0,Add,700002,16,30,6655,Add,NONE,Caster,12 +20001,Golden leaf Rune,263,180420,HIT,30731,Add,ATK,8210,Add,NONE,0,Add,700002,16,30,6665,Add,NONE,Caster,12 +20001,Golden leaf Rune,264,181700,HIT,30891,Add,ATK,8281,Add,NONE,0,Add,700002,16,30,6675,Add,NONE,Caster,12 +20001,Golden leaf Rune,265,182981,HIT,31051,Add,ATK,8352,Add,NONE,0,Add,700002,16,30,6685,Add,NONE,Caster,12 +20001,Golden leaf Rune,266,184261,HIT,31211,Add,ATK,8423,Add,NONE,0,Add,700002,16,30,6695,Add,NONE,Caster,12 +20001,Golden leaf Rune,267,185542,HIT,31371,Add,ATK,8494,Add,NONE,0,Add,700002,16,30,6705,Add,NONE,Caster,12 +20001,Golden leaf Rune,268,186822,HIT,31531,Add,ATK,8565,Add,NONE,0,Add,700002,16,30,6715,Add,NONE,Caster,12 +20001,Golden leaf Rune,269,188103,HIT,31691,Add,ATK,8636,Add,NONE,0,Add,700002,16,30,6725,Add,NONE,Caster,12 +20001,Golden leaf Rune,270,189383,HIT,31851,Add,ATK,8707,Add,NONE,0,Add,700002,16,30,6735,Add,NONE,Caster,12 +20001,Golden leaf Rune,271,190664,HIT,32011,Add,ATK,8778,Add,NONE,0,Add,700002,16,30,6745,Add,NONE,Caster,12 +20001,Golden leaf Rune,272,191944,HIT,32171,Add,ATK,8849,Add,NONE,0,Add,700002,16,30,6755,Add,NONE,Caster,12 +20001,Golden leaf Rune,273,193225,HIT,32331,Add,ATK,8920,Add,NONE,0,Add,700002,16,30,6765,Add,NONE,Caster,12 +20001,Golden leaf Rune,274,194506,HIT,32491,Add,ATK,8991,Add,NONE,0,Add,700002,16,30,6775,Add,NONE,Caster,12 +20001,Golden leaf Rune,275,195786,HIT,32651,Add,ATK,9062,Add,NONE,0,Add,700002,16,30,6785,Add,NONE,Caster,12 +20001,Golden leaf Rune,276,197067,HIT,32811,Add,ATK,9133,Add,NONE,0,Add,700002,16,30,6795,Add,NONE,Caster,12 +20001,Golden leaf Rune,277,198347,HIT,32971,Add,ATK,9204,Add,NONE,0,Add,700002,16,30,6805,Add,NONE,Caster,12 +20001,Golden leaf Rune,278,199628,HIT,33131,Add,ATK,9275,Add,NONE,0,Add,700002,16,30,6815,Add,NONE,Caster,12 +20001,Golden leaf Rune,279,200908,HIT,33291,Add,ATK,9346,Add,NONE,0,Add,700002,16,30,6825,Add,NONE,Caster,12 +20001,Golden leaf Rune,280,202189,HIT,33451,Add,ATK,9417,Add,NONE,0,Add,700002,16,30,6835,Add,NONE,Caster,12 +20001,Golden leaf Rune,281,203469,HIT,33611,Add,ATK,9488,Add,NONE,0,Add,700002,16,30,6845,Add,NONE,Caster,12 +20001,Golden leaf Rune,282,204750,HIT,33771,Add,ATK,9559,Add,NONE,0,Add,700002,16,30,6855,Add,NONE,Caster,12 +20001,Golden leaf Rune,283,206030,HIT,33931,Add,ATK,9630,Add,NONE,0,Add,700002,16,30,6865,Add,NONE,Caster,12 +20001,Golden leaf Rune,284,207311,HIT,34091,Add,ATK,9701,Add,NONE,0,Add,700002,16,30,6875,Add,NONE,Caster,12 +20001,Golden leaf Rune,285,208591,HIT,34251,Add,ATK,9772,Add,NONE,0,Add,700002,16,30,6885,Add,NONE,Caster,12 +20001,Golden leaf Rune,286,209872,HIT,34411,Add,ATK,9843,Add,NONE,0,Add,700002,16,30,6895,Add,NONE,Caster,12 +20001,Golden leaf Rune,287,211152,HIT,34571,Add,ATK,9914,Add,NONE,0,Add,700002,16,30,6905,Add,NONE,Caster,12 +20001,Golden leaf Rune,288,212433,HIT,34731,Add,ATK,9985,Add,NONE,0,Add,700002,16,30,6915,Add,NONE,Caster,12 +20001,Golden leaf Rune,289,213713,HIT,34891,Add,ATK,10056,Add,NONE,0,Add,700002,16,30,6925,Add,NONE,Caster,12 +20001,Golden leaf Rune,290,214994,HIT,35051,Add,ATK,10127,Add,NONE,0,Add,700002,16,30,6935,Add,NONE,Caster,12 +20001,Golden leaf Rune,291,216274,HIT,35211,Add,ATK,10198,Add,NONE,0,Add,700002,16,30,6945,Add,NONE,Caster,12 +20001,Golden leaf Rune,292,217555,HIT,35371,Add,ATK,10269,Add,NONE,0,Add,700002,16,30,6955,Add,NONE,Caster,12 +20001,Golden leaf Rune,293,218835,HIT,35531,Add,ATK,10340,Add,NONE,0,Add,700002,16,30,6965,Add,NONE,Caster,12 +20001,Golden leaf Rune,294,220116,HIT,35691,Add,ATK,10411,Add,NONE,0,Add,700002,16,30,6975,Add,NONE,Caster,12 +20001,Golden leaf Rune,295,221397,HIT,35851,Add,ATK,10482,Add,NONE,0,Add,700002,16,30,6985,Add,NONE,Caster,12 +20001,Golden leaf Rune,296,222677,HIT,36011,Add,ATK,10553,Add,NONE,0,Add,700002,16,30,6995,Add,NONE,Caster,12 +20001,Golden leaf Rune,297,223958,HIT,36171,Add,ATK,10624,Add,NONE,0,Add,700002,16,30,7005,Add,NONE,Caster,12 +20001,Golden leaf Rune,298,225238,HIT,36331,Add,ATK,10695,Add,NONE,0,Add,700002,16,30,7015,Add,NONE,Caster,12 +20001,Golden leaf Rune,299,226519,HIT,36491,Add,ATK,10766,Add,NONE,0,Add,700002,16,30,7025,Add,NONE,Caster,12 +20001,Golden leaf Rune,300,227799,HIT,36651,Add,ATK,10837,Add,NONE,0,Add,700002,16,30,7035,Add,NONE,Caster,12 \ No newline at end of file diff --git a/Lib9c/TableCSV/RuneCostSheet.csv b/Lib9c/TableCSV/RuneCostSheet.csv index 449d31660c5..9e1bbd81348 100644 --- a/Lib9c/TableCSV/RuneCostSheet.csv +++ b/Lib9c/TableCSV/RuneCostSheet.csv @@ -29,7 +29,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 30001,Adventurer's Rune,28,1,1,0,10000 30001,Adventurer's Rune,29,1,1,0,10000 30001,Adventurer's Rune,30,1,1,0,10000 -30001,Adventurer's Rune,31,2,10,1,10000 +30001,Adventurer's Rune,31,2,10,0,10000 30001,Adventurer's Rune,32,2,10,0,10000 30001,Adventurer's Rune,33,2,10,0,10000 30001,Adventurer's Rune,34,2,10,0,10000 @@ -39,7 +39,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 30001,Adventurer's Rune,38,2,10,0,10000 30001,Adventurer's Rune,39,2,10,0,10000 30001,Adventurer's Rune,40,2,10,0,10000 -30001,Adventurer's Rune,41,2,10,1,10000 +30001,Adventurer's Rune,41,2,10,0,10000 30001,Adventurer's Rune,42,2,10,0,10000 30001,Adventurer's Rune,43,2,10,0,10000 30001,Adventurer's Rune,44,2,10,0,10000 @@ -309,7 +309,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10001,Fenrir HP Rune,8,10,2000,0,8000 10001,Fenrir HP Rune,9,10,2000,0,6000 10001,Fenrir HP Rune,10,100,2000,0,5000 -10001,Fenrir HP Rune,11,10,2000,10,8000 +10001,Fenrir HP Rune,11,10,2000,0,8000 10001,Fenrir HP Rune,12,10,2000,0,8000 10001,Fenrir HP Rune,13,10,2000,0,6000 10001,Fenrir HP Rune,14,10,2000,0,10000 @@ -319,7 +319,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10001,Fenrir HP Rune,18,10,2000,0,8000 10001,Fenrir HP Rune,19,10,2000,0,6000 10001,Fenrir HP Rune,20,100,2000,0,5000 -10001,Fenrir HP Rune,21,10,2000,10,8000 +10001,Fenrir HP Rune,21,10,2000,0,8000 10001,Fenrir HP Rune,22,10,2000,0,8000 10001,Fenrir HP Rune,23,10,2000,0,6000 10001,Fenrir HP Rune,24,10,2000,0,10000 @@ -329,7 +329,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10001,Fenrir HP Rune,28,10,2000,0,8000 10001,Fenrir HP Rune,29,10,2000,0,6000 10001,Fenrir HP Rune,30,100,2000,0,5000 -10001,Fenrir HP Rune,31,30,10000,10,8000 +10001,Fenrir HP Rune,31,30,10000,0,8000 10001,Fenrir HP Rune,32,30,10000,0,8000 10001,Fenrir HP Rune,33,30,10000,0,6000 10001,Fenrir HP Rune,34,30,10000,0,10000 @@ -339,7 +339,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10001,Fenrir HP Rune,38,30,10000,0,8000 10001,Fenrir HP Rune,39,30,10000,0,6000 10001,Fenrir HP Rune,40,300,10000,0,5000 -10001,Fenrir HP Rune,41,30,10000,20,8000 +10001,Fenrir HP Rune,41,30,10000,0,8000 10001,Fenrir HP Rune,42,30,10000,0,8000 10001,Fenrir HP Rune,43,30,10000,0,6000 10001,Fenrir HP Rune,44,30,10000,0,10000 @@ -609,7 +609,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10002,Fenrir ATK Rune,8,5,5000,0,8000 10002,Fenrir ATK Rune,9,5,5000,0,6000 10002,Fenrir ATK Rune,10,50,50000,0,5000 -10002,Fenrir ATK Rune,11,5,5000,30,8000 +10002,Fenrir ATK Rune,11,5,5000,0,8000 10002,Fenrir ATK Rune,12,5,5000,0,8000 10002,Fenrir ATK Rune,13,5,5000,0,6000 10002,Fenrir ATK Rune,14,5,5000,0,10000 @@ -619,7 +619,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10002,Fenrir ATK Rune,18,5,5000,0,8000 10002,Fenrir ATK Rune,19,5,5000,0,6000 10002,Fenrir ATK Rune,20,50,50000,0,5000 -10002,Fenrir ATK Rune,21,5,5000,30,8000 +10002,Fenrir ATK Rune,21,5,5000,0,8000 10002,Fenrir ATK Rune,22,5,5000,0,8000 10002,Fenrir ATK Rune,23,5,5000,0,6000 10002,Fenrir ATK Rune,24,5,5000,0,10000 @@ -629,7 +629,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10002,Fenrir ATK Rune,28,5,5000,0,8000 10002,Fenrir ATK Rune,29,5,5000,0,6000 10002,Fenrir ATK Rune,30,50,50000,0,5000 -10002,Fenrir ATK Rune,31,10,20000,30,8000 +10002,Fenrir ATK Rune,31,10,20000,0,8000 10002,Fenrir ATK Rune,32,10,20000,0,8000 10002,Fenrir ATK Rune,33,10,20000,0,6000 10002,Fenrir ATK Rune,34,10,20000,0,10000 @@ -639,7 +639,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10002,Fenrir ATK Rune,38,10,20000,0,8000 10002,Fenrir ATK Rune,39,10,20000,0,6000 10002,Fenrir ATK Rune,40,100,100000,0,5000 -10002,Fenrir ATK Rune,41,10,20000,60,8000 +10002,Fenrir ATK Rune,41,10,20000,0,8000 10002,Fenrir ATK Rune,42,10,20000,0,8000 10002,Fenrir ATK Rune,43,10,20000,0,6000 10002,Fenrir ATK Rune,44,10,20000,0,10000 @@ -900,7 +900,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10002,Fenrir ATK Rune,299,50,500000,0,2000 10002,Fenrir ATK Rune,300,400,2000000,0,1000 10003,Fenrir Bleeding Rune,1,10,400000,0,10000 -10003,Fenrir Bleeding Rune,2,10,400000,10,10000 +10003,Fenrir Bleeding Rune,2,10,400000,0,10000 10003,Fenrir Bleeding Rune,3,10,400000,0,10000 10003,Fenrir Bleeding Rune,4,10,400000,0,10000 10003,Fenrir Bleeding Rune,5,10,400000,0,10000 @@ -909,7 +909,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10003,Fenrir Bleeding Rune,8,10,400000,0,10000 10003,Fenrir Bleeding Rune,9,10,400000,0,10000 10003,Fenrir Bleeding Rune,10,10,2000000,0,10000 -10003,Fenrir Bleeding Rune,11,10,400000,10,10000 +10003,Fenrir Bleeding Rune,11,10,400000,0,10000 10003,Fenrir Bleeding Rune,12,10,400000,0,10000 10003,Fenrir Bleeding Rune,13,10,400000,0,10000 10003,Fenrir Bleeding Rune,14,10,400000,0,10000 @@ -919,7 +919,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10003,Fenrir Bleeding Rune,18,10,400000,0,10000 10003,Fenrir Bleeding Rune,19,10,400000,0,10000 10003,Fenrir Bleeding Rune,20,10,2000000,0,10000 -10003,Fenrir Bleeding Rune,21,10,400000,20,10000 +10003,Fenrir Bleeding Rune,21,10,400000,0,10000 10003,Fenrir Bleeding Rune,22,10,400000,0,10000 10003,Fenrir Bleeding Rune,23,10,400000,0,10000 10003,Fenrir Bleeding Rune,24,10,400000,0,10000 @@ -929,7 +929,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10003,Fenrir Bleeding Rune,28,10,400000,0,10000 10003,Fenrir Bleeding Rune,29,10,400000,0,10000 10003,Fenrir Bleeding Rune,30,10,2000000,0,10000 -10003,Fenrir Bleeding Rune,31,30,600000,30,10000 +10003,Fenrir Bleeding Rune,31,30,600000,0,10000 10003,Fenrir Bleeding Rune,32,30,600000,0,10000 10003,Fenrir Bleeding Rune,33,30,600000,0,10000 10003,Fenrir Bleeding Rune,34,30,600000,0,10000 @@ -939,7 +939,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10003,Fenrir Bleeding Rune,38,30,600000,0,10000 10003,Fenrir Bleeding Rune,39,30,600000,0,10000 10003,Fenrir Bleeding Rune,40,30,3000000,0,10000 -10003,Fenrir Bleeding Rune,41,30,600000,50,10000 +10003,Fenrir Bleeding Rune,41,30,600000,0,10000 10003,Fenrir Bleeding Rune,42,30,600000,0,10000 10003,Fenrir Bleeding Rune,43,30,600000,0,10000 10003,Fenrir Bleeding Rune,44,30,600000,0,10000 @@ -1209,7 +1209,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10011,Saehrimnir HIT Rune,8,10,2000,0,8000 10011,Saehrimnir HIT Rune,9,10,2000,0,6000 10011,Saehrimnir HIT Rune,10,100,2000,0,5000 -10011,Saehrimnir HIT Rune,11,10,2000,10,10000 +10011,Saehrimnir HIT Rune,11,10,2000,0,10000 10011,Saehrimnir HIT Rune,12,10,2000,0,8000 10011,Saehrimnir HIT Rune,13,10,2000,0,6000 10011,Saehrimnir HIT Rune,14,10,2000,0,10000 @@ -1219,7 +1219,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10011,Saehrimnir HIT Rune,18,10,2000,0,8000 10011,Saehrimnir HIT Rune,19,10,2000,0,6000 10011,Saehrimnir HIT Rune,20,100,2000,0,5000 -10011,Saehrimnir HIT Rune,21,10,2000,10,10000 +10011,Saehrimnir HIT Rune,21,10,2000,0,10000 10011,Saehrimnir HIT Rune,22,10,2000,0,8000 10011,Saehrimnir HIT Rune,23,10,2000,0,6000 10011,Saehrimnir HIT Rune,24,10,2000,0,10000 @@ -1229,7 +1229,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10011,Saehrimnir HIT Rune,28,10,2000,0,8000 10011,Saehrimnir HIT Rune,29,10,2000,0,6000 10011,Saehrimnir HIT Rune,30,100,2000,0,5000 -10011,Saehrimnir HIT Rune,31,30,10000,10,10000 +10011,Saehrimnir HIT Rune,31,30,10000,0,10000 10011,Saehrimnir HIT Rune,32,30,10000,0,8000 10011,Saehrimnir HIT Rune,33,30,10000,0,6000 10011,Saehrimnir HIT Rune,34,30,10000,0,10000 @@ -1239,7 +1239,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10011,Saehrimnir HIT Rune,38,30,10000,0,8000 10011,Saehrimnir HIT Rune,39,30,10000,0,6000 10011,Saehrimnir HIT Rune,40,300,10000,0,5000 -10011,Saehrimnir HIT Rune,41,30,10000,20,10000 +10011,Saehrimnir HIT Rune,41,30,10000,0,10000 10011,Saehrimnir HIT Rune,42,30,10000,0,8000 10011,Saehrimnir HIT Rune,43,30,10000,0,6000 10011,Saehrimnir HIT Rune,44,30,10000,0,10000 @@ -1509,7 +1509,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10012,Saehrimnir DEF Rune,8,5,5000,0,8000 10012,Saehrimnir DEF Rune,9,5,5000,0,6000 10012,Saehrimnir DEF Rune,10,50,50000,0,5000 -10012,Saehrimnir DEF Rune,11,5,5000,30,10000 +10012,Saehrimnir DEF Rune,11,5,5000,0,10000 10012,Saehrimnir DEF Rune,12,5,5000,0,8000 10012,Saehrimnir DEF Rune,13,5,5000,0,6000 10012,Saehrimnir DEF Rune,14,5,5000,0,10000 @@ -1519,7 +1519,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10012,Saehrimnir DEF Rune,18,5,5000,0,8000 10012,Saehrimnir DEF Rune,19,5,5000,0,6000 10012,Saehrimnir DEF Rune,20,50,50000,0,5000 -10012,Saehrimnir DEF Rune,21,5,5000,30,10000 +10012,Saehrimnir DEF Rune,21,5,5000,0,10000 10012,Saehrimnir DEF Rune,22,5,5000,0,8000 10012,Saehrimnir DEF Rune,23,5,5000,0,6000 10012,Saehrimnir DEF Rune,24,5,5000,0,10000 @@ -1529,7 +1529,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10012,Saehrimnir DEF Rune,28,5,5000,0,8000 10012,Saehrimnir DEF Rune,29,5,5000,0,6000 10012,Saehrimnir DEF Rune,30,50,50000,0,5000 -10012,Saehrimnir DEF Rune,31,10,20000,30,10000 +10012,Saehrimnir DEF Rune,31,10,20000,0,10000 10012,Saehrimnir DEF Rune,32,10,20000,0,8000 10012,Saehrimnir DEF Rune,33,10,20000,0,6000 10012,Saehrimnir DEF Rune,34,10,20000,0,10000 @@ -1539,7 +1539,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10012,Saehrimnir DEF Rune,38,10,20000,0,8000 10012,Saehrimnir DEF Rune,39,10,20000,0,6000 10012,Saehrimnir DEF Rune,40,100,100000,0,5000 -10012,Saehrimnir DEF Rune,41,10,20000,60,10000 +10012,Saehrimnir DEF Rune,41,10,20000,0,10000 10012,Saehrimnir DEF Rune,42,10,20000,0,8000 10012,Saehrimnir DEF Rune,43,10,20000,0,6000 10012,Saehrimnir DEF Rune,44,10,20000,0,10000 @@ -1800,7 +1800,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10012,Saehrimnir DEF Rune,299,50,500000,0,2000 10012,Saehrimnir DEF Rune,300,400,2000000,0,1000 10013,Saehrimnir Skill Rune,1,10,400000,0,10000 -10013,Saehrimnir Skill Rune,2,10,400000,10,10000 +10013,Saehrimnir Skill Rune,2,10,400000,0,10000 10013,Saehrimnir Skill Rune,3,10,400000,0,10000 10013,Saehrimnir Skill Rune,4,10,400000,0,10000 10013,Saehrimnir Skill Rune,5,10,400000,0,10000 @@ -1809,7 +1809,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10013,Saehrimnir Skill Rune,8,10,400000,0,10000 10013,Saehrimnir Skill Rune,9,10,400000,0,10000 10013,Saehrimnir Skill Rune,10,10,2000000,0,10000 -10013,Saehrimnir Skill Rune,11,10,400000,10,10000 +10013,Saehrimnir Skill Rune,11,10,400000,0,10000 10013,Saehrimnir Skill Rune,12,10,400000,0,10000 10013,Saehrimnir Skill Rune,13,10,400000,0,10000 10013,Saehrimnir Skill Rune,14,10,400000,0,10000 @@ -1819,7 +1819,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10013,Saehrimnir Skill Rune,18,10,400000,0,10000 10013,Saehrimnir Skill Rune,19,10,400000,0,10000 10013,Saehrimnir Skill Rune,20,10,2000000,0,10000 -10013,Saehrimnir Skill Rune,21,10,400000,20,10000 +10013,Saehrimnir Skill Rune,21,10,400000,0,10000 10013,Saehrimnir Skill Rune,22,10,400000,0,10000 10013,Saehrimnir Skill Rune,23,10,400000,0,10000 10013,Saehrimnir Skill Rune,24,10,400000,0,10000 @@ -1829,7 +1829,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10013,Saehrimnir Skill Rune,28,10,400000,0,10000 10013,Saehrimnir Skill Rune,29,10,400000,0,10000 10013,Saehrimnir Skill Rune,30,10,2000000,0,10000 -10013,Saehrimnir Skill Rune,31,30,600000,30,10000 +10013,Saehrimnir Skill Rune,31,30,600000,0,10000 10013,Saehrimnir Skill Rune,32,30,600000,0,10000 10013,Saehrimnir Skill Rune,33,30,600000,0,10000 10013,Saehrimnir Skill Rune,34,30,600000,0,10000 @@ -1839,7 +1839,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10013,Saehrimnir Skill Rune,38,30,600000,0,10000 10013,Saehrimnir Skill Rune,39,30,600000,0,10000 10013,Saehrimnir Skill Rune,40,30,3000000,0,10000 -10013,Saehrimnir Skill Rune,41,30,600000,50,10000 +10013,Saehrimnir Skill Rune,41,30,600000,0,10000 10013,Saehrimnir Skill Rune,42,30,600000,0,10000 10013,Saehrimnir Skill Rune,43,30,600000,0,10000 10013,Saehrimnir Skill Rune,44,30,600000,0,10000 @@ -2100,7 +2100,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 10013,Saehrimnir Skill Rune,299,80,2000000,0,10000 10013,Saehrimnir Skill Rune,300,80,8000000,0,10000 20001,Golden leaf Rune,1,4,200000,0,10000 -20001,Golden leaf Rune,2,2,200000,100,10000 +20001,Golden leaf Rune,2,2,200000,0,10000 20001,Golden leaf Rune,3,2,200000,0,10000 20001,Golden leaf Rune,4,2,200000,0,10000 20001,Golden leaf Rune,5,2,200000,0,10000 @@ -2109,7 +2109,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 20001,Golden leaf Rune,8,2,200000,0,10000 20001,Golden leaf Rune,9,2,200000,0,10000 20001,Golden leaf Rune,10,0,1000000,0,5000 -20001,Golden leaf Rune,11,10,200000,100,10000 +20001,Golden leaf Rune,11,10,200000,0,10000 20001,Golden leaf Rune,12,10,200000,0,10000 20001,Golden leaf Rune,13,10,200000,0,10000 20001,Golden leaf Rune,14,10,200000,0,10000 @@ -2119,7 +2119,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 20001,Golden leaf Rune,18,10,200000,0,10000 20001,Golden leaf Rune,19,10,200000,0,10000 20001,Golden leaf Rune,20,0,1000000,0,5000 -20001,Golden leaf Rune,21,15,200000,100,10000 +20001,Golden leaf Rune,21,15,200000,0,10000 20001,Golden leaf Rune,22,15,200000,0,10000 20001,Golden leaf Rune,23,15,200000,0,10000 20001,Golden leaf Rune,24,15,200000,0,10000 @@ -2129,7 +2129,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 20001,Golden leaf Rune,28,15,200000,0,10000 20001,Golden leaf Rune,29,15,200000,0,10000 20001,Golden leaf Rune,30,0,1000000,0,5000 -20001,Golden leaf Rune,31,20,200000,100,10000 +20001,Golden leaf Rune,31,20,200000,0,10000 20001,Golden leaf Rune,32,20,200000,0,10000 20001,Golden leaf Rune,33,20,200000,0,10000 20001,Golden leaf Rune,34,20,200000,0,10000 @@ -2139,7 +2139,7 @@ id,_name,rune_level,rune_stone_quantity,crystal_quantity,ncg_quantity,level_up_s 20001,Golden leaf Rune,38,20,200000,0,10000 20001,Golden leaf Rune,39,20,200000,0,10000 20001,Golden leaf Rune,40,0,1000000,0,5000 -20001,Golden leaf Rune,41,25,200000,100,10000 +20001,Golden leaf Rune,41,25,200000,0,10000 20001,Golden leaf Rune,42,25,200000,0,10000 20001,Golden leaf Rune,43,25,200000,0,10000 20001,Golden leaf Rune,44,25,200000,0,10000 diff --git a/Lib9c/TableCSV/Skill/SkillBuffSheet.csv b/Lib9c/TableCSV/Skill/SkillBuffSheet.csv index 3eefdcbc0dd..ebb87b6aa20 100644 --- a/Lib9c/TableCSV/Skill/SkillBuffSheet.csv +++ b/Lib9c/TableCSV/Skill/SkillBuffSheet.csv @@ -217,4 +217,5 @@ skill_id,buff_id 230006,204003 230007,104005 230007,204003 -240006,105003 \ No newline at end of file +240006,105003 +210012,202004 \ No newline at end of file diff --git a/Lib9c/TableCSV/Skill/SkillSheet.csv b/Lib9c/TableCSV/Skill/SkillSheet.csv index 3388ff3b360..3e6b9a07484 100644 --- a/Lib9c/TableCSV/Skill/SkillSheet.csv +++ b/Lib9c/TableCSV/Skill/SkillSheet.csv @@ -12,6 +12,7 @@ _100002,일격(전체),Normal,Attack,BlowAttack,Enemies,1,1 // 노멀 속성의 110005,용암 해일,Fire,Attack,AreaAttack,Enemies,5,13 110006,Flame Attack (ATK),Fire,Attack,AreaAttack,Enemies,5,13 110007,Flame Attack (DEF),Fire,Attack,AreaAttack,Enemies,5,13 +110008,Barrage Aura (ATK),Fire,Attack,AreaAttack,Enemies,5,14 120000,물 공격,Water,Attack,NormalAttack,Enemy,1,1 120001,얼음 일격,Water,Attack,BlowAttack,Enemy,1,5 120002,얼음 일격(전체),Water,Attack,BlowAttack,Enemies,1,13 @@ -46,6 +47,7 @@ _210001,공격 강화(전체),Normal,Buff,AttackBuff,Ally,1,1 // 미구현 210009,ATK All Down (DEF),Normal,Debuff,AttackBuff,Enemies,1,14 210010,ATK Down (HP),Normal,Debuff,AttackBuff,Enemy,1,10 210011,Double edged sword,Normal,Buff,AttackBuff,Self,1,10 +210012,ATK Down (Aegis Aura),Normal,Debuff,AttackBuff,Enemy,1,14 220000,방어 강화,Normal,Buff,DefenseBuff,Self,1,25 _220001,방어 강화(전체),Normal,Buff,DefenseBuff,Ally,1,1 // 미구현 220002,방어 약화,Normal,Debuff,DefenseBuff,Enemy,1,10 diff --git a/Lib9c/TableCSV/Skill/StatBuffSheet.csv b/Lib9c/TableCSV/Skill/StatBuffSheet.csv index acc71da9f0f..0d8c4cef1af 100644 --- a/Lib9c/TableCSV/Skill/StatBuffSheet.csv +++ b/Lib9c/TableCSV/Skill/StatBuffSheet.csv @@ -29,6 +29,7 @@ id,group,_name,chance,duration,target_type,stat_type,modify_type,modify_value,is 202001,202000,공격 약화,100,10,Enemy,ATK,Percentage,-25,true 202002,202000,ATK Down (Stat conversion),100,10,Enemy,ATK,Add,0,true 202003,202000,ATK ALL Down (Stat conversion),100,6,Enemies,ATK,Add,0,true +202004,202004,ATK Down (Aegis Aura),100,30,Enemy,ATK,Percentage,0,true 203001,203000,방어 약화,100,10,Enemy,DEF,Percentage,-25,true 203002,203000,DEF Down (Stat conversion),100,10,Enemy,DEF,Add,0,true 203003,203003,Double edged sword (DEF),100,20,Self,DEF,Percentage,-20,false diff --git a/Lib9c/TableCSV/Summon/SummonSheet.csv b/Lib9c/TableCSV/Summon/SummonSheet.csv index ce04ab7dc57..382e834fc42 100644 --- a/Lib9c/TableCSV/Summon/SummonSheet.csv +++ b/Lib9c/TableCSV/Summon/SummonSheet.csv @@ -1,3 +1,3 @@ -groupID,cost_material,cost_material_count,cost_ncg,recipe1ID,recipe1ratio,recipe2ID,recipe2ratio,recipe3ID,recipe3ratio,recipe4ID,recipe4ratio,recipe5ID,recipe5ratio,recipe6ID,recipe6ratio -10001,800201,10,0,171,70,172,29,173,1,,,,,, -10002,600201,20,0,174,6500,175,2940,176,510,177,45,178,5,, \ No newline at end of file +groupID,cost_material,cost_material_count,cost_ncg,recipe1ID,recipe1ratio,recipe2ID,recipe2ratio,recipe3ID,recipe3ratio,recipe4ID,recipe4ratio,recipe5ID,recipe5ratio,recipe6ID,recipe6ratio,recipe7ID,recipe7ratio,recipe8ID,recipe8ratio,recipe9ID,recipe9ratio,recipe10ID,recipe10ratio,recipe11ID,recipe11ratio,recipe12ID,recipe12ratio,recipe13ID,recipe13ratio,recipe14ID,recipe14ratio,recipe15ID,recipe15ratio +10001,800201,10,0,171,70,172,29,173,1,,,,,,,,,,,,,,,,,,,,,,,, +10002,600201,20,0,174,6500,175,2940,176,510,177,45,178,5,179,6500,180,2940,181,510,182,45,183,5,184,6500,185,2940,186,510,187,45,188,5 \ No newline at end of file diff --git a/Lib9c/TableCSV/WorldAndStage/StageDialogSheet.csv b/Lib9c/TableCSV/WorldAndStage/StageDialogSheet.csv index 8fa16427ff5..2dfec17c9e5 100644 --- a/Lib9c/TableCSV/WorldAndStage/StageDialogSheet.csv +++ b/Lib9c/TableCSV/WorldAndStage/StageDialogSheet.csv @@ -8,7 +8,7 @@ id,stage_id,dialog_id 7,13,21 8,13,22 9,13,23 -10,15,14 +10,35,14 11,16,13 12,17,8 13,19,25 diff --git a/Lib9c/TableCSV/WorldAndStage/StageWaveSheet.csv b/Lib9c/TableCSV/WorldAndStage/StageWaveSheet.csv index 51d295b6bd6..272328310f1 100644 --- a/Lib9c/TableCSV/WorldAndStage/StageWaveSheet.csv +++ b/Lib9c/TableCSV/WorldAndStage/StageWaveSheet.csv @@ -38,117 +38,117 @@ stage_id,wave,monster1_id,monster1_level,monster1_count,monster2_id,monster2_lev 13,1,201001,7,1,201002,7,1,,,,,,,0 13,2,204000,7,2,,,,,,,,,,0 13,3,201003,8,1,,,,,,,,,,1 -14,1,201000,8,2,201004,8,1,,,,,,,0 -14,2,204000,8,2,204020,8,1,,,,,,,0 -14,3,204000,8,3,204020,8,1,,,,,,,0 -15,1,201000,9,3,,,,,,,,,,0 -15,2,201001,9,1,201004,9,2,,,,,,,0 -15,3,201000,9,3,201004,9,1,,,,,,,0 -16,1,201000,10,3,201002,10,1,,,,,,,0 -16,2,201002,10,1,201004,10,3,,,,,,,0 -16,3,201003,11,1,,,,,,,,,,1 -17,1,201001,12,2,201004,12,1,,,,,,,0 -17,2,201001,12,1,201004,12,2,,,,,,,0 -17,3,201001,12,1,201004,12,3,,,,,,,0 -18,1,201002,13,2,201004,13,1,,,,,,,0 -18,2,201000,13,2,201002,13,2,,,,,,,0 -18,3,201000,13,2,201002,13,1,201004,13,1,,,,0 -19,1,201002,14,1,201004,14,2,,,,,,,0 -19,2,201001,14,2,201002,14,2,,,,,,,0 -19,3,201001,14,2,201002,14,2,201004,14,1,,,,0 -20,1,201000,15,1,201001,15,1,,,,,,,0 -20,2,204000,15,2,,,,,,,,,,0 -20,3,201007,16,1,,,,,,,,,,1 -21,1,204010,16,2,,,,,,,,,,0 -21,2,204000,16,1,201003,16,1,,,,,,,0 -21,3,201002,16,2,201004,16,1,,,,,,,0 -22,1,201000,18,1,201001,18,1,,,,,,,0 -22,2,201003,18,1,,,,,,,,,,0 -22,3,201003,18,1,,,,,,,,,,0 -23,1,204010,19,3,,,,,,,,,,0 -23,2,201000,19,1,201001,19,1,,,,,,,0 -23,3,201006,20,1,,,,,,,,,,1 -24,1,204010,19,1,201001,19,1,201002,19,1,,,,0 -24,2,201001,19,2,201002,19,1,,,,,,,0 -24,3,201001,19,1,201002,19,2,,,,,,,0 -25,1,204000,20,2,201001,20,1,,,,,,,0 -25,2,201001,20,1,201002,20,2,,,,,,,0 -25,3,204000,20,2,201001,20,1,,,,,,,0 -26,1,204000,21,1,201000,21,1,,,,,,,0 -26,2,201000,21,1,201004,21,1,,,,,,,0 -26,3,201007,22,1,,,,,,,,,,1 -27,1,204000,22,4,,,,,,,,,,0 -27,2,201000,22,3,,,,,,,,,,0 -27,3,201003,22,1,,,,,,,,,,0 -28,1,204000,23,4,,,,,,,,,,0 -28,2,201000,23,2,201002,23,2,,,,,,,0 -28,3,201000,23,1,201002,23,1,204000,23,1,,,,0 -29,1,204000,23,2,201001,23,2,,,,,,,0 -29,2,201001,23,2,201004,23,2,,,,,,,0 -29,3,201001,23,2,201004,23,2,,,,,,,0 -30,1,204000,24,3,,,,,,,,,,0 -30,2,201002,24,2,201003,24,1,,,,,,,0 -30,3,201006,25,1,,,,,,,,,,1 -31,1,204010,25,3,,,,,,,,,,0 -31,2,201003,25,1,,,,,,,,,,0 -31,3,201000,25,2,201003,25,1,,,,,,,0 -32,1,201000,26,1,201002,26,2,,,,,,,0 -32,2,201003,26,1,,,,,,,,,,0 -32,3,204010,26,1,201000,26,1,201004,26,2,,,,0 -33,1,204010,27,3,,,,,,,,,,0 -33,2,201001,27,2,201002,27,1,,,,,,,0 -33,3,201006,28,1,,,,,,,,,,1 -34,1,204010,28,1,201001,28,1,201002,28,1,,,,0 -34,2,201001,28,1,201004,28,2,,,,,,,0 -34,3,201002,28,1,201003,28,1,,,,,,,0 -35,1,204000,29,1,201001,29,1,,,,,,,0 -35,2,201001,29,1,201002,29,1,,,,,,,0 -35,3,201007,29,1,,,,,,,,,,0 -36,1,204000,30,1,201000,30,1,,,,,,,0 -36,2,201000,30,1,201004,30,1,,,,,,,0 -36,3,201008,31,1,,,,,,,,,,1 -37,1,204000,32,2,,,,,,,,,,0 -37,2,201004,32,2,,,,,,,,,,0 -37,3,201000,32,2,201007,32,1,,,,,,,0 -38,1,204000,33,2,,,,,,,,,,0 -38,2,201000,33,1,201003,33,1,,,,,,,0 -38,3,201000,33,1,201002,33,2,204000,33,1,,,,0 -39,1,204000,34,1,201001,34,2,,,,,,,0 -39,2,201001,34,1,201004,34,2,,,,,,,0 -39,3,201006,34,1,,,,,,,,,,0 -40,1,201003,35,1,,,,,,,,,,0 -40,2,201003,35,1,,,,,,,,,,0 -40,3,201000,36,1,201003,36,1,,,,,,,1 -41,1,204010,37,2,,,,,,,,,,0 -41,2,204000,37,2,201000,37,1,,,,,,,0 -41,3,201002,37,2,204000,37,1,204010,37,1,,,,0 -42,1,204010,38,1,204000,38,1,,,,,,,0 -42,2,201000,38,1,201002,38,1,,,,,,,0 -42,3,204010,38,1,201000,38,1,201003,38,1,,,,0 -43,1,204010,39,3,,,,,,,,,,0 -43,2,201001,39,1,201004,39,1,201000,39,1,,,,0 -43,3,201008,40,1,,,,,,,,,,1 -44,1,204010,41,1,201001,41,1,201002,41,1,,,,0 -44,2,201001,41,2,201002,41,1,,,,,,,0 -44,3,201001,41,1,201002,41,1,201000,41,1,,,,0 -45,1,204000,42,2,201001,42,1,,,,,,,0 -45,2,201001,42,2,201004,42,1,,,,,,,0 -45,3,201000,42,1,201006,42,1,,,,,,,0 -46,1,204000,43,3,201000,43,1,,,,,,,0 -46,2,201000,43,2,201004,43,2,,,,,,,0 -46,3,201008,44,1,,,,,,,,,,1 -47,1,204000,44,1,201003,44,1,,,,,,,0 -47,2,201000,44,2,201003,44,1,,,,,,,0 -47,3,201004,44,2,201002,44,1,201007,44,1,,,,0 -48,1,201000,45,2,,,,,,,,,,0 -48,2,201003,45,1,201007,45,1,,,,,,,0 -48,3,201003,45,1,201008,45,1,,,,,,,0 -49,1,201003,46,1,,,,,,,,,,0 -49,2,201008,46,1,,,,,,,,,,0 -49,3,201007,46,2,,,,,,,,,,0 -50,1,201000,47,1,201003,47,1,,,,,,,0 -50,2,201000,47,1,201007,47,1,,,,,,,0 -50,3,201005,48,1,,,,,,,,,,1 +14,1,201000,7,2,201004,7,1,,,,,,,0 +14,2,204000,7,1,204020,7,1,,,,,,,0 +14,3,204000,7,2,204020,7,1,,,,,,,0 +15,1,201000,7,3,,,,,,,,,,0 +15,2,201001,8,1,201004,8,1,,,,,,,0 +15,3,201000,8,1,201004,8,1,,,,,,,0 +16,1,201000,8,1,201002,8,1,,,,,,,0 +16,2,201002,8,1,201004,8,2,,,,,,,0 +16,3,201003,9,1,,,,,,,,,,1 +17,1,201001,9,1,,,,,,,,,,0 +17,2,201001,9,1,201004,9,1,,,,,,,0 +17,3,201001,9,1,201004,9,2,,,,,,,0 +18,1,201002,9,1,201004,9,1,,,,,,,0 +18,2,201000,9,1,201002,9,1,,,,,,,0 +18,3,201000,9,1,201004,9,1,,,,,,,0 +19,1,201002,10,1,201004,10,1,,,,,,,0 +19,2,201001,10,1,201002,10,1,,,,,,,0 +19,3,201001,10,2,201004,10,1,,,,,,,0 +20,1,201000,11,1,201001,11,1,,,,,,,0 +20,2,204000,11,2,,,,,,,,,,0 +20,3,201007,12,1,,,,,,,,,,1 +21,1,204010,12,2,,,,,,,,,,0 +21,2,204000,12,1,201003,12,1,,,,,,,0 +21,3,201002,12,2,201004,12,1,,,,,,,0 +22,1,201000,13,1,201001,13,1,,,,,,,0 +22,2,201003,13,1,,,,,,,,,,0 +22,3,201003,13,1,,,,,,,,,,0 +23,1,204010,14,3,,,,,,,,,,0 +23,2,201000,14,1,201001,14,1,,,,,,,0 +23,3,201006,15,1,,,,,,,,,,1 +24,1,204010,16,1,201001,16,1,201002,16,1,,,,0 +24,2,201001,16,2,201002,16,1,,,,,,,0 +24,3,201001,16,1,201002,16,2,,,,,,,0 +25,1,204000,17,2,201001,17,1,,,,,,,0 +25,2,201001,17,1,201002,17,2,,,,,,,0 +25,3,204000,17,2,201001,17,1,,,,,,,0 +26,1,204000,18,1,201000,18,1,,,,,,,0 +26,2,201000,18,1,201004,18,1,,,,,,,0 +26,3,201007,19,1,,,,,,,,,,1 +27,1,204000,19,4,,,,,,,,,,0 +27,2,201000,19,3,,,,,,,,,,0 +27,3,201003,19,1,,,,,,,,,,0 +28,1,204000,20,4,,,,,,,,,,0 +28,2,201000,20,2,201002,20,2,,,,,,,0 +28,3,201000,20,1,201002,20,1,204000,20,1,,,,0 +29,1,204000,21,2,201001,21,2,,,,,,,0 +29,2,201001,21,2,201004,21,2,,,,,,,0 +29,3,201001,21,2,201004,21,2,,,,,,,0 +30,1,204000,22,3,,,,,,,,,,0 +30,2,201002,22,2,201003,22,1,,,,,,,0 +30,3,201006,23,1,,,,,,,,,,1 +31,1,204010,23,3,,,,,,,,,,0 +31,2,201003,23,1,,,,,,,,,,0 +31,3,201000,23,2,201003,23,1,,,,,,,0 +32,1,201000,24,1,201002,24,2,,,,,,,0 +32,2,201003,24,1,,,,,,,,,,0 +32,3,204010,24,1,201000,24,1,201004,24,2,,,,0 +33,1,204010,25,3,,,,,,,,,,0 +33,2,201001,25,2,201002,25,1,,,,,,,0 +33,3,201006,26,1,,,,,,,,,,1 +34,1,204010,26,1,201001,26,1,201002,26,1,,,,0 +34,2,201001,26,1,201004,26,2,,,,,,,0 +34,3,201002,26,1,201003,26,1,,,,,,,0 +35,1,204000,27,1,201001,27,1,,,,,,,0 +35,2,201001,27,1,201002,27,1,,,,,,,0 +35,3,201007,27,1,,,,,,,,,,0 +36,1,204000,28,1,201000,28,1,,,,,,,0 +36,2,201000,28,1,201004,28,1,,,,,,,0 +36,3,201008,29,1,,,,,,,,,,1 +37,1,204000,29,2,,,,,,,,,,0 +37,2,201004,29,2,,,,,,,,,,0 +37,3,201000,29,2,201007,29,1,,,,,,,0 +38,1,204000,30,2,,,,,,,,,,0 +38,2,201000,30,1,201003,30,1,,,,,,,0 +38,3,201000,30,1,201002,30,2,204000,30,1,,,,0 +39,1,204000,31,1,201001,31,2,,,,,,,0 +39,2,201001,31,1,201004,31,2,,,,,,,0 +39,3,201006,31,1,,,,,,,,,,0 +40,1,201003,32,1,,,,,,,,,,0 +40,2,201003,32,1,,,,,,,,,,0 +40,3,201000,33,1,201003,33,1,,,,,,,1 +41,1,204010,33,2,,,,,,,,,,0 +41,2,204000,33,2,201000,33,1,,,,,,,0 +41,3,201002,33,2,204000,33,1,204010,33,1,,,,0 +42,1,204010,34,1,204000,34,1,,,,,,,0 +42,2,201000,34,1,201002,34,1,,,,,,,0 +42,3,204010,34,1,201000,34,1,201003,34,1,,,,0 +43,1,204010,35,3,,,,,,,,,,0 +43,2,201001,35,1,201004,35,1,201000,35,1,,,,0 +43,3,201008,36,1,,,,,,,,,,1 +44,1,204010,36,1,201001,36,1,201002,36,1,,,,0 +44,2,201001,36,2,201002,36,1,,,,,,,0 +44,3,201001,36,1,201002,36,1,201000,36,1,,,,0 +45,1,204000,37,2,201001,37,1,,,,,,,0 +45,2,201001,37,2,201004,37,1,,,,,,,0 +45,3,201000,37,1,201006,37,1,,,,,,,0 +46,1,204000,38,3,201000,38,1,,,,,,,0 +46,2,201000,38,2,201004,38,2,,,,,,,0 +46,3,201008,39,1,,,,,,,,,,1 +47,1,204000,39,1,201003,39,1,,,,,,,0 +47,2,201000,39,2,201003,39,1,,,,,,,0 +47,3,201004,39,2,201002,39,1,201007,39,1,,,,0 +48,1,201000,40,2,,,,,,,,,,0 +48,2,201003,40,1,201007,40,1,,,,,,,0 +48,3,201003,40,1,201008,40,1,,,,,,,0 +49,1,201003,41,1,,,,,,,,,,0 +49,2,201008,41,1,,,,,,,,,,0 +49,3,201007,41,2,,,,,,,,,,0 +50,1,201000,42,1,201003,42,1,,,,,,,0 +50,2,201000,42,1,201007,42,1,,,,,,,0 +50,3,201005,43,1,,,,,,,,,,1 51,1,204020,48,3,,,,,,,,,,0 51,2,202000,48,4,,,,,,,,,,0 51,3,202000,48,4,,,,,,,,,,0 diff --git a/Lib9c/TableCSV/WorldBoss/WorldBossCharacterSheet.csv b/Lib9c/TableCSV/WorldBoss/WorldBossCharacterSheet.csv index 70f1e577086..3f23c191319 100644 --- a/Lib9c/TableCSV/WorldBoss/WorldBossCharacterSheet.csv +++ b/Lib9c/TableCSV/WorldBoss/WorldBossCharacterSheet.csv @@ -1,10 +1,10 @@ boss_id,wave,turn_limit,enrage_turn,enrage_skillId,elemental_type,level,hp,atk,def,cri,hit,spd -900001,1,150,30,510001,Wind,110,30000,365,97,4,879,1459 +900001,1,150,30,510001,Wind,50,11790,98,31,4,253,482 900001,2,150,30,510002,Wind,190,45000,1161,226,4,3521,3358 900001,3,150,30,510003,Wind,230,200000,2499,358,4,7619,6906 900001,4,150,30,510004,Wind,260,300000,3866,899,4,15012,16683 900001,5,150,30,510005,Wind,300,1659411,11232,2080,4,29542,27665 -900002,1,150,30,510001,Fire,110,30000,365,97,4,879,1459 +900002,1,150,30,510001,Fire,50,11790,98,31,4,253,482 900002,2,150,30,510002,Fire,190,45000,1161,226,4,3521,3358 900002,3,150,30,510003,Fire,230,200000,2499,358,4,7619,4992 900002,4,150,30,510004,Fire,260,300000,3866,899,4,15012,8745 diff --git a/Lib9c/TableCSV/WorldBoss/WorldBossListSheet.csv b/Lib9c/TableCSV/WorldBoss/WorldBossListSheet.csv index 7d0aa40c689..87078dbeea4 100644 --- a/Lib9c/TableCSV/WorldBoss/WorldBossListSheet.csv +++ b/Lib9c/TableCSV/WorldBoss/WorldBossListSheet.csv @@ -18,14 +18,14 @@ id,boss_id,started_block_index,ended_block_index,fee,ticket_price,additional_tic 17,900002,7867601,7918000,1,1,1,40 18,900001,8018801,8119600,1,1,1,40 19,900002,8220401,8341360,1,1,1,40 -20,900001,8462321,8583280,1,1,1,40 -21,900002,8704241,8825200,1,1,1,40 -22,900001,8946161,9067120,1,1,1,40 -23,900002,9188081,9309040,1,1,1,40 -24,900001,9430001,9550960,1,1,1,40 -25,900002,9671921,9792880,1,1,1,40 -26,900001,9913841,10034800,1,1,1,40 -27,900002,10155761,10276720,1,1,1,40 -28,900001,10397681,10518640,1,1,1,40 -29,900002,10639601,10760560,1,1,1,40 -30,900001,10881521,11002480,1,1,1,40 +20,900001,8462321,8607472,1,1,1,40 +21,900002,8752625,8897776,1,1,1,40 +22,900001,9042929,9188080,1,1,1,40 +23,900002,9333233,9478384,1,1,1,40 +24,900001,9623537,9768688,1,1,1,40 +25,900002,9913841,10058992,1,1,1,40 +26,900001,10204145,10349296,1,1,1,40 +27,900002,10494449,10639600,1,1,1,40 +28,900001,10784753,10929904,1,1,1,40 +29,900002,11075057,11220208,1,1,1,40 +30,900001,11365361,11510512,1,1,1,40 \ No newline at end of file diff --git a/Lib9c/TableData/Summon/SummonSheet.cs b/Lib9c/TableData/Summon/SummonSheet.cs index 04bf616d45c..e36ce8b46e5 100644 --- a/Lib9c/TableData/Summon/SummonSheet.cs +++ b/Lib9c/TableData/Summon/SummonSheet.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Linq; using static Nekoyume.TableData.TableExtensions; namespace Nekoyume.TableData.Summon @@ -7,6 +9,7 @@ public class SummonSheet : Sheet { public class Row : SheetRow { + public const int MaxRecipeCount = 15; public override int Key => GroupId; public int GroupId { get; private set; } @@ -14,14 +17,30 @@ public class Row : SheetRow public int CostMaterialCount { get; private set; } public int CostNcg { get; private set; } - public readonly List<(int, int)> Recipes = new List<(int, int)>(); - // For convenience - public int CumulativeRecipe1Ratio { get; private set; } - public int CumulativeRecipe2Ratio { get; private set; } - public int CumulativeRecipe3Ratio { get; private set; } - public int CumulativeRecipe4Ratio { get; private set; } - public int CumulativeRecipe5Ratio { get; private set; } - public int CumulativeRecipe6Ratio { get; private set; } + public readonly List<(int, int)> Recipes = new(); + + public int TotalRatio() + { + return Recipes.Sum(x => x.Item2); + } + + public int CumulativeRatio(int index) + { + if (index is < 1 or > 15) + { + throw new IndexOutOfRangeException( + $"{index} is not valid index. Use between 1 and {MaxRecipeCount}."); + } + + var ratio = 0; + for (var i = 0; i < index; i++) + { + if (i == Recipes.Count) break; + ratio += Recipes[i].Item2; + } + + return ratio; + } public override void Set(IReadOnlyList fields) { @@ -31,48 +50,22 @@ public override void Set(IReadOnlyList fields) CostNcg = ParseInt(fields[3]); // Min. Two recipes are necessary Recipes.Add((ParseInt(fields[4]), ParseInt(fields[5]))); - CumulativeRecipe1Ratio = ParseInt(fields[5]); Recipes.Add((ParseInt(fields[6]), ParseInt(fields[7]))); - CumulativeRecipe2Ratio = CumulativeRecipe1Ratio + ParseInt(fields[7]); - - // Recipe3 ~ 6 are optional - if (TryParseInt(fields[8], out _) && TryParseInt(fields[9], out _)) - { - Recipes.Add((ParseInt(fields[8]), ParseInt(fields[9]))); - CumulativeRecipe3Ratio = CumulativeRecipe2Ratio + ParseInt(fields[9]); - } - else - { - CumulativeRecipe3Ratio = CumulativeRecipe2Ratio; - } - - if (TryParseInt(fields[10], out _) && TryParseInt(fields[11], out _)) - { - Recipes.Add((ParseInt(fields[10]), ParseInt(fields[11]))); - CumulativeRecipe4Ratio = CumulativeRecipe3Ratio + ParseInt(fields[11]); - } - else - { - CumulativeRecipe4Ratio = CumulativeRecipe3Ratio; - } - if (TryParseInt(fields[12], out _) && TryParseInt(fields[13], out _)) - { - Recipes.Add((ParseInt(fields[12]), ParseInt(fields[13]))); - CumulativeRecipe5Ratio = CumulativeRecipe4Ratio + ParseInt(fields[13]); - } - else - { - CumulativeRecipe5Ratio = CumulativeRecipe4Ratio; - } - if (TryParseInt(fields[14], out _) && TryParseInt(fields[15], out _)) - { - Recipes.Add((ParseInt(fields[14]), ParseInt(fields[15]))); - CumulativeRecipe6Ratio = CumulativeRecipe5Ratio + ParseInt(fields[15]); - } - else + // Recipe3 ~ 15 are optional + for (var i = 3; i <= MaxRecipeCount; i++) { - CumulativeRecipe6Ratio = CumulativeRecipe5Ratio; + var idx = 2 * i + 2; + if (fields.Count >= idx + 2 && + TryParseInt(fields[idx], out _) && + TryParseInt(fields[idx + 1], out _)) + { + Recipes.Add((ParseInt(fields[idx]), ParseInt(fields[idx + 1]))); + } + else + { + break; + } } } }