b451f83174
Captures the pre-Godot-port state of the codebase. This is the rollback anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md). All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
62 lines
2.4 KiB
C#
62 lines
2.4 KiB
C#
namespace Theriapolis.Core.Rules.Combat;
|
|
|
|
/// <summary>
|
|
/// Per-attack situation modifiers. Flags compose: a Sneak Attack with
|
|
/// Advantage and Disadvantage (e.g. attacker prone, target shadowed)
|
|
/// cancels to a normal roll per d20 rules.
|
|
///
|
|
/// Phase 5 M4 wires the basic six (Advantage/Disadvantage and the four
|
|
/// resolver-time tags); class-feature flags like Reckless Attack come in
|
|
/// M6 once the feature engine reads from this enum.
|
|
/// </summary>
|
|
[System.Flags]
|
|
public enum SituationFlags : uint
|
|
{
|
|
None = 0,
|
|
Advantage = 1u << 0,
|
|
Disadvantage = 1u << 1,
|
|
/// <summary>Attacker is at long range — disadvantage on the roll per d20.</summary>
|
|
LongRange = 1u << 2,
|
|
/// <summary>Attacker has reach + a melee weapon vs. a target that has cover.</summary>
|
|
HalfCover = 1u << 3,
|
|
ThreeQuartersCover= 1u << 4,
|
|
/// <summary>Attacker meets the Sneak Attack precondition (advantage or ally adjacent).</summary>
|
|
SneakAttackEligible = 1u << 5,
|
|
/// <summary>Attacker is firing a ranged weapon at a target within 5 ft. — disadvantage.</summary>
|
|
RangedInMelee = 1u << 6,
|
|
}
|
|
|
|
public static class SituationFlagsExtensions
|
|
{
|
|
/// <summary>
|
|
/// True when the situation should roll the d20 with advantage. Per
|
|
/// d20 rules, advantage and disadvantage cancel exactly (no doubling).
|
|
/// </summary>
|
|
public static bool RollsAdvantage(this SituationFlags f)
|
|
{
|
|
bool adv = (f & SituationFlags.Advantage) != 0;
|
|
bool dis = (f & SituationFlags.Disadvantage) != 0
|
|
|| (f & SituationFlags.LongRange) != 0
|
|
|| (f & SituationFlags.RangedInMelee) != 0;
|
|
return adv && !dis;
|
|
}
|
|
|
|
/// <summary>True when the situation rolls with disadvantage (and no compensating advantage).</summary>
|
|
public static bool RollsDisadvantage(this SituationFlags f)
|
|
{
|
|
bool adv = (f & SituationFlags.Advantage) != 0;
|
|
bool dis = (f & SituationFlags.Disadvantage) != 0
|
|
|| (f & SituationFlags.LongRange) != 0
|
|
|| (f & SituationFlags.RangedInMelee) != 0;
|
|
return dis && !adv;
|
|
}
|
|
|
|
/// <summary>Cover modifier applied to AC: 0 / 2 / 5.</summary>
|
|
public static int CoverAcBonus(this SituationFlags f)
|
|
{
|
|
if ((f & SituationFlags.ThreeQuartersCover) != 0) return 5;
|
|
if ((f & SituationFlags.HalfCover) != 0) return 2;
|
|
return 0;
|
|
}
|
|
}
|