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>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user