Skip to content

saveexample_EN

windows99-hue edited this page Jul 20, 2026 · 1 revision

A Save Example

This is a small example demonstrating the use of dokibox's save and load functionality. Your program doesn't have to be written this way; this is just to help you understand how dokibox can be applied in your story.

from dokibox import *
import keyboard
import time
import json
import os

# Global variables
progress = [1, 0]
action_flag = None  # Used to receive commands from the background thread ('save' or 'load')

# ----------------- Callbacks (run in background thread) -----------------
# They are now only responsible for "issuing commands" and do not touch any UI
def trigger_save():
    global action_flag
    action_flag = 'save'

def trigger_load():
    global action_flag
    action_flag = 'load'

def exit_program():
    print("Exiting program...")
    keyboard.unhook_all_hotkeys()
    os._exit(0)

# ----------------- Actual execution of actions (runs in main thread) -----------------
def do_save():
    notice("Saving...")
    data_to_save = {"progress": progress}
    try:
        with open("save.json", 'w', encoding='utf-8') as f:
            json.dump(data_to_save, f, ensure_ascii=False, indent=4)
        print("Game saved")
    except Exception as e:
        print(f"Save failed: {e}")

def do_load():
    global progress
    try:
        with open('save.json', 'r', encoding='utf-8') as f:
            data = json.load(f)
        
        progress[0] = data["progress"][0]
        progress[1] = data["progress"][1]
        
        notice("Loading save...")
        print(f"Save loaded, current progress: Chapter {progress[0]}, Story {progress[1]}")
        return True  # Load successful
    except FileNotFoundError:
        notice("Save file not found!")
        print("Load failed: no save.json file found in the current directory")
        return False

# ----------------- Main program logic -----------------
def main():
    print("Program started...")
    print("Press F3 to save current progress")
    print("Press F4 to load save (will take effect after the current dialogue ends)")
    print("Press ESC to exit the program")
    
    # Register hotkeys
    # keyboard.add_hotkey('f3', trigger_save)
    # keyboard.add_hotkey('f4', trigger_load)
    keyboard.add_hotkey('esc', exit_program)

    dialogbox.save = trigger_save
    dialogbox.load = trigger_load

    # Try to load a save once at startup
    # do_load()
    
    # Start the story
    if progress[0] == 1:
        label1()
    
def label1():
    global action_flag, progress
    script = [
        ("Monika", "The weather is really nice today!"),
        ("Sayori", "Yeah, I wonder what's going to happen"),
        ("Monika", "I've been researching how to break out of Ren'Py into the Windows system"),
        ("Monika", "But the author of dokibox, 99, ran into a bit of a problem"),
        ("Monika", "He doesn't know what dokibox is supposed to be"),
        ("Monika", "So I'm helping him out. If our conversation can be successfully saved,"),
        ("Monika", "that means dokibox's existence is justified"),
        ("Sayori", "Wow! Then we can go into his computer from now on!"),
        ("Sayori", "I really want to see what it's like there"),
        ("Monika", "We'll get there, Sayori. After all, in the world of computers, anything is possible.")
    ]
    
    # Using a while loop instead of a for loop here so we can flexibly modify the value of progress[1] (i.e., jump progress) at any time
    while progress[1] < len(script):
        # 1. Check if there is a command from the hotkey
        if action_flag == 'save':
            do_save()
            action_flag = None
        elif action_flag == 'load':
            if do_load():
                action_flag = None
                continue  # If load is successful, skip the following code, restart the loop, and display the dialogue for the new progress
            action_flag = None

        # 2. Render UI (this will block the main thread until the player clicks continue)
        dialogbox(msg=script[progress[1]][1], name=script[progress[1]][0])
        
        # 3. After the dialogue ends, check whether the load key was pressed while viewing the dialogue
        # If the load key wasn't pressed, proceed to the next line. If it was pressed, don't add 1, leaving it for the next round to load.
        if action_flag != 'load':
            progress[1] += 1

if __name__ == "__main__":
    main()

Clone this wiki locally