# Decorators - Storybook Language Guide
Comprehensive documentation for the Storybook narrative simulation language

# Decorators

Decorators are special nodes that wrap a single child and modify its execution behavior. They enable timing control, retry logic, conditional execution, and result inversion without modifying the child node itself.

## What Are Decorators?

Decorators sit between a parent and child node, transforming the child’s behavior:

    Parent
      └─ Decorator
           └─ Child

The decorator intercepts the child’s execution, potentially:

- Repeating it multiple times
- Timing it out
- Inverting its result
- Guarding its execution
- Forcing a specific result

## Decorator Types

Storybook provides 10 decorator types:

Decorator | Purpose | Example
--- | --- | ---
`repeat` | Loop infinitely | `repeat { Patrol }`
`repeat(N)` | Loop N times | `repeat(3) { Check }`
`repeat(min..max)` | Loop min to max times | `repeat(2..5) { Search }`
`invert` | Flip success/failure | `invert { IsEnemy }`
`retry(N)` | Retry on failure (max N times) | `retry(5) { Open }`
`timeout(duration)` | Fail after duration | `timeout(10s) { Solve }`
`cooldown(duration)` | Run at most once per duration | `cooldown(30s) { Fire }`
`if(condition)` | Only run if condition true | `if(health > 50) { Attack }`
`succeed_always` | Always return success | `succeed_always { Try }`
`fail_always` | Always return failure | `fail_always { Test }`

## Syntax

    <decorator> ::= <repeat-decorator>
                  | <invert-decorator>
                  | <retry-decorator>
                  | <timeout-decorator>
                  | <cooldown-decorator>
                  | <if-decorator>
                  | <force-result-decorator>

    <repeat-decorator> ::= "repeat" <repeat-spec>? "{" <behavior-node> "}"

    <repeat-spec> ::= "(" <number> ")"
                    | "(" <number> ".." <number> ")"

    <invert-decorator> ::= "invert" "{" <behavior-node> "}"

    <retry-decorator> ::= "retry" "(" <number> ")" "{" <behavior-node> "}"

    <timeout-decorator> ::= "timeout" "(" <duration-literal> ")" "{" <behavior-node> "}"

    <cooldown-decorator> ::= "cooldown" "(" <duration-literal> ")" "{" <behavior-node> "}"

    <if-decorator> ::= "if" "(" <expression> ")" "{" <behavior-node> "}"

    <force-result-decorator> ::= ("succeed_always" | "fail_always") "{" <behavior-node> "}"

    <duration-literal> ::= <number> ("s" | "m" | "h" | "d")

## Repeat Decorators

### Infinite Repeat: `repeat`

Loops the child infinitely. The child is re-executed immediately after completing (success or failure).

    behavior InfinitePatrol {
        repeat {
            PatrolRoute
        }
    }

Execution:

1. Run child
2. Child completes (success or failure)
3. Immediately run child again
4. Go to step 2 (forever)

Use cases:

- Perpetual patrols
- Endless background processes
- Continuous monitoring

Warning: Infinite loops never return to parent. Ensure they’re appropriate for your use case.

### Repeat N Times: `repeat N`

Repeats the child exactly N times, then returns success.

    behavior CheckThreeTimes {
        repeat(3) {
            CheckDoor
        }
    }

Execution:

1. Counter = 0
2. Run child
3. Counter++
4. If counter < N, go to step 2
5. Return success

Use cases:

- Fixed iteration counts
- “Try three times then give up”
- Deterministic looping

### Repeat Range: `repeat min..max`

Repeats the child between min and max times. At runtime, a specific count is selected within the range.

    behavior SearchRandomly {
        repeat(2..5) {
            SearchArea
        }
    }

Execution:

1. Select count C randomly from [min, max]
2. Repeat child C times (as in `repeat N`)

Use cases:

- Variable behavior
- Procedural variation
- Non-deterministic actions

Validation:

- min ≥ 0
- max ≥ min
- Both must be integers

## Invert Decorator

Inverts the child’s return value: success becomes failure, failure becomes success.

    behavior AvoidEnemies {
        invert {
            IsEnemyNearby  // Success if NOT nearby
        }
    }

Truth table:

Child returns | Decorator returns
--- | ---
Success | Failure
Failure | Success
Running | Running (unchanged)

Use cases:

- Negating conditions (“if NOT X”)
- Inverting success criteria
- Converting “found” to “not found”

Example:

    behavior SafeExploration {
        choose safe_actions {
            // Only explore if NOT dangerous
            then explore {
                invert { IsDangerous }
                ExploreArea
            }

            // Default: Stay put
            Wait
        }
    }

## Retry Decorator

Retries the child up to N times on failure. Returns success if any attempt succeeds, failure if all N attempts fail.

    behavior PersistentDoor {
        retry(5) {
            OpenLockedDoor
        }
    }

Execution:

1. Attempts = 0
2. Run child
3. If child succeeds → return success
4. If child fails:
   - Attempts++
   - If attempts < N, go to step 2
   - Else return failure

Use cases:

- Unreliable actions (lockpicking, persuasion)
- Network/resource operations
- Probabilistic success

Example with context:

    behavior Thief_PickLock {
        then attempt_entry {
            // Try to pick lock (may fail)
            retry(3) {
                PickLock
            }

            // If succeeded, enter
            EnterBuilding

            // If failed after 3 tries, give up
        }
    }

Validation:

- N must be ≥ 1

## Timeout Decorator

Fails the child if it doesn’t complete within the specified duration.

    behavior TimeLimitedPuzzle {
        timeout(30s) {
            SolvePuzzle
        }
    }

Execution:

1. Start timer
2. Run child each tick
3. If child completes before timeout → return child’s result
4. If timer expires → return failure (interrupt child)

Use cases:

- Time-limited actions
- Preventing infinite loops
- Enforcing deadlines

Duration formats:

- `5s` - 5 seconds
- `10m` - 10 minutes
- `2h` - 2 hours
- `3d` - 3 days

Example:

    behavior QuickDecision {
        choose timed_choice {
            // Give AI 5 seconds to find optimal move
            timeout(5s) {
                CalculateOptimalStrategy
            }

            // Fallback: Use simple heuristic
            UseQuickHeuristic
        }
    }

Notes:

- Timer starts when decorator is first entered
- Timer resets if decorator exits and re-enters
- Child node should handle interruption gracefully

## Cooldown Decorator

Prevents the child from running more than once per cooldown period. Fails immediately if called within cooldown.

    behavior SpecialAbility {
        cooldown(30s) {
            FireCannon
        }
    }

Execution:

1. Check last execution time
2. If (current_time - last_time) < cooldown → return failure
3. Else:
   - Run child
   - Record current_time as last_time
   - Return child’s result

Use cases:

- Rate-limiting abilities
- Resource cooldowns (spells, items)
- Preventing spam

Example:

    behavior Mage_SpellCasting {
        choose spells {
            // Fireball: 10 second cooldown
            cooldown(10s) {
                CastFireball
            }

            // Lightning: 5 second cooldown
            cooldown(5s) {
                CastLightning
            }

            // Basic attack: No cooldown
            MeleeAttack
        }
    }

State management:

- Cooldown state persists across behavior tree ticks
- Each cooldown decorator instance has independent state
- Cooldown timers are per-entity (not global)

## If Decorator

Only runs the child if the condition is true. Fails immediately if condition is false.

    behavior ConditionalAttack {
        if(health > 50) {
            AggressiveAttack
        }
    }

Execution:

1. Evaluate condition expression
2. If true → run child and return its result
3. If false → return failure (do not run child)

Use cases:

- Preconditions (“only if X”)
- Resource checks (“only if have mana”)
- Safety checks (“only if safe”)

Expression syntax: See Expression Language for complete syntax.

Examples:

    behavior GuardedActions {
        choose options {
            // Only attack if have weapon and enemy close
            if(has_weapon and distance < 10) {
                Attack
            }

            // Only heal if health below 50%
            if(health < (max_health * 0.5)) {
                Heal
            }

            // Only flee if outnumbered
            if(enemy_count > ally_count) {
                Flee
            }
        }
    }

Comparison with bare `if` conditions:

    // Using bare 'if' condition (checks every tick, no body)
    then approach_and_attack {
        if(enemy_nearby)
        Approach
        Attack
    }

    // Using 'if' decorator with body (precondition check, fails fast)
    if(enemy_nearby) {
        then do_attack {
            Approach
            Attack
        }
    }

The `if` decorator with a body is more efficient for gating expensive subtrees.

## Force Result Decorators

### `succeed_always`

Always returns success, regardless of child’s actual result.

    behavior TryOptionalTask {
        succeed_always {
            AttemptBonus  // Even if fails, we don't care
        }
    }

Use cases:

- Optional tasks that shouldn’t block progress
- Logging/monitoring actions
- Best-effort operations

Example:

    behavior QuestSequence {
        then main_quest {
            TalkToNPC

            // Try to find secret, but don't fail quest if not found
            succeed_always {
                SearchForSecretDoor
            }

            ReturnToQuestGiver
        }
    }

### `fail_always`

Always returns failure, regardless of child’s actual result.

    behavior TestFailure {
        fail_always {
            AlwaysSucceedsAction  // But we force it to fail
        }
    }

Use cases:

- Testing/debugging
- Forcing alternative paths
- Disabling branches temporarily

Example:

    behavior UnderConstruction {
        choose abilities {
            // Temporarily disabled feature
            fail_always {
                NewExperimentalAbility
            }

            // Fallback to old ability
            ClassicAbility
        }
    }

## Combining Decorators

Decorators can nest to create complex behaviors:

    behavior ComplexPattern {
        // Repeat 3 times, each with 10 second timeout
        repeat(3) {
            timeout(10s) {
                SolveSubproblem
            }
        }
    }

More complex nesting:

    behavior ResilientAction {
        // If: Only if health > 30
        if(health > 30) {
            // Timeout: Must complete in 20 seconds
            timeout(20s) {
                // Retry: Try up to 5 times
                retry(5) {
                    // Cooldown: Can only run once per minute
                    cooldown(1m) {
                        PerformComplexAction
                    }
                }
            }
        }
    }

Execution order: Outside → Inside

1. If checks condition
2. Timeout starts timer
3. Retry begins first attempt
4. Cooldown checks last execution time
5. Child action runs

## Duration Syntax

Timeout and cooldown decorators use duration literals:

    <duration-literal> ::= <number> <unit>

    <unit> ::= "s"    // seconds
             | "m"    // minutes
             | "h"    // hours
             | "d"    // days

    <number> ::= <digit>+

Examples:

- `5s` - 5 seconds
- `30s` - 30 seconds
- `2m` - 2 minutes
- `10m` - 10 minutes
- `1h` - 1 hour
- `24h` - 24 hours
- `7d` - 7 days

Validation:

- Number must be positive integer
- No compound durations (use `120s` not `2m` if runtime expects seconds)
- No fractional units (`1.5m` not allowed; use `90s`)

## Comparison Table

Decorator | Affects Success | Affects Failure | Affects Running | Stateful
--- | --- | --- | --- | ---
`repeat` | Repeat | Repeat | Wait | Yes (counter)
`repeat N` | Repeat | Repeat | Wait | Yes (counter)
`repeat min..max` | Repeat | Repeat | Wait | Yes (counter)
`invert` | → Failure | → Success | Unchanged | No
`retry N` | → Success | Retry or fail | Wait | Yes (attempts)
`timeout dur` | → Success | → Success | → Failure if expired | Yes (timer)
`cooldown dur` | → Success | → Success | → Success | Yes (last time)
`if(expr)` | → Success | → Success | → Success | No
`succeed_always` | → Success | → Success | → Success | No
`fail_always` | → Failure | → Failure | → Failure | No

Stateful decorators maintain state across ticks. Stateless decorators evaluate fresh every tick.

## Validation Rules

1. Child required: All decorators must have exactly one child node
2. Repeat count: `repeat N` requires N ≥ 0
3. Repeat range: `repeat min..max` requires 0 ≤ min ≤ max
4. Retry count: `retry N` requires N ≥ 1
5. Duration positive: Timeout/cooldown durations must be > 0
6. Duration format: Must match `<number><unit>` (e.g., `10s`, `5m`)
7. Guard expression: Guard condition must be valid expression
8. No empty decorators: `repeat { }` is invalid (missing child)

## Use Cases by Category

### Timing Control

- timeout: Prevent infinite loops, enforce time limits
- cooldown: Rate-limit abilities, prevent spam
- repeat: Continuous processes, patrols

### Reliability

- retry: Handle unreliable actions, probabilistic success
- if: Precondition checks, resource validation
- succeed_always: Optional tasks, best-effort

### Logic Control

- invert: Negate conditions, flip results
- fail_always: Disable branches, testing

### Iteration

- repeat N: Fixed loops, deterministic behavior
- repeat min..max: Variable loops, procedural variation

## Best Practices

### 1. Use Guards for Expensive Checks

Avoid:

    then expensive {
        if(complex_condition)
        ExpensiveOperation
    }

Prefer:

    if(complex_condition) {
        ExpensiveOperation  // Only runs if condition passes
    }

### 2. Combine Timeout with Retry

Avoid: Infinite retry loops

Prefer:

    timeout(30s) {
        retry(5) {
            UnreliableAction
        }
    }

### 3. Use Cooldowns for Rate Limiting

Avoid: Manual timing in actions

Prefer:

    cooldown(10s) {
        FireCannon
    }

### 4. Invert for Readable Conditions

Avoid:

    choose options {
        then branch_a {
            if(not is_dangerous)
            Explore
        }
    }

Prefer:

    choose options {
        then branch_a {
            invert { IsDangerous }
            Explore
        }
    }

### 5. succeed_always for Optional Tasks

Avoid:

    then quest {
        MainTask
        choose optional {
            BonusTask
            DoNothing  // Awkward fallback
        }
        NextTask
    }

Prefer:

    then quest {
        MainTask
        succeed_always { BonusTask }  // Try bonus, don't fail quest
        NextTask
    }

## Cross-References

- Behavior Trees - Using decorators in behavior trees
- Expression Language - Guard condition syntax
- Value Types - Duration literals
- Design Patterns - Common decorator patterns

## Related Concepts

- Composability: Decorators can nest for complex control flow
- Separation of concerns: Decorators handle control flow, children handle logic
- State management: Stateful decorators (repeat, retry, timeout, cooldown) persist across ticks
- Performance: Guards prevent unnecessary child execution