Need help with a custom alternative to rollback [Solved]

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
EJ107
Newbie
Posts: 19
Joined: Mon Feb 01, 2016 8:46 pm
Projects: Watching Time
Location: Birmingham, UK
Contact:

Need help with a custom alternative to rollback [Solved]

#1 Post by EJ107 »

Hello, I'm new to these forums and new to Ren'Py, but I come from a programming background and am familiar with python. I decided to use Ren'Py rather than making the engine for my VN myself because it seemed much easier, but I can't work out how to implement the key aspect of my VN via Ren'Py.

My VN revolves around a time travel mechanic where the player can go back to any prior point in the game and will be given extra options in the past based on what they have seen, or what decisions they have made.

In an attempt to implement this I created a new time-travel screen that has a 'go back' button, and tried utilizing the rollback function. But since it seems to simply return the entire game to a previous state (if I understood the documentation correctly) it removes the player from the time-travel screen and I assume returns all variables to their previous values as well, which simply won't work for what I'm trying to do since the choices made need to be remembered.

I believe that I need to create a custom action, but I can only find tutorials and guides explaining how to do things via screens and existing actions, and nothing about how to create entirely new actions or actually alter things behind the scenes. I tried searched for where the existing rollback action is defined so I could use that as a template, but found nothing.

Does anyone have any advice on where to even start implementing a feature like this? Is there an obvious way to do this via existing actions that I'm just not seeing? :?
Last edited by EJ107 on Mon Feb 01, 2016 11:58 pm, edited 1 time in total.

User avatar
Belgerum
Regular
Posts: 110
Joined: Thu Nov 06, 2014 12:24 am
Skype: belgerum09
Soundcloud: Belgerum
itch: Belgerum
Contact:

Re: Need help with a custom alternative to rollback

#2 Post by Belgerum »

Try using some persistent variables for this. They won't be reset by the game when saving or loading, and will stay the same even if you completely restart the game up. Something like this might be what you want:

Code: Select all

label start:
$ persistent.time_travel1 = False
$ persistent.time_travel2 = False

"I live my life."

if persistent.time_travel1 == True:
    menu:
        "I am about to die horribly."
        "Do nothing.":
            pass
        "I've been here before...":
            jump label1
else:
    "I am about to die horribly."

"I do nothing to stop it, and I die."

$ persistent.time_travel1 = True
$ persistent.time_travel = True

"In the afterlife, I uncover time travel powers."
"Rollback to rewind..."
return


label label1:

if persistent.time_travel2 == True:
    menu:
        "Remembering dying here last time, I act quickly and prevent my death."
        "I'm safe now!":
            pass
        "Get ready for aliens.":
            jump aliens
        "Run far away":
            jump aliens2
else:
    "Remembering dying here last time, I act quickly and prevent my death."

$ persistent.time_travel2 = True
"However, I am killed by aliens because they found out I used time travel."
"I die again."
"Rollback to rewind..."
return


label aliens:
"Remembering that last time, I got killed by aliens, I hide from them when they come."
"I am saved from the aliens, and live happily ever after."
return

label aliens2:
"Remembering that last time, I got killed by aliens, I run far far away."
"The aliens are much faster than me, and manage to kill me again."
"Rollback to rewind..."
return
Last edited by Belgerum on Mon Feb 01, 2016 10:44 pm, edited 3 times in total.

User avatar
EJ107
Newbie
Posts: 19
Joined: Mon Feb 01, 2016 8:46 pm
Projects: Watching Time
Location: Birmingham, UK
Contact:

Re: Need help with a custom alternative to rollback

#3 Post by EJ107 »

Wow, thank you for your very quick response! Those look perfect for what I want to do :)

My only other issue with using rollback is how it seems to remove the player from the time-travel screen and back to the standard game screen. Here is the relevant snippet of my 'screens' file:

Code: Select all

##############################################################################
# Quick Menu
#
# A screen that's included by the default say screen, and adds quick access to
# several useful functions.
screen quick_menu():

    # Add an in-game quick menu.
    hbox:
        style_group "quick"

        xalign 1.0
        yalign 1.0

        textbutton _("Menu") action ShowMenu('')
        textbutton _("Quicksave") action QuickSave()
        textbutton _("Auto") action Preference("auto-forward", "toggle")
        textbutton _("Timewatch") action Show("timewatch")
      
init -2:
    style quick_button:
        is default
        background None
        xpadding 5

...

#init -2 python:
    #class Timewatch(Action):
        #def __init__(self, map_point, **kwargs):
            #super(Action, self).__init__(**kwargs)  
        
#############################################################################
#        
screen timewatch:

    modal True

    vbox:
        textbutton "Return" action Hide("timewatch")
        textbutton "Back" action (Rollback(), Show("timewatch"))
I want the player to be able to go back as many times as they want while staying on this screen, but after the "back" button is pushed they go back one step and are removed from this screen. I think that this is probably because the game state is being reset to when the screen wasn't open?

I try calling "Show("timewatch")" again after the rollback, but the timewatch screen still doesn't reappear automatically.

User avatar
Belgerum
Regular
Posts: 110
Joined: Thu Nov 06, 2014 12:24 am
Skype: belgerum09
Soundcloud: Belgerum
itch: Belgerum
Contact:

Re: Need help with a custom alternative to rollback

#4 Post by Belgerum »

Try adding the timewatch screen onto another ren'py default screen, like the quick menu, with a conditional switch that determines whether or not to show it. That way, it will be shown whenever you want, with just the change of a variable.

like this, maybe:

Code: Select all

##############################################################################
# Quick Menu
#
# A screen that's included by the default say screen, and adds quick access to
# several useful functions.
screen quick_menu():

    # Add an in-game quick menu.
    hbox:
        style_group "quick"

        xalign 1.0
        yalign 1.0

        textbutton _("Menu") action ShowMenu('')
        textbutton _("Quicksave") action QuickSave()
        textbutton _("Auto") action Preference("auto-forward", "toggle")

    if persistent.time_travel_menu == True:
        vbox:
            xalign 0.0 yalign 0.0
            textbutton "Back" action (Rollback(), Show("timewatch"))

init -2:
    style quick_button:
        is default
        background None
        xpadding 5
Last edited by Belgerum on Mon Feb 01, 2016 10:09 pm, edited 2 times in total.

philat
Eileen-Class Veteran
Posts: 1900
Joined: Wed Dec 04, 2013 12:33 pm
Contact:

Re: Need help with a custom alternative to rollback

#5 Post by philat »

1. Persistent objects persist across playthroughs. They're usefulbut seem ill-fitted to this use-case unless I'm misunderstanding. Is the point that the choices change based on what the player has seen across playthroughs? Or based on what the player has seen in any given playthrough? In other words, consider a Phoenix Wright game: you can interview a witness multiple times during your investigation, and depending on what you've uncovered so far you can "unlock" extra questions. Using persistent to achieve this will mean that once you've beaten the game once, those extra questions STAY UNLOCKED in your next playthrough. I can't imagine that this is the intent. You can, of course, reset the persistent variables every time you start a new game. But... why?

2. In a similar vein as point 1, I don't understand why you're attempting to use rollback for this in the first place. Rollback is useful precisely because it DOES return you to a previous state -- you're not looking for this, you're just looking for a way to revisit a particular point in the game. Why not just jump?

User avatar
EJ107
Newbie
Posts: 19
Joined: Mon Feb 01, 2016 8:46 pm
Projects: Watching Time
Location: Birmingham, UK
Contact:

Re: Need help with a custom alternative to rollback

#6 Post by EJ107 »

philat wrote:1. Persistent objects persist across playthroughs. They're usefulbut seem ill-fitted to this use-case unless I'm misunderstanding. Is the point that the choices change based on what the player has seen across playthroughs? Or based on what the player has seen in any given playthrough? In other words, consider a Phoenix Wright game: you can interview a witness multiple times during your investigation, and depending on what you've uncovered so far you can "unlock" extra questions. Using persistent to achieve this will mean that once you've beaten the game once, those extra questions STAY UNLOCKED in your next playthrough. I can't imagine that this is the intent. You can, of course, reset the persistent variables every time you start a new game. But... why?

2. In a similar vein as point 1, I don't understand why you're attempting to use rollback for this in the first place. Rollback is useful precisely because it DOES return you to a previous state -- you're not looking for this, you're just looking for a way to revisit a particular point in the game. Why not just jump?
1. They are supposed to be playthrough specific, and having them function cross-playthrough is a serious issue. :?

I'll give a simple example of how I want to use this: You see character A die, a piece of information is revealed later because you made a certain choice, now when you go back you have a new option where they can survive. But this only applies for this playthrough.

2. Because I want the player to have the freedom to go back whenever they want to wherever they want, rather than limiting it to fixed points. I also want this to be something they can do via the UI, not something they have to choose in an in-game menu. When they find that piece of information the game shouldn't tell them they can go back and make the option obvious, the player has to work it out and choose to try it themselves.

It may sound silly, but my entire logic with this game idea is "time travel should be a gameplay mechanic, not a plot device limited to a few occasions".

User avatar
Belgerum
Regular
Posts: 110
Joined: Thu Nov 06, 2014 12:24 am
Skype: belgerum09
Soundcloud: Belgerum
itch: Belgerum
Contact:

Re: Need help with a custom alternative to rollback

#7 Post by Belgerum »

That should be fairly simple. Just reset the persistent variable controlling whether the choice should be shown at the start of the script. That way, any time you start a new game, the persistent variable will be turned off automatically. The only way to turn it on would be to rollback in the time machine setup, or to load a game that already has the time travel mechanic enabled, and is past the point where you enable the time machine.

Try using the time machine menu added on to the Quick menu, like I posted above, with this script. You should only be able to access the time travel sections if you've already been to them in that playthrough. Admittedly, this only works by shutting off the time machine menu every time you make a change, and leaving it off until after the points of divergence, but hopefully that's what you're looking for.

I'll also edit the first code I posted, so you can try it with variables for each divergence point, rather than just turning the time machine off.

Code: Select all

label start:
$ persistent.time_travel = False

"I live my life."

if persistent.time_travel == True:
    menu:
        "I am about to die horribly."
        "Do nothing.":
            pass
        "I've been here before...":
            $ persistent.time_travel = False
            jump label1
else:
    "I am about to die horribly."

"I do nothing to stop it, and I die."


"In the afterlife, I uncover time travel powers."
$ persistent.time_travel = True
"Rollback to rewind..."
return


label label1:
"Am I safe now?"
if persistent.time_travel == True:
    menu:
        "Remembering dying here last time, I act quickly and prevent my death."
        "I'm safe now!":
            pass
        "Get ready for aliens.":
            jump aliens
            $ persistent.time_travel = False
        "Run far away":
            jump aliens2
            $ persistent.time_travel = False
else:
    "Remembering dying here last time, I act quickly and prevent my death."

"However, I am killed by aliens because they found out I used time travel."
"I die again."
$ persistent.time_travel = True
"Rollback to rewind..."
return


label aliens:
"Remembering that last time, I got killed by aliens, I hide from them when they come."
"I am saved from the aliens, and live happily ever after."
return

label aliens2:
"Remembering that last time, I got killed by aliens, I run far far away."
"The aliens are much faster than me, and manage to kill me again."
$ persistent.time_travel = True
"Rollback to rewind..."
return
Last edited by Belgerum on Mon Feb 01, 2016 10:39 pm, edited 1 time in total.

User avatar
EJ107
Newbie
Posts: 19
Joined: Mon Feb 01, 2016 8:46 pm
Projects: Watching Time
Location: Birmingham, UK
Contact:

Re: Need help with a custom alternative to rollback

#8 Post by EJ107 »

Doesn't that have the same limitations as using jump in the script, though? You can still only go back at certain points, and if the player exits to main menu when the rollback option is up then it will still be set to true when they load another game. Also, I may be dealing with a very large number of "future" variables, and turning them all on/off frequently would get quite messy.

Is it possible to initiate a jump from a button? Something like "action: jump(renpy.get_current_scene() -1)" or something? :P That would be ideal.

User avatar
EJ107
Newbie
Posts: 19
Joined: Mon Feb 01, 2016 8:46 pm
Projects: Watching Time
Location: Birmingham, UK
Contact:

Re: Need help with a custom alternative to rollback

#9 Post by EJ107 »

Ok, I've found a solution that uses jump:

Code: Select all

# The game starts here.
label start: 
    $ chapter = 1
    
label jumping:
    if chapter == "chapter_1":
        jump chapter_1
    if chapter == "chapter_2":
        jump chapter_2
    if chapter == "chapter_3":
        jump chapter_3
        
label chapter1:
    "Chapter 1"
  
    "Scene 1.1"
    "Scene 1.2"
    "Scene 1.3"
 
label chapter_2:
    "Chapter 2"
    $ chapter = "chapter_2"      
    
    "Scene 2.1"
    "Scene 2.2"    
    "Scene 2.3"
    
label chapter_2:    
    "Chapter 3"
    $ chapter = "chapter_2"     
    
    "Scene 3.1"
    "Scene 3.2"
    "Scene 3.3"
        
    return
And in my screens:

Code: Select all

screen timewatch:

    modal True

    vbox:
        textbutton "Return" action Hide("timewatch")
        textbutton "Back" action (Jump("jumping"))
I'll probably need to limit the time re-winding to checkpoints rather than one step at a time, but that may be a more user friendly way of doing it anyway.

Thank you for your advice, and for the funny alien scenario :) Persistent variables will come in handy if I ever get around to creating a gallery on the main menu.

User avatar
Belgerum
Regular
Posts: 110
Joined: Thu Nov 06, 2014 12:24 am
Skype: belgerum09
Soundcloud: Belgerum
itch: Belgerum
Contact:

Re: Need help with a custom alternative to rollback

#10 Post by Belgerum »

Found an easier and better solution here, at the very bottom of the page:
http://www.renpy.org/doc/html/save_load_rollback.html

Defining a CLASS with the NoRollback property makes it so that any variable defined as that class won't reset when you roll back, but isn't persistent between saves like persistent variables. Geez, I wouldn't have known about that function exists except now that you've made me have to search hard for it. XP

Here's some new code that uses my earlier example, and makes sure the "time machine" part of the Quick menu, and the rollback function itself, work with the system, without being too permanent.

Code: Select all

init python:
    class NoRoll(NoRollback):
        def __init__(self):
            self.seen = False

label start:
$ time_travel = NoRoll()
$ scene1 = NoRoll()
$ scene2 = NoRoll()

"I live my life."

if scene1.seen == True:
    menu:
        "I am about to die horribly."
        "Do nothing.":
            pass
        "I've been here before...":
            jump label1
else:
    "I am about to die horribly."

"I do nothing to stop it, and I die."
"In the afterlife, I uncover time travel powers."
$ time_travel.seen = True
$ scene1.seen = True
"Rollback to rewind..."
return


label label1:
"Am I safe now?"
if scene2.seen == True:
    menu:
        "Remembering dying here last time, I act quickly and prevent my death."
        "I'm safe now!":
            pass
        "Hide in fear!":
            jump aliens
        "Run far away!":
            jump aliens2
else:
    "Remembering dying here last time, I act quickly and prevent my death."

"However, I am killed by aliens because they found out I used time travel."
"I die again."
$ scene2.seen = True
"Rollback to rewind..."
return


label aliens:
"Remembering that last time, I got killed by aliens, I hide from them when they come."
"I am saved from the aliens, and live happily ever after."
"The End."
return

label aliens2:
"Remembering that last time, I got killed by aliens, I run far far away."
"The aliens are much faster than me, and manage to kill me again."
"Rollback to rewind..."
return
And then, in Screens.rpy:

Code: Select all

##############################################################################
# Quick Menu
#
# A screen that's included by the default say screen, and adds quick access to
# several useful functions.
screen quick_menu():

    # Add an in-game quick menu.
    hbox:
        style_group "quick"

        xalign 1.0
        yalign 1.0

        textbutton _("Menu") action ShowMenu('')
        textbutton _("Quicksave") action QuickSave()
        textbutton _("Auto") action Preference("auto-forward", "toggle")

    if time_travel.seen == 1:
        vbox:
            xalign 0.0 yalign 0.0
            textbutton "Back" action Rollback()
    
init -2:
    style quick_button:
        is default
        background None
        xpadding 5

philat
Eileen-Class Veteran
Posts: 1900
Joined: Wed Dec 04, 2013 12:33 pm
Contact:

Re: Need help with a custom alternative to rollback [Solved]

#11 Post by philat »

NoRollback is a viable option, although it will work better for variables that are assigned once rather than incremented. As seen in the example given in the documentation, it works poorly if stat increments are involved, such as o.value += 1, since every time the statement is run it will increment again. Particularly as if you roll all the way back to the start and then play through again, it will actually increment twice -- once when rolling back, then once when rolling forward.

If you do design around jump rather than rollback, note that you can name and jump to menus the same way you jump to labels, which would make it easy to jump back to the last menu choice (which I would imagine is largely enough, unless there are a lot of non-menu-choice game actions that the player can take).

Post Reply

Who is online

Users browsing this forum: No registered users