[Solved] How to best write out and organize conditional logic when using buttons?

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
User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

[Solved] How to best write out and organize conditional logic when using buttons?

#1 Post by yon » Sat Aug 20, 2022 4:51 pm

Hi all, sorry to ask yet another question, but I was wondering how best to handle things like choosing which event to run from a button with multiple conditions at play?

I HAVE something functional, but I feel like there must be a better way than how I'm doing it.

Here's an example of one of my messy solutions for choosing between events to run from a standard menu:

Code: Select all

menu:
    "Who should I hang out with today...?"

    "Yui":
        if v_yui >= 25 and f_ch_05 == True and f_yui_05_complete == False and f_yui_04_complete == True:
            call yui_05

        elif v_yui >= 20 and f_ch_04 == True and f_yui_04_complete == False and f_yui_03_complete == True:
            call yui_04

        elif v_yui >= 15 and f_ch_03 == True and f_yui_03_complete == False and f_yui_02_complete == True:
            call yui_03

        elif v_yui >= 10 and f_ch_02 == True and f_yui_02_complete == False and f_yui_01_complete == True:
            call yui_02

        elif v_yui >= 5 and f_ch_01 == True and f_yui_01_complete == False:
            call yui_01

        else:
            $ v_yui += 05
            "I spent some time with Yui playing fighting games."

        return
This is one option from a menu which determines which character you'd like to spend time with in a kind of a life sim game with multiple choices.

The conditions at play are:
  • Every chapter (out of 5), a new character event becomes possible to unlock
  • You must have a certain number of points in their route to unlock that event
  • You can play a previous chapter's event in a later chapter if you hadn't unlocked it or gotten around to it back then
  • If you have not unlocked the next event, or you HAVE done the most recently available event, it runs the else condition and you get a generic event which raises your route progress a little bit
  • If you have already completed a character event, it should not play that one again
I ask about this because I'm trying to change this to a slightly more complicated screen which involves imagebuttons which will change visuals depending on route progress and whether a new event is possible. I have attached the mockup for what I'm trying to achieve.

I believe I could theoretically come up with something on my own, but I'm almost certain it would not be the best solution.

What I'm trying to achieve with the button screen, is:
  • Display whether or not a new event is available by checking the above conditions
  • Display a bar above the imagebutton BG with the current route progress (I know how to make the bar but I'm not sure if it would work with the button as well?)
  • Use the standard hover/idle background changes (I know how to do this)
  • Call the correct event for that character (would this require the button to run a specific action that I define elsewhere, or should I dump all of the logic within the button code itself?)
I hope all of this makes sense, and that it's not too strange of a question to ask. Thank you in advance.
Attachments
cellphone.png
Last edited by yon on Sun Aug 21, 2022 7:33 am, edited 1 time in total.

User avatar
enaielei
Regular
Posts: 114
Joined: Fri Sep 17, 2021 2:09 am
Tumblr: enaielei
Deviantart: enaielei
Github: enaielei
Skype: enaielei
Soundcloud: enaielei
itch: enaielei
Discord: enaielei#7487
Contact:

Re: How to best write out and organize conditional logic when using buttons?

#2 Post by enaielei » Sat Aug 20, 2022 5:54 pm

Hi all, sorry to ask yet another question, but I was wondering how best to handle things like choosing which event to run from a button with multiple conditions at play?
It's better to have a single action on the button like a Jump() or Call() which redirects the player to the label with the complex logic (conditions, adding/removing stats, etc.).

Code: Select all

menu:
    "Who should I hang out with today...?"

    "Yui":
        if v_yui >= 25 and f_ch_05 == True and f_yui_05_complete == False and f_yui_04_complete == True:
            call yui_05
You can further simplify your conditions. Use simply the "variable" name when determining whether the value is True and "not variable" if False.

Code: Select all

menu:
    "Who should I hang out with today...?"

    "Yui":
        if v_yui >= 25 and f_ch_05 and not f_yui_05_complete and f_yui_04_complete:
            call yui_05
Display a bar above the imagebutton BG with the current route progress (I know how to make the bar but I'm not sure if it would work with the button as well?)
Not sure what you mean by this but if you're talking about how to approach adding a bar value aside from the choice text (Mori, Yui, Snake, etc.) then you can use screen parameters to do this. You can try passing a list of tuple containing the "(choice_text, bar_value)" when calling/showing the screen.

Code: Select all

screen test(*contacts):
  for lbl, text, bar_val in contacts:
    button:
      action Jump(lbl)
      text text
      ...
label start:
  call screen test(("yui_label", "Yui", 0.5), ("mike_label", "Mike", 0.25))
Last edited by enaielei on Sun Aug 21, 2022 3:35 am, edited 1 time in total.

User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

Re: How to best write out and organize conditional logic when using buttons?

#3 Post by yon » Sun Aug 21, 2022 2:38 am

Thank you for streamlining the logic on the conditionals there.

What I mean is, if I want to display a bar in the area that the button is, will displaying the bar "above" the button (I assume it would be on another layer?) prevent interaction with the button? Does including that bar in the same frame as the button work without negative interactions?

v_yui, in this case, is the value for the progress made in the route. I would use v_yui as the value for the bar to show how far (how many points out of 100) you've gotten into the route, while also using that same value as a condition for unlocking events. Separately, I know how to make and display a bar, and I know how to make and display a button, but I'm not sure how to display a bar inside of a button (or atop it, I suppose).

Sorry if this is a beginner question, but could you help me understand the structure in your example?
  • I'm not sure how exactly lbl is being used here. Is that just the name of the variable we're creating to refer to the label within that tuple? Or is that the name of the label where the complex logic is?
  • How is "yui_label" being utilized in this code? That is, what does it refer to? Is lbl referring to that? Is it a variable, or just a string acting as the name for something else? As in, would that be replaced with the name of the label for the event which is brought up?
  • Would I have to manually include those values every time I called the screen?
  • Where is the bar code included here? Would I just put it in underneath the text section?
  • Would I have to create separate logic labels for each route's conditions?
  • When I tried to include the screen with the information included, trying to call it gave me an error about being unable to find a label called "test" -- I put the screen info in the screen file, so why is it trying to find a label instead of the screen?
I'm sorry for all the questions, I'm still just very confused about the logic of how that works. When I try to read about this stuff online, it just doesn't click for whatever reason. I think I'm still lacking some understanding of the internal logic of how python operates to begin with, let alone how these aspects work, but I don't know which parts I'm missing and what I need to know to get to my goals here.

Maybe the complication is asking about how to include both the logic tree and the bar at the same time, when I should have asked one and then the other, maybe. I'm sorry for the trouble.

User avatar
enaielei
Regular
Posts: 114
Joined: Fri Sep 17, 2021 2:09 am
Tumblr: enaielei
Deviantart: enaielei
Github: enaielei
Skype: enaielei
Soundcloud: enaielei
itch: enaielei
Discord: enaielei#7487
Contact:

Re: How to best write out and organize conditional logic when using buttons?

#4 Post by enaielei » Sun Aug 21, 2022 3:35 am

What I mean is, if I want to display a bar in the area that the button is, will displaying the bar "above" the button (I assume it would be on another layer?) prevent interaction with the button? Does including that bar in the same frame as the button work without negative interactions?
The bar is supposed to be read-only right? If so then you can make set its value/range properties to a fixed number. The fixed value would be is the bar_val in the example, the range you can set it in the screen itself as 1.0. This would prevent interactions (sliding etc.).
I'm not sure how exactly lbl is being used here. Is that just the name of the variable we're creating to refer to the label within that tuple? Or is that the name of the label where the complex logic is?
It's a string referring to the declared label name for the complex logic. Say if you have a label named mike_label to process things out then use "mike_label" as the string name.
How is "yui_label" being utilized in this code? That is, what does it refer to? Is lbl referring to that? Is it a variable, or just a string acting as the name for something else? As in, would that be replaced with the name of the label for the event which is brought up?
I actually used a for loop in the example,. Each item in the contacts is stored in the variables lbl, text, bar_val. For the first iteration, the lbl variable should equal to the string value "yui_label", then on the next it will be "mike_label" and so on. I'm not really sure if you're aware of for loops but this should be easy to understand if you're familiar with them. I recommend reading about Python loops if that's the case.
Would I have to manually include those values every time I called the screen?
In my approach, yes. I intentionally used screen parameters (*choices) so that you can create a dynamic screen that changes its display depending on how you called it.
This approach is very useful in different cases, one being you won't have to create another same screen with different set of contacts displaying.
If you don't want that then you can always hard code (create a screen for each set of contacts).
The dynamic approach can still be simplified with various ways, one for example is creating classes and objects to store the label name, name, and bar value in one variable instead of a tuple.
Where is the bar code included here? Would I just put it in underneath the text section?
Considering what you actually wanted was to put the bar front of the button? The last child on the button always displays first.
So put the bar as the last child of the button if you want to see it on top of the stack.
Would I have to create separate logic labels for each route's conditions?
You're passing the label name as string upon the call of the screen so yes you need to have a label where the game will jump once the contact is clicked.
When I tried to include the screen with the information included, trying to call it gave me an error about being unable to find a label called "test" -- I put the screen info in the screen file, so why is it trying to find a label instead of the screen?
That's actually my bad, it should have been "call screen test(...)", "call test" means it's calling a label instead of a screen, so you need to have a screen keyword there.
I edited my code with regards to this.
I think I'm still lacking some understanding of the internal logic of how python operates to begin with
That would be a problem.
Familiarity with the basics such as loops, conditions, variable types (tuple, list, set, dict) would definitely help in understanding examples and stuff.

User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

Re: How to best write out and organize conditional logic when using buttons?

#5 Post by yon » Sun Aug 21, 2022 4:32 am

The bar is supposed to be read-only right? If so then you can make set its value/range properties to a fixed number. The fixed value would be is the bar_val in the example, the range you can set it in the screen itself as 1.0. This would prevent interactions (sliding etc.).
If I'm not mistaken, I would want to set the value to the variable "v_yui" in this case to display how many points in that route the player has accumulated so far, right? I have created a bar elsewhere in the game with this code to display a similar variable:

Code: Select all

bar:
    value v_mind
    range 100
    pos (120,60)
    xysize (70,20)
    left_bar "gui/mini statbar.png"
    right_bar "gui/empty statbar.png"
Would I not be able to just insert that underneath the other relevant elements inside the button? Adjusting the actual numbers and such as needed, of course.
I actually used a for loop in the example,. Each item in the contacts is stored in the variables lbl, text, bar_val. For the first iteration, the lbl variable should equal to the string value "yui_label", then on the next it will be "mike_label" and so on. I'm not really sure if you're aware of for loops but this should be easy to understand if you're familiar with them. I recommend reading about Python loops if that's the case.
Sorry, there's a lot of programming stuff that I think I used to knew when I took some classes in college years ago, but I've forgotten most of it. I likely used those in the past, but I didn't realize how it was being used in this context. I think I understand this now, though! So it replaces the variable included in the for loop with what we're using later, and that then allows the interaction to send that button to the proper label where the logic is stored. In this case, I could replace the static number for the value with v_yui, v_mike, etc, and it should display that as the value, correct? Sorry to keep going back to that, I just want to make sure.
I intentionally used screen parameters (*choices) so that you can create a dynamic screen that changes its display depending on how you called it.
So, I have another question about this. Four of the choices in this menu will always be present, but one of the choices should only appear if a flag is True. Is it possible to make a parameter only be included in the for loop if that condition is met?

Finally, how would I go about including a visual change in the button when the conditions are met? Like I said, I'd like to have it show a notification on the button if a new event is available, but I don't know how to achieve that in this circumstance.

I'm sorry again for all of the questions. I really appreciate your patience.

User avatar
yon
Regular
Posts: 153
Joined: Tue Sep 09, 2014 5:09 pm
Projects: YDSP
Location: United States
Contact:

Re: How to best write out and organize conditional logic when using buttons?

#6 Post by yon » Sun Aug 21, 2022 7:31 am

Okay, I decided to try a different approach to the screen using a frame instead of a for loop (sorry!), and while it's not especially elegant, it does work!

Code: Select all

screen sunday():

    frame:
        xsize 340
        ysize 660
        xpos 80
        ypos 60
        padding (0, 0) # Manually reset padding
        background Frame("gui/cellphone.png")

        text "{size=10}[v_date]{/size}":
            pos (215,125)
            # Displays the date in the top right corner

        # Route Buttons

        imagebutton:
            auto "gui/button/cell_button_%s.png"
            focus_mask True
            pos (45,190)
            action Call("yui_logic")

        imagebutton:
            auto "gui/button/cell_button_%s.png"
            focus_mask True
            pos (45,255)
            action Call("ani_logic")

        imagebutton:
            auto "gui/button/cell_button_%s.png"
            focus_mask True
            pos (45,320)
            action Call("snk_logic")

        imagebutton:
            auto "gui/button/cell_button_%s.png"
            focus_mask True
            pos (45,385)
            action Call("aza_logic")

        if f_route_mor:
            imagebutton:
                auto "gui/button/cell_button_%s.png"
                focus_mask True
                pos (45,450)
                action Call("mor_logic")

        # Route Bars

        bar:
            value v_yui
            range 100
            pos (70,225)
            xysize (200,10)
            left_bar "gui/cell_bar.png"
            right_bar "gui/cell_bar_empty.png"

        bar:
            value v_ani
            range 100
            pos (70,290)
            xysize (200,10)
            left_bar "gui/cell_bar.png"
            right_bar "gui/cell_bar_empty.png"

        bar:
            value v_snk
            range 100
            pos (70,355)
            xysize (200,10)
            left_bar "gui/cell_bar.png"
            right_bar "gui/cell_bar_empty.png"

        bar:
            value v_aza
            range 100
            pos (70,420)
            xysize (200,10)
            left_bar "gui/cell_bar.png"
            right_bar "gui/cell_bar_empty.png"

        if f_route_mor:
            bar:
                value v_mor
                range 100
                pos (70,485)
                xysize (200,10)
                left_bar "gui/cell_bar.png"
                right_bar "gui/cell_bar_empty.png"

        # Contact Labels

        image "gui/cell_token_yui.png":
            pos (50,195)

        text "{size=20}Yui{/size}":
            pos (75,195)

        image "gui/cell_token_ani.png":
            pos (50,260)

        text "{size=20}Anisha{/size}":
            pos (75,260)

        image "gui/cell_token_snk.png":
            pos (50,325)

        text "{size=20}Snake{/size}":
            pos (75,325)

        image "gui/cell_token_aza.png":
            pos (50,390)

        text "{size=20}Azami{/size}":
            pos (75,390)

        if f_route_mor:
            image "gui/cell_token_mor.png":
                pos (50,455)
            text "{size=20}Mori{/size}":
                pos (75,455)

        # Yui Notifications

        if v_yui >= 25 and f_ch_05 and f_yui_04_complete and not f_yui_05_complete:
            image "gui/cell_notif.png":
                pos (50,195)

        elif v_yui >= 20 and f_ch_04 and f_yui_03_complete and not f_yui_04_complete:
            image "gui/cell_notif.png":
                pos (50,195)

        elif v_yui >= 15 and f_ch_03 and f_yui_02_complete and not f_yui_03_complete:
            image "gui/cell_notif.png":
                pos (50,195)

        elif v_yui >= 10 and f_ch_02 and f_yui_01_complete and not f_yui_02_complete:
            image "gui/cell_notif.png":
                pos (50,195)

        elif v_yui >= 5 and f_ch_01 and not f_yui_01_complete:
            image "gui/cell_notif.png":
                pos (50,195)

        if v_ani >= 25 and f_ch_05 and f_ani_04_complete and not f_ani_05_complete:
            image "gui/cell_notif.png":
                pos (50,260)

        # Anisha Notifications

        elif v_ani >= 20 and f_ch_04 and f_ani_03_complete and not f_ani_04_complete:
            image "gui/cell_notif.png":
                pos (50,260)

        elif v_ani >= 15 and f_ch_03 and f_ani_02_complete and not f_ani_03_complete:
            image "gui/cell_notif.png":
                pos (50,260)

        elif v_ani >= 10 and f_ch_02 and f_ani_01_complete and not f_ani_02_complete:
            image "gui/cell_notif.png":
                pos (50,260)

        elif v_ani >= 5 and f_ch_01 and not f_ani_01_complete:
            image "gui/cell_notif.png":
                pos (50,260)

        # Snake Notifications

        if v_snk >= 25 and f_ch_05 and f_snk_04_complete and not f_snk_05_complete:
            image "gui/cell_notif.png":
                pos (50,325)

        elif v_snk >= 20 and f_ch_04 and f_snk_03_complete and not f_snk_04_complete:
            image "gui/cell_notif.png":
                pos (50,325)

        elif v_snk >= 15 and f_ch_03 and f_snk_02_complete and not f_snk_03_complete:
            image "gui/cell_notif.png":
                pos (50,325)

        elif v_snk >= 10 and f_ch_02 and f_snk_01_complete and not f_snk_02_complete:
            image "gui/cell_notif.png":
                pos (50,325)

        elif v_snk >= 5 and f_ch_01 and not f_snk_01_complete:
            image "gui/cell_notif.png":
                pos (50,325)

        # Azami Notifications

        if v_aza >= 25 and f_ch_05 and f_aza_04_complete and not f_aza_05_complete:
            image "gui/cell_notif.png":
                pos (50,390)

        elif v_aza >= 20 and f_ch_04 and f_aza_03_complete and not f_aza_04_complete:
            image "gui/cell_notif.png":
                pos (50,390)

        elif v_aza >= 15 and f_ch_03 and f_aza_02_complete and not f_aza_03_complete:
            image "gui/cell_notif.png":
                pos (50,390)

        elif v_aza >= 10 and f_ch_02 and f_aza_01_complete and not f_aza_02_complete:
            image "gui/cell_notif.png":
                pos (50,390)

        elif v_aza >= 5 and f_ch_01 and not f_aza_01_complete:
            image "gui/cell_notif.png":
                pos (50,390)

        # Morikawa Notifications

        if v_mor >= 25 and f_ch_05 and f_mor_04_complete and not f_mor_05_complete:
            image "gui/cell_notif.png":
                pos (50,455)

        elif v_mor >= 20 and f_ch_04 and f_mor_03_complete and not f_mor_04_complete:
            image "gui/cell_notif.png":
                pos (50,455)

        elif v_mor >= 15 and f_ch_03 and f_mor_02_complete and not f_mor_03_complete:
            image "gui/cell_notif.png":
                pos (50,455)

        elif v_mor >= 10 and f_ch_02 and f_mor_01_complete and not f_mor_02_complete:
            image "gui/cell_notif.png":
                pos (50,455)

        elif v_mor >= 5 and f_ch_01 and not f_mor_01_complete:
            image "gui/cell_notif.png":
                pos (50,455)
So, I think that covers my question for now. I do appreciate your help, though. I think it helped me understand the screen better, even if I chose to do something else.
Attachments
screenshot0018.png

Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot]