RenPy beginner questions

Discussion in 'Programming & Development' started by Lyka, Sep 29, 2018.

  1. HopesGaming

    HopesGaming The Godfather Game Developer

    217
    616
    Dec 21, 2017
    Then I think you are underestimating the code a bit.
    And not something that can be easily explained here.

    Check these guides instead;

    Please Log in / Register to view this link


    And

    Please Log in / Register to view this link



    The last one was what I used to create my navigation system.
     
  2. Lyka

    Lyka Member

    38
    5
    Aug 31, 2018
    i'm through with the first link. i read it weeks ago.
    i have a map running (newest is a bus travel between 2 maps), serval locations , sleeping, shop, day night sycle, even random stuff works allready

    the 2nd link is nice, maybe i can use it on another project in the far far future.

    my problem is the timed story quests. the conditions are "storArc == x Day == x variablex == x -> start quest"


    and i need some little codes for this:

    if variablex == 5 AND NOW 10,15,20,25 and so on
    or steps like 5,10,17,26...

    right now im using this code to solve it:
    elif variablex == 5 or variablex == 10 or variablex == 15 or variablex == 20:
    but if i go on like this this line will be gigantic long
     
  3. anne O'nymous

    anne O'nymous Well-Known Member Modder

    1,301
    1,312
    Jun 10, 2017
    You're neither right nor wrong, it's your premise that's wrong. The leading "$" doesn't mean, "what's following is a variable", but, "what's following is a line in Python language".
    So, it's :
    Code:
    $ storyArc += 1
    
    because you're using Python language to increment the value of storyArc, but it's :
    Code:
    default storyArc = 0
    
    because you're using Ren'py language to create the storyArc variable and assign it 0 as default value.


    Not only it's not a problem, but it's mandatory. The code I gave as example was based on

    Please Log in / Register to view this link

    . It mean that, at some point, the game would have returned to this part of the code, and then incremented storyArc. But if you use

    Please Log in / Register to view this link

    instead, then you need to increment the value before the jump. This because the game will never come back where you jumped, and so will never play the line following the jump statement.
    Code:
    default someFlag = True
    
    label start:
        if someFlag is True:
            call calledLabel
            "You returned to the calling label."
            $ someFlag is False
        else:
            jump jumpedLabel
            "You'll never see this line."
        jump start
    
    label calledLabel:
        "You are in a called label."
        "You've temporarily quit the main flow of the game."
        "Ren'py remember in which label and at what line you were before."
        "And it's time to return to this said main flow."
        return
    
    label jumpedLabel:
        "You are in a jumped label."
        "You still are in the main flow of the game."
        "Ren'py forgot everything about the label you were before."
        "If you try to return back, it will just end the game."
        return
    


    An if statement is followed by a condition, and this condition can be (almost) whatever you want.
    Code:
    init python:
        def aFunction():
            return 12
    
        aVariable = 2
        anArray = [ 0, 5, 10 ]
    
    label start:
        # This condition is True, 'aFunction' return the value 12.
        if aFunction() == 12:
           [...]
        # This condition is False, 'aVariable' value is not 5.
        elif aVariable == 5:
           [...]
        # This condition is True, the second row of 'anArray' contain the value 5.
        # Note: Row are numbered starting at 0. So the row number is the /index/ + 1
        elif anArray[1] == 5:
           [...]
        # This condition is True, the row (value of 'aVariable', so 2) of 'anArray'
        # contain the value 10.
        elif anArray[aVariable] == 10:
           [...]
        # And you can combine all this
        # anArray[1] == 5 -> True
        # aVariable == 5 -> False
        # True and False -> False
        # aFunction() == 12  -> True
        # False or True -> True
        # So, this condition is True.
        elif ( anArray[1] == 5 and aVariable == 5 ) or aFunction() == 12:
            [...]
    


    Sorry, I really not sure that I understand the question.


    Try to take the habit to only use spaces when writing code for Ren'py and Python. I know, it's a pain in the ass... But it will prevent an accident when one day you'll end with real tabulation characters in your code ; what both Ren'py and Python really hate.


    By doing this ?
    Code:
    label something:
        if storyArc == 0 and day >= 5 and variablex >=4:
            jump park
    

    Effectively, it can't be the solution. Like you're making a free roaming game it will all rely on the main design of your code, and there's many way to design the code for this.
    The solution that look the most obvious here is to split the code and use a Ren'py label as a function with the help of the (not so greatly documented)

    Please Log in / Register to view this link

    statement :
    Code:
    #  This label MUST be called, and can be called from many different
    # places in your code.
    #  Like I explained before, it will pass all the conditions for all the
    # events, and stop at the first condition that pass.
    #  When a condition pass, it will return the name of the label
    # corresponding to the event. Note that it MUST be a string.
    #  If all condition fail, it will return the None value ("there's nothing for you").
    label eventTesting:
        if storyArc == 0 and day >= 5 and variablex >=6:
            return "parkFirstEvent"
       elif storyArc == 1 and day >= 7:
            return "parkSecondEvent"
       # All other condition have failed, so there's no event actually
       else:
            return None
    
    label something:
        [...]
        # Time to see if an event is triggered.
        call eventTesting
        # If the label return something else that None.
        if not _return is None:
            #  Play the event by jumping to the label named according to
            # the value of '_return'.
            jump expression _return
        # Here, do what you'll have done if there were no event...
        # because there were no event :D
        [...]
    
    label anotherLabel:
        [...]
        # Time to see if an event is triggered.
        call eventTesting
        # If the label return something else that None.
        if not _return is None:
            #  Play the event by jumping to the label named according to
            # the value of '_return'.
            jump expression _return
        # Here, do what you'll have done if there were no event...
        # because there were no event :D
        [...]
    
    It's just one of the way to do it, but it's a way that works ;)
    Note that you need to return the value. You can not jump from the 'eventTesting' label. This label is called, if you don't return from it, it will mess with the game flow and can lead to many problems.
    There's way to deal with these problems, but you're too young with Ren'py for this. First understand the difference between jumped labels and called ones, then learn to use them correctly.
    Knowing how to mess with them, to call, jump, then return, or to force Ren'py to forget there were a call, can wait that you master the control of the game flow first.
    In the same way, you need to call the said 'eventTesting' label. It's the only way you have to return where you were in the game, if there's no events.


    No need to be sorry. If you knew the amount of times I have passed trying to do this, or that, with Ren'py... sometimes to finally discover, after many headache, that there were an easy way to do it. And I'm sure that it's also the case for anyone here.


    Well, yes there's but it don't do what you expect. It's the

    Please Log in / Register to view this link

    () function. But it only check if the given label exist or not.
    And this lead to an improvement to the code I gave :
    Code:
    label anotherLabel:
        [...]
        call eventTesting
        if not _return is None:
            if renpy.has_label( _return ):
                jump expression _return
            else:
                $ renpy.notify( "Something goes wrong, label "{}" is missing. Sorry for the inconvenient.".format( _return ) )
    
    If you forgot to create the label for the event, or misnamed it, it will not break the game. A warning will be displayed to the player, letting you know that there's a problem, but the game will continue like if there wasn't an event to play at this moment.
     
    Lyka and HopesGaming like this.
  4. anne O'nymous

    anne O'nymous Well-Known Member Modder

    1,301
    1,312
    Jun 10, 2017
    [sorry for the double post]
    Then don't do it like this.
    It will need that you call the label (see my comment right above), but you can delay the condition later. To not lost you, I will reuse the code I explained above, and the example you gave for the park label:

    Code:
    label eventTesting:
       if storyArc == 0 and day >= 5:
           return "parkFirstEvent"
       elif storyArc == 1 and day >= 7:
           return "parkSecondEvent"
       else:
           return None
    
    label something:
       [...]
       call eventTesting
       if not _return is None:
           # Note that now you CALL the label, instead of jumping to it
           call expression _return
       # You reach here either if there were no event, and if the event
       # is now finished.
       [...]
    
    label parkFirstEvent:
       # The second part of the condition are not reached.
       # Return instead of playing the event.
       if variablex != 5 and variablex != 10 and variablex != 15 and variablex != 20:
           return
        scene park
        menu:
            "walk around":
                $ time += 1
            "jump in the water":
                [whatever]
        # Here is the problem with this method. You NEED to return, it's MANDATORY
        return
    
    Like I said, this structure imply that you return from every single called label. So it will complicate a little the way you'll write your events. But in the same time, it will really ease the main structure of the code.
     
    Lyka likes this.
  5. Lyka

    Lyka Member

    38
    5
    Aug 31, 2018
    [Knowing how to mess with them, to call, jump, then return, or to force Ren'py to forget there were a call, can wait that you master the control of the game flow first.]

    "return and call" i have to start with this now.... or next week :)


    Just a test if i'm on the right page now.
    "label testing" is where every event start time condition goes in and send me from there to the next label
    "call eventTesting" let the code check if there is a a event inside for usage and if there isn't
    then this line "if not _return is None:" send it back and let the player be able to sleep ect.

    Now i could hammer the conditions in "label eventTesting" while i only add this 2 lines "call eventTesting" and
    "if not _return is None:" to all my locations. after that it won't matter where i go since it will be testet everywhere

    Code:
    
    default storyArc = 0
    
    label eventTesting:
       if storyArc == 0 and day >= 5 and variable >5:
          return "parkFirstEvent"
       elif storyArc == 1 and day >= 7 and variable >10:
          return "parkSecondEvent"
       else:
          return None
     
    ###random location
    label inn:
       call eventTesting
       if not _return is None:
        scene bar
        play music "<loop 6.333>sfx/inn.mp3"
        menu mainMenu0:
             "sleep":
                [....]
    


    about this what i think is pretty cool:
    to run this is another call required or? "call anotherlabel and if not _return is None:"

    Code:
    label anotherLabel:
       [...]
       call eventTesting
       if not _return is None:
           if renpy.has_label( _return ):
               jump expression _return
           else:
               $ renpy.notify( "Something goes wrong, label "{}" is missing. Sorry for the inconvenient.".format( _return ) )
    



    that means the" return" at this point would hinder me to get into the park if the variablex condtion isn't fulfilled?


    Code:
    label parkFirstEvent:
       # The second part of the condition are not reached.
       # Return instead of playing the event.
       if variablex != 5 and variablex != 10 and variablex != 15 and variablex != 20:
          return
       scene park
       menu:
           "walk around":
               $ time += 1
           "jump in the water":
               [whatever]
       # Here is the problem with this method. You NEED to return, it's MANDATORY
       return
    
     
  6. Maim Lain

    Maim Lain Active Member Modder

    363
    590
    Apr 4, 2018
    @anne O'nymous
    Code:
    label something:
       call eventTesting
       if not _return is None:
           # Note that now you CALL the label, instead of jumping to it
           call expression _return
    What is this '_return' black magic? I'm assuming it has to be value of the last thing that was returned. But not directly evaluating the return value of the label feels dirty.

    Edit: Okay here's how I would do it.
    Code:
    default day = 6
    
    label start:
        jump park
    
    label park:
        call event_testing
        "bye"
        return
    
    label event_testing:
        if day >= 5:
            call expression "parkFirstEvent"
            return
        elif day >= 7:
            call expression "parkSecondEvent"
            return
        else:
            return
    
    label parkFirstEvent:
        "hi"
        return
    
     
  7. anne O'nymous

    anne O'nymous Well-Known Member Modder

    1,301
    1,312
    Jun 10, 2017
    I'll answer both at once because the questions are deeply linked.

    Normally a coding programming language works with the help of a stack. Basically it looks like this :
    • You call a function ;
    • The actual position is stored in the stack ;
    • The parameters sent are stored in the stack ;
    • The code pointer is changed from "actual position" to "start of the function" ;
    • The parameters are retrieved from the stack ;
    • The function is played ;
    • The previous "actual position" is retrieved from the stack ;
    • The returned values are stored in the stack ;
    • The code pointer is changed from "position in the function" to "retrieved 'actual position'" ;
    • The returned values are retrieved from the stack.

    But, still basically, Ren'py works like this :
    1. Ren'py look at dontRememberWhat.next to know what's the next statement ;
    2. Ren'py play this statement ;
    3. Ren'py loop in 1, unless the statement is a return, call (and few many).
    If the statement is a call then :
    • Ren'py store the actual statement in the stack ;
    • Ren'py store the parameters in store._args and store.__kwargs ;
    • Ren'py put the position of the called label in dontRememberWhat.next ;
    • Ren'py raise a "CallException" exception ;
    • Ren'py intercept the said exception ;
    • Ren'py loop in the 1 of above.
    If the statement in a return then :
    • Ren'py store the returned value in store._return ;
    • Ren'py retrieve the position stored in the stack and assign it to dontRememberWhat.next ;
    • Ren'py loop in the 1 of above.

    Technically a call statement neither pass parameters nor return a value. I don't know why Tom chose this design, since it already have a stack, but it's probably the easiest anyway. I mean, you need a statement to explicitly call a label, so your code should be :
    Code:
    label park:
        if call event_testing not None:
            call expression call event_testing
    
    Note that you forgot the second call in the second line.

    Which can be read :
    instead of the actual :
    The nested statement imply a way more complicated mechanism behind the scene.

    In the same time, Ren'py works with objects. A statement is just an object with an "execute" method. Like calls are done with the help of an exception, the game quit the current flow and will never return to the "execute" method. So, using the stack to store the returned value mean that a call statement should have been split in two parts : Firstly the object that represent the call itself, then the object that will retrieve the returned value from the stack, and assign it to [whatever said the code].
    Add this to the nested statement needed and in the end you've :
    Which give me headache just by writing it ;) And yet I haventt tried to think about all the other case where a call can be nested :D


    Don't really know it my explanation were clear, but I tried ; sorry if I failed.
     
    Maim Lain and Lyka like this.
  8. Lyka

    Lyka Member

    38
    5
    Aug 31, 2018
    your explanations are a thousend times better then most tutorials out there!!
    ---

    and whats my problem now?

    simple_expression not found
    call expression -> call event_testing

    Code:
    label eventTesting:
       if storyArc == 0 and day >= 5 and activity >5:
          return "eve1"
       elif storyArc == 1 and day >= 7 and activity >10:
          return "eve2"
       else:
           return
    ############### INN ###################
    label inn:
     if call event_testing not None:
        call expression call event_testing
        scene emptybartable
        play music "<loop 6.333>sfx/inn.mp3"
        menu mainMenu0:
            "Work 1 shift":
    
    

    ehm i'm having a bit of a problem:
    i have menu with some options and one of it is "gamling" how can i make it that this one works only once a day?
     
    anne O'nymous likes this.
  9. anne O'nymous

    anne O'nymous Well-Known Member Modder

    1,301
    1,312
    Jun 10, 2017
    Yeah, but no. The code given by @Maim Lain was theoretical, it will never works. Sorry, it's our fault, we got a little too much carried by the subject. Ren'py just don't know how to deal with this.

    What you need is this :

    Code:
    label inn:
        call event_testing
        if _return not None:
        call expression _return
        scene emptybartable
        play music "<loop 6.333>sfx/inn.mp3"
        menu mainMenu0:
            "Work 1 shift":
    
    One think you should probably do is to stop working in your project for few days. But it will not be wasted time.
    Start a new project, and play with call, jump and return. No need for complex code, try things like :
    Code:
    label start:
       call calledLabel( 1, 3 )
       "it returned [_return]"
    
    label calledLabel( a, b ):
        $ retVal = a + b
        return retVal
    
    or
    Code:
    label start:
       call calledLabel
       "I came back here"
    
    label calledLabel:
       "I'm in the called label"
       call expression "once" + "Again"
       "Oh, I'm back in the first called label"
       return
    
    label onceAgain:
        "Still in a called label"
        return
    
    Just let you imagination play, don't hesitate to go wild, and try many things. I doesn't care if some failed. You'll learn to control the flow of your game, you'll understand it better, and it will be all benefit for the code of your game.
     
    Lyka likes this.
  10. Lyka

    Lyka Member

    38
    5
    Aug 31, 2018
    yea it's a good idea to test and learn this it in a new project. right now im running from one error in another i tried it now with those 3 lines and get something about an SyntaxError: unexpected eof while parsing (if _return not None:)

    as always thousand thanks!
     
  11. anne O'nymous

    anne O'nymous Well-Known Member Modder

    1,301
    1,312
    Jun 10, 2017
    Oops. My bad. Focused too much on the 'call' problem and forgot to check the rest. It should be "if not _return is None".
    The "not" mean, "reverse the result", and the "is" is the relation between the two entities, which mean "is strictly equal to". So, here it's the opposite of _return is strictly equal to the none value ; said otherwise, _return is not strictly equal to None.
    The "is" relation is to use with None, True, False.
     
  12. Maim Lain

    Maim Lain Active Member Modder

    363
    590
    Apr 4, 2018
    @Lyka Yeah I would probably take some time to learn a bit more about RenPy like anon said.

    I wrote a couple tutorials recently and one of them is about coding a typical 'dating sim' type of adult game that you might want to check out:

    Please Log in / Register to view this link




    It might be a bit advanced though idk. (and feel free to criticize my tut @anne O'nymous since you're the renpy genius)
    But it does events this way:
    Code:
        if heather.location == "room" and day >=5:
            jump expression heather.current_event

    You code your game using the 'evaluating _return' way that was mentioned. You could

    Please Log in / Register to view this link

    Or you could

    Please Log in / Register to view this link

    Or you could do it the way above. There's lots of ways to code things, and some ways might make more sense to you than others.
     
    anne O'nymous likes this.
  13. Lyka

    Lyka Member

    38
    5
    Aug 31, 2018
    i come this far in less then 15 days (ok i read about python before but not practical)
    maybe a good point for a break and learn some stuff now.
    this is the breaking point for the game. the story must work flawless.
     
  14. anne O'nymous

    anne O'nymous Well-Known Member Modder

    1,301
    1,312
    Jun 10, 2017
    Don't know if I'm really a genius, just someone that had (sometimes) too much free time and pass it with Ren'py. As for your tuts, I have really few things to say about them.
    Regarding the "sim date" :
    Code:
    default a_events = ["null", "a_event_1", "a_event_2", "a_event_3"]
    
    I would have used None instead of "null", but it's a question of personal taste. The problem I see here is not that, but the fact that you didn't explained why the "null". Few lines to explain/remember that array index start at 0, while the level start at 1, should be enough.
    Else, I fear that someone not familiar with coding can be lost and think that "null" is an effective label and that it should be different for all girls.

    Also, you should perhaps use more different names for the events, like "a_park_event", "a_pool_event", etc. It will mark more the difference between the labels. Because with this "a_event_[level]" form, you don't need an array, this is enough :
    Code:
        def __init__(self, name, base_event):
            [...]
            self.base_event = base_event
        def level_up(self):
            [...]
            self.current_event = self.base_event.format( self.level )
        [...]
    
    default alice = Girl("Alice", "a_events_{}" )
    
    You can even start with pure string names and the code that use the array, then as an example of "how to tweak", use the code with the "a_event_{}" form.
    You can even go further :
    Code:
            self.current_event = "{}_event_{}".format( self.name[0].lower(), self.level )
    

    As for the farm code, except the "== True/False" that I would have wrote "is True/False" (again a question of personal taste), I saw only two things.
    Firstly, the use of "global". By default, and if it's part of a .rpy file, Python code is played with store as global namespace, so everything in store is already global to the code. Which make your global useless. You don't even need to prefix the variable. The only exception is when you directly assign a value ; in this case Python is a little lost and will see the variable as local. So, it lead to :
    Code:
    def end_day_cows():
       for num in range(0, len(cow_list)):
           if cow_list[num].is_pregnant:
               cow_list[num].days_pregnant += 1
    
               if cow_list[num].days_pregnant >= 3:
                   store.baby_cows += 1
                   cow_list[num].is_pregnant = False
                   cow_list[num].days_pregnant = 0
       return
    
    The only direct assignation is when you increase baby_cows. So it's the only thing that need to be prefixed.

    The second thing is the fact that you increase the number of day for the pregnancy. Personally I would have decreased it. This open the possibility to have pregnancy that are more or less longer. In the case of four element trainer it doesn't mater since all the "cows" are of the same specie. But if you mix species, you don't have to make exception or to write a pregnancy check for each species.
    Something like :
    Code:
    class Cow():
       def __init__(self, has_been, is_preg, preg_duration, specie ):
           [...]
           self.preg_duration = preg_duration
           self.specie = specie
    
       def breed(self):
           [...]
           self.days_pregnant = self.preg_duration
    
    def end_day_cows():
       for num in range(0, len(cow_list)):
           if cow_list[num].is_pregnant:
               cow_list[num].days_pregnant -= 1
    
               if cow_list[num].days_pregnant == 0:
                   baby_cows[cow_list[num].specie] += 1
                   cow_list[num].is_pregnant = False
    
    Note that this time, baby_cows is not a direct assignation. You assign a value to an entry of the dictionary. So you don't need to prefix it.

    With inheritance you can even end with :
    Code:
    class Animals():
       def __init__(self, has_been, is_preg ):
       [...]
    
       def breed(self):
           [...]
           self.days_pregnant = self.preg_duration
    
    class Human( Animals ):
       def __init__(self, has_been, is_preg ):
           super( Human, self ).__init__( has_been, is_preg )
           self.preg_duration = 3
           self.specie = "human"
    
    class Alien( Animals ):
       # You can even do it in a way that don't care of the effective parameters
       def __init__(self, *args ):
           super( Alien, self ).__init__( *args )
           self.preg_duration = 5
           self.specie = "alien"
    
    def add_animal(type, specie):
       if type == 'fresh':
           cow_list.append(specie(False, False))
       if type == 'used':
           cow_list.append(specie(True, False))
       if type == 'pregnant':
           cow_list.append(specie(True, True))
       return
    
    label buyAFreshHuman:
        $ add_animal( "fresh", Human )
    


    You see, what Maim Lain said is probably the most useful things you'll learn. Ren'py present the advantage to let you do things in many ways. Some are really advanced, other really bad, but as long as it works, you need to use the one you feel the most at ease with. This just because, the more you understand it and the more it feel natural for you, then the more you'll see when you make an error ; so, the less you'll make errors :D
    That's why you need to take a break, time to time, and just mess with the code. It's the best way to tame it, and feel at ease with it.
     
    Maim Lain likes this.
  15. Maim Lain

    Maim Lain Active Member Modder

    363
    590
    Apr 4, 2018
    Thanks for reviewing my stuff. I made changes to the tutorial improving some of the things you mentioned.

    Yeah None is better than "null", and I should have added, 'The reason the first item in the event lists is empty is so that "self.current_event = self.event_list[self.level]" in the level_up() method works. This way event #X will play when your relationship level is X.'


    The type of event progression I had in mind while making the tut is how Mythic Manor and Harem Hotel do events. If you haven't played those basically it goes -> girl is level 1 -> do relationship event 1 with girl -> girl becomes level 2 -> do relationship event 2 with girl -> girl becomes level 3, etc. That's why I had the array since events are completely linear and things like pool/park events are more side events in those games where the logic for triggering those non-relationship level events is at the pool/park/etc.
    But the "self.current_event = f"{self.name[0].lower()}_event_{self.level}" you mentioned is really smart and what I'm going to change it to.


    Ahhhh, thank you! I was completely lost as to why RenPy could read variables but then it would say the variable wasn't declared when trying to assign values to them. That is pretty weird that you only need to write "store." when directly assigning but adding to and changing objects in lists and dicts doesn't need it.


    The pregnancy and inheritance are also both good ideas. I'll add both of those things to the tutorial.

    Thanks for the feedback!
     
    anne O'nymous likes this.
  16. Lyka

    Lyka Member

    38
    5
    Aug 31, 2018
    hope you aren't hungry :)

    am i right with the code?

    Code:
    label start:
       call pizza_luigi
       "you are in LABEL START"
    
    label pizza_luigi:
       "now luigi is called!"
       call expression "pizza_toni"
       "BACK FROM PIZZA TONI AND NOW IN PIZZA LUIGIs LABEL"
       return
    
    label pizza_toni:
        "best pizza only here: pizza toni"
        call expression "pizza_hut"
        "BACK FROM PIZZA HUT AND NOW IN PIZZA TONIs LABEL" # back from pasta
        return #jump pasta
    
    label pizza_hut:
        "cheap pizza at pizza hut"
        jump pasta # after changing return to jump
    
    label pasta:
        "pasta"
        return # it skips label pizza_hut: because no "call expression"?
    
    [Code]
     
    anne O'nymous likes this.
  17. Maim Lain

    Maim Lain Active Member Modder

    363
    590
    Apr 4, 2018
    @Lyka
    Code:
    label start:
       jump pizza_luigi
    
    label pizza_luigi:
       "1"
       call pizza_toni
       "7 - The end."
       return
    
    label pizza_toni:
        "2"
        call pizza_hut
        "6"
        return
    
    label pizza_hut:
        "3"
        call pasta
        "5"
        return
    
    label pasta:
        "4"
        return
    
    You can just write call label_name instead of call expression "label_name" if you're just writing the label name to call.

    Pasta doesn't return to Pizza_Hut because you jumped to pasta instead of calling it. You call if you want to return to the label you were at.

    And notice how I jumped to Luigi_Pizza instead of calling it. I don't want to return to the start label, so I use jump instead of call.
     
    anne O'nymous likes this.
  18. anne O'nymous

    anne O'nymous Well-Known Member Modder

    1,301
    1,312
    Jun 10, 2017
    You missed few details, already covered by @Maim Lain . But, yes you got the spirit ; and that's what matter the most. Congratulation for that.
     
    Lyka likes this.
  19. Lyka

    Lyka Member

    38
    5
    Aug 31, 2018
    thank you for that.

    but there is one thing i don't understand.
    if i go back to my original game then i have to use call to let the condition check and bring me to the events.

    but how do i decide what is better call or jump?
    and what does it mean for the pc: does call storage all the progress and fill the ram and jump wont?
     
  20. anne O'nymous

    anne O'nymous Well-Known Member Modder

    1,301
    1,312
    Jun 10, 2017
    I would say that "you'll know it", but it's part of the truth. You'll know it but only after you've gained more experience.
    Basically, you call a label only because you'll have to return to your starting point. So, it can be because the label is conditional ; like the example I gave above, where part of the condition is put inside the label itself. It can also be because the label do a recurring task, like the one that check for the events, or a label that reset value at the start of each day by example.
    In all the other case, you jump. And remember, what you tried demonstrated that you can have this :
    Code:
    label something:
        call calledLabel
        "blablabla"
    
    label calledLabel:
        jump jumpedLabel
    
    label jumpedLabel:
        return
    
    The return statement is mandatory, since it's what make you return to the starting point, but it isn't necessary that it's put in the label you initially called. What matter is that, at the end of the chain, you have a return.
    I know, it's a bit abstract for now, but it will come naturally after some practice.


    Only the return point is stored, but it don't really use memory space. You can chain 500 call in a row, you'll still use less space that a single picture that Ren'py put in the memory cache. Anyway, once the game found a return, then what was stored is removed from the memory. So basically a game that make a massive (and correct) use of call should use what ? 1 Ko of RAM that isn't used with a game that just jump.
     
    Lyka likes this.