diff --git a/docs/game/actions.md b/docs/game/actions.md index 25b07ed..d163850 100644 --- a/docs/game/actions.md +++ b/docs/game/actions.md @@ -258,6 +258,25 @@ We can also add more `{{handlebars}}` variables using the second argument, e.g.: ) ``` +To message only a specific player or players, use the +[`messageTo`](../api/classes/Action#messageto) method instead. This is important +since the messages may include information that is otherwise invisible to some +players. E.g.: + +```ts + .messageTo( + player, "You drew {{card}}" + ).messageTo( + player.others(), "{{player}} drew a card" + ) +``` + +Besides chaining the `message`/`messageTo` on to the actions, these can also be +called at any point using [`game.message`](../api/classes/Game#message) and +[`game.messageTo`](../api/classes/Game#messageto). This is useful if the rules +of the game generate messages outside of players taking specific actions. These +calls are the same but don't have any pre-supplied `player` or action arguments. + :::tip Using {{handlebars}} Using Boardzilla's `{{handlebars}}` syntax in messages allows references to diff --git a/docs/game/board.md b/docs/game/board.md index 0386c34..1e5977a 100644 --- a/docs/game/board.md +++ b/docs/game/board.md @@ -236,8 +236,9 @@ All elements are visible to all players by default. Often a game will require that pieces are visible only to some players and hidden from others. In Boardzilla, "hiding" a Game Element means that the properties of that element are no longer visible. For example if one of our example `Card` instances was -flipped over, the player would be able to see that it was an instance of the -`Card` class, but `card.suit` and `card.number` would be `undefined`. +flipped over, the player would be able to see only that it was an instance of +the `Card` class, but it's properties, like `name`, `suit` and `number` or any +others would be `undefined`. This can be accomplished in a number of ways, the simplest being [`hideFromAll`](../api/classes/GameElement#hidefromall). There are many [other @@ -253,6 +254,20 @@ properties with the static method Card.revealWhenHidden("deck"); ``` +Players can also have invisible properties, such as hidden roles. To make a +property of your Player class invisible to other players, simple call the static +method [`Player#hide`](../api/classes/Player#hide). This property will be +undefined on other players when seen from a specific player's perspective +(i.e. in an action choice or in UI code). + +```ts + class MyPlayer extends Player { + secretRole: 'normie' | 'killer'; + } + + MyPlayer.hide('secretRole'); +``` + ## Movement Pieces can be created in any Space or on the game itself. They can then move diff --git a/docs/introduction/debugging.md b/docs/introduction/debugging.md index c45f575..90c8230 100644 --- a/docs/introduction/debugging.md +++ b/docs/introduction/debugging.md @@ -8,6 +8,30 @@ Boardzilla provides many tools for the all-important task of testing your game code, and troubleshooting issues that might arise. You should be familiar with these tools as you develop so you can constantly check your work. +## Debug overlay + +While working in devtools, a debug overlay is provided by clicking on the +magnifying glass icon in the upper left. This provides access to a breakdown of +the current state of the game. + + + +On the left half on the overlay is a snapshot of the flow defined in the game, +showing the current block highlighted in yellow, and any variables populated in +the colored headers of the flow block that provided them. See +[Flow](../game/flow.md) for a full understanding of what's in here. One thing to +note is that flow is defined once when the game is created and never changes, so +the structure here is always the same. Only the current position and the +populated variables change during game play. That also means if this structure +looks wrong, there is a problem in the flow definition that shouldbe resolved +first. + +On the right half is a snapshot of the current actions available to the viewing +player. Actions are further broken down by the choices on each action that are +presented to the player in order for them to complete the action. If an action +in unavailable or one it's choices has been skipped, this view will explain +why. See [Actions](../game/actions.md) for more information on these. + ## Test runner Boardzilla includes a test runner class that mocks the playing environment of a @@ -15,49 +39,77 @@ server plus a prescribed number of players all sending actions to the game so you can set up automated tests that run through example games and test assertions on the game state. -The test runner exposes both the player versions of the game and the server -version of the game which was complete knowledge of all hidden -information. It's important when testing player moves to use the correct version -for the given player. - ```ts import { TestRunner } from "@boardzilla/core"; +import setup from '../src/game/index.js'; const runner = new TestRunner(setup); -const [player1, player2] = runner.start({ players: 2, settings: {} }); +const [ui1, ui2] = runner.start({ players: 2, settings: {} }); +``` + +If you need to create mock components that do not exist in the game already, You +can add additional setup when you create the test runner as a 2nd argument: + +```ts + runner = new TestRunner(setup, game => { + game.create(Card, 'some-custom-card'); + }); +``` + +The test runner exposes both the player versions of the game and the server +version of the game which was complete knowledge of all hidden +information. It's important when testing player moves to use the correct version +for the given player. -// example move -player1.move("takeCard", { card: player1.game.first(Card) }); +```ts +// example move from player 1's perspective +ui1.move("takeCard", { card: ui1.game.first(Card) }); -// example assertion on server game +// example assertion on the game accessing a property that may be hidden console.assert(runner.server.game.someProperty === "some-value"); // example assertion on player actions -console.assert(player1.actions().length === 0); +console.assert(ui1.actions().length === 0); ``` -You can import the test runner and set up tests using the testing library of -your choice. The starter game includes an [example working test -suite](https://github.com/boardzilla/boardzilla-starter-game/tree/main/test) -using `vitest`. +When you call `runner.start` the players are updated with the game state. You +can inspect the player view and even manipulate the game state from their +perspective by using `ui1.game`. This is equivalent to a player looking at the +board and attempting a move, e.g.: -### Manipulating data in the test runner -It's often useful to be able to manipulate data within the test runner to -set up specific scenarios. Because you're in the test runner rather than inside -the game's logic, some things are not in the same locations. +```ts + ui1.player.first(Card)?.putInto(ui1.game.first('discard')!); + ui1.player.first('discard')!.first(Card) // => the Card just discarded +``` + +You can perform actions with `ui1.move` and test the results. After calling +`ui1.move` the players states are updated to reflect the results of the move. ```ts -// if you want to manipulate anything about the game from the server's pespective use `runner.server.game` -const top3cards = runner.server.game.first('drawPile')?.firstN(3, Card); + ui1.move("takeCard", { card: ui1.game.first(Card) }); + ui1.allMy(Card); // => includes the Card just drawn +``` -// if you want to manipulate anything from a player perspective, use `player1.player` -const player1hand = player1.player.my('hand')?.all(); +You can also manipulate the state on the game using `runner.server.game` +as above and test the results. This is equivalent to the flow of the game making +an update, e.g. -// putting the above 2 together -player1.player.my('hand')?.first(Card)!.putInto(runner.server.game.first('discard')!); +```ts +const top3cards = runner.server.game.first('drawPile')?.firstN(3, Card); +runner.server.game.first('drawPile')!.all(Card).length // => 3 ``` +However these changes are not automatically propagated to the players +for viewing and cannot be immediately tested from a players perspective. You +must call `runner.updatePlayers()` in order to update the players view of the +game with whatever changes you have made. + +You can import the test runner and set up tests using the testing library of +your choice. The token starter game includes an [example working test +suite](https://github.com/boardzilla/boardzilla-starter-game/tree/main/test) +using `vitest`. + ## Browser developer tools Boardzilla outputs some debug info about the current state of the game and the diff --git a/static/img/debug-overlay.png b/static/img/debug-overlay.png new file mode 100644 index 0000000..298e296 Binary files /dev/null and b/static/img/debug-overlay.png differ diff --git a/static/img/element-inspect.png b/static/img/element-inspect.png new file mode 100644 index 0000000..0582a78 Binary files /dev/null and b/static/img/element-inspect.png differ