VN Ren'Py Royal Switch [Development Thread]

ffive

Forum Fanatic
Jun 19, 2022
4,925
10,631
Regarding question how to add stuff to the game's options menu, per you'd be basically adjusting with your own additions to the preferences screen (labels and checkboxes)
 
Dec 16, 2022
233
302
I've had some time today to take a look at the script and this is what I came up with. It has a several neat features...
  • No need to repeat the same animation code for every animation, making development faster and less error prone
  • Can change behavior of all animations in one place
  • There should be no weird roll bugs, can roll over animations smoothly
  • No hard pause
  • No return labels required, just one line in the script
The whole motivation was to implement a autoplay feature, which I did, I've tested it quite a bit and this version works well for me. From what I can tell, with 'default anim_autoplay = False' it behaves the exact same, but more testing is required.
Also, save compatibility should be carefully considered. This shouldn't mess with old saves, unless someone made a save during an animation, then it might. Again, more testing required.

There's still some things that can be improved, but I thought I'd share it anyways. Take a look at it if you want and let me know what you think.

Python:
# These two can be hooked into the settings menu.
# For some reason setting anim_autoplay = True will change the layout of the anim_start / anim_end screens...
default anim_autoplay = False
default anim_duration = 8.0

# The time to wait before starting any animations,
default anim_timeout = 3.0

default anim_start_btn = "imagebuttons/animbutton_%s.webp"
default anim_end_btn = "imagebuttons/finishedbutton_%s.png"


# Generic start/stop animation screens with optional timer
screen anim_start(filename):
    frame:
        xalign 0.02
        yalign 0.95
        background None
       
        $button_action = [Hide("anim_start", dissolve), Call("play_anim", filename)]
       
        imagebutton auto anim_start_btn:
            action button_action
       
        if anim_autoplay:
            timer anim_timeout action button_action
       

screen anim_end():
    modal True
    frame:
        xalign 0.02
        yalign 0.01
        background None
       
        $button_action = [Hide("anim_end", dissolve), Return()]
       
        imagebutton auto anim_end_btn:
            action button_action
           
        if anim_autoplay:
            timer anim_duration action button_action
           

# This label is called from the script, e.g. call animation("m_dhmf2a")
label animation(filename):
    # Suspend rollback, otherwise pause will create a checkpoint and rollback won't work as expected.
    $renpy.suspend_rollback(True)
   
    show screen anim_start(filename) with dissolve
   
    python:
        # This is so that we can forward roll over this screen without blocking...
        # I haven't fully figured out why this is needed, but may be related to:
        # https://github.com/renpy/renpy/issues/2794
        if not renpy.in_rollback():
            renpy.pause()
            # If afm and autoplay are on avoid skipping the animation entirely. There's probably a better way to do this.
            if renpy.game.preferences.afm_enable and anim_autoplay:
                renpy.pause(60)
   
    hide screen anim_start with dissolve
   
    $renpy.suspend_rollback(False)
    return


label play_anim(filename):
    window hide  
    show image filename with dissolve  
    show screen anim_end with dissolve  
    pause
    # In case we somehow manage to jump out of the animation early, we hide the screen and return.
    hide screen anim_end with dissolve  
    return
This can then be called from the script like this:
Python:
call animation("m_dhmf2a")
I did finish my universal patch for the current version too, which basically mimics the same autoplay feature, but injects some code at runtime.
 
  • Like
Reactions: ffive

DeepBauhaus

ALL GLORY TO THE HYPNOTOAD
Game Developer
Oct 14, 2018
112
297
I've had some time today to take a look at the script and this is what I came up with. It has a several neat features...
  • No need to repeat the same animation code for every animation, making development faster and less error prone
  • Can change behavior of all animations in one place
  • There should be no weird roll bugs, can roll over animations smoothly
  • No hard pause
  • No return labels required, just one line in the script
The whole motivation was to implement a autoplay feature, which I did, I've tested it quite a bit and this version works well for me. From what I can tell, with 'default anim_autoplay = False' it behaves the exact same, but more testing is required.
Also, save compatibility should be carefully considered. This shouldn't mess with old saves, unless someone made a save during an animation, then it might. Again, more testing required.

There's still some things that can be improved, but I thought I'd share it anyways. Take a look at it if you want and let me know what you think.

Python:
# These two can be hooked into the settings menu.
# For some reason setting anim_autoplay = True will change the layout of the anim_start / anim_end screens...
default anim_autoplay = False
default anim_duration = 8.0

# The time to wait before starting any animations,
default anim_timeout = 3.0

default anim_start_btn = "imagebuttons/animbutton_%s.webp"
default anim_end_btn = "imagebuttons/finishedbutton_%s.png"


# Generic start/stop animation screens with optional timer
screen anim_start(filename):
    frame:
        xalign 0.02
        yalign 0.95
        background None
      
        $button_action = [Hide("anim_start", dissolve), Call("play_anim", filename)]
      
        imagebutton auto anim_start_btn:
            action button_action
      
        if anim_autoplay:
            timer anim_timeout action button_action
      

screen anim_end():
    modal True
    frame:
        xalign 0.02
        yalign 0.01
        background None
      
        $button_action = [Hide("anim_end", dissolve), Return()]
      
        imagebutton auto anim_end_btn:
            action button_action
          
        if anim_autoplay:
            timer anim_duration action button_action
          

# This label is called from the script, e.g. call animation("m_dhmf2a")
label animation(filename):
    # Suspend rollback, otherwise pause will create a checkpoint and rollback won't work as expected.
    $renpy.suspend_rollback(True)
  
    show screen anim_start(filename) with dissolve
  
    python:
        # This is so that we can forward roll over this screen without blocking...
        # I haven't fully figured out why this is needed, but may be related to:
        # https://github.com/renpy/renpy/issues/2794
        if not renpy.in_rollback():
            renpy.pause()
            # If afm and autoplay are on avoid skipping the animation entirely. There's probably a better way to do this.
            if renpy.game.preferences.afm_enable and anim_autoplay:
                renpy.pause(60)
  
    hide screen anim_start with dissolve
  
    $renpy.suspend_rollback(False)
    return


label play_anim(filename):
    window hide 
    show image filename with dissolve 
    show screen anim_end with dissolve 
    pause
    # In case we somehow manage to jump out of the animation early, we hide the screen and return.
    hide screen anim_end with dissolve 
    return
This can then be called from the script like this:
Python:
call animation("m_dhmf2a")
I did finish my universal patch for the current version too, which basically mimics the same autoplay feature, but injects some code at runtime.
Thank you so much for this! I will play around with it and see if I can get it to work. I would like to include you in the game credits! If you're interested, DM me.
 
Dec 16, 2022
233
302
Thank you so much for this! I will play around with it and see if I can get it to work. I would like to include you in the game credits! If you're interested, DM me.
That's nice of you to offer, but not really necessary. I'm just having a bit of fun working with renpy and if something comes of it that you want to use, that's great.

I have been thinking about potential save game issues today and just done some more testing. It turns out it doesn't matter, because saves taken during animations are broken already, for the same reason that rolling doesn't work properly I believe.

If you save during an animation subroutine like this...
Python:
label play_m_dhmf7A:
    show screen fin_dhmf_7A with dissolve
    window hide
    $ renpy.show("m_dhmf7a")
    $ renpy.transition(Dissolve(.5))
    $ renpy.pause(12, hard=True)
... renpy doesn't know where to return to and doesn't find any instruction to execute, so it just goes back to main menu.

Adding a jump instruction at the end fixes this.
Python:
label play_m_dhmf7A:
    show screen fin_dhmf_7A with dissolve
    window hide
    $ renpy.show("m_dhmf7a")
    $ renpy.transition(Dissolve(.5))
    $ renpy.pause(12, hard=True)
    jump dhmf_cs
But tbh this approach isn't very good imo, it's not robust enough and requires a lot of manual labor, I think ultimately changing how animations are handled would be for the best. I would avoid using jump at all, unless you're jumping to labels within the same scope and instead use call for calling subroutines.