Time loops as bookkeeping: the world snaps back, the player’s knowledge does not - LoopCore.js
Time loops as bookkeeping: the world snaps back, the player’s knowledge does not(Author:CSAF — Core Systems Asset Factory) - LoopCore.js
https://en.plugin-mz.fungamemake.com/archives/12512
A loop plugin that clears state it does not own breaks the rest of your game on the second loop. This one only ever touches the ids you list.
Plugin desc :
A loop plugin that clears state it does not own breaks the rest of your game on the second loop. This one only ever touches the ids you list.
License :
・Copyright: Retained
・Commercial Use: Allowed
・Modification: Allowed
・Redistribution: Prohibited (This does not apply to works made using the material.)
・Details: See Download Page / In-plugin documentation
============================================================================
Loop Core — the world resets, the player does not
============================================================================
Majora's Mask, Outer Wilds, Deathloop, 12 Minutes. The mechanic is simple to
describe and miserable to hand-roll, because it is not really about time. It
is about bookkeeping: what snaps back, what survives, what the game must
remember that the world has forgotten, and how the player is shown any of it.
Loop Core is that bookkeeping.
THE THREE IDEAS
---------------
ANCHOR The moment a loop starts. Set it once. Every rewind returns
the world to exactly this state.
REWIND Put the world back. Switches, variables, self-switches, party
position and condition — all of it as it was at the anchor.
Then advance the loop counter.
KNOWLEDGE What the player keeps. Facts, carried items, and the record of
what they changed. A rewind cannot touch any of it.
THE SAFETY RULE THAT MATTERS MOST
---------------------------------
Loop Core only ever touches ids you list in World switches and World
variables. Everything else in your project — every other plugin's switches,
every variable you use for something that is not the world — is not read, not
written and not rewound. There is no "reset everything" mode, deliberately.
A loop plugin that clears state it does not own is a plugin that breaks the
rest of your game on the second loop.
LOOP-GATED EVENTS, WITHOUT SCRIPT CALLS
---------------------------------------
Point "Loop counter variable" at a variable and Loop Core keeps it equal to
the current loop number. Now every ordinary Conditional Branch in your game
can gate on the loop with no scripting at all:
Conditional Branch: Variable [Loop] ≥ 3
For knowledge, the script conditions read like sentences:
$gameLoop.knows('mayor_lies')
$gameLoop.loopIndex() ≥ 3
$gameLoop.learnedThisLoop('mayor_lies')
$gameLoop.divergedFrom('saved_the_smith')
THE HONEST WAY TO WRITE A LOOP
------------------------------
1. Build your day as an ordinary map. Do not think about looping yet.
2. At the moment the day starts, call Set the anchor.
3. Wherever the player learns something, call Learn a fact.
4. Wherever the day ends — death, midnight, a choice — call Rewind.
5. Gate the dialogue that should change on knows() and the loop counter.
That is the whole workflow. The Ledger is generated from it; you never
author the Ledger.
WHAT SURVIVES A REWIND
----------------------
always facts, divergence pins, the loop counter, the Ledger
if declared items in "Items that survive", switches in "Switches that survive"
never anything inside the world ranges that is not declared to survive
untouched every id outside the world ranges, whatever it belongs to
SAVE COMPATIBILITY
------------------
Loop Core stores its state in a versioned record with a migration path, and
it stores player-supplied ids in ARRAYS rather than as object keys. That is
not a style preference: an object key taken from author-supplied text can be
`__proto__`, which in JavaScript sets the prototype instead of storing a
value, and a null-prototype object then breaks MZ's own save serialiser for
the entire game. Arrays cannot express that bug.
Adding Loop Core to an existing save works. Removing it leaves the rest of
the save intact.
============================================================================
Compatible with the rest of the CSAF catalogue
============================================================================
Chronicle Core — https://csaf.itch.io/chronicle-core
A choice foreclosed in one loop can be reopened in the next. Chronicle
tracks consequence; Loop Core decides which consequences survive a reset.
============================================================================
Terms of use
============================================================================
Use in commercial and non-commercial RPG Maker MZ projects. Credit CSAF.
Do not redistribute or resell the plugin itself.
Majora’s Mask, Outer Wilds, Deathloop, 12 Minutes. The time loop is simple to describe and miserable to hand-roll, because it is not really about time. It is about bookkeeping: what snaps back, what survives, what the game must remember that the world has forgotten, and how the player is shown any of it.
Loop Core is that bookkeeping. An anchor is the moment a loop starts — set it once, and every rewind returns the world to exactly that state: switches, variables, self-switches, party position and condition. Knowledge is what the player keeps: facts, carried items, and the record of what they changed. A rewind cannot touch any of it.
The safety rule is the part worth reading before you buy. Loop Core only ever touches ids you list in World switches and World variables. Everything else in your project — every other plugin’s switches, every variable you use for something that is not the world — is not read, not written and not rewound. There is deliberately no “reset everything” mode, because a loop plugin that clears state it does not own is a plugin that breaks the rest of your game on the second loop.
Gating needs no scripting. Point a variable at the loop counter and Loop Core keeps it equal to the current loop number, so any ordinary Conditional Branch can gate on the loop with no script call at all. For knowledge, the script conditions read like sentences: $gameLoop.knows(‘mayor_lies’), $gameLoop.loopIndex(), $gameLoop.learnedThisLoop(‘mayor_lies’) and $gameLoop.divergedFrom(‘saved_the_smith’).
The workflow is five steps and no more: build your day as an ordinary map without thinking about looping yet; set the anchor when the day starts; call Learn a fact wherever the player learns something; call Rewind wherever the day ends, whether that is death, midnight or a choice; then gate the dialogue that should change. The Ledger is generated from that — you never author it.
Where to get it: the itch.io page linked above, which shows the current price. The plugin is paid. The download ships readable, unobfuscated JavaScript — no minification — plus a LICENSE.txt. Commercial use in your games is permitted; redistribution of the plugin source itself is not, which is why this entry links to the plugin rather than hosting the file.
AI disclosure: the code and the store images for this plugin were generated with AI assistance, and this is disclosed on the itch.io listing as well.
Note on the help text below: this site cannot display angle-bracket characters — it stores them as entities that then render literally. Loop Core’s help uses 2 arrows and comparison signs, written here as → and ≥. Nothing else has been changed: every other character is exactly as it ships inside the plugin.