Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce AdventureBossSimulator #2611

Merged
merged 11 commits into from
Jun 10, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,8 @@ AdventureBossGameData.ClaimableReward expectedReward
{
// Settings
var state = _initialState;
var gameConfigState = new GameConfigState(Sheets[nameof(GameConfigSheet)]);
state = state.SetLegacyState(gameConfigState.address, gameConfigState.Serialize());
foreach (var (key, value) in Sheets)
{
state = state.SetLegacyState(Addresses.TableSheet.Derive(key), value.Serialize());
Expand Down
12 changes: 8 additions & 4 deletions .Lib9c.Tests/Action/AdventureBoss/ExploreAdventureBossTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,23 +84,24 @@ public static IEnumerable<object[]> GetExecuteMemberData()
// Start from bottom, goes to 5
yield return new object[]
{
0, 5, 5, 10, 5, null, new[] { (600301, 90), (600302, 60), (600303, 0), (600304, 0) },
0, 5, 5, 10, 5, null,
new[] { (600301, 70), (600302, 0), (600303, 10), (600304, 70) },
};
// Start from bottom, goes to 3 because of potion
yield return new object[]
{
0, 5, 3, 3, 0, null, new[] { (600301, 40), (600302, 20), (600303, 0), (600304, 0) },
0, 5, 3, 3, 0, null, new[] { (600301, 30), (600302, 0), (600303, 10), (600304, 20) },
};
// Start from 3, goes to 5 because of locked floor
yield return new object[]
{
2, 5, 5, 5, 2, null, new[] { (600301, 80), (600302, 40), (600303, 0), (600304, 0) },
2, 5, 5, 5, 2, null, new[] { (600301, 90), (600302, 30), (600303, 0), (600304, 0) },
};
// Start from 6, goes to 10
yield return new object[]
{
5, 10, 10, 10, 5, null,
new[] { (600301, 240), (600302, 160), (600303, 0), (600304, 0) },
new[] { (600301, 70), (600302, 330), (600303, 0), (600304, 0) },
};
// Start from 20, cannot enter
yield return new object[]
Expand All @@ -123,6 +124,9 @@ public void Execute(
{
// Settings
var state = _initialState;
var gameConfigState = new GameConfigState(Sheets[nameof(GameConfigSheet)]);
state = state.SetLegacyState(gameConfigState.address, gameConfigState.Serialize());

foreach (var (key, value) in Sheets)
{
state = state.SetLegacyState(Addresses.TableSheet.Derive(key), value.Serialize());
Expand Down
2 changes: 2 additions & 0 deletions .Lib9c.Tests/Action/AdventureBoss/UnlockFloorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ public void Execute(bool useNcg, bool notEnough, int startFloor, int expectedFlo
{
// Settings
var state = _initialState;
var gameConfigState = new GameConfigState(Sheets[nameof(GameConfigSheet)]);
state = state.SetLegacyState(gameConfigState.address, gameConfigState.Serialize());
foreach (var (key, value) in Sheets)
{
state = state.SetLegacyState(Addresses.TableSheet.Derive(key), value.Serialize());
Expand Down
4 changes: 4 additions & 0 deletions .Lib9c.Tests/Lib9c.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,8 @@
<ProjectReference Include="..\Lib9c.DevExtensions\Lib9c.DevExtensions.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="TableData\AdventureBoss\" />
</ItemGroup>

</Project>
156 changes: 156 additions & 0 deletions .Lib9c.Tests/Model/AdventureBoss/AdventureBossSimulatorTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
namespace Lib9c.Tests.Model.AdventureBoss
{
using System;
using System.Collections.Generic;
using System.Linq;
using Lib9c.Tests.Action;
using Libplanet.Action;
using Nekoyume.Battle.AdventureBoss;
using Nekoyume.Data;
using Nekoyume.Model.BattleStatus;
using Nekoyume.Model.BattleStatus.AdventureBoss;
using Nekoyume.Model.EnumType;
using Nekoyume.Model.Item;
using Nekoyume.Model.Stat;
using Nekoyume.Model.State;
using Xunit;
using Xunit.Abstractions;

public class AdventureBossSimulatorTest
{
private readonly ITestOutputHelper _testOutputHelper;
private readonly TableSheets _tableSheets;
private readonly IRandom _random;
private readonly AvatarState _avatarState;

public AdventureBossSimulatorTest(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
_tableSheets = new TableSheets(TableSheetsImporter.ImportSheets());
_random = new TestRandom();
_avatarState = new AvatarState(
default,
default,
0,
_tableSheets.GetAvatarSheets(),
default
);
}

[Fact]
public AdventureBossSimulator Simulate()
{
var adventureBossData = AdventureBossGameData.AdventureBossRewards.First();
var row = _tableSheets.CostumeStatSheet.Values.First(r => r.StatType == StatType.ATK);
var costume =
(Costume)ItemFactory.CreateItem(_tableSheets.ItemSheet[row.CostumeId], _random);
costume.equipped = true;
_avatarState.inventory.AddItem(costume);

var simulator = new AdventureBossSimulator(
adventureBossData.BossId,
adventureBossData.exploreReward.Keys.First(), // 1
_random,
_avatarState,
new List<Guid>(),
new AllRuneState(),
new RuneSlotState(BattleType.Adventure),
_tableSheets.FloorSheet[1],
_tableSheets.FloorWaveSheet[1],
_tableSheets.GetSimulatorSheets(),
_tableSheets.EnemySkillSheet,
_tableSheets.CostumeStatSheet,
AdventureBossSimulator.GetWaveRewards(
_random,
_tableSheets.FloorSheet[1],
_tableSheets.MaterialItemSheet
),
new List<StatModifier>
{
new (StatType.ATK, StatModifier.OperationType.Add, 100),
},
_tableSheets.DeBuffLimitSheet
);

var player = simulator.Player;
Assert.Equal(row.Stat, player.Stats.CostumeStats.ATK);
Assert.Equal(100, player.Stats.CollectionStats.ATK);
Assert.Equal(100 + row.Stat + player.Stats.BaseStats.ATK, player.Stats.ATK);

simulator.Simulate();

Assert.True(simulator.Log.OfType<DropBox>().Any());
var filtered =
simulator.Log
.Select(e => e.GetType())
.Where(type => type != typeof(GetReward) && type != typeof(DropBox));
Assert.Equal(typeof(WaveTurnEnd), filtered.Last());
Assert.Equal(1, simulator.Log.OfType<WaveTurnEnd>().First().TurnNumber);

return simulator;
}

[Theory]
[InlineData(true, 1, 1)]
[InlineData(true, 1, 5)]
[InlineData(true, 1, 3)]
[InlineData(false, 1, 1)]
[InlineData(false, 1, 5)]
[InlineData(false, 1, 3)]
public void AddBreakthrough(bool simulate, int firstFloor, int lastFloor)
{
AdventureBossSimulator simulator;
if (simulate)
{
simulator = Simulate();
}
else
{
var adventureBossData = AdventureBossGameData.AdventureBossRewards.First();
var row = _tableSheets.CostumeStatSheet.Values.First(
r => r.StatType == StatType.ATK);
var costume =
(Costume)ItemFactory.CreateItem(_tableSheets.ItemSheet[row.CostumeId], _random);
costume.equipped = true;
_avatarState.inventory.AddItem(costume);

simulator = new AdventureBossSimulator(
adventureBossData.BossId,
adventureBossData.exploreReward.Keys.First(), // 1
_random,
_avatarState,
new List<Guid>(),
new AllRuneState(),
new RuneSlotState(BattleType.Adventure),
_tableSheets.FloorSheet[1],
_tableSheets.FloorWaveSheet[1],
_tableSheets.GetSimulatorSheets(),
_tableSheets.EnemySkillSheet,
_tableSheets.CostumeStatSheet,
AdventureBossSimulator.GetWaveRewards(
_random,
_tableSheets.FloorSheet[1],
_tableSheets.MaterialItemSheet
),
new List<StatModifier>
{
new (StatType.ATK, StatModifier.OperationType.Add, 100),
},
_tableSheets.DeBuffLimitSheet
);
}

simulator.AddBreakthrough(firstFloor, lastFloor, _tableSheets.FloorWaveSheet);

Assert.Equal(typeof(SpawnPlayer), simulator.Log.events.First().GetType());
if (!simulate)
{
// +2: 1 for last floor, 1 for SpawnPlayer
Assert.Equal(lastFloor - firstFloor + 2, simulator.Log.events.Count);
}

var filtered = simulator.Log.events.OfType<Breakthrough>();
Assert.Equal(lastFloor - firstFloor + 1, filtered.Count());
}
}
}
7 changes: 7 additions & 0 deletions .Lib9c.Tests/TableSheets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Lib9c.Tests
using System.Collections.Generic;
using System.Text;
using Nekoyume.TableData;
using Nekoyume.TableData.AdventureBoss;
using Nekoyume.TableData.Crystal;
using Nekoyume.TableData.Event;
using Nekoyume.TableData.Garages;
Expand Down Expand Up @@ -253,6 +254,12 @@ public StakeActionPointCoefficientSheet StakeActionPointCoefficientSheet

public DeBuffLimitSheet DeBuffLimitSheet { get; set; }

// Adventure Boss
public FloorSheet FloorSheet { get; private set; }

public FloorWaveSheet FloorWaveSheet { get; private set; }
/* Adventure Boss */

public void ItemSheetInitialize()
{
ItemSheet ??= new ItemSheet();
Expand Down
Loading
Loading