Ren'Py Help with selected buttons

Milvidi

Member
Game Developer
Feb 26, 2018
200
498
So I'm running in a bit of problem with buttons becoming selected. Here's the code

First, the class:

Python:
init python:
    class Quirks(object):
        def __init__ (self, name, cfname, isUnlocked, isActive, isSelected, baseDmg, quirkType):
            self.name = name
            self.cfname = cfname
            self.isUnlocked = isUnlocked
            self.isActive = isActive
            self.isSelected = isSelected
            self.baseDmg = baseDmg
            self.quirkType =  quirkType
Python:
label variable:
    python:
        choosenQuirk = set([])
        quirkList = []
        quirkList.append(Quirks("Gravity", "gravity", True, True, False, 10, "physical"))
        quirkList.append(Quirks("Explosion", "explosion", True, True, False, 20, "physical"))
        quirkList.append(Quirks("Frog", "frog", True, True, False, 15, "physical"))
    return
So far so good, but here's the problem:

First, I tried:

Code:
frame:
        xsize 1920
        ysize 300
        ypos 780
        background "#cc9e25"
        hbox:
            for q in quirkList:
                if q.isUnlocked:
                    textbutton q.name:
                        action [ToggleVariable(q.isSelected, True, False), SelectedIf(q.isSelected == True), ToggleSetMembership(choosenQuirk, q.cfname)]
However, it got an error:

Code:
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/script.rpy", line 32, in script
    call screen mainUI
  File "renpy/common/000statements.rpy", line 531, in execute_call_screen
    store._return = renpy.call_screen(name, *args, **kwargs)
  File "renpy/common/00action_data.rpy", line 222, in __call__
    __set_field(self.object, self.field, value, self.kind)
  File "renpy/common/00action_data.rpy", line 44, in _m1_00action_data__set_field
    fields, _, attr = name.rpartition(".")
AttributeError: 'bool' object has no attribute 'rpartition'

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "game/script.rpy", line 32, in script
    call screen mainUI
  File "D:\Renpy\renpy\ast.py", line 1949, in execute
    self.call("execute")
  File "D:\Renpy\renpy\ast.py", line 1937, in call
    return renpy.statements.call(method, parsed, *args, **kwargs)
  File "D:\Renpy\renpy\statements.py", line 277, in call
    return method(parsed, *args, **kwargs)
  File "renpy/common/000statements.rpy", line 531, in execute_call_screen
    store._return = renpy.call_screen(name, *args, **kwargs)
  File "D:\Renpy\renpy\exports.py", line 2905, in call_screen
    rv = renpy.ui.interact(mouse="screen", type="screen", roll_forward=roll_forward)
  File "D:\Renpy\renpy\ui.py", line 297, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "D:\Renpy\renpy\display\core.py", line 2702, in interact
    repeat, rv = self.interact_core(preloads=preloads, trans_pause=trans_pause, **kwargs)
  File "D:\Renpy\renpy\display\core.py", line 3518, in interact_core
    rv = root_widget.event(ev, x, y, 0)
  File "D:\Renpy\renpy\display\layout.py", line 998, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "D:\Renpy\renpy\display\layout.py", line 998, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "D:\Renpy\renpy\display\layout.py", line 998, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "D:\Renpy\renpy\display\screen.py", line 714, in event
    rv = self.child.event(ev, x, y, st)
  File "D:\Renpy\renpy\display\layout.py", line 998, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "D:\Renpy\renpy\display\layout.py", line 244, in event
    rv = d.event(ev, x - xo, y - yo, st)
  File "D:\Renpy\renpy\display\layout.py", line 998, in event
    rv = i.event(ev, x - xo, y - yo, cst)
  File "D:\Renpy\renpy\display\behavior.py", line 962, in event
    return handle_click(self.clicked)
  File "D:\Renpy\renpy\display\behavior.py", line 897, in handle_click
    rv = run(action)
  File "D:\Renpy\renpy\display\behavior.py", line 313, in run
    new_rv = run(i, *args, **kwargs)
  File "D:\Renpy\renpy\display\behavior.py", line 320, in run
    return action(*args, **kwargs)
  File "renpy/common/00action_data.rpy", line 222, in __call__
    __set_field(self.object, self.field, value, self.kind)
  File "renpy/common/00action_data.rpy", line 44, in _m1_00action_data__set_field
    fields, _, attr = name.rpartition(".")
AttributeError: 'bool' object has no attribute 'rpartition'

Windows-8-6.2.9200
Ren'Py 7.3.5.606
Combat system test 1.0
Wed Sep 16 10:29:35 2020
So, I tried:

default buttonSelected = False

Code:
frame:
        xsize 1920
        ysize 300
        ypos 780
        background "#cc9e25"
        hbox:
            for q in quirkList:
                if q.isUnlocked:
                    textbutton q.name:
                        action [ToggleVariable(buttonSelected, True, False), SelectedIf(buttonSelected == True), ToggleSetMembership(choosenQuirk, q.cfname)]
Well, this works, kinda. It causes all the buttons to be selected, no matter which one I clicked on. What I want is that only the button that I clicked on got selected, the rest stay untouched.

Is there a way to do this? Or I have to define every button manually instead of doing "for q in quirkList"?
 

recreation

pure evil!
Respected User
Game Developer
Jun 10, 2018
6,272
22,420
I had a similar issue and solved it with using a number (exchange with q in your case):
Python:
        action [SetVariable("selectedDoor", 3), SelectedIf(selectedDoor== 3), Jump("dining")]
edit: buttonSelected causes all buttons to be selected because you use it in all buttons, if it's true for one button, it's true for all buttons.
 
Last edited:

Milvidi

Member
Game Developer
Feb 26, 2018
200
498
I had a similar issue and solved it with using a number (exchange with q in your case):
Python:
        action [SetVariable("selectedDoor", 3), SelectedIf(selectedDoor== 3), Jump("dining")]
edit: buttonSelected causes all buttons to be selected because you use it in all buttons, if it's true for one button, it's true for all buttons.
Thank you, if I replace 3 with q, it kinda works, but only in making the individual button become selected. I need them to become unselected if I click on them again.

That said, I've already figured it out. So, solution for anyone needs it.


Python:
frame:
        xsize 1920
        ysize 300
        ypos 780
        background "#cc9e25"
        hbox:
            for q in quirkList:
                if q.isUnlocked:
                    textbutton q.name:
                        action ToggleSetMembership(chosenQuirk, q.cfname)
                        selected (q.cfname in chosenQuirk)
No need to SetVariable() or anything, since I use ToggleSetMembership(choosenQuirk, q.cfname), I only need to check if the string cfname is in the set chosenQuirk. If it's in there, selected. If it's not, unselected.
 
  • Like
Reactions: recreation

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,355
15,269
Well, you found a way to make it works, but never figured what was the problem, so :

Code:
                        action [ToggleVariable(q.isSelected, True, False), SelectedIf(q.isSelected == True), ToggleSetMembership(choosenQuirk, q.cfname)]
[/code]
However, it got an error:

Code:
  File "renpy/common/00action_data.rpy", line 44, in _m1_00action_data__set_field
    fields, _, attr = name.rpartition(".")
AttributeError: 'bool' object has no attribute 'rpartition'
As said by the documentation regarding :
The variable argument must be a string, and can be a simple name like "strength", or one with dots separating the variable from fields, like "hero.strength" or "persistent.show_cutscenes".
Despite the fact that ToggleVariable("q.isSelected") should works, it's that you should have used here :
Code:
                        action [ToggleField(q, "isSelected"), SelectedIf(q.isSelected == True), ToggleSetMembership(choosenQuirk, q.cfname)]
[/code]

Also note that for both screen action, the True, False part is optional. Those two parameters exist for case wheres the flag isn't an effective boolean. If you let those two blank, Ren'py will use True and False by itself.
 
  • Like
Reactions: Milvidi

Milvidi

Member
Game Developer
Feb 26, 2018
200
498
Thank you :D. I've actually tried ToggleField, but didn't think of putting isSelected into the " ", and kept getting errors.

Something to remember next time I run into this and don't have ToggleSetMembership to fall on.