Skip to content

Commit

Permalink
feat: multiple callback effects support
Browse files Browse the repository at this point in the history
  • Loading branch information
Chillu1 committed Aug 3, 2024
1 parent f1422c3 commit 3398675
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 40 deletions.
37 changes: 37 additions & 0 deletions ModiBuff/ModiBuff.Tests/CallbackEffectTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -302,5 +302,42 @@ public void StunnedFourTimes_DispelAllStatusEffects(RecipeAddFunc addFunc)
Assert.False(Unit.StatusEffectController.HasStatusEffect(StatusEffectType.Freeze));
Assert.False(Unit.StatusEffectController.HasStatusEffect(StatusEffectType.Stun));
}

[Test]
public void DamageOnStun_HealOnAnyNotStunStatusEffectRemoved()
{
AddRecipe("DamageOnStun_HealOnAnyNotStunStatusEffectRemoved")
.Effect(new DamageEffect(5), EffectOn.CallbackEffect)
.CallbackEffect(CallbackType.StatusEffectAdded, effect =>
new StatusEffectEvent((target, source, appliedStatusEffect, oldLegalAction, newLegalAction) =>
{
if (appliedStatusEffect.HasStatusEffect(StatusEffectType.Stun))
((ICallbackEffect)effect).CallbackEffect(target, source);
}))
.Effect(new HealEffect(5), EffectOn.CallbackEffect2)
.CallbackEffect(CallbackType.StatusEffectRemoved, effect =>
new StatusEffectEvent((target, source, appliedStatusEffect, oldLegalAction, newLegalAction) =>
{
if (!appliedStatusEffect.HasStatusEffect(StatusEffectType.Stun))
((ICallbackEffect)effect).CallbackEffect(target, source);
}));
AddRecipe("Stun")
.Effect(new StatusEffectEffect(StatusEffectType.Stun, 1), EffectOn.Init)
.Remove(1).Refresh();
AddRecipe("Freeze")
.Effect(new StatusEffectEffect(StatusEffectType.Freeze, 1), EffectOn.Init)
.Remove(1).Refresh();
Setup();

Unit.AddModifierSelf("DamageOnStun_HealOnAnyNotStunStatusEffectRemoved");
Unit.AddModifierSelf("Stun");
Assert.AreEqual(UnitHealth - 5, Unit.Health);
Unit.Update(1);
Assert.AreEqual(UnitHealth - 5, Unit.Health);
Unit.AddModifierSelf("Freeze");
Assert.AreEqual(UnitHealth - 5, Unit.Health);
Unit.Update(1);
Assert.AreEqual(UnitHealth, Unit.Health);
}
}
}
15 changes: 14 additions & 1 deletion ModiBuff/ModiBuff.Units/Effects/DamageEffect.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace ModiBuff.Core.Units
{
public sealed class DamageEffect : IStackEffect, IMutableStateEffect, IEffect,
public sealed class DamageEffect : IStackEffect, IMutableStateEffect, IEffect, ICallbackEffect,
IMetaEffectOwner<DamageEffect, float, float>, IPostEffectOwner<DamageEffect, float>,
IEffectStateInfo<DamageEffect.Data>, ISavableEffect<DamageEffect.SaveData>,
ISaveableRecipeEffect<DamageEffect.RecipeSaveData>
Expand Down Expand Up @@ -94,6 +94,19 @@ public void StackEffect(int stacks, IUnit target, IUnit source)
Effect(target, source);
}

//TODO Should callback effects use stack logic?
public void CallbackEffect(IUnit target, IUnit source)
{
if ((_stackEffect & StackEffectType.Set) != 0)
_extraDamage = _stackValue;

if ((_stackEffect & StackEffectType.Add) != 0)
_extraDamage += _stackValue;

if ((_stackEffect & StackEffectType.Effect) != 0)
Effect(target, source);
}

public Data GetEffectData() => new Data(_baseDamage, _extraDamage);

public void ResetState() => _extraDamage = 0;
Expand Down
1 change: 1 addition & 0 deletions ModiBuff/ModiBuff.Units/Effects/HealEffect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public void StackEffect(int stacks, IUnit target, IUnit source)
Effect(target, source);
}

//TODO Should callback effects use stack logic?
public void CallbackEffect(IUnit target, IUnit source)
{
if ((_stackEffect & StackEffectType.Set) != 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public ModifierGenerator(in ModifierRecipeData data)

_modifierEffectsCreator = new ModifierEffectsCreator(data.EffectWrappers, data.RemoveEffectWrapper,
data.DispelRegisterWrapper, data.EventRegisterWrapper, data.CallbackUnitRegisterWrapper,
data.CallbackEffectRegisterWrapper, data.CallbackEffectUnitsRegisterWrapper);
data.CallbackEffectRegisterWrappers, data.CallbackEffectUnitsRegisterWrapper);

if (HasApplyChecks)
{
Expand Down
14 changes: 14 additions & 0 deletions ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/EffectOn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,24 @@ public enum EffectOn
CallbackUnit = 32,
CallbackEffect = 64,
CallbackEffectUnits = 128,
CallbackEffect2 = 256,
CallbackEffect3 = 512,
CallbackEffect4 = 1024,
}

public static class EffectOnExtensions
{
public static RemoveEffectOn ToRemoveEffectOn(this EffectOn effectOn) => (RemoveEffectOn)effectOn;
}

public static class EffectOnCallbackEffectData
{
public static readonly EffectOn[] AllCallbackEffectData =
{
EffectOn.CallbackEffect,
EffectOn.CallbackEffect2,
EffectOn.CallbackEffect3,
EffectOn.CallbackEffect4,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public sealed class ModifierEffectsCreator
private readonly EffectWrapper _dispelRegisterWrapper;
private readonly EffectWrapper _eventRegisterWrapper;
private readonly EffectWrapper _callbackUnitRegisterWrapper;
private readonly EffectWrapper _callbackEffectRegisterWrapper;
private readonly EffectWrapper[] _callbackEffectRegisterWrappers;
private readonly EffectWrapper _callbackEffectUnitsRegisterWrapper;

private IRevertEffect[] _revertEffects;
Expand All @@ -24,7 +24,7 @@ public sealed class ModifierEffectsCreator
private IStackEffect[] _stackEffects;
private IEffect[] _eventEffects;
private IEffect[] _callbackUnitEffects;
private IEffect[] _callbackEffectEffects;
private IEffect[][] _callbackEffectEffects;
private IEffect[] _callbackEffectUnitsEffects;

private int _revertEffectsIndex,
Expand All @@ -35,11 +35,14 @@ public sealed class ModifierEffectsCreator
_eventEffectsIndex,
_callbackUnitEffectsIndex,
_callbackEffectEffectsIndex,
_callbackEffectUnitsEffectsIndex;
_callbackEffectUnitsEffectsIndex,
_callbackEffectEffectsIndex2,
_callbackEffectEffectsIndex3,
_callbackEffectEffectsIndex4;

public ModifierEffectsCreator(List<EffectWrapper> effectWrappers, EffectWrapper removeEffectWrapper,
EffectWrapper dispelRegisterWrapper, EffectWrapper eventRegisterWrapper,
EffectWrapper callbackUnitRegisterWrapper, EffectWrapper callbackEffectRegisterWrapper,
EffectWrapper callbackUnitRegisterWrapper, EffectWrapper[] callbackEffectRegisterWrappers,
EffectWrapper callbackEffectUnitsRegisterWrapper)
{
var effectsWithModifierInfoWrappers = new List<EffectWrapper>();
Expand All @@ -49,7 +52,7 @@ public ModifierEffectsCreator(List<EffectWrapper> effectWrappers, EffectWrapper
_dispelRegisterWrapper = dispelRegisterWrapper;
_eventRegisterWrapper = eventRegisterWrapper;
_callbackUnitRegisterWrapper = callbackUnitRegisterWrapper;
_callbackEffectRegisterWrapper = callbackEffectRegisterWrapper;
_callbackEffectRegisterWrappers = callbackEffectRegisterWrappers;
_callbackEffectUnitsRegisterWrapper = callbackEffectUnitsRegisterWrapper;

for (int i = 0; i < _effectWrappers.Length; i++)
Expand Down Expand Up @@ -80,6 +83,12 @@ public ModifierEffectsCreator(List<EffectWrapper> effectWrappers, EffectWrapper
_callbackEffectEffectsIndex++;
if ((effectWrapper.EffectOn & EffectOn.CallbackEffectUnits) != 0)
_callbackEffectUnitsEffectsIndex++;
if ((effectWrapper.EffectOn & EffectOn.CallbackEffect2) != 0)
_callbackEffectEffectsIndex2++;
if ((effectWrapper.EffectOn & EffectOn.CallbackEffect3) != 0)
_callbackEffectEffectsIndex3++;
if ((effectWrapper.EffectOn & EffectOn.CallbackEffect4) != 0)
_callbackEffectEffectsIndex4++;
}

_effectsWithModifierInfoWrappers = effectsWithModifierInfoWrappers.ToArray();
Expand Down Expand Up @@ -125,9 +134,13 @@ public SyncedModifierEffects Create(int genId)
_callbackUnitEffectsIndex = 0;
}

if (_callbackEffectEffectsIndex > 0 || _callbackEffectEffectsIndex2 > 0 ||
_callbackEffectEffectsIndex3 > 0 || _callbackEffectEffectsIndex4 > 0)
_callbackEffectEffects = new IEffect[4][];

if (_callbackEffectEffectsIndex > 0)
{
_callbackEffectEffects = new IEffect[_callbackEffectEffectsIndex];
_callbackEffectEffects[0] = new IEffect[_callbackEffectEffectsIndex];
_callbackEffectEffectsIndex = 0;
}

Expand All @@ -137,6 +150,24 @@ public SyncedModifierEffects Create(int genId)
_callbackEffectUnitsEffectsIndex = 0;
}

if (_callbackEffectEffectsIndex2 > 0)
{
_callbackEffectEffects[1] = new IEffect[_callbackEffectEffectsIndex2];
_callbackEffectEffectsIndex2 = 0;
}

if (_callbackEffectEffectsIndex3 > 0)
{
_callbackEffectEffects[2] = new IEffect[_callbackEffectEffectsIndex3];
_callbackEffectEffectsIndex3 = 0;
}

if (_callbackEffectEffectsIndex4 > 0)
{
_callbackEffectEffects[3] = new IEffect[_callbackEffectEffectsIndex4];
_callbackEffectEffectsIndex4 = 0;
}

if (_revertEffectsIndex > 0)
{
_revertEffects = new IRevertEffect[_revertEffectsIndex];
Expand Down Expand Up @@ -169,9 +200,15 @@ public SyncedModifierEffects Create(int genId)
if ((effectOn & EffectOn.CallbackUnit) != 0)
_callbackUnitEffects[_callbackUnitEffectsIndex++] = effect;
if ((effectOn & EffectOn.CallbackEffect) != 0)
_callbackEffectEffects[_callbackEffectEffectsIndex++] = effect;
_callbackEffectEffects[0][_callbackEffectEffectsIndex++] = effect;
if ((effectOn & EffectOn.CallbackEffectUnits) != 0)
_callbackEffectUnitsEffects[_callbackEffectUnitsEffectsIndex++] = effect;
if ((effectOn & EffectOn.CallbackEffect2) != 0)
_callbackEffectEffects[1][_callbackEffectEffectsIndex2++] = effect;
if ((effectOn & EffectOn.CallbackEffect3) != 0)
_callbackEffectEffects[2][_callbackEffectEffectsIndex3++] = effect;
if ((effectOn & EffectOn.CallbackEffect4) != 0)
_callbackEffectEffects[3][_callbackEffectEffectsIndex4++] = effect;
}

EffectStateInfo effectStateInfo = default;
Expand All @@ -197,7 +234,10 @@ public SyncedModifierEffects Create(int genId)
//Since they're always fed to effectWrappers, that we reset at the end
_eventRegisterWrapper?.GetEffectAs<IRecipeFeedEffects>().SetEffects(_eventEffects);
_callbackUnitRegisterWrapper?.GetEffectAs<IRecipeFeedEffects>().SetEffects(_callbackUnitEffects);
_callbackEffectRegisterWrapper?.GetEffectAs<IRecipeFeedEffects>().SetEffects(_callbackEffectEffects);
for (int i = 0; i < _callbackEffectRegisterWrappers?.Length; i++)
_callbackEffectRegisterWrappers[i].GetEffectAs<IRecipeFeedEffects>()
.SetEffects(_callbackEffectEffects[i]);

_callbackEffectUnitsRegisterWrapper?.GetEffectAs<IRecipeFeedEffects>()
.SetEffects(_callbackEffectUnitsEffects);

Expand Down
44 changes: 17 additions & 27 deletions ModiBuff/ModiBuff/Core/Modifier/Creation/Recipe/ModifierRecipe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public sealed partial class ModifierRecipe : IModifierRecipe, IEquatable<Modifie
private EffectWrapper _dispelRegisterWrapper;
private EffectWrapper _eventRegisterWrapper;
private EffectWrapper _callbackUnitRegisterWrapper;
private EffectWrapper _callbackEffectRegisterWrapper;
private readonly List<EffectWrapper> _callbackEffectRegisterWrappers;
private EffectWrapper _callbackEffectUnitsRegisterWrapper;

private readonly List<EffectWrapper> _effectWrappers;
Expand Down Expand Up @@ -70,6 +70,7 @@ public ModifierRecipe(int id, string name, string displayName, string descriptio
_tag = (TagType)Config.DefaultTag;

_effectWrappers = new List<EffectWrapper>(3);
_callbackEffectRegisterWrappers = new List<EffectWrapper>();

_saveInstructions = new List<SaveInstruction>
{ new SaveInstruction.Initialize(name, displayName, description) };
Expand Down Expand Up @@ -236,7 +237,7 @@ public ModifierRecipe RemoveApplier(float duration, ApplierType applierType, boo
/// <summary>
/// Adds a basic remove effect, that should be triggered on either stack, or callback
/// </summary>
public ModifierRecipe Remove(RemoveEffectOn removeEffectOn = RemoveEffectOn.CallbackUnit)
public ModifierRecipe Remove(RemoveEffectOn removeEffectOn)
{
AddRemoveEffect(removeEffectOn.ToEffectOn());
_saveInstructions.Add(new SaveInstruction.Remove(SaveInstruction.Remove.Type.RemoveOn,
Expand Down Expand Up @@ -485,44 +486,31 @@ public ModifierRecipe Callback<TCallback, TStateData>(TCallback callbackType,
/// Special callbacks, all EffectOn.<see cref="EffectOn.CallbackEffect"/> effects will
/// trigger when <see cref="callbackType"/> is triggered.
/// Supports custom callback signatures (beside <see cref="UnitCallback"/>.
/// Only ONE CallbackEffect can be registered per modifier.
/// Callback effects now have to be in order
/// </summary>
public ModifierRecipe CallbackEffect<TCallbackEffect>(TCallbackEffect callbackType,
Func<IEffect, object> @event)
{
if (_callbackEffectRegisterWrapper != null)
{
Logger.LogError("[ModiBuff] Multiple CallbackEffect effects registered, " +
"only one is allowed per modifier, ignoring.");
return this;
}

var effect = new CallbackEffectRegisterEffect<TCallbackEffect>(callbackType, @event);
_callbackEffectRegisterWrapper = new EffectWrapper(effect, EffectOn.Init);
_effectWrappers.Add(_callbackEffectRegisterWrapper);
var wrapper = new EffectWrapper(effect, EffectOn.Init);
_callbackEffectRegisterWrappers.Add(wrapper);
_effectWrappers.Add(wrapper);
return this;
}

/// <summary>
/// Special callbacks, all EffectOn.<see cref="EffectOn.CallbackEffect"/> effects will
/// trigger when <see cref="callbackType"/> is triggered.
/// Supports custom callback signatures (beside <see cref="UnitCallback"/>.
/// Only ONE CallbackEffect can be registered per modifier.
/// Allows to save state through state context.
/// </summary>
public ModifierRecipe CallbackEffect<TCallbackEffect, TStateData>(TCallbackEffect callbackType,
Func<IEffect, CallbackStateContext<TStateData>> @event)
{
if (_callbackEffectRegisterWrapper != null)
{
Logger.LogError("[ModiBuff] Multiple CallbackEffect effects registered, " +
"only one is allowed per modifier, ignoring.");
return this;
}

var effect = new CallbackStateEffectRegisterEffect<TCallbackEffect, TStateData>(callbackType, @event);
_callbackEffectRegisterWrapper = new EffectWrapper(effect, EffectOn.Init);
_effectWrappers.Add(_callbackEffectRegisterWrapper);
var wrapper = new EffectWrapper(effect, EffectOn.Init);
_callbackEffectRegisterWrappers.Add(wrapper);
_effectWrappers.Add(wrapper);
return this;
}

Expand Down Expand Up @@ -591,10 +579,10 @@ public IModifierGenerator CreateModifierGenerator()

var data = new ModifierRecipeData(Id, Name, _effectWrappers, finalRemoveEffectWrapper,
_dispelRegisterWrapper, _eventRegisterWrapper, _callbackUnitRegisterWrapper,
_callbackEffectRegisterWrapper, _callbackEffectUnitsRegisterWrapper, _hasApplyChecks, _applyCheckList,
_hasEffectChecks, _effectCheckList, _applyFuncCheckList, _effectFuncCheckList, _isAura, _tag,
_oneTimeInit, _interval, _duration, _refreshDuration, _refreshInterval, _whenStackEffect, _maxStacks,
_everyXStacks, _singleStackTime, _independentStackTime);
_callbackEffectRegisterWrappers.ToArray(), _callbackEffectUnitsRegisterWrapper, _hasApplyChecks,
_applyCheckList, _hasEffectChecks, _effectCheckList, _applyFuncCheckList, _effectFuncCheckList, _isAura,
_tag, _oneTimeInit, _interval, _duration, _refreshDuration, _refreshInterval, _whenStackEffect,
_maxStacks, _everyXStacks, _singleStackTime, _independentStackTime);
return new ModifierGenerator(in data);
}

Expand Down Expand Up @@ -673,7 +661,9 @@ private void Validate()

ValidateCallbacks(EffectOn.Event, _eventRegisterWrapper);
ValidateCallbacks(EffectOn.CallbackUnit, _callbackUnitRegisterWrapper);
ValidateCallbacks(EffectOn.CallbackEffect, _callbackEffectRegisterWrapper);
for (int i = 0; i < _callbackEffectRegisterWrappers.Count; i++)
ValidateCallbacks(EffectOnCallbackEffectData.AllCallbackEffectData[i],
_callbackEffectRegisterWrappers[i]);
ValidateCallbacks(EffectOn.CallbackEffectUnits, _callbackEffectUnitsRegisterWrapper);

if (_effectWrappers.Exists(w =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public readonly struct ModifierRecipeData
public readonly EffectWrapper DispelRegisterWrapper;
public readonly EffectWrapper EventRegisterWrapper;
public readonly EffectWrapper CallbackUnitRegisterWrapper;
public readonly EffectWrapper CallbackEffectRegisterWrapper;
public readonly EffectWrapper[] CallbackEffectRegisterWrappers;
public readonly EffectWrapper CallbackEffectUnitsRegisterWrapper;
public readonly bool HasApplyChecks;
public readonly List<ICheck> ApplyCheckList;
Expand All @@ -35,7 +35,7 @@ public readonly struct ModifierRecipeData

public ModifierRecipeData(int id, string name, List<EffectWrapper> effectWrappers,
EffectWrapper removeEffectWrapper, EffectWrapper dispelRegisterWrapper, EffectWrapper eventRegisterWrapper,
EffectWrapper callbackUnitRegisterWrapper, EffectWrapper callbackEffectRegisterWrapper,
EffectWrapper callbackUnitRegisterWrapper, EffectWrapper[] callbackEffectRegisterWrappers,
EffectWrapper callbackEffectUnitsRegisterWrapper, bool hasApplyChecks, List<ICheck> applyCheckList,
bool hasEffectChecks, List<ICheck> effectCheckList, List<Func<IUnit, bool>> applyFuncCheckList,
List<Func<IUnit, bool>> effectFuncCheckList, bool isAura, TagType tag, bool oneTimeInit, float interval,
Expand All @@ -49,7 +49,7 @@ public ModifierRecipeData(int id, string name, List<EffectWrapper> effectWrapper
DispelRegisterWrapper = dispelRegisterWrapper;
EventRegisterWrapper = eventRegisterWrapper;
CallbackUnitRegisterWrapper = callbackUnitRegisterWrapper;
CallbackEffectRegisterWrapper = callbackEffectRegisterWrapper;
CallbackEffectRegisterWrappers = callbackEffectRegisterWrappers;
CallbackEffectUnitsRegisterWrapper = callbackEffectUnitsRegisterWrapper;
HasApplyChecks = hasApplyChecks;
ApplyCheckList = applyCheckList;
Expand Down

0 comments on commit 3398675

Please sign in to comment.