A Checkpointing System in Dialog

Now that voting has ended for IFComp, I wanted to share how I implemented the checkpointing system in Forsaken Denizen.

The code below is the initial prototype I came up with before I started work on FD - with some bug fixes ported into it from the FD code. It’s possible that I’ve messed this up slightly, but hopefully this is still enough for other people to build on.

(I’d be grateful if you’d credit me if you use this code, but I’m not the police or anything.)

Note that because this works by hacking UNDO, we need to first make some changes to stdlib.dg.

Find these lines:

(parse commandline $Words with choices $ChoiceList)
	%% Before proceeding, save the current undo state:
	(if) (save undo 1) (then)
		(narrate undoing $Words)
		(stop)
	(endif)
	[more stuff here]

And comment out the first condition like so:

(parse commandline $Words with choices $ChoiceList)
	%% Before proceeding, save the current undo state:
	%%(if) (save undo 1) (then)
	%%	(narrate undoing $Words)
	%%	(stop)
	%%(endif)
	[more stuff here which we have NOT commented out]

Now that we’ve done that, a minimal game which sets a checkpoint every time you leave a safe room looks like this:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% --- A DANGEROUS GAME --- %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

(current player #player)
(#player is #in #deathroom)

#SafeRoom
(room *)
(look *) There is an exit north.
(safe *)
(from * go #north to #deathroom)

#deathroom
(room *)
(look *) There is an exit south.
(from * go #south to #SafeRoom)

#apple
(name *) green apple
(edible *)
(appearance *) A green apple is here.
(* is #in #deathroom)

#deathapple
(name *) red apple
(edible *)
(appearance *) A red apple is here.
(* is #in #deathroom)

(after [eat #deathapple])
    (game over { Oh no, you died! })

%%%%%%%%%%%%%%%%%%%%%%%%%
%% --- CHECKPOINTS --- %%
%%%%%%%%%%%%%%%%%%%%%%%%%

(before [leave $Room $Dir])
    %% Save a checkpoint whenever the player leaves a safe room
    (safe $Room)
    (from $Room go $Dir to $)
    \(Checkpoint updated\)
    (now)(any checkpoint set)
    (line)  %%room headers have a top margin
    %% most insane code I've ever written:
    %% this ensures that we always save a new checkpoint after popping the last one
    *(repeat forever)
        (if)(save undo 0)(then)
            (just)
        (endif)

(prevent [undo])
    %% Disable the undo command 
    %% so we don't confuse players used to how it normally works
    What has been done cannot be undone.
    (stop)

%% New checkpoint command - just a copy-paste of undo but with a new name

(grammar [checkpoint] for itself)
(command [checkpoint])

(prevent [checkpoint])
    %% we set checkpoints when players *leave* the safe room!
    %% if we let the player load a checkpoint *in* a safe room
    %% they'll lose all their progress since they last *left* a safe room -
    %% which may not be what they expect
    (current room $Room)
    (safe $Room)
    \(You're already in a safe room.\)

(perform [checkpoint])
    (if) ~(interpreter supports undo) (then)
        This interpreter doesn't support checkpoints.
    (elseif) (undo) (then)
        Failed to return to checkpoint.
    (else)
        No checkpoint has been set.
    (endif)
    (stop)

%% Replace UNDO with CHECKPOINT when there's a game over

(game over menu)
    (line)
    Would you like to:
    (if) (interpreter supports undo) (any checkpoint set) (then)
        (line) (space 5)
        return to the last
        (if) (library links enabled) (then)
            (link) CHECKPOINT
        (else)
             CHECKPOINT
        (endif)
        ,
    (endif)
    (line) (space 5)
    (if) (library links enabled) (then)
        (link) RESTORE a saved position,
    (else)
        RESTORE a saved position,
    (endif)
    (line) (space 5)
    (exhaust) {
        *(game over option)
        (line) (space 5)
    }
    (if) (interpreter supports quit) (then)
        (if) (library links enabled) (then)
            (link) QUIT
        (else)
            QUIT
        (endif)
        the program,
        (line) (space 5)
    (endif)
    or
    (if) (library links enabled) (then)
        (link) RESTART
    (else)
        RESTART
    (endif)
    from the beginning?
    (line)
    (prompt and input $Words)
    (stoppable) (parse game over $Words)

(parse game over [checkpoint])
    (if) (undo) (then)
        Failed to return to checkpoint.
    (else)
        No checkpoint set.
    (endif)

A transcript of this game looks like this:

Summary

An Interactive Fiction
An interactive fiction by Anonymous.
Release 1. Serial number 241016.
Dialog compiler version 0m/03. Library version 0.46.

Location
There is an exit south.

A green apple is here.

A red apple is here.

> eat red
You eat the red apple.

*** Oh no, you died! ***

Would you like to:
RESTORE a saved position,
QUIT the program,
or RESTART from the beginning?
> restart

An Interactive Fiction
An interactive fiction by Anonymous.
Release 1. Serial number 241016.
Dialog compiler version 0m/03. Library version 0.46.

Location
There is an exit south.

A green apple is here.

A red apple is here.

> s
You walk south.

Location
There is an exit north.

> n
(Checkpoint updated)
You walk north.

Location
There is an exit south.

A green apple is here.

A red apple is here.

> eat green
You eat the green apple.

> eat red
You eat the red apple.

*** Oh no, you died! ***

Would you like to:
return to the last CHECKPOINT,
RESTORE a saved position,
QUIT the program,
or RESTART from the beginning?
> checkpoint
You walk north.

Location
There is an exit south.

A green apple is here.

A red apple is here.

>

7 Likes