Skip to content

Commit

Permalink
Merge pull request #2261 from planetarium/feature/stun
Browse files Browse the repository at this point in the history
Introduce `Stun` : `ActionBuff`
  • Loading branch information
sonohoshi authored Dec 4, 2023
2 parents 1dc61aa + 0d5c718 commit c793c77
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 11 deletions.
148 changes: 148 additions & 0 deletions .Lib9c.Tests/Model/PlayerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Lib9c.Tests.Model
using Nekoyume.Battle;
using Nekoyume.Model;
using Nekoyume.Model.BattleStatus;
using Nekoyume.Model.Buff;
using Nekoyume.Model.Item;
using Nekoyume.Model.Quest;
using Nekoyume.Model.Skill;
Expand Down Expand Up @@ -422,5 +423,152 @@ public void MaxLevelTest()
Assert.Equal(maxLevel, player.Level);
Assert.Equal(requiredExp - 1, player.Exp.Current - expRow.Exp);
}

[Fact]
public void GetStun()
{
var defaultAttack = SkillFactory.GetV1(
_tableSheets.SkillSheet.Values.First(r => r.Id == GameConfig.DefaultAttackId),
100,
100
);

var simulator = new StageSimulator(
_random,
_avatarState,
new List<Guid>(),
null,
new List<Nekoyume.Model.Skill.Skill>(),
1,
1,
_tableSheets.StageSheet[1],
_tableSheets.StageWaveSheet[1],
false,
20,
_tableSheets.GetSimulatorSheets(),
_tableSheets.EnemySkillSheet,
_tableSheets.CostumeStatSheet,
StageSimulator.GetWaveRewards(
_random,
_tableSheets.StageSheet[1],
_tableSheets.MaterialItemSheet)
);
var player = simulator.Player;
var enemy = new Enemy(player, _tableSheets.CharacterSheet.Values.First(), 1);
player.Targets.Add(enemy);
simulator.Characters = new SimplePriorityQueue<CharacterBase, decimal>();
simulator.Characters.Enqueue(enemy, 0);
player.InitAI();
player.OverrideSkill(defaultAttack);

var actionBuffSheet = _tableSheets.ActionBuffSheet;
// force add buff 'Stun'
// 704000 is ActionBuff id of Stun
player.AddBuff(BuffFactory.GetActionBuff(player.Stats, actionBuffSheet[704000]));
var row = actionBuffSheet.Values.First();
var bleed = BuffFactory.GetActionBuff(enemy.Stats, row);
player.AddBuff(bleed);
player.Tick();
player.Tick();
Assert.NotEmpty(simulator.Log);
var log = simulator.Log;
var logCount = log.Count;
var logList = log.ToList();
for (int i = 0; i < logCount; i++)
{
var currLog = logList[i];
if (currLog is Tick)
{
var nextLog = logList[i + 1];

// 'Tick' does not give damage
Assert.Equal(currLog.Character.Targets.First().CurrentHP, nextLog.Character.Targets.First().CurrentHP);
Assert.True(nextLog is TickDamage);
}
else if (currLog is TickDamage)
{
var nextLog = logList[i + 1];
Assert.True(currLog.Character.CurrentHP > nextLog.Character.CurrentHP);
}
}

Assert.True(logList.Count > 0);
Assert.Contains(logList, e => e is Tick);
Assert.Contains(logList, e => e is TickDamage);
Assert.Contains(logList, e => e is RemoveBuffs);
}

[Fact]
public void GiveStun()
{
var simulator = new StageSimulator(
_random,
_avatarState,
new List<Guid>(),
null,
new List<Nekoyume.Model.Skill.Skill>(),
1,
1,
_tableSheets.StageSheet[1],
_tableSheets.StageWaveSheet[1],
false,
20,
_tableSheets.GetSimulatorSheets(),
_tableSheets.EnemySkillSheet,
_tableSheets.CostumeStatSheet,
StageSimulator.GetWaveRewards(
_random,
_tableSheets.StageSheet[1],
_tableSheets.MaterialItemSheet)
);
var skill = SkillFactory.Get(_tableSheets.SkillSheet[700004], 0, 100, 0, StatType.NONE);
skill.CustomField = new SkillCustomField { BuffDuration = 2 };
var player = simulator.Player;
var enemy = new Enemy(player, _tableSheets.CharacterSheet.Values.First(), 1);
player.Targets.Add(enemy);
simulator.Characters = new SimplePriorityQueue<CharacterBase, decimal>();
simulator.Characters.Enqueue(enemy, 0);
player.InitAI();
enemy.InitAI();
player.AddSkill(skill);
player.Tick();
var actionBuffSheet = _tableSheets.ActionBuffSheet;
var row = actionBuffSheet.Values.First();
var bleed = BuffFactory.GetActionBuff(enemy.Stats, row);
enemy.AddBuff(bleed);
enemy.Tick();
enemy.Tick();
enemy.Tick();
Assert.NotEmpty(simulator.Log);
var log = simulator.Log;
var logCount = log.Count;
var logList = log.ToList();
for (int i = 0; i < logCount; i++)
{
var currLog = logList[i];
if (currLog is Tick)
{
var nextLog = logList[i + 1];

// 'Tick' does not give damage
Assert.Equal(currLog.Character.Targets.First().CurrentHP, nextLog.Character.Targets.First().CurrentHP);
Assert.True(nextLog is TickDamage);
}
else if (currLog is TickDamage)
{
var nextLog = logList.ElementAtOrDefault(i + 1);
if (nextLog != null)
{
Assert.True(currLog.Character.CurrentHP > nextLog.Character.CurrentHP);
}
}
}

Assert.True(logList.Count > 0);
Assert.Contains(logList, e => e is Tick);
Assert.Contains(logList, e => e is TickDamage);
Assert.Contains(logList, e => e is RemoveBuffs);
Assert.Contains(logList, e => e is Nekoyume.Model.BattleStatus.NormalAttack);
}
}
}
27 changes: 27 additions & 0 deletions Lib9c/Model/BattleStatus/Arena/ArenaTick.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace Nekoyume.Model.BattleStatus.Arena
{
[Serializable]
public class ArenaTick : ArenaSkill
{
public ArenaTick(ArenaCharacter character) : this(
character,
ArraySegment<ArenaSkillInfo>.Empty,
ArraySegment<ArenaSkillInfo>.Empty)
{
}

public ArenaTick(ArenaCharacter character, IEnumerable<ArenaSkillInfo> skillInfos, IEnumerable<ArenaSkillInfo> buffInfos)
: base(character, skillInfos, buffInfos)
{
}

public override IEnumerator CoExecute(IArena arena)
{
yield return arena.CoTickDamage(Character, SkillInfos);
}
}
}
28 changes: 28 additions & 0 deletions Lib9c/Model/BattleStatus/Tick.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace Nekoyume.Model.BattleStatus
{
[Serializable]
public class Tick : Skill
{
public Tick(CharacterBase character) : this(
0,
character,
ArraySegment<SkillInfo>.Empty,
ArraySegment<SkillInfo>.Empty)
{
}

public Tick(int skillId, CharacterBase character, IEnumerable<SkillInfo> skillInfos, IEnumerable<SkillInfo> buffInfos)
: base(skillId, character, skillInfos, buffInfos)
{
}

public override IEnumerator CoExecute(IStage stage)
{
yield return stage.CoTickDamage(Character, SkillId, SkillInfos);
}
}
}
4 changes: 4 additions & 0 deletions Lib9c/Model/Buff/BuffFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public static ActionBuff GetActionBuff(Stats stat, ActionBuffSheet.Row row)
case ActionBuffType.Bleed:
var power = (int)decimal.Round(stat.ATK * row.ATKPowerRatio);
return new Bleed(row, power);
case ActionBuffType.Stun:
return new Stun(row);
default:
throw new ArgumentOutOfRangeException();
}
Expand All @@ -36,6 +38,8 @@ public static ActionBuff GetCustomActionBuff(SkillCustomField customField, Actio
{
case ActionBuffType.Bleed:
return new Bleed(customField, row);
case ActionBuffType.Stun:
return new Stun(customField, row);
default:
throw new ArgumentOutOfRangeException();
}
Expand Down
40 changes: 40 additions & 0 deletions Lib9c/Model/Buff/Stun.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using Nekoyume.Model.BattleStatus.Arena;
using Nekoyume.Model.Skill;
using Nekoyume.TableData;

namespace Nekoyume.Model.Buff
{
[Serializable]
public class Stun : ActionBuff
{
public Stun(ActionBuffSheet.Row row) : base(row)
{
}

public Stun(SkillCustomField customField, ActionBuffSheet.Row row) : base(customField, row)
{
}

protected Stun(ActionBuff value) : base(value)
{
}

public override object Clone()
{
return new Stun(this);
}

public override BattleStatus.Skill GiveEffect(CharacterBase affectedCharacter, int simulatorWaveTurn, bool copyCharacter = true)
{
// Do not anything
return null;
}

public override ArenaSkill GiveEffectForArena(ArenaCharacter affectedCharacter, int simulatorWaveTurn)
{
// Do not anything
return null;
}
}
}
17 changes: 13 additions & 4 deletions Lib9c/Model/Character/ArenaCharacter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,17 @@ private void Act()

ReduceDurationOfBuffs();
ReduceSkillCooldown();
OnPreSkill();
var usedSkill = UseSkill();
ArenaSkill usedSkill;
if (OnPreSkill())
{
usedSkill = new ArenaTick((ArenaCharacter)Clone());
_simulator.Log.Add(usedSkill);
}
else
{
usedSkill = UseSkill();
}

if (usedSkill != null)
{
OnPostSkill(usedSkill);
Expand Down Expand Up @@ -603,9 +612,9 @@ private void ActV2()
RemoveBuffs();
}

protected virtual void OnPreSkill()
protected virtual bool OnPreSkill()
{

return Buffs.Values.Any(buff => buff is Stun);
}

protected virtual void OnPostSkill(BattleStatus.Arena.ArenaSkill usedSkill)
Expand Down
22 changes: 18 additions & 4 deletions Lib9c/Model/Character/CharacterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,11 @@ public void AddBuff(Buff.Buff buff, bool updateImmediate = true)
var clone = (ActionBuff)action.Clone();
Buffs[action.RowData.GroupId] = clone;
}
else if (buff is Stun stun)
{
var clone = (Stun)stun.Clone();
Buffs[stun.BuffInfo.GroupId] = clone;
}
}

public void RemoveRecentStatBuff()
Expand Down Expand Up @@ -509,8 +514,17 @@ private void Act()
{
ReduceDurationOfBuffs();
ReduceSkillCooldown();
OnPreSkill();
var usedSkill = UseSkill();
BattleStatus.Skill usedSkill;
if (OnPreSkill())
{
usedSkill = new Tick((CharacterBase)Clone());
Simulator.Log.Add(usedSkill);
}
else
{
usedSkill = UseSkill();
}

if (usedSkill != null)
{
OnPostSkill(usedSkill);
Expand Down Expand Up @@ -556,9 +570,9 @@ private void ActV2()
EndTurn();
}

protected virtual void OnPreSkill()
protected virtual bool OnPreSkill()
{

return Buffs.Values.Any(buff => buff is Stun);
}

protected virtual void OnPostSkill(BattleStatus.Skill usedSkill)
Expand Down
1 change: 1 addition & 0 deletions Lib9c/Model/Skill/ActionBuffType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ namespace Nekoyume.Model.Skill
public enum ActionBuffType
{
Bleed,
Stun,
}
}
3 changes: 2 additions & 1 deletion Lib9c/TableCSV/Skill/ActionBuffSheet.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ id,group,_name,chance,duration,target_type,buff_type,elemental_type,atk_power_ra
500001,500001,출혈(0.5),100,10,Enemy,Bleed,Normal,0.5
500002,500001,출혈(0.4),100,10,Enemy,Bleed,Normal,0.4
500003,500001,출혈(0.2),100,10,Enemy,Bleed,Normal,0.2
600001,600001,출혈,100,0,Enemies,Bleed,Normal,1
600001,600001,출혈,100,0,Enemies,Bleed,Normal,1
704000,704000,기절,100,0,Enemy,Stun,Normal,0
3 changes: 2 additions & 1 deletion Lib9c/TableCSV/Skill/SkillActionBuffSheet.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ skill_id,buff_id
500003,500001
500004,500002
500005,500003
600001,600001
600001,600001
700004,704000
3 changes: 2 additions & 1 deletion Lib9c/TableCSV/Skill/SkillSheet.csv
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,5 @@ _250001,속도 증가(전체),Normal,Buff,SpeedBuff,Ally,1,1 // 미구현
600001,출혈,Normal,Debuff,Buff,Enemy,1,15
700001,피해 감소 (고정),Normal,Buff,DamageReductionBuff,Self,1,15
700002,피해 감소 (비율),Normal,Buff,DamageReductionBuff,Self,1,15
700003,치명 데미지 증가,Normal,Buff,CriticalDamageBuff,Self,1,15
700003,치명 데미지 증가,Normal,Buff,CriticalDamageBuff,Self,1,15
700004,기절,Normal,Debuff,Buff,Enemy,1,15

0 comments on commit c793c77

Please sign in to comment.