Saving during a non-movie cut-scene

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
Kinmoku
Miko-Class Veteran
Posts: 560
Joined: Mon Aug 11, 2014 9:39 am
Completed: One Night Stand
Projects: Love IRL, Memories
Tumblr: gamesbykinmoku
itch: kinmoku
Location: Germany
Contact:

Saving during a non-movie cut-scene

#1 Post by Kinmoku » Thu Oct 07, 2021 4:26 am

Hi all,

I have several cut-scenes in my game (containing no dialogue), but instead of creating and importing a movie clip, I thought I would use Ren'Py itself to animate the scenes, since they're fairly simple and I can adjust timing/ SFX much more easily. However, when I save during a cut-scene and reload that save, it jumps to the next line of dialogue, skipping the whole cut-scene and playing all sounds at once. When I tested a save file during a movie clip, the movie would restart (which would be preferred than skipping the scene entirely).

How can I get Ren'Py to remember where it is during the cut-scene or, if this is not possible, restart the cut-scene if it's loaded halfway through, like what happens with movie clips?

Thank you :)

jeffster
Regular
Posts: 123
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Saving during a non-movie cut-scene

#2 Post by jeffster » Thu Oct 07, 2021 5:36 am

Perhaps look here:
https://www.renpy.org/doc/html/save_load_rollback.html
- Where Ren'Py Saves
- Retaining Data After Load
etc.

If that wouldn't work, it's possible to use after_load or config.after_load_callbacks.
https://www.renpy.org/doc/html/label.ht ... after_load
https://www.renpy.org/doc/html/config.h ... _callbacks

For example, you can add a variable to track which animation runs currently, if any.

If your animation is "image this_animation", it's probably like this:

Code: Select all

    # Your original script:

    scene this_animation # or show this_animation
    "Next statement"
Then you make it:

Code: Select all

default animating = None
#...

# Script:

    animating = "this_animation"
    scene this_animation
    "Next statement"
    animating = None
And add "after_load" like this:

Code: Select all

label after_load:
    if animating:
        scene this_animation
    return
So when the game loads it calls after_load first, there it checks if it was saved during such animation and if yes then repeats it.

There's probably even a way to avoid writing "animating = ..." every time, like defining some new Ren'Py statement for such animations, though it would require some serious python programming:

https://www.renpy.org/doc/html/cds.html

So I'm not sure it's the easiest way. Just a way I know.

User avatar
Kinmoku
Miko-Class Veteran
Posts: 560
Joined: Mon Aug 11, 2014 9:39 am
Completed: One Night Stand
Projects: Love IRL, Memories
Tumblr: gamesbykinmoku
itch: kinmoku
Location: Germany
Contact:

Re: Saving during a non-movie cut-scene

#3 Post by Kinmoku » Thu Oct 07, 2021 7:42 am

jeffster wrote:
Thu Oct 07, 2021 5:36 am
So when the game loads it calls after_load first, there it checks if it was saved during such animation and if yes then repeats it.

There's probably even a way to avoid writing "animating = ..." every time, like defining some new Ren'Py statement for such animations, though it would require some serious python programming:

https://www.renpy.org/doc/html/cds.html

So I'm not sure it's the easiest way. Just a way I know.
Thank you, this is really helpful. I've tried setting it up but sadly it's still not working. I imagine I've missed something, or after_load doesn't like jumps. I haven't used it before so I'm a little clueless.

Unfortunately, my animations are quite long (there are 7 in total, each one is 100-500 lines of code), so I thought jumping to a label would help reduce code/ repetition.

Here's what I have:

Code: Select all

label ff1:
    $ ffcutscene = "1"

    scene black
    with wiperight
    
    # rest of animation here
    
    $ ffcutscene = ""

    scene irl intro excited at tiltupquick
    with dissolve

    e "No way!"
    
    # etc
    
    
This kind of thing repeats 7 times, then I have:

Code: Select all

label after_load:
    if ffcutscene == "1":
        jump ff1
    elif ffcutscene == "2":
        jump ff2
    elif ffcutscene == "3":
        jump ff3
    elif ffcutscene == "4":
        jump ff4
    elif ffcutscene == "5":
        jump ff5
    elif ffcutscene == "6":
        jump ff6
    elif ffcutscene == "7":
        jump ff7

    return

jeffster
Regular
Posts: 123
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Saving during a non-movie cut-scene

#4 Post by jeffster » Thu Oct 07, 2021 9:03 am

I think the label "after_load" gets called, not just jumped to, so that the return could automatically bring the execution to the place the game was loaded to.

Calls work like this:

1. The computer gets a command like "call some label".

2. Before it jumps to that label, it stores the address of the statement to return (it's the next statement after that "call" statement).

3. At the label it jumped to, it performs that part of the program, until it meets "return" statement.

4. On "return" it takes the return address from the list and jumps (back) there.

That list of return addresses is called "call stack" (because the return addresses are like "stacked" on each other, and they get removed starting from the top / the latest one).

(Call stack may also contain parameters used when calling the function, but that's a propos.)

https://www.renpy.org/doc/html/label.html

So if some label was called, you shouldn't just jump back from there. Normally you need to use "return" to clean the last return address from the top of the call stack.

(Otherwise your program flow will be messed up.)

So if you really want to jump instead of returning, you need to adjust the call stack. There is a function in Ren'Py for that, renpy.pop_call().

https://www.renpy.org/doc/html/other.ht ... y.pop_call

So try putting renpy.pop_call() before jumping away:

Code: Select all

label after_load:
    if ffcutscene == "1":
        $ renpy.pop_call()
        jump ff1
    #...and so on like that
Or, in more elegant way:

Code: Select all

label after_load:

    # If ffcutscene is not empty:
    if ffcutscene:
        $ renpy.pop_call()
        jump expression "ff" + ffcutscene

    return
Another way is to assign animations to images or something, then you wouldn't need to repeat many lines of code. Like this:

Code: Select all

image slideshow:
    2.0
    "park" with Dissolve(2.0)
    alpha 0.0
    yalign 0.0
    parallel:
        easein 3.0 yalign 0.9
    parallel:
        easeout 3.0 alpha 1.0
    parallel:
        1.0
        easein 2.0 zoom 0.76
    3.0
    parallel:
        "fountain" with Dissolve(2.0)
    parallel:
        easein 3.0 zoom 1.3333
    parallel:
        easein 3.0 yalign 1.0
    3.0
    easein 3.0 zoom 0.48
    3.0
etc., so you use it just like this:

Code: Select all

add "slideshow"
Also, I haven't checked "Retaining Data After Load", maybe it could be useful too?

PS. Correction: "$" before "renpy.pop_call()".

User avatar
Kinmoku
Miko-Class Veteran
Posts: 560
Joined: Mon Aug 11, 2014 9:39 am
Completed: One Night Stand
Projects: Love IRL, Memories
Tumblr: gamesbykinmoku
itch: kinmoku
Location: Germany
Contact:

Re: Saving during a non-movie cut-scene

#5 Post by Kinmoku » Thu Oct 07, 2021 9:47 am

jeffster wrote:
Thu Oct 07, 2021 9:03 am
So try putting renpy.pop_call() before jumping away:
Oh wow, thank you for such a detailed response. I thought the easiest solution was to add renpy.pop_call() so I went ahead and tried that but that didn't work either. :( However, when I tested it again, I thought I'd add a piece of dialogue...and then it worked! It shows "test" before it is dismissed, but once dismissed it jumps correctly to the label and replays the cut-scene... Although I really don't want to add any dialogue here!

Putting everything in an image is a really cool idea, but I have several sound effects and transitions that would make this tricky. Unfortunately, I'm not very smart when it comes to programming, so I'm a little confused by the Ren'Py documentation on rollback etc.

Anyway, here is my current code:

Code: Select all

label after_load:
    if ffcutscene == "1":
        $ renpy.pop_call()
        "test"
        jump ff1
    elif ffcutscene == "2":
        $ renpy.pop_call()
        jump ff2
    elif ffcutscene == "3":
        $ renpy.pop_call()
        jump ff3
    elif ffcutscene == "4":
        $ renpy.pop_call()
        jump ff4
    elif ffcutscene == "5":
        $ renpy.pop_call()
        jump ff5
    elif ffcutscene == "6":
        $ renpy.pop_call()
        jump ff6
    elif ffcutscene == "7":
        $ renpy.pop_call()
        jump ff7

    return

jeffster
Regular
Posts: 123
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Saving during a non-movie cut-scene

#6 Post by jeffster » Thu Oct 07, 2021 1:37 pm

I do not have experience with animations, apart from main menu slideshow, so I don't know what to say.

I tried to make an animated scene but it was shown together with the dialogue line that followed it.

If I saved and reloaded, that animation was shown, even without "after_load" adjustments.

So it seems that visual scenes become a part of the dialogue statement that follows after them.

I'm not sure how your animation is different.

User avatar
Kinmoku
Miko-Class Veteran
Posts: 560
Joined: Mon Aug 11, 2014 9:39 am
Completed: One Night Stand
Projects: Love IRL, Memories
Tumblr: gamesbykinmoku
itch: kinmoku
Location: Germany
Contact:

Re: Saving during a non-movie cut-scene

#7 Post by Kinmoku » Fri Oct 08, 2021 3:47 am

Hmm. I made a new game and stripped the cutscene down, removing music, sounds, variables etc to see if something was causing it, but it still behaves in the same way.

Code: Select all

label start:
    scene black
    with wiperight

    pause 0.5

    scene ffintrobg at tiltdown
    show intro-hanzo good at tiltcharacter1down
    show ff intro attack1 at tiltcharacter2down
    with loadoff

    pause 5
    
    scene ffintrofire at tiltup
    show intro-hanzo evil at tiltcharacter2up
    show intro-fall at tiltcharacter1up
    with loadoff

    pause 0.1

    show master-ugh at ff_br with ffpopup

    pause 1.5

    hide master-ugh at ff_br with ffpopup

    pause 2.4
    
    show ff intro hanzo closeup at tiltup
    with loadoff

    pause 2.5

    show hanzo-farewell at ff_bl with ffpopup

    pause 2
    
    hide hanzo-farewell at ff_bl
    scene black
    with checkerboard

    pause 1

    scene irl intro excited at tiltupquick
    with dissolve

    pause 2.5

    eintro "No way!"

    return

label after_load:
    $ renpy.pop_call()
    jump start
    return
As you can see, there are quite a few transforms and effects, but I doubt these would cause issues. Like last time, if I add "test" to the after_load label, it works, otherwise it skips to eintro "no way!" on load.

User avatar
Ocelot
Eileen-Class Veteran
Posts: 1883
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

Re: Saving during a non-movie cut-scene

#8 Post by Ocelot » Fri Oct 08, 2021 4:41 am

Is disabling saving during cutscenes out of the question? It just may be easier that way.
< < insert Rick Cook quote here > >

User avatar
Kinmoku
Miko-Class Veteran
Posts: 560
Joined: Mon Aug 11, 2014 9:39 am
Completed: One Night Stand
Projects: Love IRL, Memories
Tumblr: gamesbykinmoku
itch: kinmoku
Location: Germany
Contact:

Re: Saving during a non-movie cut-scene

#9 Post by Kinmoku » Fri Oct 08, 2021 8:06 am

Ocelot wrote:
Fri Oct 08, 2021 4:41 am
Is disabling saving during cutscenes out of the question? It just may be easier that way.
That was my original plan, but I worry this may lead to some negative feedback or cause problems porting to consoles. Having load skip the cutscene as it currently does is preferred to that.

The longest cutscene is two minutes, so there maybe some people who'd like to save in that time.

I've considered a compromise of a pause screen, which allows the player to skip the scene and then save... but when a movie clip works exactly as I want, I'm more tempted to record the screen, remove the code and just play the movie.

User avatar
Alex
Lemma-Class Veteran
Posts: 2981
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Saving during a non-movie cut-scene

#10 Post by Alex » Fri Oct 08, 2021 8:39 am

Kinmoku wrote:
Fri Oct 08, 2021 8:06 am
...
Just a shot in the dark - try to replace all pause statements with $ renpy.pause(1.0).

jeffster
Regular
Posts: 123
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Saving during a non-movie cut-scene

#11 Post by jeffster » Fri Oct 08, 2021 9:08 am

I would think about some dirty hack, like jumping to the previous dialogue line after load.

When games get upgrades it often happens that Ren'Py loads saves from previous versions a few lines shifted back, and it's not a problem.

I also don't mind to recall what was there, when I didn't play that game for some time, and so I do a little rollback after load.

Alternatively, you could (and maybe should) break long animations in parts with dialogue screens in between (like "..." or "Later that morning..." or "At the Master's doorsteps..." or "Tears were filling my ears... " :P etc.)

User avatar
Kinmoku
Miko-Class Veteran
Posts: 560
Joined: Mon Aug 11, 2014 9:39 am
Completed: One Night Stand
Projects: Love IRL, Memories
Tumblr: gamesbykinmoku
itch: kinmoku
Location: Germany
Contact:

Re: Saving during a non-movie cut-scene

#12 Post by Kinmoku » Fri Oct 08, 2021 9:17 am

Alex wrote:
Fri Oct 08, 2021 8:39 am
Just a shot in the dark - try to replace all pause statements with $ renpy.pause(1.0).
That was my original code, but that's when I noticed it not working :(
jeffster wrote:
Fri Oct 08, 2021 9:08 am
I would think about some dirty hack, like jumping to the previous dialogue line after load.
This actually sounds like a pretty good idea! I think I'll try this.

UPDATE: I moved the labels I was jumping to to the previous dialogue line. It works now, even if it's not quite where the player saved. Thanks for the help everyone :)

User avatar
Kinmoku
Miko-Class Veteran
Posts: 560
Joined: Mon Aug 11, 2014 9:39 am
Completed: One Night Stand
Projects: Love IRL, Memories
Tumblr: gamesbykinmoku
itch: kinmoku
Location: Germany
Contact:

Re: Saving during a non-movie cut-scene

#13 Post by Kinmoku » Thu Nov 18, 2021 12:14 pm

I'm back! I encountered some issues with this, mostly because my game uses screens and images a lot (and not dialogue :( ).

Code: Select all

label ff2:
    $ ffcutscene = "2"
    scene white
    with dissolve

    show chapterline

    pause 1.0

    show expression Text("{color=#000000}A few days later...{/color}", slow_cps=20, xpos=1860, ypos=936, xanchor=1.0)

    pause
    
    #cut scene here etc
    
label after_load:
    if ffcutscene == "2":
        $ renpy.pop_call()
        jump ff2

    return

When the player saves during the cut scene and then tries to load it, this gets stuck on "pause" - no clicking will help it go away. When I removed "pause" during my test, it behaves as it did earlier i.e. skips to the end of the cut scene... but the game can continue, at least!

I'm starting to think that saving must be disabled during cut scenes with a skip option if people don't want to wait, because what's EVEN worse is what I have now i.e. the false pretense that the game is saved, when really it cannot be resumed from the save file.

Post Reply

Who is online

Users browsing this forum: Bing [Bot], _ticlock_