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

Skill updates for world 8 #2454

Merged
merged 21 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 24 additions & 15 deletions .Lib9c.Tests/Action/Scenario/WorldUnlockScenarioTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ namespace Lib9c.Tests.Action.Scenario
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Libplanet.Action.State;
using Libplanet.Crypto;
using Libplanet.Types.Assets;
using Nekoyume;
using Nekoyume.Action;
using Nekoyume.Model;
Expand Down Expand Up @@ -35,12 +35,13 @@ public WorldUnlockScenarioTest()

_avatarAddress = _agentAddress.Derive("avatar");
_rankingMapAddress = _avatarAddress.Derive("ranking_map");
var gameConfigState = new GameConfigState(sheets[nameof(GameConfigSheet)]);
var avatarState = new AvatarState(
_avatarAddress,
_agentAddress,
0,
_tableSheets.GetAvatarSheets(),
new GameConfigState(sheets[nameof(GameConfigSheet)]),
gameConfigState,
_rankingMapAddress
)
{
Expand All @@ -50,11 +51,18 @@ public WorldUnlockScenarioTest()

_weeklyArenaState = new WeeklyArenaState(0);

#pragma warning disable CS0618
// Use of obsolete method Currency.Legacy(): https://github.com/planetarium/lib9c/discussions/1319
var currency = Currency.Legacy("NCG", 2, null);
#pragma warning restore CS0618
var goldCurrencyState = new GoldCurrencyState(currency);
_initialState = new World(new MockWorldState())
.SetLegacyState(Addresses.GoldCurrency, goldCurrencyState.Serialize())
.SetLegacyState(_weeklyArenaState.address, _weeklyArenaState.Serialize())
.SetAgentState(_agentAddress, agentState)
.SetAvatarState(_avatarAddress, avatarState)
.SetLegacyState(_rankingMapAddress, new RankingMapState(_rankingMapAddress).Serialize());
.SetLegacyState(_rankingMapAddress, new RankingMapState(_rankingMapAddress).Serialize())
.SetLegacyState(gameConfigState.address, gameConfigState.Serialize());

foreach (var (key, value) in sheets)
{
Expand Down Expand Up @@ -90,25 +98,27 @@ public void UnlockWorldByHackAndSlashAfterPatchTableWithAddRow(
var doomfist = Doomfist.GetOne(_tableSheets, avatarState.level, ItemSubType.Weapon);
avatarState.inventory.AddItem(doomfist);

var nextState = _initialState.SetAvatarState(_avatarAddress, avatarState);
var hackAndSlash = new HackAndSlash3
var nextState = _initialState
.SetAvatarState(_avatarAddress, avatarState)
.SetLegacyState(
_avatarAddress.Derive("world_ids"),
new Bencodex.Types.List(Enumerable.Range(1, worldIdToClear).Select(i => i.Serialize())));
var hackAndSlash = new HackAndSlash
{
worldId = worldIdToClear,
stageId = stageIdToClear,
avatarAddress = _avatarAddress,
costumes = new List<int>(),
equipments = new List<Guid> { doomfist.NonFungibleId },
foods = new List<Guid>(),
WeeklyArenaAddress = _weeklyArenaState.address,
RankingMapAddress = _rankingMapAddress,
WorldId = worldIdToClear,
StageId = stageIdToClear,
AvatarAddress = _avatarAddress,
Costumes = new List<Guid>(),
Equipments = new List<Guid> { doomfist.NonFungibleId },
Foods = new List<Guid>(),
RuneInfos = new List<RuneSlotInfo>(),
};
nextState = hackAndSlash.Execute(new ActionContext
{
PreviousState = nextState,
Signer = _agentAddress,
RandomSeed = 0,
});
Assert.True(hackAndSlash.Result.IsClear);

avatarState = nextState.GetAvatarState(_avatarAddress);
Assert.True(avatarState.worldInformation.IsStageCleared(stageIdToClear));
Expand Down Expand Up @@ -149,7 +159,6 @@ public void UnlockWorldByHackAndSlashAfterPatchTableWithAddRow(
Signer = _agentAddress,
RandomSeed = 0,
});
Assert.True(hackAndSlash.Result.IsClear);

avatarState = nextState.GetAvatarState(_avatarAddress);
Assert.True(avatarState.worldInformation.IsWorldUnlocked(worldIdToUnlock));
Expand Down
74 changes: 74 additions & 0 deletions .Lib9c.Tests/Model/Skill/Arena/ArenaCombatTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,5 +194,79 @@ public void DispelOnDuration_Affect()
Assert.Equal(2, challenger.Buffs.Count);
Assert.True(battleStatus.SkillInfos.First().Affected);
}

[Fact]
public void DispelOnDuration_Nothing()
{
var arenaSheets = _tableSheets.GetArenaSimulatorSheets();
var myDigest = new ArenaPlayerDigest(_avatar1, _arenaAvatar1);
var enemyDigest = new ArenaPlayerDigest(_avatar2, _arenaAvatar2);
var simulator = new ArenaSimulator(new TestRandom());
var challenger = new ArenaCharacter(
simulator,
myDigest,
arenaSheets,
simulator.HpModifier,
new List<StatModifier>()
);
var enemy = new ArenaCharacter(
simulator,
enemyDigest,
arenaSheets,
simulator.HpModifier,
new List<StatModifier>()
);

// Use Dispel first
var dispel = _tableSheets.ActionBuffSheet.Values.First(bf => bf.Id == ActionBuffId);
challenger.AddBuff(BuffFactory.GetActionBuff(challenger.Stats, dispel));
Assert.Single(challenger.Buffs);

// Use Bleed
var bleed = _tableSheets.ActionBuffSheet.Values.First(bf => bf.Id == 600001);
challenger.AddBuff(BuffFactory.GetActionBuff(challenger.Stats, bleed));
Assert.Equal(2, challenger.Buffs.Count);

// NormalAttack to test. This must not remove debuff by dispel
var attackRow =
_tableSheets.SkillSheet.Values.First(bf => bf.Id == 100000);
var attack = new ArenaNormalAttack(attackRow, 100, 100, 0, StatType.NONE);

// Hit
var battleStatus = attack.Use(
enemy,
challenger,
simulator.Turn,
BuffFactory.GetBuffs(
challenger.Stats,
attack,
_tableSheets.SkillBuffSheet,
_tableSheets.StatBuffSheet,
_tableSheets.SkillActionBuffSheet,
_tableSheets.ActionBuffSheet
)
);
Assert.Equal(2, challenger.Buffs.Count);
Assert.True(battleStatus.SkillInfos.First().Affected);
Assert.Contains(600001, challenger.Buffs.Values.Select(bf => bf.BuffInfo.Id));

// Attack
battleStatus = attack.Use(
challenger,
enemy,
simulator.Turn,
BuffFactory.GetBuffs(
challenger.Stats,
attack,
_tableSheets.SkillBuffSheet,
_tableSheets.StatBuffSheet,
_tableSheets.SkillActionBuffSheet,
_tableSheets.ActionBuffSheet
)
);
Assert.Equal(2, challenger.Buffs.Count);
Assert.True(battleStatus.SkillInfos.First().Affected);
Assert.Contains(600001, challenger.Buffs.Values.Select(bf => bf.BuffInfo.Id));
}
}
}
31 changes: 20 additions & 11 deletions .Lib9c.Tests/Model/Skill/Arena/ArenaShatterStrikeTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
namespace Lib9c.Tests.Model.Skill.Arena
{
using System;
using System.Collections.Generic;
using System.Linq;
using Bencodex.Types;
using Lib9c.Tests.Action;
using Nekoyume.Arena;
using Nekoyume.Model;
Expand Down Expand Up @@ -46,13 +48,19 @@ public ArenaShatterStrikeTest()

[Theory]
// 1bp == 0.01%
[InlineData(10000)]
[InlineData(1000)]
[InlineData(3700)]
[InlineData(100000)]
public void Use(int ratioBp)
[InlineData(2, 1000, false)]
[InlineData(2, 3700, false)]
[InlineData(2, 100_000, true)]
[InlineData(100_000, 100_000, false)]
public void Use(int hpModifier, int ratioBp, bool expectedEnemyDead)
{
var simulator = new ArenaSimulator(new TestRandom());
var gameConfigState =
new GameConfigState((Text)_tableSheets.GameConfigSheet.Serialize());
var simulator = new ArenaSimulator(
new TestRandom(),
hpModifier: hpModifier,
shatterStrikeMaxDamage: gameConfigState.ShatterStrikeMaxDamage
);
var myDigest = new ArenaPlayerDigest(_avatar1, _arenaAvatar1);
var enemyDigest = new ArenaPlayerDigest(_avatar2, _arenaAvatar2);
var arenaSheets = _tableSheets.GetArenaSimulatorSheets();
Expand All @@ -78,13 +86,14 @@ public void Use(int ratioBp)
var used = shatterStrike.Use(challenger, enemy, simulator.Turn, new List<Buff>());
Assert.Single(used.SkillInfos);
Assert.Equal(
(long)(enemy.HP * ratioBp / 10000m) - enemy.DEF + challenger.ArmorPenetration,
Math.Clamp(
enemy.HP * ratioBp / 10000m - enemy.DEF + challenger.ArmorPenetration,
1,
gameConfigState.ShatterStrikeMaxDamage
),
used.SkillInfos.First().Effect
);
if (ratioBp > 10000)
{
Assert.True(enemy.IsDead);
}
Assert.Equal(expectedEnemyDead, enemy.IsDead);
}
}
}
102 changes: 79 additions & 23 deletions .Lib9c.Tests/Model/Skill/CombatTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ namespace Lib9c.Tests.Model.Skill
public class CombatTest
{
private readonly TableSheets _tableSheets;
private readonly AvatarState _avatarState;
private readonly Player _player;
private readonly Enemy _enemy;

Expand All @@ -25,7 +26,7 @@ public CombatTest()
_tableSheets = new TableSheets(csv);

var gameConfigState = new GameConfigState(csv[nameof(GameConfigSheet)]);
var avatarState = new AvatarState(
_avatarState = new AvatarState(
default,
default,
0,
Expand All @@ -40,7 +41,7 @@ public CombatTest()
_tableSheets.EquipmentItemSetEffectSheet);
var simulator = new TestSimulator(
new TestRandom(),
avatarState,
_avatarState,
new List<System.Guid>(),
_tableSheets.GetSimulatorSheets());
_player.Simulator = simulator;
Expand Down Expand Up @@ -138,45 +139,43 @@ public void Bleed()
}

[Theory]
[InlineData(700009, new[] { 600001 })]
[InlineData(700010, new[] { 600001, 704000 })]
public void DispelOnUse(int dispelId, int[] debuffIdList)
[InlineData(700009, 50, 3, new[] { 600001 }, new[] { 600001, 707000 })]
[InlineData(700009, 100, 0, new[] { 600001 }, new[] { 707000 })]
[InlineData(700010, 100, 0, new[] { 600001, 704000 }, new[] { 707000 })]
public void DispelOnUse(int dispelId, int chance, int seed, int[] debuffIdList, int[] expectedResult)
{
var simulator = new TestSimulator(
new TestRandom(seed),
_avatarState,
new List<System.Guid>(),
_tableSheets.GetSimulatorSheets());
_player.Simulator = simulator;
var actionBuffSheet = _tableSheets.ActionBuffSheet;

// Add Debuff
foreach (var debuffId in debuffIdList)
{
var debuff = actionBuffSheet.Values.First(bf => bf.Id == debuffId); // 600001 is bleed
var debuff =
actionBuffSheet.Values.First(bf => bf.Id == debuffId); // 600001 is bleed
_player.AddBuff(BuffFactory.GetActionBuff(_player.Stats, debuff));
}

Assert.Equal(debuffIdList.Length, _player.Buffs.Count());

// Use Dispel
var skillRow = _tableSheets.SkillSheet.Values.First(bf => bf.Id == dispelId);
var dispelRow = _tableSheets.ActionBuffSheet.Values.First(
bf => bf.Id == _tableSheets.SkillActionBuffSheet.OrderedList.First(
abf => abf.SkillId == dispelId)
.BuffIds.First()
);
var dispel = new BuffSkill(skillRow, 0, 100, 0, StatType.NONE);
var actionBuffRow = new ActionBuffSheet.Row();
actionBuffRow.Set(new[] { "707000", "707000", chance.ToString(), "0", "Self", "Dispel", "Normal", "0" });
var dispelRow = _tableSheets.SkillSheet.Values.First(bf => bf.Id == dispelId);
var dispel = new BuffSkill(dispelRow, 0, chance, 0, StatType.NONE);
var battleStatus = dispel.Use(
_player,
0,
BuffFactory.GetBuffs(
_player.Stats,
dispel,
_tableSheets.SkillBuffSheet,
_tableSheets.StatBuffSheet,
_tableSheets.SkillActionBuffSheet,
_tableSheets.ActionBuffSheet
),
new List<Buff>() { new Dispel(actionBuffRow) },
false);
Assert.NotNull(battleStatus);
// Remove Bleed, add Dispel
Assert.Single(_player.Buffs);
Assert.Equal(dispelRow.GroupId, _player.Buffs.First().Value.BuffInfo.GroupId);
Assert.Equal(expectedResult.Length, _player.Buffs.Count);
Assert.Equal(expectedResult, _player.Buffs.Values.Select(bf => bf.BuffInfo.GroupId).ToArray());
}

[Fact]
Expand Down Expand Up @@ -249,6 +248,63 @@ public void DispelOnDuration_Affect()
Assert.True(battleStatus.SkillInfos.First().Affected);
}

[Fact]
public void DispelOnDuration_Nothing()
{
const int actionBuffId = 708000; // Dispel with duration
var actionBuffSheet = _tableSheets.ActionBuffSheet;

// Use Dispel first
var dispel = actionBuffSheet.Values.First(bf => bf.Id == actionBuffId);
_player.AddBuff(BuffFactory.GetActionBuff(_player.Stats, dispel));
Assert.Single(_player.Buffs);

// Add Bleed
var bleed = actionBuffSheet.Values.First(bf => bf.Id == 600001);
_player.AddBuff(BuffFactory.GetActionBuff(_player.Stats, bleed));

// Attack
_enemy.Targets.Add(_player);
var skillRow =
_tableSheets.SkillSheet.Values.First(bf => bf.Id == 100000);
var attack = new NormalAttack(skillRow, 100, 100, default, StatType.NONE);
var battleStatus = attack.Use(
_enemy,
0,
BuffFactory.GetBuffs(
_enemy.Stats,
attack,
_tableSheets.SkillBuffSheet,
_tableSheets.StatBuffSheet,
_tableSheets.SkillActionBuffSheet,
_tableSheets.ActionBuffSheet
),
false);

// keep debuff
Assert.Equal(2, _player.Buffs.Count);
Assert.True(battleStatus.SkillInfos.First().Affected);

// Attack
_player.Targets.Add(_enemy);
battleStatus = attack.Use(
_player,
0,
BuffFactory.GetBuffs(
_player.Stats,
attack,
_tableSheets.SkillBuffSheet,
_tableSheets.StatBuffSheet,
_tableSheets.SkillActionBuffSheet,
_tableSheets.ActionBuffSheet
),
false);

// keep debuff
Assert.Equal(2, _player.Buffs.Count);
Assert.True(battleStatus.SkillInfos.First().Affected);
}

[Theory]
// Buff
[InlineData(SkillType.Buff, true)]
Expand Down
Loading
Loading