[SOLVED] Generating buttons via a list

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
LyannaCore
Newbie
Posts: 22
Joined: Wed Jun 21, 2017 1:45 pm
Contact:

[SOLVED] Generating buttons via a list

#1 Post by LyannaCore »

I found a very helpful example on here for creating a menu using buttons, which pops up near the mouse when you click on a location button.

Image

Code: Select all

default systemmap_location_lists = {
    "sol",
    "mercury",
    "venus",
}

screen systemmap_location_menus():
    modal True
    default x = renpy.get_mouse_pos()[0]
    default y = renpy.get_mouse_pos()[1]

    frame:
        pos (x + 15, y - 30)
        background Frame("gui/systemmap/location_frame.png", left=25, top=25, right=25, bottom=25, tile=False)
        padding (10, 10)
        vbox:
            spacing -30
            for i in systemmap_location_lists:
                textbutton i:
                    text_style "mapmenu_location_buttons"
                    action NullAction()
It worked great with a bit of tweaking, but now I'm trying to complicate things beyond my skills. I would like for each location button, sol for example, to have it's own selection of buttons, without having to create a duplicate screen for every location. Something to do with the for loop that generates the buttons I would imagine, but I don't know what or how. Maybe I need a function to handle the lists?

I thought maybe something along these lines for a list:

Code: Select all

default systemmap_location_lists = {
    "sol" : {
        "Dyson Ring" : "loc_sol_ring",
    },
    "mercury" : {
        "Mercury Station" : "loc_mercury_station",
    },
    "venus" : {
        "Aeneas Station" : "loc_venus_aeneas",
        "Venus Aerostat" : "loc_venus_aerostat",
    },
}
with the button text and a label for it to jump to, but I'm not sure how to implement that sort of thing.
Last edited by LyannaCore on Sat Aug 11, 2018 2:26 pm, edited 3 times in total.

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Generating buttons via a list

#2 Post by kivik »

So what you've got there is a dictionary, which comes with a weird quirk that they won't be sorted in the order that you want when you loop through it. So it depends on whether you want to preserve the order or not:

To preserve the order, you need to use an OrderedDict, the annoying thing (I could be wrong here) I found is that you can't just throw a dict into an OrderedDict on creation and convert it - which makes sense since it'll immediately lose the order. So you'd have to create it inside a label:

Code: Select all

init python:
    import collections

default locs = collections.OrderedDict()

label start:
    $ locs['test1'] = "Testing1"
    $ locs['test2'] = "Testing2"

    python: # just to show it works
        for key, item in locs.items(): # use items() to loop through an OrderedDict
            renpy.say("", "[key]: [item]")
    return
If order doesn't matter, just use a dict, in which case you can just use your dict declaration using default. Just be aware that if the dict size is different the items will appear in different order. The for loop will be the same whether it's dict or ordereddict.

See if you can convert the code, let us know if you're stuck on anything :)

User avatar
xavimat
Eileen-Class Veteran
Posts: 1461
Joined: Sat Feb 25, 2012 8:45 pm
Completed: Yeshua, Jesus Life, Cops&Robbers
Projects: Fear&Love
Organization: Pilgrim Creations
Github: xavi-mat
itch: pilgrimcreations
Location: Spain
Discord: xavimat
Contact:

Re: Generating buttons via a list

#3 Post by xavimat »

Sorry, but I don't get the reason to use renpy.get_mouse_pos()

IIUIC you want a button on the sun that, when clicked, it shows the frame with the button "Dyson Ring", another button on Mercury that, when clicked shows the frame with the button "Mercury Station" and a third button on Venus that, when clicked, shows two buttons: "Aeneas Station" and "Venus Aerostat".

1. I understand the Venus button, because it shows two buttons, but I think it's a waste of time time to click on sun or Mercury to have only one option to click again. I would understand it if this is only an example and in your real game there are always more than one option in any planet/star.

2. I think you don't need renpy.get_mouse_pos at all, you know the positions of every planet/star, so tell renpy the exact coordinates where you want your frames to appear. this way you can use a normal dict, the order of the loop is not relevant.

Code: Select all

default systemmap_location_lists = {
    "sol" : {
        "coordinates": (40,50),
        "buttons": [
            "Dyson Ring",
            ],
        },
    "mercury" : {
        "coordinates": (100,50),
        "buttons": [
            "Mercury Station",
            ],
        },
    "venus" : {
        "coordinates": (200,50),
        "buttons": [
            "Aeneas Station",
            "Venus Aerostat",
            ],
        },
    }
screen planets():
    default submenu = None
    add "planets_background.jpg"
    for i in systemmap_location_lists:
        button:
            pos systemmap_location_lists[i]["coordinates"]
            xysize (50,50)
            action SetScreenVariable("submenu",i)

        if submenu == i:
            frame:
                pos systemmap_location_lists[i]["coordinates"]
                padding (10,10)
                has vbox
                for i2 in systemmap_location_lists[i]["buttons"]:
                    textbutton i2 action Jump("loc_"+i2.replace(' ', '_').lower())
Comunidad Ren'Py en español: ¡Únete a nuestro Discord!
Rhaier Kingdom A Ren'Py Multiplayer Adventure Visual Novel.
Cops&Robbers A two-player experiment | Fear&Love Why can't we say I love you?
Honest Critique (Avatar made with Chibi Maker by ~gen8)

LyannaCore
Newbie
Posts: 22
Joined: Wed Jun 21, 2017 1:45 pm
Contact:

Re: Generating buttons via a list

#4 Post by LyannaCore »

Thank you both for the suggestions/help. I didn't know there was a difference between lists and dictionaries, but it makes sense looking at the docs.

For the mouse_pos stuff, it was just part of the menu example I found/modified, I think it was intended for an inventory or something. I agree that it makes more sense to just have fixed menu positions so I will probably do that.

For the single button locations, there will be more, but the player needs to discover/unlock them so just getting things working for now. I can probably get it to skip the loop button menu entirely if that part of the dict has less than 2 items or somesuch.

LyannaCore
Newbie
Posts: 22
Joined: Wed Jun 21, 2017 1:45 pm
Contact:

Re: Generating buttons via a list

#5 Post by LyannaCore »

Alright, after more tweaking and changes, I have gotten it to work the way I like. In case anyone else can find this useful, the code is like so.

Code: Select all

default systemmap_location_lists = {
    "sol" : {
        "coordinates": (450, 430),
        "buttons": [
            "Dyson Ring",
            ],
        },
    "mercury" : {
        "coordinates": (536, 451),
        "buttons": [
            "Mercury Station",
            ],
        },
    "venus" : {
        "coordinates": (611, 543),
        "buttons": [
            "Aeneas Station",
            "Venus Aerostat",
            ],
        },
    }
    
screen systemmap_location_menus(location):
    modal True
    imagebutton:
        idle "gui/systemmap/5percent.png"
        hover "gui/systemmap/5percent.png"
        focus_mask None
        action Hide("systemmap_location_menus")

    frame:
        pos systemmap_location_lists[location]["coordinates"]
        background Frame("gui/systemmap/location_frame.png", left=25, top=25, right=25, bottom=25, tile=False)
        padding (10, 10)
        vbox:
            spacing -30
            for i2 in systemmap_location_lists[location]["buttons"]:
                textbutton i2:
                    text_style "mapmenu_location_buttons"
                    action NullAction()
I have existing imagebuttons already, and they show the menu like so:

Code: Select all

action Show("systemmap_location_menus", location='sol')

LyannaCore
Newbie
Posts: 22
Joined: Wed Jun 21, 2017 1:45 pm
Contact:

Re: Generating buttons via a list

#6 Post by LyannaCore »

(It seemed like it would be best to re-open this topic rather than create a new one, but I can do that if it's preferred.)

So I broke things again by once more adding extra complexity. This is the current code I'm working on.

Code: Select all

   
default systemmap_location_lists = {
    "sol" :                             #primary location
        {
        "coordinates": (489, 414),      #where to place the dropdown menu
        "target position": (360, 425),  #where the location arrow will bounce
        "buttons":                      #list of button/action lists
            [
                ["Dyson Ring",
                    [SetVariable("player_destination_broad", "sol"), SetVariable("player_destination_granular", "the Dyson Ring"), SetVariable("player_destination_label", "loc_sol_dyson"), Hide("systemmap_location_menus"), Show("destination_checker")],
                ],
            ],
        },
    "venus" : {
        "coordinates": (632, 525),
        "target position": (360, 425),
        "buttons":
            [
                ["Aeneas Station",
                    [SetVariable("player_destination_broad", "venus"), SetVariable("player_destination_granular", "Aeneas Station"), SetVariable("player_destination_label", "loc_venus_aeneas"), Hide("systemmap_location_menus"), Show("destination_checker")]
                ],
                ["Venus Aerostat",
                    [SetVariable("player_destination_broad", "venus"), SetVariable("player_destination_granular", "Venus Aerostat"), SetVariable("player_destination_label", "loc_venus_aerostat"), Hide("systemmap_location_menus"), Show("destination_checker")],
                ],
            ],
        },
screen systemmap_location_menus(location):
    modal True
    imagebutton:
        idle "gui/systemmap/5percent.png"
        hover "gui/systemmap/5percent.png"
        focus_mask None
        action Hide("systemmap_location_menus")
    frame:
        pos systemmap_location_lists[location]["coordinates"]
        background Frame("gui/systemmap/location_frame.png", left=25, top=25, right=25, bottom=25, tile=False)
        padding (10, 10)
        vbox:
            spacing -30
            for i2 in systemmap_location_lists[location]["buttons"]:
                textbutton i2:
                    text_style "mapmenu_location_buttons"
                    action NullAction()
I decided that I wanted to give each button it's own actions, so I changed from having a list of all button names, to giving each name it's own list, containing it's name and the specific actions I want to give it. But that's not working and I'm once again floundering, in over my head.

Currently, a location will correctly generate a button if there is only one sub-location, like Earth, but Venus crashes.

Code: Select all

...
  File "game/scripts/systemmap.rpy", line 355, in execute

Exception: Cannot display [<store.SetField object at 0x0D393AB0>, <store.SetField object at 0x0D393D30>, <store.SetField object at 0x0D393A70>, <store.Hide object at 0x0D393BD0>] as text.
...
Line 355 is

Code: Select all

 textbutton i2
I am still just calling the screen with a button action based on the location:

Code: Select all

action Show("systemmap_location_menus", location="sol")

LyannaCore
Newbie
Posts: 22
Joined: Wed Jun 21, 2017 1:45 pm
Contact:

Re: Generating buttons via a list

#7 Post by LyannaCore »

Made a bit of progress on my own and think I got it working.

Code: Select all

screen systemmap_location_menus(location):
    modal True
    imagebutton:
        idle "gui/systemmap/5percent.png"
        hover "gui/systemmap/5percent.png"
        focus_mask None
        action Hide("systemmap_location_menus")
    frame:
        pos systemmap_location_lists[location]["coordinates"]
        background Frame("gui/systemmap/location_frame.png", left=25, top=25, right=25, bottom=25, tile=False)
        padding (10, 10)
        vbox:
            spacing -30
            for i2 in systemmap_location_lists[location]["buttons"]:
                textbutton i2[0]:
                    text_style "mapmenu_location_buttons"
                    action i2[1]

Post Reply

Who is online

Users browsing this forum: Andredron