Ren'Py Problem with Ren'py imagebuttons with more than one function

xxx3me

Newbie
Jun 19, 2020
57
30
Hi again!

I'm working in a card game inside my story in Ren'py, most of it is done, but I'm struggling with some complex imabuttons. I'll put the full code for a better explanation:

Python:
imagebutton idle "images/cards/deckback.png" hover "images/cards/deckback_h.png" xpos 0.70 ypos 0.45 focus_mask True action [SensitiveIf(hand1 == 'deckback' or hand2 == 'deckback' or hand3 == 'deckback' or hand4 == 'deckback' or hand5 == 'deckback'), If(hand1=='deckback', SetVariable('hand1',renpy.random.sample(deck,1)[0]),If(hand2=='deckback',SetVariable('hand2',renpy.random.sample(deck,1)[0]),If(hand3=='deckback',SetVariable('hand3',renpy.random.sample(deck,1)[0]),If(hand4=='deckback',SetVariable('hand4',renpy.random.sample(deck,1)[0]),If(hand5=='deckback',SetVariable('hand5',renpy.random.sample(deck,1)[0]))))))]
There is a 'deck' var holding a list with cards (a list of names like ace_of_spades, two_of_hearts, etc). This is the button to buy one card to hand (max of 5 cards). So it first checks if one of the "hand slots" is empty (with a 'deckback' value) to be active/sensitive, and if so, it puts a card in that "slot". Else, checks the next, and so on.

The problem is that cards are being repeated, so suddenly I can get two aces of spades at same time. I'm trying to implement a "deck.del()" to remove from deck the card that was just bought (so, the value of the "hand1" var, or "hand2", etc).

Any idea? Maybe I'm trying a wrong approach?
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,286
Python:
imagebutton idle "images/cards/deckback.png" hover "images/cards/deckback_h.png" xpos 0.70 ypos 0.45 focus_mask True action [SensitiveIf(hand1 == 'deckback' or hand2 == 'deckback' or hand3 == 'deckback' or hand4 == 'deckback' or hand5 == 'deckback'), If(hand1=='deckback', SetVariable('hand1',renpy.random.sample(deck,1)[0]),If(hand2=='deckback',SetVariable('hand2',renpy.random.sample(deck,1)[0]),If(hand3=='deckback',SetVariable('hand3',renpy.random.sample(deck,1)[0]),If(hand4=='deckback',SetVariable('hand4',renpy.random.sample(deck,1)[0]),If(hand5=='deckback',SetVariable('hand5',renpy.random.sample(deck,1)[0]))))))]
Firstly, when you've so many properties to set, use imagebutton as block:
Code:
imagebutton;
    idle "images/cards/deckback.png"
    hover "images/cards/deckback_h.png"
    xpos 0.70 ypos 0.45
    focus_mask True
    action [SensitiveIf(hand1 == 'deckback' or hand2 == 'deckback' or hand3 == 'deckback' or hand4 == 'deckback' or hand5 == 'deckback'), If(hand1=='deckback', SetVariable('hand1',renpy.random.sample(deck,1)[0]),If(hand2=='deckback',SetVariable('hand2',renpy.random.sample(deck,1)[0]),If(hand3=='deckback',SetVariable('hand3',renpy.random.sample(deck,1)[0]),If(hand4=='deckback',SetVariable('hand4',renpy.random.sample(deck,1)[0]),If(hand5=='deckback',SetVariable('hand5',renpy.random.sample(deck,1)[0]))))))]
It give you a better view.

Secondly, SensitiveIf is outdated, use the sensitive property instead:
Code:
imagebutton;
    idle "images/cards/deckback.png"
    hover "images/cards/deckback_h.png"
    xpos 0.70 ypos 0.45
    focus_mask True
    action [If(hand1=='deckback', SetVariable('hand1',renpy.random.sample(deck,1)[0]),If(hand2=='deckback',SetVariable('hand2',renpy.random.sample(deck,1)[0]),If(hand3=='deckback',SetVariable('hand3',renpy.random.sample(deck,1)[0]),If(hand4=='deckback',SetVariable('hand4',renpy.random.sample(deck,1)[0]),If(hand5=='deckback',SetVariable('hand5',renpy.random.sample(deck,1)[0]))))))]
    sensitive  hand1 == 'deckback' or hand2 == 'deckback' or hand3 == 'deckback' or hand4 == 'deckback' or hand5 == 'deckback'
This already simplify a little your action.

Thirdly, when you've so many embedded If, prefer to use a function, it will make your code easier to read:
Code:
init python:
    def pickCard():
      if renpy.hand1 == 'deckback':
           renpy.hand1 = renpy.random.sample(store.deck,1)[0]
      elif  hand2=='deckback':
           renpy.hand2 = renpy.random.sample(store.deck,1)[0]
      elif  hand3=='deckback':
           renpy.hand3 = renpy.random.sample(store.deck,1)[0]
      elif  hand4=='deckback':
           renpy.hand4 = renpy.random.sample(store.deck,1)[0]
      elif  hand5=='deckback':
           renpy.hand5 = renpy.random.sample(store.deck,1)[0]

screen whatever():
    [...]
    imagebutton;
        idle "images/cards/deckback.png"
        hover "images/cards/deckback_h.png"
        xpos 0.70 ypos 0.45
        focus_mask True
        action pickCard
        sensitive  hand1 == 'deckback' or hand2 == 'deckback' or hand3 == 'deckback' or hand4 == 'deckback' or hand5 == 'deckback'
Fourthly, why using random.sample, that force you to get the first entry on the returned list, when random.choice would return you a single element from the whole list ?

Fifthly, well, the solution to your problem should (it's near to 4 AM here) be this :
Python:
init python:
    def pickCard():
      # Keep track of the free space
      if renpy.hand1 == 'deckback':
           hand = "hand1"
      elif  hand2=='deckback':
           hand = "hand2"
      elif  hand3=='deckback':
           hand = "hand3"
      elif  hand4=='deckback':
           hand = "hand4"
      elif  hand5=='deckback':
           hand = "hand5"
      # There's no free space, just return.
      else:
           return

     # Randomly pick one card
     card = renpy.random.choice( store.deck )
     # Remove it from the packet.
     store.deck.remove( card )
     # Add it to the player hand, at the right place
     setattr( store, hand, card )


screen whatever():
    [...]
    imagebutton;
        idle "images/cards/deckback.png"
        hover "images/cards/deckback_h.png"
        xpos 0.70 ypos 0.45
        focus_mask True
        action pickCard
        sensitive  hand1 == 'deckback' or hand2 == 'deckback' or hand3 == 'deckback' or hand4 == 'deckback' or hand5 == 'deckback'
Note that you'll have to rebuild deck each time a new party start, for it to contain again all the cards.
 

xxx3me

Newbie
Jun 19, 2020
57
30
Ok, tested and it's almost there. Just a small "upgrade" to properly change the card on hand (renpy.restart_interaction()) and changing the ; for :

Final code, maybe it's useful for someone:

Python:
init python:
    def pickCard():
        # Keep track of the free space
        if hand1 == 'deckback':
            hand = "hand1"
        elif hand2=='deckback':
            hand = "hand2"
        elif hand3=='deckback':
            hand = "hand3"
        elif hand4=='deckback':
            hand = "hand4"
        elif hand5=='deckback':
            hand = "hand5"
        # There's no free space, just return.
        else:
            return

        # Randomly pick one card
        card = renpy.random.choice( store.deck )
        # Remove it from the packet.
        store.deck.remove( card )
        # Add it to the player hand, at the right place
        setattr( store, hand, card )
        renpy.restart_interaction()
 
  • Like
Reactions: vampayano