Timed window
timed-window-1
This contract defines the behaviour of timed windows: i-frames, a cooldown, or a status effect.
It decides how i-frames, cooldowns, and status effects repeat, keep or lose time while play is suspended, end early, or expire.
- 4 questions
- no numbers
- 1 list
- 7 tests
Use in your game
Opens the authoring tool with this contract added and its questions unanswered. Or download the ZIP and add it later.
What is in the ZIP
The ZIP holds the contract and its acceptance tests. In the authoring tool, choose Add contract and pick this ZIP. If you keep your design as files, put them in contracts/ and fill in the answers there.
4 questions per window
You answer these once for each window.
- The unit used by the duration and its clock.
- For a window whose clock runs with play — seconds, frames, or ticks — whether that clock pauses with ordinary play.
- What a new opening does while this window is already open.
- Whether the window can close before its duration ends.
Lists1 list
Some settings are lists of rows.
A reference points to a number or a rule in your design. For a number, use its address in your tuning. For a rule, use its file and heading, such as 02-mechanics.md#recovery. Each field's description says what it needs.
Windows
windows
List every named window. An empty list is a claim its author must defend. A cap uses the window's unit and cannot be shorter than its normal duration. The duration unit must match the clock. A real-time window cannot use turns to avoid the suspension choice. The validator (the checking tool) cannot check this; a reviewer does.
Each row is: id, opens-at, duration, duration-unit, clock, while-suspended, on-retrigger, retrigger-cap, ends-early, early-end.
Every field
| Field | Kind | When it appears | Meaning |
|---|---|---|---|
id |
string | Required | The window's stable name as your game writes it. A poison effect might be named poison. |
opens-at |
reference | Required | Where your fixed game prose says what opens the window. A poison window might open when a poisoned attack lands. |
duration |
reference | Required | Where your game states how long the window lasts. Cite a number for a fixed duration, or fixed prose for a duration calculated from game state. The value is read when the window opens. For example, poison may read its turn count when the hit lands. |
duration-unit |
choice: seconds, frames, ticks, turns | Required | The unit used by the duration and its clock. Seconds measure real time. Frames count updates. Ticks count clock steps. Turns count game turns. A poison effect might use turns. |
clock |
reference | Required | Where your fixed game prose names the clock that closes this window. A poison effect may use the turn clock. |
while-suspended |
choice: stops, keeps-running | Present when row duration unit is Seconds or Frames or Ticks. | For a window whose clock runs with play — seconds, frames, or ticks — whether that clock pauses with ordinary play. If it stops, an invulnerability window keeps all its remaining time during a pause. If it keeps running, the window can expire before play resumes. |
on-retrigger |
choice: ignore, new-duration, keep-longer, extend-to-cap, stack | Required | What a new opening does while this window is already open. Ignore leaves the poison window unchanged. New duration replaces its remaining time with the duration from the new poison hit. Keep longer uses whichever time is longer. Extend to cap adds time without passing its cap. Stack opens another independent poison copy. Only stacking creates a new copy. Every other choice continues the current copy and keeps one opening in its history. |
retrigger-cap |
reference | Present when row on retrigger is Extend to cap. | Where your game states the largest amount of time that can remain after an extension. A poison effect may cap all extensions at its maximum duration. Add this only when repeat openings extend up to a cap. Use the same unit as the duration. |
ends-early |
choice: expiry-only, declared-ending | Required | Whether the window can close before its duration ends. Expiry only keeps a poison effect open until time runs out. A declared ending lets a cure close every open poison copy on the entity it cures, unless the cited prose names more. |
early-end |
reference | Present when row ends early is Declared ending. | Where your fixed game prose names every event or condition that ends this window early. This includes using or cancelling it. For poison, this may be an antidote or cleansing the target. Add this only when the window can end early. |
For builders
Exact mechanism wording and 7 pack tests
Exact mechanism wording
Each row declares one timed window. The row cites the game's own Fixed material for what opens it, its duration, and the clock that advances it; the contract owns none of those game-specific rules or numbers. An opening is an event of the entity the window is given to. Each entity that the game's rules give the window gets its own instance, opened, advanced, and closed by that entity's own events, unless the adoption's Fixed prose explicitly names the window as shared. This per-entity reading is binding for every sentence and generated check that speaks of open copies. The validator cannot check this; a reviewer does.
When the cited opening occurs, the duration is read once and the window opens for that duration; later changes to the cited number or calculation do not move an open copy's endpoint. A fixed duration cites its tuning number; a duration computed from game state cites the Fixed prose that defines the calculation. A window includes its named last moment: it is still open exactly when the cited clock has advanced by that duration, and closed at any point after that, unless its row says it can end early.
A row's on-retrigger answer applies when its opening occurs again while that window is open. ignore leaves the open copy unchanged. new-duration replaces its remaining time with the newly granted duration. keep-longer keeps whichever is longer: the remaining time or the newly granted duration. extend-to-cap adds the newly granted duration to the time remaining, but never leaves more than the row's cited cap. The same open copy continues under ignore, new-duration, keep-longer, and extend-to-cap, and its history shows one opening; only stack creates a new copy. stack opens another independent copy and leaves every open copy unchanged. A game whose extension has a largest permitted duration names that duration as its cap; a game that permits no largest duration states the exception in its own prose and adopts this contract as promised rather than checked. A game whose stacking has a largest number of open copies states that limit in its own prose and adopts this row as promised rather than checked; this contract does not count copies.
Under expiry-only, nothing closes any open copy before its duration ends; a retrigger's own rewrite of an open copy's remaining time is not an early closure. Under declared-ending, the event or condition cited by the row closes every open copy on the entity the ending happens to, unless the cited prose names more; this covers copies being used, cancelled, dispelled, or otherwise ended by the game.
stops means the row's clock does not advance while ordinary play is suspended. keeps-running means it does. The cited clock definition decides what ordinary play being suspended means; this contract does not define pause or catch-up behavior.
The answers belong to each window row, not to the game as a whole. If one apparent window follows different repeat-trigger rules for different opening causes, this version does not model those causes separately; the game must name them as separate windows or state the exception in its own prose.
Verification pack
sha256:0b00f8a7b2f1f165dbffc65ea394d7fad1cb9fdf6dc123b74bf78c675ad138ed
The format calls an adoption with its matching pack Checked: the tests travel with it, but a game has not necessarily passed them. Without the pack the adoption is Promised: the builder still owes the chosen behavior.
7 pack tests
Placeholders are filled from the adoption's answers, values, rows, and verification inputs.
the declared window list matches the game
declared-window-set
Applies for every adoption
The window list in Instance is complete for Inputs scope: every window in scope has one row, no window has two rows, and no row names something outside the scope.
- Scope
Inputs scope- Holds
every timed window in scope has exactly one row in
Instance, and every row inInstancenames a timed window in scope
Row.id opens and expires on its declared clock
opens-and-expires
Applies for every adoption
Row.id opens on the occurrence defined at Row.opens at, reads its Row.duration unit duration from Row.duration, and closes after that much progress on the clock defined at Row.clock.
- Given
the
Row.idwindow closed, with its opening defined atRow.opens at, its duration atRow.durationinRow.duration unit, and its clock atRow.clock- When
- the opening defined at
Row.opens atoccurs once, with no repeat trigger and no declared early ending
- the opening defined at
- Then
Row.idbecomes open when that occurrence happens- a change to the value or calculation at
Row.durationafter that moment does not move this copy's endpoint; the copy still closes after the duration read at opening - it is still open when the clock at
Row.clockhas advanced by exactly that duration - it is closed at the first observable step after the clock has advanced beyond that duration
- Diagnostics
Instance-Row.id-open-close-traceInstance-Row.id-clock-trace
Row.id handles a repeat trigger in the declared way
retrigger-behavior
Applies when row on retrigger is Ignore or New duration or Keep longer or Stack.
Repeat triggers of Row.id follow one rule: Bind retrigger claim. The worked arithmetic fixes the meaning even when the game's own duration uses another number or unit.
- Scope
repeat triggers of
Row.idwhile at least one copy is open- Holds
Bind retrigger claim- Diagnostics
Instance-Row.id-trigger-traceInstance-Row.id-remaining-time-traceInstance-Row.id-open-copy-count
Row.id extends on a repeat trigger without passing its cap
retrigger-extends-to-cap
Applies when row on retrigger is Extend to cap.
Repeat triggers extend Row.id without passing the cap at Row.retrigger cap. The worked cases leave twelve units when four remain and ten are added under a cap of twelve, and nine when four remain and five are added, fixing both the addition and the cap.
- Scope
repeat triggers of
Row.idwhile one copy is open- Holds
a repeat trigger adds the newly granted duration to the remaining time without passing the cap at
Row.retrigger cap; the arithmetic gives twelve units when four remain, ten are added, and the cap is twelve, and gives nine units when four remain, five are added, and the cap is twelve- Diagnostics
Instance-Row.id-trigger-traceInstance-Row.id-remaining-time-trace
Row.id cannot end early
expiry-is-the-only-ending
Applies when row ends early is Expiry only.
Row.id has no early ending: using it, removing related state, or changing the world does not close it. A retrigger's own rewrite of remaining time is not an early closure. Only its duration ending closes the copy.
- Scope
the finite list of events and world changes that the game's Fixed prose associates with
Row.id, plus its game-local acceptance-test sample of ordinary play while a copy is open with time remaining- Holds
no event or world change in scope closes any open
Row.idcopy before its duration ends; a copy's remaining time changes only through ordinary progress on the clock atRow.clockor through this row's declared repeat-trigger behavior; a retrigger's own rewrite of remaining time is not an early closure- Diagnostics
Instance-Row.id-open-close-trace
Row.id closes at its declared early ending
declared-ending-closes
Applies when row ends early is Declared ending.
Every open Row.id copy on the entity the ending happens to closes when the event or condition defined at Row.early end occurs, unless the cited prose names more. Remaining duration does not delay an affected copy's ending.
- Given
one or more
Row.idcopies open with time remaining, with their early ending defined atRow.early end- When
- one early-ending event or condition defined at
Row.early endoccurs
- one early-ending event or condition defined at
- Then
- every open
Row.idcopy on the entity the ending happens to closes at that occurrence, unless the prose atRow.early endnames more - no remaining duration keeps any affected copy open
- every open
- Diagnostics
Instance-Row.id-early-ending-trace
Row.id treats suspended play in the declared way
suspension-behavior
Applies when row duration unit is Seconds or Frames or Ticks.
Suspended play leaves an observable answer for every Row.id copy: Bind suspension result. Each remaining-time trace is read during the suspension so the two answers cannot pass on the same later state.
- Given
one or more
Row.idcopies open, with an observed copy having fourRow.duration unitleft and a remaining-time trace for every copy- When
- ordinary play is suspended for an interval that would advance the clock at
Row.clockby sixRow.duration unitduring ordinary play, while that clock and every open copy are observed
- ordinary play is suspended for an interval that would advance the clock at
- Then
Bind suspension result- the remaining-time trace shows whether time advanced during the suspension, even if the stored open state after play resumes could look the same
- Diagnostics
Instance-Row.id-remaining-time-traceInstance-Row.id-suspension-trace