This is a documentation for Board Game Arena: play board games online !

PlayerCounter and TableCounter: Difference between revisions

From Board Game Arena
Jump to navigation Jump to search
(Fixed wrong variable name)
 
(14 intermediate revisions by 2 users not shown)
Line 3: Line 3:
Counters allow to manipulate numbers in the game. PlayerCounter is for counters that have a distinct value for each player (for example, the player money). TableCounter is for single values, like current round.
Counters allow to manipulate numbers in the game. PlayerCounter is for counters that have a distinct value for each player (for example, the player money). TableCounter is for single values, like current round.


== Overview ==
They both share similar functions, and they can update automatically the JS counter (see [[Counter]] "create" parameters).
They both share similar functions, and they can update automatically the JS counter (see [[Counter]] "create" parameters).


You can initialize them using the counterFactory available in the Game class (and State classes) like this:
You can initialize them using the counterFactory available in the Game class (and State classes) like this:
<pre>
<pre>
         $this->roundCounter = $this->counterFactory->createTableCounter('round', defaultValue: 1);
         $this->roundCounter = $this->counterFactory->createTableCounter('round');
         $this->playerCredits = $this->counterFactory->createPlayerCounter('credits', defaultValue: 3);
         $this->playerCredits = $this->counterFactory->createPlayerCounter('credits');
</pre>
</pre>
Note that by default, they have a min to 0, no max, and a default value to 0, but you can change that in the create function.
Note that by default, they have a min to 0 and no max, but you can change that in the create function.


Two PlayerCounter are available by default on the games, playerScore and playerScoreAux. As their name suggests, they will update the player_score and player_score_aux for you (and scoreCtrl on front-side), so you never need to update manually the scores on the DB. They don't have a min, and default is 0, so if you need to set a different initial value, call <code>$this->playerScore->setAll(2)</code>.
Two PlayerCounter are available by default on the games, playerScore and playerScoreAux. As their name suggests, they will update the player_score and player_score_aux for you (and scoreCtrl on front-side), so you never need to update manually the scores on the DB. They don't have a min, and default is 0, so if you need to set a different initial value, call <code>$this->playerScore->setAll(2)</code>.


'''$this->counterFactory->createPlayerCounter(string $name, ?int $min = 0, ?int $max = null, int $defaultValue = 0): PlayerCounter'''
'''$this->counterFactory->createPlayerCounter(string $name, ?int $min = 0, ?int $max = null): PlayerCounter'''


'''$this->counterFactory->createTableCounter(string $name, ?int $min = 0, ?int $max = null, int $defaultValue = 0): TableCounter'''
'''$this->counterFactory->createTableCounter(string $name, ?int $min = 0, ?int $max = null): TableCounter'''


=== PlayerCounter ===
== PlayerCounter ==
;initDb(array $playerIds)
;initDb(array $playerIds, int $initialValue = 0)
:Initialize the DB elements. Must be called during game `setupNewGame`.
:Creates database table if needed (bga_player_counters). Must be called from <code>setupNewGame</code> (or if adding to older games in <code>upgradeTableDb</code>).
:Parameters:
:Parameters:
:* <code>array $playerIds</code> the player ids having the counter (usually, <code>array_keys($players)</code>, but you might want to add 0 for an automata)
:* <code>array $playerIds</code> the player ids having the counter (usually, <code>array_keys($players)</code>, but you might want to add 0 for an automata)
:* <code>int $initialValue</code> initial value, if different than 0


;get(int $playerId)<nowiki>:</nowiki> int
;get(int $playerId)<nowiki>:</nowiki> int
Line 29: Line 31:
:* <code>int $playerId</code> the player id
:* <code>int $playerId</code> the player id
:Throws:
:Throws:
:* <code>UnknownPlayerException</code> if $playerId is not in the player ids initialized by initDb
:* <code>UnknownPlayerException</code> if $playerId is not in the player ids initialized by <code>initDb</code>


;set(int $playerId, int $value, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
;set(int $playerId, int $value, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
:Set the value of the counter, and send a notif to update the value on the front side. Returns the new value.
:Set the value of the counter, and send a notif (of type <code>setPlayerCounter)</code> to update the value on the front side. Returns the new value.
:Parameters:
:Parameters:
:* <code>int $playerId</code> the player id
:* <code>int $playerId</code> the player id
Line 42: Line 44:


;inc(int $playerId, int $inc, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
;inc(int $playerId, int $inc, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
:Increment the value of the counter, and send a notif to update the value on the front side. Returns the new value. Note: if the inc is 0, no notif will be sent.
:Increment the value of the counter, and send a notif (of type <code>setPlayerCounter)</code>to update the value on the front side. Returns the new value. Note: if the inc is 0, no notif will be sent.
:Parameters:
:Parameters:
:* <code>int $playerId</code> the player id
:* <code>int $playerId</code> the player id
Line 61: Line 63:


;setAll(int $value, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
;setAll(int $value, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
:Set the value of the counter for all the players, and send a notif to update the value on the front side. Returns the new value.
:Set the value of the counter for all the players, and send a notif (of type <code>setPlayerCounterAll)</code> to update the value on the front side. Returns the new value.
:Parameters:
:Parameters:
:* <code>int $value</code> the new value
:* <code>int $value</code> the new value
Line 69: Line 71:


;fillResult(array &$result, ?string $fieldName = null)
;fillResult(array &$result, ?string $fieldName = null)
:Updates the result object, to be used in the `getAllDatas` function. Will set the value on each $result["players"] sub-array.
:Updates the result object, to be used in the <code>getAllDatas</code> function. Will set the value on each <code>$result["players"]</code> sub-array.
:Parameters:
:Parameters:
:* <code>array &$result</code> the object to update
:* <code>array &$result</code> the object to update
:* <code>?string $fieldName</code> the field name to set in $result["players"], if different than the counter name.
:* <code>?string $fieldName</code> the field name to set in $result["players"], if different than the counter name.


===TableCounter===
==TableCounter==


;initDb()
;initDb(int $initialValue = 0)
:Initialize the DB elements. Must be called during game `setupNewGame`.
:Creates database table if needed (bga_table_counters). Must be called from <code>setupNewGame</code>.
:Parameters:
:* <code>int $initialValue</code> initial value, if different than 0


;get()<nowiki>:</nowiki> int
;get()<nowiki>:</nowiki> int
Line 83: Line 87:


;set(int $value, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
;set(int $value, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
:Set the value of the counter, and send a notif to update the value on the front side. Returns the new value.
:Set the value of the counter, and send a notif (of type <code>setTableCounter)</code> to update the value on the front side. Returns the new value.
:Parameters:
:Parameters:
:* <code>int $value</code> the new value
:* <code>int $value</code> the new value
Line 91: Line 95:


;inc(int $inc, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
;inc(int $inc, ?\Bga\GameFramework\NotificationMessage $message)<nowiki>:</nowiki> int
:Increment the value of the counter, and send a notif to update the value on the front side. Returns the new value. Note: if the inc is 0, no notif will be sent.
:Increment the value of the counter, and send a notif (of type <code>setTableCounter)</code>to update the value on the front side. Returns the new value. Note: if the inc is 0, no notif will be sent.
:Parameters:
:Parameters:
:* <code>int $inc</code> the value to add to the current value
:* <code>int $inc</code> the value to add to the current value
Line 103: Line 107:
:* <code>array &$result</code> the object to update
:* <code>array &$result</code> the object to update
:* <code>?string $fieldName</code> the field name to set in $result[, if different than the counter name.
:* <code>?string $fieldName</code> the field name to set in $result[, if different than the counter name.
== Default args sent to the notif ==
The notification sent to the front-end will contain some default args, so if you want to write something like this:
<pre>
$this->playerScore->inc(
  $playerId,
  -1,
  new NotificationMessage(clienttranslate('${player_name} loses ${absInc} points with played card ${card_name}'), ['card_name' => 'Hunter'])
);
</pre>
The NotificationMessage args only needs the one that are not supplied automatically by the PlayerCounter.
Built-in args are:
* name: the name of the player counter
* value: the new value
* oldValue: the value before the update
* inc: the increment
* absInc: the absolute value of the increment, allowing you to use <code>'...loses ${absInc} ...'</code> in the notif message if you are incrementing with a negative value
* playerId (only for PlayerCounter)
* player_name (only for PlayerCounter)
== Example ==
To have a counter to store and display the player energy, you will have :
In the Game class properties (with <code>use Bga\GameFramework\Components\Counters\PlayerCounter;</code> on top of the file):
<pre>
public PlayerCounter $playerEnergy;
</pre>
In __construct of Game class:
<pre>
$this->playerEnergy = $this->counterFactory->createPlayerCounter('energy');
</pre>
In setupNewGame:
<pre>
$this->playerEnergy->initDb(array_keys($players));
</pre>
In getAllDatas:
<pre>
$this->playerEnergy->fillResult($result);
</pre>
In an act function (i.e. in State class), when you want to update it:
<pre>
$this->game->playerEnergy->inc($activePlayerId, 1);
</pre>
In the JS setup:
<pre>
            Object.values(gamedatas.players).forEach(player => {
                this.getPlayerPanelElement(player.id).insertAdjacentHTML('beforeend', `
                    <div id="energy-player-counter-${player.id}"></div>
                    <span>${_("Energy")}</span>
                `);
                const counter = new ebg.counter();
                counter.create(
                    `energy-player-counter-${player.id}`,
                    { value: player.energy, playerCounter: 'energy', playerId: player.id }
                );
            });
</pre>
Nothing more needs to be set, the JS counter will update automatically when you call <code>set</code> or <code>inc</code>!
== Listen to counter notification on the client == 
If you want to get the update values on the client for something else than updating a Counter, you can listen to the predefined notification to do additional stuff:
<pre>
    notif_setPlayerCounter: async function( args )
    {
        const { name, value, oldValue, inc, absInc, playerId } = args;
        if (name === 'energy') {
            this.getPlayerTable(playerId).setEnergyTokens(value);
        }
    }
</pre>
In the same fashion, there is <code>notif_setTableCounter</code> and <code>notif_setPlayerCounterAll</code>.

Latest revision as of 22:49, 11 November 2025


Game File Reference



Useful Components

Official

  • Deck: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).
  • PlayerCounter and TableCounter: PHP components to manage counters.
  • Draggable: a JS component to manage drag'n'drop actions.
  • Counter: a JS component to manage a counter that can increase/decrease (ex: player's score).
  • ExpandableSection: a JS component to manage a rectangular block of HTML than can be displayed/hidden.
  • Scrollmap: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples: Saboteur or Takenoko games).
  • Stock: a JS component to manage and display a set of game elements displayed at a position.
  • Zone: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token's places at Can't Stop).
  • bga-animations : a JS component for animations.
  • bga-cards : a JS component for cards.
  • bga-dice : a JS component for dice.
  • bga-autofit : a JS component to make text fit on a fixed size div.
  • bga-score-sheet : a JS component to help you display an animated score sheet at the end of the game.

Unofficial



Game Development Process



Guides for Common Topics



Miscellaneous Resources

Counters allow to manipulate numbers in the game. PlayerCounter is for counters that have a distinct value for each player (for example, the player money). TableCounter is for single values, like current round.

Overview

They both share similar functions, and they can update automatically the JS counter (see Counter "create" parameters).

You can initialize them using the counterFactory available in the Game class (and State classes) like this:

        $this->roundCounter = $this->counterFactory->createTableCounter('round');
        $this->playerCredits = $this->counterFactory->createPlayerCounter('credits');

Note that by default, they have a min to 0 and no max, but you can change that in the create function.

Two PlayerCounter are available by default on the games, playerScore and playerScoreAux. As their name suggests, they will update the player_score and player_score_aux for you (and scoreCtrl on front-side), so you never need to update manually the scores on the DB. They don't have a min, and default is 0, so if you need to set a different initial value, call $this->playerScore->setAll(2).

$this->counterFactory->createPlayerCounter(string $name, ?int $min = 0, ?int $max = null): PlayerCounter

$this->counterFactory->createTableCounter(string $name, ?int $min = 0, ?int $max = null): TableCounter

PlayerCounter

initDb(array $playerIds, int $initialValue = 0)
Creates database table if needed (bga_player_counters). Must be called from setupNewGame (or if adding to older games in upgradeTableDb).
Parameters:
  • array $playerIds the player ids having the counter (usually, array_keys($players), but you might want to add 0 for an automata)
  • int $initialValue initial value, if different than 0
get(int $playerId): int
Returns the current value of the counter for a player.
Parameters:
  • int $playerId the player id
Throws:
  • UnknownPlayerException if $playerId is not in the player ids initialized by initDb
set(int $playerId, int $value, ?\Bga\GameFramework\NotificationMessage $message): int
Set the value of the counter, and send a notif (of type setPlayerCounter) to update the value on the front side. Returns the new value.
Parameters:
  • int $playerId the player id
  • int $value the new value
  • ?\Bga\GameFramework\NotificationMessage $message the next notif to send to the front. Empty for no log, null for no notif at all (the front will not be updated).
Throws:
  • OutOfRangeCounterException if the value is outside the min/max
  • UnknownPlayerException if $playerId is not in the player ids initialized by initDb
inc(int $playerId, int $inc, ?\Bga\GameFramework\NotificationMessage $message): int
Increment the value of the counter, and send a notif (of type setPlayerCounter)to update the value on the front side. Returns the new value. Note: if the inc is 0, no notif will be sent.
Parameters:
  • int $playerId the player id
  • int $inc the value to add to the current value
  • ?\Bga\GameFramework\NotificationMessage $message the next notif to send to the front. Empty for no log, null for no notif at all (the front will not be updated).
Throws:
  • OutOfRangeCounterException if the value is outside the min/max
  • UnknownPlayerException if $playerId is not in the player ids initialized by initDb
getMin(): int
Returns the lowest value.
getMax(): int
Returns the highest value.
getAll(): array
Return the values for each player, as an associative array $playerId => $value.
setAll(int $value, ?\Bga\GameFramework\NotificationMessage $message): int
Set the value of the counter for all the players, and send a notif (of type setPlayerCounterAll) to update the value on the front side. Returns the new value.
Parameters:
  • int $value the new value
  • ?\Bga\GameFramework\NotificationMessage $message the next notif to send to the front. Empty for no log, null for no notif at all (the front will not be updated).
Throws:
  • OutOfRangeCounterException if the value is outside the min/max
fillResult(array &$result, ?string $fieldName = null)
Updates the result object, to be used in the getAllDatas function. Will set the value on each $result["players"] sub-array.
Parameters:
  • array &$result the object to update
  • ?string $fieldName the field name to set in $result["players"], if different than the counter name.

TableCounter

initDb(int $initialValue = 0)
Creates database table if needed (bga_table_counters). Must be called from setupNewGame.
Parameters:
  • int $initialValue initial value, if different than 0
get(): int
Returns the current value of the counter.
set(int $value, ?\Bga\GameFramework\NotificationMessage $message): int
Set the value of the counter, and send a notif (of type setTableCounter) to update the value on the front side. Returns the new value.
Parameters:
  • int $value the new value
  • ?\Bga\GameFramework\NotificationMessage $message the next notif to send to the front. Empty for no log, null for no notif at all (the front will not be updated).
Throws:
  • OutOfRangeCounterException if the value is outside the min/max
inc(int $inc, ?\Bga\GameFramework\NotificationMessage $message): int
Increment the value of the counter, and send a notif (of type setTableCounter)to update the value on the front side. Returns the new value. Note: if the inc is 0, no notif will be sent.
Parameters:
  • int $inc the value to add to the current value
  • ?\Bga\GameFramework\NotificationMessage $message the next notif to send to the front. Empty for no log, null for no notif at all (the front will not be updated).
Throws:
  • OutOfRangeCounterException if the value is outside the min/max
fillResult(array &$result, ?string $fieldName = null)
Updates the result object, to be used in the `getAllDatas` function.
Parameters:
  • array &$result the object to update
  • ?string $fieldName the field name to set in $result[, if different than the counter name.

Default args sent to the notif

The notification sent to the front-end will contain some default args, so if you want to write something like this:

$this->playerScore->inc(
  $playerId, 
  -1, 
  new NotificationMessage(clienttranslate('${player_name} loses ${absInc} points with played card ${card_name}'), ['card_name' => 'Hunter'])
);

The NotificationMessage args only needs the one that are not supplied automatically by the PlayerCounter.

Built-in args are:

  • name: the name of the player counter
  • value: the new value
  • oldValue: the value before the update
  • inc: the increment
  • absInc: the absolute value of the increment, allowing you to use '...loses ${absInc} ...' in the notif message if you are incrementing with a negative value
  • playerId (only for PlayerCounter)
  • player_name (only for PlayerCounter)

Example

To have a counter to store and display the player energy, you will have :

In the Game class properties (with use Bga\GameFramework\Components\Counters\PlayerCounter; on top of the file):

public PlayerCounter $playerEnergy;

In __construct of Game class:

$this->playerEnergy = $this->counterFactory->createPlayerCounter('energy');

In setupNewGame:

$this->playerEnergy->initDb(array_keys($players));

In getAllDatas:

$this->playerEnergy->fillResult($result);

In an act function (i.e. in State class), when you want to update it:

$this->game->playerEnergy->inc($activePlayerId, 1);

In the JS setup:

            Object.values(gamedatas.players).forEach(player => {
                this.getPlayerPanelElement(player.id).insertAdjacentHTML('beforeend', `
                    <div id="energy-player-counter-${player.id}"></div> 
                    <span>${_("Energy")}</span>
                `);
                const counter = new ebg.counter();
                counter.create(
                    `energy-player-counter-${player.id}`, 
                    { value: player.energy, playerCounter: 'energy', playerId: player.id }
                );
            });

Nothing more needs to be set, the JS counter will update automatically when you call set or inc!

Listen to counter notification on the client

If you want to get the update values on the client for something else than updating a Counter, you can listen to the predefined notification to do additional stuff:

    notif_setPlayerCounter: async function( args )
    {
        const { name, value, oldValue, inc, absInc, playerId } = args;
        if (name === 'energy') {
            this.getPlayerTable(playerId).setEnergyTokens(value);
        }
    }

In the same fashion, there is notif_setTableCounter and notif_setPlayerCounterAll.