Insert variables into code instead of into strings?

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.
Message
Author
Apa
Regular
Posts: 103
Joined: Fri Dec 23, 2016 2:26 am
Location: NYC
Contact:

Re: Insert variables into code instead of into strings?

#16 Post by Apa »

No prob. I hope you understand what I am looking for exactly.
Does it make any sense to ask here?

User avatar
PyTom
Ren'Py Creator
Posts: 16096
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Insert variables into code instead of into strings?

#17 Post by PyTom »

config.lint_hooks gives a list of functions that are called at lint time. You could use that to check it, but it only runs after define statements are called - default statements would not be set yet. But you probably want _hooks to be a define rather than a default anyway, unless it changes after the game is run.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

Apa
Regular
Posts: 103
Joined: Fri Dec 23, 2016 2:26 am
Location: NYC
Contact:

Re: Insert variables into code instead of into strings?

#18 Post by Apa »

PyTom wrote:config.lint_hooks gives a list of functions that are called at lint time. You could use that to check it, but it only runs after define statements are called - default statements would not be set yet. But you probably want _hooks to be a define rather than a default anyway, unless it changes after the game is run.
PyTom,
Thanks for clarification!
Compete game code is here (38 lines)
Looks like there is no problem with define custom_link_check() function.
But what is the best way to handle default variables then?

Code: Select all

default room = "home"
default rooms = {
    "home" : ["yard", "city"],
    "yard" : ["home",],
    "city" : ["home",],
}
Just change default to define?

User avatar
PyTom
Ren'Py Creator
Posts: 16096
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Insert variables into code instead of into strings?

#19 Post by PyTom »

You basically can't lint default variables.

That being said, it looks like rooms should not be a default variable. It never changes, so there's no need to stick it in default. I might write this code like;'

Code: Select all

define default_room = "home"
default room = default_room
deine rooms = {
    "home" : ["yard", "city"],
    "yard" : ["home",],
    "city" : ["home",],
}
That makes default_room and rooms both available to your lint code, which probably should be enough to do any check you want to.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

Apa
Regular
Posts: 103
Joined: Fri Dec 23, 2016 2:26 am
Location: NYC
Contact:

Re: Insert variables into code instead of into strings?

#20 Post by Apa »

PyTom,
Thanks again for your invaluable help!
Here is final "location wondering" game code, with intentional misspelling catch-able by lint.
Could you comment, if it can be done any better, please?

Code: Select all

define home = "home"
define city = "city"
define yard = "yard"

define rooms = { 
    home : [yard, city],
    yard : [home,],
    city : [home,],
}
default room = home


label home:
    "It's boring at home..."
    return

label yard:
    "Wow, back yard!"
    return

label city1:
    "No way!"
    return

label start:
    "You are here: [room]"
    call expression room
    $ items = [(i, i) for i in rooms[room]]
    $ room = renpy.display_menu(items)
    jump start


label splashscreen:
    "config.lint_hooks: [config.lint_hooks]"
    $ missing = check_labels()
    if missing:
        "missing labels: [missing]"
    return


init python:
    def check_labels():
        z = [l for w in rooms for l in rooms[w]]
        z.extend([w for w in rooms])
        return [w for w in set(z) if not renpy.has_label(w)]

    def lint():
        missing = check_labels()
        if missing: print("Missing labels:", missing)

    config.lint_hooks.append(lint)
I was wondering, is there a way to replace

Code: Select all

define home = "home"
with

Code: Select all

define home = label_name(home) # returns label name as string, i.e. "home" for "label home:"
If it is one, all above won’t be necessary.

Still, it was nice to learn, we can add custom lint code easily! :D

User avatar
PyTom
Ren'Py Creator
Posts: 16096
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Insert variables into code instead of into strings?

#21 Post by PyTom »

No, you really can't do better than that. You also already check that, since has_label will fail if the define is wrong. If I was really obsessed with checking this, I might do something like check to see that the graph was fully connected - there's always a path from A->B and B->A. But that's code you can find in a tutorial on graph theory.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

Apa
Regular
Posts: 103
Joined: Fri Dec 23, 2016 2:26 am
Location: NYC
Contact:

Re: Insert variables into code instead of into strings?

#22 Post by Apa »

PyTom wrote:If I was really obsessed with checking this, I might do something like check to see that the graph was fully connected - there's always a path from A->B and B->A. But that's code you can find in a tutorial on graph theory.
That’ll be more like checking game logic.
The graph describes places where you can travel.
The idea was to update it with new nodes as game progress.
Now, that mentioned it, is seems more reasonable to set path from very beginning (so we can lint it all!) and have flag to show if a node is available at current game stage.

Code: Select all

define rooms_ex = { # "e" - enabled, "n" - nodes
    home :   { "e" : True,  "n": [yard, city], },
    yard :   { "e" : True,  "n": [home,], },
    city :   { "e" : True,  "n": [home, beyond], },
    beyond : { "e" : False, "n": [city,], },
}
I haven’t check it yet, I hope, it won’t be a problem with game save/load when beyond become available later in the game (beyond : { "e" : True, ... }), right?
Thanks again! :D

Update:
Just checked, there is a problem with game save/load with it.
Need to add a bit more code to handle it properly, I guess.
I'll post code later, need shovel snow right now! :D

Apa
Regular
Posts: 103
Joined: Fri Dec 23, 2016 2:26 am
Location: NYC
Contact:

Re: Insert variables into code instead of into strings?

#23 Post by Apa »

I don’t know easy way to fix load/save (and rollback too, I guess)
I don’t see "defined" variables in Variable viewer, only "defaulted" ones.
So I created another default variable and aliased it to defined one.

Code: Select all

define rooms_init = { # "e" - enabled, "n" - nodes
...
}
default room = home
I know, it’s a bad thing to do...
I’d appreciate an advice how to do it right.

Full code:

Code: Select all

define home = "home"
define city = "city"
define yard = "yard"
define beyond = "beyond"

# Map: yard <-> home <-> city <?> beyond
# * beyond opens after visiting yard
define rooms_init = { # "e" - enabled, "n" - nodes
    home :   { "e" : True,  "n": [yard, city], },
    yard :   { "e" : True,  "n": [home,], },
    city :   { "e" : True,  "n": [home, beyond], },
    beyond : { "e" : False, "n": [city,], },
}

default room = home
default rooms = rooms_init


label home:
    "Home Sweet Home!"
    return


label yard:
    "Wow, back yard!"
    $ rooms[beyond]['e'] = True
    return


label city:
    if rooms[beyond]['e']:
       "I see beautiful beyond!!!"
    else:
       "Nothing interesting..."
    return


label start:
    call expression room
    $ narrator("You are here: %s" % room, interact=False)
    $ items = [("Go to %s" % r, r) for r in rooms[room]['n'] if rooms[r]['e']] # get enabled rooms list
    $ room = renpy.display_menu(items)
    jump start


label splashscreen:
    $ missing = check_labels()
    if missing:
        "{color=#FF0000}{b}Missing labels: [missing]{/b}{/color}"
    return


init python:
    def check_labels():
        z = [n for r in rooms_init for n in rooms_init[r]['n']]
        z.extend([r for r in rooms_init])
        return [w for w in set(z) if not renpy.has_label(w)]

    def lint():
        missing = check_labels()
        if missing: print("Missing labels:", missing)

    config.lint_hooks.append(lint)
Seems, I cannot get spoiler tag work to hide my code... :?

Post Reply

Who is online

Users browsing this forum: Google [Bot]