Hearts tutorial: setSelectionMode() to restrict playable cards list doesn't work as coded

Game development with Board Game Arena Studio
Post Reply
User avatar
Reyvolution
Posts: 8
Joined: 06 April 2020, 04:49

Hearts tutorial: setSelectionMode() to restrict playable cards list doesn't work as coded

Post by Reyvolution »

The good news is I survived the rest of the tutorial and have a working game. :P However, I couldn't get the client-side control for setSelectionMode() to work correctly. I'm following the code samples in the Rule Enforcements section:

The server-side logic correctly determines playable cards in the current player's hand and throws an exception if they attempt to play a disallowed card. I have it working with a call to this.game.handStock.setSelectionMode("single"); to just limit selection to one card, but anytime I try to send in a 2nd parameter for selectable cards, the result is the full hand grayed out with nothing selectable.

Here's the code from the tutorial:

Code: Select all

onEnteringState(args, isCurrentPlayerActive) {
      console.log("Entering state: " + this.bga.states.currentStateName, args);

      this.bga.statusBar.setTitle(
        isCurrentPlayerActive
          ? _("${you} must play a card")
          : _("${actplayer} must play a card"),
      );

      switch (stateName) {
        case "PlayerTurn":
          if (isCurrentPlayerActive) {
            const playableCardsIds = args.playableCardsIds; // returned by the PlayerTurn::getArgs
            const allCards = this.game.handStock.getCards();
            const playableCards = allCards.filter(
              (card) => playableCardIds.includes(parseInt(card.id)) // never know if we get int or string, this method cares
            );
            this.game.handStock.setSelectionMode("single", playableCards);
          }
          break;
      }
    },
I already had to do some tweaks to this:
  • Explicitly set stateName to trigger the switch statement: var stateName = this.bga.states.currentStateName;
  • Loaded the playable cards list from args._private.playableCards instead of args.playableCardsIds since it seems to be nested one level down and have a slightly different name
  • Corrected typo playableCardIds vs playableCardsIds (extra 's')
Walking through the debugger, this gets me into the correct switch case and creates a local playableCardsIds array that holds a set of string values for the card IDs.

If I pass that array of strings as the 2nd param in setSelectionMode, I get all grayed-out cards.

If I pass an array of integers as a hack, I still get all grayed-out cards.

Is it supposed to take an array of a different object type? The provided code seems to just expect it to work with an array of strings.

Looking at the documentation for setSelectionMode I'm having trouble understanding what a valid format for CardsInput should be.

Any ideas why this keeps failing and setting 0 cards as selectable?
User avatar
nalka
Posts: 26
Joined: 11 June 2016, 01:53

Re: Hearts tutorial: setSelectionMode() to restrict playable cards list doesn't work as coded

Post by nalka »

You have to send an array of cards (or at least objects with the property used in your manager's settings' getId) for it to work. For example, if you did

Code: Select all

playableCards = this.game.handStock.getCards();
it'd do the same as when you don't provide setSelectionMode's second parameter (all cards selectable)

In your snippet, if the local playableCardsIds contains strings, I think it fails because you send an int to .includes and includes surely does === instead of ==.
User avatar
Reyvolution
Posts: 8
Joined: 06 April 2020, 04:49

Re: Hearts tutorial: setSelectionMode() to restrict playable cards list doesn't work as coded

Post by Reyvolution »

Thank you, that's helpful! I can see that if I pass an array of 'card' objects it works. And I can get the 'filter' function to work by passing integers instead of strings.

I did this using map(parseInt) on my array of strings, and for some reason, some of the values will map to 'NaN' instead of an integer, even though all of the strings are just representing numeric IDs. For example, map(parseInt) given ['26', '32'] will create an array with values [26, NaN]. So that's the remaining reason why I can't reliably get this to show the correct "playable" cards. :?
User avatar
Reyvolution
Posts: 8
Joined: 06 April 2020, 04:49

Re: Hearts tutorial: setSelectionMode() to restrict playable cards list doesn't work as coded

Post by Reyvolution »

Well, I found a workaround: for some reason Number() works when parseInt() does not.

It's also possible to tighten up the switch case to use one fewer variable. Here's what I ended up using:

Code: Select all

switch (stateName) {
        case "PlayerTurn":
          if (isCurrentPlayerActive) {
            // Visually limits available cards and prevents clicking on non-playable cards. 
            // Philosophically, should the game show this constraint or let the player make a mistake and then explain?
            
            const allCards = this.game.handStock.getCards();
            const playableCardsInts = args._private.playableCards.map(Number);

            const playableCards = allCards.filter(
              (card) => playableCardsInts.includes(card.id) // Needs to be provided int values, not strings
            );
            this.game.handStock.setSelectionMode("single", playableCards);
          }
          break;
      }
Thanks again for the help thinking this one through! :)
Post Reply

Return to “Developers”