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 Vampiric : ActionBuff #2274

Merged
merged 14 commits into from
Dec 6, 2023
89 changes: 89 additions & 0 deletions .Lib9c.Tests/Model/PlayerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -570,5 +570,94 @@ public void GiveStun()
Assert.Contains(logList, e => e is RemoveBuffs);
Assert.Contains(logList, e => e is Nekoyume.Model.BattleStatus.NormalAttack);
}

[Theory]
[InlineData(1, 100)]
[InlineData(2, 10)]
[InlineData(1, 1)]
public void Vampiric(int duration, int percent)
{
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 'Vampiric'
// 705000 is ActionBuff id of Vampiric
var vampiric = (Vampiric)BuffFactory.GetCustomActionBuff(
new SkillCustomField { BuffDuration = duration, BuffValue = percent }, actionBuffSheet[705000]);
player.AddBuff(vampiric);
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 Nekoyume.Model.BattleStatus.NormalAttack)
{
var nextLog = logList[i + 1];
if (currLog.Character.ActionBuffs.Any(actionBuff => actionBuff is Vampiric))
{
Assert.True(nextLog is Tick);
}
else
{
Assert.True(nextLog is TickDamage);
}
}
else if (currLog is Tick healSkill)
{
Assert.Equal(vampiric.RowData.Id, healSkill.SkillId);
var healInfo = healSkill.SkillInfos.First();
var prevAttack = logList.Take(i).OfType<Nekoyume.Model.BattleStatus.NormalAttack>()
.Last();
Assert.Equal(
(int)(prevAttack.SkillInfos.First().Effect * vampiric.BasisPoint / 10000m),
healInfo.Effect);
}
}

Assert.True(logList.Count > 0);
Assert.Contains(logList, e => e is Nekoyume.Model.BattleStatus.NormalAttack);
Assert.Contains(logList, e => e is TickDamage);
Assert.Contains(logList, e => e is RemoveBuffs);
Assert.Contains(logList, e => e is Tick);
}
}
}
2 changes: 1 addition & 1 deletion Lib9c/Model/BattleStatus/Arena/ArenaTick.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public ArenaTick(ArenaCharacter character, IEnumerable<ArenaSkillInfo> skillInfo

public override IEnumerator CoExecute(IArena arena)
{
yield return arena.CoTickDamage(Character, SkillInfos);
yield return arena.CoCustomEvent(Character, this);
}
}
}
2 changes: 1 addition & 1 deletion Lib9c/Model/BattleStatus/Tick.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public Tick(int skillId, CharacterBase character, IEnumerable<SkillInfo> skillIn

public override IEnumerator CoExecute(IStage stage)
{
yield return stage.CoTickDamage(Character, SkillId, SkillInfos);
yield return stage.CoCustomEvent(Character, this);
}
}
}
8 changes: 0 additions & 8 deletions Lib9c/Model/Buff/ActionBuff.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,5 @@ protected ActionBuff(ActionBuff value) : base(value)
RowData = value.RowData;
CustomField = value.CustomField;
}

public abstract BattleStatus.Skill GiveEffect(
CharacterBase affectedCharacter,
int simulatorWaveTurn, bool copyCharacter = true);

public abstract BattleStatus.Arena.ArenaSkill GiveEffectForArena(
ArenaCharacter affectedCharacter,
int simulatorWaveTurn);
}
}
4 changes: 2 additions & 2 deletions Lib9c/Model/Buff/Bleed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public override object Clone()
return new Bleed(this);
}

public override BattleStatus.Skill GiveEffect(CharacterBase affectedCharacter,
public BattleStatus.Skill GiveEffect(CharacterBase affectedCharacter,
int simulatorWaveTurn, bool copyCharacter = true)
{
var clone = copyCharacter ? (CharacterBase) affectedCharacter.Clone() : null;
Expand All @@ -53,7 +53,7 @@ public override BattleStatus.Skill GiveEffect(CharacterBase affectedCharacter,
null);
}

public override ArenaSkill GiveEffectForArena(
public ArenaSkill GiveEffectForArena(
ArenaCharacter affectedCharacter,
int simulatorWaveTurn)
{
Expand Down
4 changes: 4 additions & 0 deletions Lib9c/Model/Buff/BuffFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public static ActionBuff GetActionBuff(Stats stat, ActionBuffSheet.Row row)
return new Bleed(row, power);
case ActionBuffType.Stun:
return new Stun(row);
case ActionBuffType.Vampiric:
return new Vampiric(row, 0);
default:
throw new ArgumentOutOfRangeException();
}
Expand All @@ -40,6 +42,8 @@ public static ActionBuff GetCustomActionBuff(SkillCustomField customField, Actio
return new Bleed(customField, row);
case ActionBuffType.Stun:
return new Stun(customField, row);
case ActionBuffType.Vampiric:
return new Vampiric(customField, row);
default:
throw new ArgumentOutOfRangeException();
}
Expand Down
12 changes: 0 additions & 12 deletions Lib9c/Model/Buff/Stun.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,5 @@ 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;
}
}
}
81 changes: 81 additions & 0 deletions Lib9c/Model/Buff/Vampiric.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using Nekoyume.Model.BattleStatus.Arena;
using Nekoyume.Model.Skill;
using Nekoyume.TableData;

namespace Nekoyume.Model.Buff
{
[Serializable]
public class Vampiric : ActionBuff
{
public int BasisPoint { get; }

public Vampiric(ActionBuffSheet.Row row, int basisPoint) : base(row)
{
BasisPoint = basisPoint;
}

public Vampiric(SkillCustomField customField, ActionBuffSheet.Row row) : base(customField, row)
{
BasisPoint = customField.BuffValue;
}

protected Vampiric(Vampiric value) : base(value)
{
BasisPoint = value.BasisPoint;
}

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

public BattleStatus.Skill GiveEffect(CharacterBase affectedCharacter, BattleStatus.Skill.SkillInfo skillInfo, int simulatorWaveTurn, bool copyCharacter = true)
{
var target = copyCharacter ? (CharacterBase) affectedCharacter.Clone() : null;
var effect = (int)(skillInfo.Effect * BasisPoint / 10000m);
affectedCharacter.Heal(effect);
// Copy new Character with healed.
var infos = new List<BattleStatus.Skill.SkillInfo>
{
new(affectedCharacter.Id,
affectedCharacter.IsDead,
affectedCharacter.Thorn,
effect,
false,
SkillCategory.Heal,
simulatorWaveTurn,
RowData.ElementalType,
RowData.TargetType,
target: target)
};
return new BattleStatus.Tick(RowData.Id,
target,
infos,
ArraySegment<BattleStatus.Skill.SkillInfo>.Empty);
}

public ArenaSkill GiveEffectForArena(ArenaCharacter affectedCharacter, ArenaSkill.ArenaSkillInfo skillInfo, int simulatorWaveTurn)
{
var clone = (ArenaCharacter)affectedCharacter.Clone();
var effect = (int)(skillInfo.Effect * BasisPoint / 10000m);
affectedCharacter.Heal(effect);
// Copy new Character with healed.
var infos = new List<ArenaSkill.ArenaSkillInfo>
{
new(affectedCharacter,
effect,
false,
SkillCategory.Heal,
simulatorWaveTurn,
RowData.ElementalType,
RowData.TargetType)
};
return new ArenaTick(
clone,
infos,
null);
}
}
}
34 changes: 25 additions & 9 deletions Lib9c/Model/Character/ArenaCharacter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,28 @@ protected virtual bool OnPreSkill()

protected virtual void OnPostSkill(BattleStatus.Arena.ArenaSkill usedSkill)
{
var attackSkills = usedSkill.SkillInfos
.Where(skillInfo => skillInfo.SkillCategory
is SkillCategory.NormalAttack
or SkillCategory.BlowAttack
or SkillCategory.DoubleAttack
or SkillCategory.AreaAttack
or SkillCategory.BuffRemovalAttack)
.ToList();
if (Buffs.Values.OfType<Vampiric>().OrderBy(x => x.BuffInfo.Id) is
{ } vampirics)
{
foreach (var vampiric in vampirics)
{
foreach (var effect in attackSkills
.Select(skillInfo =>
vampiric.GiveEffectForArena(this, skillInfo, _simulator.Turn)))
{
_simulator.Log.Add(effect);
}
}
}

var bleeds = Buffs.Values.OfType<Bleed>().OrderBy(x => x.BuffInfo.Id);
foreach (var bleed in bleeds)
{
Expand All @@ -627,15 +649,9 @@ protected virtual void OnPostSkill(BattleStatus.Arena.ArenaSkill usedSkill)
}

// Apply thorn damage if target has thorn
foreach (var skillInfo in usedSkill.SkillInfos)
{
var isAttackSkill =
skillInfo.SkillCategory == SkillCategory.NormalAttack ||
skillInfo.SkillCategory == SkillCategory.BlowAttack ||
skillInfo.SkillCategory == SkillCategory.DoubleAttack ||
skillInfo.SkillCategory == SkillCategory.AreaAttack ||
skillInfo.SkillCategory == SkillCategory.BuffRemovalAttack;
if (isAttackSkill && skillInfo.Target.Thorn > 0)
foreach (var skillInfo in attackSkills)
{
if (skillInfo.Target.Thorn > 0)
{
var effect = GiveThornDamage(skillInfo.Target.Thorn);
_simulator.Log.Add(effect);
Expand Down
35 changes: 26 additions & 9 deletions Lib9c/Model/Character/CharacterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,31 @@ protected virtual bool OnPreSkill()

protected virtual void OnPostSkill(BattleStatus.Skill usedSkill)
{
var log = Simulator.LogEvent;
var attackSkills = usedSkill.SkillInfos
.Where(skillInfo => skillInfo.SkillCategory
is SkillCategory.NormalAttack
or SkillCategory.BlowAttack
or SkillCategory.DoubleAttack
or SkillCategory.AreaAttack
or SkillCategory.BuffRemovalAttack)
.ToList();
if (Buffs.Values.OfType<Vampiric>().OrderBy(x => x.BuffInfo.Id) is
{ } vampirics)
{
foreach (var vampiric in vampirics)
{
foreach (var effect in attackSkills
.Select(skillInfo =>
vampiric.GiveEffect(this, skillInfo, Simulator.WaveTurn, log))
.Where(_ => log))
{
Simulator.Log.Add(effect);
}
}
}

var bleeds = Buffs.Values.OfType<Bleed>().OrderBy(x => x.BuffInfo.Id);
bool log = Simulator.LogEvent;
foreach (var bleed in bleeds)
{
var effect = bleed.GiveEffect(this, Simulator.WaveTurn, log);
Expand All @@ -589,15 +612,9 @@ protected virtual void OnPostSkill(BattleStatus.Skill usedSkill)
}

// Apply thorn damage if target has thorn
foreach (var skillInfo in usedSkill.SkillInfos)
foreach (var skillInfo in attackSkills)
{
var isAttackSkill =
skillInfo.SkillCategory == SkillCategory.NormalAttack ||
skillInfo.SkillCategory == SkillCategory.BlowAttack ||
skillInfo.SkillCategory == SkillCategory.DoubleAttack ||
skillInfo.SkillCategory == SkillCategory.AreaAttack ||
skillInfo.SkillCategory == SkillCategory.BuffRemovalAttack;
if (isAttackSkill && skillInfo.Thorn > 0)
if (skillInfo.Thorn > 0)
{
var effect = GiveThornDamage(skillInfo.Thorn);
if (log)
Expand Down
1 change: 1 addition & 0 deletions Lib9c/Model/IArena.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ public interface IArena
IEnumerator CoRemoveBuffs(ArenaCharacter caster);
IEnumerator CoDead(ArenaCharacter caster);
IEnumerator CoTurnEnd(int turnNumber);
IEnumerator CoCustomEvent(ArenaCharacter caster, ArenaEventBase eventBase);
}
}
8 changes: 5 additions & 3 deletions Lib9c/Model/IStage.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using Nekoyume.Model.BattleStatus;
using Nekoyume.Model.Item;

namespace Nekoyume.Model
Expand All @@ -19,16 +20,17 @@ public interface IStage
IEnumerator CoHeal(CharacterBase caster, int skillId, IEnumerable<BattleStatus.Skill.SkillInfo> skillInfos, IEnumerable<BattleStatus.Skill.SkillInfo> buffInfos);
IEnumerator CoBuff(CharacterBase caster, int skillId, IEnumerable<BattleStatus.Skill.SkillInfo> skillInfos, IEnumerable<BattleStatus.Skill.SkillInfo> buffInfos);
IEnumerator CoTickDamage(CharacterBase affectedCharacter, int skillId, IEnumerable<BattleStatus.Skill.SkillInfo> skillInfos);

#endregion

IEnumerator CoRemoveBuffs(CharacterBase caster);

IEnumerator CoDropBox(List<ItemBase> items);
IEnumerator CoGetReward(List<ItemBase> rewards);
IEnumerator CoSpawnWave(int waveNumber, int waveTurn, List<Enemy> enemies, bool hasBoss);
IEnumerator CoGetExp(long exp);
IEnumerator CoWaveTurnEnd(int turnNumber, int waveTurn);
IEnumerator CoDead(CharacterBase character);
IEnumerator CoCustomEvent(CharacterBase character, EventBase eventBase);
}
}
Loading
Loading