Files
TheriapolisV3/Theriapolis.Core/Rules/Character/HybridDetriments.cs
T
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

56 lines
2.6 KiB
C#

namespace Theriapolis.Core.Rules.Character;
/// <summary>
/// Phase 6.5 M4 — universal Hybrid detriments, applied automatically to
/// every <see cref="HybridState"/>-bearing character per
/// <c>theriapolis-rpg-clades.md</c> HYBRID ORIGIN section.
///
/// The four detriments are *invariant rules*, not authored content —
/// they don't vary per hybrid character — so they ship as code constants
/// rather than a JSON content block. (Plan §3.1's "HybridDetrimentsDef
/// loader" is documented as deviation: code constants are simpler and
/// match the design's universality.)
///
/// 1. <see cref="ScentDysphoriaSaveDc"/> — WIS save DC 10 imposed on the
/// first NPC interaction; failure → disadvantage on first CHA check.
/// 2. <see cref="IllegibleBodyLanguagePenalty"/> — disadvantage on
/// nonverbal CHA checks with purebred NPCs.
/// 3. <see cref="SocialStigmaFirstCheckPenalty"/> — -2 to first CHA check
/// with strangers in non-progressive settlements.
/// 4. <see cref="MedicalIncompatibilityMultiplier"/> — healing from
/// potions / Field Repair / Lay on Paws scaled by 0.75.
/// </summary>
public static class HybridDetriments
{
/// <summary>WIS save DC for Scent Dysphoria detection check.</summary>
public const int ScentDysphoriaSaveDc = 10;
/// <summary>Magnitude of the Social Stigma first-CHA-check penalty (negative).</summary>
public const int SocialStigmaFirstCheckPenalty = -2;
/// <summary>
/// Multiplier applied to healing received by a hybrid character.
/// 0.75 = three-quarters effective per <c>clades.md</c>; round down.
/// </summary>
public const float MedicalIncompatibilityMultiplier = 0.75f;
/// <summary>True if Illegible Body Language imposes disadvantage on the given check.</summary>
public static bool IllegibleBodyLanguagePenalty => true;
/// <summary>
/// Apply the Medical Incompatibility multiplier to a heal amount when
/// the recipient is a hybrid PC. Round down per <c>clades.md</c>.
/// Non-hybrid recipients pass through unchanged.
/// </summary>
public static int ScaleHealForHybrid(Character recipient, int rawHeal)
{
if (recipient.Hybrid is null) return rawHeal;
if (rawHeal <= 0) return rawHeal;
// Round down — clades.md says "function at 75% effectiveness (round
// down)". (int)(0.75 * 7) = 5; (int)(0.75 * 1) = 0 → clamp to 1
// because "no heal" is mechanically harsher than "small heal".
int scaled = (int)(rawHeal * MedicalIncompatibilityMultiplier);
return System.Math.Max(1, scaled);
}
}