1. Hey! Guest! The 36th GMC Jam will take place between February 27th, 12:00 UTC - March 2nd, 12:00 UTC. Why not join in! Click here to find out more!
    Dismiss Notice
  2. NOTICE: We will be applying a Xenforo update on Tuesday 25th of February. This means that from approximately 10:00 to 14:00 BST the forums will be offline (or possibly longer). Sorry for the inconvenience! Official Announcement here.

GM:S 1.4 Wait until mouse_click

Discussion in 'Programming' started by Dagoba, Jul 24, 2017.

  1. Dagoba

    Dagoba Member

    Joined:
    Jul 12, 2016
    Posts:
    86
    Hello, long time no see!
    I am currently programming a Texas Hold'Em online game, and I am encountering a problem.

    There are turns for each player on the table, and it's running by for loop for each player.
    I need to make a method that waits until the player has clicked either call, check, fold, raise or all-in button.
    It is made like this:
    Code:
    for (var i = 0; i < tablecount; i++) {
        /* Some code here that already works
        *
        *
        *
        *
        */
        //Now the method to check if player has clicked a button
        if (!turn_used) {
            if (position_meeting(mouse_x, mouse_y, obj_btn_call) && mouse_check_button_pressed(mb_left)) {
                turn_used = true;
            }
            if (position_meeting(mouse_x, mouse_y, obj_btn_fold) && mouse_check_button_pressed(mb_left)) {
                turn_used = true;
            }
            // etc etc...
        }
        if (i == tablecount) {
            alarm[0] = 30; // Now draw the cards to the table (3)
        }
        
    }
    I know, that I should use while(!turn_used), but everytime I use while loop in Game Maker, the game will freeze due to infinite loop.
    Now the code doesn't work because it checks if player has clicked a button, it has not because the loop goes so fast, that it starts with another players turn.

    Now how can I "stop" this for loop until the player has ran out of time (30 sec) OR has clicked any button?
    Is there any way to make some kind of while loop without causing a freezing?

    Thanks in advance!
     
  2. BattleRifle BR55

    BattleRifle BR55 Member

    Joined:
    Jun 24, 2016
    Posts:
    1,087
    Short answer: you can't. Why does it have to be in a loop? The code doesn't seem to use anything relevant to it. Maybe knowing the working code would help form a solution.
     
  3. Dagoba

    Dagoba Member

    Joined:
    Jul 12, 2016
    Posts:
    86
    Because it needs to check for every object (the seat object) where a player can sit on and start playing.
    Also it needs to check if the seat object is joined, has the player folded and all kind of variables inside of it, if the seat object is empty (no players sitting on it), then skip it.
    Why would I not use for loop for this?

    And you really do not need my full code, because the part I commented is full of local variables declaring like small blinds and stuff, that is not relevant to the problem I am having...
     
  4. BattleRifle BR55

    BattleRifle BR55 Member

    Joined:
    Jun 24, 2016
    Posts:
    1,087
    The code doesn't use the for loop in any way, so you're just polling the mouse and checking for collisions several times per frame for no discernible purpose. The reason I asked for the working code is because I wanted to see this code in relation to that in order to find a proper solution that doesn't break what you currently have that is working. Right now, all I can recommend is that you move the code just outside the for loop.
     
  5. Dagoba

    Dagoba Member

    Joined:
    Jul 12, 2016
    Posts:
    86
    I do need the for loop, to check if table(i) is done this and that.
    Fine, I post the entire script:
    Code:
    var tablecount = instance_number(obj_sit_in);
    for (var i = 0; i < tablecount; i++)
    {
        with(obj_sit_in)
        {
            if (seat_number == i && !my_turn && !turn_used && joined && !folded)
            {
                my_turn = true;
                show_message("Player " + string(i+1) + "'s turn.");
                var sb = obj_controller.small_blind;
                var bb = sb * 2;
                var lc, lc_amount; // Lower cash than the small blind, lc_amount = remaining cash
                var betID; // This players bet ID
                if (seat_cash >= sb) seat_cash -= sb; // Fee the small blind
                else
                {
                    lc = true;
                    lc_amount = seat_cash;
                    seat_cash = 0;
                }
                with(par_btn_turn)active = true;
    
                if (!turn_used)
                {
                    if (position_meeting(mouse_x, mouse_y, obj_btn_call) && mouse_check_button_pressed(mb_left))
                    {
                        // Check if the player needs to call or check and then do the method
                        turn_used = true;
                    }
                    if (position_meeting(mouse_x, mouse_y, obj_btn_fold) && mouse_check_button_pressed(mb_left))
                    {
                        folded = true;
                        turn_used = true;
                    }
                    if (position_meeting(mouse_x, mouse_y, obj_btn_bet) && mouse_check_button_pressed(mb_left))
                    {
                        betId = 0;//read value from the bet string
                        if (global.bet < betID) global.bet = betID;
                        else seat_cash = 0;
                        turn_used = true;
                    }
                    if (position_meeting(mouse_x, mouse_y, obj_btn_allin) && mouse_check_button_pressed(mb_left))
                    {
                        betID = seat_cash;
                        
                        // Checks if there is a higher bet already
                        if (global.bet < betID) global.bet = betID;
                        else seat_cash = 0;
                        
                        turn_used = true;
                    }
                }
            }
        }
        // After the loop, draw the cards
        // ALSO ADD IF EVERYBODY HAS RAISED/CHECKED
        if (i == tablecount-1)
        {
            i++;
            show_message("Soon alarm...");
            total_middle_bet += round_middle_bet;
            round_middle_bet = 0;
            alarm[1] = 30;  // Draw the cards to the table
        }
    }
     
  6. TheouAegis

    TheouAegis Member

    Joined:
    Jul 3, 2016
    Posts:
    7,451
    obviously you do not want to freeze your game, so stop using loops. allow the program to run over multiple steps and wait until all players have provided their input. You do not want to freeze the game at all, so get this out of your head. that is what battlerifle is basically saying, that your loop does absolutely nothing pertinent to progress your code. Use a variable to keep track of what the program should be doing each step.
     
    Matt Hawkins likes this.
  7. BattleRifle BR55

    BattleRifle BR55 Member

    Joined:
    Jun 24, 2016
    Posts:
    1,087
    Thanks for the code. It actually makes a huge difference to know that the code sits inside a with statement. That's where all my confusion came from.

    However, it still leaves me at the same conclusion. The for loop isn't necessary as you don't need to track every player every frame. At a glance, you could remove the for statement and use a more appropriately named variable to replace i which states whose turn it currently is (which also replaces the my_turn variable) and it will accomplish the same feat without needing to worry about stopping loops.

    Also, you can optimize the mouse bits by checking for the button only once.

    if (mouse pressed)
    {
    if (here)
    else if (there)
    }
     
  8. Dagoba

    Dagoba Member

    Joined:
    Jul 12, 2016
    Posts:
    86
    This is true, would be faster and more efficient code. Thanks for the tip! :)

    However I am quite unsure how to do this, so just a variable like seatID that starts from number 0, after the player has done their turn, the seatID would increase by one.
    But then I should use something like "do this method until seatID == instance_number(obj_sit_in)", but doesn't that need some kind of loop or should I just check it at the beginning of the code that if (seatID < instance_number(obj_sit_in)) ?
     
  9. BattleRifle BR55

    BattleRifle BR55 Member

    Joined:
    Jun 24, 2016
    Posts:
    1,087
    You don't need any loops at all. Think of it this way: your current logic dictates that the dealer on every play asks every player if it's their turn, and whoever says yes is allowed to do something. What logic you need is that the dealer simply asks whose turn it is, and the applicable person speaks up and performs an action. If you think about it, using the with statement and the for loop meant that if you had five players, there would be 25 checks for whose turn it was since the with statement would check all five players, and the for statement would make this action repeat another five times.

    Your very first if statement checks to see if the seat number is equal to i. Instead of using a loop and scanning through all of the players, the with statement will already take care of that, so all you need to do is check if the seat number is equal to the current turn set by the control object calling this code, which, as you have already pointed out, would simply be a variable that would increase by one. Once this variable count exceeds the number of players minus 1, it loops back over; you could use mod to keep the calculation simple. This also removes the need for the my_turn and turn_used variables since those were already redundant anyway.

    The only thing left is dealing with a player who has folded, otherwise the game will soft-lock. You could structure your code as such:
    Code:
    if (seat_number == current_turn)
    {
        if (!folded)
        {
            // stuff
        }
        else
            current_turn = (current_turn + 1) mod instance_number(obj_sit_in);
    }

    I'm not too familiar with poker, so I can't speak on the "joined" variable.
     
  10. Dagoba

    Dagoba Member

    Joined:
    Jul 12, 2016
    Posts:
    86
    Yeah, will try to make something like that.
    Thank you for the advices, and the "joined" variable means, if a player has joined on the table (aka. sitting on the seat). The seats can be empty as well, so skip those that are.
     
  11. the above function its self is the problem its a one off function.
    from: http://docs.yoyogames.com/source/dadiospice/002_reference/mouse, keyboard and other controls/mouse input/mouse_check_button_pressed.html
    This function will only be triggered once for any mouse button when it is first pressed and to trigger it again the button will need to have been released and pressed again.

    edit: try this approach instead:
    Code:
       //Now the method to check if player has clicked a button
       if (!turn_used && mouse_check_button_pressed(mb_left)) {
           if (position_meeting(mouse_x, mouse_y, obj_btn_call)) {
               turn_used = true;
           }
           if (position_meeting(mouse_x, mouse_y, obj_btn_fold)) {
               turn_used = true;
           }
           // etc etc...
    
    *Note: sorry if the link is not clickable (i'm under 5 posts)
     
  12. Dagoba

    Dagoba Member

    Joined:
    Jul 12, 2016
    Posts:
    86
    Yeah. There is now another problem; whenever I click any of those buttons, nothing happens.
    I guess the code reaches its end because it checks if !turn_used, it goes through but then there's if mouse_pressed, it doesn't go through because the user doesn't press anything, and will end the code I guess.
    It still doesn't "wait" until user input.

    Could this be achieved by another method, like if (mouse_pressed) { bla bla} else { doThisMethod(); } and in doThisMethod it goes back to my original script to check if the user has clicked.
    Or any other suggestions?
     
  13. BattleRifle BR55

    BattleRifle BR55 Member

    Joined:
    Jun 24, 2016
    Posts:
    1,087
    My recommendation was to get rid of the turn_used variable because the seat check would already be handling that. I'm guessing there's some interference. Would you mind posting your updated code?
     
  14. Dagoba

    Dagoba Member

    Joined:
    Jul 12, 2016
    Posts:
    86
    Yeah, I should've deleted that.
    Anyways here is the current code with !turn_used, but gonna remove it afterwards:
    Code:
    var tablecount = instance_number(obj_sit_in);
    if (obj_controller.current_turn != tablecount)
    {
        with(obj_sit_in)
        {
            if (seat_number == obj_controller.current_turn && joined && !folded)
            {
                var sb = obj_controller.small_blind;
                var bb = sb * 2;
                var lc, lc_amount; // Lower cash than the small blind, lc_amount = remaining cash
                var betID; // This players bet ID
                if (seat_cash >= sb) seat_cash -= sb; // Fee the small blind
                else
                {
                    lc = true;
                    lc_amount = seat_cash;
                    seat_cash = 0;
                }
                with(par_btn_turn)active = true;
    
                if (!turn_used && mouse_check_button_pressed(mb_left))
                {
                    if (place_meeting(mouse_x, mouse_y, obj_btn_call))
                    {
                        // Check if the player needs to call or check and then do the method
                        obj_controller.current_turn++;
                    }
                    if (position_meeting(mouse_x, mouse_y, obj_btn_fold))
                    {
                        folded = true;
                        obj_controller.current_turn++;
                    }
                    if (position_meeting(mouse_x, mouse_y, obj_btn_bet))
                    {
                        betId = 0;//read value from the bet string
                        if (global.bet < betID) global.bet = betID;
                        else seat_cash = 0;
                        obj_controller.current_turn++;
                    }
                    if (position_meeting(mouse_x, mouse_y, obj_btn_allin))
                    {
                        betID = seat_cash;
                        round_middle_bet += betID;
                            
                        // Checks if there is a higher bet already
                        if (global.bet < betID) global.bet = betID;
                        else seat_cash = 0;
                            
                        obj_controller.current_turn++;
                    }
                }
            }
        }
    }
    // After the loop, draw the cards
    // ALSO ADD IF EVERYBODY HAS RAISED/CHECKED
    if (obj_controller.current_turn == tablecount-1)
    {
        total_middle_bet += round_middle_bet;
        round_middle_bet = 0;
        alarm[1] = 30;  // Draw the cards to the table
    }
     
  15. BattleRifle BR55

    BattleRifle BR55 Member

    Joined:
    Jun 24, 2016
    Posts:
    1,087
    Keep in mind that we're no longer in loop territory, so there's no more waiting for things to happen before other things can execute. Each frame, both major if statements are running, checking all seats to see whose turn it is before doing anything, rather than just waiting on the active player that's next.

    - Change the second current turn check (after everything) into a mere else statement. If you have 5 players, once it's player 5's turn, the second code will run (and will run continually) since his turn will be 4 and tablecount-1 is also 4.
    - Consider my approach to handling folded/joined turns. You don't have anything to move onto the next player, and my guess is this soft lock is the brokenness you're experiencing. For example, if player 1 just performed an action, player 2 will be next but since he has already folded and player 3 isn't even at the table, the code will not move on from player 1 to 4, it will still wait for player 2 to do something.
     

Share This Page