# SPDX-FileCopyrightText: 2025 2025 # SPDX-FileContributor: Gergely Polonkai # # SPDX-License-Identifier: GPL-3.0-or-later """Calculate the odds using Mythic RPG’s Fate Chart""" from enum import Enum from .dice import Die class FateOutcome(Enum): """Possible outcomes""" EXC_YES = "eyes" YES = "yes" NO = "no" EXC_NO = "eno" class FateOdds(Enum): """Odds of a “yes” answer""" IMPOSSIBLE = 0 NO_WAY = 1 VERY_UNLIKELY = 2 UNLIKELY = 3 FIFTY_FIFTY = 4 SOMEWHAT_LIKELY = 5 LIKELY = 6 VERY_LIKELY = 7 NEAR_SURE_THING = 8 SURE_THING = 9 HAS_TO_BE = 10 HAS_TO_BE2 = 11 TABLE: dict[FateOdds, list[tuple[int, int, int]]] = { FateOdds.IMPOSSIBLE: [ (0, -20, 77), (0, 0, 81), (0, 0, 81), (1, 5, 82), (1, 5, 82), (2, 10, 83), (3, 15, 84), (5, 25, 86), (10, 50, 91), ], FateOdds.NO_WAY: [ (0, 0, 81), (1, 5, 82), (1, 5, 82), (2, 10, 83), (3, 15, 84), (5, 25, 86), (7, 35, 88), (10, 50, 91), (15, 75, 96), ], FateOdds.VERY_UNLIKELY: [ (1, 5, 82), (1, 5, 82), (2, 10, 83), (3, 15, 84), (5, 25, 86), (9, 45, 90), (10, 50, 91), (13, 65, 94), (16, 85, 97), ], FateOdds.UNLIKELY: [ (1, 5, 82), (2, 10, 83), (3, 15, 84), (4, 20, 85), (7, 35, 88), (10, 50, 91), (11, 55, 92), (15, 75, 96), (18, 90, 99), ], FateOdds.FIFTY_FIFTY: [ (2, 10, 83), (3, 15, 84), (5, 25, 86), (7, 35, 88), (10, 50, 91), (13, 65, 94), (15, 75, 96), (16, 85, 97), (19, 95, 100), ], FateOdds.SOMEWHAT_LIKELY: [ (4, 20, 85), (5, 25, 86), (9, 45, 90), (10, 50, 91), (13, 65, 94), (16, 80, 97), (16, 85, 97), (18, 90, 99), (19, 95, 100), ], FateOdds.LIKELY: [ (5, 25, 86), (7, 35, 88), (10, 50, 91), (11, 55, 92), (15, 75, 96), (16, 85, 97), (18, 90, 99), (19, 95, 100), (20, 100, 0), ], FateOdds.VERY_LIKELY: [ (9, 45, 90), (10, 50, 91), (13, 65, 94), (15, 75, 96), (16, 85, 97), (18, 90, 99), (19, 95, 100), (19, 95, 100), (21, 105, 0), ], FateOdds.NEAR_SURE_THING: [ (10, 50, 91), (11, 55, 92), (15, 75, 96), (16, 80, 97), (18, 90, 99), (19, 95, 100), (19, 95, 100), (20, 100, 0), (23, 115, 0), ], FateOdds.SURE_THING: [ (11, 55, 92), (13, 65, 94), (16, 80, 97), (16, 85, 97), (18, 90, 99), (19, 95, 100), (19, 95, 100), (22, 110, 0), (25, 125, 0), ], FateOdds.HAS_TO_BE: [ (16, 80, 97), (16, 85, 97), (18, 90, 99), (19, 95, 100), (19, 95, 100), (20, 100, 0), (20, 100, 0), (26, 130, 0), (26, 145, 0), ], FateOdds.HAS_TO_BE2: [ (18, 90, 99), (19, 95, 100), (19, 95, 100), (20, 100, 0), (22, 110, 0), (24, 120, 0), (24, 120, 0), (30, 150, 0), (29, 165, 0), ], } def decide(odds: FateOdds, chaos_level: int = 5) -> FateOutcome: """Decide the outcome of a situation using the Fate Chart""" # Chaos levels range from 1 and 9 (both included), but list indices start at 0 chaos_level -= 1 eyes, yes, eno = TABLE[odds][chaos_level] value = Die("d100").roll() if value <= eyes: return FateOutcome.EXC_YES if value <= yes: return FateOutcome.YES if value >= eno: return FateOutcome.EXC_NO return FateOutcome.NO