Files
Christopher Wiebe b451f83174 Initial commit: Theriapolis baseline at port/godot branch point
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>
2026-04-30 20:40:51 -07:00

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;
}
}