first commit

This commit is contained in:
2025-11-24 23:10:55 -06:00
commit 8315fa51c9
279 changed files with 74600 additions and 0 deletions

247
api/app/game_logic/dice.py Normal file
View File

@@ -0,0 +1,247 @@
"""
Dice mechanics module for Code of Conquest.
This module provides core dice rolling functionality using a D20 + modifier vs DC system.
All game chance mechanics (searches, skill checks, etc.) use these functions to determine
outcomes before passing results to AI for narration.
"""
import random
from dataclasses import dataclass
from typing import Optional
from enum import Enum
class Difficulty(Enum):
"""Standard difficulty classes for skill checks."""
TRIVIAL = 5
EASY = 10
MEDIUM = 15
HARD = 20
VERY_HARD = 25
NEARLY_IMPOSSIBLE = 30
class SkillType(Enum):
"""
Skill types and their associated base stats.
Each skill maps to a core stat for modifier calculation.
"""
# Wisdom-based
PERCEPTION = "wisdom"
INSIGHT = "wisdom"
SURVIVAL = "wisdom"
MEDICINE = "wisdom"
# Dexterity-based
STEALTH = "dexterity"
ACROBATICS = "dexterity"
SLEIGHT_OF_HAND = "dexterity"
LOCKPICKING = "dexterity"
# Charisma-based
PERSUASION = "charisma"
DECEPTION = "charisma"
INTIMIDATION = "charisma"
PERFORMANCE = "charisma"
# Strength-based
ATHLETICS = "strength"
# Intelligence-based
ARCANA = "intelligence"
HISTORY = "intelligence"
INVESTIGATION = "intelligence"
NATURE = "intelligence"
RELIGION = "intelligence"
# Constitution-based
ENDURANCE = "constitution"
@dataclass
class CheckResult:
"""
Result of a dice check.
Contains all information needed for UI display (dice roll animation)
and game logic (success/failure determination).
Attributes:
roll: The natural d20 roll (1-20)
modifier: Total modifier from stats
total: roll + modifier
dc: Difficulty class that was checked against
success: Whether the check succeeded
margin: How much the check succeeded or failed by (total - dc)
skill_type: The skill used for this check (if applicable)
"""
roll: int
modifier: int
total: int
dc: int
success: bool
margin: int
skill_type: Optional[str] = None
@property
def is_critical_success(self) -> bool:
"""Natural 20 - only relevant for combat."""
return self.roll == 20
@property
def is_critical_failure(self) -> bool:
"""Natural 1 - only relevant for combat."""
return self.roll == 1
def to_dict(self) -> dict:
"""Serialize for API response."""
return {
"roll": self.roll,
"modifier": self.modifier,
"total": self.total,
"dc": self.dc,
"success": self.success,
"margin": self.margin,
"skill_type": self.skill_type,
}
def roll_d20() -> int:
"""
Roll a standard 20-sided die.
Returns:
Integer from 1 to 20 (inclusive)
"""
return random.randint(1, 20)
def calculate_modifier(stat_value: int) -> int:
"""
Calculate the D&D-style modifier from a stat value.
Formula: (stat - 10) // 2
Examples:
- Stat 10 = +0 modifier
- Stat 14 = +2 modifier
- Stat 18 = +4 modifier
- Stat 8 = -1 modifier
Args:
stat_value: The raw stat value (typically 1-20)
Returns:
The modifier value (can be negative)
"""
return (stat_value - 10) // 2
def skill_check(
stat_value: int,
dc: int,
skill_type: Optional[SkillType] = None,
bonus: int = 0
) -> CheckResult:
"""
Perform a skill check: d20 + modifier vs DC.
Args:
stat_value: The relevant stat value (e.g., character's wisdom for perception)
dc: Difficulty class to beat
skill_type: Optional skill type for logging/display
bonus: Additional bonus (e.g., from equipment or proficiency)
Returns:
CheckResult with full details of the roll
"""
roll = roll_d20()
modifier = calculate_modifier(stat_value) + bonus
total = roll + modifier
success = total >= dc
margin = total - dc
return CheckResult(
roll=roll,
modifier=modifier,
total=total,
dc=dc,
success=success,
margin=margin,
skill_type=skill_type.name if skill_type else None
)
def get_stat_for_skill(skill_type: SkillType) -> str:
"""
Get the base stat name for a skill type.
Args:
skill_type: The skill to look up
Returns:
The stat name (e.g., "wisdom", "dexterity")
"""
return skill_type.value
def perception_check(wisdom: int, dc: int, bonus: int = 0) -> CheckResult:
"""
Convenience function for perception checks (searching, spotting).
Args:
wisdom: Character's wisdom stat
dc: Difficulty class
bonus: Additional bonus
Returns:
CheckResult
"""
return skill_check(wisdom, dc, SkillType.PERCEPTION, bonus)
def stealth_check(dexterity: int, dc: int, bonus: int = 0) -> CheckResult:
"""
Convenience function for stealth checks (sneaking, hiding).
Args:
dexterity: Character's dexterity stat
dc: Difficulty class
bonus: Additional bonus
Returns:
CheckResult
"""
return skill_check(dexterity, dc, SkillType.STEALTH, bonus)
def persuasion_check(charisma: int, dc: int, bonus: int = 0) -> CheckResult:
"""
Convenience function for persuasion checks (convincing, negotiating).
Args:
charisma: Character's charisma stat
dc: Difficulty class
bonus: Additional bonus
Returns:
CheckResult
"""
return skill_check(charisma, dc, SkillType.PERSUASION, bonus)
def lockpicking_check(dexterity: int, dc: int, bonus: int = 0) -> CheckResult:
"""
Convenience function for lockpicking checks.
Args:
dexterity: Character's dexterity stat
dc: Difficulty class
bonus: Additional bonus
Returns:
CheckResult
"""
return skill_check(dexterity, dc, SkillType.LOCKPICKING, bonus)