Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions grimoire-runner/src/grimoire_runner/executors/table_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import TYPE_CHECKING, Any

from ..integrations.dice_integration import DiceIntegration
from ..models.roll_result import RollResult, TableRollResult
from .base import BaseStepExecutor

if TYPE_CHECKING:
Expand All @@ -20,6 +21,17 @@ class TableExecutor(BaseStepExecutor):
def __init__(self):
self.dice_integration = DiceIntegration()

def _dice_result_to_roll_result(self, dice_result) -> RollResult:
"""Convert a DiceResult from DiceIntegration to a RollResult."""
return RollResult(
total=dice_result.total,
detail=dice_result.detailed_result
or f"{dice_result.total} ({dice_result.expression})",
expression=dice_result.expression,
breakdown=dice_result.breakdown,
individual_rolls=dice_result.rolls,
)

def execute(
self, step: "StepDefinition", context: "ExecutionContext", system: "System"
) -> "StepResult":
Expand Down Expand Up @@ -87,6 +99,9 @@ def _execute_table_roll(
dice_result = self.dice_integration.roll_expression("1d100")
roll_value = dice_result.total

# Convert dice result to RollResult
roll_result = self._dice_result_to_roll_result(dice_result)

# Get the result from the table
table_result = table.get_entry_by_range(roll_value)
if table_result is None:
Expand All @@ -102,14 +117,12 @@ def _execute_table_roll(
f"table_result={table_result}, typed_result type={type(typed_result).__name__}"
)

result_data = {
"table": table_name,
"roll": roll_value,
"result": typed_result,
"dice_expression": table.roll or "1d100",
}
# Create the TableRollResult object
table_roll_result = TableRollResult(
entry=typed_result, roll_result=roll_result
)

results.append(result_data)
results.append(table_roll_result)

# Log the individual table roll result
logger.debug(
Expand All @@ -119,10 +132,10 @@ def _execute_table_roll(
# Execute table actions with result context
if table_roll.actions:
logger.debug(
f"Executing table actions with typed_result: {type(typed_result).__name__}"
f"Executing table actions with table_roll_result: {type(table_roll_result).__name__}"
)
self._execute_table_actions(
table_roll.actions, context, system, typed_result, results
table_roll.actions, context, system, table_roll_result, results
)

# If only one result, return it directly, otherwise return list
Expand Down
3 changes: 2 additions & 1 deletion grimoire-runner/src/grimoire_runner/models/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ class OutputDefinition:
id: str
validate: bool = False
description: str | None = None
enum: list[str] | None = None


@dataclass
@dataclass
class VariableDefinition:
"""Flow variable definition."""
Expand All @@ -49,6 +49,7 @@ class VariableDefinition:
type: str = "unknown"
description: str | None = None
default: Any = None # Default value for the variable
enum: list[str] | None = None


@dataclass
Expand Down
20 changes: 20 additions & 0 deletions grimoire-runner/src/grimoire_runner/models/roll_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,23 @@ def __eq__(self, other) -> bool:
def __ne__(self, other) -> bool:
"""Inequality comparison based on total."""
return not self.__eq__(other)


@dataclass
class TableRollResult:
"""Result of a table roll operation containing both the entry and roll information."""

entry: Any
"""The entry selected from the table (type depends on table's entry_type)."""

roll_result: RollResult
"""The RollResult object for the dice roll that was performed."""

def __str__(self) -> str:
"""String representation shows the entry and roll details."""
return f"{self.entry} (rolled {self.roll_result.total})"

@property
def result(self) -> Any:
"""Alias for entry to support legacy template usage."""
return self.entry
9 changes: 6 additions & 3 deletions grimoire-runner/src/grimoire_runner/ui/rich_tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@
}


def get_step_start_message(step_type: StepType) -> str:
"""Get generic start message for a step type."""
def get_step_start_message(step_type: StepType, step_prompt: str = None) -> str:
"""Get start message for a step type, prioritizing custom prompt."""
emoji = STEP_TYPE_EMOJIS.get(step_type, "⚙️")

if step_prompt:
return f"{emoji} {step_prompt}"

messages = {
StepType.DICE_ROLL: "Rolling dice...",
StepType.DICE_SEQUENCE: "Rolling dice sequence...",
Expand Down Expand Up @@ -405,7 +408,7 @@ def execute_flow(self, flow_obj, context, system) -> bool:
def _execute_single_step(self, step, step_num: int) -> tuple[bool, str | None]:
"""Execute a single step."""
# Show generic start message for step type
start_message = get_step_start_message(step.type)
start_message = get_step_start_message(step.type, step.prompt)
self._print_indented(f"[cyan]{start_message}[/cyan]")

# Special handling for flow_call steps to show sub-flow execution
Expand Down
77 changes: 77 additions & 0 deletions grimoire-runner/tests/systems/flow_test/flows/enum-flow.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Test flow demonstrating enum support for inputs, outputs, and variables
id: "enum-flow"
type: "flow"
name: "Enum Test Flow"
description: "Flow demonstrating enum parameter support"
version: "1.0"

inputs:
- id: "difficulty"
type: "str"
enum: ["easy", "medium", "hard"]
required: true
description: "Game difficulty level"
- id: "character_class"
type: "str"
enum: ["warrior", "mage", "rogue"]
required: true
description: "Character class selection"

outputs:
- id: "battle_result"
type: "str"
enum: ["victory", "defeat", "draw"]
description: "The outcome of the battle"
- id: "initiative_side"
type: "str"
enum: ["players", "enemies"]
description: "Which side has initiative"

variables:
- id: "current_phase"
type: "str"
enum: ["preparation", "combat", "resolution"]
default: "preparation"
description: "Current phase of the encounter"
- id: "player_status"
type: "str"
enum: ["healthy", "wounded", "critical"]
default: "healthy"
description: "Player's current health status"

steps:
- id: "start"
name: "Initialize Battle"
type: "completion"
prompt: "Starting battle with difficulty: {{ inputs.difficulty }}, class: {{ inputs.character_class }}"
actions:
- type: "set_value"
data:
path: "variables.current_phase"
value: "combat"
next_step: "determine_initiative"

- id: "determine_initiative"
name: "Roll Initiative"
type: "dice_roll"
roll: "1d6"
actions:
- type: "set_value"
data:
path: "outputs.initiative_side"
value: "{% if result.total > 3 %}players{% else %}enemies{% endif %}"
next_step: "battle_resolution"

- id: "battle_resolution"
name: "Resolve Battle"
type: "completion"
prompt: "Battle resolving with {{ outputs.initiative_side }} having initiative"
actions:
- type: "set_value"
data:
path: "outputs.battle_result"
value: "{% if inputs.difficulty == 'easy' %}victory{% elif inputs.difficulty == 'hard' %}defeat{% else %}draw{% endif %}"
- type: "set_value"
data:
path: "variables.current_phase"
value: "resolution"
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ steps:
- type: "set_value"
data:
path: "outputs.character.name"
value: "{{ result }}"
value: "{{ result.entry }}"
Loading