Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 0 additions & 2 deletions ModiBuff/ModiBuff.Benchmarks/BenchmarkModifierRecipes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,9 @@ protected override void SetupRecipes()
.Stack(WhenStackEffect.Always);

Add("InitDamage_CostMana")
.ApplyCost(CostType.Mana, 5)
.Effect(new DamageEffect(5), EffectOn.Init);

Add("InitDamage_ApplyCondition_HealthAbove100")
.ApplyCondition(StatType.Health, 100, ComparisonType.GreaterOrEqual)
.Effect(new DamageEffect(5), EffectOn.Init);
}
}
Expand Down
14 changes: 7 additions & 7 deletions ModiBuff/ModiBuff.Examples/BasicConsole/GameController.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Linq;
using ModiBuff.Core;

namespace ModiBuff.Examples.BasicConsole
Expand Down Expand Up @@ -47,9 +48,8 @@ public GameController()
//But we're adding it as an applier, and not as a normal modifier
//This means that instead of it being applier to the player
//it will be applied to a unit that the player attacks
_player.ModifierApplierController.TryAddApplier(_idManager.GetId("DoT")!.Value, false, ApplierType.Attack);
_player.ModifierApplierController.TryAddApplier(_idManager.GetId("InitHeal")!.Value, false,
ApplierType.Cast);
_player.AddApplierModifierNew(_idManager.GetId("DoT")!.Value, ApplierType.Attack);
_player.AddApplierModifierNew(_idManager.GetId("InitHeal")!.Value, ApplierType.Cast);
//_player.ModifierController.TryAddApplier(_idManager.GetId("DisarmChance"), true, ApplierType.Cast);
}

Expand Down Expand Up @@ -101,12 +101,12 @@ private bool PlayerAction()
private bool PlayerCastAction()
{
//Display all possible modifiers to cast, then when one was chosen, choose the target
var modifierIds = _player.ModifierApplierController.GetApplierCastModifierIds();
int[] modifierIds = _player.GetApplierCastModifierIds().ToArray();

while (true)
{
Console.GameMessage("Choose modifier to cast, or c to cancel");
for (int i = 0; i < modifierIds.Count; i++)
for (int i = 0; i < modifierIds.Length; i++)
{
var modifierInfo = _recipes.GetModifierInfo(modifierIds[i]);
Console.GameMessage($"{i + 1} - {modifierInfo.DisplayName} - {modifierInfo.Description}");
Expand All @@ -115,10 +115,10 @@ private bool PlayerCastAction()
string castAction = System.Console.ReadLine();
if (int.TryParse(castAction, out int castActionInt))
{
if (castActionInt > 0 && castActionInt <= modifierIds.Count)
if (castActionInt > 0 && castActionInt <= modifierIds.Length)
{
//TODO: choosing target
_player.TryCast(modifierIds[castActionInt - 1], _player);
_player.TryApply(modifierIds[castActionInt - 1], _player);
break;
}
}
Expand Down
4 changes: 1 addition & 3 deletions ModiBuff/ModiBuff.Examples/BasicConsole/ModifierRecipes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,8 @@ protected override void SetupRecipes()
.Effect(new DamageEffect(1), EffectOn.Interval);

//Here we introduce a new effect, and a chance for the modifier to be applied
//Chance needs to be applied when adding the applier
Add("DisarmChance", "Disarm", "Disarms target for 1 second, 20% chance to apply")
//When applying a modifier (through attacking or casting it)
//It will have 20% chance to apply the modifier to the unit
.ApplyChance(0.2f)
//Disarms (can't attack) the target unit for 1 second when applied
.Effect(new StatusEffectEffect(StatusEffectType.Disarm, 1f), EffectOn.Init)
.Remove(1f).Refresh();
Expand Down
14 changes: 7 additions & 7 deletions ModiBuff/ModiBuff.Examples/BasicConsole/UIExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Linq;
using ModiBuff.Core;
using ModiBuff.Core.Units;
using ModiBuff.Core.Units.Interfaces.NonGeneric;
Expand All @@ -10,30 +11,29 @@ public static class UIExtensions
public static void PrintStateAndModifiers(this IModifierApplierOwner owner, IModifierRecipes modifierRecipes)
{
var modifierController = ((IModifierOwner)owner).ModifierController;
var modifierApplierController = owner.ModifierApplierController;
//Stats, ApplyModifiers, Normal modifiers.
var damagable = (IDamagable)owner;
var attacker = (IAttacker)owner;
Console.GameMessage($"Player stats: {damagable.Health}/{damagable.MaxHealth} HP, " +
$"{attacker.Damage} Damage");
//Appliers
//Name, description, checks, (states, like cooldown)
var applierAttackIds = modifierApplierController.GetApplierAttackModifierIds();
if (applierAttackIds != null && applierAttackIds.Count > 0)
var applierAttackIds = ((Unit)owner).GetApplierCastModifierIds().ToArray();
if (applierAttackIds.Length > 0)
{
Console.GameMessage("Player attack appliers:");
for (int i = 0; i < applierAttackIds.Count; i++)
for (int i = 0; i < applierAttackIds.Length; i++)
{
var modifierInfo = modifierRecipes.GetModifierInfo(applierAttackIds[i]);
Console.GameMessage($"{i + 1} - {modifierInfo.DisplayName} - {modifierInfo.Description}");
}
}

var applierCastIds = modifierApplierController.GetApplierCastModifierIds();
if (applierCastIds != null && applierCastIds.Count > 0)
var applierCastIds = ((Unit)owner).GetApplierCastModifierIds().ToArray();
if (applierCastIds.Length > 0)
{
Console.GameMessage("Player cast appliers:");
for (int i = 0; i < applierCastIds.Count; i++)
for (int i = 0; i < applierCastIds.Length; i++)
{
var modifierInfo = modifierRecipes.GetModifierInfo(applierCastIds[i]);
Console.GameMessage($"{i + 1} - {modifierInfo.DisplayName} - {modifierInfo.Description}");
Expand Down
114 changes: 109 additions & 5 deletions ModiBuff/ModiBuff.Examples/BasicConsole/Unit.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using ModiBuff.Core;
using ModiBuff.Core.Units;
using ModiBuff.Core.Units.Interfaces.NonGeneric;
Expand All @@ -21,7 +22,7 @@ public sealed class Unit : IModifierOwner, IUpdatable, IDamagable, IAttacker, IH
public ModifierController ModifierController { get; }

//TODO Explain
public ModifierApplierController ModifierApplierController { get; }
private readonly Dictionary<ApplierType, List<(int Id, ICheck[] Checks)>> _modifierAppliers;

//Basic implementation of status effects, unit can't attack when it's disarmed
//Move when it's rooted/frozen/stunned, etc.
Expand All @@ -47,7 +48,11 @@ public Unit(string name, float health, float damage)

//Remember to rent the modifier controllers in the constructor
ModifierController = ModifierControllerPool.Instance.Rent();
ModifierApplierController = ModifierControllerPool.Instance.RentApplier();
_modifierAppliers = new Dictionary<ApplierType, List<(int, ICheck[])>>
{
{ ApplierType.Attack, new List<(int, ICheck[])>() },
{ ApplierType.Cast, new List<(int, ICheck[])>() }
};
StatusEffectController = new StatusEffectController();
_targetingSystem = new TargetingSystem();
}
Expand All @@ -60,7 +65,6 @@ public void Update(float deltaTime)
//We need to update the modifier controller each frame/tick
//To update the modifier timers (interval, duration)
ModifierController.Update(deltaTime);
ModifierApplierController.Update(deltaTime);
StatusEffectController.Update(deltaTime);
}

Expand Down Expand Up @@ -95,14 +99,71 @@ public float Attack(Unit target)
if (!StatusEffectController.HasLegalAction(LegalAction.Act))
return 0;

//This method will try to apply all our applier attack modifiers to the target
this.ApplyAllAttackModifier(target);
foreach ((int id, ICheck[] checks) in _modifierAppliers[ApplierType.Attack])
{
bool checksPassed = true;
if (checks != null)
foreach (var check in checks)
{
if (!check.Check(this))
{
checksPassed = false;
break;
}
}

if (!checksPassed)
continue;

if (checks != null)
foreach (var check in checks)
check.Use(this);

target.ModifierController.Add(id, target, this);
}

float damageDealt = target.TakeDamage(Damage, this);

return damageDealt;
}

public bool TryApply(int modifierId, IUnit target)
{
if (!(target is IModifierOwner modifierTarget))
return false;
if (!StatusEffectController.HasLegalAction(LegalAction.Cast))
return false;
if (!_modifierAppliers.TryGetValue(ApplierType.Cast, out var appliers))
return false;

(int Id, ICheck[] Checks)? applier = null;
for (int i = 0; i < appliers.Count; i++)
{
if (appliers[i].Id == modifierId)
{
applier = appliers[i];
break;
}
}

if (applier == null)
return false;

if (applier.Value.Checks != null)
{
foreach (var check in applier.Value.Checks)
if (!check.Check(this))
return false;

for (int i = 0; i < applier.Value.Checks.Length; i++)
applier.Value.Checks[i].Use(this);
}

modifierTarget.ModifierController.Add(modifierId, modifierTarget, this);

return true;
}

public float TakeDamage(float damage, IUnit source)
{
if (IsDead)
Expand Down Expand Up @@ -141,6 +202,49 @@ public float Heal(float heal, IUnit source)
return Health - originalHealth;
}

public bool ContainsApplier(int modifierId, ApplierType applierType)
{
return _modifierAppliers.TryGetValue(applierType, out var list) && list.Exists(c => c.Id == modifierId);
}

public bool RemoveApplier(int id, ApplierType applierType)
{
if (!_modifierAppliers.TryGetValue(applierType, out var list))
return false;

int index = list.FindIndex(c => c.Id == id);
if (index == -1)
return false;

list.RemoveAt(index);
return true;
}

public void AddApplierModifierNew(int modifierId, ApplierType applierType, ICheck[] checks = null)
{
if (checks?.Length > 0)
{
if (_modifierAppliers.TryGetValue(applierType, out var list))
{
list.Add((modifierId, checks));
return;
}

_modifierAppliers[applierType] =
new List<(int Id, ICheck[] Checks)>(new[] { (modifierId, checks) });
return;
}

_modifierAppliers[applierType].Add((modifierId, null));
}

public IEnumerable<int> GetApplierCastModifierIds()
{
if (_modifierAppliers.TryGetValue(ApplierType.Cast, out var list))
foreach ((int id, ICheck[] _) in list)
yield return id;
}

public string GetDebugString()
{
return $"Unit, health: {Health}/{MaxHealth}, damage: {Damage}";
Expand Down
Loading