Ren'Py Labels & Control

Evildad

Member
Jan 7, 2019
113
218
Hello,
I need help for my current project again.
Is there a way to query which label you are currently on?
Without assigning a variable to each label.
 

LightmanP

Well-Known Member
Modder
Game Developer
Oct 5, 2020
1,669
15,441
I saw Qleaf doing this in one of his mods:

Python:
    current_label = ""
   
    def label_callback(name, abnormal):
        if name.startswith("_") or name == "save_screen": return
        store.current_label = name

    config.label_callback = label_callback
current_label can then be used to check which label the game is currently on. Similiar advice found .
I'm sure that 79flavors or anne O'nymous could weigh in on this better. I think it would also be good to know what your end goal is.

Such threads could get more attention at Dev help forum.
 

Evildad

Member
Jan 7, 2019
113
218
Thank you so much!

I am currently creating image-based navigation. But depending on where I am, buttons should be hidden or hidden and provide additional functions.
In my first draft I created a variable event_label and assigned numbers to the individual labels. Now I ask inside the screen which number is stored.

Let's see what works better.

Python:
label Hinter_dem_Haus:
    $ event_label = 1
   
    show screen game_navigation
   
    window hide
    $ renpy.pause(hard=True)
Python:
screen game_navigation () :

    hbox:
        style "navi_style"

        xalign 0.5
        yalign 0.98

        imagebutton:
            xalign 0.5
            idle "navi_haus"
            hover "navi_haus_hover"
            action Hide("game_navigation") , Show("game_navigation2")

        imagebutton:
            xalign 0.2
            idle "navi_arbeit"
            hover "navi_arbeit_hover"
            action Hide("game_navigation") , Show("game_navigation_arbeit")

        imagebutton:
            xalign 0.2
            idle "navi_map"
            hover "navi_map_hover"
            action Hide("game_navigation") , Show("game_navigation3")
           
           
           
#--------------------------------------

screen game_navigation_arbeit () :

    hbox:

        xalign 0.5
        yalign 0.85

        if event_label == 0:
            textbutton _("Umschauen") action Call("sammeln_vor_dem_haus")
        if event_label == 1:
            textbutton _("Beeren Sammeln") action Hide("game_navigation_arbeit") , Call("beeren_hinter_haus")
Python:
label beeren_hinter_haus:
    if Beeren_hinter_haus == False:
        "Du sammelst eine Handvoll Beeren."
        $ Beeren_hinter_haus = True
        $ Nahrungsspeicher += 5
        call max_min_lager from _call_max_min_lager
        jump Hinter_dem_Haus
    else:
        "Du hast heute genug gesammelt. Versuche es morgen wieder."
        jump Hinter_dem_Haus
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,299
15,166
I'm sure that 79flavors or anne O'nymous could weigh in on this better.
I can, and I can even tell why his code is broke ; probably works, but this is "until it don't".

The code to use have not really evolved since I gave it in my compatibility How-to:
Python:
init python:

    #  Give you the effective current label.
    def currentLabel():
        try: return labelsStack[renpy.call_stack_depth()]
        except: return None

    def labelCB( lName, abnormal=False ):
            #  The /from/ clause of the /call/ statement create a label that will be
            # reached by a /return/ and that shouldn't change the name of the
            # current label.
            if abnormal is False: return

            #  Ren'py's core have a tons of label, and you absolutely don't care
            # about them. Assuming that they all, and will always all, starts with
            # '-' is a wrong assumption.
            if renpy.get_filename_line()[0].startswith( 'renpy' ): return

            #  Labels can be jumped or called, and you need to know what is the
            # current label even after a /call/|/return/ chain. Therefore you don't
            # just store the label name flat, but store the label for the current
            # "call stack" depth.
            labelsStack.update( { renpy.call_stack_depth(): lName } )

    # Finally you define the callback for it to be used.
    config.label_callback = labelCB

default labelsStack = {}

In my first draft I created a variable event_label and assigned numbers to the individual labels. [...]
Let's see what works better.
Totally depend of the number you give.

If it's one different for each label, then it's the callback solution that will works the best. You'll often mess in the label number, assigning the same twice, not testing the right value, and things like that.
But if it's the "1 is for 'show this'", "2 is for 'show that'" kind of numbers, then it's number. You'll have less values and explicit ones to test.

This being said, currentLabel function can perfectly be coupled with a whatToShow function. If you give consistent names to your labels, it can facilitate your job :
Python:
def whatToShow():
    cLabel = currentLabel()
    try:
        if cLabel.startswith( "something_" ):
            return 1   # as in "1 is for 'show this'"
        elif cLabel.endswith( "_another_thing" ):
            return 2 # as in "2 is for 'show that'"
        else:
            #  Raise an exception on error, so no need to
            # test the value unless you explicitly need it.
            # But this also imply a different syntax since the
            # exception break the /if/ structure.
            try:            
                cLabel.index( "_that_" )
                return 3 # as in "3 is for 'show this and that'"
           except:
                pass # mean, "do not contain '_that_'"
           try:
                cLabel.index( "_boo_" )
                return 4 # as in ...
           except:
                pass # mean, "do not contain '_boo_'"
    except:
        pass # No need to effectively treat the exception.
    return 0   # as in "0 is for 'default behavior'"
Then labels "something_girl1" and "something_day5" will return "1", labels "girl1_another_thing" and "girl2_another_thing" will return "2", and labels "girl1_that_day1" and "girl1_that_day2" will return "3". This while every other labels will return "0".


Edit:
More explicit code for the index part.
 
Last edited:

Mastur Bar

Member
Game Developer
Oct 7, 2021
232
165
I can, and I can even tell why his code is broke ; probably works, but this is "until it don't".

The code to use have not really evolved since I gave it in my compatibility How-to:
Python:
init python:

    #  Give you the effective current label.
    def currentLabel():
        try: return labelsStack[renpy.call_stack_depth()]
        except: return None

    def labelCB( lName, abnormal=False ):
            #  The /from/ clause of the /call/ statement create a label that will be
            # reached by a /return/ and that shouldn't change the name of the
            # current label.
            if abnormal is False: return

            #  Ren'py's core have a tons of label, and you absolutely don't care
            # about them. Assuming that they all, and will always all, starts with
            # '-' is a wrong assumption.
            if renpy.get_filename_line()[0].startswith( 'renpy' ): return

            #  Labels can be jumped or called, and you need to know what is the
            # current label even after a /call/|/return/ chain. Therefore you don't
            # just store the label name flat, but store the label for the current
            # "call stack" depth.
            labelsStack.update( { renpy.call_stack_depth(): lName } )

    # Finally you define the callback for it to be used.
    config.label_callback = labelCB

default labelsStack = {}



Totally depend of the number you give.

If it's one different for each label, then it's the callback solution that will works the best. You'll often mess in the label number, assigning the same twice, not testing the right value, and things like that.
But if it's the "1 is for 'show this'", "2 is for 'show that'" kind of numbers, then it's number. You'll have less values and explicit ones to test.

This being said, currentLabel function can perfectly be coupled with a whatToShow function. If you give consistent names to your labels, it can facilitate your job :
Python:
def whatToShow():
    cLabel = currentLabel()
    try:
        if cLabel.startswith( "something_" ):
            return 1   # as in "1 is for 'show this'"
        elif cLabel.endswith( "_another_thing" ):
            return 2 # as in "2 is for 'show that'"
        else:
            #  Raise an exception on error, so no need to
            # test the value unless you explicitly need it.
            # But this also imply a different syntax since the
            # exception break the /if/ structure.
            try:           
                cLabel.index( "_that_" )
                return 3 # as in "3 is for 'show this and that'"
           except:
                pass # mean, "do not contain '_that_'"
           try:
                cLabel.index( "_boo_" )
                return 4 # as in ...
           except:
                pass # mean, "do not contain '_boo_'"
    except:
        pass # No need to effectively treat the exception.
    return 0   # as in "0 is for 'default behavior'"
Then labels "something_girl1" and "something_day5" will return "1", labels "girl1_another_thing" and "girl2_another_thing" will return "2", and labels "girl1_that_day1" and "girl1_that_day2" will return "3". This while every other labels will return "0".


Edit:
More explicit code for the index part.
Dude, my deepest thanks, you helped me to fix a problem I was struggling to solve.