Ren'Py While and if statement in menu

obsessionau

Member
Game Developer
Sep 27, 2018
270
376
I need some help with menu's,

I have list where the player can choose to swap two items which is presented via a menu.
It only shows the items after his current position in the list (stagePath):
Is there a way I can incorporate a for/while loop as this list can grow and shrink?

The following code works but it assumes there is never more than 12 list items and it is very code inefficient.

Code:
            menu:
                "Choose a card to swap"
                "[deckPath[1][1]]" if stagePath < 1:
                    $swapFirstValue = 1
                "[deckPath[2][1]]" if stagePath < 2:
                    $swapFirstValue = 2
                "[deckPath[3][1]]" if (stagePath < 3) and 3 < len(deckPath):
                    $swapFirstValue = 3
                "[deckPath[4][1]]" if (stagePath < 4) and 4 < len(deckPath):
                    $swapFirstValue = 4
                "[deckPath[5][1]]" if (stagePath < 5) and 5 < len(deckPath):
                    $swapFirstValue = 5
                "[deckPath[6][1]]" if (stagePath < 6) and 6 < len(deckPath):
                    $swapFirstValue = 6
                "[deckPath[7][1]]" if (stagePath < 7) and 7 < len(deckPath):
                    $swapFirstValue = 7
                "[deckPath[8][1]]" if (stagePath < 8) and 8 < len(deckPath):
                    $swapFirstValue = 8
                "[deckPath[9][1]]" if (stagePath < 9) and 9 < len(deckPath):
                    $swapFirstValue = 9
                "[deckPath[10][1]]" if (stagePath < 10) and 10 < len(deckPath):
                    $swapFirstValue = 10
                "[deckPath[11][1]]" if (stagePath < 11) and 11 < len(deckPath):
                    $swapFirstValue = 11
                "None...":
                    $skipSwap = False

            if skipSwap:
                menu:
                    "Choose the card to swap with"
                    "[deckPath[1][1]]" if stagePath < 1 and swapFirstValue != 1:
                        $swapSecondValue = 1
                    "[deckPath[2][1]]" if stagePath < 2 and swapFirstValue != 2:
                        $swapSecondValue = 2
                    "[deckPath[3][1]]" if (stagePath < 3) and 3 < len(deckPath) and swapFirstValue != 3:
                        $swapSecondValue = 3
                    "[deckPath[4][1]]" if (stagePath < 4) and 4 < len(deckPath) and swapFirstValue != 4:
                        $swapSecondValue = 4
                    "[deckPath[5][1]]" if (stagePath < 5) and 5 < len(deckPath) and swapFirstValue != 5:
                        $swapSecondValue = 5
                    "[deckPath[6][1]]" if (stagePath < 6) and 6 < len(deckPath) and swapFirstValue != 6:
                        $swapSecondValue = 6
                    "[deckPath[7][1]]" if (stagePath < 7) and 7 < len(deckPath) and swapFirstValue != 7:
                        $swapSecondValue = 7
                    "[deckPath[8][1]]" if (stagePath < 8) and 8 < len(deckPath) and swapFirstValue != 8:
                        $swapSecondValue = 8
                    "[deckPath[9][1]]" if (stagePath < 9) and 9 < len(deckPath) and swapFirstValue != 9:
                        $swapFirstValue = 9
                    "[deckPath[10][1]]" if (stagePath < 10) and 10 < len(deckPath) and swapFirstValue != 10:
                        $swapFirstValue = 10
                    "[deckPath[11][1]]" if (stagePath < 11) and 11 < len(deckPath) and swapFirstValue != 10:
                        $swapFirstValue = 11
I have tried to use renpy.display_menu() but it's 2:30am I am half asleep. It isn't throwing any errors, but also it's not displaying anything.

Code:
label smartMenu(*items):
    python:
        # construct a menu
        menuitems = []
        for i in range(1,len(items)):
            menuitems.append((items[i][0],items[i][1]))
        menuChoice = renpy.display_menu(menuitems)
    return
Code:
            $menulist = []
            $k=0
            while k < len(deckPath):
                if stagePath < i:
                    $menulist.append((deckPath[i][1],i))
                $k = k+1
            call smartMenu(menulist)
            $swapFirstValue = menuChoice
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,978
16,234
I have tried to use renpy.display_menu() but it's 2:30am I am half asleep. It isn't throwing any errors, but also it's not displaying anything.
Remark as comments in your code :
Python:
# You pass a list, not a suit of values. Therefore you
# don't need to group them into a tuple ; its already
# a single value.
label smartMenu(*items):
    python:
        # construct a menu
        # <<< You already did this before calling the label
        # Anyway, /items/ have only one entry, the list you
        # passed as parameter.
        menuitems = []
        for i in range(1,len(items)):
            menuitems.append((items[i][0],items[i][1]))
        # You already did this before calling the label >>>
        menuChoice = renpy.display_menu(menuitems)
    return
Python:
            $menulist = []
            $k=0
            while k < len(deckPath):
                # /i/ while you use /k/ for the indice.
                # Anyway, why this when you're already in a 
                # loop and can limit at this level.
                if stagePath < i:
                    $menulist.append((deckPath[i][1],i))
                $k = k+1
            call smartMenu(menulist)
            $swapFirstValue = menuChoice
The correct code is :
Code:
label whatever:
    call smartMenu
    $ swapFirstValue = _return

label smartMenu:
    python:
        menulist = []
        for k in range( 0, stagePath ):
            menulist.append((deckPath[k][0],k))

    return renpy.display_menu(menulist)

This being said, it's probably better to find a totally different way to do this. With the 11 possible entries in the menu you shown as example, you already goes further than what a menu can display with its style by default in a 1280x980 windows.
Of course, you can change the style to limit the screen occupation, and/or the windows' size, but you'll still have a limited number of possible entries. This while a screen could let you split this on multiple columns. By example something like :

Code:
init python:
    def smartMenu():
        menulist = []
        for k in range( 0, stagePath ):
            menulist.append((deckPath[k][0],k))
        return menulist

label whatever:
    call screen smartMenu( smartMenu() )
    $ swapFirstValue = _return
 
screen smartMenu(items):

    frame:
        xalign 0.5 yalign 0.5

        vbox:
            for i in range( 0, stagePath, 2 ):
                hbox:
                    xsize 400

                    textbutton _( items[i][0] ):
                        xalign 0.0
                        action Return( items[i][1] )
                    if( i + 1 < stagePath ):
                        textbutton _( items[i+1][0] ):
                            xalign 1.0
                            action Return( items[i+1][1] )
 
  • Wow
Reactions: Phlexxx

obsessionau

Member
Game Developer
Sep 27, 2018
270
376
Thank you,

I have recreated a card game and am ironing out the bugs before I retheme and fanservice it.

Thank you for also addressing the issue of a big list! Which has also been on my mind. The menu is on the bottom right and only comfortably displays 5 choices.

1589591088632.png

Wost case scenario there are 3/60 cards in the game that add allow the user to add 2 cards (or do another option). Assuming the very unlikely scenario that these are the first 3 cards in a row of 6 and there is the Scorpion card in position 4 there would be 10 choices to display as you will be adding another 7 cards however by this stage you will be in position 4 (stagePath) so only displaying cards 5 to 13 plus giving the option to not swap).

This is however extremely unlikely and in most cases the player will avoid adding cards (as they are generally bad and the order you place cards is important to mitigate that fact). A still rare but more likely scenario would be a single +2 card at the start followed by a swap which would be a list of 6-7 options breaking the appearance.

I will give your suggestions a go now that I am a bit more awake :D

Thanks again!
 
Last edited:

obsessionau

Member
Game Developer
Sep 27, 2018
270
376
Can't believe I actually got it working without too much stress!

1589636708243.png
1589636853110.png

I made a few minor changes to get it working how I needed.
Here is the code if other people need to do something similar...

Python:
    # Build a list of the remaining cards on the path to swap
    def swapMenu():
        menulist = []
        for k in range( (stagePath+1), len(deckPath)):
            # If this is the second choice, don't show the first item picked in the list
            if k != swapFirstValue:
                menulist.append((deckPath[k][1],k))
       # Include the option to ignore doing the swap
        if swapFirstValue == 0:
            menulist.append(("Pass...",0))
        return menulist
Python:
elif effectName == "Swap":
       #If there are two or more cards remaining in the row to swap, continue...
        if stagePath < (len(deckPath) -2):
            $swapFirstValue = 0
            $swapSecondValue = 0

            #Get user to select first card to swap from remaining cards
            call screen swapMenu(swapMenu(),"Choose a card to swap or Pass.")
            $ swapFirstValue = _return

            if swapFirstValue:
                #Get user to select second card to swap from remaining cards
                call screen swapMenu(swapMenu(), "Chose the card to swap with.")
                $ swapSecondValue = _return

                #Rebuild the path but swap the two cards
                $deckTemp =[] # list to temporary store the new path
                python:
                    for swapi in range(0, len(deckPath)):
                        if swapi == swapFirstValue:
                            deckTemp.append(deckPath[swapSecondValue])
                        elif swapi == swapSecondValue:
                            deckTemp.append(deckPath[swapFirstValue])
                        else:
                            deckTemp.append(deckPath[swapi])
                $deckPath = deckTemp
Python:
################################################################################
# Swap cards screen
################################################################################
screen swapMenu(items, what):
    style_prefix "say"
    zorder 200
    # Show narration text
    window:
        id "window"
        text what xpos 50 ypos 45
    # Show the menu options
    vbox:
        style_prefix "choice"
        yalign 0.0 xalign 1.0
        # If list is small just display in one row otherwise split into two
        if len(items) < 6:
            vbox:
                xsize 250
                for i in range( 0, len(items)):
                    textbutton _(items[i][0] ):
                        action Return( items[i][1] )
        else:
            vbox:
                for i in range( 0, len(items), 2 ):
                    hbox:
                        textbutton _(items[i][0] ):
                            xsize 300
                            action Return( items[i][1] )
                        if( i + 1 < len(items) ):
                            textbutton _(items[i+1][0] ):
                                xsize 300
                                action Return( items[i+1][1] )
 
Last edited:
  • Wow
Reactions: Phlexxx