Ren'Py Filtering Load/Save screen slots based on sub-story identifier

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,607
2,256
Okay. So someone asked me a question and I've gotten close to an answer... but it still doesn't work.
I'm wondering if any of the brilliant minds out there can see a solution that is eluding me.

The basic problem:
The dev wants to create a game which is a collection of stories.
They want to select each story when they start a new game. I presume there's no restriction about playing them in order or anything.
Call them "Story 1", "Story 2" and "Story 3".

Now the quirk:
They only want "Story 1" save games to show in the load/save screens, when that story has been selected. Likewise Story 2 and Story 3.
In effect, they want to filter the list of save slots based on the selected story.

My solutions so far:
  • Forget it. Don't filter the save files. Let the player load any save file they like. Maybe set save_name to "Story 1", etc so the player knows which story the save belongs to.
  • Make each story a separate RenPy game. The saves will be separated and the concept will be mostly identical (except being able to choose which story from a menu).
  • Filter the save/load slots by comparing the value of save_load (via ) with a persistent variable set when each story starts.

The dev really wants to get things working how they originally envisioned. So #1 and #2 are out for the moment.

So I did some playing around with concept #3.

The problem I have run into is the way the slots are numbered compared with the filenames and the way the paging works.
RenPy's load/save pages are flexible enough to start at being a 2x3 grid, but can be expanded to 2x4 or even 3x4 (if you set the thumbnail sizes smaller).
As a result going from page 1 to page 2 doesn't always mean forward 6 slots - though that is the most common, since it's the default.

But if I filter out certain slots, it messes with how it's working.
My initial problem was the slot grid. Showing less than 6 elements in a 2x3 grid causes an error. (Fixed by padding out the slots if there's a shortfall).
But then you start to get into the different behaviours of the save screen -vs- the load screen... where if the slot is empty matters.
Next I've convinced myself that there's going to be paging problems. Except, given the way RenPy names save files with both the page number and slot number... perhaps that's less of an issue than I thought.
Except... now I think more... it's likely that saving Page #1, Slot #1 when showing "Story 2" saves will inadvertently overwrite an identically named Page #1, Slot #1 save for "Story 1".

I know I'm missing something fundament here, but even if I can get over that... I'm not sure this filtering idea is the way to solve the original problem anyway.

Anyone got any other thoughts or insights.
 
Last edited:
  • Like
Reactions: | Vee |

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,607
2,256
Nevermind.

Already talked myself into a solution.

Python:
# within screens.rpy -- screen file_slots(title):

                for i in range(gui.file_slot_cols * gui.file_slot_rows):

                    if persistent.story_id == "Story 2":
                        $ slot_adjust = 10
                    elif persistent.story_id == "Story 3":
                        $ slot_adjust = 20
                    else:
                        $ slot_adjust = 0

                    $ slot = i + 1 + slot_adjust

                    button:
                        action FileAction(slot)

In effect, I'm using slots 1-6 for story 1, slots 11-16 for story 2, etc. Paging isn't an issue. Filling in empty grid slots isn't an issue.

Final attempt:


Other thoughts, solutions or insights still welcome though.
 

guest1492

Member
Apr 28, 2018
350
288
I think you're going to have to disable auto saves and I don't know what you're going to have to do with quick saves.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,963
16,199
Other thoughts, solutions or insights still welcome though.
Hmm, totally not tested, but like that I would just play with the save page, giving to each story a slice to 100 pages:

Python:
label start_story1:
    $ storySlice = 0
    [...]

label start_story2:
    $ storySlice = 100
    [...]

label start_story2:
    $ storySlice = 200
    [...]
Then you rely on the optional "page" arguments of the Files related objects.
Instead of letting Ren'Py use persistent._file_page to know with which page it should interact, you use the persistent value as "logicial page". It's not anymore the the page number from the starts, but the page number for the current slice.

Python:
screen file_slots(title):

    # Add this
    default realPage = str( int( persistent._file_page ) + storySlice ) if not persistent._file_page in [ "auto", "quick" ] else persistent._file_page
    # update
    default page_name_value = FilePageNameInputValue(pattern=_("Page {}"), auto=_("Automatic saves"), page=realPage, quick=_("Quick saves"))

    [...]
                for i in range(gui.file_slot_cols * gui.file_slot_rows):

                    $ slot = i + 1

                    button:
                        # update
                        action FileAction(slot, page=realPage )

                        has vbox

                        # update
                        add FileScreenshot(slot, page=realPage ) xalign 0.5

                        # update
                        text FileTime(slot, format=_("{#file_time}%A, %B %d %Y, %H:%M"), empty=_("empty slot"), page=realPage ):
                            style "slot_time_text"

                        # update
                        text FileSaveName(slot, page=realPage ):
                            style "slot_name_text"

                        # update
                        key "save_delete" action FileDelete(slot, page=realPage )

    [...]
Then it should be totally transparent for the player. From his side the page will be named "1", "2", "3", "4", etc, but for Ren'py it will be "1", "101", "201" depending of the story.
 

crabsinthekitchen

Well-Known Member
Apr 28, 2020
1,565
9,063
oh, that's something I have ideas about. basically, the bare minimum you need is 3 pages (or however many stories there are)

what you have on a single page doesn't have to be a grid or have a fixed amount of saves. you can have 6, 100, 0 saves or even make it dynamic and have a "New save" button at the top with the rest of the saves listed below (I even tried listing saves from ALL pages but that does get a bit too messy for my liking). the only thing you need to double-check is that "New save" doesn't overwrite any existing saves when you start deleting and overwriting saves

it looks somewhat like this (kinda working prototype but it has pieces of other functionality so parts of it are broken and I'm too lazy to fix)
Python:
 viewport:
                mousewheel True
                scrollbars "vertical"

                has vbox
                spacing 5
                #Sorting by last updated time so that newer saves are on top
                $ crabs_saves = sorted(FileUsedSlots(page=FileCurrentPage(), highest_first=False), key=lambda x: FileTime(x, format=_("{#file_time}%Y %m %d, %H:%M:%S")))
                if title == "Save" and FileCurrentPage().isnumeric():
                    $ last_save_slot = (FileUsedSlots(page=FileCurrentPage(), highest_first=True) or [0])[0]
                   
                    $ crabs_new_slot = last_save_slot + 1
                    fixed:
                        xsize 1400
                        ysize 135
                        add "#3d86c6"
                        hbox xsize 1400 ysize 135:
                           
                            add "#aaa" size(190, 108) ycenter 0.5 xalign 1.0
                            vbox ycenter 0.5 xcenter 0.5 xsize 700:
                                text "New save"

                            button xsize 448 ysize 100:
                                xcenter 0.5
                                ycenter 0.5
                                background "#191970"
                                text "Save" text_align 0.5 yalign 0.5 xcenter 0.5
                                action SetVariable("save_name", FileSaveName(crabs_new_slot)), Show("screen_save_name", slot=crabs_new_slot)


                for slot in crabs_saves[::-1]:
                    fixed:
                        xsize 1400
                        ysize 135

                        add "#3d86c6"

                        hbox:
                            xsize 1400
                            ysize 135
                            add FileScreenshot(slot) size(190, 108) ycenter 0.5 xalign 1.0
                            vbox ycenter 0.5 xcenter 0.5 xsize 700:
                                text FileSaveName(slot):
                                    substitute False
                                    style "slot_name_text"
                                    color '#ffdf00'
                                    size 33
                                    xalign 0.0
                                $ game_time = FileJson(slot, key="game_date_time", empty="", missing="")
                                $ save_time = FileTime(slot, format=_("{#file_time}%A, %B %d %Y, %H:%M"))
                                text "[game_time] ([save_time])":
                                    size 22
                                    xalign 0.0
                                hbox:
                                    spacing 25
                                    if FileCurrentPage().isnumeric() and title == "Save":
                                        button:
                                            background "#191970"
                                            xsize 200
                                            ysize 50
                                            text "Overwrite" text_align 0.5 xcenter 0.5
                                            action SetVariable("save_name", FileSaveName(slot)), Show("screen_save_name", slot=slot)
                                    if title == "Load":
                                        button:
                                            background "#191970"
                                            xsize 200
                                            ysize 50
                                            text "Load" text_align 0.5 xcenter 0.5
                                            action FileLoad(slot)
                                    button:
                                        background "#191970"

                                        xsize 200
                                        ysize 50
                                        text "Delete" text_align 0.5 xcenter 0.5
                                        action FileDelete(slot)
with
 
Last edited:
  • Thinking Face
Reactions: | Vee |