Skip to content
Merged
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
7 changes: 7 additions & 0 deletions src/OpenRpg.Combat/Abilities/Ability.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using OpenRpg.Core.Templates;

namespace OpenRpg.Combat.Abilities
{
public class Ability : TemplateInstance<AbilityTemplate, AbilityData>
{}
}
7 changes: 5 additions & 2 deletions src/OpenRpg.Combat/Attacks/Attack.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
using System;
using System.Collections.Generic;

namespace OpenRpg.Combat.Attacks
{
public class Attack
{
public ICollection<Damage> Damages { get; set; } = new List<Damage>();
public bool IsCritical { get; set; }
public IReadOnlyList<Damage> Damages { get; set; } = Array.Empty<Damage>();

public Attack(){}
public Attack(ICollection<Damage> damages)
public Attack(IReadOnlyList<Damage> damages, bool isCritical = false)
{
Damages = damages;
IsCritical = isCritical;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Collections.Generic;
using OpenRpg.Combat.Abilities;
using OpenRpg.Combat.Effects;
using OpenRpg.Combat.Types;
using OpenRpg.Entities.Entity.Variables;
Expand Down
21 changes: 21 additions & 0 deletions src/OpenRpg.Combat/Extensions/CombatTemplateVariableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using OpenRpg.Combat.Abilities;
using OpenRpg.Combat.Types;
using OpenRpg.Core.Extensions;
using OpenRpg.Core.Templates.Variables;

namespace OpenRpg.Combat.Extensions
{
public static class CombatTemplateVariableExtensions
{
public static bool HasAbilities(this ITemplateVariables vars) =>
vars.ContainsKey(CombatTemplateVariableTypes.Abilities);

public static IReadOnlyCollection<AbilityData> Abilities(this ITemplateVariables vars) =>
vars.GetAsOrDefault(CombatTemplateVariableTypes.Abilities, Array.Empty<AbilityData>);

public static void Abilities(this ITemplateVariables vars, IReadOnlyCollection<AbilityData> abilities) =>
vars[CombatTemplateVariableTypes.Abilities] = abilities;
}
}
20 changes: 20 additions & 0 deletions src/OpenRpg.Combat/Extensions/IRandomizerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using OpenRpg.Core.Utils;
using OpenRpg.CurveFunctions.Extensions;

namespace OpenRpg.Combat.Extensions
{
public static class IRandomizerExtensions
{
/// <summary>
/// This is a quick way to check if you have made a critical hit
/// </summary>
/// <param name="randomizer">The randomizer to user for this</param>
/// <param name="criticalChance">The critical chance between 0-1</param>
/// <returns>true if a critical attack was made, false if not</returns>
public static bool ShouldCritical(this IRandomizer randomizer, float criticalChance)
{
var sanitizedCritChance = criticalChance.SanitizeAndClamp();
return randomizer.Random() <= sanitizedCritChance;
}
}
}
3 changes: 3 additions & 0 deletions src/OpenRpg.Combat/Processors/Attacks/IAttackGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using OpenRpg.Combat.Abilities;
using OpenRpg.Combat.Attacks;
using OpenRpg.Entities.Stats;

Expand All @@ -6,5 +7,7 @@ namespace OpenRpg.Combat.Processors.Attacks
public interface IAttackGenerator<in T> where T : IStatsVariables
{
Attack GenerateAttack(T stats);
Attack GenerateAttack(Ability ability, T stats);
Attack GenerateAttack(Damage damage, T stats);
}
}
11 changes: 11 additions & 0 deletions src/OpenRpg.Combat/Types/CombatTemplateVariableTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace OpenRpg.Combat.Types
{
public interface CombatTemplateVariableTypes
{
// Unknown
public static int Unknown = 0;

// For adding the notion of procedural effects
public static int Abilities = 6000;
}
}
2 changes: 1 addition & 1 deletion src/OpenRpg.Demos.Infrastructure/DI/OpenRpgModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void Setup(IServiceCollection services)
services.AddSingleton<IEntityStatPopulator>(new FantasyStatsPopulator([new DamageStatPopulator(), new DefenseStatPopulator()]));
services.AddSingleton<IEntityStatePopulator, FantasyStatePopulator>();
services.AddSingleton<IRandomizer>(x => new DefaultRandomizer(new Random()));
services.AddSingleton<IEntityAttackGenerator, BasicAttackGenerator>();
services.AddSingleton<IEntityAttackGenerator, FantasyAttackGenerator>();
services.AddSingleton<IAttackProcessor<EntityStatsVariables>, DefaultAttackProcessor>();
services.AddSingleton<ICharacterRequirementChecker, DefaultFantasyCharacterRequirementChecker>();
services.AddSingleton<ICharacterEffectProcessor, CharacterEffectProcessor>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using OpenRpg.Core.Effects;
using OpenRpg.Core.Templates;
using OpenRpg.Entities.Effects;

namespace OpenRpg.Entities.Modifications.Templates
{
Expand Down
21 changes: 0 additions & 21 deletions src/OpenRpg.Genres.Fantasy/Combat/BasicAttackGenerator.cs

This file was deleted.

76 changes: 76 additions & 0 deletions src/OpenRpg.Genres.Fantasy/Combat/FantasyAttackGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using System;
using System.Linq;
using OpenRpg.Combat.Abilities;
using OpenRpg.Combat.Attacks;
using OpenRpg.Combat.Extensions;
using OpenRpg.Combat.Processors.Attacks.Entity;
using OpenRpg.Core.Extensions;
using OpenRpg.Core.Utils;
using OpenRpg.Entities.Stats.Variables;
using OpenRpg.Genres.Extensions;
using OpenRpg.Genres.Fantasy.Extensions;

namespace OpenRpg.Genres.Fantasy.Combat
{
public class FantasyAttackGenerator : IEntityAttackGenerator
{
public float DamageVariance { get; set; } = 0.05f;
public IRandomizer Randomizer { get; set; }

public FantasyAttackGenerator(IRandomizer randomizer)
{ Randomizer = randomizer; }

public Damage ApplyVariance(Damage damage)
{
if(damage.Value == 0) { return damage; }

var varianceAmount = damage.Value * DamageVariance;
var randomVariance = Randomizer.Random(-varianceAmount, varianceAmount);
damage.Value += randomVariance;
return damage;
}

public virtual (float scaledCritRate, float scaledCritMultiplier) GetScaledCriticalRateAndMultiplier(
EntityStatsVariables stats)
{
return (stats.CriticalDamageChance(), stats.CriticalDamageMultiplier());
}

public (bool DidCrit, Damage[] Damages) AttemptToCritical(Damage[] damages, EntityStatsVariables stats)
{
if(damages?.Length == 0) { return (false, Array.Empty<Damage>()); }

var scaledCritData = GetScaledCriticalRateAndMultiplier(stats);
var isCritical = Randomizer.ShouldCritical(scaledCritData.scaledCritRate);
if (!isCritical) { return (false, damages); }

damages.ForEach(x => x.Value *= scaledCritData.scaledCritMultiplier);
return (true, damages);
}

public virtual Attack GenerateAttack(EntityStatsVariables stats)
{
var damages = stats?.GetDamageReferences()
.Where(x => x.StatValue != 0)
.Select(x => ApplyVariance(new Damage(x.StatType, x.StatValue)))
.ToArray();

var outcome = AttemptToCritical(damages, stats);
return new Attack(outcome.Damages, outcome.DidCrit);
}

public virtual Attack GenerateAttack(Ability ability, EntityStatsVariables stats)
{
var baseDamage = ability.Template.Variables.Damage();
return GenerateAttack(baseDamage, stats);
}

public virtual Attack GenerateAttack(Damage damage, EntityStatsVariables stats)
{
damage.Value += stats.GetDamageFromDamageType(damage.Type);
ApplyVariance(damage);
var outcome = AttemptToCritical(new[] { damage }, stats);
return new Attack(outcome.Damages, outcome.DidCrit);
}
}
}
14 changes: 14 additions & 0 deletions src/OpenRpg.Genres.Scifi/Combat/ShipAttackGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Linq;
using OpenRpg.Combat.Abilities;
using OpenRpg.Combat.Attacks;
using OpenRpg.Combat.Extensions;
using OpenRpg.Combat.Processors.Attacks;
using OpenRpg.Genres.Scifi.Extensions;
using OpenRpg.Genres.Scifi.Variables;
Expand All @@ -17,5 +19,17 @@ public Attack GenerateAttack(ShipStatsVariables stats)

return new Attack(damages);
}

public Attack GenerateAttack(Ability ability, ShipStatsVariables stats)
{
var baseDamage = ability.Template.Variables.Damage();
return GenerateAttack(baseDamage, stats);
}

public Attack GenerateAttack(Damage damage, ShipStatsVariables stats)
{
damage.Value += stats.GetDamageFor(damage.Type);
return new Attack(new[] { damage });
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static float GetDefenseFor(this ShipStatsVariables stats, int effectType)
return 0;
}

public static float GetDefenseFromDamageType(this EntityStatsVariables stats, int damageType)
public static float GetDefenseFromDamageType(this ShipStatsVariables stats, int damageType)
{
if (damageType == ScifiDamageTypes.Ballistic) { return stats.BallisticDamage(); }
if (damageType == ScifiDamageTypes.Explosive) { return stats.ExplosiveDamage(); }
Expand All @@ -52,7 +52,7 @@ public static float GetDefenseFromDamageType(this EntityStatsVariables stats, in
return 0;
}

public static float GetDamageFor(this EntityStatsVariables stats, int effectType)
public static float GetDamageFor(this ShipStatsVariables stats, int effectType)
{
if (effectType == ScifiEffectTypes.BallisticDamageAmount) { return stats.BallisticDamage(); }
if (effectType == ScifiEffectTypes.ExplosiveDamageAmount) { return stats.ExplosiveDamage(); }
Expand Down
Loading