<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://en.doc.boardgamearena.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=AmadanNaBriona</id>
	<title>Board Game Arena - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://en.doc.boardgamearena.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=AmadanNaBriona"/>
	<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/Special:Contributions/AmadanNaBriona"/>
	<updated>2026-10-08T16:59:35Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.0</generator>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpproteus&amp;diff=27280</id>
		<title>Gamehelpproteus</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpproteus&amp;diff=27280"/>
		<updated>2025-11-11T20:04:50Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: Created page with &amp;quot;***Background*** In ancient Greek mythology there was a sea god named Proteus. His most notable characteristic was that he could change his shape at will, from a man to a fish, a whale, a bird, or anything else. This most useful skill against opponents gave rise to the expression of being in a &amp;quot;Protean struggle.&amp;quot; The Proteus game set is so named because the game can change its form — not its physical form, but rather the game rules themselves.   How to play PROTEUS®...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;***Background*** In ancient Greek mythology there was a sea god named Proteus. His most notable characteristic was that he could change his shape at will, from a man to a fish, a whale, a bird, or anything else. This most useful skill against opponents gave rise to the expression of being in a &amp;quot;Protean struggle.&amp;quot; The Proteus game set is so named because the game can change its form — not its physical form, but rather the game rules themselves. &lt;br /&gt;
&lt;br /&gt;
How to play PROTEUS®&lt;br /&gt;
&lt;br /&gt;
    Players:     Two.&lt;br /&gt;
    Object:     Attain the Goal in effect at the end of the turn.&lt;br /&gt;
    Equipment:     The Proteus board; 3 pieces per player; 9 engraved tiles. &lt;br /&gt;
&lt;br /&gt;
The rule tiles:&lt;br /&gt;
&lt;br /&gt;
The 9 tiles have markings on their face only. The backs are blank. There are 3 tiles in each of three colors. During the game, only one tile of each color may be face up (active) at a time. Here&#039;s what the inscriptions mean:&lt;br /&gt;
&lt;br /&gt;
MOVE (maroon tiles)&lt;br /&gt;
Proteus pieces move like certain chess figures, with these exceptions: — a piece, except when moving as a king, may leap over another piece if there is an empty space on the other side of the piece being jumped over; there is no capturing. Active MOVE rules apply equally to all pieces. Only one piece allowed per space.&lt;br /&gt;
&lt;br /&gt;
    KING — moves like a chess king, one space in any direction.&lt;br /&gt;
    ROOK — moves like a chess rook, any distance in the same row or column (horizontal or vertical).&lt;br /&gt;
    BISHOP/KNIGHT — moves to any empty space not in the same row or column. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
TRADE (turquoise tiles)&lt;br /&gt;
Two tiles may exchange places. Their relative positions don’t matter, nor whether they are face-up or face-down. Pieces, if any occupy them, stay put to await the new tile. Only one tile allowed per space. There are 27 different tile pair combinations for each of these:&lt;br /&gt;
&lt;br /&gt;
    POLARITY — both tiles to be traded must contain pieces, and the pieces must belong to opposing players. The symbols on the pieces don&#039;t matter.&lt;br /&gt;
    COLOR — both tiles to be traded must be the same color. The color doesn&#039;t matter, and they need not be occupied.&lt;br /&gt;
    SHAPE — both tiles to be traded must be the same shape. The shape doesn&#039;t matter, and they need not be occupied. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
GOAL (gold tiles)&lt;br /&gt;
These tiles represent the three different ways a game can be won. The first method is just like Tic-Tac-Toe. The other two methods require that a player&#039;s 3 pieces occupy similar tiles, regardless of their relative positions on the board.&lt;br /&gt;
&lt;br /&gt;
    3-IN-LINE — The winning player&#039;s three pieces must be in a straight line, horizontally, vertically, or diagonally.&lt;br /&gt;
    COLOR — the player&#039;s three pieces must occupy tiles of a single color; symbols on pieces need not match the tiles.&lt;br /&gt;
    SHAPE — the player&#039;s three pieces must occupy tiles of the same shape. &lt;br /&gt;
&lt;br /&gt;
Placement Phase&lt;br /&gt;
&lt;br /&gt;
The board begins empty, with the 9 tiles spread around for easy selection in a common pool. Black places first.&lt;br /&gt;
&lt;br /&gt;
Players take turns placing any of the tiles from the pool face-down onto any empty space of the board, or placing one of their own pieces onto any space already occupied by a vacant tile (never onto an empty space). Once placed, no piece or tile can be moved during this phase of the game.&lt;br /&gt;
&lt;br /&gt;
When a piece and a tile of the same shape come together, that tile is turned face-up and becomes active. Its rule will stay in effect until another tile of the same color is activated.&lt;br /&gt;
&lt;br /&gt;
During the 15 turns of the placement phase, one and only one tile of each color must be activated. They may be activated in any order and by either player. Once a tile is activated, no other tile of the same color can accept a piece of matching shape until after all tiles and pieces have been placed.&lt;br /&gt;
&lt;br /&gt;
Plan ahead:  it may happen that only one player can activate a tile and therefore must do so. For example, if two of the three tiles of a color are already occupied by non-matching pieces, only the third tile is still open for activation. If only one player has a piece of the requisite shape to activate that tile, that is a mandatory placement for that player.&lt;br /&gt;
&lt;br /&gt;
Movement Phase&lt;br /&gt;
&lt;br /&gt;
The movement phase begins when all the pieces and tiles are on the board and three tiles of different colors are active (provided the game was not already won during the placement phase).&lt;br /&gt;
&lt;br /&gt;
Players take turns moving any one of their own pieces to a vacant tile (according to the active Move rule), or exchanging two tiles (according to the active Trade rule).&lt;br /&gt;
&lt;br /&gt;
When, through a move or trade, a piece and tile of the same shape are brought together, that tile becomes activated. It is turned face-up, and the previously active tile of the same color is turned face-down. The new rule is now in effect for both players. If a trade of two inactive tiles of the same color produces two matches, they cancel each other and the previously active tile stays in effect.&lt;br /&gt;
&lt;br /&gt;
The first player to satisfy the Goal active at the end of that turn is the winner. If both players simultaneously meet the goal, neither wins and the game continues until there is a clear winner.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_material_description:_material.inc.php&amp;diff=27279</id>
		<title>Game material description: material.inc.php</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_material_description:_material.inc.php&amp;diff=27279"/>
		<updated>2025-11-11T16:03:40Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT NOTE&#039;&#039;&#039;: This file is not generated anymore by default, but you can still create it (the name is important as only a &amp;lt;code&amp;gt;material.inc.php&amp;lt;/code&amp;gt; file at the root of your project will be automatically loaded) to describe the material of your game.&lt;br /&gt;
&lt;br /&gt;
If you want to put all your material.inc.php in modules/php instead, please read [https://en.doc.boardgamearena.com/Game_material_description:_material.inc.php#Move_it_to_modules/php Move it to modules/php]&lt;br /&gt;
&lt;br /&gt;
This file is included by the constructor of your main game logic (yourgame.game.php), and then the variables defined here are accessible everywhere in your game logic file (and also view.php file).&lt;br /&gt;
&lt;br /&gt;
Using material.inc.php makes your PHP logic file smaller and clean. Normally you put ALL static information about your cards, tokens, tiles, etc in that file which do not change. Do not store static info in database.&lt;br /&gt;
&lt;br /&gt;
== Definition ==&lt;br /&gt;
Example from &amp;quot;Eminent Domain&amp;quot;: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;token_types = [&lt;br /&gt;
 &#039;card_role_survey&#039; =&amp;gt; [&lt;br /&gt;
   &#039;type&#039; =&amp;gt; &#039;card_role&#039;,&lt;br /&gt;
   &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Survey&amp;quot;),&lt;br /&gt;
   &#039;tooltip&#039; =&amp;gt; clienttranslate(&amp;quot;ACTION: Draw 2 Cards&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;ROLE: Look at &amp;lt;div class=&#039;icon survey&#039;&amp;gt;&amp;lt;/div&amp;gt; - 1 planet cards, keep 1&amp;lt;br/&amp;gt; &amp;lt;span class=&#039;yellow&#039;&amp;gt;Leader:&amp;lt;/span&amp;gt; Look at 1 additional card&amp;quot;),&lt;br /&gt;
   &#039;b&#039;=&amp;gt;0,&lt;br /&gt;
   &#039;p&#039;=&amp;gt;&#039;&#039;,&lt;br /&gt;
   &#039;i&#039;=&amp;gt;&#039;S&#039;,&lt;br /&gt;
   &#039;v&#039;=&amp;gt;0,&lt;br /&gt;
   &#039;a&#039;=&amp;gt;&#039;dd&#039;,&lt;br /&gt;
   &#039;r&#039;=&amp;gt;&#039;S&#039;, &lt;br /&gt;
   &#039;l&#039;=&amp;gt;&#039;v&#039;,&lt;br /&gt;
  ],&lt;br /&gt;
&lt;br /&gt;
 &#039;card_tech_1_51&#039; =&amp;gt; [&lt;br /&gt;
   &#039;type&#039; =&amp;gt; &#039;tech&#039;,&lt;br /&gt;
   &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Improved Trade&amp;quot;),&lt;br /&gt;
   &#039;b&#039; =&amp;gt; 3,&lt;br /&gt;
   &#039;p&#039; =&amp;gt; &#039;E&#039;,&lt;br /&gt;
   &#039;i&#039; =&amp;gt; &#039;TP&#039;,&lt;br /&gt;
   &#039;v&#039; =&amp;gt; 0,&lt;br /&gt;
   &#039;a&#039; =&amp;gt; &#039;i&#039;,&lt;br /&gt;
   &#039;side&#039; =&amp;gt; 0,&lt;br /&gt;
   &#039;tooltip&#039; =&amp;gt; clienttranslate(&amp;quot;Collect 1 Influence from the supply.&amp;quot;),&lt;br /&gt;
 ],&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So this defines all info about cards, including types, names, tooltips (to be show on client), rules, payment cost, etc.&lt;br /&gt;
&lt;br /&gt;
You can also define PHP constants that can be used in material file and game.php file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (!defined(&#039;TAPESTRY&#039;)) { // guard since this included multiple times&lt;br /&gt;
    define(&amp;quot;TAPESTRY&amp;quot;, 0);&lt;br /&gt;
    define(&amp;quot;TRACK_EXPLORATION&amp;quot;, 1);&lt;br /&gt;
    define(&amp;quot;TRACK_SCIENCE&amp;quot;, 2);&lt;br /&gt;
    define(&amp;quot;TRACK_MILITARY&amp;quot;, 3);&lt;br /&gt;
    define(&amp;quot;TRACK_TECHNOLOGY&amp;quot;, 4);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Access ==&lt;br /&gt;
&lt;br /&gt;
=== Data fields ===&lt;br /&gt;
To access this in PHP side:&lt;br /&gt;
  $type = $this-&amp;gt;token_types[&#039;card_tech_1_51&#039;][&#039;type&#039;];&lt;br /&gt;
&lt;br /&gt;
To access on JS side you have to send all variables from material file via getAllDatas first:&lt;br /&gt;
    protected function getAllDatas() {&lt;br /&gt;
        $result = array ();&lt;br /&gt;
        $result [&#039;token_types&#039;] = $this-&amp;gt;token_types;&lt;br /&gt;
        ...&lt;br /&gt;
        return $result;&lt;br /&gt;
    }&lt;br /&gt;
  &lt;br /&gt;
Then you can access it in similar way:&lt;br /&gt;
  var type = this.gamedatas.token_types[&#039;card_tech_1_51&#039;].type; // not translatable&lt;br /&gt;
  var name = _(this.gamedatas.token_types[&#039;card_tech_1_51&#039;].name); // to be shown to user (NOI18N)&lt;br /&gt;
&lt;br /&gt;
To send this in notification from PHP side:&lt;br /&gt;
  $this-&amp;gt;notifyAllUsers(&#039;gainCard&#039;,clienttranslate(&#039;player gains ${card_name}&#039;), [&lt;br /&gt;
       &#039;i18n&#039;=&amp;gt;[&#039;card_name&#039;],&lt;br /&gt;
       &#039;card_id&#039; =&amp;gt; $card_id,&lt;br /&gt;
       &#039;card_name&#039; =&amp;gt; $this-&amp;gt;token_types[$card_id][&#039;name&#039;]&lt;br /&gt;
  ]);&lt;br /&gt;
&lt;br /&gt;
=== PHP constants ===&lt;br /&gt;
If you also want to access constants in JS side, you can send them via getAllData like this&lt;br /&gt;
&lt;br /&gt;
        $cc = get_defined_constants(true)[&#039;user&#039;];&lt;br /&gt;
        $result[&#039;constants&#039;]=$cc; // this will be all constants though, you may have to filter some stuff out for security reasons&lt;br /&gt;
&lt;br /&gt;
Alternately you can include a material.inc.php in local php file and call this method to print constants in JS format, then include this file in JS, you may have to synchronize this manually, but its better for auto-complete also.&lt;br /&gt;
        // this needs to be run locally after including materal file (see example in testing below)&lt;br /&gt;
        $cc = get_defined_constants(true)[&#039;user&#039;];&lt;br /&gt;
        foreach ($cc as $key =&amp;gt; $value) {          &lt;br /&gt;
            print (&amp;quot;const $key = $value;\n&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
If you screw up your material file such as by missing some brackets, it is very hard to diagnose. But you can test it locally like this:&lt;br /&gt;
&lt;br /&gt;
misc/material_test.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
class material_test {&lt;br /&gt;
    function __construct() {&lt;br /&gt;
        include &#039;../material.inc.php&#039;;&lt;br /&gt;
        var_dump($this-&amp;gt;token_types); // whatever your var&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
// stub&lt;br /&gt;
function clienttranslate($x) { return $x; }&lt;br /&gt;
&lt;br /&gt;
new material_test();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Adjusting material ==&lt;br /&gt;
&lt;br /&gt;
In rare cases expansions of the game changes the materials of the original game. In such cases (for example, the same card was re-printed with a different text/rules),&lt;br /&gt;
can you keep same card and have material adjust based on selected game options? It is possible with some trickery.&lt;br /&gt;
&lt;br /&gt;
You need to modify the data in that file AFTER constructor when database access is initialized, and have it available for all php entry points.&lt;br /&gt;
This is possible if you override function initTable() in your game.php file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * This is called before every action, unlike constructor this method has initialized state of the table so it can&lt;br /&gt;
     * access db&lt;br /&gt;
     *&lt;br /&gt;
     * @Override&lt;br /&gt;
     */&lt;br /&gt;
    protected function initTable() {&lt;br /&gt;
        // this fiddles with material file depending on the extension selected&lt;br /&gt;
        $this-&amp;gt;adjustMaterial();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function adjustMaterial($force = false) {&lt;br /&gt;
        if ( !$force &amp;amp;&amp;amp; $this-&amp;gt;token_types_adjusted)&lt;br /&gt;
            return;&lt;br /&gt;
        $this-&amp;gt;token_types_adjusted = true;&lt;br /&gt;
        ... // fiddle with data in material file&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To adjust material itself - you can do it in any number of ways I personally use this method: for modified values I specify key posfix that match my game option, and adjustment function re-write my keys, for example&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &#039;card_tech_1_51&#039; =&amp;gt; [&lt;br /&gt;
   &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Improved Trade&amp;quot;),&lt;br /&gt;
   &#039;name@e3&#039; =&amp;gt; clienttranslate(&amp;quot;Much Improved Trade&amp;quot;),&lt;br /&gt;
   &#039;cost&#039; =&amp;gt; 3,&lt;br /&gt;
   &#039;cost@p2&#039; =&amp;gt; 2&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example if player selects game expansion 3, the key name@e2 would override key name, and if there is 2 players, cost@p2 will override cost. If you need exact code, check adjustMaterial in Ultimate Railroads&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: if you need to add some data to material.inc.php programmatically which does not require database, you can just do it right in that file. Keep in mind will run multiple time for each php call back, so it should be very light&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;decks = array (&lt;br /&gt;
        &#039;g&#039; =&amp;gt; array (&#039;id&#039; =&amp;gt; &#039;green&#039;,&#039;name&#039; =&amp;gt; clienttranslate(&#039;Green&#039;),&#039;num&#039; =&amp;gt; 1 ),&lt;br /&gt;
        &#039;r&#039; =&amp;gt; array (&#039;id&#039; =&amp;gt; &#039;red&#039;,&#039;name&#039; =&amp;gt; clienttranslate(&#039;Red&#039;),&#039;num&#039; =&amp;gt; 3 ),&lt;br /&gt;
        &#039;v&#039; =&amp;gt; array (&#039;id&#039; =&amp;gt; &#039;violet&#039;,&#039;name&#039; =&amp;gt; clienttranslate(&#039;Violet&#039;),&#039;num&#039; =&amp;gt; 4 ),&lt;br /&gt;
        &#039;y&#039; =&amp;gt; array (&#039;id&#039; =&amp;gt; &#039;yellow&#039;,&#039;name&#039; =&amp;gt; clienttranslate(&#039;Yellow&#039;),&#039;num&#039; =&amp;gt; 2 ) )&lt;br /&gt;
;&lt;br /&gt;
    &lt;br /&gt;
$this-&amp;gt;dcolor_map = array();&lt;br /&gt;
// reverse map&lt;br /&gt;
foreach ($this-&amp;gt;decks as $info) {&lt;br /&gt;
    $this-&amp;gt;dcolor_map[$info[&#039;num&#039;]]=$info[&#039;id&#039;];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Move it to modules/php ==&lt;br /&gt;
You can move the file to any modules/php folder/subfolder, but it will not be included automatically, you&#039;ll need to import it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Game extends Table {&lt;br /&gt;
    private array $DECKS; // so the IDE knows you define an array called DECKS on the material file&lt;br /&gt;
    &lt;br /&gt;
	function __construct()&lt;br /&gt;
	{&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
&lt;br /&gt;
        require &#039;material.inc.php&#039;; // your material.inc.php in modules/php folder contains $this-&amp;gt;DECKS = [...]&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;initGameStateLabels([]);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
    protected function getAllDatas(): array&lt;br /&gt;
    {&lt;br /&gt;
        // ...&lt;br /&gt;
        // use it the same way&lt;br /&gt;
        $result[&#039;DECKS&#039;] = $this-&amp;gt;DECKS;&lt;br /&gt;
  &lt;br /&gt;
        return $result;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this way, you can use any file name and even split you material in multiple files if you want to.&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Testing_by_developer&amp;diff=27265</id>
		<title>Testing by developer</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Testing_by_developer&amp;diff=27265"/>
		<updated>2025-11-10T01:24:38Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
When you develop a game you obviously have to test it, this page collects the info about testing in one place&lt;br /&gt;
&lt;br /&gt;
== Manual Testing on BGA ==&lt;br /&gt;
&lt;br /&gt;
For manual testing the most important things to know are:&lt;br /&gt;
* how to start/stop game in one click&lt;br /&gt;
* how to switch between players in one click&lt;br /&gt;
* how to save/restore the game state&lt;br /&gt;
* how to construct the game state automatically&lt;br /&gt;
All of these described here https://en.doc.boardgamearena.com/Tools_and_tips_of_BGA_Studio&lt;br /&gt;
&lt;br /&gt;
There is also HUGE checklist of things you need to test manually which you may not even think about, defined here https://en.doc.boardgamearena.com/Pre-release_checklist&lt;br /&gt;
&lt;br /&gt;
== Manual Testing locally ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HTML/CSS&#039;&#039;&#039;&lt;br /&gt;
At this era the file sync is almost instant so you do not save much by doing this locally, however if internet is a challenge - here are some tips&lt;br /&gt;
https://en.doc.boardgamearena.com/Tools_and_tips_of_BGA_Studio#Speed_up_CSS_development_and_layout&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PHP&#039;&#039;&#039;&lt;br /&gt;
You can run and debug php locally using tip https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Creating_a_test_class_to_run_PHP_locally&lt;br /&gt;
&lt;br /&gt;
== Automated Testing ==&lt;br /&gt;
&#039;&#039;&#039;JavaScript&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
I have not tried it. If you have any success please add instructions here. Theoretically its is possible to hook something like selenium to studio games&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;PHP&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can hook up phpunit and write unit tests for php, for that you need stubs for framework functions and classes.&lt;br /&gt;
&lt;br /&gt;
* Install php-cli (you need a verson that bga runs - consult https://en.doc.boardgamearena.com/Studio#Software_Versions)&lt;br /&gt;
* Install phpunit matching this specific php version (the latest does not work), if you use composer DO not install it in the game directory - install it somewhere else &lt;br /&gt;
* Create directory modules/tests&lt;br /&gt;
** If you do file sync - exclude it from the sync&lt;br /&gt;
* Checkout/get stubs from github (see https://en.doc.boardgamearena.com/Setting_up_BGA_Development_environment_using_VSCode), i.e&lt;br /&gt;
** git clone git@github.com:elaskavaia/bga-sharedcode.git&lt;br /&gt;
* So the main issue - php unit needs to find the parts of bga framework which is not available, in this example we will use stubs above&lt;br /&gt;
* Create autoload.php in modules/ directory&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
define(&amp;quot;APP_GAMEMODULE_PATH&amp;quot;, getenv(&#039;APP_GAMEMODULE_PATH&#039;)); &lt;br /&gt;
&lt;br /&gt;
spl_autoload_register(function ($class_name) {&lt;br /&gt;
  &lt;br /&gt;
    switch ($class_name) {&lt;br /&gt;
        case &amp;quot;APP_DbObject&amp;quot;:&lt;br /&gt;
            //var_dump($class_name);&lt;br /&gt;
            //var_dump(APP_GAMEMODULE_PATH);&lt;br /&gt;
            include APP_GAMEMODULE_PATH.&amp;quot;/module/table/table.game.php&amp;quot;;&lt;br /&gt;
            break;&lt;br /&gt;
        default:&lt;br /&gt;
            include $class_name . &amp;quot;.php&amp;quot;;&lt;br /&gt;
            break;&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Set env var APP_GAMEMODULE_PATH to point to where stubs are, in this case APP_GAMEMODULE_PATH=$HOME/git/bga-sharedcode/misc/&lt;br /&gt;
* Create a test in tests/ folder (see phpunit examples)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php declare(strict_types=1);&lt;br /&gt;
use PHPUnit\Framework\TestCase;&lt;br /&gt;
&lt;br /&gt;
require_once &amp;quot;../mygame.game.php&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
class GameUT extends MyGame {&lt;br /&gt;
    function __construct() {&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        include &amp;quot;../material.inc.php&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    // override/stub methods here that access db and stuff&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
final class GameTest extends TestCase {&lt;br /&gt;
    public function testGameProgression() {&lt;br /&gt;
        $m = new GameUT();&lt;br /&gt;
        $this-&amp;gt;assertEquals(0,$m-&amp;gt;getGameProgression());&lt;br /&gt;
    }&lt;br /&gt;
    // more tests&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Run this from modules/ dir (this assumes env var above already set globally)&lt;br /&gt;
 phpunit --bootstrap autoload.php tests/&lt;br /&gt;
&lt;br /&gt;
== Play testing on studio ==&lt;br /&gt;
&lt;br /&gt;
To play test on studio you can use your test accounts dev0... dev9. You can give some of these account to other people just make sure you change the password.&lt;br /&gt;
You should not encourage other people who are not developers to create studio account, this is against bga policy.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=15022</id>
		<title>Game interface logic: Game.js</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=15022"/>
		<updated>2022-10-09T19:46:40Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Destroy */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
This is the main file for your game interface. Here you will define:&lt;br /&gt;
&lt;br /&gt;
* Which actions on the page will generate calls to the server.&lt;br /&gt;
* What happens when you get a notification for a change from the server and how it will show in the browser. &lt;br /&gt;
* Setup user interface&lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
&lt;br /&gt;
The details of how the file is structured are described below with comments in the code skeleton provided to you.&lt;br /&gt;
&lt;br /&gt;
Here is the basic structure:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;constructor&#039;&#039;&#039;: here you can define global variables for your whole interface.&lt;br /&gt;
* &#039;&#039;&#039;setup&#039;&#039;&#039;: this method is called when the page is refreshed, and sets up the game interface.&lt;br /&gt;
* &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;: this method is called when entering a new game state. You can use it to customize the view for each game state.&lt;br /&gt;
* &#039;&#039;&#039;onLeavingState&#039;&#039;&#039;: this method is called when leaving a game state.&lt;br /&gt;
* &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039;: called when entering a new state, in order to add action buttons to the status bar.&lt;br /&gt;
* &#039;&#039;(utility methods)&#039;&#039;: this is where you can define your utility methods.&lt;br /&gt;
* &#039;&#039;(player&#039;s actions)&#039;&#039;: this is where you can write your handlers for player actions on the interface (example: click on an item).&lt;br /&gt;
* &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;: this method associates notifications with notification handlers. For each game notification, you can trigger a javascript method to handle it and update the game interface.&lt;br /&gt;
* &#039;&#039;(notification handlers)&#039;&#039;: this is where you define the notifications handlers associated with notifications in &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;, above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
More details:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setup(gamedatas: object)            &#039;&#039;&#039;&lt;br /&gt;
This method must set up the game user interface according to current game situation specified in parameters.&lt;br /&gt;
The method is called each time the game interface is displayed to a player, ie:&lt;br /&gt;
&lt;br /&gt;
* when the game starts&lt;br /&gt;
* when a player opens a game in the browser later &lt;br /&gt;
* when a player refreshes the game page (F5)&lt;br /&gt;
* when player does a server side Undo&lt;br /&gt;
&lt;br /&gt;
&amp;quot;gamedatas&amp;quot; argument contains all data retrieved by your &amp;quot;getAllDatas&amp;quot; PHP method and some more.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onEnteringState(stateName: string, args: { args: any } | null): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is called each time we enter a new game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
To access state arguments passed via calling php arg* method use args?.args.&lt;br /&gt;
Typically you would do something only for active player, using this.isCurrentPlayerActive() check.&lt;br /&gt;
It is also called (for the current game state only) when doing a browser refresh (after the setup method is called).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: for multipleactiveplayer states:&lt;br /&gt;
the active players are NOT active yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/inactive status.&lt;br /&gt;
If you are doing initialization of some structures which do not depend on the active player, you can just replace (this.isCurrentPlayerActive()) with (!this.isSpectator) &lt;br /&gt;
for the main switch in that method.&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Difference_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onLeavingState(stateName: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is called each time we leave a game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this point (i.e. cleanup).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onUpdateActionButtons(stateName: string, args: object | null): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this method you can manage &amp;quot;action buttons&amp;quot; that are displayed in the action status bar and highlight active UI elements.&lt;br /&gt;
To access state arguments passed via calling php arg* method use &#039;&#039;&#039;args&#039;&#039;&#039; parameter. Note: args can be null! For &#039;&#039;&#039;game&#039;&#039;&#039; states and when you don&#039;t supply state args function - it is null.&lt;br /&gt;
This method is called when the active or multiactive player changes. In a classic &amp;quot;activePlayer&amp;quot; state this method is called before the onEnteringState state.&lt;br /&gt;
In multipleactiveplayer state it is a mess. The sequencing of calls depends on whether you get into that state from transitions OR from reloading the whole game (i.e. F5).&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Difference_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dojo framework ==&lt;br /&gt;
&lt;br /&gt;
BGA uses the [http://dojotoolkit.org/ Dojo Javascript framework].&lt;br /&gt;
&lt;br /&gt;
The Dojo framework allows us to do complex things more easily. The BGA framework uses Dojo extensively.&lt;br /&gt;
&lt;br /&gt;
To implement a game, you only need to use a few parts of the Dojo framework. All the Dojo methods you need are described on this page.&lt;br /&gt;
&lt;br /&gt;
== Javascript minimization (after July 2020) ==&lt;br /&gt;
&lt;br /&gt;
For performance reasons, when deploying a game the javascript code is minimized using &#039;&#039;&#039;terser&#039;&#039;&#039; (https://github.com/terser/terser). This minifier works with modern javascript syntax. From your project &amp;quot;Manage game&amp;quot; page, you can now test a minified version of your javascript on the studio (and revert to the original).&lt;br /&gt;
&lt;br /&gt;
NB: it has been reported that there is an issue with this minifier and percentage values for opacity.&lt;br /&gt;
&lt;br /&gt;
== Accessing Players Information ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;player_id: number&#039;&#039;&#039;&lt;br /&gt;
id of the player who is looking at the game. The player may not be part of the game (i.e. spectator)&lt;br /&gt;
  if (notif.args.player_id == this.player_id) {&lt;br /&gt;
    ...&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;isSpectator: boolean&#039;&#039;&#039;&lt;br /&gt;
Flag set to true if the user at the table is a spectator (not a player).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    if (this.isSpectator) {&lt;br /&gt;
        this.player_color = &#039;ffffff&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
        this.player_color = gamedatas.players[this.player_id].color;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: If you want to hide an element from spectators, you should use [[Game_interface_stylesheet:_yourgamename.css#spectatorMode|CSS &#039;spectatorMode&#039; class]].&lt;br /&gt;
&lt;br /&gt;
You may consider making a function like this, to detect if the game is in a read-only state (i.e. non-interactive):&lt;br /&gt;
  // Returns true for spectators, instant replay (during game), archive mode (after game end)&lt;br /&gt;
  isReadOnly: function () {&lt;br /&gt;
    return this.isSpectator || typeof g_replayFrom != &#039;undefined&#039; || g_archive_mode;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gamedatas: object&#039;&#039;&#039;&lt;br /&gt;
Contains the initial set of data to init the game, created at game start or by game refresh (F5).&lt;br /&gt;
You can update it as needed to keep an up-to-date reference of the game on the client side if you need it, however most of the time this is unnecessary.&lt;br /&gt;
&lt;br /&gt;
Note: In hotseat mode, the framework does not keep this.gamedatas of hotseat players and shares the same set as the main player to store data.&lt;br /&gt;
&lt;br /&gt;
Note: be careful when you update this data structurally, many framework functions expect data to be certain way and they will break if they see something else.&lt;br /&gt;
&lt;br /&gt;
Typical example of accessing player&#039;s info&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for (var player_id in this.gamedatas.players) { &lt;br /&gt;
    var playerInfo = this.gamedatas.players [player_id];&lt;br /&gt;
    var c = playerInfo.color;&lt;br /&gt;
    var name = playerInfo.name;&lt;br /&gt;
    // do something &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;isCurrentPlayerActive(): boolean&#039;&#039;&#039;&lt;br /&gt;
Returns true if the player on whose browser the code is running is currently active (it&#039;s his turn to play). Note: see remarks above about usage of this function inside onEnteringState method.&lt;br /&gt;
  if (this.isCurrentPlayerActive()) {&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getActivePlayerId(): number&#039;&#039;&#039;&lt;br /&gt;
Return the ID of the active player, or null if we are not in an &amp;quot;activeplayer&amp;quot; type state.&lt;br /&gt;
  if (this.player_id == this.getActivePlayerId()) ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getActivePlayers(): number[]&#039;&#039;&#039;&lt;br /&gt;
Return an array with the IDs of players who are currently active (or an empty array if there are none).&lt;br /&gt;
&lt;br /&gt;
== Accessing and manipulating the DOM ==&lt;br /&gt;
&lt;br /&gt;
=== Element by Id ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$(elementId: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The $ function is used to get an HTML element using its &amp;quot;id&amp;quot; attribute.&lt;br /&gt;
&lt;br /&gt;
Example: modify the content of a &amp;quot;span&amp;quot; element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In your HTML code:&lt;br /&gt;
   &amp;lt;span id=&amp;quot;a_value_in_the_game_interface&amp;quot;&amp;gt;1234&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In your Javascript code:&lt;br /&gt;
   $(&#039;a_value_in_the_game_interface&#039;).innerHTML = &amp;quot;9999&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: It is safe to use if you don&#039;t know if variable is string (id of element) or element itself, i.e. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  foo: function(card) {&lt;br /&gt;
       card = $(card); // now its node, no need to write if (typeof card === &#039;string&#039;) ...&lt;br /&gt;
       // but its good idea to check for null here&lt;br /&gt;
       ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getElementById(elementId: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note: $() is the standard method to access some HTML element with the BGA Framework. You can use &#039;&#039;&#039;getElementById&#039;&#039;&#039; but a longer to type and less handy as it does not do some checks.&lt;br /&gt;
&lt;br /&gt;
=== Style ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.style(node: ElementOrId, styleName: string, styleValue: any): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.style you can modify the CSS property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Make an element disappear&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Give an element a 2px border&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;borderWidth&#039;, &#039;2px&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Change the background position of an element&lt;br /&gt;
     // (very practical when you are using CSS sprites to transform an element to another)&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;backgroundPosition&#039;, &#039;-20px -50px&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you have to modify several CSS properties of an element, or if you have a complex CSS transformation to do, you should consider using dojo.addClass/dojo.removeClass (see below).&lt;br /&gt;
&lt;br /&gt;
You can also use object to set multiple values&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dojo.setStyle(&amp;quot;thinger&amp;quot;, {&lt;br /&gt;
  &amp;quot;opacity&amp;quot;: 0.5,&lt;br /&gt;
  &amp;quot;border&amp;quot;: &amp;quot;3px solid black&amp;quot;,&lt;br /&gt;
  &amp;quot;height&amp;quot;: &amp;quot;300px&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;addStyleToClass(cssClassName: string, styleName: string, styleValue: any):void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as dojo.style(), but for all the nodes set with the specified cssClassName&lt;br /&gt;
Equivalent of &lt;br /&gt;
  &lt;br /&gt;
  dojo.query(`.${aclass}`).style(styleName, styleValue)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dojo.query(&amp;quot;#baz &amp;gt; div&amp;quot;).style({&lt;br /&gt;
  opacity:0.75,&lt;br /&gt;
  fontSize:&amp;quot;13pt&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS style&#039;&#039;&#039;&lt;br /&gt;
  $(&#039;my_element&#039;).style.display=&#039;none&#039;; // set&lt;br /&gt;
  var display = $(&#039;my_element&#039;).style.display; // get&lt;br /&gt;
  $(&#039;my_element&#039;).style.removeProperty(&#039;display&#039;); // remove&lt;br /&gt;
&lt;br /&gt;
=== Classes ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.addClass(node: ElementOrId, classes: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.removeClass(node: ElementOrId, classes: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.hasClass(node: ElementOrId, aclass: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.toggleClass(node: ElementOrId, aclass: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In many situations, many small CSS property updates can be replaced by a CSS class change (i.e., you add a CSS class to your element instead of applying all modifications manually).&lt;br /&gt;
&lt;br /&gt;
Advantages are:&lt;br /&gt;
* All your CSS stuff remains in your CSS file.&lt;br /&gt;
* You can add/remove a list of CSS modifications with a simple function and without error.&lt;br /&gt;
* You can test whether you applied the CSS to an element with the &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Example from &#039;&#039;Reversi&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // We add &amp;quot;possibleMove&amp;quot; to an element&lt;br /&gt;
    dojo.addClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
    // In our CSS file, the class is defined as:&lt;br /&gt;
    .possibleMove {&lt;br /&gt;
      background-color: white;&lt;br /&gt;
      opacity: 0.2;&lt;br /&gt;
      filter:alpha(opacity=20); /* For IE8 and earlier */  &lt;br /&gt;
      cursor: pointer;  &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     // So we&#039;ve applied 4 CSS property changes in one line of code.&lt;br /&gt;
&lt;br /&gt;
     // ... and when we need to check if a square is a possible move on the client side:&lt;br /&gt;
     if( dojo.hasClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; ) )&lt;br /&gt;
     { ... }&lt;br /&gt;
&lt;br /&gt;
     // ... and if we want to remove all possible moves in one line of code (see &amp;quot;dojo.query&amp;quot; method):&lt;br /&gt;
     dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS classList&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is the only exception where dojo versions are better&lt;br /&gt;
  // add class&lt;br /&gt;
  $(token_id).classList.addClass(&#039;possibleMove&#039;);&lt;br /&gt;
  // remove class&lt;br /&gt;
  $(token_id).classList.removeClass(&#039;possibleMove&#039;);&lt;br /&gt;
  // add 2 classes&lt;br /&gt;
  const myclasses = [&#039;a&#039;,&#039;b&#039;];&lt;br /&gt;
  $(token_id).classList.addClass(...myclasses);&lt;br /&gt;
  // add classes to query result&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.hand .card&amp;quot;).forEach((node)=&amp;gt;node.classList.addClass(&#039;possibleMove&#039;));&lt;br /&gt;
&lt;br /&gt;
=== Attributes ===&lt;br /&gt;
&lt;br /&gt;
;dojo.attr&lt;br /&gt;
&lt;br /&gt;
With dojo.attr you can access or change the value of an attribute or property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Get the title of a node&lt;br /&gt;
     var title = dojo.attr( id, &#039;title&#039; );&lt;br /&gt;
     // Change the height of a node&lt;br /&gt;
     dojo.attr( &#039;img_growing_tree&#039;, &#039;height&#039;, 100 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS attr&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
   $(token).id=new_id; // set attr for &amp;quot;id&amp;quot;&lt;br /&gt;
   var id = $(token).id; // get&lt;br /&gt;
&lt;br /&gt;
=== Queries ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.query(cssSelector: string): Element[]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.query, you can query a bunch of HTML elements with a single function, with a &amp;quot;CSS selector&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // All elements with class &amp;quot;possibleMove&amp;quot;:&lt;br /&gt;
     var elements = dojo.query( &#039;.possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Count number of tokens (i.e., elements of class &amp;quot;token&amp;quot;) on the board (i.e., the element with id &amp;quot;board&amp;quot;):&lt;br /&gt;
     dojo.query( &#039;#board .token&#039; ).length;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But what is really cool with dojo.query is that you can combine it with almost all methods above.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Trigger a method when the mouse enter in any element with class &amp;quot;meeple&amp;quot;:&lt;br /&gt;
     dojo.query( &#039;.meeple&#039; ).connect( &#039;onmouseenter&#039;, this, &#039;myMethodToTrigger&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Hide all meeples who are on the board&lt;br /&gt;
     dojo.query( &#039;#board .meeple&#039; ).style( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS query&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  var cards=document.querySelectorAll(&amp;quot;.hand .card&amp;quot;);// all cards in all hands&lt;br /&gt;
  var cards=$(&#039;hand&#039;).querySelectorAll(&amp;quot;.card&amp;quot;);// all cards in specific hand&lt;br /&gt;
  var card=document.querySelector(&amp;quot;.hand .card&amp;quot;);// first card or null if none (super handy)&lt;br /&gt;
&lt;br /&gt;
=== Creating and Destroying elements ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.empty(node: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove all children of the node element&lt;br /&gt;
   dojo.empty(&#039;my_hand&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.destroy(node: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove the element&lt;br /&gt;
   dojo.destroy(&#039;my_token&#039;);&lt;br /&gt;
&lt;br /&gt;
   dojo.query(&amp;quot;.green&amp;quot;, mynode).forEach(dojo.destroy); // this remove all subnode of class green from mynode&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.create(tag: string, attributes?: obj, parent?: ElementOrId): Element&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create element&lt;br /&gt;
&lt;br /&gt;
    dojo.create(&amp;quot;div&amp;quot;, { class: &amp;quot;yellow_arrow&amp;quot; }, parent); // this creates div with class yellow_array and places it in &amp;quot;parent&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.format_block(name: string, args: object): string&#039;&#039;&#039;&lt;br /&gt;
This bga function that takes global var from template file and substitute variables, typical use would be&lt;br /&gt;
&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                var div = this.format_block(&#039;jstpl_player_board&#039;, player ); // var jstpl_player_board = ... is defined in .tpl file &lt;br /&gt;
Note: result is trimmed&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.format_string(name: string, args: object): string&#039;&#039;&#039;&lt;br /&gt;
This bga function just substitute variables in a string, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     var div = this.format_string(&#039;&amp;lt;div color=&amp;quot;${player_color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, {player_color: &#039;#ff0000&#039;} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: result is trimmed&lt;br /&gt;
&lt;br /&gt;
Note: this can be replaced by using backquoted string now: &lt;br /&gt;
     const player_color =  &#039;#ff0000&#039;;&lt;br /&gt;
     const div = `&amp;lt;div color=&amp;quot;${player_color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;`;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.format_string_recursive&#039;&#039;&#039;&lt;br /&gt;
This bga function is similar to this.format_string but is capable of processing recursive argument structures and translations. It is used to format server notifications.&lt;br /&gt;
&lt;br /&gt;
TODO: find better place for these function docs&lt;br /&gt;
&lt;br /&gt;
=== Moving elements ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.place(node: string | Element, refNode: ElementOrId, pos?: string | number): Element&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
dojo.place is the best function to insert HTML code somewhere in your game interface without breaking something. It is much better to use than the &#039;&#039;&#039;innerHTML=&#039;&#039;&#039; method if you must insert HTML tags and not only values.&lt;br /&gt;
&lt;br /&gt;
node: &lt;br /&gt;
&lt;br /&gt;
Can be a String or a DOM node. If it is a string starting with “&amp;lt;”, it is assumed to be an HTML fragment, which will be created. Otherwise it is assumed to be an id of a DOM node.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Insert your HTML code as a child of a container element&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;div class=&#039;foo&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
pos:&lt;br /&gt;
&lt;br /&gt;
Optional argument. Can be a number or one of the following strings: “before”, “after”, “replace”, “only”, “first”, or “last”. If omitted, “last” is assumed. &lt;br /&gt;
&lt;br /&gt;
&amp;quot;replace&amp;quot;: Replace the container element with my_node element&lt;br /&gt;
&lt;br /&gt;
&amp;quot;first&amp;quot;: Places the node as a child of the reference node. The node is placed as the first child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;last&amp;quot; (default): Places the node as a child of the reference node. The node is placed as the last child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;before&amp;quot;: places the node right before the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;after&amp;quot;: places the node right after the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;only&amp;quot;: replaces all children of the reference node with the node.&lt;br /&gt;
&lt;br /&gt;
positive integer: This parameter can be a positive integer. In this case, the node will be placed as a child of the reference node with this number (counting from 0). If the number is more than number of children, the node will be appended to the reference node making it the last child. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Replace all children of container with my_node &lt;br /&gt;
     dojo.place( $(&#039;my_node&#039;), &amp;quot;your_container_element_id&amp;quot;, &amp;quot;only&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
See also full doc on dojo.place: [https://dojotoolkit.org/reference-guide/1.7/dojo/place.html]&lt;br /&gt;
&lt;br /&gt;
Usually, when you want to insert some piece of HTML in your game interface, you should use &amp;quot;[[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
But you can also relocate elements like that. Note: it won&#039;t animate if you do that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;placeOnObject(mobile_obj: ElementOrId, target_obj: ElementOrId): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
places mobile_obj on target_obj, set the absolute positions and centers the mobile_obj on target_obj,&lt;br /&gt;
effect is immediate&lt;br /&gt;
&lt;br /&gt;
This is not really an animation, but placeOnObject is frequently used before starting an animation.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // (We just created an object &amp;quot;my_new_token&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  // Place the new token on current player board&lt;br /&gt;
  this.placeOnObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;overall_player_board_&amp;quot;+this.player_id );&lt;br /&gt;
  &lt;br /&gt;
  // Then slide it to its position on the board&lt;br /&gt;
  this.slideToObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;a_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;placeOnObjectPos( mobile_obj: ElementOrId, target_obj: ElementOrId, target_x: number, target_y: number ): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method works exactly like placeOnObject, except than you can specify some (x,y) coordinates (in px). This way, the center of &amp;quot;mobile_obj&amp;quot; will be placed to the specified x,y position relatively to the center of &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: the placement works differently from this.slideToObjectPos&#039;&#039;, since coordinates are calculated based on the center of objects.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.attachToNewParent(mobile_obj: ElementOrId, target_obj: ElementOrId): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With this method, you change the HTML parent of &amp;quot;mobile_obj&amp;quot; element without moving it. &lt;br /&gt;
&amp;quot;target_obj&amp;quot; is the new parent of this element. The beauty of &lt;br /&gt;
attachToNewParent is that the mobile_obj element DOES NOT MOVE during this process.&lt;br /&gt;
&lt;br /&gt;
What happens is that the method calculate a relative position of mobile_obj to make sure it does not move after the HTML parent changes.&lt;br /&gt;
&lt;br /&gt;
Why using this method?&lt;br /&gt;
&lt;br /&gt;
Changing the HTML parent of an element can be useful for the following reasons:&lt;br /&gt;
* When the HTML parent moves, all its child are moving with them. If some game elements is no more linked with a parent HTML object, you may want to attach it to another place.&lt;br /&gt;
* The z_order (vertical order of display) depends on the position in the DOM, so you may need to change the parent of some game elements when they are moving in your game area.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CAREFUL&#039;&#039;&#039;: this function destroys original object and places a clone onto a new parent, this will break all references to this HTML element (ex: dojo.connect).&lt;br /&gt;
If you need version that does not destroy the object but the same otherwise see [[BGA_Studio_Cookbook#Attach_to_new_parent_without_destroying_the_object]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Animations ==&lt;br /&gt;
&lt;br /&gt;
===Dojo Animations===&lt;br /&gt;
&lt;br /&gt;
BGA animations is based on Dojo Animation ([http://dojotoolkit.org/documentation/tutorials/1.8/animation/ see tutorial here]).&lt;br /&gt;
&lt;br /&gt;
However, most of the time, you can just use methods below, which are built on top of Dojo Animation.&lt;br /&gt;
&lt;br /&gt;
Note: one interesting method from Dojo that could be useful from time to time is &amp;quot;Dojo.Animation&amp;quot;. It allows you to make any CSS property &amp;quot;slide&amp;quot; from one value to another.&lt;br /&gt;
&lt;br /&gt;
Note 2: the slideTo methods are not compatible with CSS transform (scale, zoom, rotate...). If possible, avoid using CSS transform on nodes that are being slided. Eventually, the only possible solution to make these 2 compatible is to disable all CSS transform properties, use slideToObjectPos/placeOnObjectPos, and then apply them again.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sliding===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;slideToObject(mobile_obj: string | Element, target_obj: string | Element, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can use slideToObject to &amp;quot;slide&amp;quot; an element to a target position.&lt;br /&gt;
&lt;br /&gt;
Sliding element on the game area is the recommended and the most used way to animate your game interface. Using slides allow players to figure out what is happening on the game, as if they were playing with the real boardgame.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* mobile_obj: the ID of the object to move. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned.&lt;br /&gt;
* target_obj: the ID of the target object. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned. Note that it is not mandatory that mobile_obj and target_obj have the same size. If their size are different, the system slides the center of mobile_obj to the center of target_obj.&lt;br /&gt;
* duration: (optional) defines the duration in millisecond of the slide. The default is 500 milliseconds.&lt;br /&gt;
* delay: (optional). If you defines a delay, the slide will start only after this delay. This is particularly useful when you want to slide several object from the same position to the same position: you can give a 0ms delay to the first object, a 100ms delay to the second one, a 200ms delay to the third one, ... this way they won&#039;t be superposed during the slide.&lt;br /&gt;
&lt;br /&gt;
BE CAREFUL: The method returns an dojo.fx animation, so you can combine it with other animation if you want to. It means that you have to call the &amp;quot;play()&amp;quot; method, otherwise the animation WON&#039;T START.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.slideToObject( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;slideToObjectPos(mobile_obj: string | Element, target_obj: string | Element, target_x: number, target_y: number, duration?: number, delay?: number ): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method does exactly the same as &amp;quot;slideToObject&amp;quot;, except than you can specify some (x,y) coordinates. This way, &amp;quot;mobile_obj&amp;quot; will slide to the specified x,y position relatively to &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example: slide a token to some place on the board, 10 pixels from the top:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.slideToObjectPos( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 0, 10 ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;slideTemporaryObject( mobile_obj_html: string, mobile_obj_parent: string | Element, from: string  | Element, to: string  | Element, duration?: number, delay?: number ): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is useful when you want to slide a temporary HTML object from one place to another. As this object does not exists before the animation and won&#039;t remain after, it could be complex to create this object (with dojo.place), to place it at its origin (with placeOnObject) to slide it (with slideToObject) and to make it disappear at the end.&lt;br /&gt;
&lt;br /&gt;
slideTemporaryObject does all of this for you:&lt;br /&gt;
* mobile_obj_html is a piece of HTML code that represent the object to slide.&lt;br /&gt;
* mobile_obj_parent is the ID of an HTML element of your interface that will be the parent of this temporary HTML object.&lt;br /&gt;
* from is the ID of the origin of the slide.&lt;br /&gt;
* to is the ID of the target of the slide.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.slideTemporaryObject( &#039;&amp;lt;div class=&amp;quot;token_icon&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, &#039;tokens&#039;, &#039;my_origin_div&#039;, &#039;my_target_div&#039; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Destroy===&lt;br /&gt;
&#039;&#039;&#039;slideToObjectAndDestroy: function(mobile_obj: string | Element, target_obj: string | Element, duration?: number, delay?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is a handy shortcut to slide an existing HTML object to some place then destroy it upon arrival. It can be used for example to move a victory token or a card from the board to the player panel to show that the player earns it, then destroy it when we don&#039;t need to keep it visible on the player panel.&lt;br /&gt;
&lt;br /&gt;
It works the same as this.slideToObject and takes the same arguments, but it starts the animation. &lt;br /&gt;
&lt;br /&gt;
CAREFUL: Make sure nothing is creating the same object at the same time the animation is running, because this will cause some random disappearing effects&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.slideToObjectAndDestroy( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 1000, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;fadeOutAndDestroy( node: string | Element, duration?: number, delay?: number):void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function fade out the target node, then destroy it. Its starts the animation.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.fadeOutAndDestroy( &amp;quot;a_card_that_must_disappear&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the HTML node still exists until during few milliseconds, until the fadeOut has been completed.&lt;br /&gt;
Make sure nothing is creating same object at the same time as animation is running, because you will be some random dissapearing effects&lt;br /&gt;
&lt;br /&gt;
===Rotating elements===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This example combines &amp;quot;Dojo.Animation&amp;quot; method and a CSS property transform that allow you to rotate the element.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// node is Element we rotating&lt;br /&gt;
		    var animation = new dojo.Animation({&lt;br /&gt;
			    curve: [fromDegree, toDegree],&lt;br /&gt;
			    onAnimate: (v) =&amp;gt; {&lt;br /&gt;
				    node.style.transform = &#039;rotate(&#039; + v + &#039;deg)&#039;;&lt;br /&gt;
			    } &lt;br /&gt;
		    });&lt;br /&gt;
		    &lt;br /&gt;
		    animation.play();  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BGA has its own interface to rotate&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;rotateTo(node: string | Element, degree: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It starts the animation, and stored the rotation degree in the class, so next time you rotate object - it is additive.&lt;br /&gt;
There is no animation hooks in this one, if you need to change any parameters use dojo animation above.&lt;br /&gt;
&lt;br /&gt;
There is also &#039;&#039;&#039;rotateInstantTo&#039;&#039;&#039; with same signature which does not animate&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Animation Callbacks===&lt;br /&gt;
&lt;br /&gt;
If you wish to run some code only after an animation has completed you can do this by linking a callback method to &#039;onEnd&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var animation_id = this.slideToObject( mobile_obj, target_obj, 500 );&lt;br /&gt;
dojo.connect(animation_id, &#039;onEnd&#039;, ()-&amp;gt;{&lt;br /&gt;
   // do something here&lt;br /&gt;
});&lt;br /&gt;
animation_id.play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you wish to call a second animation after the first (rather than general code) then you can use a dojo animation chain (see tutorial referenced above).&lt;br /&gt;
&lt;br /&gt;
== Players input ==&lt;br /&gt;
&lt;br /&gt;
=== Connecting ===&lt;br /&gt;
&#039;&#039;&#039;dojo.connect(element: ElementOrId, event: string, context: object, method: eventHandler): any&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
Example: associate a click on an element (&amp;quot;my_element&amp;quot;) with one of our methods (&amp;quot;onClickOnMyElement&amp;quot;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      dojo.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, this, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same idea but base on query (i.e. all element of &#039;pet&#039; class)&lt;br /&gt;
      dojo.query(&amp;quot;.pet&amp;quot;).connect(&#039;onclick&#039;, this, &#039;onPet&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: if you need to disconnect the handler you have to store handler returned from this method, i.e.&lt;br /&gt;
   &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var handler = dojo.connect(...);&lt;br /&gt;
    ...&lt;br /&gt;
    dojo.disconnect(handler);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t store the handler - you have to destroy the object to disconnect it&lt;br /&gt;
&lt;br /&gt;
Typical function that implements the input handler will look like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onPet: function(event) {&lt;br /&gt;
    var id = event.currentTarget.id;&lt;br /&gt;
    console.log(&#039;onPet &#039; + id);&lt;br /&gt;
    dojo.stopEvent(event);&lt;br /&gt;
    if (this.gamedatas.gamestate.name == &#039;playerTurnPet&#039;) {&lt;br /&gt;
          this.ajaxcallwrapper(&#039;playPet&#039;, {card: id});&lt;br /&gt;
    } else {&lt;br /&gt;
          this.showMoveUnauthorized();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;connect(element: ElementOrId, event: string, method: eventHandler): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&lt;br /&gt;
Or you can use an in-place handler&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, (e) =&amp;gt; { console.log(&#039;boo&#039;); } );&lt;br /&gt;
&lt;br /&gt;
Note that this function stores the connection handler. That is the only real difference between &#039;&#039;&#039;this.connect&#039;&#039;&#039; and &#039;&#039;&#039;dojo.connect&#039;&#039;&#039;. If you plan to destroy the element you connected, you &#039;&#039;&#039;must&#039;&#039;&#039; call this.disconnect() to prevent memory leaks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;connectClass(cssClassName: string, event: string, method: eventHandler): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as connect(), but for all the nodes set with the specified cssClassName.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	this.connectClass(&#039;pet&#039;, &#039;onclick&#039;, &#039;onPet&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;disconnect(element: ElementOrId, event: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disconnect event handler (previously registered with this.connect or this.connectClass).&lt;br /&gt;
&lt;br /&gt;
   this.disconnect( $(&#039;my_element&#039;), &#039;onclick&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: dynamic connect/disconnect is for advanced cases ONLY, you should always connect elements statically if possible, i.e. in setup() method.&lt;br /&gt;
&lt;br /&gt;
;disconnectAll() &lt;br /&gt;
&lt;br /&gt;
Disconnect all previously registed event handlers (registered via this.connect or this.connectClass)&lt;br /&gt;
&lt;br /&gt;
  this.disconnectAll();&lt;br /&gt;
&lt;br /&gt;
=== Actions ===&lt;br /&gt;
&#039;&#039;&#039;this.ajaxcall(url, parameters, obj_callback, callback, callback_anycase?, ajax_method?: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method must be used to send a player input to the game server. &#039;&#039;&#039;It should not be triggered programmatically&#039;&#039;&#039;, especially not in loops, in callbacks, in notifications, or in onEnteringState/onUpdateActionButtons/onLeavingState, in order not to create race conditions or break replay game and tutorial features. It should be used only in reaction to a user action in the interface.&lt;br /&gt;
&lt;br /&gt;
* url: the url of the action to perform. For a game, it must be: &amp;quot;/&amp;lt;mygame&amp;gt;/&amp;lt;mygame&amp;gt;/myAction.html&amp;quot;&lt;br /&gt;
* parameters: an array of parameter to send to the game server. &lt;br /&gt;
** Note that &amp;quot;lock: true&amp;quot; must always be specified in this list of parameters in order the interface can be locked during the server call. Cannot use lock: false - to not lock it has to be undefined.&lt;br /&gt;
** Note: Restricted parameter names (please don&#039;t use them):&lt;br /&gt;
*** &amp;quot;action&amp;quot;&lt;br /&gt;
*** &amp;quot;module&amp;quot;&lt;br /&gt;
*** &amp;quot;class&amp;quot;&lt;br /&gt;
* obj_callback: must be set to &amp;quot;this&amp;quot;.&lt;br /&gt;
* callback (non-optional but rarely used): a function to trigger when the server returns result and everything went fine (not used, as all data handling is done via notifications).&lt;br /&gt;
* callback_anycase: (optional) a function to trigger when the server returns ok OR error.  If no error this function is called with parameter value false.&lt;br /&gt;
* ajax_method: (optional and rarely used) if you need to send large amounts of data (over 2048 bytes), you can set this parameter to &#039;post&#039; (all lower-case) to send a POST request as opposed to the default GET. This works, but was not officially documented, so only use if you really need to.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.ajaxcall( &#039;/mygame/mygame/myaction.html&#039;, { lock: true, &lt;br /&gt;
   arg1: myarg1, &lt;br /&gt;
   arg2: myarg2&lt;br /&gt;
}, this, (result)=&amp;gt;{} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: to reduce the boilerplate code you can define your own wrapper, which will do checking, locking and allow to skip parameters, for example&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ajaxcallwrapper: function(action, args, handler) {&lt;br /&gt;
	if (!args) {&lt;br /&gt;
		args = {};&lt;br /&gt;
	}&lt;br /&gt;
	args.lock = true;&lt;br /&gt;
&lt;br /&gt;
	if (this.checkAction(action)) {&lt;br /&gt;
		this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + action + &amp;quot;.html&amp;quot;, args, this, (result) =&amp;gt; { }, handler);&lt;br /&gt;
	}&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be called like this which is a lot more compact&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playDraw&#039;);&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playMove&#039;, {card: id})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;checkAction(action: string, nomessage?: boolean): boolean &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* if interface is locked it will return false and show message &amp;quot;An action is already in progress&amp;quot;,  unless nomessage set to true &lt;br /&gt;
* if player is not active it will return false and show message &amp;quot;This is not your turn&amp;quot;, unless nomessage set to true &lt;br /&gt;
* if action is not in list in possible actions (defined by &amp;quot;possibleaction&amp;quot; in current game state) it will return false and show &amp;quot;This move is not authorized now&amp;quot; error (unconditionally).&lt;br /&gt;
* otherwise returns true&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  function onClickOnGameElement( evt )  {&lt;br /&gt;
     if( this.checkAction( &amp;quot;my_action&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;checkPossibleActions(action: string): boolean&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* this is independent of the player being active, so can be used instead of this.checkAction(). This is particularly useful for multiplayer states when the player is not active in a &#039;player may like to change their mind&#039; scenario. Unlike this.checkAction, this function does NOT take interface locking into account &lt;br /&gt;
&lt;br /&gt;
* if action is not in list in possible actions (defined by &amp;quot;possibleaction&amp;quot; in current game state) it will return false and show &amp;quot;This move is not authorized now&amp;quot; error (unconditionally).&lt;br /&gt;
* otherwise returns true&lt;br /&gt;
&lt;br /&gt;
  function onChangeMyMind( evt )  {&lt;br /&gt;
     if( this.checkPossibleActions( &amp;quot;my_action&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;checkLock(nomessage?: boolean): boolean&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When using &amp;quot;lock: true&amp;quot; in ajax call you can use this function to check if interface is in lock state (it will be locked during server call and notification processing).&lt;br /&gt;
This check can be used to block some other interactions which do not result in ajaxcall or if you want to suppress errors. Note: normally you only need to use this.checkAction(...), this is for advanced cases.&lt;br /&gt;
&lt;br /&gt;
It will also show error unless nomessage is set to true&lt;br /&gt;
&lt;br /&gt;
  function onChangeMyMind( evt )  {&lt;br /&gt;
     if( this.checkLock() ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Notifications ==&lt;br /&gt;
&lt;br /&gt;
When something happens on the server side, your game interface Javascript logic received a notification.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can handle these notifications on the client side.&lt;br /&gt;
&lt;br /&gt;
=== Subscribe to notifications ===&lt;br /&gt;
&lt;br /&gt;
Your Javascript &amp;quot;setupNotifications&amp;quot; method is the place where you can subscribe to notifications from your PHP code.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you associate one of your Javascript method to a notification &amp;quot;playDisc&amp;quot; (from Reversi example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // In setupNotifications method:&lt;br /&gt;
   dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the &amp;quot;playDisc&amp;quot; corresponds to the name of the notification you define it in your PHP code, in your &amp;quot;notifyAllPlayers&amp;quot; or &amp;quot;notifyPlayer&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Then, you have to define your &amp;quot;notif_playDisc&amp;quot; method:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        notif_playDisc: function( notif )&lt;br /&gt;
        {&lt;br /&gt;
            // Remove current possible moves (makes the board more clear)&lt;br /&gt;
            dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );        &lt;br /&gt;
        &lt;br /&gt;
            this.addDiscOnBoard( notif.args.x, notif.args.y, notif.args.player_id );&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a notification handler like our &amp;quot;notif_playDisc&amp;quot; method, you can access all notifications arguments with &amp;quot;notif.args&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
PHP&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    self::notifyAllPlayers( &amp;quot;myNotification&amp;quot;, &#039;&#039;, array( &amp;quot;myArgument&amp;quot; =&amp;gt; 3 ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
JavaScript&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    //You can access the &amp;quot;myArgument&amp;quot; like this:&lt;br /&gt;
    notif_myNotification: function( notif )&lt;br /&gt;
    {&lt;br /&gt;
       alert( &amp;quot;myArgument = &amp;quot; + notif.args.myArgument );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The notification Object received by client ===&lt;br /&gt;
&lt;br /&gt;
When sending a notification on your PHP, the client side will receive an Object with the following attributes:&lt;br /&gt;
&lt;br /&gt;
* type - type of the notification (as passed by php function)&lt;br /&gt;
* log - the log string passed from php notification&lt;br /&gt;
* args - This is the arguments that you passed on your notification method on php&lt;br /&gt;
* bIsTableMsg - is true when you use [[Main_game_logic:_yourgamename.game.php#NotifyAllPlayers|NotifyAllPlayers]] method (false otherwise)&lt;br /&gt;
* channelorig - information about table ID (formatted as : &amp;quot;/table/t[TABLE_NUMBER]&amp;quot;)&lt;br /&gt;
* gamenameorig - name of the game&lt;br /&gt;
* move_id - ID of the move associated with the notification&lt;br /&gt;
* table_id - ID of the table (comes as string)&lt;br /&gt;
* time - UNIX GMT timestamp&lt;br /&gt;
* uid - unique identifier of the notification&lt;br /&gt;
* h - unknown&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; Note that those information were inferred from observation on console log. If an Admin can confirm/correct (and remove this line), you&#039;re welcome :)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ignoring notifications ===&lt;br /&gt;
Sometimes you need to ignore some notification on client side. You don&#039;t want them to be shown in game log and you don&#039;t want them to be handled.&lt;br /&gt;
&lt;br /&gt;
The most common use case is when a player gets private information. They will receive a specific notification (such as &amp;quot;You received Ace of Heart&amp;quot;), while other players would receive more generic notification (&amp;quot;Player received a card&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
In X.game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $this-&amp;gt;notifyAllPlayers(&amp;quot;dealCard&amp;quot;, clienttranslate(&#039;${player_name} received a card&#039;), [&lt;br /&gt;
            &#039;player_id&#039; =&amp;gt; $playerId,&lt;br /&gt;
            &#039;player_name&#039; =&amp;gt; $this-&amp;gt;getActivePlayerName()&lt;br /&gt;
        ]);&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;notifyPlayer($playerId, &amp;quot;dealCardPrivate&amp;quot;, clienttranslate(&#039;You received ${cardName}&#039;), [&lt;br /&gt;
            &amp;quot;type&amp;quot; =&amp;gt; $card[&amp;quot;type&amp;quot;],&lt;br /&gt;
            &amp;quot;cardName&amp;quot; =&amp;gt; $this-&amp;gt;getCardName($card[&amp;quot;type&amp;quot;])&lt;br /&gt;
        ]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The problem with this approach is that the active player will receive two notifications:&lt;br /&gt;
* Player1 received a card&lt;br /&gt;
* You received Ace of Hearts&lt;br /&gt;
&lt;br /&gt;
Hence, notification ignoring.&lt;br /&gt;
&lt;br /&gt;
NOTE: You can think that it would be possible to send such notification to all players except active just by using notifyPlayer and it seems to work. The problem however is that table spectators would miss such notification and their user interface (and game log) wouldn&#039;t be updated. Since there is no way to send notification just to spectators, ignoring the notification (or &amp;quot;filtering&amp;quot;) is the only reasonable solution.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setIgnoreNotificationCheck(notif_type: string, predicate: ((notif: Notif)=&amp;gt;boolean))&#039;&#039;&#039;&lt;br /&gt;
This method will set a check whether any of notifications of specific type should be ignored.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* notif_type: type of the notification &lt;br /&gt;
* predicate (notif =&amp;gt; boolean): a function that will receive notif object and will return true if this specific notification should be ignored&lt;br /&gt;
&lt;br /&gt;
Before dispatching any notification of this type, the framework will call predicate to check whether notification should be ignored, if it return true - the notification will be dispatched, i.e. logged or handled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.notifqueue.setIgnoreNotificationCheck( &#039;dealCard&#039;, (notif) =&amp;gt; (notif.args.player_id == this.player_id) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: Remember that this notification is ignored on the client side, but was still received by the client. Therefore it shouldn&#039;t contain any private information as cheaters can get it. In other words this is not a way to hide information.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: When a game is reloaded with F5 or when opening a turn based game, old notifications are replayed as history notification. They are used just to update the game log and are stripped of all arguments except player_id, i18n and any argument present in message. If you use and other argument in your predicate you should &#039;&#039;&#039;preserve&#039;&#039;&#039; it as explained [[Main_game_logic:_yourgamename.game.php#Notify_players|here]].&lt;br /&gt;
&lt;br /&gt;
=== Synchronous notifications ===&lt;br /&gt;
&lt;br /&gt;
When several notifications are received by your game interface, these notifications are processed immediately, one after the other, in the same exact order they have been generated in your PHP game logic.&lt;br /&gt;
&lt;br /&gt;
However, sometimes, you need to give some time to the players to figure out what happened on the game before jumping to the next notification. Indeed, in many games, there are a lot of automatic actions, and the computer is going to resolve all these actions very fast if you don&#039;t tell it not to do so.&lt;br /&gt;
&lt;br /&gt;
As an example, for Reversi, when someone is playing a disc, we want to wait 500 milliseconds before doing anything else in order the opponent player can figure out what move has been played.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we do this, right after our subscription:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;playDisc&#039;, 500 );   // Wait 500 milliseconds after executing the playDisc handler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
It is also possible to control the delay timing dynamically (e.g., using notification args). As an example, maybe your notification &#039;cardPlayed&#039; should pause for a different amount of time depending on the number or type of cards played.&lt;br /&gt;
&lt;br /&gt;
For this case, use &#039;&#039;&#039;setSynchronous&#039;&#039;&#039; without specifying the duration and use &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039; within the notification callback.&lt;br /&gt;
&lt;br /&gt;
* NOTE: If you forget to invoke &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039;, the game will remain paused forever!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupNotifications: function () {&lt;br /&gt;
    dojo.subscribe( &#039;cardPlayed&#039;, this, &#039;notif_cardPlayed&#039; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;cardPlayed&#039; ); // wait time is dynamic&lt;br /&gt;
    ...&lt;br /&gt;
},&lt;br /&gt;
&lt;br /&gt;
notif_cardPlayed: function (notif) {&lt;br /&gt;
    // MUST call setSynchronousDuration&lt;br /&gt;
&lt;br /&gt;
    // Example 1: From notification args (PHP)&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(notif.args.duration);&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Or, example 2: Match the duration to a Dojo animation&lt;br /&gt;
    var anim = dojo.fx.combine([&lt;br /&gt;
        ...&lt;br /&gt;
    ]);&lt;br /&gt;
    anim.play();&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(anim.duration);&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING: combining synchronous and ignored notifications&#039;&#039;&#039;&lt;br /&gt;
You must be careful when combining dynamic synchronous durations (as described above) with ignored notifications. If you have a conditionally ignored notification like this (see below section):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.notifqueue.setIgnoreNotificationCheck( &#039;myNotif&#039;, (notif) =&amp;gt; (notif.args.player_id == this.player_id) /* or any other condition */ )&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then you CANNOT do&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.notifqueue.setSynchronous(&#039;myNotif&#039;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as, when the ignored check passes, the notification handler, in which `this.notifqueue.setSychronousDuration` is called, is never called and so the duration is never set and interface locking results.&lt;br /&gt;
&lt;br /&gt;
The workaround is to set a &amp;quot;dummy&amp;quot; time:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.notifqueue.setSynchronous(&#039;myNotif&#039;, 5000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whose value is irrelevant but must be large enough to cover the time before the notification handler is called. The large value never actually comes into play because the notification is either ignored, or the synchronous duration is reset to a sensible value inside the handler.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Pre-defined notification types ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tableWindow&#039;&#039;&#039; - This defines notification to display [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialogs]], see below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;message&#039;&#039;&#039; - This defines notification that shows on players log and have no other effect (technically any unhandled notification will do the same but its recommended to use this keyword for consistency)&lt;br /&gt;
&lt;br /&gt;
   // You can call this on php side without doing anything on client side&lt;br /&gt;
    self::notifyAllPlayers( &#039;message&#039;, clienttranslate(&#039;hello&#039;), [] );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;simplePause&#039;&#039;&#039; - This notification will just delay other notifications, maybe useful if you know you need some extra time for animation or something. Requires a time parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    self::notifyAllPlayers( &#039;simplePause&#039;, &#039;&#039;, [ &#039;time&#039; =&amp;gt; 500] ); // time is in milliseconds&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the following types are RESERVED by framework, do not use:&lt;br /&gt;
&lt;br /&gt;
gameStateChange gameStateChangePrivateArg gameStateMultipleActiveUpdate newActivePlayer playerstatus yourturnack clockalert tableInfosChanged playerEliminated tableDecision  archivewaitingdelay end_archivewaitingdelay replaywaitingdelay end_replaywaitingdelay replayinitialwaitingdelay end_replayinitialwaitingdelay aiPlayerWaitingDelay replay_has_ended updateSpectatorList  wouldlikethink updateReflexionTime undoRestorePoint resetInterfaceWithAllDatas zombieModeFail zombieModeFailWarning aiError skipTurnOfPlayer zombieBack allPlayersAreZombie gameResultNeutralized playerConcedeGame showTutorial showCursor showCursorClick skipTurnOfPlayerWarning  banFromTable resultsAvailable switchToTurnbased newPrivateState infomsg&lt;br /&gt;
&lt;br /&gt;
== Tooltips ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltip( nodeId, helpStringTranslated, actionStringTranslated, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to the DOM node.&lt;br /&gt;
&lt;br /&gt;
Specify &#039;helpStringTranslated&#039; to display some information about &amp;quot;what is this game element?&amp;quot;.&lt;br /&gt;
Specify &#039;actionStringTranslated&#039; to display some information about &amp;quot;what happens when I click on this element?&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You must specify both of the strings. You can only use one and specify an empty string (&#039;&#039;) for the other one.&lt;br /&gt;
&lt;br /&gt;
When you pass text directly function _() must be used for the text to be marked for translation! Except for empty string.&lt;br /&gt;
&lt;br /&gt;
Parameter &amp;quot;delay&amp;quot; is optional. It is primarily used to specify a zero delay for some game element when the tooltip gives really important information for the game - but remember: no essential information must be placed in tooltips as they won&#039;t be displayed in some browsers (see [[BGA_Studio_Guidelines|Guidelines]]).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.addTooltip( &#039;cardcount&#039;, _(&#039;Number of cards in hand&#039;), &#039;&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this generates static tooltip and attaches to existing dom element, if you need to generate tooltip more dynamically you have to call that method every time information about object is updated or use completely different tehnique&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipHtml( nodeId, html, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to the DOM node (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipToClass( cssClass, helpStringTranslated, actionStringTranslated, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to all the DOM nodes set with this cssClass. See more details above for this.addTooltip.&lt;br /&gt;
     this.addTooltipToClass( &#039;meeple&#039;, _(&#039;This is A Meeple&#039;), _(&#039;Click to tickle&#039;) );&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must exist and have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipHtmlToClass( cssClass, html, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to to all the DOM nodes set with this cssClass (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must exist and have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.removeTooltip( nodeId )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove a tooltip from the DOM node with given id.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;force tooltip to open&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you want to force tooltip to open in reaction to some other action, i.e. click you can do this&lt;br /&gt;
&lt;br /&gt;
   this.tooltips[id].open(id)&lt;br /&gt;
&lt;br /&gt;
where id is the id of the tooltip node where tooltip was installed.&lt;br /&gt;
&lt;br /&gt;
== Dialogs, warning messages, confirmation dialogs, ... ==&lt;br /&gt;
&lt;br /&gt;
=== Warning messages ===&lt;br /&gt;
&lt;br /&gt;
Sometimes, there is something important that is happening in the game and you have to make sure all players get the message. Most of the time, the evolution of the game situation or the game log is enough, but sometimes you need something more visible.&lt;br /&gt;
&lt;br /&gt;
Ex: someone fulfills one of the end of the game conditions, so this is the last turn.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.showMessage(msg: string, type: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
showMessage shows a message in a big rectangular area on the top of the screen of the current player.&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;msg&amp;quot; is the string to display. It should be translated.&lt;br /&gt;
* &amp;quot;type&amp;quot; can be set to &amp;quot;info&amp;quot;, &amp;quot;error&amp;quot;, &amp;quot;only_to_log&amp;quot; or custom string. If set to &amp;quot;info&amp;quot;, the message will be an informative message on a white background. If set to &amp;quot;error&amp;quot;, the message will be an error message on a red background and it will be added to log. If set to &amp;quot;only_to_log&amp;quot;, the message will be added to the game log but will not popup at the top of the screen.&lt;br /&gt;
If set to custom string, it will be transparent, to use other stype define &amp;quot;head_xxx&amp;quot; in css, where xxx is the type. For example if you want yellow warning, use &amp;quot;warning&amp;quot; as type and add this to css:&lt;br /&gt;
 .head_warning {&lt;br /&gt;
    background-color: #e6c66e;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Important: the normal way to inform players about the progression of the game is the game log. &amp;quot;showMessage&amp;quot; is intrusive and should not be used often.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
			notif_messageinfo: function(notif) {&lt;br /&gt;
				if (!g_archive_mode) {&lt;br /&gt;
					var message = this.format_string_recursive(notif.log, notif.args);&lt;br /&gt;
					this.showMessage(_(&#039;Announcement:&#039;) + &amp;quot; &amp;quot; + message, &#039;info&#039;);&lt;br /&gt;
				}&lt;br /&gt;
			},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Show message could be used on the client side to prevent user wrong moves before it is send to server.&lt;br /&gt;
Example from &#039;battleship&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onGrid(event) {&lt;br /&gt;
                if (checkIfPlayerTriesToFireOnThemselves) {&lt;br /&gt;
                    this.showMessage(_(&#039;This is your own board silly!&#039;), &#039;error&#039;);&lt;br /&gt;
                    return;&lt;br /&gt;
                }&lt;br /&gt;
                ...&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;showMoveUnauthorized()&lt;br /&gt;
&lt;br /&gt;
Shows predefined user error that move is unauthorized now&lt;br /&gt;
&lt;br /&gt;
=== Confirmation dialog ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;confirmationDialog( message, yesHandler, noHandler )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When an important action with a lot of consequences is triggered by the player, you may want to propose a confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the general guideline of BGA is to AVOID the use of confirmation dialogs. Confirmation dialogs slow down the game and bother players. The players know that they have to pay attention to each move when they are playing online.&lt;br /&gt;
&lt;br /&gt;
The situations where you should use a confirmation dialog are the following:&lt;br /&gt;
* It must not happen very often during a game.&lt;br /&gt;
* It must be linked to an action that can really &amp;quot;kill a game&amp;quot; if the player does not pay attention.&lt;br /&gt;
* It must be something that can be done by mistake (ex: a link on the action status bar).&lt;br /&gt;
&lt;br /&gt;
How to display a confirmation dialog:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog(_(&#039;Are you sure you want to bake the pie?&#039;), () =&amp;gt; {&lt;br /&gt;
            this.bakeThePie();&lt;br /&gt;
        }); &lt;br /&gt;
        return; // nothing should be called or done after calling this, all action must be done in the handler  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Multiple choice dialog ===&lt;br /&gt;
You can use this dialog to give user a choice with small amount of options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        var keys = [1,5,10];&lt;br /&gt;
        this.multipleChoiceDialog(&lt;br /&gt;
          _(&#039;How many bugs to fix?&#039;), keys, &lt;br /&gt;
            (choice) =&amp;gt; {&lt;br /&gt;
                            var bugchoice = keys[choice];&lt;br /&gt;
                            console.log(&#039;dialog callback with &#039;+bugchoice);&lt;br /&gt;
                            this.ajaxcall( &#039;/mygame/mygame/fixBugs.html&#039;, { bugs: bugchoice}, this, function( result ) {} );&lt;br /&gt;
                        }&lt;br /&gt;
        );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dialogs ===&lt;br /&gt;
&lt;br /&gt;
As a general rule, you shouldn&#039;t use dialogs windows.&lt;br /&gt;
&lt;br /&gt;
BGA guidelines specify that all game elements should be displayed on the main screen. Players can eventually scroll down to see game elements they don&#039;t need to see anytime, and you may eventually create anchors to move between game area section. Of course dialogs windows are very practical, but the thing is: all players know how to scroll down, and not all players know how to show up your dialog window. In addition, when the dialog shows up, players can&#039;t access the other game components.&lt;br /&gt;
&lt;br /&gt;
Sometimes although, you need to display a dialog window. Here is how you do this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  // Create the new dialog over the play zone. You should store the handler in a member variable to access it later&lt;br /&gt;
  this.myDlg = new ebg.popindialog();&lt;br /&gt;
  this.myDlg.create( &#039;myDialogUniqueId&#039; );&lt;br /&gt;
  this.myDlg.setTitle( _(&amp;quot;my dialog title to translate&amp;quot;) );&lt;br /&gt;
  this.myDlg.setMaxWidth( 500 ); // Optional&lt;br /&gt;
  &lt;br /&gt;
  // Create the HTML of my dialog. &lt;br /&gt;
  // The best practice here is to use [[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&lt;br /&gt;
  var html = this.format_block( &#039;jstpl_myDialogTemplate&#039;, { &lt;br /&gt;
                arg1: myArg1,&lt;br /&gt;
                arg2: myArg2,&lt;br /&gt;
                ...&lt;br /&gt;
            } );  &lt;br /&gt;
  &lt;br /&gt;
  // Show the dialog&lt;br /&gt;
  this.myDlg.setContent( html ); // Must be set before calling show() so that the size of the content is defined before positioning the dialog&lt;br /&gt;
  this.myDlg.show();&lt;br /&gt;
  &lt;br /&gt;
  // Now that the dialog has been displayed, you can connect your method to some dialog elements&lt;br /&gt;
  // Example, if you have an &amp;quot;OK&amp;quot; button in the HTML of your dialog:&lt;br /&gt;
  dojo.connect( $(&#039;my_ok_button&#039;), &#039;onclick&#039;, this, function(evt){&lt;br /&gt;
                evt.preventDefault();&lt;br /&gt;
                this.myDlg.destroy();&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
If necessary, you can remove the default top right corner &#039;close&#039; icon, or replace the function called when it is clicked:&lt;br /&gt;
  // Removes the default close icon&lt;br /&gt;
  this.myDlg.hideCloseIcon();&lt;br /&gt;
&lt;br /&gt;
  // Replace the function call when it&#039;s clicked&lt;br /&gt;
  this.myDlg.replaceCloseCallback( function() { ... } );&lt;br /&gt;
&lt;br /&gt;
=== Scoring dialogs ===&lt;br /&gt;
&lt;br /&gt;
Sometimes at the end of a round you want to display a big table that details the points wins in each section of the game.&lt;br /&gt;
&lt;br /&gt;
Example: in Hearts game, we display at the end of each round the number of &amp;quot;heart&amp;quot; cards collected by each player, the player who collected the Queen of Spades, and the total number of points loose by each player.&lt;br /&gt;
&lt;br /&gt;
Scoring dialogs are managed entirely on &#039;&#039;&#039;PHP side&#039;&#039;&#039;, but they are described here as their effects are visible only on client side.&lt;br /&gt;
&lt;br /&gt;
Displaying a scoring dialog is quite simple and is using a special notification type: &amp;quot;tableWindow&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // on PHP side:&lt;br /&gt;
  $this-&amp;gt;notifyAllPlayers( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table&lt;br /&gt;
        ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;table&amp;quot; argument is a 2 dimensional PHP array that describe the table you want to display, line by line and column by column.&lt;br /&gt;
&lt;br /&gt;
Example: display an 3x3 array of strings&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = array(&lt;br /&gt;
      array( &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, &amp;quot;three&amp;quot; ),    // This is my first line&lt;br /&gt;
      array( &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ),    // This is my second line&lt;br /&gt;
      array( &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; )    // This is my third line&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see above, in each &amp;quot;cell&amp;quot; of your array you can display a simple string value. But you can also display a complex value with a template and associated arguments like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = array(&lt;br /&gt;
      array( &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, array( &amp;quot;str&amp;quot; =&amp;gt; clienttranslate(&amp;quot;a string with an ${argument}&amp;quot;), &amp;quot;args&amp;quot; =&amp;gt; array( &#039;argument&#039; =&amp;gt; &#039;argument_value&#039; )  ) ),&lt;br /&gt;
      array( &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ), &lt;br /&gt;
      array( &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; )&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is especially useful when you want to display player names with colors. Example from &amp;quot;Hearts&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $firstRow = array( &#039;&#039; );&lt;br /&gt;
        foreach( $players as $player_id =&amp;gt; $player )&lt;br /&gt;
        {&lt;br /&gt;
            $firstRow[] = array( &#039;str&#039; =&amp;gt; &#039;${player_name}&#039;,&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; array( &#039;player_name&#039; =&amp;gt; $player[&#039;player_name&#039;] ),&lt;br /&gt;
                                 &#039;type&#039; =&amp;gt; &#039;header&#039;&lt;br /&gt;
                               );&lt;br /&gt;
        }&lt;br /&gt;
        $table[] = $firstRow;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use three extra attributes in the parameter array for the notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $this-&amp;gt;notifyAllPlayers( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table,&lt;br /&gt;
            &amp;quot;header&amp;quot; =&amp;gt; array(&#039;str&#039; =&amp;gt; clienttranslate(&#039;Table header with parameter ${number}&#039;),&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; array( &#039;number&#039; =&amp;gt; 3 ),&lt;br /&gt;
                               ),&lt;br /&gt;
            &amp;quot;footer&amp;quot; =&amp;gt; &#039;&amp;lt;div&amp;gt;Some footer&amp;lt;/div&amp;gt;&#039;,&lt;br /&gt;
            &amp;quot;closing&amp;quot; =&amp;gt; clienttranslate( &amp;quot;Closing button label&amp;quot; )&lt;br /&gt;
        ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;header&#039;&#039;&#039;: the content for this parameter will display before the table (also, the html will be parsed and player names will be colored according to the current game colors). &lt;br /&gt;
*&#039;&#039;&#039;footer&#039;&#039;&#039;: the content for this parameter will display after the table (no parsing for coloring the player names)&lt;br /&gt;
*&#039;&#039;&#039;closing&#039;&#039;&#039;: if this parameter is used, a button will be displayed with this label at the bottom of the popup and will allow players to close it (more easily than by clicking the top right &#039;cross&#039; icon).&lt;br /&gt;
&lt;br /&gt;
=== Scoring animated display ===&lt;br /&gt;
&lt;br /&gt;
Sometimes (Terra Mystica final scoring for example), you may want to display a score value over an element to make the scoring easier to follow for the players.&lt;br /&gt;
You can do it with:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;displayScoring( anchor_id:string, color:string, score:number|string, duration?:number, offset_x?:number, offset_y?: number ):void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;anchor_id&#039;&#039;&#039;: ID of the element to place the animated score onto (without the &#039;#&#039;) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;color&#039;&#039;&#039;: hexadecimal RGB representation of the color (should be the color of the scoring player), but without a leading &#039;#&#039;.  For instance, &#039;ff0000&#039; for red.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;score&#039;&#039;&#039;: numeric score to display, prefixed by a &#039;+&#039; or &#039;-&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;duration&#039;&#039;&#039;: animation duration in milliseconds (optional, default is 1000)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;offset_x&#039;&#039;&#039; and &#039;&#039;&#039;offset_y&#039;&#039;&#039;: if both offset_x and offset_y are defined and not null, apply the following offset (in pixels) to the scoring animation. Note that the score is centered in the anchor, so the offsets might have to be negative if you calculate the position.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: if you want to display successively each score, you can use &#039;&#039;this.notifqueue.setSynchronous()&#039;&#039; function.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setupNotifications: function()   {&lt;br /&gt;
           dojo.subscribe( &#039;displayScoring&#039;, this, &amp;quot;notif_displayScoring&amp;quot; );&lt;br /&gt;
           ...&lt;br /&gt;
    }&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
    notif_displayScoring: function(notif) {&lt;br /&gt;
            const duration = notif.args.duration?notif.args.duration:1000;&lt;br /&gt;
            this.notifqueue.setSynchronous(&#039;displayScoring&#039;, duration );&lt;br /&gt;
			this.displayScoring( notif.args.target, notif.args.color, notif.args.score, duration);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Speech bubble ===&lt;br /&gt;
&lt;br /&gt;
For better interactivity in some games (Love Letter for example), you may use comic book style speech bubbles to express the players voices.&lt;br /&gt;
This is done with showBubble:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;showBubble(anchor_id: string, text: string, delay?: number, duration?: number, custom_class?: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
anchor_id - where to attach the bubble&lt;br /&gt;
&lt;br /&gt;
text - what to put in bubble, can be html actually not just text&lt;br /&gt;
&lt;br /&gt;
delay - in milliseconds is optional (default 0)&lt;br /&gt;
&lt;br /&gt;
duration -  in milliseconds is optional (default 3000)&lt;br /&gt;
&lt;br /&gt;
custom_class - extra class to add to bubble is optional, if you need to override the default bubble style&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.showBubble(&#039;meeple_2&#039;, _(&#039;Hello&#039;), 0, 1000, &#039;pink_bubble&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  notif_speechBubble(notif) {&lt;br /&gt;
    var html = this.format_string_recursive(notif.args.text, notif.args.args);&lt;br /&gt;
    this.showBubble(notif.args.target, html, notif.args.delay, notif.args.duration);&lt;br /&gt;
  },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: if your bubble could overlap other active elements of the interface (buttons in particular), as it stays in place even after disappearing, you should use a custom class to give it the style &amp;quot;pointer-events: none;&amp;quot; in order to intercept click events.&lt;br /&gt;
&lt;br /&gt;
Note: If you want this visually, but want to take complete control over this bubble and its animation (for example to make it permanent) you can just use div with &#039;discussion_bubble&#039; class on it, and content of div is what will be shown.&lt;br /&gt;
&lt;br /&gt;
== Translations ==&lt;br /&gt;
&lt;br /&gt;
See [[Translations]]&lt;br /&gt;
&lt;br /&gt;
== Players panels ==&lt;br /&gt;
&lt;br /&gt;
=== Update players score ===&lt;br /&gt;
&lt;br /&gt;
The column player_score from the player table is automatically loaded into this.scoreCtrl and therefore into the stars location on the player board. This occurs sometime after the game setup() function. However this score must be updated as the game progresses using notifications.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: this.scoreCtrl[player_id] is object of class [[Counter]], you can use other counter API.&lt;br /&gt;
&lt;br /&gt;
Increase a player score (with a positive or negative number):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].incValue( score_delta );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set a player score to a specific value:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].setValue( new_score );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set a player score to a specific value with animation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].toValue( new_score );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typical usage would be (that will process &#039;score&#039; notification):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setupNotifications : function() {&lt;br /&gt;
              ...&lt;br /&gt;
             dojo.subscribe(&#039;score&#039;, this, &amp;quot;notif_score&amp;quot;);&lt;br /&gt;
        },&lt;br /&gt;
        notif_score: function(notif) {&lt;br /&gt;
            this.scoreCtrl[notif.args.player_id].setValue(notif.args.player_score);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Adding stuff to player&#039;s panel ===&lt;br /&gt;
&lt;br /&gt;
At first, create a new &amp;quot;JS template&amp;quot; string in your template (tpl) file:&lt;br /&gt;
&lt;br /&gt;
(from Gomoku example)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var jstpl_player_board = &#039;\&amp;lt;div class=&amp;quot;cp_board&amp;quot;&amp;gt;\&lt;br /&gt;
    &amp;lt;div id=&amp;quot;stoneicon_p${id}&amp;quot; class=&amp;quot;gmk_stoneicon gmk_stoneicon_${color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;span id=&amp;quot;stonecount_p${id}&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;\&lt;br /&gt;
&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, you add this piece of code in your JS file to add this template to each player panel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Setting up player boards&lt;br /&gt;
            for( var player_id in gamedatas.players )&lt;br /&gt;
            {&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                         &lt;br /&gt;
                // Setting up players boards if needed&lt;br /&gt;
                var player_board_div = $(&#039;player_board_&#039;+player_id);&lt;br /&gt;
                dojo.place( this.format_block(&#039;jstpl_player_board&#039;, player ), player_board_div );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Note: the code above is of course from your &amp;quot;setup&amp;quot; function in your Javascript).&lt;br /&gt;
&lt;br /&gt;
Very often, you have to distinguish current player and others players. In this case, you just have to create another JS template (ex: jstpl_otherplayer_board) and use it when &amp;quot;player_id&amp;quot; is different than &amp;quot;this.player_id&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s panel disabling/enabling ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.disablePlayerPanel(player_id: number):void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disable given player panel (the panel background become gray).&lt;br /&gt;
&lt;br /&gt;
Usually, this is used to signal that this played passes, or will be inactive during a while.&lt;br /&gt;
&lt;br /&gt;
Note that the only effect of this is visual. There are no consequences on the behaviour of the panel itself.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.enablePlayerPanel(player_id:number):void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable a player panel that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.enableAllPlayerPanels():void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable all player panels that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
=== Counters ===&lt;br /&gt;
Note: there is bga component called  &amp;quot;ebg/counter&amp;quot; this API is not using it, these methods&lt;br /&gt;
below declared right in core game. If you need animation for counters use ebg/counter&lt;br /&gt;
&lt;br /&gt;
To use this API just create a counter dom element like this (class does not really matter)&lt;br /&gt;
 &amp;lt;div class=&amp;quot;counter&amp;quot; id=&amp;quot;bread&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
 &amp;lt;div class=&amp;quot;counter&amp;quot; id=&amp;quot;coin&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
The &amp;quot;bread&amp;quot; will the counter name.&lt;br /&gt;
&lt;br /&gt;
The php code should send all &amp;quot;counters&amp;quot; data from getAllDatas() method like this&lt;br /&gt;
&lt;br /&gt;
game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  protected function getAllDatas() {&lt;br /&gt;
    // (the key must match counter_name)&lt;br /&gt;
    $result[&#039;counters&#039;]=[&lt;br /&gt;
        &#039;bread&#039; =&amp;gt; [ &lt;br /&gt;
         &#039;counter_name&#039; =&amp;gt; &#039;bread&#039;, &lt;br /&gt;
         &#039;counter_value&#039; =&amp;gt; 3&lt;br /&gt;
         ], &lt;br /&gt;
        &#039;coin&#039; =&amp;gt; [&lt;br /&gt;
          &#039;counter_name&#039; =&amp;gt; &#039;coin&#039;, &lt;br /&gt;
          &#039;counter_value&#039; =&amp;gt; 5&lt;br /&gt;
        ]&lt;br /&gt;
   ];&lt;br /&gt;
   return $result;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setCounter(counter_name:stirng, new_value: string | number): void&lt;br /&gt;
updates the global this.gamedatas.counters and value of node $(counter_name)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  notif_counter: function(notif) { &lt;br /&gt;
    this.setCounter(notif.args.counter_name, notif.args.counter_value);&lt;br /&gt;
  },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;incCounter(counter_name:string, delta: number): void&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  notif_counter : function(notif) {&lt;br /&gt;
    this.incCounter(notif.args.counter_name, notif.args.inc);&lt;br /&gt;
  },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;updateCounters(counters: object): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Useful for updating game counters in the player panel (such as resources). &lt;br /&gt;
&#039;counters&#039; arg is map of counters (the key must match counter_name)&lt;br /&gt;
  {&lt;br /&gt;
    &#039;bread&#039;: { &lt;br /&gt;
         &#039;counter_name&#039; : &#039;bread&#039;, &lt;br /&gt;
         &#039;counter_value&#039; =&amp;gt; 3&lt;br /&gt;
    }, &lt;br /&gt;
    &#039;coin&#039;: { &lt;br /&gt;
         &#039;counter_name&#039; : &#039;coin&#039;, &lt;br /&gt;
         &#039;counter_value&#039; =&amp;gt; 5&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
All counters MUST be referenced in this.gamedatas.counters (means they should be send from php) and will be updated.&lt;br /&gt;
DOM objects referenced by &#039;counter_name&#039; will have their innerHTML updated with &#039;counter_value&#039;.&lt;br /&gt;
&lt;br /&gt;
Usually you call this from notification&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                        notif_counter : function(notif) {&lt;br /&gt;
                            this.updateCounters(notif.args.counters);&lt;br /&gt;
                        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== BGA GUI components ==&lt;br /&gt;
&lt;br /&gt;
BGA framework provides some useful ready-to-use components for the game interface:&lt;br /&gt;
&lt;br /&gt;
[[Studio#BGA_Studio_game_components_reference]]&lt;br /&gt;
&lt;br /&gt;
Note that each time you are using an additional component, you must declare it at the top of your Javascript file in the list of modules used.&lt;br /&gt;
&lt;br /&gt;
Example if you are using &amp;quot;ebg.stock&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;  /// &amp;lt;=== we are using ebg.stock module&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA Buttons ==&lt;br /&gt;
&lt;br /&gt;
=== Basic Button ===&lt;br /&gt;
&#039;&#039;&#039;addActionButton( id: string, label: string, method: string | eventhandler, destination?: string, blinking?: boolean, color?:string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use this method to add an action button in the main action status bar (or other places).&lt;br /&gt;
&lt;br /&gt;
Arguments:&lt;br /&gt;
* id: an element ID that should be unique in your HTML DOM document.&lt;br /&gt;
* label: the text of the button. Should be translatable (use _() function). Note: this can also be any html, such as &amp;quot;&amp;lt;div class=&#039;brick&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, see example below on how to make image action buttons.&lt;br /&gt;
* method: the name of your method that must be triggered when the player clicks on this button (can be name of the method on game class or handler).&lt;br /&gt;
* destination (optional): id of parent on where to add button, ONLY use in rare cases if location is not action bar. Use &#039;&#039;&#039;null&#039;&#039;&#039; as value if you need to specify other arguments.&lt;br /&gt;
* blinking (optional): if set to &#039;&#039;&#039;true&#039;&#039;&#039;, the button is going blink to catch player&#039;s attention. Please DO NOT abuse blinking button. If you need button to blink after some time passed add class &#039;blinking&#039; to the button later.&lt;br /&gt;
* color: could be &#039;&#039;&#039;blue&#039;&#039;&#039; (default), &#039;&#039;&#039;red&#039;&#039;&#039;,&#039;&#039;&#039;gray&#039;&#039;&#039; or &#039;&#039;&#039;none&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You should only use this method in your &amp;quot;onUpdateActionButtons&amp;quot; method. Usually, you use it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onUpdateActionButtons: function( stateName, args ) {                      &lt;br /&gt;
            if (this.isCurrentPlayerActive()) {            &lt;br /&gt;
                switch( stateName ) {&lt;br /&gt;
                case &#039;giveCards&#039;:&lt;br /&gt;
                    this.addActionButton( &#039;giveCards_button&#039;, _(&#039;Give selected cards&#039;), &#039;onGiveCards&#039; ); &lt;br /&gt;
                    this.addActionButton( &#039;pass_button&#039;, _(&#039;Pass&#039;), ()=&amp;gt;this.ajaxcallwrapper(&#039;pass&#039;) ); &lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are adding a &amp;quot;Give selected cards&amp;quot; button in the case we are on game state &amp;quot;giveCards&amp;quot;. When player clicks on this button, it triggers our &amp;quot;onGiveCards&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Example using blinking red button:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.addActionButton( &#039;button_confirm&#039;, _(&#039;Confirm?&#039;), &#039;onConfirm&#039;, null, true, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to call the handled with arguments, you can use arrow functions, like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     this.addActionButton( &#039;commit_button&#039;, _(&#039;Confirm&#039;), () =&amp;gt; this.onConfirm(this.selectedCardId), null, false, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Image Button ===&lt;br /&gt;
&lt;br /&gt;
You can use the same method, but add extra class to a button to disable the padding and style it, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.addActionButton( &#039;button_brick&#039;, &#039;&amp;lt;div class=&amp;quot;brick&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, ()=&amp;gt;{... on brick ...}, null, null, &#039;gray&#039;); &lt;br /&gt;
dojo.addClass(&#039;button_brick&#039;,&#039;bgaimagebutton&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.bgaimagebutton {&lt;br /&gt;
  padding: 0px 12px;&lt;br /&gt;
  min-height: 28px;&lt;br /&gt;
  border: none;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use this a lot, you can define a helper function, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This method can be used instead of addActionButton, to add a button which is an image (i.e. resource). Can be useful when player&lt;br /&gt;
 * need to make a choice of resources or tokens.&lt;br /&gt;
 */&lt;br /&gt;
addImageActionButton: function(id, div, handler, bcolor, tooltip) {&lt;br /&gt;
	if (typeof bcolor == &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
		bcolor = &amp;quot;gray&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
	// this will actually make a transparent button id color = gray&lt;br /&gt;
	this.addActionButton(id, div, handler, null, false, bcolor);&lt;br /&gt;
	// remove boarder, for images it better without&lt;br /&gt;
	dojo.style(id, &amp;quot;border&amp;quot;, &amp;quot;none&amp;quot;);&lt;br /&gt;
	// but add shadow style (box-shadow, see css)&lt;br /&gt;
	dojo.addClass(id, &amp;quot;shadow bgaimagebutton&amp;quot;);&lt;br /&gt;
	// you can also add additional styles, such as background&lt;br /&gt;
	if (tooltip) {&lt;br /&gt;
		dojo.attr(id, &amp;quot;title&amp;quot;, tooltip);&lt;br /&gt;
	}&lt;br /&gt;
	return $(id);&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Disabling Button ===&lt;br /&gt;
&lt;br /&gt;
You can disable the &#039;&#039;&#039;bgabutton&#039;&#039;&#039; by adding the css class &#039;&#039;&#039;disabled&#039;&#039;&#039; in you js. The disabled button is still visible but is grey and not clickable.&lt;br /&gt;
For example in the &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039; : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.addActionButton(&#039;play_button_id&#039;, _(&#039;Play 1 to 3 cards&#039;), &#039;playFunctionButton&#039;); &lt;br /&gt;
if (condition) {&lt;br /&gt;
  dojo.addClass(&#039;play_button_id&#039;, &#039;disabled&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Custom Buttons ===&lt;br /&gt;
&lt;br /&gt;
You can create a custom button, but the BGA framework provides a standard button that requires only .css classes: &#039;&#039;&#039;bgabutton&#039;&#039;&#039; and &#039;&#039;&#039;bgabutton_${color}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_blue&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My blue button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_red bgabutton_big&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My big red button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: To see it in action, check out &#039;&#039;Coloretto&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Button outside of action bar ===&lt;br /&gt;
&lt;br /&gt;
Use addActionButton() method with destination argument set&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.addActionButton( &#039;commit_button&#039;, _(&#039;Confirm&#039;), &#039;onConfirm&#039;, &#039;player_board&#039;, true, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Image loading ==&lt;br /&gt;
&lt;br /&gt;
See also [[Game_art:_img_directory]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Be careful&#039;&#039;&#039;: by default, ALL images of your img directory are loaded on a player&#039;s browser when he loads the game. For this reason, don&#039;t let in your img directory images that are not useful, otherwise it&#039;s going to slowdown the game load.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dontPreloadImage(image_file_name: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using dontPreloadImage, you tell the interface to not preload a specific image in your img directory.&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is particularly useful if for example you have 2 different themes for a game. To accelerate the loading of the game, you can specify to not preload images corresponding to the other theme.&lt;br /&gt;
&lt;br /&gt;
Another example of use: in &amp;quot;Gosu&amp;quot; game with Kamakor extension, you play with 5 sets of cards among 10 available. Cards images are organized by sets, and we only preload the images corresponding to the 5 current sets with &#039;&#039;&#039;ensureSpecificGameImageLoading( image_file_names_array )&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// By default, do not preload anything&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan1.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan2.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan3.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan4.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan5.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan6.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan7.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan8.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan9.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan10.png&#039; );&lt;br /&gt;
var to_preload = [];&lt;br /&gt;
for( i in this.gamedatas.clans )&lt;br /&gt;
{&lt;br /&gt;
	var clan_id = this.gamedatas.clans[i];&lt;br /&gt;
	to_preload.push( &#039;clan&#039;+clan_id+&#039;.png&#039; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this.ensureSpecificGameImageLoading( to_preload );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; You don&#039;t need to specify to not preload game box images (game_box.png, game_box75.png...) since they are not preloaded by default.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ensureSpecificGameImageLoading(list: string[])&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is oppostive of dontPreloadImage - its ensure specific images is loaded. Note: only makes sense if preload list is empty, otherwise everything is loaded anyway&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;load specific images&#039;&#039;&#039;&lt;br /&gt;
All images that will be preloaded stored in g_img_preload. If you want to override it directly - there is no API, but you can do this in GAME constructor&lt;br /&gt;
&lt;br /&gt;
          g_img_preload = [&#039;tokens.png&#039;, &#039;trains.png&#039;, &#039;loc_plan.png&#039;, &#039;eng.png&#039;, &#039;eng-back.png&#039;];&lt;br /&gt;
&lt;br /&gt;
You can also set it to empty array and call ensureSpecificGameImageLoading() on specific images&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sounds ==&lt;br /&gt;
&lt;br /&gt;
Add a custom sound and make it load with your interface:&lt;br /&gt;
&lt;br /&gt;
Add this in your template (.tpl) file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.mp3&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_o_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.ogg&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this is a requirement to provide both a mp3 and a ogg file with the names &amp;lt;code&amp;gt;&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;[.ogg][.mp3]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Play the sound (from your .js file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
playSound(&#039;&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&#039;);   // do not add &#039;this.&#039; - its a global function&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the standard &amp;quot;move&amp;quot; sound for this move (to replace it with your custom sound):&lt;br /&gt;
&lt;br /&gt;
Add this to your notification handler:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.disableNextMoveSound();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: it only disable the sound for the next move.&lt;br /&gt;
&lt;br /&gt;
== Title bar and states ==&lt;br /&gt;
&lt;br /&gt;
=== Client states ===&lt;br /&gt;
&lt;br /&gt;
Client states is a way to simulate the state transition but without actually going&lt;br /&gt;
to server. It is usefull when you need to ask user multiple questions before you&lt;br /&gt;
send things to server&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setClientState(newState: string, args: object)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
     this.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                               descriptionmyturn : _(&amp;quot;${you} must select location&amp;quot;),&lt;br /&gt;
                           });&lt;br /&gt;
&lt;br /&gt;
For more information see [[BGA_Studio_Cookbook#Multi_Step_Interactions:_Select_Worker.2FPlace_Worker_-_Using_Client_States]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;restoreServerGameState()&#039;&#039;&#039;&lt;br /&gt;
If you are in client state it will restore the current server state (cheap undo)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.on_client_state&#039;&#039;&#039;&lt;br /&gt;
Boolean indicating that we are in client state&lt;br /&gt;
&lt;br /&gt;
=== Title bar ===&lt;br /&gt;
If you simply want to show something in title bar you can do it directly &lt;br /&gt;
     $(&#039;pagemaintitletext&#039;).innerHTML = text;&lt;br /&gt;
&lt;br /&gt;
This however will not work with parameters and will not draw You in color,&lt;br /&gt;
if you want to do proper args rendering use method below&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;removeActionButtons()&#039;&#039;&#039;&lt;br /&gt;
Removes all buttons from title bar&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;updatePageTitle()&#039;&#039;&#039;&lt;br /&gt;
:This function allows to update the current page title and turn description according to the game state. If the current game state description this.gamedatas.gamestate.descriptionmyturn is modified before :calling the function allows to update the turn description without changing state.&lt;br /&gt;
&lt;br /&gt;
Note: this functional also will call onUpdateActionButtons, if you want different buttons, use method in example to replace them&lt;br /&gt;
&lt;br /&gt;
Example from Terra Mystica:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onClickFavorTile: function( evt ) {&lt;br /&gt;
    ...&lt;br /&gt;
    if ( ... ) {&lt;br /&gt;
        this.gamedatas.gamestate.descriptionmyturn = _(&#039;Special action: &#039;) + _(&#039;Advance 1 space	on a Cult track&#039;);&lt;br /&gt;
        this.updatePageTitle();&lt;br /&gt;
        this.removeActionButtons();&lt;br /&gt;
        this.addActionButton( ... );&lt;br /&gt;
         ...&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Other useful stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.hitch&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.hitch, you can create a callback function that will run with your game object context whatever happen.&lt;br /&gt;
&lt;br /&gt;
Typical example: display a BGA confirmation dialog with a callback function created with dojo.hitch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), dojo.hitch( this, function() {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, function( result ) {} );&lt;br /&gt;
        } ) );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, using dojo.hitch, we ensure that the &amp;quot;this&amp;quot; object will be set when the callback is called.&lt;br /&gt;
&lt;br /&gt;
NOTE: In modern JS there are lambdas that eliminate need for that, the example above will look like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), () =&amp;gt; {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, (result) =&amp;gt; {} );&lt;br /&gt;
        } );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;onScreenWidthChange()&#039;&#039;&#039;&lt;br /&gt;
:This function can be overridden in your game to manage some resizing on the client side when the browser window is resized. This function is also triggered at load time, so it can be used to adapt to the :viewport size at the start of the game too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; this.bRealtime&lt;br /&gt;
: Return true if the game is in realtime. Note that having a distinct behavior in realtime and turn-based should be exceptional.&lt;br /&gt;
&lt;br /&gt;
; g_replayFrom&lt;br /&gt;
: Global contains reply number in live game, it is set to undefined (i.e. not set) when it is not a reply mode, so consequentially the good check is &#039;&#039;&#039;typeof g_replayFrom != &#039;undefined&#039;&#039;&#039;&#039; which returns true if the game is in replay mode &amp;lt;i&amp;gt;during the game&amp;lt;/i&amp;gt; (the game is ongoing but the user clicked &amp;quot;reply from this move&amp;quot; in the log)&lt;br /&gt;
&lt;br /&gt;
; g_archive_mode&lt;br /&gt;
: Returns true if the game is in archive mode &amp;lt;i&amp;gt;after the game&amp;lt;/i&amp;gt; (the game has ended)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; this.instantaneousMode&lt;br /&gt;
: Returns true during replay/archive mode if animations should be skipped. Only needed if you are doing custom animations. (The BGA-provided animation functions like &amp;lt;i&amp;gt;this.slideToObject()&amp;lt;/i&amp;gt; automatically handle instantaneous mode.)&lt;br /&gt;
: Technically, when you click &amp;quot;replay from move #20&amp;quot;, the system replays the game from the very beginning with moves 0 - 19 happening in instantaneous mode and moves 20+ happening in normal mode.&lt;br /&gt;
&lt;br /&gt;
; g_tutorialwritten&lt;br /&gt;
: Returns an object like the below if the game is in tutorial mode, or undefined otherwise. Tutorial mode is a special case of archive mode where comments have been added to a previous game to teach new players the rules.&lt;br /&gt;
    {&lt;br /&gt;
        author: &amp;quot;91577332&amp;quot;,&lt;br /&gt;
        id: &amp;quot;576&amp;quot;,&lt;br /&gt;
        mode: &amp;quot;view&amp;quot;&lt;br /&gt;
        status: &amp;quot;alpha&amp;quot;&lt;br /&gt;
        version_override: null&lt;br /&gt;
        viewer_id: &amp;quot;84554161&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=14959</id>
		<title>BGA Code Sharing</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=14959"/>
		<updated>2022-10-05T01:53:06Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Projects hosted not in studio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is for listing of externally hosted bga projects, tools and resources, as well as internal project&lt;br /&gt;
intended for sharing&lt;br /&gt;
&lt;br /&gt;
== Community shared components, pens, etc ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DESCRIPTION&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Dice models and animation&lt;br /&gt;
|-&lt;br /&gt;
| Die: 4 sided &lt;br /&gt;
| https://codepen.io/mrkiffie/pen/doVZgW&lt;br /&gt;
| code pen&lt;br /&gt;
|-&lt;br /&gt;
| Die: 6 sided &lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Code can be found in project&lt;br /&gt;
|-&lt;br /&gt;
| Die: 12 sided (dodecahedron) &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/xxLLxOP&lt;br /&gt;
| Code pen&lt;br /&gt;
|- &lt;br /&gt;
| Die: 20 sided &lt;br /&gt;
| https://codepen.io/vicentemundim/details/cenIh&lt;br /&gt;
| Code pen&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Moving object using CSS animation (mostly)&lt;br /&gt;
|-&lt;br /&gt;
| Phantom object move on oversurface &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/gORvdJo&lt;br /&gt;
| This technique creates clone of the object it moves it on another surface. It works well when parents that css transform applies such as scale and rotate&lt;br /&gt;
|-&lt;br /&gt;
| Move object directly using positioning &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/dyzgKVX&lt;br /&gt;
| This technique is modification of BGA framework method to allow mobile object not to have absolute position before or after the move (and uses css animation not dojo). Methods slideToObjectRelative, attachToNewObjectNoDestroy&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Responsive layout for game boards&lt;br /&gt;
|-&lt;br /&gt;
|Flex Layout&lt;br /&gt;
|https://codepen.io/VictoriaLa/pen/XWjJJgG&lt;br /&gt;
|Example on how to create flexible layout just by using css&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Algorithms&lt;br /&gt;
|-&lt;br /&gt;
|Hex grid&lt;br /&gt;
|tapestry,Tumbleweed,gaia project,Gold West&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Shortest path on hex grid&lt;br /&gt;
|memoir 44&lt;br /&gt;
| Disjktra&lt;br /&gt;
|-&lt;br /&gt;
|Largest area on hex grid&lt;br /&gt;
|tapestry, ...&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Largest area on square grid&lt;br /&gt;
|king domino, ...&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tetris pieces&lt;br /&gt;
|patchwork, ...&lt;br /&gt;
|Matrix manupations to rotate, flip and fit tetris pieces&lt;br /&gt;
|-&lt;br /&gt;
|Line of sights on hex grid&lt;br /&gt;
|memoir 44&lt;br /&gt;
|Find intersecting hexes on a line between two cells&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects hosted not in studio ==&lt;br /&gt;
&lt;br /&gt;
See the table a link and nickname of the developer on bga (same as used for dev forum), and short description. See [[Tools_and_tips_of_BGA_Studio#Version_Control]] for some suggestions on how and where to publish your code externally. Also see the [https://github.com/topics/boardgamearena boardgamearena] tag on github.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important notice about artwork on BGA Open Source projects: original hi-resolution images from publishers must not be published on the repositories. In addition, it is better to specify that the images derivated from publishers artwork are copyrighted and cannot be licensed under a free license like Creative Commons.&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NON-GAME PROJECTS&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
! COMMENT&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
| Examples of various game components and PHP stubs of framework code to make IDE happy&lt;br /&gt;
|-&lt;br /&gt;
| Vanilla Typescipt template (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-dojoless&lt;br /&gt;
| Victoria_La&lt;br /&gt;
| Project template for typescript and using minimal dojo, good for vscode - type checking, auto-complete, navigation&lt;br /&gt;
|-&lt;br /&gt;
| BoardGameArena Workbench (not a game)&lt;br /&gt;
| https://github.com/danielholmes/bga-workbench&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
! GAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
! COMMENT&lt;br /&gt;
|-&lt;br /&gt;
| 99 (Trick-taking Card Game)&lt;br /&gt;
| https://github.com/ekelly/bga-ninetynine&lt;br /&gt;
| QuasarDukeDev&lt;br /&gt;
|-&lt;br /&gt;
| Assyria &lt;br /&gt;
| https://github.com/sebastien-prudhomme/bga-assyria&lt;br /&gt;
| daikinee &lt;br /&gt;
|-&lt;br /&gt;
| Aura&lt;br /&gt;
| https://github.com/micahstairs/bga-aura&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Bandido &lt;br /&gt;
| https://github.com/opheliehb/BandidoBGA&lt;br /&gt;
| ophelopede &amp;amp; Harkle &lt;br /&gt;
|-&lt;br /&gt;
| The Battle for Hill 218&lt;br /&gt;
| https://github.com/danielholmes/battle-for-hill-218&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
| Bonbons&lt;br /&gt;
| https://github.com/AntonioSoler/bga-bonbons&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Coinche&lt;br /&gt;
| https://github.com/drasill/bga-coinche&lt;br /&gt;
| Draasill&lt;br /&gt;
|-&lt;br /&gt;
| Coup: City State&lt;br /&gt;
| https://github.com/quietmint/bga-coupcitystate&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dungeon Roll&lt;br /&gt;
| https://github.com/MartinGoulet/bga-dungeonroll&lt;br /&gt;
| MGoulet&lt;br /&gt;
|-&lt;br /&gt;
| Egyptian Ratscrew&lt;br /&gt;
| https://github.com/0BuRner/bga-egyptianratscrew&lt;br /&gt;
| 0BuRner&lt;br /&gt;
|-&lt;br /&gt;
| Eruption&lt;br /&gt;
| https://github.com/AndyKerrison/bga-eruption&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| A Fistful Of Gold&lt;br /&gt;
| https://bitbucket.org/Joel_L/fistfulofgold&lt;br /&gt;
| Brainchild&lt;br /&gt;
|-&lt;br /&gt;
| Florenza: The Card Game&lt;br /&gt;
| https://github.com/alberto-bottarini/bga-florenza&lt;br /&gt;
| tarini &lt;br /&gt;
|-&lt;br /&gt;
| Hearts &#039;&#039;&#039;(Tutorial)&#039;&#039;&#039;&lt;br /&gt;
| https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Homesteaders&lt;br /&gt;
| https://github.com/npatron/bga-homesteaders&lt;br /&gt;
| TheBoot&lt;br /&gt;
|-&lt;br /&gt;
| Incan Gold&lt;br /&gt;
| https://github.com/AntonioSoler/bga-incangold&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Innovation&lt;br /&gt;
| https://github.com/micahstairs/bga-innovation&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Mapmaker: The Gerrymandering Game&lt;br /&gt;
| https://github.com/gzhang01/bga-mapmaker&lt;br /&gt;
| gkz&lt;br /&gt;
|-&lt;br /&gt;
| Marco Polo&lt;br /&gt;
| https://github.com/rcitaliano/MarcoPolo&lt;br /&gt;
| rcitaliano&lt;br /&gt;
|-&lt;br /&gt;
| Nile&lt;br /&gt;
| https://github.com/AndyKerrison/bga-nile&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| Noir: Killer vs Inspector&lt;br /&gt;
| https://bitbucket.org/chhuang76/bga_noirkvi&lt;br /&gt;
| ch huang&lt;br /&gt;
|-&lt;br /&gt;
| Penny Press&lt;br /&gt;
| https://github.com/AdamNovotny/bga-blooms&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| P.I.&lt;br /&gt;
| https://gitlab.com/fa81/bga-pi, https://github.com/hellp/bga-pi (mirror)&lt;br /&gt;
| Fabian Neumann (fa81)&lt;br /&gt;
|-&lt;br /&gt;
| Santorini&lt;br /&gt;
| https://github.com/AntonioSoler/bga-santorini&lt;br /&gt;
| Morgalad, quietmint, Tisaac&lt;br /&gt;
|-&lt;br /&gt;
| Tablut&lt;br /&gt;
| https://github.com/Lucas-C/tablut&lt;br /&gt;
| Lucas-C &amp;amp; ntaffore&lt;br /&gt;
|-&lt;br /&gt;
| Takara Island&lt;br /&gt;
| https://github.com/AntonioSoler/bga-takaraisland&lt;br /&gt;
| Morgalad&lt;br /&gt;
|-&lt;br /&gt;
| Taluva&lt;br /&gt;
| https://github.com/quietmint/bga-taluva&lt;br /&gt;
| Morgalad &amp;amp; quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Teotihuacan: City of Gods&lt;br /&gt;
| https://github.com/Trompetenhut/bga-teotihuacan&lt;br /&gt;
| Trompetenhut&lt;br /&gt;
|-&lt;br /&gt;
| Texas 42 (domino game, still under development)&lt;br /&gt;
| https://github.com/ishermandom/bga-42&lt;br /&gt;
| Stardust Spikes, Jason Turner-Maier, Ilya Sherman&lt;br /&gt;
|-&lt;br /&gt;
| Tic Tac Match&lt;br /&gt;
| https://github.com/leocaseiro/bga-tictacmatch&lt;br /&gt;
| Leo Caseiro&lt;br /&gt;
|-&lt;br /&gt;
| Uptown&lt;br /&gt;
| https://github.com/elliotkendall/bga-uptown&lt;br /&gt;
| SpottedShroom&lt;br /&gt;
|-&lt;br /&gt;
| Via Magica&lt;br /&gt;
| https://github.com/christopherburke/bga_viamagica&lt;br /&gt;
| CuriousTerran&lt;br /&gt;
|-&lt;br /&gt;
| Just Desserts&lt;br /&gt;
| https://github.com/mizutismask/bga-just-desserts&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| The King&#039;s Guild&lt;br /&gt;
| https://github.com/AdamNovotny/BGG-KingsGuild&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| Get the MacGuffin&lt;br /&gt;
| https://github.com/mizutismask/bga-get-the-MacGuffin&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| President&lt;br /&gt;
| https://github.com/quaresma95/president&lt;br /&gt;
| quaresma95&lt;br /&gt;
|-&lt;br /&gt;
| Hardback&lt;br /&gt;
| https://github.com/quietmint/bga-hardback&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dice Summoners&lt;br /&gt;
| https://github.com/eoincos/bga-dicesummoners&lt;br /&gt;
| eoincos&lt;br /&gt;
|-&lt;br /&gt;
| Trick of the Rails&lt;br /&gt;
| https://github.com/Fnordistan/trickoftherails&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
| The Lady and the Tiger (Doors)&lt;br /&gt;
| https://github.com/Fnordistan/ladyandthetiger&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
| For-Ex&lt;br /&gt;
| https://github.com/Fnordistan/forex&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
| In the Year of the Dragon (10th Anniversary Edition)&lt;br /&gt;
| https://github.com/Fnordistan/ityotd&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
| Perikles&lt;br /&gt;
| https://github.com/Fnordistan/perikles&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects on studio ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Any developer can add themselves to a project as read-only from https://studio.boardgamearena.com/#!projects page (almost any project).&lt;br /&gt;
The list below are no-games which do not have bgg id and not showing up there.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code&lt;br /&gt;
| https://studio.boardgamearena.com/gamepanel?game=sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Original BGA template&lt;br /&gt;
| https://studio.boardgamearena.com/gamepanel?game=template&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other useful resources ==&lt;br /&gt;
&lt;br /&gt;
Moved to [[Tools_and_tips_of_BGA_Studio]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=14958</id>
		<title>BGA Code Sharing</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=14958"/>
		<updated>2022-10-05T01:51:35Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Projects hosted not in studio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is for listing of externally hosted bga projects, tools and resources, as well as internal project&lt;br /&gt;
intended for sharing&lt;br /&gt;
&lt;br /&gt;
== Community shared components, pens, etc ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DESCRIPTION&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Dice models and animation&lt;br /&gt;
|-&lt;br /&gt;
| Die: 4 sided &lt;br /&gt;
| https://codepen.io/mrkiffie/pen/doVZgW&lt;br /&gt;
| code pen&lt;br /&gt;
|-&lt;br /&gt;
| Die: 6 sided &lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Code can be found in project&lt;br /&gt;
|-&lt;br /&gt;
| Die: 12 sided (dodecahedron) &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/xxLLxOP&lt;br /&gt;
| Code pen&lt;br /&gt;
|- &lt;br /&gt;
| Die: 20 sided &lt;br /&gt;
| https://codepen.io/vicentemundim/details/cenIh&lt;br /&gt;
| Code pen&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Moving object using CSS animation (mostly)&lt;br /&gt;
|-&lt;br /&gt;
| Phantom object move on oversurface &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/gORvdJo&lt;br /&gt;
| This technique creates clone of the object it moves it on another surface. It works well when parents that css transform applies such as scale and rotate&lt;br /&gt;
|-&lt;br /&gt;
| Move object directly using positioning &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/dyzgKVX&lt;br /&gt;
| This technique is modification of BGA framework method to allow mobile object not to have absolute position before or after the move (and uses css animation not dojo). Methods slideToObjectRelative, attachToNewObjectNoDestroy&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Responsive layout for game boards&lt;br /&gt;
|-&lt;br /&gt;
|Flex Layout&lt;br /&gt;
|https://codepen.io/VictoriaLa/pen/XWjJJgG&lt;br /&gt;
|Example on how to create flexible layout just by using css&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Algorithms&lt;br /&gt;
|-&lt;br /&gt;
|Hex grid&lt;br /&gt;
|tapestry,Tumbleweed,gaia project,Gold West&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Shortest path on hex grid&lt;br /&gt;
|memoir 44&lt;br /&gt;
| Disjktra&lt;br /&gt;
|-&lt;br /&gt;
|Largest area on hex grid&lt;br /&gt;
|tapestry, ...&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Largest area on square grid&lt;br /&gt;
|king domino, ...&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tetris pieces&lt;br /&gt;
|patchwork, ...&lt;br /&gt;
|Matrix manupations to rotate, flip and fit tetris pieces&lt;br /&gt;
|-&lt;br /&gt;
|Line of sights on hex grid&lt;br /&gt;
|memoir 44&lt;br /&gt;
|Find intersecting hexes on a line between two cells&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects hosted not in studio ==&lt;br /&gt;
&lt;br /&gt;
See the table a link and nickname of the developer on bga (same as used for dev forum), and short description. See [[Tools_and_tips_of_BGA_Studio#Version_Control]] for some suggestions on how and where to publish your code externally. Also see the [https://github.com/topics/boardgamearena boardgamearena] tag on github.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important notice about artwork on BGA Open Source projects: original hi-resolution images from publishers must not be published on the repositories. In addition, it is better to specify that the images derivated from publishers artwork are copyrighted and cannot be licensed under a free license like Creative Commons.&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NON-GAME PROJECTS&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
! COMMENT&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
| Examples of various game components and PHP stubs of framework code to make IDE happy&lt;br /&gt;
|-&lt;br /&gt;
| Vanilla Typescipt template (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-dojoless&lt;br /&gt;
| Victoria_La&lt;br /&gt;
| Project template for typescript and using minimal dojo, good for vscode - type checking, auto-complete, navigation&lt;br /&gt;
|-&lt;br /&gt;
| BoardGameArena Workbench (not a game)&lt;br /&gt;
| https://github.com/danielholmes/bga-workbench&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
! GAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
! COMMENT&lt;br /&gt;
|-&lt;br /&gt;
| 99 (Trick-taking Card Game)&lt;br /&gt;
| https://github.com/ekelly/bga-ninetynine&lt;br /&gt;
| QuasarDukeDev&lt;br /&gt;
|-&lt;br /&gt;
| Assyria &lt;br /&gt;
| https://github.com/sebastien-prudhomme/bga-assyria&lt;br /&gt;
| daikinee &lt;br /&gt;
|-&lt;br /&gt;
| Aura&lt;br /&gt;
| https://github.com/micahstairs/bga-aura&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Bandido &lt;br /&gt;
| https://github.com/opheliehb/BandidoBGA&lt;br /&gt;
| ophelopede &amp;amp; Harkle &lt;br /&gt;
|-&lt;br /&gt;
| The Battle for Hill 218&lt;br /&gt;
| https://github.com/danielholmes/battle-for-hill-218&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
| Bonbons&lt;br /&gt;
| https://github.com/AntonioSoler/bga-bonbons&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Coinche&lt;br /&gt;
| https://github.com/drasill/bga-coinche&lt;br /&gt;
| Draasill&lt;br /&gt;
|-&lt;br /&gt;
| Coup: City State&lt;br /&gt;
| https://github.com/quietmint/bga-coupcitystate&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dungeon Roll&lt;br /&gt;
| https://github.com/MartinGoulet/bga-dungeonroll&lt;br /&gt;
| MGoulet&lt;br /&gt;
|-&lt;br /&gt;
| Egyptian Ratscrew&lt;br /&gt;
| https://github.com/0BuRner/bga-egyptianratscrew&lt;br /&gt;
| 0BuRner&lt;br /&gt;
|-&lt;br /&gt;
| Eruption&lt;br /&gt;
| https://github.com/AndyKerrison/bga-eruption&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| A Fistful Of Gold&lt;br /&gt;
| https://bitbucket.org/Joel_L/fistfulofgold&lt;br /&gt;
| Brainchild&lt;br /&gt;
|-&lt;br /&gt;
| Florenza: The Card Game&lt;br /&gt;
| https://github.com/alberto-bottarini/bga-florenza&lt;br /&gt;
| tarini &lt;br /&gt;
|-&lt;br /&gt;
| Hearts &#039;&#039;&#039;(Tutorial)&#039;&#039;&#039;&lt;br /&gt;
| https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Homesteaders&lt;br /&gt;
| https://github.com/npatron/bga-homesteaders&lt;br /&gt;
| TheBoot&lt;br /&gt;
|-&lt;br /&gt;
| Incan Gold&lt;br /&gt;
| https://github.com/AntonioSoler/bga-incangold&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Innovation&lt;br /&gt;
| https://github.com/micahstairs/bga-innovation&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Mapmaker: The Gerrymandering Game&lt;br /&gt;
| https://github.com/gzhang01/bga-mapmaker&lt;br /&gt;
| gkz&lt;br /&gt;
|-&lt;br /&gt;
| Marco Polo&lt;br /&gt;
| https://github.com/rcitaliano/MarcoPolo&lt;br /&gt;
| rcitaliano&lt;br /&gt;
|-&lt;br /&gt;
| Nile&lt;br /&gt;
| https://github.com/AndyKerrison/bga-nile&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| Noir: Killer vs Inspector&lt;br /&gt;
| https://bitbucket.org/chhuang76/bga_noirkvi&lt;br /&gt;
| ch huang&lt;br /&gt;
|-&lt;br /&gt;
| Penny Press&lt;br /&gt;
| https://github.com/AdamNovotny/bga-blooms&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| P.I.&lt;br /&gt;
| https://gitlab.com/fa81/bga-pi, https://github.com/hellp/bga-pi (mirror)&lt;br /&gt;
| Fabian Neumann (fa81)&lt;br /&gt;
|-&lt;br /&gt;
| Santorini&lt;br /&gt;
| https://github.com/AntonioSoler/bga-santorini&lt;br /&gt;
| Morgalad, quietmint, Tisaac&lt;br /&gt;
|-&lt;br /&gt;
| Tablut&lt;br /&gt;
| https://github.com/Lucas-C/tablut&lt;br /&gt;
| Lucas-C &amp;amp; ntaffore&lt;br /&gt;
|-&lt;br /&gt;
| Takara Island&lt;br /&gt;
| https://github.com/AntonioSoler/bga-takaraisland&lt;br /&gt;
| Morgalad&lt;br /&gt;
|-&lt;br /&gt;
| Taluva&lt;br /&gt;
| https://github.com/quietmint/bga-taluva&lt;br /&gt;
| Morgalad &amp;amp; quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Teotihuacan: City of Gods&lt;br /&gt;
| https://github.com/Trompetenhut/bga-teotihuacan&lt;br /&gt;
| Trompetenhut&lt;br /&gt;
|-&lt;br /&gt;
| Texas 42 (domino game, still under development)&lt;br /&gt;
| https://github.com/ishermandom/bga-42&lt;br /&gt;
| Stardust Spikes, Jason Turner-Maier, Ilya Sherman&lt;br /&gt;
|-&lt;br /&gt;
| Tic Tac Match&lt;br /&gt;
| https://github.com/leocaseiro/bga-tictacmatch&lt;br /&gt;
| Leo Caseiro&lt;br /&gt;
|-&lt;br /&gt;
| Uptown&lt;br /&gt;
| https://github.com/elliotkendall/bga-uptown&lt;br /&gt;
| SpottedShroom&lt;br /&gt;
|-&lt;br /&gt;
| Via Magica&lt;br /&gt;
| https://github.com/christopherburke/bga_viamagica&lt;br /&gt;
| CuriousTerran&lt;br /&gt;
|-&lt;br /&gt;
| Just Desserts&lt;br /&gt;
| https://github.com/mizutismask/bga-just-desserts&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| The King&#039;s Guild&lt;br /&gt;
| https://github.com/AdamNovotny/BGG-KingsGuild&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| Get the MacGuffin&lt;br /&gt;
| https://github.com/mizutismask/bga-get-the-MacGuffin&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| President&lt;br /&gt;
| https://github.com/quaresma95/president&lt;br /&gt;
| quaresma95&lt;br /&gt;
|-&lt;br /&gt;
| Hardback&lt;br /&gt;
| https://github.com/quietmint/bga-hardback&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dice Summoners&lt;br /&gt;
| https://github.com/eoincos/bga-dicesummoners&lt;br /&gt;
| eoincos&lt;br /&gt;
|-&lt;br /&gt;
| Trick of the Rails&lt;br /&gt;
| https://github.com/Fnordistan/trickoftherails&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
| The Lady and the Tiger (Doors)&lt;br /&gt;
| https://github.com/Fnordistan/ladyandthetiger&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
| For-Ex&lt;br /&gt;
| https://github.com/Fnordistan/forex&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects on studio ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Any developer can add themselves to a project as read-only from https://studio.boardgamearena.com/#!projects page (almost any project).&lt;br /&gt;
The list below are no-games which do not have bgg id and not showing up there.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code&lt;br /&gt;
| https://studio.boardgamearena.com/gamepanel?game=sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Original BGA template&lt;br /&gt;
| https://studio.boardgamearena.com/gamepanel?game=template&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other useful resources ==&lt;br /&gt;
&lt;br /&gt;
Moved to [[Tools_and_tips_of_BGA_Studio]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=14957</id>
		<title>BGA Code Sharing</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=14957"/>
		<updated>2022-10-05T01:50:16Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Projects hosted not in studio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is for listing of externally hosted bga projects, tools and resources, as well as internal project&lt;br /&gt;
intended for sharing&lt;br /&gt;
&lt;br /&gt;
== Community shared components, pens, etc ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DESCRIPTION&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Dice models and animation&lt;br /&gt;
|-&lt;br /&gt;
| Die: 4 sided &lt;br /&gt;
| https://codepen.io/mrkiffie/pen/doVZgW&lt;br /&gt;
| code pen&lt;br /&gt;
|-&lt;br /&gt;
| Die: 6 sided &lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Code can be found in project&lt;br /&gt;
|-&lt;br /&gt;
| Die: 12 sided (dodecahedron) &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/xxLLxOP&lt;br /&gt;
| Code pen&lt;br /&gt;
|- &lt;br /&gt;
| Die: 20 sided &lt;br /&gt;
| https://codepen.io/vicentemundim/details/cenIh&lt;br /&gt;
| Code pen&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Moving object using CSS animation (mostly)&lt;br /&gt;
|-&lt;br /&gt;
| Phantom object move on oversurface &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/gORvdJo&lt;br /&gt;
| This technique creates clone of the object it moves it on another surface. It works well when parents that css transform applies such as scale and rotate&lt;br /&gt;
|-&lt;br /&gt;
| Move object directly using positioning &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/dyzgKVX&lt;br /&gt;
| This technique is modification of BGA framework method to allow mobile object not to have absolute position before or after the move (and uses css animation not dojo). Methods slideToObjectRelative, attachToNewObjectNoDestroy&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Responsive layout for game boards&lt;br /&gt;
|-&lt;br /&gt;
|Flex Layout&lt;br /&gt;
|https://codepen.io/VictoriaLa/pen/XWjJJgG&lt;br /&gt;
|Example on how to create flexible layout just by using css&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Algorithms&lt;br /&gt;
|-&lt;br /&gt;
|Hex grid&lt;br /&gt;
|tapestry,Tumbleweed,gaia project,Gold West&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Shortest path on hex grid&lt;br /&gt;
|memoir 44&lt;br /&gt;
| Disjktra&lt;br /&gt;
|-&lt;br /&gt;
|Largest area on hex grid&lt;br /&gt;
|tapestry, ...&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Largest area on square grid&lt;br /&gt;
|king domino, ...&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Tetris pieces&lt;br /&gt;
|patchwork, ...&lt;br /&gt;
|Matrix manupations to rotate, flip and fit tetris pieces&lt;br /&gt;
|-&lt;br /&gt;
|Line of sights on hex grid&lt;br /&gt;
|memoir 44&lt;br /&gt;
|Find intersecting hexes on a line between two cells&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects hosted not in studio ==&lt;br /&gt;
&lt;br /&gt;
See the table a link and nickname of the developer on bga (same as used for dev forum), and short description. See [[Tools_and_tips_of_BGA_Studio#Version_Control]] for some suggestions on how and where to publish your code externally. Also see the [https://github.com/topics/boardgamearena boardgamearena] tag on github.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important notice about artwork on BGA Open Source projects: original hi-resolution images from publishers must not be published on the repositories. In addition, it is better to specify that the images derivated from publishers artwork are copyrighted and cannot be licensed under a free license like Creative Commons.&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NON-GAME PROJECTS&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
! COMMENT&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
| Examples of various game components and PHP stubs of framework code to make IDE happy&lt;br /&gt;
|-&lt;br /&gt;
| Vanilla Typescipt template (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-dojoless&lt;br /&gt;
| Victoria_La&lt;br /&gt;
| Project template for typescript and using minimal dojo, good for vscode - type checking, auto-complete, navigation&lt;br /&gt;
|-&lt;br /&gt;
| BoardGameArena Workbench (not a game)&lt;br /&gt;
| https://github.com/danielholmes/bga-workbench&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
! GAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
! COMMENT&lt;br /&gt;
|-&lt;br /&gt;
| 99 (Trick-taking Card Game)&lt;br /&gt;
| https://github.com/ekelly/bga-ninetynine&lt;br /&gt;
| QuasarDukeDev&lt;br /&gt;
|-&lt;br /&gt;
| Assyria &lt;br /&gt;
| https://github.com/sebastien-prudhomme/bga-assyria&lt;br /&gt;
| daikinee &lt;br /&gt;
|-&lt;br /&gt;
| Aura&lt;br /&gt;
| https://github.com/micahstairs/bga-aura&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Bandido &lt;br /&gt;
| https://github.com/opheliehb/BandidoBGA&lt;br /&gt;
| ophelopede &amp;amp; Harkle &lt;br /&gt;
|-&lt;br /&gt;
| The Battle for Hill 218&lt;br /&gt;
| https://github.com/danielholmes/battle-for-hill-218&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
| Bonbons&lt;br /&gt;
| https://github.com/AntonioSoler/bga-bonbons&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Coinche&lt;br /&gt;
| https://github.com/drasill/bga-coinche&lt;br /&gt;
| Draasill&lt;br /&gt;
|-&lt;br /&gt;
| Coup: City State&lt;br /&gt;
| https://github.com/quietmint/bga-coupcitystate&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dungeon Roll&lt;br /&gt;
| https://github.com/MartinGoulet/bga-dungeonroll&lt;br /&gt;
| MGoulet&lt;br /&gt;
|-&lt;br /&gt;
| Egyptian Ratscrew&lt;br /&gt;
| https://github.com/0BuRner/bga-egyptianratscrew&lt;br /&gt;
| 0BuRner&lt;br /&gt;
|-&lt;br /&gt;
| Eruption&lt;br /&gt;
| https://github.com/AndyKerrison/bga-eruption&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| A Fistful Of Gold&lt;br /&gt;
| https://bitbucket.org/Joel_L/fistfulofgold&lt;br /&gt;
| Brainchild&lt;br /&gt;
|-&lt;br /&gt;
| Florenza: The Card Game&lt;br /&gt;
| https://github.com/alberto-bottarini/bga-florenza&lt;br /&gt;
| tarini &lt;br /&gt;
|-&lt;br /&gt;
| Hearts &#039;&#039;&#039;(Tutorial)&#039;&#039;&#039;&lt;br /&gt;
| https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Homesteaders&lt;br /&gt;
| https://github.com/npatron/bga-homesteaders&lt;br /&gt;
| TheBoot&lt;br /&gt;
|-&lt;br /&gt;
| Incan Gold&lt;br /&gt;
| https://github.com/AntonioSoler/bga-incangold&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Innovation&lt;br /&gt;
| https://github.com/micahstairs/bga-innovation&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Mapmaker: The Gerrymandering Game&lt;br /&gt;
| https://github.com/gzhang01/bga-mapmaker&lt;br /&gt;
| gkz&lt;br /&gt;
|-&lt;br /&gt;
| Marco Polo&lt;br /&gt;
| https://github.com/rcitaliano/MarcoPolo&lt;br /&gt;
| rcitaliano&lt;br /&gt;
|-&lt;br /&gt;
| Nile&lt;br /&gt;
| https://github.com/AndyKerrison/bga-nile&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| Noir: Killer vs Inspector&lt;br /&gt;
| https://bitbucket.org/chhuang76/bga_noirkvi&lt;br /&gt;
| ch huang&lt;br /&gt;
|-&lt;br /&gt;
| Penny Press&lt;br /&gt;
| https://github.com/AdamNovotny/bga-blooms&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| P.I.&lt;br /&gt;
| https://gitlab.com/fa81/bga-pi, https://github.com/hellp/bga-pi (mirror)&lt;br /&gt;
| Fabian Neumann (fa81)&lt;br /&gt;
|-&lt;br /&gt;
| Santorini&lt;br /&gt;
| https://github.com/AntonioSoler/bga-santorini&lt;br /&gt;
| Morgalad, quietmint, Tisaac&lt;br /&gt;
|-&lt;br /&gt;
| Tablut&lt;br /&gt;
| https://github.com/Lucas-C/tablut&lt;br /&gt;
| Lucas-C &amp;amp; ntaffore&lt;br /&gt;
|-&lt;br /&gt;
| Takara Island&lt;br /&gt;
| https://github.com/AntonioSoler/bga-takaraisland&lt;br /&gt;
| Morgalad&lt;br /&gt;
|-&lt;br /&gt;
| Taluva&lt;br /&gt;
| https://github.com/quietmint/bga-taluva&lt;br /&gt;
| Morgalad &amp;amp; quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Teotihuacan: City of Gods&lt;br /&gt;
| https://github.com/Trompetenhut/bga-teotihuacan&lt;br /&gt;
| Trompetenhut&lt;br /&gt;
|-&lt;br /&gt;
| Texas 42 (domino game, still under development)&lt;br /&gt;
| https://github.com/ishermandom/bga-42&lt;br /&gt;
| Stardust Spikes, Jason Turner-Maier, Ilya Sherman&lt;br /&gt;
|-&lt;br /&gt;
| Tic Tac Match&lt;br /&gt;
| https://github.com/leocaseiro/bga-tictacmatch&lt;br /&gt;
| Leo Caseiro&lt;br /&gt;
|-&lt;br /&gt;
| Uptown&lt;br /&gt;
| https://github.com/elliotkendall/bga-uptown&lt;br /&gt;
| SpottedShroom&lt;br /&gt;
|-&lt;br /&gt;
| Via Magica&lt;br /&gt;
| https://github.com/christopherburke/bga_viamagica&lt;br /&gt;
| CuriousTerran&lt;br /&gt;
|-&lt;br /&gt;
| Just Desserts&lt;br /&gt;
| https://github.com/mizutismask/bga-just-desserts&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| The King&#039;s Guild&lt;br /&gt;
| https://github.com/AdamNovotny/BGG-KingsGuild&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| Get the MacGuffin&lt;br /&gt;
| https://github.com/mizutismask/bga-get-the-MacGuffin&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| President&lt;br /&gt;
| https://github.com/quaresma95/president&lt;br /&gt;
| quaresma95&lt;br /&gt;
|-&lt;br /&gt;
| Hardback&lt;br /&gt;
| https://github.com/quietmint/bga-hardback&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dice Summoners&lt;br /&gt;
| https://github.com/eoincos/bga-dicesummoners&lt;br /&gt;
| eoincos&lt;br /&gt;
|-&lt;br /&gt;
| Trick of the Rails&lt;br /&gt;
| https://github.com/Fnordistan/trickoftherails&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects on studio ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Any developer can add themselves to a project as read-only from https://studio.boardgamearena.com/#!projects page (almost any project).&lt;br /&gt;
The list below are no-games which do not have bgg id and not showing up there.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code&lt;br /&gt;
| https://studio.boardgamearena.com/gamepanel?game=sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Original BGA template&lt;br /&gt;
| https://studio.boardgamearena.com/gamepanel?game=template&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other useful resources ==&lt;br /&gt;
&lt;br /&gt;
Moved to [[Tools_and_tips_of_BGA_Studio]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_meta-information:_gameinfos.jsonc&amp;diff=14880</id>
		<title>Game meta-information: gameinfos.jsonc</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_meta-information:_gameinfos.jsonc&amp;diff=14880"/>
		<updated>2022-10-01T18:37:07Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Multiple tie breaker management */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
From this file, you can edit the various meta-information of your game.&lt;br /&gt;
&lt;br /&gt;
Once you modified the file, don&#039;t forget to click on &amp;quot;Reload game informations&amp;quot; from the Control Panel in order in can be taken into account.&lt;br /&gt;
&lt;br /&gt;
Note: if you broke gameinfos and cannot load management page reload using direct URL https://studio.boardgamearena.com/admin/studio/reloadGameInfos.html?game= (with your game name at the end of url).&lt;br /&gt;
&lt;br /&gt;
Most information provided in this file are self-explainable.&lt;br /&gt;
&lt;br /&gt;
See sections below for specific cases.&lt;br /&gt;
&lt;br /&gt;
== Publisher/Designer fields ==&lt;br /&gt;
&lt;br /&gt;
These fields should match the publisher/designer for the game. In the case of a public domain name, they should be left empty (empty string &#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
== Beta ==&lt;br /&gt;
&lt;br /&gt;
You are not allowed to set the &amp;quot;&#039;&#039;&#039;is_beta&#039;&#039;&#039;&amp;quot; to 0 before the game has been released on BGA and stabilized.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Time Profiles ==&lt;br /&gt;
&#039;&#039;&#039;fast/medium/slow_additional_time&#039;&#039;&#039;: please set high values here: after the game has been released, we will lower these value to match the real game duration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Number of players ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;players&#039;&#039;&#039;&lt;br /&gt;
  &#039;players&#039; =&amp;gt; array( 3, 4, 6 ),&lt;br /&gt;
&lt;br /&gt;
* during the first step of development of a game, it is recommended to have &amp;quot;1 player&amp;quot; configuration: much easy to start/stop a game this way, don&#039;t need to switch players.&lt;br /&gt;
* if you change the minimum number of players from for example 1 to 2, make sure the new tables you create are not restricted from 1 to 1 player otherwise when you create a new table and this account setting is used, there will be a conflict with the new minimum number of players allowed and you will be blocked from creating the game.&lt;br /&gt;
But you can also unblock yourself by changing player number again, launching a game with a larger number, and then getting back to the numbers you want.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;suggest_player_number&#039;&#039;&#039; / &#039;&#039;&#039;not_recommend_player_number&#039;&#039;&#039;&lt;br /&gt;
don&#039;t specify anything here if there is no configuration that is REALLY better/worst than another one. You can check player&#039;s poll on BoardGameGeek game page if you have any doubt. &#039;&#039;&#039;Important exception:&#039;&#039;&#039; in the automatic lobby, if &#039;suggest_player_number&#039; is not specified, the system will try first the lowest. So if the lowest player number is not compatible with the default options for your game (especially if there is a Solo mode that can only be played in training mode) you have to specify a suggest_player_number of your choice, so that players launching a game in the automatic lobby without checking the option don&#039;t get an error with the default configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Colors ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;player_colors&#039;&#039;&#039;&lt;br /&gt;
   &#039;player_colors&#039; =&amp;gt; array( &amp;quot;ff0000&amp;quot;, &amp;quot;008000&amp;quot;, &amp;quot;0000ff&amp;quot;, &amp;quot;ffa500&amp;quot;, &amp;quot;ffffff&amp;quot; ),&lt;br /&gt;
&lt;br /&gt;
This array defines the default player colors, theoretically this can be bigger then maximum number of players but you have to support all of the in your game.&lt;br /&gt;
Your setupNewGame in php is responsible for attributing these values to players. See section &amp;quot;Player color preferences&amp;quot; in [[Main_game_logic:_yourgamename.game.php]] for details.&lt;br /&gt;
&lt;br /&gt;
== Losers not ranked between themselves ==&lt;br /&gt;
&lt;br /&gt;
By default, all player are ranked, but in some games, the rules say that there is only one winner and that all the other players are losers and not ranked between themselves. You can set this option to true so that for your game, there is only one winner and losers, without a full ranking of all players.&lt;br /&gt;
&lt;br /&gt;
The score in this case should be 1 for the winner and 0 for the losers.&lt;br /&gt;
&lt;br /&gt;
 // If in the game, all losers are equal (no score to rank them or explicit in the rules that losers are not ranked between them), set this to true &lt;br /&gt;
 // The game end result will display &amp;quot;Winner&amp;quot; for the 1st player and &amp;quot;Loser&amp;quot; for all other players&lt;br /&gt;
 &#039;losers_not_ranked&#039; =&amp;gt; false,&lt;br /&gt;
&lt;br /&gt;
== Disable player rotation in case of rematch ==&lt;br /&gt;
&lt;br /&gt;
By default, in case of a rematch players are rotated so that the first player changes. If for your game it&#039;s better to always have a random player order you can change this option.&lt;br /&gt;
&lt;br /&gt;
 // When doing a rematch, the player order is swapped using a &amp;quot;rotation&amp;quot; so the starting player is not the same&lt;br /&gt;
 // If you want to disable this, set this to true (even if the comment in your game file say the opposite).&lt;br /&gt;
 &#039;disable_player_order_swap_on_rematch&#039; =&amp;gt; false,&lt;br /&gt;
&lt;br /&gt;
== Custom &amp;quot;buy this game&amp;quot; button ==&lt;br /&gt;
&lt;br /&gt;
By default, the &amp;quot;buy this game&amp;quot; button is a link to an Amazon search with the name of the game.&lt;br /&gt;
&lt;br /&gt;
You can replace it by a different URL / game button label with :&lt;br /&gt;
&lt;br /&gt;
 &#039;custom_buy_button&#039; =&amp;gt; array(&lt;br /&gt;
    &#039;url&#039; =&amp;gt; &#039;http://yoururl.com&#039;,&lt;br /&gt;
    &#039;label&#039; =&amp;gt; &#039;Name of the website&#039;&lt;br /&gt;
 ),&lt;br /&gt;
&lt;br /&gt;
Note : button label will be &amp;quot;Buy on &amp;lt;Name of the website&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Tags ==&lt;br /&gt;
&lt;br /&gt;
A maximum of &#039;&#039;&#039;ten&#039;&#039;&#039; tags can be attributed to your game (not counting complexity and duration tags).&lt;br /&gt;
&lt;br /&gt;
Tags are useful to place your game in the correct game list section and to give a good quick overview of what the game is about to players.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;⚠ Note&#039;&#039;&#039;: The &#039;&#039;order&#039;&#039; of the tags is very important too, you&#039;ll have to put the most relevant first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;⚠ Note&#039;&#039;&#039;: tags are &amp;lt;b style=&amp;quot;color:darkred&amp;quot;&amp;gt;only read during the first deploy&amp;lt;/b&amp;gt; from the file &amp;lt;code&amp;gt;gameinfos.inc.php&amp;lt;/code&amp;gt; ; afterwards, setting tags for a game is done via the [[Game_metadata_manager|Game Metadata Manager]].&lt;br /&gt;
&lt;br /&gt;
Game complexity (you &#039;&#039;&#039;must&#039;&#039;&#039; specify one tag &#039;&#039;&#039;and only one&#039;&#039;&#039; from this category):&lt;br /&gt;
* &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;: Casual games&lt;br /&gt;
* &amp;lt;code&amp;gt;3&amp;lt;/code&amp;gt;: For regular players&lt;br /&gt;
* &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;: For core gamers&lt;br /&gt;
&lt;br /&gt;
Duration tags (only indicative - the correct tag will be automatically set by BGA after a while):&lt;br /&gt;
* &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt;: Short game (&amp;lt;10 minutes)&lt;br /&gt;
* &amp;lt;code&amp;gt;11&amp;lt;/code&amp;gt;: Medium length game (10 minutes to 30 minutes)&lt;br /&gt;
* &amp;lt;code&amp;gt;12&amp;lt;/code&amp;gt;: Long game (&amp;gt;30mn)&lt;br /&gt;
&lt;br /&gt;
Other tags:&lt;br /&gt;
* &amp;lt;code&amp;gt;20&amp;lt;/code&amp;gt;: Awarded game (Win a prestigious award) (the game must have been at the &#039;&#039;&#039;first&#039;&#039;&#039; place of one the [http://boardgamegeek.com/wiki/page/Gaming_Industry_Awards# following major awards list]).&lt;br /&gt;
* &amp;lt;code&amp;gt;22&amp;lt;/code&amp;gt;: Prototype (This game has not been published yet)&lt;br /&gt;
* &amp;lt;code&amp;gt;23&amp;lt;/code&amp;gt;: Classic (This game is a classic from Public Domain)&lt;br /&gt;
* &amp;lt;code&amp;gt;25&amp;lt;/code&amp;gt;: Party game&lt;br /&gt;
* &amp;lt;code&amp;gt;26&amp;lt;/code&amp;gt;: Family&lt;br /&gt;
* &amp;lt;code&amp;gt;27&amp;lt;/code&amp;gt;: Miniatures (figurines)&lt;br /&gt;
* &amp;lt;code&amp;gt;28&amp;lt;/code&amp;gt;: Recommended in Realtime&lt;br /&gt;
* &amp;lt;code&amp;gt;29&amp;lt;/code&amp;gt;: Recommended in Turnbased&lt;br /&gt;
* &amp;lt;code&amp;gt;30&amp;lt;/code&amp;gt;: Best for 2 (best with 2 players) (automatically added to games for 2p only)&lt;br /&gt;
&lt;br /&gt;
Theme tags:&lt;br /&gt;
* &amp;lt;code&amp;gt;100&amp;lt;/code&amp;gt;: Fantasy&lt;br /&gt;
* &amp;lt;code&amp;gt;101&amp;lt;/code&amp;gt;: Science-Fiction&lt;br /&gt;
* &amp;lt;code&amp;gt;102&amp;lt;/code&amp;gt;: Historical&lt;br /&gt;
* &amp;lt;code&amp;gt;103&amp;lt;/code&amp;gt;: Adventure&lt;br /&gt;
* &amp;lt;code&amp;gt;104&amp;lt;/code&amp;gt;: Exploration&lt;br /&gt;
* &amp;lt;code&amp;gt;105&amp;lt;/code&amp;gt;: Conquest&lt;br /&gt;
* &amp;lt;code&amp;gt;106&amp;lt;/code&amp;gt;: Building&lt;br /&gt;
* &amp;lt;code&amp;gt;107&amp;lt;/code&amp;gt;: Western&lt;br /&gt;
* &amp;lt;code&amp;gt;108&amp;lt;/code&amp;gt;: Espionage&lt;br /&gt;
* &amp;lt;code&amp;gt;109&amp;lt;/code&amp;gt;: Trains&lt;br /&gt;
* &amp;lt;code&amp;gt;110&amp;lt;/code&amp;gt;: Sport&lt;br /&gt;
* &amp;lt;code&amp;gt;111&amp;lt;/code&amp;gt;: Economy&lt;br /&gt;
* &amp;lt;code&amp;gt;112&amp;lt;/code&amp;gt;: Aviation&lt;br /&gt;
* &amp;lt;code&amp;gt;113&amp;lt;/code&amp;gt;: Surreal/Silly/Absurd&lt;br /&gt;
* &amp;lt;code&amp;gt;114&amp;lt;/code&amp;gt;: Animals&lt;br /&gt;
* &amp;lt;code&amp;gt;115&amp;lt;/code&amp;gt;: Wargame&lt;br /&gt;
* &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;: Abstract game&lt;br /&gt;
&lt;br /&gt;
Mechanism tags:&lt;br /&gt;
* &amp;lt;code&amp;gt;200&amp;lt;/code&amp;gt;: Cards (cards plays a central role in this game)&lt;br /&gt;
* &amp;lt;code&amp;gt;201&amp;lt;/code&amp;gt;: Dice&lt;br /&gt;
* &amp;lt;code&amp;gt;202&amp;lt;/code&amp;gt;: Solo&lt;br /&gt;
* &amp;lt;code&amp;gt;203&amp;lt;/code&amp;gt;: Worker placement&lt;br /&gt;
* &amp;lt;code&amp;gt;204&amp;lt;/code&amp;gt;: Hand management&lt;br /&gt;
* &amp;lt;code&amp;gt;205&amp;lt;/code&amp;gt;: Bluffing&lt;br /&gt;
* &amp;lt;code&amp;gt;206&amp;lt;/code&amp;gt;: Tile placement&lt;br /&gt;
* &amp;lt;code&amp;gt;207&amp;lt;/code&amp;gt;: Combos&lt;br /&gt;
* &amp;lt;code&amp;gt;208&amp;lt;/code&amp;gt;: Area Majority&lt;br /&gt;
* &amp;lt;code&amp;gt;209&amp;lt;/code&amp;gt;: Race&lt;br /&gt;
* &amp;lt;code&amp;gt;210&amp;lt;/code&amp;gt;: Collection&lt;br /&gt;
* &amp;lt;code&amp;gt;211&amp;lt;/code&amp;gt;: Cooperative&lt;br /&gt;
* &amp;lt;code&amp;gt;212&amp;lt;/code&amp;gt;: Random&lt;br /&gt;
* &amp;lt;code&amp;gt;213&amp;lt;/code&amp;gt;: Speed&lt;br /&gt;
* &amp;lt;code&amp;gt;214&amp;lt;/code&amp;gt;: Asymmetrical&lt;br /&gt;
* &amp;lt;code&amp;gt;215&amp;lt;/code&amp;gt;: Communication&lt;br /&gt;
* &amp;lt;code&amp;gt;216&amp;lt;/code&amp;gt;: Conquest&lt;br /&gt;
* &amp;lt;code&amp;gt;217&amp;lt;/code&amp;gt;: Team&lt;br /&gt;
* &amp;lt;code&amp;gt;218&amp;lt;/code&amp;gt;: Bidding&lt;br /&gt;
* &amp;lt;code&amp;gt;219&amp;lt;/code&amp;gt;: Objectives&lt;br /&gt;
* &amp;lt;code&amp;gt;220&amp;lt;/code&amp;gt;: Trick-taking&lt;br /&gt;
* &amp;lt;code&amp;gt;221&amp;lt;/code&amp;gt;: Resource management&lt;br /&gt;
* &amp;lt;code&amp;gt;222&amp;lt;/code&amp;gt;: Roles&lt;br /&gt;
* &amp;lt;code&amp;gt;223&amp;lt;/code&amp;gt;: Roll &amp;amp; Write&lt;br /&gt;
* &amp;lt;code&amp;gt;224&amp;lt;/code&amp;gt;: Push your luck&lt;br /&gt;
* &amp;lt;code&amp;gt;225&amp;lt;/code&amp;gt;: Voting&lt;br /&gt;
* &amp;lt;code&amp;gt;226&amp;lt;/code&amp;gt;: Word games&lt;br /&gt;
* &amp;lt;code&amp;gt;227&amp;lt;/code&amp;gt;: Deck Building&lt;br /&gt;
* &amp;lt;code&amp;gt;228&amp;lt;/code&amp;gt;: Engine building&lt;br /&gt;
* &amp;lt;code&amp;gt;229&amp;lt;/code&amp;gt;: Drafting&lt;br /&gt;
* &amp;lt;code&amp;gt;230&amp;lt;/code&amp;gt;: Player elimination&lt;br /&gt;
&lt;br /&gt;
== Game Presentation ==&lt;br /&gt;
&lt;br /&gt;
Short game presentation text that will appear on the game description page, structured as an array of paragraphs.&lt;br /&gt;
&lt;br /&gt;
Each paragraph must be wrapped with totranslate() for translation and should not contain html (plain text without formatting). A good length for this text is between 100 and 150 words (about 6 to 9 lines on a standard display)&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 &#039;presentation&#039; =&amp;gt; array(&lt;br /&gt;
    totranslate(&amp;quot;This wonderful game is about geometric shapes!&amp;quot;),&lt;br /&gt;
    totranslate(&amp;quot;It was awarded best triangle game of the year in 2005 and nominated for the Spiel des Jahres.&amp;quot;),&lt;br /&gt;
    ...&lt;br /&gt;
 ),&lt;br /&gt;
&lt;br /&gt;
== Tie breaker description ==&lt;br /&gt;
Describe tie breaker score calculation (player_score_aux in player table).&lt;br /&gt;
&lt;br /&gt;
Important: This is used in the javascript too, which is automatically generated. Using newlines in here will cause errors in the javascript, which will cause the game to not load.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 &#039;tie_breaker_description&#039; =&amp;gt; totranslate(&amp;quot;Number of remaining cards in hand&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
== Multiple tie breaker management ==&lt;br /&gt;
&lt;br /&gt;
If your game has multiple tie breakers, here is what you should do.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s take this example: &amp;quot;In case of a tie, the winner is the game with the most remaining money, then number of buildings built, then number of cards in your hand&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In this example, your &amp;quot;player_score_aux&amp;quot; field might be calculated like this:&lt;br /&gt;
&lt;br /&gt;
10000 * (remaining_money ) + 100 * (buildings_built) + (number_of_cards)&lt;br /&gt;
&lt;br /&gt;
In this case, you should add the following in gameinfos.inc.php:&lt;br /&gt;
&lt;br /&gt;
  &#039;tie_breaker_split&#039; =&amp;gt; array( 10000, 100 , 1 ),&lt;br /&gt;
&lt;br /&gt;
It means that the first tie breaker has been multiplied by 10000, the second by 100, and the third by 1.&lt;br /&gt;
&lt;br /&gt;
Using this, the result screen will be adapted to show exactly what is needed. For example:&lt;br /&gt;
* When 2 players are tied, it will show their remaining money.&lt;br /&gt;
* If their remaining money are equal, it will show the number of building built in addition to the remaining money.&lt;br /&gt;
* If these two tie breaker are still the same, it will show the 3 tie breaking values.&lt;br /&gt;
&lt;br /&gt;
== Language dependency ==&lt;br /&gt;
&lt;br /&gt;
If you have a game that is language dependent, you can use the option described here: [[Main_game_logic:_yourgamename.game.php#Language_dependent_games_API]]&lt;br /&gt;
&lt;br /&gt;
== Game page warning ==&lt;br /&gt;
&lt;br /&gt;
If a specific warning is needed on the game page (to discuss and validate with admins) it can be displayed from the game infos. For example for Texas Hold&#039;em:&lt;br /&gt;
&lt;br /&gt;
    &#039;gamepanel_page_warning&#039; =&amp;gt; totranslate(&amp;quot;There is no real money involved on BGA: this game has the mechanism of Poker but is using points instead of real money.&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
== Coop Elo Mode ==&lt;br /&gt;
&lt;br /&gt;
For cooperative games, by default players will earn as many Elo points as the score. &lt;br /&gt;
&lt;br /&gt;
For games where there is no variable difficulty (such as for example Bandido) we keep that setting, but for all coop games where we have options to change the difficulty level and/or where the score reached indicates a higher level of skill and/or where the number of players has a significant impact on the difficulty, we have to set up a reference scale for Elo points (between 1300 and 2500). Players regularly winning with a specific difficulty setting will have their Elo nearing this value asymptotically over time.&lt;br /&gt;
&lt;br /&gt;
For this, you have to set up the coop_elo_mode parameter.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning: While this can reflect player skills more precisely compared to flat ELO gain, players may abandon losing games or avoid new players to prevent ELO loss.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Related discussion - https://forum.boardgamearena.com/viewtopic.php?f=3&amp;amp;t=24363&lt;br /&gt;
&lt;br /&gt;
Here is an example using options and win/loss (score 1/0):&lt;br /&gt;
&lt;br /&gt;
    &#039;coop_elo_mode&#039; =&amp;gt; [&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;points_references&#039;,&lt;br /&gt;
        &#039;references&#039; =&amp;gt; [&lt;br /&gt;
            // Difficulty 1&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1400]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1470]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1350]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1400]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1400]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1470]],&lt;br /&gt;
            // Difficulty 2&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1540]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1450]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1540]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1540]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            // Difficulty 3&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1910]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1540]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1910]],&lt;br /&gt;
            // Difficulty 4&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1830]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 2120]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1640]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1830]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1830]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 2120]],&lt;br /&gt;
            // Difficulty 5&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1980]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 2340]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1740]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1980]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1980]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 2340]],&lt;br /&gt;
        ],&lt;br /&gt;
    ],&lt;br /&gt;
&lt;br /&gt;
Here is an example using different scoring values to indicate the level of difficulty mastered by the players winning the game:&lt;br /&gt;
&lt;br /&gt;
    &#039;coop_elo_mode&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;points_references&#039;,&lt;br /&gt;
        &#039;references&#039; =&amp;gt; array(&lt;br /&gt;
            array(&lt;br /&gt;
                &#039;players_nbr&#039; =&amp;gt; 2,&lt;br /&gt;
                //&#039;options&#039; =&amp;gt; array( ),&lt;br /&gt;
                &#039;elo&#039; =&amp;gt; array(&lt;br /&gt;
                    0 =&amp;gt; 1000,&lt;br /&gt;
                    1 =&amp;gt; 1350,&lt;br /&gt;
                    2 =&amp;gt; 1425,&lt;br /&gt;
                    3 =&amp;gt; 1500,&lt;br /&gt;
                    4 =&amp;gt; 1576,&lt;br /&gt;
                    5 =&amp;gt; 1651,&lt;br /&gt;
                    6 =&amp;gt; 1727,&lt;br /&gt;
                    7 =&amp;gt; 1802,&lt;br /&gt;
                    8 =&amp;gt; 1878,&lt;br /&gt;
                    9 =&amp;gt; 1953,&lt;br /&gt;
                    10 =&amp;gt; 2029,&lt;br /&gt;
                    11 =&amp;gt; 2104,&lt;br /&gt;
                    12 =&amp;gt; 2180&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
            array(&lt;br /&gt;
                &#039;players_nbr&#039; =&amp;gt; 3,&lt;br /&gt;
                //&#039;options&#039; =&amp;gt; array( ),&lt;br /&gt;
                &#039;elo&#039; =&amp;gt; array(&lt;br /&gt;
                    0 =&amp;gt; 1000,&lt;br /&gt;
                    1 =&amp;gt; 1400,&lt;br /&gt;
                    2 =&amp;gt; 1470,&lt;br /&gt;
                    3 =&amp;gt; 1541,&lt;br /&gt;
                    4 =&amp;gt; 1612,&lt;br /&gt;
                    5 =&amp;gt; 1683,&lt;br /&gt;
                    6 =&amp;gt; 1754,&lt;br /&gt;
                    7 =&amp;gt; 1825,&lt;br /&gt;
                    8 =&amp;gt; 1895,&lt;br /&gt;
                    9 =&amp;gt; 1966,&lt;br /&gt;
                    10 =&amp;gt; 2018,&lt;br /&gt;
                    11 =&amp;gt; 2095,&lt;br /&gt;
                    12 =&amp;gt; 2250&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
            array(&lt;br /&gt;
                &#039;players_nbr&#039; =&amp;gt; 4,&lt;br /&gt;
                //&#039;options&#039; =&amp;gt; array( ),&lt;br /&gt;
                &#039;elo&#039; =&amp;gt; array(&lt;br /&gt;
                    0 =&amp;gt; 1000,&lt;br /&gt;
                    1 =&amp;gt; 1430,&lt;br /&gt;
                    2 =&amp;gt; 1505,&lt;br /&gt;
                    3 =&amp;gt; 1580,&lt;br /&gt;
                    4 =&amp;gt; 1655,&lt;br /&gt;
                    5 =&amp;gt; 1730,&lt;br /&gt;
                    6 =&amp;gt; 1805,&lt;br /&gt;
                    7 =&amp;gt; 1880,&lt;br /&gt;
                    8 =&amp;gt; 1955,&lt;br /&gt;
                    9 =&amp;gt; 2030,&lt;br /&gt;
                    10 =&amp;gt; 2105,&lt;br /&gt;
                    11 =&amp;gt; 2180,&lt;br /&gt;
                    12 =&amp;gt; 2330&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
            array(&lt;br /&gt;
                &#039;players_nbr&#039; =&amp;gt; 5,&lt;br /&gt;
                // &#039;options&#039; =&amp;gt; array( ),&lt;br /&gt;
                &#039;elo&#039; =&amp;gt; array(&lt;br /&gt;
                    0 =&amp;gt; 1000,&lt;br /&gt;
                    1 =&amp;gt; 1480,&lt;br /&gt;
                    2 =&amp;gt; 1558,&lt;br /&gt;
                    3 =&amp;gt; 1636,&lt;br /&gt;
                    4 =&amp;gt; 1714,&lt;br /&gt;
                    5 =&amp;gt; 1792,&lt;br /&gt;
                    6 =&amp;gt; 1870,&lt;br /&gt;
                    7 =&amp;gt; 1949,&lt;br /&gt;
                    8 =&amp;gt; 2027,&lt;br /&gt;
                    9 =&amp;gt; 2105,&lt;br /&gt;
                    10 =&amp;gt; 2183,&lt;br /&gt;
                    11 =&amp;gt; 2261,&lt;br /&gt;
                    12 =&amp;gt; 2340&lt;br /&gt;
                )&lt;br /&gt;
            )&lt;br /&gt;
        )&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Table&amp;diff=14876</id>
		<title>Table</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Table&amp;diff=14876"/>
		<updated>2022-10-01T17:08:02Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Selected static methods in utility modules */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is reference for public and protected method defined in Table and its ancestors, this information obtained by using php reflection.&lt;br /&gt;
&lt;br /&gt;
Most of these methods documented on various other wikis, this is just refeference for completeness and in case you run into accidental overloading of undocumented functions...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;&lt;br /&gt;
Its a long list please help with editing this wiki&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you need these method for IDE autocompletion and validation there is unofficial project that has stubs to documented methods: &lt;br /&gt;
* https://github.com/elaskavaia/bga-sharedcode/blob/master/misc/module/table/table.game.php (if you want more stubs pull requests are welcome to this repo)&lt;br /&gt;
* https://github.com/danielholmes/bga-workbench/tree/master/src/BGAWorkbench/Stubs (not sure who is supporting this one)&lt;br /&gt;
&lt;br /&gt;
== Class hierarchy ==&lt;br /&gt;
&lt;br /&gt;
* APP_Object&lt;br /&gt;
** APP_DbObject&lt;br /&gt;
***  APP_GameClass&lt;br /&gt;
****    Table - this is a class all games inherit&lt;br /&gt;
****    [[Deck]] - db handling component for specific schema (deck)&lt;br /&gt;
&lt;br /&gt;
== Methods in the Table class ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;Table.getGameName&lt;br /&gt;
:part of template, return game name, not to be modified by developer, not document on wiki&lt;br /&gt;
;Table._&lt;br /&gt;
:translation wrapper function, see [[Translations]]&lt;br /&gt;
;Table.setTable&lt;br /&gt;
:method that sets up the php side, do not call or override&lt;br /&gt;
;Table.initTable protected&lt;br /&gt;
:This method is called by framework before every action (does nothing by default), unlike constructor this method has initialized state of the table so it can access db, undocumented as it has very limited use&lt;br /&gt;
;Table.getAllTableDatas&lt;br /&gt;
:undocumented&lt;br /&gt;
;Table.getAllDatas&lt;br /&gt;
:part of template, override, see [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
;Table.setupNewGameTable&lt;br /&gt;
:undocumented&lt;br /&gt;
;Table.setupNewGame&lt;br /&gt;
:part of template, override, see [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
;Table.getTableOptionsForGame static&lt;br /&gt;
:undocumented&lt;br /&gt;
;Table.getTableOptions&lt;br /&gt;
:undocumented, likely return gameoptions (i.e. variants of the games)&lt;br /&gt;
;Table.getTablePreferencesForGame static&lt;br /&gt;
:undocumented&lt;br /&gt;
;Table.getTablePreferences&lt;br /&gt;
:undocumented, likely return UI preferences (i.e. display tooltips or not) &lt;br /&gt;
;Table.getGameInfosForGame static&lt;br /&gt;
:undocuments, likely return $gameinfos from gameinfos.inc.php&lt;br /&gt;
;Table.getGameOptionsInfos&lt;br /&gt;
:undocumented&lt;br /&gt;
;Table.start&lt;br /&gt;
:undocumented, likely starts the game, do not call&lt;br /&gt;
;Table.stMakeEveryoneActive&lt;br /&gt;
:this method can be used in state machine to make everybody active as &amp;quot;st&amp;quot; method of multiplayeractive state&lt;br /&gt;
&lt;br /&gt;
;Table.loadPlayersBasicInfos&lt;br /&gt;
:very usefull function get players table, see [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
;Table.reloadPlayersBasicInfos&lt;br /&gt;
:reload players info, see [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
;Table.reattributeColorsBasedOnPreferences&lt;br /&gt;
:change players colors, see [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
;Table.getBestColorFromColorPrefs&lt;br /&gt;
:undocumented, do not call, use to pick a color based on preference&lt;br /&gt;
;Table.initSetupPlayersInfos&lt;br /&gt;
:undocumented&lt;br /&gt;
;Table.getPlayersNumber&lt;br /&gt;
:returns number of players, see [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
;Table.checkAction&lt;br /&gt;
:check action on server, see [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
;Table.checkGameStart&lt;br /&gt;
;Table.color_to_color_back&lt;br /&gt;
:@deprecated, undocumented&lt;br /&gt;
;Table.initGameStateLabels&lt;br /&gt;
;Table.setGameStateInitialValue&lt;br /&gt;
:Set initial state of global, technically same as setGameStateValue see [[Main_game_logic:_yourgamename.game.php#Use_globals]]&lt;br /&gt;
;Table.getGameStateValue&lt;br /&gt;
:get value of global see [[Main_game_logic:_yourgamename.game.php#Use_globals]]&lt;br /&gt;
;Table.setGameStateValue&lt;br /&gt;
:set value of global see [[Main_game_logic:_yourgamename.game.php#Use_globals]]&lt;br /&gt;
;Table.incGameStateValue&lt;br /&gt;
:increment value of global see [[Main_game_logic:_yourgamename.game.php#Use_globals]]&lt;br /&gt;
;Table.is_testmode&lt;br /&gt;
:@deprecated&lt;br /&gt;
;Table.testmodedatas&lt;br /&gt;
:@deprecated&lt;br /&gt;
;Table.applyTestModeDbFixture&lt;br /&gt;
;Table.getActivePlayerId&lt;br /&gt;
:get active player id, see [[Main_game_logic:_yourgamename.game.php#Game_states_and_active_players]]&lt;br /&gt;
;Table.getActivePlayerName&lt;br /&gt;
:get active player name, see [[Main_game_logic:_yourgamename.game.php#Game_states_and_active_players]]&lt;br /&gt;
;Table.getCurrentPlayerId&lt;br /&gt;
:get current player id, see [[Main_game_logic:_yourgamename.game.php#Game_states_and_active_players]]&lt;br /&gt;
;Table.getCurrentPlayerName&lt;br /&gt;
:get currrent player name, see [[Main_game_logic:_yourgamename.game.php#Game_states_and_active_players]]&lt;br /&gt;
;Table.getCurrentPlayerColor&lt;br /&gt;
:get current player color, see [[Main_game_logic:_yourgamename.game.php#Game_states_and_active_players]]&lt;br /&gt;
;Table.getPlayerNameById&lt;br /&gt;
:get the name by id, see [[Main_game_logic:_yourgamename.game.php#Accessing_player_information]]&lt;br /&gt;
;Table.getPlayerColorById&lt;br /&gt;
:get the color by id, see [[Main_game_logic:_yourgamename.game.php#Accessing_player_information]]&lt;br /&gt;
;Table.getPlayerNoById&lt;br /&gt;
:get &#039;player_no&#039; (number) by id, see [[Main_game_logic:_yourgamename.game.php#Accessing_player_information]]&lt;br /&gt;
;Table.isCurrentPlayerZombie&lt;br /&gt;
;Table.getPlayerCount&lt;br /&gt;
:@deprecated, use getPlayersNumber, &lt;br /&gt;
;Table.createNextPlayerTable&lt;br /&gt;
:Return linked table of player order using passed parameter, see [[Main_game_logic:_yourgamename.game.php#Players turn order]]&lt;br /&gt;
;Table.getNextPlayerTable&lt;br /&gt;
:Return linked table of player order using natural players order, see [[Main_game_logic:_yourgamename.game.php#Players turn order]]&lt;br /&gt;
;Table.createPrevPlayerTable&lt;br /&gt;
:do not use&lt;br /&gt;
;Table.getPrevPlayerTable&lt;br /&gt;
:Return linked table of player order using natural players order reversed, see [[Main_game_logic:_yourgamename.game.php#Players turn order]]&lt;br /&gt;
;Table.getPlayerAfter&lt;br /&gt;
:get player after, see [[Main_game_logic:_yourgamename.game.php#Players turn order]]&lt;br /&gt;
;Table.getPlayerBefore&lt;br /&gt;
:get player before, see [[Main_game_logic:_yourgamename.game.php#Players turn order]]&lt;br /&gt;
;Table.activeNextPlayer&lt;br /&gt;
:Make the next player active in the natural player orde, see [[Main_game_logic:_yourgamename.game.php#Game states and active players]]&lt;br /&gt;
;Table.activePrevPlayer&lt;br /&gt;
:Make the prev player active in the natural player orde, see [[Main_game_logic:_yourgamename.game.php#Game states and active players]]&lt;br /&gt;
;Table.forceEndOfGame&lt;br /&gt;
:force to abandon game, normally its called when all players agree, but can be called to force people out when testing alpha or beta games and don&#039;t want to deal with update db and such ($this-&amp;gt;forceEndOfGame( $reason ))&lt;br /&gt;
;Table.giveExtraTime&lt;br /&gt;
:give extra time to a player, usually when turn require multiple player states, see [[Main_game_logic:_yourgamename.game.php#Reflexion_time]]&lt;br /&gt;
;Table.checkZombieTurn&lt;br /&gt;
;Table.skipPlayersOutOfTime&lt;br /&gt;
:this is called by framework, do not use&lt;br /&gt;
;Table.onPlayerHasBeenZombified&lt;br /&gt;
:called when some player has been zombified because he quits the game (or have been &amp;quot;skipped&amp;quot;), unlikely you need to override this method, if you do you have to take into account first player quit vs any other player quit, you must call super implementation in any case if you decide to override it&lt;br /&gt;
;Table.forceAbandon&lt;br /&gt;
:it may be possible for force to abandon game in some cases, for example in alpha games when new database schema requires update and you did not code this (because for alpha its waste of time)&lt;br /&gt;
;Table.zombieBack&lt;br /&gt;
;Table.aiPlayer&lt;br /&gt;
;Table.aiNotPlaying&lt;br /&gt;
;Table.aiError&lt;br /&gt;
;Table.say&lt;br /&gt;
:this function processes chat message, do not use for game purposes, for word games use dedicated control&lt;br /&gt;
;Table.getGameProgression&lt;br /&gt;
:part of template, override to return proper data, see [[Main_game_logic:_yourgamename.game.php]] and [[Your_game_state_machine:_states.inc.php]]&lt;br /&gt;
;Table.getStatTypesForGame static&lt;br /&gt;
;Table.getStatTypes &lt;br /&gt;
:get the $stats_type array defined in stats.inc.php&lt;br /&gt;
;Table.stat_type_id_to_name&lt;br /&gt;
;Table.initStat&lt;br /&gt;
:initialize statistic https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Game_statistics&lt;br /&gt;
;Table.getStat&lt;br /&gt;
:get statistic https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Game_statistics&lt;br /&gt;
;Table.setStat&lt;br /&gt;
:set statistic https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Game_statistics&lt;br /&gt;
;Table.setStatForAllPlayers&lt;br /&gt;
:set player statistics for all players, not document, does not check params, have some bad side effects&lt;br /&gt;
;Table.incStat&lt;br /&gt;
:inc statistic https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Game_statistics&lt;br /&gt;
;Table.getStatFromResult&lt;br /&gt;
:helper function, do not use, should have been private for table class&lt;br /&gt;
;Table.setStatOnResult&lt;br /&gt;
:helper function, do not use, should have been private for table class&lt;br /&gt;
;Table.setStatOnResultForPlayer&lt;br /&gt;
:helper function, do not use, should have been private for table class&lt;br /&gt;
;Table.getStandardGameResultObject&lt;br /&gt;
:helper function, do not use, should have been private for table class&lt;br /&gt;
;Table.getGameRankInfos&lt;br /&gt;
;Table.argGameEnd&lt;br /&gt;
:framework end game function, do not call or override&lt;br /&gt;
;Table.stGameEnd&lt;br /&gt;
:framework end game function, do not call or override&lt;br /&gt;
;Table.stTutorialStart&lt;br /&gt;
;Table.isSoloGame&lt;br /&gt;
:return true if game is 1 player game or all other players are AI&lt;br /&gt;
;Table.notifyAllPlayers&lt;br /&gt;
:notification function, see https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php&lt;br /&gt;
;Table.notifyPlayer&lt;br /&gt;
:notification function, see https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php&lt;br /&gt;
;Table.onEndAjaxAction&lt;br /&gt;
:can be overriden to be executed before end of ajax action, unclear why would anybody need that&lt;br /&gt;
;Table.checkReturnState&lt;br /&gt;
:framework internal check action, do not call or override&lt;br /&gt;
;Table.sendNotifications&lt;br /&gt;
:framework internal function, do not call or override&lt;br /&gt;
;Table.getCurrentNotificationNextNo&lt;br /&gt;
;Table.getNotificationHistory&lt;br /&gt;
;Table.debugChat&lt;br /&gt;
:studio only - execute php code from chat, overriding won&#039;t work as it is called statically from table class&lt;br /&gt;
;Table.timeout&lt;br /&gt;
:studio only - can call from chat console to zombify current player&lt;br /&gt;
;Table.eliminatePlayer&lt;br /&gt;
:eliminate player, https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php&lt;br /&gt;
;Table.isAsync&lt;br /&gt;
:return true if game is turn based, false if realtime, undocumented (why?)&lt;br /&gt;
;Table.getTimeLimits static&lt;br /&gt;
:internal framework function, do not call or override&lt;br /&gt;
;Table.getAsyncTimeLimits&lt;br /&gt;
:return time limits for turn based games&lt;br /&gt;
;Table.checkAsyncActivePlayersChange&lt;br /&gt;
:framework internal check action, do not call or override&lt;br /&gt;
;Table.upgradeTableDb&lt;br /&gt;
:override to perform db upgrade, see game template, also some notes in https://en.doc.boardgamearena.com/Post-release_phase&lt;br /&gt;
;Table.getReplayPoints&lt;br /&gt;
;Table.saveReplayPoint&lt;br /&gt;
;Table.undoAndReplayInit&lt;br /&gt;
;Table.removeAutoIncrementFromTable&lt;br /&gt;
:@deprecated&lt;br /&gt;
;Table.getFieldsListOfTable&lt;br /&gt;
:do not use or override, framework internal method to return columns of table&lt;br /&gt;
;Table.undoInit&lt;br /&gt;
;Table.undoSavepoint&lt;br /&gt;
:Instruction to save database state after current transaction is complete [[Main game logic: yourgamename.game.php#Undo moves]]&lt;br /&gt;
;Table.doUndoSavePoint&lt;br /&gt;
:do not call directly&lt;br /&gt;
;Table.undoRestorePoint&lt;br /&gt;
:Restore database from save point [[Main game logic: yourgamename.game.php#Undo moves]]&lt;br /&gt;
;Table.showTutorial&lt;br /&gt;
:do not call directly&lt;br /&gt;
;Table.seenTutorial&lt;br /&gt;
:do not call directly&lt;br /&gt;
;Table.activeTutorial&lt;br /&gt;
:do not call directly&lt;br /&gt;
;Table.forceGameTournamendEnd&lt;br /&gt;
:do not call directly&lt;br /&gt;
;Table.showCursor&lt;br /&gt;
;Table.showCursorClick&lt;br /&gt;
:undocumented, probably to share the cursor for demo/training &lt;br /&gt;
;Table.storeLegacyData&lt;br /&gt;
:API for campain games see [[Main game logic: yourgamename.game.php#Legacy games API]]&lt;br /&gt;
;Table.storeLegacyTeamData&lt;br /&gt;
:API for campain games see [[Main game logic: yourgamename.game.php#Legacy games API]]&lt;br /&gt;
;Table.retrieveLegacyData&lt;br /&gt;
:API for campain games see [[Main game logic: yourgamename.game.php#Legacy games API]]&lt;br /&gt;
;Table.retrieveLegacyTeamData&lt;br /&gt;
:API for campain games see [[Main game logic: yourgamename.game.php#Legacy games API]]&lt;br /&gt;
;Table.removeLegacyData&lt;br /&gt;
:API for campain games see [[Main game logic: yourgamename.game.php#Legacy games API]]&lt;br /&gt;
;Table.removeLegacyTeamData&lt;br /&gt;
:API for campain games see [[Main game logic: yourgamename.game.php#Legacy games API]]&lt;br /&gt;
&lt;br /&gt;
== Methods in the APP_GameClass class ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;APP_GameClass.getNewUnique&lt;br /&gt;
;APP_GameClass.getNew&lt;br /&gt;
;APP_GameClass.notifyNow&lt;br /&gt;
&lt;br /&gt;
== Methods in the APP_DbObject class ==&lt;br /&gt;
&lt;br /&gt;
;APP_DbObject.ConnectDb static&lt;br /&gt;
;APP_DbObject.DbQuery static&lt;br /&gt;
:main query method, see https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Accessing_the_database&lt;br /&gt;
;APP_DbObject.DbTraceTimeBefore static&lt;br /&gt;
;APP_DbObject.DbTraceTimeAfter static&lt;br /&gt;
;APP_DbObject.DbGetLastId static&lt;br /&gt;
;APP_DbObject.DbDumpQueryHistory static&lt;br /&gt;
;APP_DbObject.DbAffectedRow static&lt;br /&gt;
;APP_DbObject.DbStartTransaction static&lt;br /&gt;
;APP_DbObject.DbCommit static&lt;br /&gt;
;APP_DbObject.DbRollback static&lt;br /&gt;
;APP_DbObject.DbRestartTransaction static&lt;br /&gt;
;APP_DbObject.DbSelect static&lt;br /&gt;
;APP_DbObject.CommitAllAndRestart static&lt;br /&gt;
;APP_DbObject.setDeadlockMode&lt;br /&gt;
;APP_DbObject.isDeadlockModeRetry&lt;br /&gt;
;APP_DbObject.enableMultiQueries&lt;br /&gt;
;APP_DbObject.sendMultiQueries&lt;br /&gt;
;APP_DbObject.escapeStringForDB&lt;br /&gt;
;APP_DbObject.getCollectionFromDB&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Accessing_the_database&lt;br /&gt;
;APP_DbObject.getNonEmptyCollectionFromDB&lt;br /&gt;
;APP_DbObject.getDoubleKeyCollectionFromDB&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Accessing_the_database&lt;br /&gt;
;APP_DbObject.getUniqueValueFromDB&lt;br /&gt;
;APP_DbObject.mysql_fetch_row&lt;br /&gt;
;APP_DbObject.mysql_fetch_assoc&lt;br /&gt;
;APP_DbObject.mysql_query&lt;br /&gt;
;APP_DbObject.getObjectFromDB&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Accessing_the_database&lt;br /&gt;
;APP_DbObject.getNonEmptyObjectFromDB&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Accessing_the_database&lt;br /&gt;
;APP_DbObject.getObjectListFromDB&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Accessing_the_database&lt;br /&gt;
;APP_DbObject.getSelectedDb static&lt;br /&gt;
;APP_DbObject.sqlParsing&lt;br /&gt;
;APP_DbObject.DbUsePrefix&lt;br /&gt;
;APP_DbObject.applyPrefix&lt;br /&gt;
;APP_DbObject.cache_store static&lt;br /&gt;
;APP_DbObject.cache_add static&lt;br /&gt;
;APP_DbObject.cache_exists static&lt;br /&gt;
;APP_DbObject.cache_fetch static&lt;br /&gt;
;APP_DbObject.cache_delete static&lt;br /&gt;
;APP_DbObject.cache_rollback static&lt;br /&gt;
;APP_DbObject.cache_commit static&lt;br /&gt;
;APP_DbObject.ensure_enough_time_since_last_action&lt;br /&gt;
;APP_DbObject.getMasterNodeDomain&lt;br /&gt;
;APP_DbObject.getMasterNodeUrl&lt;br /&gt;
;APP_DbObject.masterNodeRequest&lt;br /&gt;
;APP_DbObject.gameserverNodeRequest&lt;br /&gt;
;APP_DbObject.gameserverNodeRequestNoTable&lt;br /&gt;
;APP_DbObject.bgaCallUrl&lt;br /&gt;
&lt;br /&gt;
== Methods in the APP_Object class ==&lt;br /&gt;
;APP_Object.watch&lt;br /&gt;
:@deprecated, do not use (noop)&lt;br /&gt;
;APP_Object.debug&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Practical_debugging&lt;br /&gt;
;APP_Object.trace&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Practical_debugging&lt;br /&gt;
;APP_Object.warn&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Practical_debugging&lt;br /&gt;
;APP_Object.error&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Practical_debugging&lt;br /&gt;
;APP_Object.dump&lt;br /&gt;
:see https://en.doc.boardgamearena.com/Practical_debugging&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Selected static methods in utility modules ==&lt;br /&gt;
;bga_rand&lt;br /&gt;
:recommended for randomness (dice rolls, etc), see [[Main game logic: yourgamename.game.php#About random and randomness]]&lt;br /&gt;
;shuffle_with_keys&lt;br /&gt;
:shuffle array with keys (basically shuffle keys and keep linked values), it shuffle argument, does not return anything&lt;br /&gt;
;totranslate&lt;br /&gt;
:returns its argument, used for MARKING of string for server strings https://en.doc.boardgamearena.com/Translations&lt;br /&gt;
;clienttranslate&lt;br /&gt;
:returns its argument, used for MARKING of string for client strings https://en.doc.boardgamearena.com/Translations&lt;br /&gt;
;_&lt;br /&gt;
:this is not the same as self::_, it is also translation function but only can translate mainsite strings, do not use in game code&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpforex&amp;diff=14198</id>
		<title>Gamehelpforex</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpforex&amp;diff=14198"/>
		<updated>2022-07-29T01:39:09Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* RESOLVE */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= FOR-EX GAME SUMMARY =&lt;br /&gt;
&lt;br /&gt;
== SPOT TRANSACTION== &lt;br /&gt;
&lt;br /&gt;
Before taking your action for your turn, you may, but are not required to, perform one Spot Transaction with another player, trading 1 buck of any currency for its equivalent in another, or vice-versa.&lt;br /&gt;
&lt;br /&gt;
== MAKE A CONTRACT ==&lt;br /&gt;
&lt;br /&gt;
Take the next available set of Contract cards, placing one in front of yourself, one at the back of the Contract Queue, and leaving the last in the Contract Display. To the left of this last card, place the amount (taken from the Bank) that you wish to pay. To its right, place the equivalent amount in the other currency. The amount of the Stronger Currency must be a whole number, and cannot be in excess of ten bucks.&lt;br /&gt;
&lt;br /&gt;
== INVEST ==&lt;br /&gt;
&lt;br /&gt;
Buy one or two certificates for 2 bucks each of the relevant currencies. You cannot buy two certificates for the same currency in a single action, nor can you have more than four certificates in a single currency at one time. Any currencies that are invested in are &#039;&#039;&#039;strengthened&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== DIVEST ==&lt;br /&gt;
&lt;br /&gt;
Sell one or more certificates of a single type, removing those certificates from the game and receiving 2 bucks of that currency for each certificate divested. As part of your turn, clockwise around the table, each other player has the opportunity to divest certificates of the same type, likewise receiving 2 bucks of that currency and removing the certificate from the game. The divested currency is weakened &#039;&#039;&#039;once for each certificate that is divested&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== RESOLVE ==&lt;br /&gt;
&lt;br /&gt;
Resolve the front item in the Contract Queue:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* If the front item is a Contract, the player who created it must pay the amount to the left of the Contract, and receive the amount to its right.  If they cannot pay, they still receive the amount to its right, and the Contract converts to a Loan, with the amount owed increased by +1.  The Loan moves to the back of the Contract Queue, with the player who created the Contract now responsible for the Loan. If the player already has a Loan in the Contract Queue, the new Loan is combined with the previous Loan; all combined Loans must be paid off at the same time.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* If the front item is a Loan, the player who is responsible for the Loan must pay the amount owed.  If the Loan cannot be repaid, the player is Bankrupt and the game immediately ends.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* If the front item is a Dividend, players earn 0, 2, or 3 bucks of a given currency for each Certificate they hold in that currency, as shown on the Dividend card.  If a Currency has any counters on the &amp;quot;8&amp;quot; space, Certificates for that Currency pay nothing.  After making payouts, determine which Currency has the most Certificates currently in player hands: &#039;&#039;&#039;that Currency is Strengthened&#039;&#039;&#039;. If multiple Currencies qualify, the acting player chooses one Currency from among the tied Currencies. When the final Dividend is Resolved, there are no more player turns; instead, the remaining items in the Contract Queue are Resolved in order.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If either a Contract or a Loan is paid off, all associated Contract cards return to the contract display and can be used again.&lt;br /&gt;
&lt;br /&gt;
== STRENGTHENING/WEAKENING ==&lt;br /&gt;
&lt;br /&gt;
Currencies are Strengthened:&lt;br /&gt;
* each time it is Invested in.&lt;br /&gt;
* when, after Resolving a Dividend, it has the most Certificates in player hands.&lt;br /&gt;
&lt;br /&gt;
Currencies are Weakened:&lt;br /&gt;
* each time it is Divested in.&lt;br /&gt;
&lt;br /&gt;
== GAME END ==&lt;br /&gt;
&lt;br /&gt;
The game ends when one of the following occurs:&lt;br /&gt;
* Any player goes Bankrupt.&lt;br /&gt;
* There are no items left in the Contract Queue.&lt;br /&gt;
&lt;br /&gt;
Determine which Currency is Strongest (the stronger half of the most Currency Pairs); if there is a tie, the tied Currency with the most Certificates in player hands is the Strongest; if a tie persists, the player who last took a turn decides which of those tied Currencies is Strongest. All players convert all monies to that Currency, rounding any fractions down. The player with the most money wins.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpforex&amp;diff=14197</id>
		<title>Gamehelpforex</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpforex&amp;diff=14197"/>
		<updated>2022-07-29T01:36:57Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= FOR-EX GAME SUMMARY =&lt;br /&gt;
&lt;br /&gt;
== SPOT TRANSACTION== &lt;br /&gt;
&lt;br /&gt;
Before taking your action for your turn, you may, but are not required to, perform one Spot Transaction with another player, trading 1 buck of any currency for its equivalent in another, or vice-versa.&lt;br /&gt;
&lt;br /&gt;
== MAKE A CONTRACT ==&lt;br /&gt;
&lt;br /&gt;
Take the next available set of Contract cards, placing one in front of yourself, one at the back of the Contract Queue, and leaving the last in the Contract Display. To the left of this last card, place the amount (taken from the Bank) that you wish to pay. To its right, place the equivalent amount in the other currency. The amount of the Stronger Currency must be a whole number, and cannot be in excess of ten bucks.&lt;br /&gt;
&lt;br /&gt;
== INVEST ==&lt;br /&gt;
&lt;br /&gt;
Buy one or two certificates for 2 bucks each of the relevant currencies. You cannot buy two certificates for the same currency in a single action, nor can you have more than four certificates in a single currency at one time. Any currencies that are invested in are &#039;&#039;&#039;strengthened&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== DIVEST ==&lt;br /&gt;
&lt;br /&gt;
Sell one or more certificates of a single type, removing those certificates from the game and receiving 2 bucks of that currency for each certificate divested. As part of your turn, clockwise around the table, each other player has the opportunity to divest certificates of the same type, likewise receiving 2 bucks of that currency and removing the certificate from the game. The divested currency is weakened &#039;&#039;&#039;once for each certificate that is divested&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== RESOLVE ==&lt;br /&gt;
&lt;br /&gt;
Resolve the front item in the Contract Queue:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* If the front item is a Contract, the player who created it must pay the amount to the left of the Contract, and receive the amount to its right.  If they cannot pay, they still receive the amount to its right, and the Contract converts to a Loan, with the amount owed increased by +1.  The Loan moves to the back of the Contract Queue, with the player who created the Contract now responsible for the Loan. If the player already has a Loan in the Contract Queue, the new Loan is combined with the previous Loan, and all Loans be paid off at the same time.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* If the front item is a Loan, the player who is responsible for the Loan must pay the amount owed.  If the Loan cannot be repaid, the player is Bankrupt and the game immediately ends.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* If the front item is a Dividend, players earn 0, 2, or 3 bucks of a given currency for each Certificate they hold in that currency, as shown on the Dividend card.  If a Currency has any counters on the &amp;quot;8&amp;quot; space, Certificates for that Currency pay nothing.  After making payouts, determine which Currency has the most Certificates currently in player hands: &#039;&#039;&#039;that Currency is Strengthened&#039;&#039;&#039;. If multiple Currencies qualify, the acting player chooses one Currency from among the tied Currencies. When the final Dividend is Resolved, there are no more player turns; instead, the remaining items in the Contract Queue are Resolved in order.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If either a Contract or a Loan is paid off, all associated Contract cards return to the contract display and can be used again.&lt;br /&gt;
&lt;br /&gt;
== STRENGTHENING/WEAKENING ==&lt;br /&gt;
&lt;br /&gt;
Currencies are Strengthened:&lt;br /&gt;
* each time it is Invested in.&lt;br /&gt;
* when, after Resolving a Dividend, it has the most Certificates in player hands.&lt;br /&gt;
&lt;br /&gt;
Currencies are Weakened:&lt;br /&gt;
* each time it is Divested in.&lt;br /&gt;
&lt;br /&gt;
== GAME END ==&lt;br /&gt;
&lt;br /&gt;
The game ends when one of the following occurs:&lt;br /&gt;
* Any player goes Bankrupt.&lt;br /&gt;
* There are no items left in the Contract Queue.&lt;br /&gt;
&lt;br /&gt;
Determine which Currency is Strongest (the stronger half of the most Currency Pairs); if there is a tie, the tied Currency with the most Certificates in player hands is the Strongest; if a tie persists, the player who last took a turn decides which of those tied Currencies is Strongest. All players convert all monies to that Currency, rounding any fractions down. The player with the most money wins.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Stock&amp;diff=13996</id>
		<title>Stock</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Stock&amp;diff=13996"/>
		<updated>2022-07-15T02:32:08Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Customize apperance */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Stock&#039;&#039;&#039; is a javascript component that you can use in your game interface to display a set of elements of the same size that need to be arranged in single or multiple lines.&lt;br /&gt;
&lt;br /&gt;
Stock is very flexible and is the most used component in BGA games.&lt;br /&gt;
&lt;br /&gt;
Examples of stock use cases:&lt;br /&gt;
&lt;br /&gt;
* Display a set of cards, typically hands (examples: &#039;&#039;Hearts&#039;&#039;, &#039;&#039;Seasons&#039;&#039;, &#039;&#039;The Boss&#039;&#039;, &#039;&#039;Race for the Galaxy&#039;&#039;).&lt;br /&gt;
* Display items in player panels (examples: &#039;&#039;Takenoko&#039;&#039;, &#039;&#039;Amyitis&#039;&#039;, ...)&lt;br /&gt;
* ... Many other situations. For example, black dice and cubes on cards in &#039;&#039;Troyes&#039;&#039; are displayed with stock components.&lt;br /&gt;
&lt;br /&gt;
Using stock:&lt;br /&gt;
&lt;br /&gt;
* Your items are arranged nicely and sorted by type.&lt;br /&gt;
* When adding or removing items to a set, all items slide smoothly to their new position in the set.&lt;br /&gt;
* Selecting and unselecting items are built-in functions.&lt;br /&gt;
* You don&#039;t have to worry about inserting/removing HTML code; the entire life cycle of the stock is managed by the component.&lt;br /&gt;
&lt;br /&gt;
== Using stock: a simple example ==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s have a look on how the stock is used in the game &#039;&#039;Hearts&#039;&#039; to display a hand of standard cards.&lt;br /&gt;
&lt;br /&gt;
First, don&#039;t forget to add &amp;quot;ebg/stock&amp;quot; as a dependency in your js file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;     /// &amp;lt;==== HERE&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The stock is initialized in the Javascript &amp;quot;setup&amp;quot; method like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Player hand&lt;br /&gt;
    this.playerHand = new ebg.stock();&lt;br /&gt;
    this.playerHand.create( this, $(&#039;myhand&#039;), this.cardwidth, this.cardheight );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanations:&lt;br /&gt;
* We create a new stock object for the player hand.&lt;br /&gt;
* As parameters of the &amp;quot;create&amp;quot; method, we provide the width/height of an item (a card), and the div container &amp;quot;myhand&amp;quot; - which is a simple empty &amp;quot;div&amp;quot; element defined in our HTML template (.tpl).&lt;br /&gt;
&lt;br /&gt;
Then, we must tell the stock what items it is going to display during its life: the 52 cards of a standard card game. Of course, we did not create 52 different images, but a &amp;quot;CSS sprite&amp;quot; image named &amp;quot;cards.jpg&amp;quot; with the cards arranged in 4 rows and 13 columns.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we tell stock what items to display:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Specify that there are 13 images per row in the CSS sprite image&lt;br /&gt;
    this.playerHand.image_items_per_row = 13;&lt;br /&gt;
&lt;br /&gt;
    // Create card types:&lt;br /&gt;
    for( var color=1;color&amp;lt;=4;color++ )&lt;br /&gt;
    {&lt;br /&gt;
        for( var value=2;value&amp;lt;=14;value++ )&lt;br /&gt;
        {&lt;br /&gt;
            // Build card type id&lt;br /&gt;
            var card_type_id = this.getCardUniqueId( color, value );&lt;br /&gt;
            this.playerHand.addItemType( card_type_id, card_type_id, g_gamethemeurl+&#039;img/cards.jpg&#039;, card_type_id );&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanation:&lt;br /&gt;
&lt;br /&gt;
* First, we tell the stock component that our CSS sprite contains 13 items per row. This way, it can find the correct image for each card type id.&lt;br /&gt;
* Then for the 4x13 cards, we call the &amp;quot;addItemType&amp;quot; method that creates the type. The arguments are the type id, the weight of the card (for sorting purpose), the URL of our CSS sprite, and the position of our card image in the CSS sprite.&lt;br /&gt;
&lt;br /&gt;
Note: In this specific example we need to generate a unique ID for each type of card based on its color and value. This is the only purpose of &amp;quot;getCardUniqueId&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
From now on, if we need to add a card - for example, the 5 of Hearts - to a player&#039;s hand, we can do this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.playerHand.addToStock( this.getCardUniqueId( 2 /* 2=hearts */, 5 ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In reality, cards have some IDs, which are useful to manipulate them. This is the reason we are using &amp;quot;addToStockWithId&amp;quot; instead:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.playerHand.addToStockWithId( this.getCardUniqueId( 2 /* 2=hearts */, 5 ), my_card_id );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If afterwards we want to remove this card from the stock:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.playerHand.removeFromStockById( my_card_id );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Complete stock component reference ==&lt;br /&gt;
&lt;br /&gt;
=== Creation ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;create( page, container_div, item_width, item_height ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With create, you create a new stock component.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
* page: the container page. Usually: &amp;quot;this&amp;quot;.&lt;br /&gt;
* container_div: the container &amp;quot;div&amp;quot; element (an empty div element in your template, with an id).&lt;br /&gt;
* width and height (in pixels) for the stock component.&lt;br /&gt;
&lt;br /&gt;
(See &#039;&#039;Hearts&#039;&#039; example above).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;addItemType( type, weight, image, image_position ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Define a new type of item and add it to the stock.&lt;br /&gt;
&lt;br /&gt;
This is mandatory to define a new item type before adding it to the stock. Example: if you want to have a stock contain cubes of 3 different colors, you must add 3 item types (one for each color).&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
* {int} type: id of the type to add. You can choose any positive integer. All item types must have distinct IDs.&lt;br /&gt;
* {int} weight: weight of items of this type. Weight value is used to sort items of the stock during the display. Note that you can specify the same weight for all items; in this case, they are not sorted and their order might change randomly at any time.&lt;br /&gt;
* {string} image: URL of item image. Most of the time, you will use a CSS sprite for stock items, so you have to specify CSS sprite image here.&lt;br /&gt;
&lt;br /&gt;
Be careful: you must specify the image url as this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  g_gamethemeurl+&#039;img/yourimage.png&#039;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* image_position: if &amp;quot;image&amp;quot; specify the URL of a CSS sprite, you must specify the position of the item image in this CSS sprite. For example, if you have a CSS sprite with 3 cubes with a size of 20x20 pixels each (so your CSS image has for example a size of 20x60 or 60x20), you specify &amp;quot;0&amp;quot; for the first cube image, 1 for the second, 2 for the third.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Important&#039;&#039;: if there is more than one line of items in your CSS sprite,  you must specify how many items per line you have in your CSS sprite, see image_items_per_row below:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;image_items_per_row&#039;&#039;&#039;&lt;br /&gt;
Class member to set number of columns in css sprite (or how many items per row). I.e. if you sprite is 4 cards horizontally and 6 vertically, you have to set it to 4.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Specify that there are 10 image items per row in images used in &amp;quot;myStockObject&amp;quot; control.&lt;br /&gt;
    this.myStockObject.image_items_per_row = 4;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Add/Remove items ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;addToStock( type, from )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an item to the stock, with the specified type, but without a unique ID.&lt;br /&gt;
&lt;br /&gt;
To make your life easier, in most cases we suggest you use &#039;&#039;&#039;addToStockWithId&#039;&#039;&#039; in order to give an ID to the item added. &#039;&#039;&#039;addToStock&#039;&#039;&#039; is suitable when you are using a stock to control items that are generic game materials that don&#039;t need to be tracked individually (example: a bunch of money tokens).&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
* type: ID of the item type to use (as specified in &amp;quot;addItemType&amp;quot;)&lt;br /&gt;
* from: OPTIONAL: if you specify an HTML item here, the item will appear on this item and will be slid to its position on the stock item.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Add a money token to the &amp;quot;player money&amp;quot; stock.&lt;br /&gt;
  // The money token will appear on &amp;quot;player_id&amp;quot; player panel and will move to its position.&lt;br /&gt;
  this.playerMoney.addToStock( MONEY_TOKEN, &#039;overall_player_board_&#039;+player_id );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Important: for a given stock control, you must use either &#039;&#039;&#039;addToStock&#039;&#039;&#039; or &#039;&#039;&#039;addToStockWithId&#039;&#039;&#039;, but NEVER BOTH OF THEM.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;addToStockWithId( type, id, from )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is the same method as &#039;&#039;&#039;addToStock&#039;&#039;&#039;, except that it also associates an ID with the newly created item.&lt;br /&gt;
&lt;br /&gt;
This is especially useful:&lt;br /&gt;
&lt;br /&gt;
* When you need to know which item(s) have been selected by the user (see &#039;&#039;&#039;getSelectedItems&#039;&#039;&#039;).&lt;br /&gt;
* When you need to remove a specific item from the stock with &#039;&#039;&#039;removeFromStockById&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;removeFromStock( type, to, noupdate )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove an item of the specific type from the stock.&lt;br /&gt;
&lt;br /&gt;
&#039;to&#039; is an optional parameter. If &amp;quot;to&amp;quot; contains the ID of an HTML element, the item removed from the Stock slides to this HTML element before it disappears. Note that this method does not expose the associated animation object, however, so it&#039;s not possible to trigger other actions when it finishes, for example. If you need to do that, use Dojo&#039;s slideToObject() instead.&lt;br /&gt;
&lt;br /&gt;
&#039;noupdate&#039; is an optional parameter. If set to &amp;quot;true&amp;quot; it will prevent the Stock display from changing. This is useful when multiple (but not all) items are removed at the same time, to avoid ghost items appearing briefly. If you pass noupdate you have to call updateDisplay() after all items are removed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;removeFromStockById( id, to, noupdate )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove an item with a specific ID from the stock.&lt;br /&gt;
&lt;br /&gt;
&#039;to&#039; is an optional parameter. If &amp;quot;to&amp;quot; contains the ID of an HTML element, the item removed from the Stock slides to this HTML element before it disappears. Note that this method does not expose the associated animation object, however, so it&#039;s not possible to trigger other actions when it finishes, for example. If you need to do that, use Dojo&#039;s slideToObject() instead.&lt;br /&gt;
&lt;br /&gt;
&#039;noupdate&#039; is an optional parameter. If set to &amp;quot;true&amp;quot; it will prevent the Stock display from changing. This is useful when multiple (but not all) items are removed at the same time, to avoid ghost items appearing briefly. If you pass noupdate you have to call updateDisplay() after all items are removed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;removeAll()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove all items from the stock.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;removeAllTo( to )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove all items from the stock. If &amp;quot;to&amp;quot; contains the ID of an HTML element, the item removed from the stock slides to this HTML element before it disappears.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Getters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getPresentTypeList()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return an array with all the types of items present in the stock right now.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.myStockControl.removeAll();&lt;br /&gt;
    this.myStockControl.addToStock( 65 );&lt;br /&gt;
    this.myStockControl.addToStock( 34 );&lt;br /&gt;
    this.myStockControl.addToStock( 89 );&lt;br /&gt;
    this.myStockControl.addToStock( 65 );&lt;br /&gt;
    &lt;br /&gt;
    // The following returns: { 34:1,  65:1,  89:1  }&lt;br /&gt;
    var item_types = this.myStockControl.getPresentTypeList();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;count():&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return the total number of items in the stock right now.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getAllItems()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get all items (same format as getSelectedItems and getUnselectedItems).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getItemDivId(id)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the div id using the stock item id (to manipulate element properties directly).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getItemById(id)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the Stock item with the id in parameter&lt;br /&gt;
ex : return the object { type:1,  id:  1001 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selection ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setSelectionMode( mode )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each stock control, you can specify a selection mode:&lt;br /&gt;
* 0: no item can be selected by the player.&lt;br /&gt;
* 1: a maximum of one item can be selected by the player at a time.&lt;br /&gt;
* 2 (default): multiple items can be selected by the player at the same time.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setSelectionAppearance( type )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each stock control, you can specify a selection highlighting type:&lt;br /&gt;
* &#039;border&#039;: there will be a red border around selected items (this is the default). The attribute &#039;apparenceBorderWidth&#039; can be used to manage the width of the border (in pixels).&lt;br /&gt;
* &#039;disappear&#039;: the selected item will fade out and disappear. This is useful when the selection has the effect of destroying the item.&lt;br /&gt;
* &#039;class&#039;: there will be an extra &#039;&#039;&#039;stockitem_selected&#039;&#039;&#039; css class added to the element when it is selected (and removed when unselected). The name of the class can be changed by using the &#039;&#039;&#039;selectionClass&#039;&#039;&#039; attribute. You can also override the default class in the css file for your game but beware of the &#039;&#039;&#039;!important&#039;&#039;&#039; keyword.&lt;br /&gt;
&lt;br /&gt;
By default this class definition is:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.stockitem_selected {&lt;br /&gt;
	border: 2px solid red ! important;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to override it (for example, to change the border color) add this in your &amp;lt;game&amp;gt;.css file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.stockitem_selected {&lt;br /&gt;
	border: 2px solid orange ! important;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;isSelected( id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return a boolean indicating whether the specified item id has been selected.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;selectItem( id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Select the specified item.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;unselectItem( id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Unselect the specified item.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;unselectAll()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Unselect all items of the stock.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onChangeSelection&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This callback method is called when the player selects/unselects an item of the stock.&lt;br /&gt;
&lt;br /&gt;
You can connect this to one of your methods like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.connect( this.myStockControl, &#039;onChangeSelection&#039;, this, &#039;onMyMethodToCall&#039; );&lt;br /&gt;
    &lt;br /&gt;
    (...)&lt;br /&gt;
    &lt;br /&gt;
    onMyMethodToCall: function( control_name, item_id )&lt;br /&gt;
    {&lt;br /&gt;
        // This method is called when myStockControl selected items changed&lt;br /&gt;
        var items = this.myStockControl.getSelectedItems();&lt;br /&gt;
        &lt;br /&gt;
        // (do something)&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nota bene: &lt;br /&gt;
- The &amp;quot;control_name&amp;quot; argument is the ID (the &amp;quot;DOM&amp;quot; id) of the &amp;quot;div&amp;quot; container of your stock control. Using &amp;quot;control_name&amp;quot;, you can use the same callback method for different Stock control and see which one trigger the method.&lt;br /&gt;
- The &amp;quot;item_id&amp;quot; argument is the stock ID (index) of the stock item that has just been selected/unselected.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getSelectedItems()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return the list of selected items, as an array with the following format:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[&lt;br /&gt;
   { type:1,  id:  1001 },&lt;br /&gt;
   { type:1,  id:  1002 },&lt;br /&gt;
   { type:3,  id:  1003 }&lt;br /&gt;
   ...&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getUnselectedItems()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as the previous one, but return unselected item instead of seleted ones.&lt;br /&gt;
&lt;br /&gt;
=== Layout ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;resetItemsPosition()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you moved an item from the stock control manually (ex: after a drag&#039;n&#039;drop) and want to reset their positions to their original ones, you can call this method.&lt;br /&gt;
Note: it is the same as updateDisplay() without arugment, not sure why there are two methods.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;updateDisplay(from)&#039;&#039;&#039;&lt;br /&gt;
Update the display completely (if &#039;from&#039; is defined: moves new items from this location).&lt;br /&gt;
&lt;br /&gt;
Example code if you change the underlying stock item, or otherwise want to make the stock item refresh:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.myStockControl.updateDisplay();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;item_margin&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
By default, there is a margin of 5px between the items of a stock. You can change the member variable &amp;quot;item_margin&amp;quot; to change this.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     this.myStockControl.item_margin=5;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;changeItemsWeight( newWeights )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With this method you can change dynamically the weight of the item types in a stock control.&lt;br /&gt;
&lt;br /&gt;
Items are immediately re-sorted with the new weight.&lt;br /&gt;
&lt;br /&gt;
Example: with a stock control that contains classic cards, you can order them by value or by color. Using changeItemsWeight you can switch from one sort method to another when a player request this.&lt;br /&gt;
&lt;br /&gt;
newWeights is an associative array: item type id =&amp;gt; new weight.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Item type 1 gets a new weight of 10, 2 a new weight of 20, 3 a new weight of 30.&lt;br /&gt;
    this.myStockControl.changeItemsWeight( { 1: 10, 2: 20, 3: 30 } );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Be careful with object initialisers with variables, use the bracket notation.&lt;br /&gt;
    // Item type 1 gets a new weight of 10&lt;br /&gt;
    var card_type = 1;&lt;br /&gt;
    this.myStockControl.changeItemsWeight( { [card_type]: 10 } );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;centerItems&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Center the stock items in the middle of the stock container.&lt;br /&gt;
e.g. this.myStock.centerItems = true; &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setOverlap( horizontal_percent, vertical_percent )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Make items of the stock control &amp;quot;overlap&amp;quot; each other, to save space.&lt;br /&gt;
&lt;br /&gt;
By default, horizontal_overlap and vertical_overlap are 0.&lt;br /&gt;
&lt;br /&gt;
When horizontal_overlap=20, it means that a stock item will overlap to only show 20% of the width of all the previous items. horizontal_overlap can&#039;t be greater than 100.&lt;br /&gt;
&lt;br /&gt;
vertical_overlap works differently: one items on two are shifted up.&lt;br /&gt;
&lt;br /&gt;
See the games &amp;quot;Jaipur&amp;quot; or &amp;quot;Koryŏ&amp;quot; to see examples of use of this function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;autowidth&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Stock does not play well if you attempt to inline-block it with other blocks, to fix that you have to set this flag which will calculate width properly&lt;br /&gt;
   mystock.autowidth = true;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;resizeItems( width, height, background_width, background_height )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
background_width is an optional argument.&lt;br /&gt;
&lt;br /&gt;
background_height is an optional argument.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; stock.resizeItems(100, 120, 150, 170);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Customize Appearance ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;extraClasses&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Can be set to a list of class names (separated by space) on stock object, so when div is created these are added, i.e.&lt;br /&gt;
&lt;br /&gt;
  this.playerHand.extraClasses=&#039;mycard&#039;;&lt;br /&gt;
&lt;br /&gt;
Note that it is the same list for all items.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onItemCreate&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using onItemCreate, you can trigger a method each time a new item is added to the Stock, in order to customize it.&lt;br /&gt;
&lt;br /&gt;
Complete example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // During &amp;quot;setup&amp;quot; phase, we associate our method &amp;quot;setupNewCard&amp;quot; with the creation of a new stock item:&lt;br /&gt;
    this.myStockItem.onItemCreate = dojo.hitch( this, &#039;setupNewCard&#039; ); &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    // And here is our &amp;quot;setupNewCard&amp;quot;:&lt;br /&gt;
    setupNewCard: function( card_div, card_type_id, card_id )&lt;br /&gt;
    {&lt;br /&gt;
       // Add a special tooltip on the card:&lt;br /&gt;
       this.addTooltip( card_div.id, _(&amp;quot;Some nice tooltip for this item&amp;quot;), &#039;&#039; );&lt;br /&gt;
&lt;br /&gt;
       // Note that &amp;quot;card_type_id&amp;quot; contains the type of the item, so you can do special actions depending on the item type&lt;br /&gt;
&lt;br /&gt;
       // Add some custom HTML content INSIDE the Stock item:&lt;br /&gt;
       dojo.place( this.format_block( &#039;jstpl_my_card_content&#039;, {&lt;br /&gt;
                                ....&lt;br /&gt;
                           } ), card_div.id );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onItemDelete&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Function handler called when div is removed&lt;br /&gt;
&lt;br /&gt;
   this.myStock.onItemDelete = (card_div, card_type_id, card_id) =&amp;gt; { console.log(&amp;quot;card deleted from myStock: &amp;quot;+card_id); };&lt;br /&gt;
&lt;br /&gt;
== Tips when adding/removing items to/from Stock components ==&lt;br /&gt;
&lt;br /&gt;
Most cases will be one of the following situations:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Situation A&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
When you add a card to a stock item, and this card is &#039;&#039;&#039;not&#039;&#039;&#039; coming from another stock:&lt;br /&gt;
&lt;br /&gt;
* Use &#039;&#039;&#039;addToStockWithId&#039;&#039;&#039; with a &amp;quot;from&amp;quot; argument set to the element of your interface where the card should come from (i.e. div id). For example if you want to &amp;quot;reveal&amp;quot; card from player hand and it is not an interface element you can set from to be &#039;player_board_&#039;+activePlayerId (where activePlayerId is player who played that card).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Situation B&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
When you add a card to a stock item, and this card is coming from another stock:&lt;br /&gt;
&lt;br /&gt;
* On the destination Stock, use &#039;&#039;&#039;addToStockWithId&#039;&#039;&#039; with a &amp;quot;from&amp;quot; argument which is the HTML id of the corresponding item in the source Stock. For example, if the source stock id is &amp;quot;myHand&amp;quot;, then the HTML id of card 48 is &amp;quot;myHand_item_48&amp;quot;.&lt;br /&gt;
* Then, remove the source item with &#039;&#039;&#039;removeFromStockById&#039;&#039;&#039;. Note: do NOT set the &#039;to&#039; argument in this call, otherwise you&#039;ll get two animations.&lt;br /&gt;
&lt;br /&gt;
(Note that it&#039;s important to do things in this order, because the source item must still exist when you use it as the origin of the slide.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Situation C&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
When you move a card from a stock item to something that is not a stock item:&lt;br /&gt;
&lt;br /&gt;
* Insert the card as a classic HTML template (dojo.place / this.format_block).&lt;br /&gt;
* Place it on the Stock item with &#039;&#039;&#039;this.placeOnObject&#039;&#039;&#039;, using the Stock item HTML id (see above).&lt;br /&gt;
* Slide it to its new position with &#039;&#039;&#039;this.slideToObject&#039;&#039;&#039;.&lt;br /&gt;
* Remove the card from the Stock item with &#039;&#039;&#039;removeFromStockById&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Using the methods above, your cards should slide to, from, and between your Stock controls smoothly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can customize this (showing the default value):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
this.mystock.jstpl_stock_item= &amp;quot;&amp;lt;div id=\&amp;quot;${id}\&amp;quot; class=\&amp;quot;stockitem\&amp;quot; style=\&amp;quot;top:${top}px;left:${left}px;width:${width}px;height:${height}px;z-index:${position};background-image:url(&#039;${image}&#039;);\&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
To produce a different type of stock item&lt;br /&gt;
&lt;br /&gt;
== Known issues ==&lt;br /&gt;
&lt;br /&gt;
==== Incorrectly displayed sprites on Safari ====&lt;br /&gt;
&lt;br /&gt;
As mentioned above, stock displays its images using &amp;quot;sprites&amp;quot; consisting of a portion of a larger image. To accomplish this, it uses the CSS background-position attribute in negative multiples of 100%. For example, the first element of the first row would be 0% 0%. The second element of the first row would be -100% 0%, etc.&lt;br /&gt;
&lt;br /&gt;
This works fine except in Safari, which sometimes slightly modifies the width of elements at smaller screen sizes (usually when minimum width of &#039;game_interface_width&#039; is not null) in game. For example, you might get a ~49.99px x ~49.99px div instead of the 50px x 50px specified by CSS width/height. Combined with using percentages in background-position, this can cause sprites to be slightly off-center.&lt;br /&gt;
&lt;br /&gt;
Using pixels in background-position is probably the easiest way to fix this problem, but that would require modifying the stock code itself. As a developer, you can also work around the problem by specifying a background-size attribute based on the size in elements of your source image. For example, if you have a source image that contains 5 rows of 28 sprites, you should specify &amp;quot;background-size: 2800% 500%;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
You can add background-size to your stock items by using the extraClasses attribute as explained above and then specifying the values in your game.css file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=11980</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=11980"/>
		<updated>2022-02-20T19:11:23Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Method _ (underscore) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
== Localization Overview ==&lt;br /&gt;
&lt;br /&gt;
Localization for BGA games happens largely on the CLIENT. Games must be developed in English and English strings are sent to the client.&lt;br /&gt;
&lt;br /&gt;
It&#039;s only at the client that your English strings will be displayed with the translation for the user&#039;s language, when such a translation exists.&lt;br /&gt;
&lt;br /&gt;
For anyone who has worked on a system where translation happens at the server and localized strings are sent to the client: you must unlearn what you have learned. Just stick with English and send the untranslated English strings. The magic happens at the client.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== How will my strings be translated? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Once your game enters Beta, the BGA player community will descend upon your game like a plague of locusts and translate it into dozens of languages before you can say &amp;quot;Je ne parle pas anglais&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What do I have to do from a programming standpoint? ==&lt;br /&gt;
&lt;br /&gt;
Not as much as you think. Read on for full details, but the golden rules are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Make sure that any string on the server side that needs to be translated on the client side is wrapped in a clienttranslate() function when defined. For example: $my_response = clienttranslate(&#039;Hey translators, please translate this string&#039;). clienttranslate doesn&#039;t actually do anything at all (it just passes the text through) but the translation engine searches your code for strings wrapped in that function and uses them to build the list of strings that need to be translated.&lt;br /&gt;
# On the client side, just display your text, but wrap it in _().&lt;br /&gt;
## If you pass a string constant to _() - such as _(&#039;This is my string&#039;) then the parser will automatically detect and add your string to the list of strings that need to be translated, AND it will display the local translation for it when displaying.&lt;br /&gt;
## If you pass a variable to _() - such as _(args.my_message) then MAKE SURE that the variable is set to an English string that is either defined somewhere in your PHP code in a clienttranslate() function or somewhere else in your javascript code in a _() function. As long as it is, the translators will provide translations for it, and the _() function will display the local translation of your English string.&lt;br /&gt;
# A string used as the message for notifyAllPlayers or notifyPlayer will automatically have its translation displayed on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used as the &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; for a state in your state machine will also be automatically translated on the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a clienttranslate() on the server, so that it gets translated.&lt;br /&gt;
# A string used in the pre-games option screen will also automatically have any translation displayed at the client - you don&#039;t need to do anything EXCEPT make sure that it is wrapped in a totranslate() on the server (nota bene: you should not use clienttranslate() here as this file is processed specifically and those strings will not be included in the game translation file but in the main site translation file - with a prefix to keep translations isolated by module - as they have to be translated on main site pages. If you need exactly the same string in your game for a client side translation, it should be declared somewhere else in your code wrapped inside a clienttranslate() to be included in the game translation file.&lt;br /&gt;
# A string used in the statistics screen will operate like a string in the pre-game options screen. It will automatically have any translation displayed at the client as long as you make sure that it is wrapped in a totranslate() on the server.&lt;br /&gt;
# If you are using parameters for a call to notifyAllPlayers or notifyPlayers, or for a state&#039;s &amp;quot;description&amp;quot; or &amp;quot;descriptionmyturn&amp;quot; and those parameters contain text that needs to be translated, you will need to tell the system to display the translated versions of them by using the &#039;i18n&#039; argument. See below for full details.&lt;br /&gt;
&lt;br /&gt;
== What strings should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages.&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final period &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final period&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final period.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final period:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current actions in the status bar&lt;br /&gt;
** Final period:&lt;br /&gt;
*** complete sentences (e.g., explanations and descriptions) that can be chained with other sentences&lt;br /&gt;
** Either a period or no period is acceptable (but this should be consistent throughout the game) for:&lt;br /&gt;
*** isolated tooltips / small sentences&lt;br /&gt;
*** game logs (no period is usually preferable)&lt;br /&gt;
*** error messages (unless there is more than one sentence in the error message; final period is mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the published English rulebook and game materials.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* Try to reuse the exact same strings (with the same case, etc.) to minimize the number of strings to translate.&lt;br /&gt;
** &#039;&#039;&#039;Example&#039;&#039;&#039;: Consider replacing &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;self::_(&amp;quot;Winners&amp;quot;)&amp;lt;/pre&amp;gt; (two strings to translate) with &amp;lt;pre&amp;gt;self::_(&amp;quot;Winner(s)&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
** &#039;&#039;&#039;Example 2&#039;&#039;&#039;: &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;play a card&amp;quot;)&amp;lt;/pre&amp;gt; and &amp;lt;pre&amp;gt;clienttranslate(&amp;quot;Play a card&amp;quot;)&amp;lt;/pre&amp;gt; means there will be two strings to translate.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (e.g., if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The shorter the string is, the more difficult the task is for them. As a rule of thumb, try to avoid short, insignificant strings that require knowledge of their surrounding context. You can also leave a comment on the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar. We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; rather than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing elaborate strings like &amp;quot;With the effect of ZZZ, player XXX gains a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past. E.g., &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;.&lt;br /&gt;
* Avoid using gender-specific wording as much as possible. If needed be aware that [[https://forum.boardgamearena.com/viewtopic.php?f=11&amp;amp;t=19432&amp;amp;start=10#p88592 a pronoun replacement system]] is in place, and cannot work if your use &amp;quot;their&amp;quot; as a singular genderless pronoun, as it removes the information that it&#039;s singular. E.g., you should write &amp;quot;playerX returns card to *his* hand&amp;quot; or &amp;quot;playerX returns card to *his/her* hand&amp;quot; and not &amp;quot;playerX returns card to *their* hand&amp;quot; as in the 2 first case the system will substitute the proper pronoun his/her/their depending on playerX declared/undeclared gender, but in the second case it will always stay &amp;quot;their&amp;quot; whatever the player preference setting.&lt;br /&gt;
* Where two strings are identical apart from (say) a number, use the same string with a ${parameter}, and call format_string_recursive (on the client) or use args (for notifications and state descriptions) to provide the details. But *never* do that for composing multiple sentences with words: other languages have different grammar and it would most likely create untranslatable strings.&lt;br /&gt;
&lt;br /&gt;
== WARNING: Make sure your strings will be translated! ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool does a full scan of the code, looking for translation markers like &amp;quot;_()&amp;quot; or &amp;quot;clienttranslate()&amp;quot;. (See below for the full list of translation markers.)&lt;br /&gt;
&lt;br /&gt;
If your original string is not completely contained inside one of these markers, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not contained within a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Ditto&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
=== Function clienttranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &#039;string to translate&#039; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;transparent&#039;&#039;: it will return the original English string without any change. Its only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* In your &#039;&#039;&#039;states.inc.php&#039;&#039;&#039;, for the fields &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;material.inc.php&#039;&#039;&#039;, when defining text for game materials that must be displayed on the client side.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&#039;Amulet of Air&#039;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &#039;&#039;notifyAllPlayers&#039;&#039; or &#039;&#039;notifyPlayer&#039;&#039;, in the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&#039;Everyone draw cards from their library&#039;), [] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function. E.g.:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;;&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(notif),[]); // BAD&lt;br /&gt;
    &lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, notif,[]); // GOOD&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains ${num} gems&amp;quot;),[num=&amp;gt;2]); // BAD it is dynamic string enterpreted by php &lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&#039;player gains ${num} gems&#039;),[num=&amp;gt;2]); // GOOD, difference is single quotes&lt;br /&gt;
&lt;br /&gt;
    self::notifyAllPlayers( &#039;log&#039;, clienttranslate(&amp;quot;player gains &amp;quot;.${num}.&amp;quot; gems&amp;quot;),[num=&amp;gt;2]); // BAD concatenation &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. This uses the &#039;&#039;&#039;i18n&#039;&#039;&#039; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Fire&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using the &#039;&#039;&#039;i18n&#039;&#039;&#039; argument when translating arguments for the client: do NOT use same argument for both translations AND key codes for client-side actions (like using &#039;card_name&#039; to move it on the player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument names like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with &#039;&#039;clienttranslate&#039;&#039;, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Method _ (underscore) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
This can be used like self::_(&#039;bla&#039;) or this-&amp;gt;(&#039;bla&#039;). You cannot use static underscore function _(&#039;bla&#039;) in php, it is not the same, it will not translate strings from your game.&lt;br /&gt;
&lt;br /&gt;
The returned string will be surrounded by HTML tags, so you cannot use it in places where pure text is required or your string already has another html markup.&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following situations:&lt;br /&gt;
* Throwing user exceptions&lt;br /&gt;
* Creating the labels for the game interface used in your template&lt;br /&gt;
* Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions&lt;br /&gt;
* Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user&lt;br /&gt;
&lt;br /&gt;
Imporant! This function does two things:&lt;br /&gt;
* Mark string for translation&lt;br /&gt;
* Translates in runtime&lt;br /&gt;
As a consequence you absolutely cannot have $var in there! Or string concatenations.&lt;br /&gt;
I.e.&lt;br /&gt;
  $food=self::_(&amp;quot;Banana&amp;quot;);// good&lt;br /&gt;
  self::_(&amp;quot;User gives $food to a cat&amp;quot;); // bad&lt;br /&gt;
For the translator we will have two strings &amp;quot;Banana&amp;quot; and &amp;quot;User gives $food to a cat&amp;quot;, but in runtime we will be&lt;br /&gt;
&amp;quot;Banana&amp;quot; and &amp;quot;User gives Banana to a cat&amp;quot; and second string would not match anything. And this is as bad&lt;br /&gt;
  self::_(&amp;quot;User gives &amp;quot;.$food.&amp;quot; to a cat&amp;quot;);// bad&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Throwing an exception because the player did a forbidden move ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Creating labels ====&lt;br /&gt;
&lt;br /&gt;
In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Nota bene:&#039;&#039;&#039; it is recommended to set translated text in your interface client side rather than use template variables and server translation, so that translation works natively in replays (that don&#039;t have server side translations). For simple strings, the framework will handle moving the translation client side, but for more complex strings it may not work. In particular, you should not use server side translation for templates with substitution variables (or use the specific function &amp;quot;gameview_str_replace( $search, $replace, $string )&amp;quot; if not possible otherwise or for old code compatibility). Also, you should never use a &amp;quot;to_translate&amp;quot; class in your .tpl as it is used internally by the framework.&lt;br /&gt;
&lt;br /&gt;
Example with view.php:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;{EMPIRE_LABEL}&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in view.php:&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player_board&amp;quot;, array (&amp;quot;COLOR&amp;quot; =&amp;gt; $color,&amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $name,&amp;quot;PLAYER_NO&amp;quot; =&amp;gt; $no,&lt;br /&gt;
                &amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id, &amp;quot;CLASSES&amp;quot; =&amp;gt; $own?&amp;quot;own&amp;quot;:&amp;quot;&amp;quot;, &lt;br /&gt;
                &amp;quot;EMPIRE_LABEL&amp;quot; =&amp;gt; self::raw(gameview_str_replace(&#039;${player_name}&#039;, $name, self::_(&#039;${player_name}\&#039;s EMPIRE&#039;)))&lt;br /&gt;
              ));&lt;br /&gt;
Example with client side:&lt;br /&gt;
in .tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;empire_title_{COLOR}&amp;quot; class=&amp;quot;side_title color_{COLOR}&amp;quot;&amp;gt;Stub&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in .js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  for (var player_id in this.gamedatas.players) {&lt;br /&gt;
      var player_color = this.gamedatas.players[player_id].color;&lt;br /&gt;
      var player_name = this.gamedatas.players[player_id].name;&lt;br /&gt;
      $(&#039;empire_title_&#039;+player_color).innerHTML=this.format_string_recursive(_(&amp;quot;${player_name}&#039;s EMPIRE&amp;quot;), {player_name: player_name});&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Translating strings in material file ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you could also do this, so you don&#039;t need to pollute your material file&lt;br /&gt;
   throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.self::_($this-&amp;gt;energies[$resource_id][&#039;name&#039;]) );&lt;br /&gt;
&lt;br /&gt;
where $this-&amp;gt;energies[$resource_id][&#039;name&#039;] were marked in material file using regular clienttranslate function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;energies = [&lt;br /&gt;
      22 =&amp;gt; [&lt;br /&gt;
          &#039;name&#039; =&amp;gt; clienttranslate(&#039;Sun&#039;)&lt;br /&gt;
          ...&lt;br /&gt;
      ]&lt;br /&gt;
  ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Strings in getAllDatas ====&lt;br /&gt;
&lt;br /&gt;
Rarely, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
Note: not sure why would you send strings from the server in this case, as same can be achieved on the client usually.&lt;br /&gt;
&lt;br /&gt;
=== Function totranslate ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;br /&gt;
&lt;br /&gt;
== Top Secret Undocumented Features ==&lt;br /&gt;
&lt;br /&gt;
If your string contains the clause &#039;$${value}&#039; (such as &#039;You gain $${value}.&#039;) then the translation system seems to move the position of the $ to a localized location (eg $5 in English but 5$ in French). This only seems to occur when using the argument &#039;value&#039;.&lt;br /&gt;
&lt;br /&gt;
In JavaScript, you can get the current user&#039;s language by retrieving the translation for the special string &amp;quot;$locale&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
    var lang = _(&#039;$locale&#039;); // en, fr, etc.&lt;br /&gt;
&lt;br /&gt;
== On server side - advanced (PHP) ==&lt;br /&gt;
&lt;br /&gt;
If you want to use translation system in your custom static modules, you will first need to expose the _() function :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class mygame extends Table {&lt;br /&gt;
  // Exposing protected method translation&lt;br /&gt;
  public static function totranslate($text) {&lt;br /&gt;
    return self::_($text);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you&#039;ll be able to use this directly in other modules by doing&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate(&amp;quot;Translated error from my awesome module file&amp;quot;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notice how the &amp;quot;totranslate&amp;quot; is also used by the static analysis to detect your string. So the following will not work :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$msg = &amp;quot;Translated error from my awesome module file&amp;quot;;&lt;br /&gt;
throw new BgaUserException(mygame::totranslate($msg));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Analyze your project ==&lt;br /&gt;
&lt;br /&gt;
It looks super complex but there is help!&lt;br /&gt;
On studio control panel you can find a button &amp;quot;Check project&amp;quot; - it runs bunch of static analysis on your project including scanning for bad translations and missing translations.&lt;br /&gt;
It also will extact all you translation keys as translator will see them so you can double check - and run spell checker on them.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=10375</id>
		<title>BGA Code Sharing</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=10375"/>
		<updated>2021-11-27T23:07:39Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: Undo revision 10374 by AmadanNaBriona (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is for listing of externally hosted bga projects, tools and resources, as well as internal project&lt;br /&gt;
intended for sharing&lt;br /&gt;
&lt;br /&gt;
== Community shared components, pens, etc ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DESCRIPTION&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Dice models and animation&lt;br /&gt;
|-&lt;br /&gt;
| Die: 4 sided &lt;br /&gt;
| https://codepen.io/mrkiffie/pen/doVZgW&lt;br /&gt;
| code pen&lt;br /&gt;
|-&lt;br /&gt;
| Die: 6 sided &lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Code can be found in project&lt;br /&gt;
|-&lt;br /&gt;
| Die: 12 sided (dodecahedron) &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/xxLLxOP&lt;br /&gt;
| Code pen&lt;br /&gt;
|- &lt;br /&gt;
| Die: 20 sided &lt;br /&gt;
| https://codepen.io/vicentemundim/details/cenIh&lt;br /&gt;
| Code pen&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Moving object using CSS animation (mostly)&lt;br /&gt;
|-&lt;br /&gt;
| Phantom object move on oversurface &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/gORvdJo&lt;br /&gt;
| This technique creates clone of the object it moves it on another surface. It works well when parents that css transform applies such as scale and rotate&lt;br /&gt;
|-&lt;br /&gt;
| Move object directly using positioning &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/dyzgKVX&lt;br /&gt;
| This technique is modification of BGA framework method to allow mobile object not to have absolute position before or after the move (and uses css animation not dojo). Methods slideToObjectRelative, attachToNewObjectNoDestroy&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Responsive layout for game boards&lt;br /&gt;
|-&lt;br /&gt;
|Flex Layout&lt;br /&gt;
|https://codepen.io/VictoriaLa/pen/XWjJJgG&lt;br /&gt;
|Example on how to create flexible layout buy just using css&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects hosted not in studio ==&lt;br /&gt;
&lt;br /&gt;
See the table a link and nickname of the developer on bga (same as used for dev forum), and short description. See [[Tools_and_tips_of_BGA_Studio#Version_Control]] for some suggestions on how and where to publish your code externally. Also see the [https://github.com/topics/boardgamearena boardgamearena] tag on github.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important notice about artwork on BGA Open Source projects: original hi-resolution images from publishers must not be published on the repositories. In addition, it is better to specify that the images derivated from publishers artwork are copyrighted and cannot be licensed under a free license like Creative Commons.&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NON-GAME PROJECTS&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| BoardGameArena Workbench (not a game)&lt;br /&gt;
| https://github.com/danielholmes/bga-workbench&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
! GAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| 99 (Trick-taking Card Game)&lt;br /&gt;
| https://github.com/ekelly/bga-ninetynine&lt;br /&gt;
| QuasarDukeDev&lt;br /&gt;
|-&lt;br /&gt;
| Assyria &lt;br /&gt;
| https://github.com/sebastien-prudhomme/bga-assyria&lt;br /&gt;
| daikinee &lt;br /&gt;
|-&lt;br /&gt;
| Aura&lt;br /&gt;
| https://github.com/micahstairs/bga-aura&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Bandido &lt;br /&gt;
| https://github.com/opheliehb/BandidoBGA&lt;br /&gt;
| ophelopede &amp;amp; Harkle &lt;br /&gt;
|-&lt;br /&gt;
| The Battle for Hill 218&lt;br /&gt;
| https://github.com/danielholmes/battle-for-hill-218&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
| Bonbons&lt;br /&gt;
| https://github.com/AntonioSoler/bga-bonbons&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Coinche&lt;br /&gt;
| https://github.com/drasill/bga-coinche&lt;br /&gt;
| Draasill&lt;br /&gt;
|-&lt;br /&gt;
| Coup: City State&lt;br /&gt;
| https://github.com/quietmint/bga-coupcitystate&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dungeon Roll&lt;br /&gt;
| https://github.com/MartinGoulet/bga-dungeonroll&lt;br /&gt;
| MGoulet&lt;br /&gt;
|-&lt;br /&gt;
| Egyptian Ratscrew&lt;br /&gt;
| https://github.com/0BuRner/bga-egyptianratscrew&lt;br /&gt;
| 0BuRner&lt;br /&gt;
|-&lt;br /&gt;
| Eruption&lt;br /&gt;
| https://github.com/AndyKerrison/bga-eruption&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| A Fistful Of Gold&lt;br /&gt;
| https://bitbucket.org/Joel_L/fistfulofgold&lt;br /&gt;
| Brainchild&lt;br /&gt;
|-&lt;br /&gt;
| Florenza: The Card Game&lt;br /&gt;
| https://github.com/alberto-bottarini/bga-florenza&lt;br /&gt;
| tarini &lt;br /&gt;
|-&lt;br /&gt;
| Hearts &#039;&#039;&#039;(Tutorial)&#039;&#039;&#039;&lt;br /&gt;
| https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Homesteaders&lt;br /&gt;
| https://github.com/npatron/bga-homesteaders&lt;br /&gt;
| TheBoot&lt;br /&gt;
|-&lt;br /&gt;
| Incan Gold&lt;br /&gt;
| https://github.com/AntonioSoler/bga-incangold&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Innovation&lt;br /&gt;
| https://github.com/micahstairs/bga-innovation&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Mapmaker: The Gerrymandering Game&lt;br /&gt;
| https://github.com/gzhang01/bga-mapmaker&lt;br /&gt;
| gkz&lt;br /&gt;
|-&lt;br /&gt;
| Marco Polo&lt;br /&gt;
| https://github.com/rcitaliano/MarcoPolo&lt;br /&gt;
| rcitaliano&lt;br /&gt;
|-&lt;br /&gt;
| Nile&lt;br /&gt;
| https://github.com/AndyKerrison/bga-nile&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| Noir: Killer vs Inspector&lt;br /&gt;
| https://bitbucket.org/chhuang76/bga_noirkvi&lt;br /&gt;
| ch huang&lt;br /&gt;
|-&lt;br /&gt;
| Penny Press&lt;br /&gt;
| https://github.com/AdamNovotny/bga-blooms&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| P.I.&lt;br /&gt;
| https://gitlab.com/fa81/bga-pi, https://github.com/hellp/bga-pi (mirror)&lt;br /&gt;
| Fabian Neumann (fa81)&lt;br /&gt;
|-&lt;br /&gt;
| Santorini&lt;br /&gt;
| https://github.com/AntonioSoler/bga-santorini&lt;br /&gt;
| Morgalad, quietmint, Tisaac&lt;br /&gt;
|-&lt;br /&gt;
| Tablut&lt;br /&gt;
| https://github.com/Lucas-C/tablut&lt;br /&gt;
| Lucas-C &amp;amp; ntaffore&lt;br /&gt;
|-&lt;br /&gt;
| Takara Island&lt;br /&gt;
| https://github.com/AntonioSoler/bga-takaraisland&lt;br /&gt;
| Morgalad&lt;br /&gt;
|-&lt;br /&gt;
| Taluva&lt;br /&gt;
| https://github.com/quietmint/bga-taluva&lt;br /&gt;
| Morgalad &amp;amp; quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Teotihuacan: City of Gods&lt;br /&gt;
| https://github.com/Trompetenhut/bga-teotihuacan&lt;br /&gt;
| Trompetenhut&lt;br /&gt;
|-&lt;br /&gt;
| Texas 42 (domino game, still under development)&lt;br /&gt;
| https://github.com/ishermandom/bga-42&lt;br /&gt;
| Stardust Spikes, Jason Turner-Maier, Ilya Sherman&lt;br /&gt;
|-&lt;br /&gt;
| Uptown&lt;br /&gt;
| https://github.com/elliotkendall/bga-uptown&lt;br /&gt;
| SpottedShroom&lt;br /&gt;
|-&lt;br /&gt;
| Via Magica&lt;br /&gt;
| https://github.com/christopherburke/bga_viamagica&lt;br /&gt;
| CuriousTerran&lt;br /&gt;
|-&lt;br /&gt;
| Just Desserts&lt;br /&gt;
| https://github.com/mizutismask/bga-just-desserts&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| The King&#039;s Guild&lt;br /&gt;
| https://github.com/AdamNovotny/BGG-KingsGuild&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| Get the MacGuffin&lt;br /&gt;
| https://github.com/mizutismask/bga-get-the-MacGuffin&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| President&lt;br /&gt;
| https://github.com/quaresma95/president&lt;br /&gt;
| quaresma95&lt;br /&gt;
|-&lt;br /&gt;
| Hardback&lt;br /&gt;
| https://github.com/quietmint/bga-hardback&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dice Summoners&lt;br /&gt;
| https://github.com/eoincos/bga-dicesummoners&lt;br /&gt;
| eoincos&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects on studio ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Any developer can add themselves to a project as read-only from https://studio.boardgamearena.com/#!projects page (almost any project).&lt;br /&gt;
The list below are no-games which do not have bgg id and not showing up there.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code&lt;br /&gt;
| https://studio.boardgamearena.com/#!studiogame?game=sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Original BGA template&lt;br /&gt;
| https://studio.boardgamearena.com/#!studiogame?game=template&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other useful resources ==&lt;br /&gt;
&lt;br /&gt;
Moved to [[Tools_and_tips_of_BGA_Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=10374</id>
		<title>BGA Code Sharing</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=10374"/>
		<updated>2021-11-27T23:06:38Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: added Trick of the Rails&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is for listing of externally hosted bga projects, tools and resources, as well as internal project&lt;br /&gt;
intended for sharing&lt;br /&gt;
&lt;br /&gt;
== Community shared components, pens, etc ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DESCRIPTION&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Dice models and animation&lt;br /&gt;
|-&lt;br /&gt;
| Die: 4 sided &lt;br /&gt;
| https://codepen.io/mrkiffie/pen/doVZgW&lt;br /&gt;
| code pen&lt;br /&gt;
|-&lt;br /&gt;
| Die: 6 sided &lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Code can be found in project&lt;br /&gt;
|-&lt;br /&gt;
| Die: 12 sided (dodecahedron) &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/xxLLxOP&lt;br /&gt;
| Code pen&lt;br /&gt;
|- &lt;br /&gt;
| Die: 20 sided &lt;br /&gt;
| https://codepen.io/vicentemundim/details/cenIh&lt;br /&gt;
| Code pen&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Moving object using CSS animation (mostly)&lt;br /&gt;
|-&lt;br /&gt;
| Phantom object move on oversurface &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/gORvdJo&lt;br /&gt;
| This technique creates clone of the object it moves it on another surface. It works well when parents that css transform applies such as scale and rotate&lt;br /&gt;
|-&lt;br /&gt;
| Move object directly using positioning &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/dyzgKVX&lt;br /&gt;
| This technique is modification of BGA framework method to allow mobile object not to have absolute position before or after the move (and uses css animation not dojo). Methods slideToObjectRelative, attachToNewObjectNoDestroy&lt;br /&gt;
|-&lt;br /&gt;
! colspan=&amp;quot;3&amp;quot; | Responsive layout for game boards&lt;br /&gt;
|-&lt;br /&gt;
|Flex Layout&lt;br /&gt;
|https://codepen.io/VictoriaLa/pen/XWjJJgG&lt;br /&gt;
|Example on how to create flexible layout buy just using css&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects hosted not in studio ==&lt;br /&gt;
&lt;br /&gt;
See the table a link and nickname of the developer on bga (same as used for dev forum), and short description. See [[Tools_and_tips_of_BGA_Studio#Version_Control]] for some suggestions on how and where to publish your code externally. Also see the [https://github.com/topics/boardgamearena boardgamearena] tag on github.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important notice about artwork on BGA Open Source projects: original hi-resolution images from publishers must not be published on the repositories. In addition, it is better to specify that the images derivated from publishers artwork are copyrighted and cannot be licensed under a free license like Creative Commons.&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NON-GAME PROJECTS&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| BoardGameArena Workbench (not a game)&lt;br /&gt;
| https://github.com/danielholmes/bga-workbench&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
! GAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| 99 (Trick-taking Card Game)&lt;br /&gt;
| https://github.com/ekelly/bga-ninetynine&lt;br /&gt;
| QuasarDukeDev&lt;br /&gt;
|-&lt;br /&gt;
| Assyria &lt;br /&gt;
| https://github.com/sebastien-prudhomme/bga-assyria&lt;br /&gt;
| daikinee &lt;br /&gt;
|-&lt;br /&gt;
| Aura&lt;br /&gt;
| https://github.com/micahstairs/bga-aura&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Bandido &lt;br /&gt;
| https://github.com/opheliehb/BandidoBGA&lt;br /&gt;
| ophelopede &amp;amp; Harkle &lt;br /&gt;
|-&lt;br /&gt;
| The Battle for Hill 218&lt;br /&gt;
| https://github.com/danielholmes/battle-for-hill-218&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
| Bonbons&lt;br /&gt;
| https://github.com/AntonioSoler/bga-bonbons&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Coinche&lt;br /&gt;
| https://github.com/drasill/bga-coinche&lt;br /&gt;
| Draasill&lt;br /&gt;
|-&lt;br /&gt;
| Coup: City State&lt;br /&gt;
| https://github.com/quietmint/bga-coupcitystate&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dungeon Roll&lt;br /&gt;
| https://github.com/MartinGoulet/bga-dungeonroll&lt;br /&gt;
| MGoulet&lt;br /&gt;
|-&lt;br /&gt;
| Egyptian Ratscrew&lt;br /&gt;
| https://github.com/0BuRner/bga-egyptianratscrew&lt;br /&gt;
| 0BuRner&lt;br /&gt;
|-&lt;br /&gt;
| Eruption&lt;br /&gt;
| https://github.com/AndyKerrison/bga-eruption&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| A Fistful Of Gold&lt;br /&gt;
| https://bitbucket.org/Joel_L/fistfulofgold&lt;br /&gt;
| Brainchild&lt;br /&gt;
|-&lt;br /&gt;
| Florenza: The Card Game&lt;br /&gt;
| https://github.com/alberto-bottarini/bga-florenza&lt;br /&gt;
| tarini &lt;br /&gt;
|-&lt;br /&gt;
| Hearts &#039;&#039;&#039;(Tutorial)&#039;&#039;&#039;&lt;br /&gt;
| https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Homesteaders&lt;br /&gt;
| https://github.com/npatron/bga-homesteaders&lt;br /&gt;
| TheBoot&lt;br /&gt;
|-&lt;br /&gt;
| Incan Gold&lt;br /&gt;
| https://github.com/AntonioSoler/bga-incangold&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Innovation&lt;br /&gt;
| https://github.com/micahstairs/bga-innovation&lt;br /&gt;
| Micah Stairs (micahstairs)&lt;br /&gt;
|-&lt;br /&gt;
| Mapmaker: The Gerrymandering Game&lt;br /&gt;
| https://github.com/gzhang01/bga-mapmaker&lt;br /&gt;
| gkz&lt;br /&gt;
|-&lt;br /&gt;
| Marco Polo&lt;br /&gt;
| https://github.com/rcitaliano/MarcoPolo&lt;br /&gt;
| rcitaliano&lt;br /&gt;
|-&lt;br /&gt;
| Nile&lt;br /&gt;
| https://github.com/AndyKerrison/bga-nile&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| Noir: Killer vs Inspector&lt;br /&gt;
| https://bitbucket.org/chhuang76/bga_noirkvi&lt;br /&gt;
| ch huang&lt;br /&gt;
|-&lt;br /&gt;
| Penny Press&lt;br /&gt;
| https://github.com/AdamNovotny/bga-blooms&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| P.I.&lt;br /&gt;
| https://gitlab.com/fa81/bga-pi, https://github.com/hellp/bga-pi (mirror)&lt;br /&gt;
| Fabian Neumann (fa81)&lt;br /&gt;
|-&lt;br /&gt;
| Santorini&lt;br /&gt;
| https://github.com/AntonioSoler/bga-santorini&lt;br /&gt;
| Morgalad, quietmint, Tisaac&lt;br /&gt;
|-&lt;br /&gt;
| Tablut&lt;br /&gt;
| https://github.com/Lucas-C/tablut&lt;br /&gt;
| Lucas-C &amp;amp; ntaffore&lt;br /&gt;
|-&lt;br /&gt;
| Takara Island&lt;br /&gt;
| https://github.com/AntonioSoler/bga-takaraisland&lt;br /&gt;
| Morgalad&lt;br /&gt;
|-&lt;br /&gt;
| Taluva&lt;br /&gt;
| https://github.com/quietmint/bga-taluva&lt;br /&gt;
| Morgalad &amp;amp; quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Teotihuacan: City of Gods&lt;br /&gt;
| https://github.com/Trompetenhut/bga-teotihuacan&lt;br /&gt;
| Trompetenhut&lt;br /&gt;
|-&lt;br /&gt;
| Texas 42 (domino game, still under development)&lt;br /&gt;
| https://github.com/ishermandom/bga-42&lt;br /&gt;
| Stardust Spikes, Jason Turner-Maier, Ilya Sherman&lt;br /&gt;
|-&lt;br /&gt;
| Uptown&lt;br /&gt;
| https://github.com/elliotkendall/bga-uptown&lt;br /&gt;
| SpottedShroom&lt;br /&gt;
|-&lt;br /&gt;
| Via Magica&lt;br /&gt;
| https://github.com/christopherburke/bga_viamagica&lt;br /&gt;
| CuriousTerran&lt;br /&gt;
|-&lt;br /&gt;
| Just Desserts&lt;br /&gt;
| https://github.com/mizutismask/bga-just-desserts&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| The King&#039;s Guild&lt;br /&gt;
| https://github.com/AdamNovotny/BGG-KingsGuild&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| Get the MacGuffin&lt;br /&gt;
| https://github.com/mizutismask/bga-get-the-MacGuffin&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| President&lt;br /&gt;
| https://github.com/quaresma95/president&lt;br /&gt;
| quaresma95&lt;br /&gt;
|-&lt;br /&gt;
| Hardback&lt;br /&gt;
| https://github.com/quietmint/bga-hardback&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dice Summoners&lt;br /&gt;
| https://github.com/eoincos/bga-dicesummoners&lt;br /&gt;
| eoincos&lt;br /&gt;
|-&lt;br /&gt;
| Trick of the Rails&lt;br /&gt;
| https://github.com/Fnordistan/trickoftherails&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects on studio ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Any developer can add themselves to a project as read-only from https://studio.boardgamearena.com/#!projects page (almost any project).&lt;br /&gt;
The list below are no-games which do not have bgg id and not showing up there.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code&lt;br /&gt;
| https://studio.boardgamearena.com/#!studiogame?game=sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Original BGA template&lt;br /&gt;
| https://studio.boardgamearena.com/#!studiogame?game=template&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other useful resources ==&lt;br /&gt;
&lt;br /&gt;
Moved to [[Tools_and_tips_of_BGA_Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=10023</id>
		<title>Game interface logic: Game.js</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=10023"/>
		<updated>2021-11-02T01:47:08Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* File structure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This is the main file for your game interface. Here you will define:&lt;br /&gt;
&lt;br /&gt;
* Which actions on the page will generate calls to the server.&lt;br /&gt;
* What happens when you get a notification for a change from the server and how it will show in the browser. &lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
&lt;br /&gt;
The details of how the file is structured are described below with comments on the code skeleton provided to you.&lt;br /&gt;
&lt;br /&gt;
Here is the basic structure:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;constructor&#039;&#039;&#039;: here you can define global variables for your whole interface.&lt;br /&gt;
* &#039;&#039;&#039;setup&#039;&#039;&#039;: this method is called when the page is refreshed, and sets up the game interface.&lt;br /&gt;
* &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;: this method is called when entering a new game state. You can use it to customize the view for each game state.&lt;br /&gt;
* &#039;&#039;&#039;onLeavingState&#039;&#039;&#039;: this method is called when leaving a game state.&lt;br /&gt;
* &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039;: called when entering a new state, in order to add action buttons to the status bar.&lt;br /&gt;
* &#039;&#039;(utility methods)&#039;&#039;: this is where you can define your utility methods.&lt;br /&gt;
* &#039;&#039;(player&#039;s actions)&#039;&#039;: this is where you can write your handlers for player actions on the interface (example: click on an item).&lt;br /&gt;
* &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;: this method associates notifications with notification handlers. For each game notification, you can trigger a javascript method to handle it and update the game interface.&lt;br /&gt;
* &#039;&#039;(notification handlers)&#039;&#039;: this is where you define the notifications handlers associated with notifications in &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;, above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
More details:&lt;br /&gt;
&lt;br /&gt;
;setup(gamedatas)            &lt;br /&gt;
This method must set up the game user interface according to current game situation specified in parameters.&lt;br /&gt;
The method is called each time the game interface is displayed to a player, ie:&lt;br /&gt;
&lt;br /&gt;
- when the game starts&lt;br /&gt;
&lt;br /&gt;
- when a player refreshes the game page (F5)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;gamedatas&amp;quot; argument contains all datas retrieved by your &amp;quot;getAllDatas&amp;quot; PHP method.&lt;br /&gt;
&lt;br /&gt;
;onEnteringState(stateName, args)&lt;br /&gt;
This method is called each time we are entering into a new game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
To access state arguments passed via calling arg* method use args.args.&lt;br /&gt;
Typically you would do something only for active player, using this.isCurrentPlayerActive() check.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: for multipleactiveplayer states:&lt;br /&gt;
the active players are NOT active yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/unactive status.&lt;br /&gt;
If you are doing initialization of some structure which do not depend on active player, you can just replace (this.isCurrentPlayerActive()) with (!this.isSpectator) &lt;br /&gt;
for the main switch in that method.&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Diffrence_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
;onLeavingState(stateName)&lt;br /&gt;
This method is called each time we are leaving a game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment (i.e. cleanup).&lt;br /&gt;
&lt;br /&gt;
;onUpdateActionButtons(stateName, args)&lt;br /&gt;
In this method you can manage &amp;quot;action buttons&amp;quot; that are displayed in the action status bar and highlight active UI elements.&lt;br /&gt;
To access state arguments passed via calling arg* method use &#039;&#039;&#039;args&#039;&#039;&#039; parameter. Note: args can be null! For &#039;&#039;&#039;game&#039;&#039;&#039; states and when you don&#039;t supply state args function - it is null.&lt;br /&gt;
This method is called when active or multiactive player changes. In classic &amp;quot;activePlayer&amp;quot; state this method is called before the onEnteringState state.&lt;br /&gt;
In multipleactiveplayer state it is a mess. The sequencing of calls would depends on either you get into that state from transitions OR from reloading the whole game (i.e. F5).&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Difference_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
== General tips ==&lt;br /&gt;
&lt;br /&gt;
; this.player_id&lt;br /&gt;
: ID of the player on whose browser the code is running.&lt;br /&gt;
&lt;br /&gt;
; this.isSpectator&lt;br /&gt;
: Flag set to true if the user at the table is a spectator (not a player).&lt;br /&gt;
: Note: This is a variable, not a function.&lt;br /&gt;
: Note: If you want to hide an element from spectators, you should use [[Game_interface_stylesheet:_yourgamename.css#spectatorMode|CSS &#039;spectatorMode&#039; class]].&lt;br /&gt;
&lt;br /&gt;
; this.gamedatas&lt;br /&gt;
: Contains the initial set of data to init the game, created at game start or by game refresh (F5).&lt;br /&gt;
: You can update it as needed to keep an up-to-date reference of the game on the client side if you need it. (Most of the time this is unnecessary).&lt;br /&gt;
&lt;br /&gt;
; this.isCurrentPlayerActive()&lt;br /&gt;
: Returns true if the player on whose browser the code is running is currently active (it&#039;s his turn to play). Note: see remarks above about usage of this function inside onEnteringState method.&lt;br /&gt;
&lt;br /&gt;
; this.getActivePlayerId()&lt;br /&gt;
: Return the ID of the active player, or null if we are not in an &amp;quot;activeplayer&amp;quot; type state.&lt;br /&gt;
&lt;br /&gt;
; this.getActivePlayers()&lt;br /&gt;
: Return an array with the IDs of players who are currently active (or an empty array if there are none).&lt;br /&gt;
&lt;br /&gt;
; this.bRealtime&lt;br /&gt;
: Return true if the game is in realtime. Note that having a distinct behavior in realtime and turn-based should be exceptional.&lt;br /&gt;
&lt;br /&gt;
; g_replayFrom&lt;br /&gt;
: Global contains reply number in live game, it is set to undefined (i.e. not set) when it is not a reply mode, so consequentially the good check is &#039;&#039;&#039;g_replayFrom !== undefined&#039;&#039;&#039; which returns true if the game is in replay mode &amp;lt;i&amp;gt;during the game&amp;lt;/i&amp;gt; (the game is ongoing but the user clicked &amp;quot;reply from this move&amp;quot; in the log)&lt;br /&gt;
&lt;br /&gt;
; g_archive_mode&lt;br /&gt;
: Returns true if the game is in archive mode &amp;lt;i&amp;gt;after the game&amp;lt;/i&amp;gt; (the game has ended)&lt;br /&gt;
&lt;br /&gt;
; this.instantaneousMode&lt;br /&gt;
: Returns true during replay/archive mode if animations should be skipped. Only needed if you are doing custom animations. (The BGA-provided animation functions like &amp;lt;i&amp;gt;this.slideToObject()&amp;lt;/i&amp;gt; automatically handle instantaneous mode.)&lt;br /&gt;
: Technically, when you click &amp;quot;replay from move #20&amp;quot;, the system replays the game from the very beginning with moves 0 - 19 happening in instantaneous mode and moves 20+ happening in normal mode.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You may consider making a function like this, to detect if the game is in a read-only state:&lt;br /&gt;
&lt;br /&gt;
  // Returns true for spectators, instant replay (during game), archive mode (after game end)&lt;br /&gt;
  isReadOnly: function () {&lt;br /&gt;
    return this.isSpectator || typeof g_replayFrom != &#039;undefined&#039; || g_archive_mode;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
== Dojo framework ==&lt;br /&gt;
&lt;br /&gt;
BGA uses the [http://dojotoolkit.org/ Dojo Javascript framework].&lt;br /&gt;
&lt;br /&gt;
The Dojo framework allows us to do complex things more easily. The BGA framework uses Dojo extensively.&lt;br /&gt;
&lt;br /&gt;
To implement a game, you only need to use a few parts of the Dojo framework. All the Dojo methods you need are described on this page.&lt;br /&gt;
&lt;br /&gt;
== Javascript minimization (after July 2020) ==&lt;br /&gt;
&lt;br /&gt;
For performance reasons, when deploying a game the javascript code is minimized using &#039;&#039;&#039;terser&#039;&#039;&#039; (https://github.com/terser/terser). This minifier works with modern javascript syntax. From your project &amp;quot;Manage game&amp;quot; page, you can now test a minified version of your javascript on the studio (and revert to the original).&lt;br /&gt;
&lt;br /&gt;
NB: it has been reported that there is an issue with this minifier and percentage values for opacity.&lt;br /&gt;
&lt;br /&gt;
== Accessing and manipulating the DOM ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$(&#039;some_html_element_id&#039;)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The $() function is used to get an HTML element using its &amp;quot;id&amp;quot; attribute.&lt;br /&gt;
&lt;br /&gt;
Example 1: modify the content of a &amp;quot;span&amp;quot; element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In your HTML code:&lt;br /&gt;
   &amp;lt;span id=&amp;quot;a_value_in_the_game_interface&amp;quot;&amp;gt;1234&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In your Javascript code:&lt;br /&gt;
   $(&#039;a_value_in_the_game_interface&#039;).innerHTML = &amp;quot;9999&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: $() is the standard method to access some HTML element with the BGA Framework. You can use &#039;&#039;&#039;getElementById&#039;&#039;&#039; but a longer to type and less handy as it does not do some checks.&lt;br /&gt;
Note²: It is safe to use if you don&#039;t know if variable is string (id of element) or element itself, i.e. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  foo: function(card) {&lt;br /&gt;
       card = $(card); // now its node, no need to write if (typeof card === &#039;string&#039;) ...&lt;br /&gt;
       // but its good idea to check for null here&lt;br /&gt;
       ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.style&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.style you can modify the CSS property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Make an element disappear&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Give an element a 2px border&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;borderWidth&#039;, &#039;2px&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Change the background position of an element&lt;br /&gt;
     // (very practical when you are using CSS sprites to transform an element to another)&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;backgroundPosition&#039;, &#039;-20px -50px&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you must always use dojo.style to modify the CSS properties of HTML elements.&lt;br /&gt;
&lt;br /&gt;
Note²: if you have to modify several CSS properties of an element, or if you have a complex CSS transformation to do, you should consider using dojo.addClass/dojo.removeClass (see below).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS style&#039;&#039;&#039;&lt;br /&gt;
  $(&#039;my_element&#039;).style.display=&#039;none&#039;; // set&lt;br /&gt;
  var display = $(&#039;my_element&#039;).style.display; // get&lt;br /&gt;
  $(&#039;my_element&#039;).style.removeProperty(&#039;display&#039;); // remove&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.addClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.removeClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.toggleClass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In many situations, many small CSS property updates can be replaced by a CSS class change (i.e., you add a CSS class to your element instead of applying all modifications manually).&lt;br /&gt;
&lt;br /&gt;
Advantages are:&lt;br /&gt;
* All your CSS stuff remains in your CSS file.&lt;br /&gt;
* You can add/remove a list of CSS modifications with a simple function and without error.&lt;br /&gt;
* You can test whether you applied the CSS to an element with the &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Example from &#039;&#039;Reversi&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // We add &amp;quot;possibleMove&amp;quot; to an element&lt;br /&gt;
    dojo.addClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
    // In our CSS file, the class is defined as:&lt;br /&gt;
    .possibleMove {&lt;br /&gt;
      background-color: white;&lt;br /&gt;
      opacity: 0.2;&lt;br /&gt;
      filter:alpha(opacity=20); /* For IE8 and earlier */  &lt;br /&gt;
      cursor: pointer;  &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     // So we&#039;ve applied 4 CSS property changes in one line of code.&lt;br /&gt;
&lt;br /&gt;
     // ... and when we need to check if a square is a possible move on the client side:&lt;br /&gt;
     if( dojo.hasClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; ) )&lt;br /&gt;
     { ... }&lt;br /&gt;
&lt;br /&gt;
     // ... and if we want to remove all possible moves in one line of code (see &amp;quot;dojo.query&amp;quot; method):&lt;br /&gt;
     dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Conclusion: We encourage you to use &#039;&#039;&#039;dojo.addClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.removeClass&#039;&#039;&#039; and &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; to make your life easier :)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.attr&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.attr you can access or change the value of an attribute or property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Get the title of a node&lt;br /&gt;
     var title = dojo.attr( id, &#039;title&#039; );&lt;br /&gt;
     // Change the height of a node&lt;br /&gt;
     dojo.attr( &#039;img_growing_tree&#039;, &#039;height&#039;, 100 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS attr&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
   $(token).id=new_id; // set attr for &amp;quot;id&amp;quot;&lt;br /&gt;
   var id = $(token).id; // get&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.query&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.query, you can query a bunch of HTML elements with a single function, with a &amp;quot;CSS selector&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // All elements with class &amp;quot;possibleMove&amp;quot;:&lt;br /&gt;
     var elements = dojo.query( &#039;.possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Count number of tokens (i.e., elements of class &amp;quot;token&amp;quot;) on the board (i.e., the element with id &amp;quot;board&amp;quot;):&lt;br /&gt;
     dojo.query( &#039;#board .token&#039; ).length;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But what is really cool with dojo.query is that you can combine it with almost all methods above.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Trigger a method when the mouse enter in any element with class &amp;quot;meeple&amp;quot;:&lt;br /&gt;
     dojo.query( &#039;.meeple&#039; ).connect( &#039;onmouseenter&#039;, this, &#039;myMethodToTrigger&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Hide all meeples who are on the board&lt;br /&gt;
     dojo.query( &#039;#board .meeple&#039; ).style( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS query&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  var cards=document.querySelectorAll(&amp;quot;.hand .card&amp;quot;);// all cards in all hands&lt;br /&gt;
  var cards=$(&#039;hand&#039;).querySelectorAll(&amp;quot;.card&amp;quot;);// all cards in specific hand&lt;br /&gt;
  var card=document.querySelector(&amp;quot;.hand .card&amp;quot;);// first card or null if none (super handy)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.place&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
dojo.place is the best function to insert HTML code somewhere in your game interface without breaking something. It is much better to use than the &#039;&#039;&#039;innerHTML=&#039;&#039;&#039; method if you must insert HTML tags and not only values.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Insert your HTML code as a child of a container element&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;your html code&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
     // Replace the container element with your new html&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;your html code&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot;, &amp;quot;replace&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The third parameter of dojo.place can take various interesting values:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;replace&amp;quot; : (see description above).&lt;br /&gt;
&lt;br /&gt;
&amp;quot;first&amp;quot; : Places the node as a child of the reference node. The node is placed as the first child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;last&amp;quot; (default) : Places the node as a child of the reference node. The node is placed as the last child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;before&amp;quot; : places the node right before the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;after&amp;quot; : places the node right after the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;only&amp;quot; : replaces all children of the reference node with the node.&lt;br /&gt;
&lt;br /&gt;
positive integer: This parameter can be a positive integer. In this case, the node will be placed as a child of the reference node with this number (counting from 0). If the number is more than number of children, the node will be appended to the reference node making it the last child. &lt;br /&gt;
&lt;br /&gt;
See also full doc on dojo.place: [https://dojotoolkit.org/reference-guide/1.7/dojo/place.html]&lt;br /&gt;
&lt;br /&gt;
Usually, when you want to insert some piece of HTML in your game interface, you should use &amp;quot;[[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
But you can also relocate elements like that. Note: it won&#039;t animate if you do that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.empty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove all children of the node element&lt;br /&gt;
   dojo.empty(&#039;my_hand&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.destroy&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove the element&lt;br /&gt;
&lt;br /&gt;
   dojo.query(&amp;quot;.green&amp;quot;, mynode).forEach(dojo.destroy); // this remove all subnode of class green from mynode&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.create&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create element&lt;br /&gt;
&lt;br /&gt;
    dojo.create(&amp;quot;div&amp;quot;, { class: &amp;quot;yellow_arrow&amp;quot; }, parent); // this creates div with class yellow_array and places it in &amp;quot;parent&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;addStyleToClass: function( cssClassName, cssProperty, propertyValue )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as dojo.style(), but for all the nodes set with the specified cssClassName&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.format_block&#039;&#039;&#039;&lt;br /&gt;
This bga function that takes global var from template file and substitute variables, typical use would be&lt;br /&gt;
&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                var div = this.format_block(&#039;jstpl_player_board&#039;, player ); // var jstpl_player_board = ... is defined in .tpl file &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.format_string&#039;&#039;&#039;&lt;br /&gt;
This bga function just substitute variables in a string, i.e.&lt;br /&gt;
     var div = this.format_string(&#039;&amp;lt;div color=&amp;quot;${player_color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, {player_color: &#039;#ff0000&#039;} );&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.format_string_recursive&#039;&#039;&#039;&lt;br /&gt;
This bga function is similar to this.format_string but is capable of processing recursive argument structures and translations. It is used to format server notifications.&lt;br /&gt;
&lt;br /&gt;
=== Animations ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dojo Animations&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
BGA animations is based on Dojo Animation ([http://dojotoolkit.org/documentation/tutorials/1.8/animation/ see tutorial here]).&lt;br /&gt;
&lt;br /&gt;
However, most of the time, you can just use methods below, which are built on top of Dojo Animation.&lt;br /&gt;
&lt;br /&gt;
Note: one interesting method from Dojo that could be useful from time to time is &amp;quot;Dojo.Animation&amp;quot;. It allows you to make any CSS property &amp;quot;slide&amp;quot; from one value to another.&lt;br /&gt;
&lt;br /&gt;
Note 2: the slideTo methods are not compatible with CSS transform (scale, zoom, rotate...). If possible, avoid using CSS transform on nodes that are being slided. Eventually, the only possible solution to make these 2 compatible is to disable all CSS transform properties, use slideToObjectPos/placeOnObjectPos, and then apply them again.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideToObject( mobile_obj, target_obj, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use slideToObject to &amp;quot;slide&amp;quot; an element to a target position.&lt;br /&gt;
&lt;br /&gt;
Sliding element on the game area is the recommended and the most used way to animate your game interface. Using slides allow players to figure out what is happening on the game, as if they were playing with the real boardgame.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* mobile_obj: the ID of the object to move. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned.&lt;br /&gt;
* target_obj: the ID of the target object. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned. Note that it is not mandatory that mobile_obj and target_obj have the same size. If their size are different, the system slides the center of mobile_obj to the center of target_obj.&lt;br /&gt;
* duration: (optional) defines the duration in millisecond of the slide. The default is 500 milliseconds.&lt;br /&gt;
* delay: (optional). If you defines a delay, the slide will start only after this delay. This is particularly useful when you want to slide several object from the same position to the same position: you can give a 0ms delay to the first object, a 100ms delay to the second one, a 200ms delay to the third one, ... this way they won&#039;t be superposed during the slide.&lt;br /&gt;
&lt;br /&gt;
BE CAREFUL: The method returns an dojo.fx animation, so you can combine it with other animation if you want to. It means that you have to call the &amp;quot;play()&amp;quot; method, otherwise the animation WON&#039;T START.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.slideToObject( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideToObjectPos( mobile_obj, target_obj, target_x, target_y, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method does exactly the same as &amp;quot;slideToObject&amp;quot;, except than you can specify some (x,y) coordinates. This way, &amp;quot;mobile_obj&amp;quot; will slide to the specified x,y position relatively to &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example: slide a token to some place on the board, 10 pixels to the bottom:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.slideToObjectPos( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 0, 10 ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideTemporaryObject( mobile_obj_html, mobile_obj_parent, from, to, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is useful when you want to slide a temporary HTML object from one place to another. As this object does not exists before the animation and won&#039;t remain after, it could be complex to create this object (with dojo.place), to place it at its origin (with placeOnObject) to slide it (with slideToObject) and to make it disappear at the end.&lt;br /&gt;
&lt;br /&gt;
slideTemporaryObject does all of this for you:&lt;br /&gt;
* mobile_obj_html is a piece of HTML code that represent the object to slide.&lt;br /&gt;
* mobile_obj_parent is the ID of an HTML element of your interface that will be the parent of this temporary HTML object.&lt;br /&gt;
* from is the ID of the origin of the slide.&lt;br /&gt;
* to is the ID of the target of the slide.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.slideTemporaryObject( &#039;&amp;lt;div class=&amp;quot;token_icon&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, &#039;tokens&#039;, &#039;my_origin_div&#039;, &#039;my_target_div&#039; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideToObjectAndDestroy: function( node, to, time, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is a handy shortcut to slide an existing HTML object to some place then destroy it upon arrival. It can be used for example to move a victory token or a card from the board to the player panel to show that the player earns it, then destroy it when we don&#039;t need to keep it visible on the player panel.&lt;br /&gt;
&lt;br /&gt;
It works the same as this.slideToObject and takes the same arguments, but it starts the animation. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.slideToObjectAndDestroy( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 1000, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.fadeOutAndDestroy( node, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function fade out the target HTML node, then destroy it. Its starts the animation.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.fadeOutAndDestroy( &amp;quot;a_card_that_must_disappear&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the HTML node still exists until during few milliseconds, until the fadeOut has been completed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rotating elements&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can check here [http://jimfulton.info/demos/dojo-animated-rotate.html an example of use] of Dojo to make an element rotate.&lt;br /&gt;
&lt;br /&gt;
This example combines &amp;quot;Dojo.Animation&amp;quot; method and a CSS3 property that allow you to rotate the element.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: to asses browser compatibility, you must select the CSS property to use just like in the example (see sourcecode below):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        var transform;&lt;br /&gt;
        dojo.forEach(&lt;br /&gt;
            [&#039;transform&#039;, &#039;WebkitTransform&#039;, &#039;msTransform&#039;,&lt;br /&gt;
             &#039;MozTransform&#039;, &#039;OTransform&#039;],&lt;br /&gt;
            function (name) {&lt;br /&gt;
                if (typeof dojo.body().style[name] != &#039;undefined&#039;) {&lt;br /&gt;
                    transform = name;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        // ... and then use &amp;quot;transform&amp;quot; as the name of your CSS property for rotation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: This wiki was probably written 10 years ago - now all modern broser support &#039;transform&#039; so just ignore this and use transform.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Animation Callbacks&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you wish to run some code only after an animation has completed you can do this by linking a callback method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var animation_id = this.slideToObject( mobile_obj, target_obj, duration, delay );&lt;br /&gt;
dojo.connect(animation_id, &#039;onEnd&#039;, dojo.hitch(this, &#039;callback_function&#039;, parameters));&lt;br /&gt;
animation_id.play();&lt;br /&gt;
&lt;br /&gt;
…&lt;br /&gt;
&lt;br /&gt;
callback_function: function(params) {&lt;br /&gt;
   // this will be called after the animation ends&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you wish to call a second animation after the first (rather than general code) then you can use a dojo animation chain (see tutorial referenced above).&lt;br /&gt;
&lt;br /&gt;
=== Moving elements ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.placeOnObject( mobile_obj, target_obj )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
placeOnObject works exactly like &amp;quot;slideToObject&amp;quot;, except that the effect is immediate and that it is centered.&lt;br /&gt;
&lt;br /&gt;
This is not really an animation, but placeOnObject is frequently used before starting an animation.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // (We just created an object &amp;quot;my_new_token&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  // Place the new token on current player board&lt;br /&gt;
  this.placeOnObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;overall_player_board_&amp;quot;+this.player_id );&lt;br /&gt;
  &lt;br /&gt;
  // Then slide it to its position on the board&lt;br /&gt;
  this.slideToObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;a_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.placeOnObjectPos( mobile_obj, target_obj, target_x, target_y )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method works exactly like placeOnObject, except than you can specify some (x,y) coordinates. This way, &amp;quot;mobile_obj&amp;quot; will be placed to the specified x,y position relatively to &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.attachToNewParent( mobile_obj, target_obj )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With this method, you change the HTML parent of &amp;quot;mobile_obj&amp;quot; element. &amp;quot;target_obj&amp;quot; is the new parent of this element. The beauty of &lt;br /&gt;
attachToNewParent is that the mobile_obj element DOES NOT MOVE during this process.&lt;br /&gt;
&lt;br /&gt;
Note: what happens is that the method calculate a relative position of mobile_obj to make sure it does not move after the HTML parent changes.&lt;br /&gt;
&lt;br /&gt;
Why using this method?&lt;br /&gt;
&lt;br /&gt;
Changing the HTML parent of an element can be useful for the following reasons:&lt;br /&gt;
* When the HTML parent moves, all its child are moving with them. If some game elements is no more linked with a parent HTML object, you may want to attach it to another place.&lt;br /&gt;
* The z_order (vertical order of display) depends on the position in the DOM, so you may need to change the parent of some game elements when they are moving in your game area.&lt;br /&gt;
&lt;br /&gt;
CAREFUL: this function destroys original object and places a clone onto a new parent, this will break all references to this HTML element (ex: dojo.connect).&lt;br /&gt;
&lt;br /&gt;
== Players input ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.connect&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
Example: associate a click on an element (&amp;quot;my_element&amp;quot;) with one of our methods (&amp;quot;onClickOnMyElement&amp;quot;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      dojo.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, this, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same idea but base on query (i.e. all element of &#039;pet&#039; class)&lt;br /&gt;
      dojo.query(&amp;quot;.pet&amp;quot;).connect(&#039;onclick&#039;, this, &#039;onPet&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: the methods described here are the only correct ways to associate a player input event to your code, and you should not use anything else.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.connect&#039;&#039;&#039;&lt;br /&gt;
function(element, event, handler)&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&lt;br /&gt;
Or you can use an in-place handler&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, (e) =&amp;gt; { console.log(&#039;boo&#039;); } );&lt;br /&gt;
&lt;br /&gt;
Note that this function stores the connection handler. That is the only real difference between &#039;&#039;&#039;this.connect&#039;&#039;&#039; and &#039;&#039;&#039;dojo.connect&#039;&#039;&#039;. If you plan to destroy the element you connected, you &#039;&#039;&#039;must&#039;&#039;&#039; call this.disconnect() to prevent memory leaks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.connectClass&#039;&#039;&#039;&lt;br /&gt;
function( cssClassName, event, handler )&lt;br /&gt;
&lt;br /&gt;
Same as connect(), but for all the nodes set with the specified cssClassName.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	this.connectClass(&#039;pet&#039;, &#039;onclick&#039;, &#039;onPet&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;this.disconnect&#039;&#039;&#039;&lt;br /&gt;
function( element, event )&lt;br /&gt;
&lt;br /&gt;
Disconnect event handler (previously registered with this.connect or this.connectClass).&lt;br /&gt;
&lt;br /&gt;
   this.disconnect( $(&#039;my_element&#039;), &#039;onclick&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: dynamic connect/disconnect is for advanced cases ONLY, you should always connect elements statically if possible, i.e. in setup() method.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.disconnectAll&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disconnect all previously registed event handlers (registered via this.connect or this.connectClass)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.checkAction&#039;&#039;&#039;&lt;br /&gt;
function( action, nomessage )&lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* current game state&lt;br /&gt;
* interface locking (a player can&#039;t do any action if an action is already in progress)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
return true if action is authorized (i.e: the action is listed as a &amp;quot;possibleaction&amp;quot; in current game state).&lt;br /&gt;
&lt;br /&gt;
return false and display an error message if not authorized (display no message if nomessage parameter is true). &lt;br /&gt;
The displayed error message could be either &amp;quot;This move is not allowed at this moment&amp;quot; or &amp;quot;An action is already in progress&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  function onClickOnGameElement( evt )  {&lt;br /&gt;
     if( this.checkAction( &amp;quot;my_action&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.checkPossibleActions&#039;&#039;&#039;&lt;br /&gt;
function( action, nomessage )&lt;br /&gt;
&lt;br /&gt;
* this is independent of the player being active, so can be used instead of this.checkAction(). This is particularly useful for multiplayer states when the player is not active in a &#039;player may like to change their mind&#039; scenario. &lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* current game state&lt;br /&gt;
* interface locking (a player can&#039;t do any action if an action is already in progress)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.ajaxcall( url, parameters, obj_callback, callback, callback_error, ajax_method )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method must be used to send a player input to the game server. &#039;&#039;&#039;It should not be triggered programmatically&#039;&#039;&#039;, especially not in loops, in callbacks, in notifications, or in onEnteringState/onUpdateActionButtons/onLeavingState, in order not to create race conditions.&lt;br /&gt;
&lt;br /&gt;
* url: the url of the action to perform. For a game, it must be: &amp;quot;/&amp;lt;mygame&amp;gt;/&amp;lt;mygame&amp;gt;/myAction.html&amp;quot;&lt;br /&gt;
* parameters: an array of parameter to send to the game server. &lt;br /&gt;
** Note that &amp;quot;lock: true&amp;quot; must always be specified in this list of parameters in order the interface can be locked during the server call.&lt;br /&gt;
** Note: Restricted parameter names (please don&#039;t use them):&lt;br /&gt;
*** &amp;quot;action&amp;quot;&lt;br /&gt;
*** &amp;quot;module&amp;quot;&lt;br /&gt;
*** &amp;quot;class&amp;quot;&lt;br /&gt;
* obj_callback: must be set to &amp;quot;this&amp;quot;.&lt;br /&gt;
* callback: a function to trigger when the server returns and everything went fine (not used, as all data handling is done via notifications).&lt;br /&gt;
* callback_error: (optional and rarely used) a function to trigger when the server returns an error.  if no error this function is called with parameter value false.&lt;br /&gt;
* ajax_method: (optional and rarely used) if you need to send large amounts of data (over 2048 bytes), you can set this parameter to &#039;post&#039; (all lower-case) to send a POST request as opposed to the default GET. This works, but was not officially documented, so only use if you really need to.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.ajaxcall( &#039;/mygame/mygame/myaction.html&#039;, { lock: true, &lt;br /&gt;
   arg1: myarg1, &lt;br /&gt;
   arg2: myarg2, &lt;br /&gt;
   ...&lt;br /&gt;
}, this, function( result ) {&lt;br /&gt;
   // Do some stuff after a successful call&lt;br /&gt;
   // NB : usually not needed as changes must be handled by notifications&lt;br /&gt;
   // You should NOT modify the interface in a callback or it will most likely break the framework replays (or make it inaccurate)&lt;br /&gt;
   // You should NOT make another ajaxcall in a callback in order not to create race conditions&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: to reduce the boilerplate code you can define your own wrapper, which will do checking, locking and allow to skip parameters, for example&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
		ajaxcallwrapper: function(action, args, handler) {&lt;br /&gt;
			if (!args) {&lt;br /&gt;
				args = [];&lt;br /&gt;
			}&lt;br /&gt;
			args.lock = true;&lt;br /&gt;
&lt;br /&gt;
			if (this.checkAction(action)) {&lt;br /&gt;
				this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + action + &amp;quot;.html&amp;quot;, args,// &lt;br /&gt;
					this, (result) =&amp;gt; { }, handler);&lt;br /&gt;
			}&lt;br /&gt;
		},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be called like this which is a lot more compact&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playDraw&#039;);&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playMove&#039;, {card: id})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.isInterfaceLocked()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When using &amp;quot;lock: true&amp;quot; in ajax call you can use this function to check if interface is in lock state (it will be locked during server call and notification processing).&lt;br /&gt;
This check can be used to block some other interactions which do not result in ajaxcall or if you want to suppress errors.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Translations ==&lt;br /&gt;
&lt;br /&gt;
See [[Translations]]&lt;br /&gt;
&lt;br /&gt;
== Notifications ==&lt;br /&gt;
&lt;br /&gt;
When something happens on the server side, your game interface Javascript logic received a notification.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can handle these notifications on the client side.&lt;br /&gt;
&lt;br /&gt;
=== Subscribe to notifications ===&lt;br /&gt;
&lt;br /&gt;
Your Javascript &amp;quot;setupNotifications&amp;quot; method is the place where you can subscribe to notifications from your PHP code.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you associate one of your Javascript method to a notification &amp;quot;playDisc&amp;quot; (from Reversi example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // In setupNotifications method:&lt;br /&gt;
   dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the &amp;quot;playDisc&amp;quot; corresponds to the name of the notification you define it in your PHP code, in your &amp;quot;notifyAllPlayers&amp;quot; or &amp;quot;notifyPlayer&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Then, you have to define your &amp;quot;notif_playDisc&amp;quot; method:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        notif_playDisc: function( notif )&lt;br /&gt;
        {&lt;br /&gt;
            // Remove current possible moves (makes the board more clear)&lt;br /&gt;
            dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );        &lt;br /&gt;
        &lt;br /&gt;
            this.addDiscOnBoard( notif.args.x, notif.args.y, notif.args.player_id );&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a notification handler like our &amp;quot;notif_playDisc&amp;quot; method, you can access all notifications arguments with &amp;quot;notif.args&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
PHP&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    self::notifyAllPlayers( &amp;quot;myNotification&amp;quot;, &#039;&#039;, array( &amp;quot;myArgument&amp;quot; =&amp;gt; 3 ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
JavaScript&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    //You can access the &amp;quot;myArgument&amp;quot; like this:&lt;br /&gt;
    notif_myNotification: function( notif )&lt;br /&gt;
    {&lt;br /&gt;
       alert( &amp;quot;myArgument = &amp;quot; + notif.args.myArgument );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The notification Object received by client ===&lt;br /&gt;
&lt;br /&gt;
When sending a notification on your PHP, the client side will receive an Object with the following attributes:&lt;br /&gt;
&lt;br /&gt;
* args : This is the arguments that you passed on your notification method on php&lt;br /&gt;
* bIsTableMsg : Boolean, is true when you use [[Main_game_logic:_yourgamename.game.php#NotifyAllPlayers|NotifyAllPlayers]] method (false otherwise)&lt;br /&gt;
* channelorig : information about table ID (formatted as : &amp;quot;/table/t[TABLE_NUMBER]&amp;quot;)&lt;br /&gt;
* gamenameorig : name of the game&lt;br /&gt;
* log: the log information as written in PHP function&lt;br /&gt;
* move_id : ID of the move associated with the notification&lt;br /&gt;
* table_id : ID of the table&lt;br /&gt;
* time : UNIX GMT time&lt;br /&gt;
* type : name of the notification&lt;br /&gt;
* uid : identifier of the notification&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; Note that those information were inferred from observation on console log. If an Admin can confirm/correct (and remove this line), you&#039;re welcome :)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Synchronous notifications ===&lt;br /&gt;
&lt;br /&gt;
When several notifications are received by your game interface, these notifications are processed immediately, one after the other, in the same exact order they have been generated in your PHP game logic.&lt;br /&gt;
&lt;br /&gt;
However, sometimes, you need to give some time to the players to figure out what happened on the game before jumping to the next notification. Indeed, in many games, there are a lot of automatic actions, and the computer is going to resolve all these actions very fast if you don&#039;t tell it not to do so.&lt;br /&gt;
&lt;br /&gt;
As an example, for Reversi, when someone is playing a disc, we want to wait 500 milliseconds before doing anything else in order the opponent player can figure out what move has been played.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we do this, right after our subscription:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;playDisc&#039;, 500 );   // Wait 500 milliseconds after executing the playDisc handler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
It is also possible to control the delay timing dynamically (e.g., using notification args). As an example, maybe your notification &#039;cardPlayed&#039; should pause for a different amount of time depending on the number or type of cards played.&lt;br /&gt;
&lt;br /&gt;
For this case, use &#039;&#039;&#039;setSynchronous&#039;&#039;&#039; without specifying the duration and use &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039; within the notification callback.&lt;br /&gt;
&lt;br /&gt;
* NOTE: If you forget to invoke &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039;, the game will remain paused forever!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupNotifications: function () {&lt;br /&gt;
    dojo.subscribe( &#039;cardPlayed&#039;, this, &#039;notif_cardPlayed&#039; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;cardPlayed&#039; ); // wait time is dynamic&lt;br /&gt;
    ...&lt;br /&gt;
},&lt;br /&gt;
&lt;br /&gt;
notif_cardPlayed: function (notif) {&lt;br /&gt;
    // MUST call setSynchronousDuration&lt;br /&gt;
&lt;br /&gt;
    // Example 1: From notification args (PHP)&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(notif.args.duration);&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Or, example 2: Match the duration to a Dojo animation&lt;br /&gt;
    var anim = dojo.fx.combine([&lt;br /&gt;
        ...&lt;br /&gt;
    ]);&lt;br /&gt;
    anim.play();&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(anim.duration);&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WARNING: combining synchronous and ignored notifications ===&lt;br /&gt;
You must be careful when combining dynamic synchronous durations (as described above) with ignored notifications. If you have a conditionally ignored notification like this (see below section):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.notifqueue.setIgnoreNotificationCheck( &#039;myNotif&#039;, (notif) =&amp;gt; (notif.args.player_id == this.player_id) /* or any other condition */ )&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then you CANNOT do&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.notifqueue.setSynchronous(&#039;myNotif&#039;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as, when the ignored check passes, the notification handler, in which `this.notifqueue.setSychronousDuration` is called, is never called and so the duration is never set and interface locking results.&lt;br /&gt;
&lt;br /&gt;
The workaround is to set a &amp;quot;dummy&amp;quot; time:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.notifqueue.setSynchronous(&#039;myNotif&#039;, 5000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whose value is irrelevant but must be large enough to cover the time before the notification handler is called. The large value never actually comes into play because the notification is either ignored, or the synchronous duration is reset to a sensible value inside the handler.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Ignoring notifications ===&lt;br /&gt;
Sometimes you need to ignore some notification on client side. You don&#039;t want them to be shown in game log and you don&#039;t want them to be handled.&lt;br /&gt;
&lt;br /&gt;
The most common use case is when a player gets private information. They will receive a specific notification (such as &amp;quot;You received Ace of Heart&amp;quot;), while other players would receive more generic notification (&amp;quot;Player received a card&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
In X.game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $this-&amp;gt;notifyAllPlayers(&amp;quot;dealCard&amp;quot;, clienttranslate(&#039;${player_name} received a card&#039;), [&lt;br /&gt;
            &#039;player_id&#039; =&amp;gt; $playerId,&lt;br /&gt;
            &#039;player_name&#039; =&amp;gt; $this-&amp;gt;getActivePlayerName()&lt;br /&gt;
        ]);&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;notifyPlayer($playerId, &amp;quot;dealCardPrivate&amp;quot;, clienttranslate(&#039;You received ${cardName}&#039;), [&lt;br /&gt;
            &amp;quot;type&amp;quot; =&amp;gt; $card[&amp;quot;type&amp;quot;],&lt;br /&gt;
            &amp;quot;cardName&amp;quot; =&amp;gt; $this-&amp;gt;getCardName($card[&amp;quot;type&amp;quot;])&lt;br /&gt;
        ]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The problem with this approach is that the active player will receive two notifications:&lt;br /&gt;
* Player1 received a card&lt;br /&gt;
* You received Ace of Hearts&lt;br /&gt;
&lt;br /&gt;
Hence, notification ignoring. Similar to setting a synchronous notification above, you can set up a check whether a notification should be ignored:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.notifqueue.setIgnoreNotificationCheck( &#039;dealCard&#039;, (notif) =&amp;gt; (notif.args.player_id == this.player_id) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setIgnoreNotificationCheck(notificationId, predicate)&#039;&#039;&#039;&lt;br /&gt;
This method will set a check whether any of notifications of specific type should be ignored.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* notificationId: before dispatching any notification of this type, the framework will call predicate to check whether notification should be ignored&lt;br /&gt;
* predicate (notif =&amp;gt; boolean): a function that will receive notif object and will return true if this specific notification should be ignored&lt;br /&gt;
&lt;br /&gt;
NOTE: You can think that it could be possible to send generic notification to all other players with notifyAllPlayers and it will seem to work. The problem is that table spectators would miss this notification and their user interface (and game log) wouldn&#039;t be updated.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: Remember that this notification is ignored on the client side, but was still received by the client. Therefore it shouldn&#039;t contain any private information as cheaters can get it. In other words this is not a way to hide information.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: When a game is reloaded with F5 or when opening a turn based game, old notifications are replayed as history notification. They are used just to update the game log and are stripped of all arguments except player_id, i18n and any argument present in message. If you use and other argument in your predicate you should preserve it as explained [[Main_game_logic:_yourgamename.game.php#Notify_players|here]].&lt;br /&gt;
&lt;br /&gt;
=== Pre-defined notification types ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tableWindow&#039;&#039;&#039; - This defines notification to display [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialogs]], see below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;message&#039;&#039;&#039; - This defines notification that shows on players log and have no other effect&lt;br /&gt;
&lt;br /&gt;
   // You can call this on php side without doing anything on client side&lt;br /&gt;
    self::notifyAllPlayers( &#039;message&#039;, &#039;hello&#039;, [] );&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;simplePause&#039;&#039;&#039; - This notification will just delay other notifications, maybe useful if you know you need some extra time for animation or something. Requires a time parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    self::notifyAllPlayers( &#039;simplePause&#039;, &#039;&#039;, [ &#039;time&#039; =&amp;gt; 500] ); // time is in milliseconds&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tooltips ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltip( nodeId, helpStringTranslated, actionStringTranslated, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to the DOM node.&lt;br /&gt;
&lt;br /&gt;
Specify &#039;helpStringTranslated&#039; to display some information about &amp;quot;what is this game element?&amp;quot;.&lt;br /&gt;
Specify &#039;actionStringTranslated&#039; to display some information about &amp;quot;what happens when I click on this element?&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You must specify both of the strings. You can only use one and specify an empty string (&#039;&#039;) for the other one.&lt;br /&gt;
&lt;br /&gt;
When you pass text directly function _() must be used for the text to be marked for translation! Except for empty string.&lt;br /&gt;
&lt;br /&gt;
Parameter &amp;quot;delay&amp;quot; is optional. It is primarily used to specify a zero delay for some game element when the tooltip gives really important information for the game - but remember: no essential information must be placed in tooltips as they won&#039;t be displayed in some browsers (see [[BGA_Studio_Guidelines|Guidelines]]).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.addTooltip( &#039;cardcount&#039;, _(&#039;Number of cards in hand&#039;), &#039;&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this generates static tooltip and attaches to existing dom element, if you need to generate tooltip more dynamically you have to call that method every time information about object is updated or use completely different tehnique&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipHtml( nodeId, html, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to the DOM node (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipToClass( cssClass, helpStringTranslated, actionStringTranslated, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to all the DOM nodes set with this cssClass. See more details above for this.addTooltip.&lt;br /&gt;
     this.addTooltipToClass( &#039;meeple&#039;, _(&#039;This is A Meeple&#039;), _(&#039;Click to tickle&#039;) );&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must exist and have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipHtmlToClass( cssClass, html, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to to all the DOM nodes set with this cssClass (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must exist and have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.removeTooltip( nodeId )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove a tooltip from the DOM node with given id.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;force tooltip to open&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you want to force tooltip to open in reaction to some other action, i.e. click you can do this&lt;br /&gt;
&lt;br /&gt;
   this.tooltips[id].open(id)&lt;br /&gt;
&lt;br /&gt;
where id is the id of the tooltip node where tooltip was installed.&lt;br /&gt;
&lt;br /&gt;
== Dialogs, warning messages, confirmation dialogs, ... ==&lt;br /&gt;
&lt;br /&gt;
=== Warning messages ===&lt;br /&gt;
&lt;br /&gt;
Sometimes, there is something important that is happening in the game and you have to make sure all players get the message. Most of the time, the evolution of the game situation or the game log is enough, but sometimes you need something more visible.&lt;br /&gt;
&lt;br /&gt;
Ex: someone fulfills one of the end of the game conditions, so this is the last turn.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.showMessage( msg, type )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
showMessage shows a message in a big rectangular area on the top of the screen of the current player.&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;msg&amp;quot; is the string to display. It should be translated.&lt;br /&gt;
* &amp;quot;type&amp;quot; can be set to &amp;quot;info&amp;quot;, &amp;quot;error&amp;quot;, or &amp;quot;only_to_log&amp;quot;. If set to &amp;quot;info&amp;quot;, the message will be an informative message on a white background. If set to &amp;quot;error&amp;quot;, the message will be an error message on a red background. If set to &amp;quot;only_to_log&amp;quot;, the message will be added to the game log but will not popup at the top of the screen.&lt;br /&gt;
&lt;br /&gt;
Important: the normal way to inform players about the progression of the game is the game log. &amp;quot;showMessage&amp;quot; is intrusive and should not be used often.&lt;br /&gt;
&lt;br /&gt;
=== Confirmation dialog ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;confirmationDialog( message, yesHandler, noHandler )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When an important action with a lot of consequences is triggered by the player, you may want to propose a confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the general guideline of BGA is to AVOID the use of confirmation dialogs. Confirmation dialogs slow down the game and bother players. The players know that they have to pay attention to each move when they are playing online.&lt;br /&gt;
&lt;br /&gt;
The situations where you should use a confirmation dialog are the following:&lt;br /&gt;
* It must not happen very often during a game.&lt;br /&gt;
* It must be linked to an action that can really &amp;quot;kill a game&amp;quot; if the player does not pay attention.&lt;br /&gt;
* It must be something that can be done by mistake (ex: a link on the action status bar).&lt;br /&gt;
&lt;br /&gt;
How to display a confirmation dialog:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to bake the pie?&#039;), dojo.hitch( this, function() {&lt;br /&gt;
            this.bakeThePie();&lt;br /&gt;
        } ) ); &lt;br /&gt;
        return; // nothing should be called or done after calling this, all action must be done in the handler  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Multiple choice dialog ===&lt;br /&gt;
You can use this dialog to give user a choice with small amount of options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        var keys = [1,5,10];&lt;br /&gt;
        this.multipleChoiceDialog(&lt;br /&gt;
          _(&#039;How many bugs to fix?&#039;), keys, &lt;br /&gt;
            dojo.hitch(this, function(choice) {&lt;br /&gt;
                            var bugchoice = keys[choice];&lt;br /&gt;
                            console.log(&#039;dialog callback with &#039;+bugchoice);&lt;br /&gt;
                            this.ajaxcall( &#039;/mygame/mygame/fixBugs.html&#039;, { bugs: bugchoice}, this, function( result ) {} );                        }));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dialogs ===&lt;br /&gt;
&lt;br /&gt;
As a general rule, you shouldn&#039;t use dialogs windows.&lt;br /&gt;
&lt;br /&gt;
BGA guidelines specify that all game elements should be displayed on the main screen. Players can eventually scroll down to see game elements they don&#039;t need to see anytime, and you may eventually create anchors to move between game area section. Of course dialogs windows are very practical, but the thing is: all players know how to scroll down, and not all players know how to show up your dialog window. In addition, when the dialog shows up, players can&#039;t access the other game components.&lt;br /&gt;
&lt;br /&gt;
Sometimes although, you need to display a dialog window. Here is how you do this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  // Create the new dialog over the play zone. You should store the handler in a member variable to access it later&lt;br /&gt;
  this.myDlg = new ebg.popindialog();&lt;br /&gt;
  this.myDlg.create( &#039;myDialogUniqueId&#039; );&lt;br /&gt;
  this.myDlg.setTitle( _(&amp;quot;my dialog title to translate&amp;quot;) );&lt;br /&gt;
  this.myDlg.setMaxWidth( 500 ); // Optional&lt;br /&gt;
  &lt;br /&gt;
  // Create the HTML of my dialog. &lt;br /&gt;
  // The best practice here is to use [[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&lt;br /&gt;
  var html = this.format_block( &#039;jstpl_myDialogTemplate&#039;, { &lt;br /&gt;
                arg1: myArg1,&lt;br /&gt;
                arg2: myArg2,&lt;br /&gt;
                ...&lt;br /&gt;
            } );  &lt;br /&gt;
  &lt;br /&gt;
  // Show the dialog&lt;br /&gt;
  this.myDlg.setContent( html ); // Must be set before calling show() so that the size of the content is defined before positioning the dialog&lt;br /&gt;
  this.myDlg.show();&lt;br /&gt;
  &lt;br /&gt;
  // Now that the dialog has been displayed, you can connect your method to some dialog elements&lt;br /&gt;
  // Example, if you have an &amp;quot;OK&amp;quot; button in the HTML of your dialog:&lt;br /&gt;
  dojo.connect( $(&#039;my_ok_button&#039;), &#039;onclick&#039;, this, function(evt){&lt;br /&gt;
                evt.preventDefault();&lt;br /&gt;
                this.myDlg.destroy();&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
If necessary, you can remove the default top right corner &#039;close&#039; icon, or replace the function called when it is clicked:&lt;br /&gt;
  // Removes the default close icon&lt;br /&gt;
  this.myDlg.hideCloseIcon();&lt;br /&gt;
&lt;br /&gt;
  // Replace the function call when it&#039;s clicked&lt;br /&gt;
  this.myDlg.replaceCloseCallback( function() { ... } );&lt;br /&gt;
&lt;br /&gt;
=== Scoring dialogs ===&lt;br /&gt;
&lt;br /&gt;
Sometimes at the end of a round you want to display a big table that details the points wins in each section of the game.&lt;br /&gt;
&lt;br /&gt;
Example: in Hearts game, we display at the end of each round the number of &amp;quot;heart&amp;quot; cards collected by each player, the player who collected the Queen of Spades, and the total number of points loose by each player.&lt;br /&gt;
&lt;br /&gt;
Scoring dialogs are managed entirely on &#039;&#039;&#039;PHP side&#039;&#039;&#039;, but they are described here as their effects are visible only on client side.&lt;br /&gt;
&lt;br /&gt;
Displaying a scoring dialog is quite simple and is using a special notification type: &amp;quot;tableWindow&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // on PHP side:&lt;br /&gt;
  $this-&amp;gt;notifyAllPlayers( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table&lt;br /&gt;
        ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;table&amp;quot; argument is a 2 dimensional PHP array that describe the table you want to display, line by line and column by column.&lt;br /&gt;
&lt;br /&gt;
Example: display an 3x3 array of strings&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = array(&lt;br /&gt;
      array( &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, &amp;quot;three&amp;quot; ),    // This is my first line&lt;br /&gt;
      array( &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ),    // This is my second line&lt;br /&gt;
      array( &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; )    // This is my third line&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see above, in each &amp;quot;cell&amp;quot; of your array you can display a simple string value. But you can also display a complex value with a template and associated arguments like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = array(&lt;br /&gt;
      array( &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, array( &amp;quot;str&amp;quot; =&amp;gt; clienttranslate(&amp;quot;a string with an ${argument}&amp;quot;), &amp;quot;args&amp;quot; =&amp;gt; array( &#039;argument&#039; =&amp;gt; &#039;argument_value&#039; )  ) ),&lt;br /&gt;
      array( &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ), &lt;br /&gt;
      array( &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; )&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is especially useful when you want to display player names with colors. Example from &amp;quot;Hearts&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $firstRow = array( &#039;&#039; );&lt;br /&gt;
        foreach( $players as $player_id =&amp;gt; $player )&lt;br /&gt;
        {&lt;br /&gt;
            $firstRow[] = array( &#039;str&#039; =&amp;gt; &#039;${player_name}&#039;,&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; array( &#039;player_name&#039; =&amp;gt; $player[&#039;player_name&#039;] ),&lt;br /&gt;
                                 &#039;type&#039; =&amp;gt; &#039;header&#039;&lt;br /&gt;
                               );&lt;br /&gt;
        }&lt;br /&gt;
        $table[] = $firstRow;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use three extra attributes in the parameter array for the notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $this-&amp;gt;notifyAllPlayers( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table,&lt;br /&gt;
            &amp;quot;header&amp;quot; =&amp;gt; array(&#039;str&#039; =&amp;gt; clienttranslate(&#039;Table header with parameter ${number}&#039;),&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; array( &#039;number&#039; =&amp;gt; 3 ),&lt;br /&gt;
                               ),&lt;br /&gt;
            &amp;quot;footer&amp;quot; =&amp;gt; &#039;&amp;lt;div&amp;gt;Some footer&amp;lt;/div&amp;gt;&#039;,&lt;br /&gt;
            &amp;quot;closing&amp;quot; =&amp;gt; clienttranslate( &amp;quot;Closing button label&amp;quot; )&lt;br /&gt;
        ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;header&#039;&#039;&#039;: the content for this parameter will display before the table (also, the html will be parsed and player names will be colored according to the current game colors). &lt;br /&gt;
*&#039;&#039;&#039;footer&#039;&#039;&#039;: the content for this parameter will display after the table (no parsing for coloring the player names)&lt;br /&gt;
*&#039;&#039;&#039;closing&#039;&#039;&#039;: if this parameter is used, a button will be displayed with this label at the bottom of the popup and will allow players to close it (more easily than by clicking the top right &#039;cross&#039; icon).&lt;br /&gt;
&lt;br /&gt;
=== Scoring animated display ===&lt;br /&gt;
&lt;br /&gt;
Sometimes (Terra Mystica final scoring for example), you may want to display a score value over an element to make the scoring easier to follow for the players.&lt;br /&gt;
You can do it with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.displayScoring( anchor_id, color, score, duration, offset_x, offset_y );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;anchor_id&#039;&#039;&#039;: ID of the element to place the animated score onto (without the &#039;#&#039;) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;color&#039;&#039;&#039;: hexadecimal RGB representation of the color (should be the color of the scoring player), but without a leading &#039;#&#039;.  For instance, &#039;ff0000&#039; for red.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;score&#039;&#039;&#039;: numeric score to display, prefixed by a &#039;+&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;duration&#039;&#039;&#039;: animation duration in milliseconds&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;offset_x&#039;&#039;&#039; and &#039;&#039;&#039;offset_y&#039;&#039;&#039;: if both offset_x and offset_y are defined and not null, apply the following offset (in pixels) to the scoring animation. Note that the score is centered in the anchor, so the offsets might have to be negative if you calculate the position.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: if you want to display successively each score, you can use &#039;&#039;this.notifqueue.setSynchronous()&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
=== Speech bubble ===&lt;br /&gt;
&lt;br /&gt;
For better interactivity in some games (Love Letter for example), you may use comic book style speech bubbles to express the players voices.&lt;br /&gt;
This is done with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.showBubble(anchor_id, text, delay, duration, custom_class)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
text - what to put in bubble, can be html actually not just text&lt;br /&gt;
&lt;br /&gt;
delay - in milliseconds is optional (default 0)&lt;br /&gt;
&lt;br /&gt;
duration -  in milliseconds is optional (default 3000)&lt;br /&gt;
&lt;br /&gt;
custom_class - extra class to add to bubble is optional, if you need to override the default bubble style&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: if your bubble could overlap other active elements of the interface (buttons in particular), as it stays in place even after disappearing, you should use a custom class to give it the style &amp;quot;pointer-events: none;&amp;quot; in order to intercept click events.&lt;br /&gt;
&lt;br /&gt;
Note: If you want this visually, but want to take complete control over this bubble and its animation (for example to make it permanent) you can just use div with &#039;discussion_bubble&#039; class on it, and content of div is what will be shown.&lt;br /&gt;
&lt;br /&gt;
== Update players score ==&lt;br /&gt;
&lt;br /&gt;
The column player_score from the player table is automatically loaded into this.scoreCtrl and therefore into the stars location on the player board. This occurs sometime after the &amp;lt;gamename&amp;gt;.js setup() function. However this score must be updated as the game progresses through player notifications (notifs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Increase a player score (with a positive or negative number):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].incValue( score_delta );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set a player score to a specific value:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].setValue( new_score );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set a player score to a specific value with animation :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].toValue( new_score );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typical usage would be (that will process &#039;score&#039; notification):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setupNotifications : function() {&lt;br /&gt;
              ...&lt;br /&gt;
             dojo.subscribe(&#039;score&#039;, this, &amp;quot;notif_score&amp;quot;);&lt;br /&gt;
        },&lt;br /&gt;
        notif_score: function(notif) {&lt;br /&gt;
            this.scoreCtrl[notif.args.player_id].setValue(notif.args.player_score);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Players panels ==&lt;br /&gt;
&lt;br /&gt;
=== Adding stuff to player&#039;s panel ===&lt;br /&gt;
&lt;br /&gt;
At first, create a new &amp;quot;JS template&amp;quot; string in your template (tpl) file:&lt;br /&gt;
&lt;br /&gt;
(from Gomoku example)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var jstpl_player_board = &#039;\&amp;lt;div class=&amp;quot;cp_board&amp;quot;&amp;gt;\&lt;br /&gt;
    &amp;lt;div id=&amp;quot;stoneicon_p${id}&amp;quot; class=&amp;quot;gmk_stoneicon gmk_stoneicon_${color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;span id=&amp;quot;stonecount_p${id}&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;\&lt;br /&gt;
&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, you add this piece of code in your JS file to add this template to each player panel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Setting up player boards&lt;br /&gt;
            for( var player_id in gamedatas.players )&lt;br /&gt;
            {&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                         &lt;br /&gt;
                // Setting up players boards if needed&lt;br /&gt;
                var player_board_div = $(&#039;player_board_&#039;+player_id);&lt;br /&gt;
                dojo.place( this.format_block(&#039;jstpl_player_board&#039;, player ), player_board_div );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Note: the code above is of course from your &amp;quot;setup&amp;quot; function in your Javascript).&lt;br /&gt;
&lt;br /&gt;
Very often, you have to distinguish current player and others players. In this case, you just have to create another JS template (ex: jstpl_otherplayer_board) and use it when &amp;quot;player_id&amp;quot; is different than &amp;quot;this.player_id&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s panel disabling/enabling ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.disablePlayerPanel( player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disable given player panel (the panel background become gray).&lt;br /&gt;
&lt;br /&gt;
Usually, this is used to signal that this played passes, or will be inactive during a while.&lt;br /&gt;
&lt;br /&gt;
Note that the only effect of this is visual. There are no consequences on the behaviour of the panel itself.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.enablePlayerPanel( player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable a player panel that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.enableAllPlayerPanels()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable all player panels that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
== Image loading ==&lt;br /&gt;
&lt;br /&gt;
See also [[Game_art:_img_directory]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Be careful&#039;&#039;&#039;: by default, ALL images of your img directory are loaded on a player&#039;s browser when he loads the game. For this reason, don&#039;t let in your img directory images that are not useful, otherwise it&#039;s going to slowdown the game load.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dontPreloadImage( image_file_name )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using dontPreloadImage, you tell the interface to not preload a specific image in your img directory.&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is particularly useful if for example you have 2 different themes for a game. To accelerate the loading of the game, you can specify to not preload images corresponding to the other theme.&lt;br /&gt;
&lt;br /&gt;
Another example of use: in &amp;quot;Gosu&amp;quot; game with Kamakor extension, you play with 5 sets of cards among 10 available. Cards images are organized by sets, and we only preload the images corresponding to the 5 current sets with &#039;&#039;&#039;ensureSpecificGameImageLoading( image_file_names_array )&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// By default, do not preload anything&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan1.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan2.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan3.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan4.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan5.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan6.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan7.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan8.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan9.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan10.png&#039; );&lt;br /&gt;
var to_preload = [];&lt;br /&gt;
for( i in this.gamedatas.clans )&lt;br /&gt;
{&lt;br /&gt;
	var clan_id = this.gamedatas.clans[i];&lt;br /&gt;
	to_preload.push( &#039;clan&#039;+clan_id+&#039;.png&#039; );&lt;br /&gt;
}&lt;br /&gt;
if( to_preload.length == 5 )&lt;br /&gt;
{&lt;br /&gt;
	this.ensureSpecificGameImageLoading( to_preload );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; You don&#039;t need to specify to not preload game box images (game_box.png, game_box75.png...) since they are not preloaded by default.&lt;br /&gt;
&lt;br /&gt;
== Other useful stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.hitch&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.hitch, you can create a callback function that will run with your game object context whatever happen.&lt;br /&gt;
&lt;br /&gt;
Typical example: display a BGA confirmation dialog with a callback function created with dojo.hitch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), dojo.hitch( this, function() {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, function( result ) {} );&lt;br /&gt;
        } ) );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, using dojo.hitch, we ensure that the &amp;quot;this&amp;quot; object will be set when the callback is called.&lt;br /&gt;
&lt;br /&gt;
NOTE: In modern JS there are lambdas that eliminate need for that, the example above will look like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), () =&amp;gt; {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, (result) =&amp;gt; {} );&lt;br /&gt;
        } );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; updateCounters(counters)&lt;br /&gt;
: Useful for updating game counters in the player panel (such as resources). &lt;br /&gt;
: &#039;counters&#039; arg is an associative array [counter_name_value =&amp;gt; [ &#039;counter_name&#039; =&amp;gt; counter_name_value, &#039;counter_value&#039; =&amp;gt; counter_value_value], ... ]&lt;br /&gt;
: All counters must be referenced in this.gamedatas.counters and will be updated.&lt;br /&gt;
: DOM objects referenced by &#039;counter_name&#039; will have their innerHTML updated with &#039;counter_value&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;onScreenWidthChange()&#039;&#039;&#039;&lt;br /&gt;
:This function can be overridden in your game to manage some resizing on the client side when the browser window is resized. This function is also triggered at load time, so it can be used to adapt to the :viewport size at the start of the game too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;updatePageTitle()&#039;&#039;&#039;&lt;br /&gt;
:This function allows to update the current page title and turn description according to the game state. If the current game state description this.gamedatas.gamestate.descriptionmyturn is modified before :calling the function, it allows to update the turn description without changing state.&lt;br /&gt;
&lt;br /&gt;
Example from Terra Mystica:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onClickFavorTile: function( evt ) {&lt;br /&gt;
    ...&lt;br /&gt;
    if ( ... ) {&lt;br /&gt;
        this.gamedatas.gamestate.descriptionmyturn = _(&#039;Special action: &#039;) + _(&#039;Advance 1 space	on a Cult track&#039;);&lt;br /&gt;
        this.updatePageTitle();&lt;br /&gt;
        this.removeActionButtons();&lt;br /&gt;
        this.addActionButton( ... );&lt;br /&gt;
         ...&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA GUI components ==&lt;br /&gt;
&lt;br /&gt;
BGA framework provides some useful ready-to-use components for the game interface:&lt;br /&gt;
&lt;br /&gt;
[[Studio#BGA_Studio_game_components_reference]]&lt;br /&gt;
&lt;br /&gt;
Note that each time you are using an additional component, you must declare it at the top of your Javascript file in the list of modules used.&lt;br /&gt;
&lt;br /&gt;
Example if you are using &amp;quot;ebg.stock&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;  /// &amp;lt;=== we are using ebg.stock module&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA Buttons ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addActionButton( id, label, method, (opt)destination, (opt)blinking, (opt)color )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use this method to add an action button in the main action status bar.&lt;br /&gt;
&lt;br /&gt;
Arguments:&lt;br /&gt;
* id: an element ID that should be unique in your HTML DOM document.&lt;br /&gt;
* label: the text of the button. Should be translatable (use _() function).&lt;br /&gt;
* method: the name of your method that must be triggered when the player clicks on this button.&lt;br /&gt;
* destination (optional): deprecated, do not use this. Use &#039;&#039;&#039;null&#039;&#039;&#039; as value if you need to specify other arguments.&lt;br /&gt;
* blinking (optional): if set to &#039;&#039;&#039;true&#039;&#039;&#039;, the button is going blink to catch player&#039;s attention. Please don&#039;t abuse of blinking button.&lt;br /&gt;
* color: could be &#039;&#039;&#039;blue&#039;&#039;&#039; (default), &#039;&#039;&#039;red&#039;&#039;&#039; or &#039;&#039;&#039;gray&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You should only use this method in your &amp;quot;onUpdateActionButtons&amp;quot; method. Usually, you use it like this (from Hearts example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onUpdateActionButtons: function( stateName, args ) {&lt;br /&gt;
                      &lt;br /&gt;
            if (this.isCurrentPlayerActive()) {            &lt;br /&gt;
                switch( stateName ) {&lt;br /&gt;
                case &#039;giveCards&#039;:&lt;br /&gt;
                    this.addActionButton( &#039;giveCards_button&#039;, _(&#039;Give selected cards&#039;), &#039;onGiveCards&#039; ); &lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are adding a &amp;quot;Give selected cards&amp;quot; button in the case we are on game state &amp;quot;giveCards&amp;quot;. When player clicks on this button, it triggers our &amp;quot;onGiveCards&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Example using blinking red button:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     this.addActionButton( &#039;commit_button&#039;, _(&#039;Confirm&#039;), &#039;onConfirm&#039;, null, true, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: at least in studio example above will make button huge, because it sets it display of blinking things to &#039;&#039;&#039;block&#039;&#039;&#039;, &lt;br /&gt;
if you don&#039;t like it you have to change css display value&lt;br /&gt;
of the button to inline-block (the id of the button is the first argument, i.e &#039;commit_button&#039; in example above)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;buttons with images&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use the same method, but add extra class to a button to disable the padding and style it, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.addActionButton( &#039;button_brick&#039;, &#039;&amp;lt;div class=&amp;quot;brick&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, ()=&amp;gt;{... on brick ...}, null, null, &#039;gray&#039;); &lt;br /&gt;
dojo.addClass(&#039;button_brick&#039;,&#039;bgaimagebutton&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.bgaimagebutton {&lt;br /&gt;
  padding: 0px 12px;&lt;br /&gt;
  min-height: 28px;&lt;br /&gt;
  border: none;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use this a lot, you can define a helper function, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This method can be used instead of addActionButton, to add a button which is an image (i.e. resource). Can be useful when player&lt;br /&gt;
 * need to make a choice of resources or tokens.&lt;br /&gt;
 */&lt;br /&gt;
addImageActionButton: function(id, div, handler, bcolor, tooltip) {&lt;br /&gt;
	if (typeof bcolor == &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
		bcolor = &amp;quot;gray&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
	// this will actually make a transparent button id color = gray&lt;br /&gt;
	this.addActionButton(id, div, handler, &#039;&#039;, false, bcolor);&lt;br /&gt;
	// remove boarder, for images it better without&lt;br /&gt;
	dojo.style(id, &amp;quot;border&amp;quot;, &amp;quot;none&amp;quot;);&lt;br /&gt;
	// but add shadow style (box-shadow, see css)&lt;br /&gt;
	dojo.addClass(id, &amp;quot;shadow bgaimagebutton&amp;quot;);&lt;br /&gt;
	// you can also add addition styles, such as background&lt;br /&gt;
	if (tooltip) {&lt;br /&gt;
		dojo.attr(id, &amp;quot;title&amp;quot;, tooltip);&lt;br /&gt;
	}&lt;br /&gt;
	return $(id);&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;buttons outside of action bar&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can create a custom button, but the BGA framework provides a standard button that requires only .css classes: &#039;&#039;&#039;bgabutton&#039;&#039;&#039; and &#039;&#039;&#039;bgabutton_${color}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_blue&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My blue button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_gray&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My gray button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_red&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My red button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_red bgabutton_big&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My big red button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: To see it in action, check out &#039;&#039;Coloretto&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Note: You can also create button using addActionButton() method, then move anywhere&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.addActionButton( &#039;commit_button&#039;, _(&#039;Confirm&#039;), &#039;onConfirm&#039;, null, true, &#039;red&#039;); &lt;br /&gt;
dojo.place(&#039;commit_button&#039;,&#039;player_board&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Disabling:&#039;&#039;&#039;&lt;br /&gt;
You can disable the &#039;&#039;&#039;bgabutton&#039;&#039;&#039; by adding the css class &#039;&#039;&#039;disabled&#039;&#039;&#039; in you js. The disabled button is still visible but is grey and not clickable.&lt;br /&gt;
For example in the &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039; : &lt;br /&gt;
&amp;lt;pre&amp;gt;this.addActionButton( &#039;play_button_id&#039;, _(&#039;Play 1 to 3 cards&#039;), &#039;playFunctionButton&#039;, null, false, &#039;blue&#039; ); //Create a blue button&lt;br /&gt;
if (Condition == true)&lt;br /&gt;
{&lt;br /&gt;
	dojo.addClass( &#039;play_button_id&#039;, &#039;disabled&#039;);//disable the button&lt;br /&gt;
}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Sounds ==&lt;br /&gt;
&lt;br /&gt;
Add a custom sound and make it load with your interface:&lt;br /&gt;
&lt;br /&gt;
Add this in your template (.tpl) file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.mp3&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_o_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.ogg&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this is a requirement to provide both a mp3 and a ogg file.&lt;br /&gt;
&lt;br /&gt;
Play the sound (from your .js file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
playSound(&#039;&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&#039;);             &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the standard &amp;quot;move&amp;quot; sound for this move (to replace it with your custom sound):&lt;br /&gt;
&lt;br /&gt;
Add this to your notification handler:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.disableNextMoveSound();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: it only disable the sound for the next move.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Your_game_state_machine:_states.inc.php&amp;diff=10022</id>
		<title>Your game state machine: states.inc.php</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Your_game_state_machine:_states.inc.php&amp;diff=10022"/>
		<updated>2021-11-02T01:46:25Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Difference between Single active and Multi active states */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This file describes the state machine of your game (all the game states properties, and the transitions to get from one state to another).&lt;br /&gt;
&lt;br /&gt;
Important: to understand the game state machine, it&#039;s recommended that you read this presentation first:&lt;br /&gt;
&lt;br /&gt;
[http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine]&lt;br /&gt;
&lt;br /&gt;
== Overall structure ==&lt;br /&gt;
&lt;br /&gt;
The machine states are described by a PHP associative array.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
    // The initial state. Please do not modify.&lt;br /&gt;
    1 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Game setup&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
    &lt;br /&gt;
    // Note: ID=2 =&amp;gt; your first state&lt;br /&gt;
&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card or pass&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a card or pass&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
    		&amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; =&amp;gt; 2, &amp;quot;pass&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
=== id ===&lt;br /&gt;
&lt;br /&gt;
The keys determine game state IDs (in the example above: 1 and 2).&lt;br /&gt;
&lt;br /&gt;
IDs must be positive integers.&lt;br /&gt;
&lt;br /&gt;
ID=1 is reserved for the first game state and should not be used (and you must not modify it).&lt;br /&gt;
&lt;br /&gt;
ID=99 is reserved for the last game state (end of the game) (and you must not modify it).&lt;br /&gt;
&lt;br /&gt;
Note: you may use any ID, even an ID greater than 100. But you cannot use 1 or 99.&lt;br /&gt;
&lt;br /&gt;
Note²: You must not use the same ID twice.&lt;br /&gt;
&lt;br /&gt;
Note³: When a game is in prod and you change the ID of a state, all active games (including many turn based) will behave unpredictably.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
The name of a game state is used to identify it in your game logic.&lt;br /&gt;
&lt;br /&gt;
Several game states can share the same name; however, this is not recommended.&lt;br /&gt;
&lt;br /&gt;
Warning! Do not put spaces in the name. This could cause unexpected problems in some cases.&lt;br /&gt;
&lt;br /&gt;
PHP example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Get current game state&lt;br /&gt;
$state = $this-&amp;gt;gamestate-&amp;gt;state();&lt;br /&gt;
if( $state[&#039;name&#039;] == &#039;myGameState&#039; )&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
JS example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )&lt;br /&gt;
        {&lt;br /&gt;
            console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )&lt;br /&gt;
            case &#039;myGameState&#039;:&lt;br /&gt;
            &lt;br /&gt;
                // Do some stuff at the beginning at this game state&lt;br /&gt;
                ....&lt;br /&gt;
                &lt;br /&gt;
                break;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== type ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
You can use 3 types of game states:&lt;br /&gt;
* activeplayer (1 player is active and must play.)&lt;br /&gt;
* multipleactiveplayer (1..N players can be active and must play.)&lt;br /&gt;
* game (No player is active. This is a transitional state to do something automatic specified by the game rules.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Make sure you don&#039;t mistype the value of this attribute. If you do (e.g. &#039;multiactiveplayer&#039; instead of &#039;multipleactiveplayer&#039;), things won&#039;t work, and you might have a hard time figuring out why.&lt;br /&gt;
&lt;br /&gt;
=== description ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
The description is the string that is displayed in the main action bar (top of the screen) when the state is active.&lt;br /&gt;
&lt;br /&gt;
When a string is specified as a description, you must use &amp;quot;clienttranslate&amp;quot; in order for the string to be translated on the client side:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card or pass&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the description string, you can use ${actplayer} to refer to the active player.&lt;br /&gt;
&lt;br /&gt;
You can also use custom arguments in your description. These custom arguments correspond to values returned by your &amp;quot;args&amp;quot; PHP method (see below &amp;quot;args&amp;quot; field).&lt;br /&gt;
&lt;br /&gt;
Example of custom field:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must choose ${nbr} identical energies&#039;),&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argMyArgumentMethod&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    function argMyArgumentMethod()&lt;br /&gt;
    {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;nbr&#039; =&amp;gt; 2  // In this case ${nbr} in the description will be replaced by &amp;quot;2&amp;quot;&lt;br /&gt;
        );    &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: You may specify an empty string (&amp;quot;&amp;quot;) here if it never happens that the game remains in this state (i.e., if this state immediately jumps to another state when activated).&lt;br /&gt;
&lt;br /&gt;
Note²: Usually, you specify a string for &amp;quot;activeplayer&amp;quot; and &amp;quot;multipleactiveplayer&amp;quot; game states, and you specify an empty string for &amp;quot;game&amp;quot; game states. BUT, if you are using synchronous notifications, the client can remain on a &amp;quot;game&amp;quot; type game state for a few seconds, and in this case it may be useful to display a description in the status bar while in this state.&lt;br /&gt;
&lt;br /&gt;
=== descriptionmyturn ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039; when the state type is &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;descriptionmyturn&amp;quot; has exactly the same role and properties as &amp;quot;description&amp;quot;, except that this value is displayed to the current active player - or to all active players in case of a multipleactiveplayer game state.&lt;br /&gt;
&lt;br /&gt;
In general, we have this situation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} can take some actions&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} can take some actions&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you can use ${you} in descriptionmyturn so the description will display &amp;quot;You&amp;quot; instead of the name of the player.&lt;br /&gt;
&lt;br /&gt;
Note 2: you can use ${otherplayer} to refer to some other player if you want this to be shown in player&#039;s color, but you must provide otherplayer_id as argument (along with otherplayer) to specify this player&#039;s id in this case or game won&#039;t load.&lt;br /&gt;
&lt;br /&gt;
I.e.&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} can follow action of ${otherplayer}&#039;),&lt;br /&gt;
&lt;br /&gt;
And this will have to be state arguments for this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function arg_playerTurnFollow(){&lt;br /&gt;
        return [&#039;otherplayer&#039;=&amp;gt; $this-&amp;gt;getLeaderPlayerName(),&lt;br /&gt;
                &#039;otherplayer_id&#039;=&amp;gt; $this-&amp;gt;getLeaderPlayerId()&lt;br /&gt;
        ];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== action ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039; when the state type is &amp;quot;game.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;action&amp;quot; specifies a PHP method to call when entering this game state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    28 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Updating some stuff...&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;st_gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_gameTurnNextPlayer() {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        $next_player_id = $this-&amp;gt;getPlayerAfter($player_id);&lt;br /&gt;
        $this-&amp;gt;giveExtraTime($next_player_id);&lt;br /&gt;
        $this-&amp;gt;incStat(1, &#039;turns_number&#039;, $next_player_id);&lt;br /&gt;
        $this-&amp;gt;incStat(1, &#039;turns_number&#039;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer($next_player_id);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;next&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usually, for a &amp;quot;game&amp;quot; state type, the action method is used to perform automatic functions specified by the rules (for example: check victory conditions, deal cards for a new round, go to the next player, etc.) and then jump to another game state.&lt;br /&gt;
&lt;br /&gt;
Note: a BGA convention specifies that PHP methods called with &amp;quot;action&amp;quot; are prefixed by &amp;quot;st&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Note: this field CAN be used for player states to set something up; e.g., for multiplayer states, it can make all players active.&lt;br /&gt;
&lt;br /&gt;
Example for action in player state:&lt;br /&gt;
in states.inc.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurnPlace&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Other player must place ships&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must place ships (click on YOUR SHIPS board to place)&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;multipleactiveplayer&amp;quot;,&lt;br /&gt;
            &#039;action&#039; =&amp;gt; &#039;st_MultiPlayerInit&#039;,&lt;br /&gt;
            &#039;args&#039; =&amp;gt; &#039;arg_playerTurnPlace&#039;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playPlace&amp;quot; ),&lt;br /&gt;
            &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;next&amp;quot; =&amp;gt; 4, &amp;quot;last&amp;quot; =&amp;gt; 99)&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in mygame.game.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_MultiPlayerInit() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== transitions ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
With &amp;quot;transitions&amp;quot; you specify which game state(s) you can jump to from a given game state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    25 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;myGameState&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextPlayer&amp;quot; =&amp;gt; 27, &amp;quot;endRound&amp;quot; =&amp;gt; 39 ),&lt;br /&gt;
        ....&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, if &amp;quot;myGameState&amp;quot; is the current active game state, I can jump to the game state with ID 27 or the game state with ID 39.&lt;br /&gt;
&lt;br /&gt;
Example to jump to ID 27:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;nextState( &amp;quot;nextPlayer&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Important: &amp;quot;nextPlayer&amp;quot; is the name of the transition, and NOT the name of the target game state. Multiple transitions can lead to the same game state.&lt;br /&gt;
&lt;br /&gt;
Note: If there is only 1 transition, you may give it an empty name.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
    &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 27 ),&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;nextState(  );     // We don&#039;t need to specify a transition as there is only one here&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== possibleactions ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039; when the game state is &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;possibleactions&amp;quot; defines the actions possible by the players in this game state, and ensures they cannot perform actions that are not allowed in this state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In states.game.php:&lt;br /&gt;
       	&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
        function playCard( ...)&lt;br /&gt;
        {&lt;br /&gt;
             self::checkAction( &amp;quot;playCard&amp;quot; );    // Will fail if &amp;quot;playCard&amp;quot; is not specified in &amp;quot;possibleactions&amp;quot; in the current game state.&lt;br /&gt;
&lt;br /&gt;
            ....&lt;br /&gt;
&lt;br /&gt;
In mygame.js:&lt;br /&gt;
        playCard: function( ... )&lt;br /&gt;
        {&lt;br /&gt;
            if( this.checkAction( &amp;quot;playCard&amp;quot; ) ) // Will fail if &amp;quot;playCard&amp;quot; is not specified in &amp;quot;possibleactions&amp;quot; in the current game state.&lt;br /&gt;
            {  return ;   }&lt;br /&gt;
&lt;br /&gt;
            ....&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== args ===&lt;br /&gt;
&lt;br /&gt;
(optional)&lt;br /&gt;
&lt;br /&gt;
Sometimes it happens that you need some information on the client side (i.e., for your game interface) only for a specific game state.&lt;br /&gt;
&lt;br /&gt;
Example 1: in &#039;&#039;Reversi&#039;&#039;, the list of possible moves during the playerTurn state.&lt;br /&gt;
&lt;br /&gt;
Example 2: in &#039;&#039;Caylus&#039;&#039;, the number of remaining king&#039;s favors to choose in the state where the player is choosing a favor.&lt;br /&gt;
&lt;br /&gt;
Example 3: in &#039;&#039;Can&#039;t Stop&#039;&#039;, the list of possible die combinations to be displayed to the active player so that he can choose from among them.&lt;br /&gt;
&lt;br /&gt;
In such a situation, you can specify a method name as the « args » argument for your game state. This method must retrieve some piece of information about the game (example: for &#039;&#039;Reversi&#039;&#039;, the list of possible moves) and return it.&lt;br /&gt;
&lt;br /&gt;
Thus, this data can be transmitted to the clients and used by the clients to display it. It should always be an associative array.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see a complete example using args with &#039;&#039;Reversi&#039;&#039; game:&lt;br /&gt;
&lt;br /&gt;
In states.inc.php, we specify an &#039;&#039;&#039;args&#039;&#039;&#039; argument for gamestate &#039;&#039;&#039;playerTurn&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    10 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a disc&#039;),&lt;br /&gt;
		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a disc&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argPlayerTurn&amp;quot;,    // &amp;lt;==== HERE&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &#039;playDisc&#039; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playDisc&amp;quot; =&amp;gt; 11, &amp;quot;zombiePass&amp;quot; =&amp;gt; 11 )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It corresponds to a &#039;&#039;&#039;argPlayerTurn&#039;&#039;&#039; method in our PHP code (reversi.game.php):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn() {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, when we enter into the &#039;&#039;&#039;playerTurn&#039;&#039;&#039; game state on the client side, we can highlight the possible moves on the board using information returned by &#039;&#039;&#039;argPlayerTurn&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )  {&lt;br /&gt;
           console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )  {&lt;br /&gt;
            case &#039;playerTurn&#039;:&lt;br /&gt;
                this.updatePossibleMoves( args.args.possibleMoves );&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Naming and API conventions ====&lt;br /&gt;
&lt;br /&gt;
As a BGA convention, PHP methods called with &amp;quot;args&amp;quot; are prefixed by &amp;quot;arg&amp;quot; followed by state name (example: &#039;&#039;&#039;argPlayerTurn&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
All &amp;quot;arg*&amp;quot; methods are put into corresponding section of .game.php file commented as&lt;br /&gt;
   //////////// Game state arguments&lt;br /&gt;
&lt;br /&gt;
Arg method MUST return array. Return integer or string will result in some undebuggable exceptions.&lt;br /&gt;
&lt;br /&gt;
Arg method MUST be defined in php if it is declared in state description, if you don&#039;t need it comment it out from the states.inc.php file (the &#039;&#039;&#039;args&#039;&#039;&#039; parameter). If you not sure if you need it or not you can keep it returning empty array until you figure it out.&lt;br /&gt;
&lt;br /&gt;
    function argPlayerTurn() {&lt;br /&gt;
        return array(); // must be an array&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: the &amp;quot;args&amp;quot; method can be called before the &amp;quot;action&amp;quot; method so don&#039;t expect data modifications by the &amp;quot;action&amp;quot; method to be available in the &amp;quot;args&amp;quot; method!&lt;br /&gt;
Also don&#039;t modify database in this method!&lt;br /&gt;
&lt;br /&gt;
You should NOT be calling getCurrentPlayer() in the context of this function, since state transitions are broadcasted to all player independent of who initiated it. Instead you should send information on per player basis (Note: if this is private info see section below). &lt;br /&gt;
&lt;br /&gt;
If you using this function in multi-player state, you should not call getActivePlayer() either, you should send per player info:&lt;br /&gt;
&lt;br /&gt;
    function arg_playerTurn() {&lt;br /&gt;
        $res = array ();&lt;br /&gt;
        $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player_info ) {&lt;br /&gt;
            $color = $player_info [&#039;player_color&#039;];&lt;br /&gt;
            $res [$player_id] = array(&amp;quot;color&amp;quot;=&amp;gt;$color);&lt;br /&gt;
        }&lt;br /&gt;
        return $res;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Note: you never need to send player color like this, this is just an example.&lt;br /&gt;
&lt;br /&gt;
Note 2: you CAN call methods that return all active players if multi-player states if its relevant.&lt;br /&gt;
&lt;br /&gt;
==== Other usages ====&lt;br /&gt;
&lt;br /&gt;
You can use values returned by your &amp;quot;args&amp;quot; method to have some custom values in your &amp;quot;description&amp;quot;/&amp;quot;descriptionmyturn&amp;quot;, i.e. in states.inc.php:&lt;br /&gt;
&lt;br /&gt;
   &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play ${color} disc&#039;),&lt;br /&gt;
&lt;br /&gt;
So arg function will be something like:&lt;br /&gt;
&lt;br /&gt;
  function argPlayerTurn() {&lt;br /&gt;
        return array(&#039;color&#039;=&amp;gt;this-&amp;gt;getActivePlayerColor()); &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
You can use args also in &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039; function on js side, however two important notes:&lt;br /&gt;
* it is just &#039;&#039;&#039;args&#039;&#039;&#039; (not args.args like in &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;)&lt;br /&gt;
* it is args of the current state, which may not be state you think it will be! This method is called during change of active player, which happens in some weird place especially during &amp;quot;multipleactiveplayer&amp;quot; states. If you pulling your hair thinking why its &amp;quot;undefined&amp;quot; on js side - check the current state.&lt;br /&gt;
&lt;br /&gt;
==== Private info in args ====&lt;br /&gt;
&lt;br /&gt;
By default, all data provided through this method are PUBLIC TO ALL PLAYERS. Please do not send any private data with this method, as a cheater could see it even it is not used explicitly by the game interface logic.&lt;br /&gt;
&lt;br /&gt;
However, it is possible to specify that some data should be sent to specific players only.&lt;br /&gt;
&lt;br /&gt;
Example 1: send information to active player(s) only:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn()  {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;_private&#039; =&amp;gt; array(          // Using &amp;quot;_private&amp;quot; keyword, all data inside this array will be made private&lt;br /&gt;
                &#039;active&#039; =&amp;gt; array(       // Using &amp;quot;active&amp;quot; keyword inside &amp;quot;_private&amp;quot;, you select active player(s)&lt;br /&gt;
                    &#039;somePrivateData&#039; =&amp;gt; self::getSomePrivateData()   // will be send only to active player(s)&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()          // will be sent to all players&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inside the js file, these variables will be available through `args.args._private`. (e.g. `args.args._private.somePrivateData` -- it is not `args._private.active.somePrivateData` nor is it `args.somePrivateData`)&lt;br /&gt;
&lt;br /&gt;
Example 2: send information to a specific player (&amp;lt;specific_player_id&amp;gt;) only:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn()  {&lt;br /&gt;
        $specific_player_id = ...; // calculate some-how&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;_private&#039; =&amp;gt; array(   // all data inside this array will be private&lt;br /&gt;
                $specific_player_id =&amp;gt; array(   // will be sent only to that player   &lt;br /&gt;
                    &#039;somePrivateData&#039; =&amp;gt; self::getSomePrivateData()   &lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()   // will be sent to all players&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: in certain situations (i.e. &amp;quot;multipleactiveplayer&amp;quot; game state) these &amp;quot;private data&amp;quot; features can have a significant impact on performance. Please do not use if not needed.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use these private args in the &amp;quot;description&amp;quot; messages, like &amp;quot;${you} have to play ${_private.count} cards&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Translations in args ====&lt;br /&gt;
You can do the same as in notification by adding i18n parameter, i.e&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function argPlayerTurn()  {&lt;br /&gt;
 return [&lt;br /&gt;
      &#039;i18n&#039; =&amp;gt; [&#039;terrainName&#039; ],&lt;br /&gt;
      &#039;terrainName&#039; =&amp;gt; ($this-&amp;gt;token_types[$terrain][&#039;name&#039;]), // this should be defined in material.inc.php and with clienttranslate &lt;br /&gt;
      &#039;terrain&#039; =&amp;gt; $terrain,&lt;br /&gt;
   ];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Than you can do something like this in state:&lt;br /&gt;
  &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must place a house on ${terrainName}&#039;),&lt;br /&gt;
&lt;br /&gt;
See more in [[Translations]]&lt;br /&gt;
&lt;br /&gt;
=== updateGameProgression ===&lt;br /&gt;
&lt;br /&gt;
(optional)&lt;br /&gt;
&lt;br /&gt;
If you specify &amp;quot;updateGameProgression =&amp;gt; true&amp;quot; in a game state, your &amp;quot;getGameProgression&amp;quot; PHP method will be called at the beginning of this game state - and thus the game progression of the game will be updated.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;At least one&#039;&#039; of your game states (any one) must specify &amp;quot;updateGameProgression=&amp;gt;true&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Implementation Notes ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Using Named Constants for States ===&lt;br /&gt;
&lt;br /&gt;
Using numeric constants is prone to errors. If you want you can declare state constants as PHP named constants. This way you can&lt;br /&gt;
use them in the states file and in game.php as well&lt;br /&gt;
&lt;br /&gt;
EXAMPLE:&lt;br /&gt;
&lt;br /&gt;
states.inc.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// define contants for state ids&lt;br /&gt;
if (!defined(&#039;STATE_END_GAME&#039;)) { // ensure this block is only invoked once, since it is included multiple times&lt;br /&gt;
   define(&amp;quot;STATE_PLAYER_TURN&amp;quot;, 2);&lt;br /&gt;
   define(&amp;quot;STATE_GAME_TURN&amp;quot;, 3);&lt;br /&gt;
   define(&amp;quot;STATE_PLAYER_TURN_CUBES&amp;quot;, 4);&lt;br /&gt;
   define(&amp;quot;STATE_END_GAME&amp;quot;, 99);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
&lt;br /&gt;
    STATE_PLAYER_TURN =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must select an Action Space or Pass&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must select an Action Space or Pass&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &#039;arg_playerTurn&#039;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;selectWorkerAction&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
    		&amp;quot;transitions&amp;quot; =&amp;gt; array( &lt;br /&gt;
    		        &amp;quot;loopback&amp;quot; =&amp;gt; STATE_PLAYER_TURN,&lt;br /&gt;
    		        &amp;quot;playCubes&amp;quot; =&amp;gt; STATE_PLAYER_TURN_CUBES,&lt;br /&gt;
    		        &amp;quot;pass&amp;quot; =&amp;gt; STATE_GAME_TURN )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example of multipleactiveplayer state ===&lt;br /&gt;
&lt;br /&gt;
This is an example of a multipleactiveplayer state:&lt;br /&gt;
&lt;br /&gt;
  2 =&amp;gt;  array (&lt;br /&gt;
    &#039;name&#039; =&amp;gt; &#039;playerTurnSetup&#039;,&lt;br /&gt;
    &#039;type&#039; =&amp;gt; &#039;multipleactiveplayer&#039;,&lt;br /&gt;
    &#039;description&#039; =&amp;gt; clienttranslate(&#039;Other players must choose one Objective&#039;),&lt;br /&gt;
    &#039;descriptionmyturn&#039; =&amp;gt; clienttranslate(&#039;${you} must choose one Objective card to keep&#039;),&lt;br /&gt;
    &#039;possibleactions&#039; =&amp;gt;     array (&#039;playKeep&#039; ),&lt;br /&gt;
    &#039;transitions&#039; =&amp;gt;    array (       &#039;next&#039; =&amp;gt; 5, &#039;loopback&#039; =&amp;gt; 2, ),&lt;br /&gt;
    &#039;action&#039; =&amp;gt; &#039;st_MultiPlayerInit&#039;,&lt;br /&gt;
    &#039;args&#039; =&amp;gt; &#039;arg_playerTurnSetup&#039;,&lt;br /&gt;
  ),&lt;br /&gt;
&lt;br /&gt;
In game.php:&lt;br /&gt;
    // this will make all players multiactive just before entering the state&lt;br /&gt;
    function st_MultiPlayerInit() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Note: if you want exact this function its already defined in table class its called &#039;stMakeEveryoneActive&#039;&lt;br /&gt;
&lt;br /&gt;
When ending the player action, instead of a state transition, deactivate player.&lt;br /&gt;
&lt;br /&gt;
    function action_playKeep($cardId) {&lt;br /&gt;
        $this-&amp;gt;checkAction(&#039;playKeep&#039;);&lt;br /&gt;
        $player_id = $this-&amp;gt;getCurrentPlayerId(); // CURRENT!!! not active&lt;br /&gt;
        ... // some logic here&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive($player_id, &#039;next&#039;); // deactivate player; if none left, transition to &#039;next&#039; state&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Difference between Single active and Multi active states ===&lt;br /&gt;
In a classic &amp;quot;activePlayer&amp;quot; state:&lt;br /&gt;
&lt;br /&gt;
* You cannot change the active player DURING the state. This is to ensure that during 1 activePlayer state, only ONE player is active&lt;br /&gt;
* As a consequence, you must set the active player BEFORE entering the activePlayer state&lt;br /&gt;
* In such states on JS side onUpdateActionButtons is called before onEnteringState during game play (but after during reload, i.e. F5)&lt;br /&gt;
* Finally, during onEnteringState, on JS side, the active player is signaled as active and the information is reliable and usable.&lt;br /&gt;
&lt;br /&gt;
In a &amp;quot;multiplePlayer&amp;quot; state:&lt;br /&gt;
&lt;br /&gt;
* You can (and must) change the active players DURING the state&lt;br /&gt;
* During such a state, players can be activated/desactivated anytime during the state, giving you the maximum of possibilities.&lt;br /&gt;
* You shouldn&#039;t set active player before entering the state. But you can set it in &amp;quot;state initializer&amp;quot; php function (see example above st_MultiPlayerInit)&lt;br /&gt;
* Finally, during onEnteringState, on JS side, the active players are NOT active yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/inactive status.&lt;br /&gt;
&lt;br /&gt;
=== Designing states ===&lt;br /&gt;
&lt;br /&gt;
As a general rule you state machine should resemble &amp;quot;round/turn overview&amp;quot; from the game rule-book. Normally if book say its player turn and player can do multiple things during their turn it is still only&lt;br /&gt;
one player state (plus a game to switch player), not muliple states.&lt;br /&gt;
&lt;br /&gt;
In a classic game (i.e. chess), there is only active player at any time, so it is simple playerTurn/gameTurn sequence and you only need 2 states.&lt;br /&gt;
&lt;br /&gt;
[[File:Simplestates.png]]&lt;br /&gt;
&lt;br /&gt;
In complex euro game there can be multiple rounds, and each round have phases which can be distinctly unique, i.e. in first phase everybody draws card and discard (multi-player), then player have one turn each (single-active), then another is resolution of actions from players and some of them may become active again, then there is round upkeep/reset. This would require one multi-player state for phase 1, pair of states for phase2 (singel-active + game), pair of states for phase3 and finally round-end/unkeep game state.&lt;br /&gt;
&lt;br /&gt;
For pair of active player/game states you can make player state first, which transitions to game state, or the other way around, you start with game state which transition to active player state, its loop in any case but depends on how you want to do &amp;quot;phase&amp;quot; initiazations.&lt;br /&gt;
&lt;br /&gt;
[[File:Eurogamestates.png]]&lt;br /&gt;
&lt;br /&gt;
=== Complete examples ===&lt;br /&gt;
&lt;br /&gt;
Example of simple game where player take turns&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if ( !defined(&#039;STATE_END_GAME&#039;)) { // guard since this included multiple times&lt;br /&gt;
    define(&amp;quot;STATE_PLAYER_TURN&amp;quot;, 2);&lt;br /&gt;
    define(&amp;quot;STATE_GAME_TURN_NEXT_PLAYER&amp;quot;, 3);&lt;br /&gt;
    define(&amp;quot;STATE_PLAYER_GAME_END&amp;quot;, 4);&lt;br /&gt;
    define(&amp;quot;STATE_END_GAME&amp;quot;, 99);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$machinestates = [    &lt;br /&gt;
        1 =&amp;gt; [ // The initial state. Please do not modify.&lt;br /&gt;
               &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
               &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
               &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
               &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
               &amp;quot;transitions&amp;quot; =&amp;gt; [ &amp;quot;&amp;quot; =&amp;gt; STATE_PLAYER_TURN ] ],&lt;br /&gt;
        // Game states &lt;br /&gt;
        STATE_PLAYER_TURN =&amp;gt; [ // main active player state &lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must do something or pass&#039;),&lt;br /&gt;
                &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must do something or pass&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;arg_playerTurn&amp;quot;,&lt;br /&gt;
                &amp;quot;possibleactions&amp;quot; =&amp;gt; [ &amp;quot;dosomething&amp;quot;,&amp;quot;pass&amp;quot; ],&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; [ &amp;quot;next&amp;quot; =&amp;gt; STATE_GAME_TURN_NEXT_PLAYER,&amp;quot;last&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END ] // &lt;br /&gt;
        ],&lt;br /&gt;
        STATE_GAME_TURN_NEXT_PLAYER =&amp;gt; [ // next player state&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Upkeep...&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;, //&lt;br /&gt;
                &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;st_gameTurnNextPlayer&amp;quot;, //&lt;br /&gt;
                &amp;quot;updateGameProgression&amp;quot; =&amp;gt; true,&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; [ &amp;quot;next&amp;quot; =&amp;gt; STATE_PLAYER_TURN,&amp;quot;loopback&amp;quot; =&amp;gt; STATE_GAME_TURN_NEXT_PLAYER,&lt;br /&gt;
                        &amp;quot;last&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END ], // TODO replace with STATE_END_GAME, its there to use undo/restore during dev&lt;br /&gt;
        ],&lt;br /&gt;
    &lt;br /&gt;
        STATE_PLAYER_GAME_END =&amp;gt; [ // active player state for debugging end of game&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerGameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} Game Over&#039;),&lt;br /&gt;
                &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} Game Over&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;arg_playerTurn&amp;quot;,&lt;br /&gt;
                &amp;quot;possibleactions&amp;quot; =&amp;gt; [&amp;quot;endGame&amp;quot;],&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; [&amp;quot;next&amp;quot; =&amp;gt; STATE_END_GAME,&amp;quot;loopback&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END ] // &lt;br /&gt;
        ],&lt;br /&gt;
        // End of Game states &lt;br /&gt;
        // Final state.&lt;br /&gt;
        // Please do not modify (and do not overload action/args methods).&lt;br /&gt;
        STATE_END_GAME =&amp;gt; [&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;End of game&amp;quot;),&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
                &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argGameEnd&amp;quot; ] &lt;br /&gt;
&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Your_game_state_machine:_states.inc.php&amp;diff=10021</id>
		<title>Your game state machine: states.inc.php</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Your_game_state_machine:_states.inc.php&amp;diff=10021"/>
		<updated>2021-11-02T01:39:58Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Diffrence between Single active and Multi active states */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This file describes the state machine of your game (all the game states properties, and the transitions to get from one state to another).&lt;br /&gt;
&lt;br /&gt;
Important: to understand the game state machine, it&#039;s recommended that you read this presentation first:&lt;br /&gt;
&lt;br /&gt;
[http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine]&lt;br /&gt;
&lt;br /&gt;
== Overall structure ==&lt;br /&gt;
&lt;br /&gt;
The machine states are described by a PHP associative array.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
    // The initial state. Please do not modify.&lt;br /&gt;
    1 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Game setup&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
    &lt;br /&gt;
    // Note: ID=2 =&amp;gt; your first state&lt;br /&gt;
&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card or pass&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a card or pass&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
    		&amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; =&amp;gt; 2, &amp;quot;pass&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Syntax ==&lt;br /&gt;
&lt;br /&gt;
=== id ===&lt;br /&gt;
&lt;br /&gt;
The keys determine game state IDs (in the example above: 1 and 2).&lt;br /&gt;
&lt;br /&gt;
IDs must be positive integers.&lt;br /&gt;
&lt;br /&gt;
ID=1 is reserved for the first game state and should not be used (and you must not modify it).&lt;br /&gt;
&lt;br /&gt;
ID=99 is reserved for the last game state (end of the game) (and you must not modify it).&lt;br /&gt;
&lt;br /&gt;
Note: you may use any ID, even an ID greater than 100. But you cannot use 1 or 99.&lt;br /&gt;
&lt;br /&gt;
Note²: You must not use the same ID twice.&lt;br /&gt;
&lt;br /&gt;
Note³: When a game is in prod and you change the ID of a state, all active games (including many turn based) will behave unpredictably.&lt;br /&gt;
&lt;br /&gt;
=== name ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
The name of a game state is used to identify it in your game logic.&lt;br /&gt;
&lt;br /&gt;
Several game states can share the same name; however, this is not recommended.&lt;br /&gt;
&lt;br /&gt;
Warning! Do not put spaces in the name. This could cause unexpected problems in some cases.&lt;br /&gt;
&lt;br /&gt;
PHP example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Get current game state&lt;br /&gt;
$state = $this-&amp;gt;gamestate-&amp;gt;state();&lt;br /&gt;
if( $state[&#039;name&#039;] == &#039;myGameState&#039; )&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
JS example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )&lt;br /&gt;
        {&lt;br /&gt;
            console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )&lt;br /&gt;
            case &#039;myGameState&#039;:&lt;br /&gt;
            &lt;br /&gt;
                // Do some stuff at the beginning at this game state&lt;br /&gt;
                ....&lt;br /&gt;
                &lt;br /&gt;
                break;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== type ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
You can use 3 types of game states:&lt;br /&gt;
* activeplayer (1 player is active and must play.)&lt;br /&gt;
* multipleactiveplayer (1..N players can be active and must play.)&lt;br /&gt;
* game (No player is active. This is a transitional state to do something automatic specified by the game rules.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; Make sure you don&#039;t mistype the value of this attribute. If you do (e.g. &#039;multiactiveplayer&#039; instead of &#039;multipleactiveplayer&#039;), things won&#039;t work, and you might have a hard time figuring out why.&lt;br /&gt;
&lt;br /&gt;
=== description ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
The description is the string that is displayed in the main action bar (top of the screen) when the state is active.&lt;br /&gt;
&lt;br /&gt;
When a string is specified as a description, you must use &amp;quot;clienttranslate&amp;quot; in order for the string to be translated on the client side:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card or pass&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the description string, you can use ${actplayer} to refer to the active player.&lt;br /&gt;
&lt;br /&gt;
You can also use custom arguments in your description. These custom arguments correspond to values returned by your &amp;quot;args&amp;quot; PHP method (see below &amp;quot;args&amp;quot; field).&lt;br /&gt;
&lt;br /&gt;
Example of custom field:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must choose ${nbr} identical energies&#039;),&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argMyArgumentMethod&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    function argMyArgumentMethod()&lt;br /&gt;
    {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;nbr&#039; =&amp;gt; 2  // In this case ${nbr} in the description will be replaced by &amp;quot;2&amp;quot;&lt;br /&gt;
        );    &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: You may specify an empty string (&amp;quot;&amp;quot;) here if it never happens that the game remains in this state (i.e., if this state immediately jumps to another state when activated).&lt;br /&gt;
&lt;br /&gt;
Note²: Usually, you specify a string for &amp;quot;activeplayer&amp;quot; and &amp;quot;multipleactiveplayer&amp;quot; game states, and you specify an empty string for &amp;quot;game&amp;quot; game states. BUT, if you are using synchronous notifications, the client can remain on a &amp;quot;game&amp;quot; type game state for a few seconds, and in this case it may be useful to display a description in the status bar while in this state.&lt;br /&gt;
&lt;br /&gt;
=== descriptionmyturn ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039; when the state type is &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;descriptionmyturn&amp;quot; has exactly the same role and properties as &amp;quot;description&amp;quot;, except that this value is displayed to the current active player - or to all active players in case of a multipleactiveplayer game state.&lt;br /&gt;
&lt;br /&gt;
In general, we have this situation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} can take some actions&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} can take some actions&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you can use ${you} in descriptionmyturn so the description will display &amp;quot;You&amp;quot; instead of the name of the player.&lt;br /&gt;
&lt;br /&gt;
Note 2: you can use ${otherplayer} to refer to some other player if you want this to be shown in player&#039;s color, but you must provide otherplayer_id as argument (along with otherplayer) to specify this player&#039;s id in this case or game won&#039;t load.&lt;br /&gt;
&lt;br /&gt;
I.e.&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} can follow action of ${otherplayer}&#039;),&lt;br /&gt;
&lt;br /&gt;
And this will have to be state arguments for this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function arg_playerTurnFollow(){&lt;br /&gt;
        return [&#039;otherplayer&#039;=&amp;gt; $this-&amp;gt;getLeaderPlayerName(),&lt;br /&gt;
                &#039;otherplayer_id&#039;=&amp;gt; $this-&amp;gt;getLeaderPlayerId()&lt;br /&gt;
        ];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== action ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039; when the state type is &amp;quot;game.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;action&amp;quot; specifies a PHP method to call when entering this game state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    28 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Updating some stuff...&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;st_gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_gameTurnNextPlayer() {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        $next_player_id = $this-&amp;gt;getPlayerAfter($player_id);&lt;br /&gt;
        $this-&amp;gt;giveExtraTime($next_player_id);&lt;br /&gt;
        $this-&amp;gt;incStat(1, &#039;turns_number&#039;, $next_player_id);&lt;br /&gt;
        $this-&amp;gt;incStat(1, &#039;turns_number&#039;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer($next_player_id);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;next&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usually, for a &amp;quot;game&amp;quot; state type, the action method is used to perform automatic functions specified by the rules (for example: check victory conditions, deal cards for a new round, go to the next player, etc.) and then jump to another game state.&lt;br /&gt;
&lt;br /&gt;
Note: a BGA convention specifies that PHP methods called with &amp;quot;action&amp;quot; are prefixed by &amp;quot;st&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Note: this field CAN be used for player states to set something up; e.g., for multiplayer states, it can make all players active.&lt;br /&gt;
&lt;br /&gt;
Example for action in player state:&lt;br /&gt;
in states.inc.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurnPlace&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Other player must place ships&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must place ships (click on YOUR SHIPS board to place)&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;multipleactiveplayer&amp;quot;,&lt;br /&gt;
            &#039;action&#039; =&amp;gt; &#039;st_MultiPlayerInit&#039;,&lt;br /&gt;
            &#039;args&#039; =&amp;gt; &#039;arg_playerTurnPlace&#039;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playPlace&amp;quot; ),&lt;br /&gt;
            &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;next&amp;quot; =&amp;gt; 4, &amp;quot;last&amp;quot; =&amp;gt; 99)&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
in mygame.game.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_MultiPlayerInit() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== transitions ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
With &amp;quot;transitions&amp;quot; you specify which game state(s) you can jump to from a given game state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    25 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;myGameState&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextPlayer&amp;quot; =&amp;gt; 27, &amp;quot;endRound&amp;quot; =&amp;gt; 39 ),&lt;br /&gt;
        ....&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, if &amp;quot;myGameState&amp;quot; is the current active game state, I can jump to the game state with ID 27 or the game state with ID 39.&lt;br /&gt;
&lt;br /&gt;
Example to jump to ID 27:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;nextState( &amp;quot;nextPlayer&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Important: &amp;quot;nextPlayer&amp;quot; is the name of the transition, and NOT the name of the target game state. Multiple transitions can lead to the same game state.&lt;br /&gt;
&lt;br /&gt;
Note: If there is only 1 transition, you may give it an empty name.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In states.inc.php:&lt;br /&gt;
    &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 27 ),&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;nextState(  );     // We don&#039;t need to specify a transition as there is only one here&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== possibleactions ===&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;&#039;Mandatory&#039;&#039;&#039; when the game state is &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;possibleactions&amp;quot; defines the actions possible by the players in this game state, and ensures they cannot perform actions that are not allowed in this state.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In states.game.php:&lt;br /&gt;
       	&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
&lt;br /&gt;
In mygame.game.php:&lt;br /&gt;
        function playCard( ...)&lt;br /&gt;
        {&lt;br /&gt;
             self::checkAction( &amp;quot;playCard&amp;quot; );    // Will fail if &amp;quot;playCard&amp;quot; is not specified in &amp;quot;possibleactions&amp;quot; in the current game state.&lt;br /&gt;
&lt;br /&gt;
            ....&lt;br /&gt;
&lt;br /&gt;
In mygame.js:&lt;br /&gt;
        playCard: function( ... )&lt;br /&gt;
        {&lt;br /&gt;
            if( this.checkAction( &amp;quot;playCard&amp;quot; ) ) // Will fail if &amp;quot;playCard&amp;quot; is not specified in &amp;quot;possibleactions&amp;quot; in the current game state.&lt;br /&gt;
            {  return ;   }&lt;br /&gt;
&lt;br /&gt;
            ....&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== args ===&lt;br /&gt;
&lt;br /&gt;
(optional)&lt;br /&gt;
&lt;br /&gt;
Sometimes it happens that you need some information on the client side (i.e., for your game interface) only for a specific game state.&lt;br /&gt;
&lt;br /&gt;
Example 1: in &#039;&#039;Reversi&#039;&#039;, the list of possible moves during the playerTurn state.&lt;br /&gt;
&lt;br /&gt;
Example 2: in &#039;&#039;Caylus&#039;&#039;, the number of remaining king&#039;s favors to choose in the state where the player is choosing a favor.&lt;br /&gt;
&lt;br /&gt;
Example 3: in &#039;&#039;Can&#039;t Stop&#039;&#039;, the list of possible die combinations to be displayed to the active player so that he can choose from among them.&lt;br /&gt;
&lt;br /&gt;
In such a situation, you can specify a method name as the « args » argument for your game state. This method must retrieve some piece of information about the game (example: for &#039;&#039;Reversi&#039;&#039;, the list of possible moves) and return it.&lt;br /&gt;
&lt;br /&gt;
Thus, this data can be transmitted to the clients and used by the clients to display it. It should always be an associative array.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s see a complete example using args with &#039;&#039;Reversi&#039;&#039; game:&lt;br /&gt;
&lt;br /&gt;
In states.inc.php, we specify an &#039;&#039;&#039;args&#039;&#039;&#039; argument for gamestate &#039;&#039;&#039;playerTurn&#039;&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    10 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a disc&#039;),&lt;br /&gt;
		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a disc&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argPlayerTurn&amp;quot;,    // &amp;lt;==== HERE&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &#039;playDisc&#039; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playDisc&amp;quot; =&amp;gt; 11, &amp;quot;zombiePass&amp;quot; =&amp;gt; 11 )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It corresponds to a &#039;&#039;&#039;argPlayerTurn&#039;&#039;&#039; method in our PHP code (reversi.game.php):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn() {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, when we enter into the &#039;&#039;&#039;playerTurn&#039;&#039;&#039; game state on the client side, we can highlight the possible moves on the board using information returned by &#039;&#039;&#039;argPlayerTurn&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onEnteringState: function( stateName, args )  {&lt;br /&gt;
           console.log( &#039;Entering state: &#039;+stateName );&lt;br /&gt;
            &lt;br /&gt;
            switch( stateName )  {&lt;br /&gt;
            case &#039;playerTurn&#039;:&lt;br /&gt;
                this.updatePossibleMoves( args.args.possibleMoves );&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Naming and API conventions ====&lt;br /&gt;
&lt;br /&gt;
As a BGA convention, PHP methods called with &amp;quot;args&amp;quot; are prefixed by &amp;quot;arg&amp;quot; followed by state name (example: &#039;&#039;&#039;argPlayerTurn&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
All &amp;quot;arg*&amp;quot; methods are put into corresponding section of .game.php file commented as&lt;br /&gt;
   //////////// Game state arguments&lt;br /&gt;
&lt;br /&gt;
Arg method MUST return array. Return integer or string will result in some undebuggable exceptions.&lt;br /&gt;
&lt;br /&gt;
Arg method MUST be defined in php if it is declared in state description, if you don&#039;t need it comment it out from the states.inc.php file (the &#039;&#039;&#039;args&#039;&#039;&#039; parameter). If you not sure if you need it or not you can keep it returning empty array until you figure it out.&lt;br /&gt;
&lt;br /&gt;
    function argPlayerTurn() {&lt;br /&gt;
        return array(); // must be an array&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: the &amp;quot;args&amp;quot; method can be called before the &amp;quot;action&amp;quot; method so don&#039;t expect data modifications by the &amp;quot;action&amp;quot; method to be available in the &amp;quot;args&amp;quot; method!&lt;br /&gt;
Also don&#039;t modify database in this method!&lt;br /&gt;
&lt;br /&gt;
You should NOT be calling getCurrentPlayer() in the context of this function, since state transitions are broadcasted to all player independent of who initiated it. Instead you should send information on per player basis (Note: if this is private info see section below). &lt;br /&gt;
&lt;br /&gt;
If you using this function in multi-player state, you should not call getActivePlayer() either, you should send per player info:&lt;br /&gt;
&lt;br /&gt;
    function arg_playerTurn() {&lt;br /&gt;
        $res = array ();&lt;br /&gt;
        $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player_info ) {&lt;br /&gt;
            $color = $player_info [&#039;player_color&#039;];&lt;br /&gt;
            $res [$player_id] = array(&amp;quot;color&amp;quot;=&amp;gt;$color);&lt;br /&gt;
        }&lt;br /&gt;
        return $res;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Note: you never need to send player color like this, this is just an example.&lt;br /&gt;
&lt;br /&gt;
Note 2: you CAN call methods that return all active players if multi-player states if its relevant.&lt;br /&gt;
&lt;br /&gt;
==== Other usages ====&lt;br /&gt;
&lt;br /&gt;
You can use values returned by your &amp;quot;args&amp;quot; method to have some custom values in your &amp;quot;description&amp;quot;/&amp;quot;descriptionmyturn&amp;quot;, i.e. in states.inc.php:&lt;br /&gt;
&lt;br /&gt;
   &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play ${color} disc&#039;),&lt;br /&gt;
&lt;br /&gt;
So arg function will be something like:&lt;br /&gt;
&lt;br /&gt;
  function argPlayerTurn() {&lt;br /&gt;
        return array(&#039;color&#039;=&amp;gt;this-&amp;gt;getActivePlayerColor()); &lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
You can use args also in &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039; function on js side, however two important notes:&lt;br /&gt;
* it is just &#039;&#039;&#039;args&#039;&#039;&#039; (not args.args like in &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;)&lt;br /&gt;
* it is args of the current state, which may not be state you think it will be! This method is called during change of active player, which happens in some weird place especially during &amp;quot;multipleactiveplayer&amp;quot; states. If you pulling your hair thinking why its &amp;quot;undefined&amp;quot; on js side - check the current state.&lt;br /&gt;
&lt;br /&gt;
==== Private info in args ====&lt;br /&gt;
&lt;br /&gt;
By default, all data provided through this method are PUBLIC TO ALL PLAYERS. Please do not send any private data with this method, as a cheater could see it even it is not used explicitly by the game interface logic.&lt;br /&gt;
&lt;br /&gt;
However, it is possible to specify that some data should be sent to specific players only.&lt;br /&gt;
&lt;br /&gt;
Example 1: send information to active player(s) only:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn()  {&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;_private&#039; =&amp;gt; array(          // Using &amp;quot;_private&amp;quot; keyword, all data inside this array will be made private&lt;br /&gt;
                &#039;active&#039; =&amp;gt; array(       // Using &amp;quot;active&amp;quot; keyword inside &amp;quot;_private&amp;quot;, you select active player(s)&lt;br /&gt;
                    &#039;somePrivateData&#039; =&amp;gt; self::getSomePrivateData()   // will be send only to active player(s)&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()          // will be sent to all players&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Inside the js file, these variables will be available through `args.args._private`. (e.g. `args.args._private.somePrivateData` -- it is not `args._private.active.somePrivateData` nor is it `args.somePrivateData`)&lt;br /&gt;
&lt;br /&gt;
Example 2: send information to a specific player (&amp;lt;specific_player_id&amp;gt;) only:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argPlayerTurn()  {&lt;br /&gt;
        $specific_player_id = ...; // calculate some-how&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;_private&#039; =&amp;gt; array(   // all data inside this array will be private&lt;br /&gt;
                $specific_player_id =&amp;gt; array(   // will be sent only to that player   &lt;br /&gt;
                    &#039;somePrivateData&#039; =&amp;gt; self::getSomePrivateData()   &lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
&lt;br /&gt;
            &#039;possibleMoves&#039; =&amp;gt; self::getPossibleMoves()   // will be sent to all players&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: in certain situations (i.e. &amp;quot;multipleactiveplayer&amp;quot; game state) these &amp;quot;private data&amp;quot; features can have a significant impact on performance. Please do not use if not needed.&lt;br /&gt;
&lt;br /&gt;
It is also possible to use these private args in the &amp;quot;description&amp;quot; messages, like &amp;quot;${you} have to play ${_private.count} cards&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Translations in args ====&lt;br /&gt;
You can do the same as in notification by adding i18n parameter, i.e&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function argPlayerTurn()  {&lt;br /&gt;
 return [&lt;br /&gt;
      &#039;i18n&#039; =&amp;gt; [&#039;terrainName&#039; ],&lt;br /&gt;
      &#039;terrainName&#039; =&amp;gt; ($this-&amp;gt;token_types[$terrain][&#039;name&#039;]), // this should be defined in material.inc.php and with clienttranslate &lt;br /&gt;
      &#039;terrain&#039; =&amp;gt; $terrain,&lt;br /&gt;
   ];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Than you can do something like this in state:&lt;br /&gt;
  &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must place a house on ${terrainName}&#039;),&lt;br /&gt;
&lt;br /&gt;
See more in [[Translations]]&lt;br /&gt;
&lt;br /&gt;
=== updateGameProgression ===&lt;br /&gt;
&lt;br /&gt;
(optional)&lt;br /&gt;
&lt;br /&gt;
If you specify &amp;quot;updateGameProgression =&amp;gt; true&amp;quot; in a game state, your &amp;quot;getGameProgression&amp;quot; PHP method will be called at the beginning of this game state - and thus the game progression of the game will be updated.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;At least one&#039;&#039; of your game states (any one) must specify &amp;quot;updateGameProgression=&amp;gt;true&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Implementation Notes ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Using Named Constants for States ===&lt;br /&gt;
&lt;br /&gt;
Using numeric constants is prone to errors. If you want you can declare state constants as PHP named constants. This way you can&lt;br /&gt;
use them in the states file and in game.php as well&lt;br /&gt;
&lt;br /&gt;
EXAMPLE:&lt;br /&gt;
&lt;br /&gt;
states.inc.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// define contants for state ids&lt;br /&gt;
if (!defined(&#039;STATE_END_GAME&#039;)) { // ensure this block is only invoked once, since it is included multiple times&lt;br /&gt;
   define(&amp;quot;STATE_PLAYER_TURN&amp;quot;, 2);&lt;br /&gt;
   define(&amp;quot;STATE_GAME_TURN&amp;quot;, 3);&lt;br /&gt;
   define(&amp;quot;STATE_PLAYER_TURN_CUBES&amp;quot;, 4);&lt;br /&gt;
   define(&amp;quot;STATE_END_GAME&amp;quot;, 99);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
&lt;br /&gt;
    STATE_PLAYER_TURN =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must select an Action Space or Pass&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must select an Action Space or Pass&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &#039;arg_playerTurn&#039;,&lt;br /&gt;
    		&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;selectWorkerAction&amp;quot;, &amp;quot;pass&amp;quot; ),&lt;br /&gt;
    		&amp;quot;transitions&amp;quot; =&amp;gt; array( &lt;br /&gt;
    		        &amp;quot;loopback&amp;quot; =&amp;gt; STATE_PLAYER_TURN,&lt;br /&gt;
    		        &amp;quot;playCubes&amp;quot; =&amp;gt; STATE_PLAYER_TURN_CUBES,&lt;br /&gt;
    		        &amp;quot;pass&amp;quot; =&amp;gt; STATE_GAME_TURN )&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Example of multipleactiveplayer state ===&lt;br /&gt;
&lt;br /&gt;
This is an example of a multipleactiveplayer state:&lt;br /&gt;
&lt;br /&gt;
  2 =&amp;gt;  array (&lt;br /&gt;
    &#039;name&#039; =&amp;gt; &#039;playerTurnSetup&#039;,&lt;br /&gt;
    &#039;type&#039; =&amp;gt; &#039;multipleactiveplayer&#039;,&lt;br /&gt;
    &#039;description&#039; =&amp;gt; clienttranslate(&#039;Other players must choose one Objective&#039;),&lt;br /&gt;
    &#039;descriptionmyturn&#039; =&amp;gt; clienttranslate(&#039;${you} must choose one Objective card to keep&#039;),&lt;br /&gt;
    &#039;possibleactions&#039; =&amp;gt;     array (&#039;playKeep&#039; ),&lt;br /&gt;
    &#039;transitions&#039; =&amp;gt;    array (       &#039;next&#039; =&amp;gt; 5, &#039;loopback&#039; =&amp;gt; 2, ),&lt;br /&gt;
    &#039;action&#039; =&amp;gt; &#039;st_MultiPlayerInit&#039;,&lt;br /&gt;
    &#039;args&#039; =&amp;gt; &#039;arg_playerTurnSetup&#039;,&lt;br /&gt;
  ),&lt;br /&gt;
&lt;br /&gt;
In game.php:&lt;br /&gt;
    // this will make all players multiactive just before entering the state&lt;br /&gt;
    function st_MultiPlayerInit() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Note: if you want exact this function its already defined in table class its called &#039;stMakeEveryoneActive&#039;&lt;br /&gt;
&lt;br /&gt;
When ending the player action, instead of a state transition, deactivate player.&lt;br /&gt;
&lt;br /&gt;
    function action_playKeep($cardId) {&lt;br /&gt;
        $this-&amp;gt;checkAction(&#039;playKeep&#039;);&lt;br /&gt;
        $player_id = $this-&amp;gt;getCurrentPlayerId(); // CURRENT!!! not active&lt;br /&gt;
        ... // some logic here&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive($player_id, &#039;next&#039;); // deactivate player; if none left, transition to &#039;next&#039; state&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== Difference between Single active and Multi active states ===&lt;br /&gt;
In a classic &amp;quot;activePlayer&amp;quot; state:&lt;br /&gt;
&lt;br /&gt;
* You cannot change the active player DURING the state. This is to ensure that during 1 activePlayer state, only ONE player is active&lt;br /&gt;
* As a consequence, you must set the active player BEFORE entering the activePlayer state&lt;br /&gt;
* In such sates on JS side onUpdateActionButtons is called before onEnteringState during game play (but after during reload, i.e. F5)&lt;br /&gt;
* Finally, during onEnteringState, on JS side, the active player is signaled as active and the information is reliable and usable.&lt;br /&gt;
&lt;br /&gt;
In a &amp;quot;multiplePlayer&amp;quot; state:&lt;br /&gt;
&lt;br /&gt;
* You can (and must) change the active players DURING the state&lt;br /&gt;
* During such a state, players can be activated/desactivated anytime during the state, giving you the maximum of possibilities.&lt;br /&gt;
* You shouldn&#039;t set active player before entering the state. But you can set it in &amp;quot;state initializer&amp;quot; php function (see example above st_MultiPlayerInit)&lt;br /&gt;
* Finally, during onEnteringState, on JS side, the active players are NOT active yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/inactive status.&lt;br /&gt;
&lt;br /&gt;
=== Designing states ===&lt;br /&gt;
&lt;br /&gt;
As a general rule you state machine should resemble &amp;quot;round/turn overview&amp;quot; from the game rule-book. Normally if book say its player turn and player can do multiple things during their turn it is still only&lt;br /&gt;
one player state (plus a game to switch player), not muliple states.&lt;br /&gt;
&lt;br /&gt;
In a classic game (i.e. chess), there is only active player at any time, so it is simple playerTurn/gameTurn sequence and you only need 2 states.&lt;br /&gt;
&lt;br /&gt;
[[File:Simplestates.png]]&lt;br /&gt;
&lt;br /&gt;
In complex euro game there can be multiple rounds, and each round have phases which can be distinctly unique, i.e. in first phase everybody draws card and discard (multi-player), then player have one turn each (single-active), then another is resolution of actions from players and some of them may become active again, then there is round upkeep/reset. This would require one multi-player state for phase 1, pair of states for phase2 (singel-active + game), pair of states for phase3 and finally round-end/unkeep game state.&lt;br /&gt;
&lt;br /&gt;
For pair of active player/game states you can make player state first, which transitions to game state, or the other way around, you start with game state which transition to active player state, its loop in any case but depends on how you want to do &amp;quot;phase&amp;quot; initiazations.&lt;br /&gt;
&lt;br /&gt;
[[File:Eurogamestates.png]]&lt;br /&gt;
&lt;br /&gt;
=== Complete examples ===&lt;br /&gt;
&lt;br /&gt;
Example of simple game where player take turns&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if ( !defined(&#039;STATE_END_GAME&#039;)) { // guard since this included multiple times&lt;br /&gt;
    define(&amp;quot;STATE_PLAYER_TURN&amp;quot;, 2);&lt;br /&gt;
    define(&amp;quot;STATE_GAME_TURN_NEXT_PLAYER&amp;quot;, 3);&lt;br /&gt;
    define(&amp;quot;STATE_PLAYER_GAME_END&amp;quot;, 4);&lt;br /&gt;
    define(&amp;quot;STATE_END_GAME&amp;quot;, 99);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$machinestates = [    &lt;br /&gt;
        1 =&amp;gt; [ // The initial state. Please do not modify.&lt;br /&gt;
               &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
               &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
               &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
               &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
               &amp;quot;transitions&amp;quot; =&amp;gt; [ &amp;quot;&amp;quot; =&amp;gt; STATE_PLAYER_TURN ] ],&lt;br /&gt;
        // Game states &lt;br /&gt;
        STATE_PLAYER_TURN =&amp;gt; [ // main active player state &lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must do something or pass&#039;),&lt;br /&gt;
                &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must do something or pass&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;arg_playerTurn&amp;quot;,&lt;br /&gt;
                &amp;quot;possibleactions&amp;quot; =&amp;gt; [ &amp;quot;dosomething&amp;quot;,&amp;quot;pass&amp;quot; ],&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; [ &amp;quot;next&amp;quot; =&amp;gt; STATE_GAME_TURN_NEXT_PLAYER,&amp;quot;last&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END ] // &lt;br /&gt;
        ],&lt;br /&gt;
        STATE_GAME_TURN_NEXT_PLAYER =&amp;gt; [ // next player state&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Upkeep...&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;, //&lt;br /&gt;
                &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;st_gameTurnNextPlayer&amp;quot;, //&lt;br /&gt;
                &amp;quot;updateGameProgression&amp;quot; =&amp;gt; true,&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; [ &amp;quot;next&amp;quot; =&amp;gt; STATE_PLAYER_TURN,&amp;quot;loopback&amp;quot; =&amp;gt; STATE_GAME_TURN_NEXT_PLAYER,&lt;br /&gt;
                        &amp;quot;last&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END ], // TODO replace with STATE_END_GAME, its there to use undo/restore during dev&lt;br /&gt;
        ],&lt;br /&gt;
    &lt;br /&gt;
        STATE_PLAYER_GAME_END =&amp;gt; [ // active player state for debugging end of game&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerGameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} Game Over&#039;),&lt;br /&gt;
                &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} Game Over&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;arg_playerTurn&amp;quot;,&lt;br /&gt;
                &amp;quot;possibleactions&amp;quot; =&amp;gt; [&amp;quot;endGame&amp;quot;],&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; [&amp;quot;next&amp;quot; =&amp;gt; STATE_END_GAME,&amp;quot;loopback&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END ] // &lt;br /&gt;
        ],&lt;br /&gt;
        // End of Game states &lt;br /&gt;
        // Final state.&lt;br /&gt;
        // Please do not modify (and do not overload action/args methods).&lt;br /&gt;
        STATE_END_GAME =&amp;gt; [&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;End of game&amp;quot;),&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
                &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argGameEnd&amp;quot; ] &lt;br /&gt;
&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=9895</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=9895"/>
		<updated>2021-10-22T18:26:30Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Contest End = */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that the lady was in number two.&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;When he burst through her door,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;he found out by the roar,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
--Tom Lang&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 identity cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
=== COLLECTOR ===&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
=== GUESSER ===&lt;br /&gt;
&lt;br /&gt;
Discard one card from the display.&lt;br /&gt;
&lt;br /&gt;
You may then: (a) Guess your opponent&#039;s identity. (b) Match a set. (c) Pass.&lt;br /&gt;
&lt;br /&gt;
(You may choose to guess or match a set before discarding.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guessing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may guess Color &#039;&#039;or&#039;&#039; Role &#039;&#039;or&#039;&#039; both,&lt;br /&gt;
&lt;br /&gt;
* Guess Color &#039;&#039;&#039;or&#039;&#039;&#039; Role: 1 gem&lt;br /&gt;
* Guess Color &#039;&#039;&#039;and&#039;&#039;&#039; Role: 5 gems&lt;br /&gt;
* Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Match a set&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may match a set from the &#039;&#039;&#039;Collector&#039;s&#039;&#039;&#039; cards. If the Collector has a set of four cards matching either your Color &#039;&#039;&#039;or&#039;&#039;&#039; your Role, you may reveal your identity and score 2 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: You are the Blue Tiger. If the Collector has collected either 4 blue cards or 4 Tigers, you may reveal your identity and score 2 gems.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Play passes to the Collector.&lt;br /&gt;
&lt;br /&gt;
If the Deck runs out, the Guesser scores 3 gems.&lt;br /&gt;
&lt;br /&gt;
== Contest End ==&lt;br /&gt;
&lt;br /&gt;
Each Contest (round) ends when either player scores gems. A new Contest begins, and each player is given a new identity.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
The first player to score 10 gems wins!&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=9894</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=9894"/>
		<updated>2021-10-22T17:44:36Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that the lady was in number two.&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;When he burst through her door,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;he found out by the roar,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
--Tom Lang&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 identity cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
=== COLLECTOR ===&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
=== GUESSER ===&lt;br /&gt;
&lt;br /&gt;
Discard one card from the display.&lt;br /&gt;
&lt;br /&gt;
You may then: (a) Guess your opponent&#039;s identity. (b) Match a set. (c) Pass.&lt;br /&gt;
&lt;br /&gt;
(You may choose to guess or match a set before discarding.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guessing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may guess Color &#039;&#039;or&#039;&#039; Role &#039;&#039;or&#039;&#039; both,&lt;br /&gt;
&lt;br /&gt;
* Guess Color &#039;&#039;&#039;or&#039;&#039;&#039; Role: 1 gem&lt;br /&gt;
* Guess Color &#039;&#039;&#039;and&#039;&#039;&#039; Role: 5 gems&lt;br /&gt;
* Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Match a set&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may match a set from the &#039;&#039;&#039;Collector&#039;s&#039;&#039;&#039; cards. If the Collector has a set of four cards matching either your Color &#039;&#039;&#039;or&#039;&#039;&#039; your Role, you may reveal your identity and score 2 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: You are the Blue Tiger. If the Collector has collected either 4 blue cards or 4 Tigers, you may reveal your identity and score 2 gems.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Play passes to the Collector.&lt;br /&gt;
&lt;br /&gt;
If the Deck runs out, the Guesser scores 3 gems.&lt;br /&gt;
&lt;br /&gt;
== Contest End ===&lt;br /&gt;
&lt;br /&gt;
Each Contest (round) ends when either player scores gems. A new Contest begins, and each player is given a new identity.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
The first player to score 10 gems wins!&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=9893</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=9893"/>
		<updated>2021-10-22T17:38:46Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;— Tom Lang&lt;br /&gt;
&lt;br /&gt;
== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that the lady was in number two.&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;When he burst through her door,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;he found out by the roar,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
--Tom Lang&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 identity cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
=== COLLECTOR ===&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
=== GUESSER ===&lt;br /&gt;
&lt;br /&gt;
Discard one card from the display.&lt;br /&gt;
&lt;br /&gt;
You may then: (a) Guess your opponent&#039;s identity. (b) Match a set. (c) Pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guessing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may guess Color &#039;&#039;or&#039;&#039; Role &#039;&#039;or&#039;&#039; both,&lt;br /&gt;
&lt;br /&gt;
* Guess Color &#039;&#039;&#039;or&#039;&#039;&#039; Role: 1 gem&lt;br /&gt;
* Guess Color &#039;&#039;&#039;and&#039;&#039;&#039; Role: 5 gems&lt;br /&gt;
* Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Match a set&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may match a set from the &#039;&#039;&#039;Collector&#039;s&#039;&#039;&#039; cards. If the Collector has a set of four cards matching either your Color &#039;&#039;&#039;or&#039;&#039;&#039; your Role, you may reveal your identity and score 2 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: You are the Blue Tiger. If the Collector has collected either 4 blue cards or 4 Tigers, you may reveal your identity and score 2 gems.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Play passes to the Collector.&lt;br /&gt;
&lt;br /&gt;
If the Deck runs out, the Guesser scores 3 gems.&lt;br /&gt;
&lt;br /&gt;
== Contest End ===&lt;br /&gt;
&lt;br /&gt;
Each Contest (round) ends when either player scores gems. A new Contest begins, and each player is given a new identity.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
The first player to score 10 gems wins!&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Anti-Stock&amp;diff=9624</id>
		<title>Anti-Stock</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Anti-Stock&amp;diff=9624"/>
		<updated>2021-10-05T00:16:27Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Presentation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Overivew ==&lt;br /&gt;
If the [[Stock]] component works for you then great, you don&#039;t need this article. If you start tweaking it and you are doing something slightly more complex and you cannot find an answer, it may be best to not use it.&lt;br /&gt;
This article describes how to replace Stock.&lt;br /&gt;
What is Stock? It&#039;s a component that does a lot of stuff at once:&lt;br /&gt;
* It generates in-line attributes of an object the represents graphics and dimensions for &amp;quot;cards&amp;quot; (can be anything really).&lt;br /&gt;
* It also manages the layout of a single container of such cards, and cards within it - including animation.&lt;br /&gt;
* It also manages selections in that container.&lt;br /&gt;
&lt;br /&gt;
Recipe to get rid of Stock (the gist): &lt;br /&gt;
* Create all cards as divs in the template file (with the help of view.php as needed)&lt;br /&gt;
* Create generic css classes for the cards defining images, sizing, etc. Create/generate a css class for each card type with background positioning - there are scripts in sharescode to generate grid positioning (which is what Stock does under the hood) &lt;br /&gt;
* Create a parent div for card placement and use dojo.place to move cards there. In css use your preferred layout for this, including margins, etc.&lt;br /&gt;
* Tricky one: When cards are moved during animations you have to use a special method; none of animation methods from BGA parent classes will work, as the card will not have absolute positioning. You can use methods from the sharedcode project or create your own (the trick is that during animation the object has to have absolute positioning, which is removed after the animation).&lt;br /&gt;
&lt;br /&gt;
== Presentation ==&lt;br /&gt;
In modern JS the objects that we want to render will always be represented by &#039;&#039;&#039;div&#039;&#039;&#039; elements in the dom. This div will have a unique id, classes, and also custom data attributes which can be used for styling and selection.&lt;br /&gt;
&lt;br /&gt;
Here is an example of some sort of card 1 of type card_21. Note that you probably don&#039;t need both card_21 as a class and as a data-num, you can use either for selection or styling. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;card_21_1&amp;quot; class=&amp;quot;card card_21&amp;quot; data-num=&amp;quot;21&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the 10 of hearts and king of clubs inside a hand in a game&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;game&amp;quot; class=&amp;quot;classic_deck&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;hand&amp;quot; class=&amp;quot;hand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_H_10&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;H&#039; data-rank=&amp;quot;10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_C_K&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;C&#039; data-rank=&amp;quot;K&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you prefer not to use custom attributes you can do this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_H_10&amp;quot; class=&amp;quot;card_H_10 suit_H rank_10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Card id, does not have to be like this either, I use this one because it maps to my db, but if you are using the &#039;&#039;&#039;Deck&#039;&#039;&#039; component for cards in a &amp;quot;deck&amp;quot; table, you can use something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;deck_33&amp;quot; class=&amp;quot;card_H_10 suit_H rank_10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
where 33 is id which maps to database id of deck table.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we can use css to show graphics and defined size. Note unlike Stock - the size should not be bound in this component, your cards can have different sizes (for example in tooltips vs. in the hand).&lt;br /&gt;
&lt;br /&gt;
We will use the BGA card stock https://x.boardgamearena.net/data/others/cards/FULLREZ_CARDS_ORIGINAL_NORMAL.jpg.&lt;br /&gt;
&lt;br /&gt;
It has 15 columns.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.card {&lt;br /&gt;
   background-image: url(&#039;https://x.boardgamearena.net/data/others/cards/FULLREZ_CARDS_ORIGINAL_NORMAL.jpg&#039;);   /* don&#039;t do full url in your game, copy this file inside img folder */&lt;br /&gt;
   background-size: 1500% auto;  /* this mean size of background is 15 times bigger than size of card, because its sprite */&lt;br /&gt;
   border-radius: 5%;&lt;br /&gt;
   width: 10em;&lt;br /&gt;
   height: 13.5em;&lt;br /&gt;
   box-shadow: 0.1em 0.1em 0.2em 0.1em #555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.card[data-rank=&amp;quot;10&amp;quot;] { /* 10 is column number 10 - 2 because we start from 0 and first card is sprite is 2. The multiplier is (15 - 1) is because we have 15 columns. -1 is because % in CSS is weird like that. */&lt;br /&gt;
   background-position-x: calc(100% / (15 - 1) * (10 - 2));&lt;br /&gt;
}&lt;br /&gt;
.card[data-rank=&amp;quot;K&amp;quot;] { /* King will be number 13 in rank */&lt;br /&gt;
   background-position-x: calc(100% / (15 - 1) * (13 - 2));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.card[data-suit=&amp;quot;H&amp;quot;] { /* Hears row position is 1 (because we count from 0). Multiplier (4 - 1) is because we have 4 rows and -1 is because % in CSS is weird like that. */&lt;br /&gt;
   background-position-y: calc(100% / (4 - 1) * (1));&lt;br /&gt;
}&lt;br /&gt;
.card[data-suit=&amp;quot;C&amp;quot;] { /* Clubs row position is 2 */&lt;br /&gt;
   background-position-y: calc(100% / (4 - 1) * (2));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now if you want to see these cards, we can put them in some specific component for example hand, and there we can define layout and sizing just for hand&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.hand .card {&lt;br /&gt;
  font-size: 2.4rem;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Working example: https://codepen.io/VictoriaLa/pen/rNwgWrB&lt;br /&gt;
&lt;br /&gt;
To finish the deck you have to finish css for all rows/columns which whould be only 10-20 records, really easy and repetitive!&lt;br /&gt;
If you really cannot write that much css manually you can also generate it using php code (this is side kick command line - does not go to your game)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// this simple script generates sprite css&lt;br /&gt;
// it has no params - fix inline to change what it generates&lt;br /&gt;
&lt;br /&gt;
$from=1; // from index&lt;br /&gt;
$to=40+4; // to index&lt;br /&gt;
$maxcol=4; // number of columns in the sprite&lt;br /&gt;
$scol=$maxcol-1;&lt;br /&gt;
$srow=((int)(($to-$from)/$maxcol));&lt;br /&gt;
for ($num=$from;$num&amp;lt;=$to;$num++) {&lt;br /&gt;
    $index=$num-$from;&lt;br /&gt;
    $row=(int)($index/$maxcol);&lt;br /&gt;
    $col=$index%$maxcol;&lt;br /&gt;
    echo &amp;quot;.tech_E_$num { background-position: calc(100% / $scol * $col) calc(100% / $srow * $row);}\n&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And now if you want to user to have preferece for what deck style to use its just matter of change class from &amp;quot;classic_deck&amp;quot; to &amp;quot;fancy_deck&amp;quot; in our game parent div and adding in CSS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.fancy_deck .card {&lt;br /&gt;
   background-image: url(&#039;https://x.boardgamearena.net/data/others/cards/FULLREZ_CARDS_DESIGN_COLORED.jpg&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Generating Dom Elements ==&lt;br /&gt;
&lt;br /&gt;
=== Static - basic ===&lt;br /&gt;
You basically write all your cards in .tpl file. Just cut &amp;amp; paste you template and fix few classes. That is easiest!&lt;br /&gt;
In your js code you never create new element, you just move existing element inside dome. If you need a copy for tooltips, logs or button you can clone&lt;br /&gt;
one of them change id and add/remove class if needed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;limbo&amp;quot; class=&amp;quot;limbo&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_H_10&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;H&#039; data-rank=&amp;quot;10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_C_K&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;C&#039; data-rank=&amp;quot;K&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
... rice and repeat ...&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Static - bga template engine ===&lt;br /&gt;
in .tpl&lt;br /&gt;
  &amp;lt;div id=&amp;quot;limbo&amp;quot; class=&amp;quot;limbo&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;!-- BEGIN deck_cards --&amp;gt;&lt;br /&gt;
	&amp;lt;div id=&amp;quot;card_{SUIT}_{RANK}&amp;quot; class=&amp;quot;card card_{SUIT}_{RANK}&amp;quot; data-suit=&amp;quot;{SUIT}&amp;quot; data-rank=&amp;quot;{RANK}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;!-- END deck_cards --&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in view.php&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;begin_block($template, &amp;quot;deck_cards&amp;quot;);&lt;br /&gt;
        $ranks = [2,3,4,5,6,7,8,9,10,&#039;J&#039;,&#039;Q&#039;,&#039;K&#039;,&#039;A&#039;];&lt;br /&gt;
        $suits = [&#039;S&#039;,&#039;H&#039;,&#039;C&#039;,&#039;D&#039;];&lt;br /&gt;
        foreach ($ranks as $rank) {&lt;br /&gt;
          foreach ($suits as $suit) {&lt;br /&gt;
            $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;deck_cards&amp;quot;, [&lt;br /&gt;
                    &#039;SUIT&#039; =&amp;gt; &amp;quot;$suit,&lt;br /&gt;
                    &#039;RANK&#039; =&amp;gt; &amp;quot;$rank,&lt;br /&gt;
            ]);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dynamic using .tpl thingy ===&lt;br /&gt;
&lt;br /&gt;
In the js section of .tpl&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      var jstpl_card = &#039;&amp;lt;div id=&amp;quot;card_{SUIT}_{RANK}&amp;quot; class=&amp;quot;card card_{SUIT}_{RANK}&amp;quot; data-suit=&amp;quot;{SUIT}&amp;quot; data-rank=&amp;quot;{RANK}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in js:&lt;br /&gt;
 let cardDiv = this.format_block(&#039;jstpl_card&#039;, {&lt;br /&gt;
                                SUIT : &#039;H&#039;,&lt;br /&gt;
                                RANK : &#039;A&#039;&lt;br /&gt;
                            }); // this in js code somewhere before placing it&lt;br /&gt;
&lt;br /&gt;
=== Dynamic using dojo ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 let suit = &#039;H&#039;;&lt;br /&gt;
 let rank = &#039;A&#039;;&lt;br /&gt;
 let cardNode = dojo.create(&#039;div&#039;, {id: `card_${suit}_${rank}`, class: `card card_${suit}_${rank}`, dataSuit: suit, dataRank: rank});&lt;br /&gt;
 dojo.place(cardNode, &#039;hand&#039;); // place in hand for example&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Technically you can do it all in one line as &amp;quot;place&amp;quot; is 3rd parameter of dojo.create&lt;br /&gt;
&lt;br /&gt;
=== Dynamic not using dojo ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let suit = &#039;H&#039;;&lt;br /&gt;
let rank = &#039;A&#039;;&lt;br /&gt;
let div = document.createElement(&#039;div&#039;);&lt;br /&gt;
div.id = `card_${suit}_${rank}`;&lt;br /&gt;
div.className = `card card_${suit}_${rank}`;&lt;br /&gt;
div.setAttribute(&#039;data-suit&#039;,suit);&lt;br /&gt;
div.setAttribute(&#039;data-rank&#039;,rank);&lt;br /&gt;
//console.log(div);&lt;br /&gt;
$(&#039;hand&#039;).appendChild(div);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see this is not most compact method, so you if you do that a lot probably create a function that generates this (which also would set a click handler and tooltip for example)&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
&lt;br /&gt;
You can use all web resources and powser of css to do any sort of fancy layout for your cards, you not bound to any predefined layouts.&lt;br /&gt;
The simplest would be display: inline-block  as we already did above. You can also add margins to overlap cards for example&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.tableau {&lt;br /&gt;
   position: relative;&lt;br /&gt;
   width: 50em;&lt;br /&gt;
   height: 30em;&lt;br /&gt;
   outline: dashed 1px green;&lt;br /&gt;
   transform: rotate(-90deg) scale(0.5); &lt;br /&gt;
   padding: 1em;&lt;br /&gt;
    display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tableau .card{&lt;br /&gt;
  margin-right: -2em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example cards on tableu are smaller, rotated 90 degrees and overlaping.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
https://codepen.io/VictoriaLa/pen/PojvWEV&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Deck Layouts - codepen.io.png]]&lt;br /&gt;
&lt;br /&gt;
== Selection and Click Handlers ==&lt;br /&gt;
&lt;br /&gt;
To hookup selection or clicking, you have to manually hook up handler to all cards, which is easy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.querySelectorAll(&amp;quot;.card&amp;quot;).forEach(node=&amp;gt;node.addEventListener(&amp;quot;click&amp;quot;, (event) =&amp;gt; {&lt;br /&gt;
  var target = event.target;&lt;br /&gt;
  target.classList.toggle(&#039;selected&#039;);&lt;br /&gt;
  }&lt;br /&gt;
}));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And you define class for selected in css&lt;br /&gt;
  .selected {&lt;br /&gt;
     outline: dashed blue 0.1em;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
How if you need to do some action based on selection this can be in your &amp;quot;do something&amp;quot; button handler (this example below will create array of ids of cards)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  const card_ids = Array.from(document.querySelectorAll(&#039;.card.selected&#039;)).map(x=&amp;gt;x.id);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need single selection, just add a call to remove all previous &#039;selected&#039; from all card, before adding it.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t need selection you can hook ajax call directly to handler above.&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
&lt;br /&gt;
The animation is the only tricky part because it does not come for free. The proper animation function is pretty lengthy so I won&#039;t even put it here.&lt;br /&gt;
Basically it short you would have to reparent out object without visual movement and then you can run animation on positions, and after it is done remove absolute positioning.&lt;br /&gt;
&lt;br /&gt;
The simplier method is moving object itself, you can see code and example in https://github.com/elaskavaia/bga-sharedcode/blob/master/sharedcode.js&lt;br /&gt;
(slideToObjectRelative).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And more complex method moves &amp;quot;phantom&amp;quot; object on oversurface  (which is neither parent of original object nor destination), code can found here (to use this your need 2 js methods for movement and classes for oversurface and oversurfacew &amp;gt; * from css):&lt;br /&gt;
https://codepen.io/VictoriaLa/pen/PojvWEV&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Anti-Stock&amp;diff=9622</id>
		<title>Anti-Stock</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Anti-Stock&amp;diff=9622"/>
		<updated>2021-10-04T23:03:06Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Overivew */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Overivew ==&lt;br /&gt;
If the [[Stock]] component works for you then great, you don&#039;t need this article. If you start tweaking it and you are doing something slightly more complex and you cannot find an answer, it may be best to not use it.&lt;br /&gt;
This article describes how to replace Stock.&lt;br /&gt;
What is Stock? It&#039;s a component that does a lot of stuff at once:&lt;br /&gt;
* It generates in-line attributes of an object the represents graphics and dimensions for &amp;quot;cards&amp;quot; (can be anything really).&lt;br /&gt;
* It also manages the layout of a single container of such cards, and cards within it - including animation.&lt;br /&gt;
* It also manages selections in that container.&lt;br /&gt;
&lt;br /&gt;
Recipe to get rid of Stock (the gist): &lt;br /&gt;
* Create all cards as divs in the template file (with the help of view.php as needed)&lt;br /&gt;
* Create generic css classes for the cards defining images, sizing, etc. Create/generate a css class for each card type with background positioning - there are scripts in sharescode to generate grid positioning (which is what Stock does under the hood) &lt;br /&gt;
* Create a parent div for card placement and use dojo.place to move cards there. In css use your preferred layout for this, including margins, etc.&lt;br /&gt;
* Tricky one: When cards are moved during animations you have to use a special method; none of animation methods from BGA parent classes will work, as the card will not have absolute positioning. You can use methods from the sharedcode project or create your own (the trick is that during animation the object has to have absolute positioning, which is removed after the animation).&lt;br /&gt;
&lt;br /&gt;
== Presentation ==&lt;br /&gt;
In modern word the objects that we want to render will be always represented by div element in the dom. This div will have unique Id, classes and also custom data attributes which can be used for styling and selection.&lt;br /&gt;
&lt;br /&gt;
This is some sort of card 1 of type card_21. Note that you probably don&#039;t need both card_21 as class and as data-num, you can use either for selection or styling. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;card_21_1&amp;quot; class=&amp;quot;card card_21&amp;quot; data-num=&amp;quot;21&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is 10 of hearts and king of clubs inside a hand inside a game&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;game&amp;quot; class=&amp;quot;classic_deck&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;hand&amp;quot; class=&amp;quot;hand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_H_10&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;H&#039; data-rank=&amp;quot;10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_C_K&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;C&#039; data-rank=&amp;quot;K&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you prefer not to use custom attributes you can do this &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_H_10&amp;quot; class=&amp;quot;card_H_10 suit_H rank_10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Card id, does not have to be like this either, I use this one because it maps to my db, but if you using Deck component for cards in &amp;quot;deck&amp;quot; table, you can use something like&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;deck_33&amp;quot; class=&amp;quot;card_H_10 suit_H rank_10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
where 33 is id which maps to database id of deck table.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now we can use css to show graphics and defined size. Note unlike stock - the size should not be bound this component, you cards can have different size for example in tooltips vs hand&lt;br /&gt;
&lt;br /&gt;
We will use the BGA card stock https://x.boardgamearena.net/data/others/cards/FULLREZ_CARDS_ORIGINAL_NORMAL.jpg.&lt;br /&gt;
It has 15 columns.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.card {&lt;br /&gt;
   background-image: url(&#039;https://x.boardgamearena.net/data/others/cards/FULLREZ_CARDS_ORIGINAL_NORMAL.jpg&#039;);   /* don&#039;t do full url in your game, copy this file inside img folder */&lt;br /&gt;
   background-size: 1500% auto;  /* this mean size of background is 15 times bigger than size of card, because its sprite */&lt;br /&gt;
   border-radius: 5%;&lt;br /&gt;
   width: 10em;&lt;br /&gt;
   height: 13.5em;&lt;br /&gt;
   box-shadow: 0.1em 0.1em 0.2em 0.1em #555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.card[data-rank=&amp;quot;10&amp;quot;] { /* 10 is column number 10 - 2 because we start from 0 and first card is sprite is 2. The multiplier is (15 - 1) is because we have 15 columns. -1 is because % in CSS is weird like that. */&lt;br /&gt;
   background-position-x: calc(100% / (15 - 1) * (10 - 2));&lt;br /&gt;
}&lt;br /&gt;
.card[data-rank=&amp;quot;K&amp;quot;] { /* King will be number 13 in rank */&lt;br /&gt;
   background-position-x: calc(100% / (15 - 1) * (13 - 2));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.card[data-suit=&amp;quot;H&amp;quot;] { /* Hears row position is 1 (because we count from 0). Multiplier (4 - 1) is because we have 4 rows and -1 is because % in CSS is weird like that. */&lt;br /&gt;
   background-position-y: calc(100% / (4 - 1) * (1));&lt;br /&gt;
}&lt;br /&gt;
.card[data-suit=&amp;quot;C&amp;quot;] { /* Clubs row position is 2 */&lt;br /&gt;
   background-position-y: calc(100% / (4 - 1) * (2));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now if you want to see these cards, we can put them in some specific component for example hand, and there we can define layout and sizing just for hand&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.hand .card {&lt;br /&gt;
  font-size: 2.4rem;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Working example: https://codepen.io/VictoriaLa/pen/rNwgWrB&lt;br /&gt;
&lt;br /&gt;
To finish the deck you have to finish css for all rows/columns which whould be only 10-20 records, really easy and repetitive!&lt;br /&gt;
If you really cannot write that much css manually you can also generate it using php code (this is side kick command line - does not go to your game)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// this simple script generates sprite css&lt;br /&gt;
// it has no params - fix inline to change what it generates&lt;br /&gt;
&lt;br /&gt;
$from=1; // from index&lt;br /&gt;
$to=40+4; // to index&lt;br /&gt;
$maxcol=4; // number of columns in the sprite&lt;br /&gt;
$scol=$maxcol-1;&lt;br /&gt;
$srow=((int)(($to-$from)/$maxcol));&lt;br /&gt;
for ($num=$from;$num&amp;lt;=$to;$num++) {&lt;br /&gt;
    $index=$num-$from;&lt;br /&gt;
    $row=(int)($index/$maxcol);&lt;br /&gt;
    $col=$index%$maxcol;&lt;br /&gt;
    echo &amp;quot;.tech_E_$num { background-position: calc(100% / $scol * $col) calc(100% / $srow * $row);}\n&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And now if you want to user to have preferece for what deck style to use its just matter of change class from &amp;quot;classic_deck&amp;quot; to &amp;quot;fancy_deck&amp;quot; in our game parent div and adding in CSS&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.fancy_deck .card {&lt;br /&gt;
   background-image: url(&#039;https://x.boardgamearena.net/data/others/cards/FULLREZ_CARDS_DESIGN_COLORED.jpg&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Generating Dom Elements ==&lt;br /&gt;
&lt;br /&gt;
=== Static - basic ===&lt;br /&gt;
You basically write all your cards in .tpl file. Just cut &amp;amp; paste you template and fix few classes. That is easiest!&lt;br /&gt;
In your js code you never create new element, you just move existing element inside dome. If you need a copy for tooltips, logs or button you can clone&lt;br /&gt;
one of them change id and add/remove class if needed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;limbo&amp;quot; class=&amp;quot;limbo&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_H_10&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;H&#039; data-rank=&amp;quot;10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_C_K&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;C&#039; data-rank=&amp;quot;K&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
... rice and repeat ...&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Static - bga template engine ===&lt;br /&gt;
in .tpl&lt;br /&gt;
  &amp;lt;div id=&amp;quot;limbo&amp;quot; class=&amp;quot;limbo&amp;quot;&amp;gt;&lt;br /&gt;
	&amp;lt;!-- BEGIN deck_cards --&amp;gt;&lt;br /&gt;
	&amp;lt;div id=&amp;quot;card_{SUIT}_{RANK}&amp;quot; class=&amp;quot;card card_{SUIT}_{RANK}&amp;quot; data-suit=&amp;quot;{SUIT}&amp;quot; data-rank=&amp;quot;{RANK}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;!-- END deck_cards --&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in view.php&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;begin_block($template, &amp;quot;deck_cards&amp;quot;);&lt;br /&gt;
        $ranks = [2,3,4,5,6,7,8,9,10,&#039;J&#039;,&#039;Q&#039;,&#039;K&#039;,&#039;A&#039;];&lt;br /&gt;
        $suits = [&#039;S&#039;,&#039;H&#039;,&#039;C&#039;,&#039;D&#039;];&lt;br /&gt;
        foreach ($ranks as $rank) {&lt;br /&gt;
          foreach ($suits as $suit) {&lt;br /&gt;
            $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;deck_cards&amp;quot;, [&lt;br /&gt;
                    &#039;SUIT&#039; =&amp;gt; &amp;quot;$suit,&lt;br /&gt;
                    &#039;RANK&#039; =&amp;gt; &amp;quot;$rank,&lt;br /&gt;
            ]);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dynamic using .tpl thingy ===&lt;br /&gt;
&lt;br /&gt;
In the js section of .tpl&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      var jstpl_card = &#039;&amp;lt;div id=&amp;quot;card_{SUIT}_{RANK}&amp;quot; class=&amp;quot;card card_{SUIT}_{RANK}&amp;quot; data-suit=&amp;quot;{SUIT}&amp;quot; data-rank=&amp;quot;{RANK}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in js:&lt;br /&gt;
 let cardDiv = this.format_block(&#039;jstpl_card&#039;, {&lt;br /&gt;
                                SUIT : &#039;H&#039;,&lt;br /&gt;
                                RANK : &#039;A&#039;&lt;br /&gt;
                            }); // this in js code somewhere before placing it&lt;br /&gt;
&lt;br /&gt;
=== Dynamic using dojo ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 let suit = &#039;H&#039;;&lt;br /&gt;
 let rank = &#039;A&#039;;&lt;br /&gt;
 let cardNode = dojo.create(&#039;div&#039;, {id: `card_${suit}_${rank}`, class: `card card_${suit}_${rank}`, dataSuit: suit, dataRank: rank});&lt;br /&gt;
 dojo.place(cardNode, &#039;hand&#039;); // place in hand for example&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Technically you can do it all in one line as &amp;quot;place&amp;quot; is 3rd parameter of dojo.create&lt;br /&gt;
&lt;br /&gt;
=== Dynamic not using dojo ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let suit = &#039;H&#039;;&lt;br /&gt;
let rank = &#039;A&#039;;&lt;br /&gt;
let div = document.createElement(&#039;div&#039;);&lt;br /&gt;
div.id = `card_${suit}_${rank}`;&lt;br /&gt;
div.className = `card card_${suit}_${rank}`;&lt;br /&gt;
div.setAttribute(&#039;data-suit&#039;,suit);&lt;br /&gt;
div.setAttribute(&#039;data-rank&#039;,rank);&lt;br /&gt;
//console.log(div);&lt;br /&gt;
$(&#039;hand&#039;).appendChild(div);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see this is not most compact method, so you if you do that a lot probably create a function that generates this (which also would set a click handler and tooltip for example)&lt;br /&gt;
&lt;br /&gt;
== Layout ==&lt;br /&gt;
&lt;br /&gt;
You can use all web resources and powser of css to do any sort of fancy layout for your cards, you not bound to any predefined layouts.&lt;br /&gt;
The simplest would be display: inline-block  as we already did above. You can also add margins to overlap cards for example&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.tableau {&lt;br /&gt;
   position: relative;&lt;br /&gt;
   width: 50em;&lt;br /&gt;
   height: 30em;&lt;br /&gt;
   outline: dashed 1px green;&lt;br /&gt;
   transform: rotate(-90deg) scale(0.5); &lt;br /&gt;
   padding: 1em;&lt;br /&gt;
    display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tableau .card{&lt;br /&gt;
  margin-right: -2em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In this example cards on tableu are smaller, rotated 90 degrees and overlaping.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
https://codepen.io/VictoriaLa/pen/PojvWEV&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Deck Layouts - codepen.io.png]]&lt;br /&gt;
&lt;br /&gt;
== Selection and Click Handlers ==&lt;br /&gt;
&lt;br /&gt;
To hookup selection or clicking, you have to manually hook up handler to all cards, which is easy&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.querySelectorAll(&amp;quot;.card&amp;quot;).forEach(node=&amp;gt;node.addEventListener(&amp;quot;click&amp;quot;, (event) =&amp;gt; {&lt;br /&gt;
  var target = event.target;&lt;br /&gt;
  target.classList.toggle(&#039;selected&#039;);&lt;br /&gt;
  }&lt;br /&gt;
}));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And you define class for selected in css&lt;br /&gt;
  .selected {&lt;br /&gt;
     outline: dashed blue 0.1em;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
How if you need to do some action based on select this can be your do something button bandler (this will create array of ids of cards)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  const card_ids = Array.from(document.querySelectorAll(&#039;.card.selected&#039;)).map(x=&amp;gt;x.id);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need single selection, just add a call to remove all previous &#039;selected&#039; from all card, before adding it.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t need selection you can hook ajax call directly to handler above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
&lt;br /&gt;
The animation is the only tricky part because it does not come for free. The proper animation function is pretty lengthy so I won&#039;t even put it here.&lt;br /&gt;
Basically it short you would have to reparent out object without visual movement and then you can run animation on positions, and after it is done remove absolute positioning.&lt;br /&gt;
&lt;br /&gt;
The simplier method is moving object itself, you can see code and example in https://github.com/elaskavaia/bga-sharedcode/blob/master/sharedcode.js&lt;br /&gt;
(slideToObjectRelative).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And more complex method moves &amp;quot;phantom&amp;quot; object on oversurface  (which is neither parent of original object nor destination), code can found here (to use this your need 2 js methods for movement and classes for oversurface and oversurfacew &amp;gt; * from css):&lt;br /&gt;
https://codepen.io/VictoriaLa/pen/PojvWEV&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8702</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8702"/>
		<updated>2021-07-05T19:05:03Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* GUESSER */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;— Tom Lang&lt;br /&gt;
&lt;br /&gt;
== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that the lady was in number two.&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;When he burst through her door,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;he found out by the roar,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
--Tom Lang&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 identity cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
=== COLLECTOR ===&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
=== GUESSER ===&lt;br /&gt;
&lt;br /&gt;
Discard one card from the display.&lt;br /&gt;
&lt;br /&gt;
You may then: (a) Guess your opponent&#039;s identity. (b) Match a set. (c) Pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guessing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may guess Color &#039;&#039;or&#039;&#039; Role &#039;&#039;or&#039;&#039; both,&lt;br /&gt;
&lt;br /&gt;
* Guess Color &#039;&#039;&#039;or&#039;&#039;&#039; Role: 1 gem&lt;br /&gt;
* Guess Color &#039;&#039;&#039;and&#039;&#039;&#039; Role: 5 gems&lt;br /&gt;
* Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Match a set&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may match a set from the &#039;&#039;&#039;Collector&#039;s&#039;&#039;&#039; cards. If the Collector has a set of four cards matching either your Color &#039;&#039;&#039;or&#039;&#039;&#039; your Role, you may reveal your identity and score 2 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: You are the Blue Tiger. If the Collector has collected either 4 blue cards or 4 Tigers, you may reveal your identity and score 2 gems.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Play passes to the Collector.&lt;br /&gt;
&lt;br /&gt;
If the Deck runs out, the Guesser scores 3 gems.&lt;br /&gt;
&lt;br /&gt;
== Contest End ===&lt;br /&gt;
&lt;br /&gt;
Each Contest (round) ends when either player scores gems. A new Contest begins, and each player is given a new identity.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
The first player to score 10 gems wins!&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8701</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8701"/>
		<updated>2021-07-05T19:04:32Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* GUESSER */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;— Tom Lang&lt;br /&gt;
&lt;br /&gt;
== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that the lady was in number two.&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;When he burst through her door,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;he found out by the roar,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
--Tom Lang&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 identity cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
=== COLLECTOR ===&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
=== GUESSER ===&lt;br /&gt;
&lt;br /&gt;
Discard one card from the display.&lt;br /&gt;
&lt;br /&gt;
You may then: (a) Guess your opponent&#039;s identity. (b) Match a set. (c) Pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guessing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may guess Color &#039;&#039;or&#039;&#039; Role &#039;&#039;or&#039;&#039; both,&lt;br /&gt;
&lt;br /&gt;
# Guess Color &#039;&#039;&#039;or&#039;&#039;&#039; Role: 1 gem&lt;br /&gt;
# Guess Color &#039;&#039;&#039;and&#039;&#039;&#039; Role: 5 gems&lt;br /&gt;
# Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Match a set&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may match a set from the &#039;&#039;&#039;Collector&#039;s&#039;&#039;&#039; cards. If the Collector has a set of four cards matching either your Color &#039;&#039;&#039;or&#039;&#039;&#039; your Role, you may reveal your identity and score 2 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: You are the Blue Tiger. If the Collector has collected either 4 blue cards or 4 Tigers, you may reveal your identity and score 2 gems.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Play passes to the Collector.&lt;br /&gt;
&lt;br /&gt;
If the Deck runs out, the Guesser scores 3 gems.&lt;br /&gt;
&lt;br /&gt;
== Contest End ===&lt;br /&gt;
&lt;br /&gt;
Each Contest (round) ends when either player scores gems. A new Contest begins, and each player is given a new identity.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
The first player to score 10 gems wins!&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8700</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8700"/>
		<updated>2021-07-05T19:03:37Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* DOORS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;— Tom Lang&lt;br /&gt;
&lt;br /&gt;
== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that the lady was in number two.&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;When he burst through her door,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;he found out by the roar,&#039;&#039;&amp;lt;br/&amp;gt;&lt;br /&gt;
&#039;&#039;that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
--Tom Lang&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 identity cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
=== COLLECTOR ===&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
=== GUESSER ===&lt;br /&gt;
&lt;br /&gt;
Discard one card from the display.&lt;br /&gt;
&lt;br /&gt;
You may then: (a) Guess your opponent&#039;s identity. (b) Match a set. (c) Pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guessing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may guess Color &#039;&#039;or&#039;&#039; Role &#039;&#039;or&#039;&#039; both,&lt;br /&gt;
&lt;br /&gt;
Guess Color &#039;&#039;&#039;or&#039;&#039;&#039; Role: 1 gem&lt;br /&gt;
Guess Color &#039;&#039;&#039;and&#039;&#039;&#039; Role: 5 gems&lt;br /&gt;
Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Match a set&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may match a set from the &#039;&#039;&#039;Collector&#039;s&#039;&#039;&#039; cards. If the Collector has a set of four cards matching either your Color &#039;&#039;&#039;or&#039;&#039;&#039; your Role, you may reveal your identity and score 2 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: You are the Blue Tiger. If the Collector has collected either 4 blue cards or 4 Tigers, you may reveal your identity and score 2 gems.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Play passes to the Collector.&lt;br /&gt;
&lt;br /&gt;
If the Deck runs out, the Guesser scores 3 gems.&lt;br /&gt;
&lt;br /&gt;
== Contest End ===&lt;br /&gt;
&lt;br /&gt;
Each Contest (round) ends when either player scores gems. A new Contest begins, and each player is given a new identity.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
The first player to score 10 gems wins!&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8699</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8699"/>
		<updated>2021-07-05T19:02:56Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* DOORS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;— Tom Lang&lt;br /&gt;
&lt;br /&gt;
== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&amp;lt;br/&amp;gt;&lt;br /&gt;
that the lady was in number two.&amp;lt;br/&amp;gt;&lt;br /&gt;
When he burst through her door,&amp;lt;br/&amp;gt;&lt;br /&gt;
he found out by the roar,&amp;lt;br/&amp;gt;&lt;br /&gt;
that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 identity cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
=== COLLECTOR ===&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
=== GUESSER ===&lt;br /&gt;
&lt;br /&gt;
Discard one card from the display.&lt;br /&gt;
&lt;br /&gt;
You may then: (a) Guess your opponent&#039;s identity. (b) Match a set. (c) Pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guessing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may guess Color &#039;&#039;or&#039;&#039; Role &#039;&#039;or&#039;&#039; both,&lt;br /&gt;
&lt;br /&gt;
Guess Color &#039;&#039;&#039;or&#039;&#039;&#039; Role: 1 gem&lt;br /&gt;
Guess Color &#039;&#039;&#039;and&#039;&#039;&#039; Role: 5 gems&lt;br /&gt;
Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Match a set&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may match a set from the &#039;&#039;&#039;Collector&#039;s&#039;&#039;&#039; cards. If the Collector has a set of four cards matching either your Color &#039;&#039;&#039;or&#039;&#039;&#039; your Role, you may reveal your identity and score 2 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: You are the Blue Tiger. If the Collector has collected either 4 blue cards or 4 Tigers, you may reveal your identity and score 2 gems.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Play passes to the Collector.&lt;br /&gt;
&lt;br /&gt;
If the Deck runs out, the Guesser scores 3 gems.&lt;br /&gt;
&lt;br /&gt;
== Contest End ===&lt;br /&gt;
&lt;br /&gt;
Each Contest (round) ends when either player scores gems. A new Contest begins, and each player is given a new identity.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
The first player to score 10 gems wins!&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8698</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8698"/>
		<updated>2021-07-05T19:01:52Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* DOORS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;— Tom Lang&lt;br /&gt;
&lt;br /&gt;
== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&lt;br /&gt;
&lt;br /&gt;
that the lady was in number two.&lt;br /&gt;
&lt;br /&gt;
When he burst through her door,&lt;br /&gt;
&lt;br /&gt;
he found out by the roar,&lt;br /&gt;
&lt;br /&gt;
that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 identity cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
=== COLLECTOR ===&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
=== GUESSER ===&lt;br /&gt;
&lt;br /&gt;
Discard one card from the display.&lt;br /&gt;
&lt;br /&gt;
You may then: (a) Guess your opponent&#039;s identity. (b) Match a set. (c) Pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guessing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may guess Color &#039;&#039;or&#039;&#039; Role &#039;&#039;or&#039;&#039; both,&lt;br /&gt;
&lt;br /&gt;
Guess Color &#039;&#039;&#039;or&#039;&#039;&#039; Role: 1 gem&lt;br /&gt;
Guess Color &#039;&#039;&#039;and&#039;&#039;&#039; Role: 5 gems&lt;br /&gt;
Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Match a set&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may match a set from the &#039;&#039;&#039;Collector&#039;s&#039;&#039;&#039; cards. If the Collector has a set of four cards matching either your Color &#039;&#039;&#039;or&#039;&#039;&#039; your Role, you may reveal your identity and score 2 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: You are the Blue Tiger. If the Collector has collected either 4 blue cards or 4 Tigers, you may reveal your identity and score 2 gems.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Play passes to the Collector.&lt;br /&gt;
&lt;br /&gt;
If the Deck runs out, the Guesser scores 3 gems.&lt;br /&gt;
&lt;br /&gt;
== Contest End ===&lt;br /&gt;
&lt;br /&gt;
Each Contest (round) ends when either player scores gems. A new Contest begins, and each player is given a new identity.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
The first player to score 10 gems wins!&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8697</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8697"/>
		<updated>2021-07-05T19:01:38Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;— Tom Lang&lt;br /&gt;
&lt;br /&gt;
== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&lt;br /&gt;
that the lady was in number two.&lt;br /&gt;
When he burst through her door,&lt;br /&gt;
he found out by the roar,&lt;br /&gt;
that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 identity cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
=== COLLECTOR ===&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
=== GUESSER ===&lt;br /&gt;
&lt;br /&gt;
Discard one card from the display.&lt;br /&gt;
&lt;br /&gt;
You may then: (a) Guess your opponent&#039;s identity. (b) Match a set. (c) Pass.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Guessing&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may guess Color &#039;&#039;or&#039;&#039; Role &#039;&#039;or&#039;&#039; both,&lt;br /&gt;
&lt;br /&gt;
Guess Color &#039;&#039;&#039;or&#039;&#039;&#039; Role: 1 gem&lt;br /&gt;
Guess Color &#039;&#039;&#039;and&#039;&#039;&#039; Role: 5 gems&lt;br /&gt;
Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Match a set&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You may match a set from the &#039;&#039;&#039;Collector&#039;s&#039;&#039;&#039; cards. If the Collector has a set of four cards matching either your Color &#039;&#039;&#039;or&#039;&#039;&#039; your Role, you may reveal your identity and score 2 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: You are the Blue Tiger. If the Collector has collected either 4 blue cards or 4 Tigers, you may reveal your identity and score 2 gems.)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Play passes to the Collector.&lt;br /&gt;
&lt;br /&gt;
If the Deck runs out, the Guesser scores 3 gems.&lt;br /&gt;
&lt;br /&gt;
== Contest End ===&lt;br /&gt;
&lt;br /&gt;
Each Contest (round) ends when either player scores gems. A new Contest begins, and each player is given a new identity.&lt;br /&gt;
&lt;br /&gt;
== Game End ==&lt;br /&gt;
&lt;br /&gt;
The first player to score 10 gems wins!&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8696</id>
		<title>Gamehelpladyandthetiger</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpladyandthetiger&amp;diff=8696"/>
		<updated>2021-07-05T18:52:45Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;— Tom Lang&lt;br /&gt;
&lt;br /&gt;
== DOORS ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;He was safe in his choice, for he knew&lt;br /&gt;
that the lady was in number two.&lt;br /&gt;
When he burst through her door,&lt;br /&gt;
he found out by the roar,&lt;br /&gt;
that tigers can be ladies too.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Objective ===&lt;br /&gt;
&lt;br /&gt;
To win, be the first player to earn 10 gems. Gems are earned by guessing your opponent’s identity, being guessed incorrectly, or scoring a set of cards which match your identity.&lt;br /&gt;
&lt;br /&gt;
=== SETUP ===&lt;br /&gt;
&lt;br /&gt;
One player is the Collector, the other player is the Guesser.&lt;br /&gt;
&lt;br /&gt;
Each player is secretly dealt one of 4 Role Cards: Red Lady, Blue Lady, Red Tiger, or Blue Tiger.&lt;br /&gt;
&lt;br /&gt;
The Collector goes first.&lt;br /&gt;
&lt;br /&gt;
==== COLLECTOR ====&lt;br /&gt;
&lt;br /&gt;
Choose one card.&lt;br /&gt;
&lt;br /&gt;
If you have a set of 4 cards matching your identity, reveal your Role and score 6 gems.&lt;br /&gt;
&lt;br /&gt;
(&#039;&#039;Example&#039;&#039;: If you are the Red Lady, you will score 6 gems upon acquiring either 4 Red cards or 4 Ladies.)&lt;br /&gt;
&lt;br /&gt;
==== GUESSER ====&lt;br /&gt;
&lt;br /&gt;
Discard 1 card.&lt;br /&gt;
&lt;br /&gt;
Optionally, BEFORE or AFTER discarding a card, guess the Collector&#039;s identity and/or score a set from the Collector&#039;s cards.&lt;br /&gt;
&lt;br /&gt;
Guess Color OR Role: 1 gem&lt;br /&gt;
Guess Color AND Role: 5 gems&lt;br /&gt;
Guess incorrectly: Collector scores 4 gems&lt;br /&gt;
&lt;br /&gt;
Score a set (4 cards matching your color OR Role): 2 gems&lt;br /&gt;
&lt;br /&gt;
Deck runs out: Guesser scores 3 gems&lt;br /&gt;
&lt;br /&gt;
First player to score 10 gems wins.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=8325</id>
		<title>BGA Studio Cookbook</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=8325"/>
		<updated>2021-05-22T17:05:12Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Ajax Call wrapper */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
This page is collection of design and implementation recipes for BGA Studio framework.&lt;br /&gt;
For tooling and usage recipes see [[Tools and tips of BGA Studio]].&lt;br /&gt;
If you have your own recipes feel free to edit this page.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Visual Effects, Layout and Animation ==&lt;br /&gt;
&lt;br /&gt;
=== Create pieces dynamically (using template) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: this method is recommended by BGA guildlines&lt;br /&gt;
&lt;br /&gt;
Declared js template with variables in .tpl file, like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Javascript HTML templates&lt;br /&gt;
    var jstpl_ipiece = &#039;&amp;lt;div class=&amp;quot;${type} ${type}_${color} inlineblock&amp;quot; aria-label=&amp;quot;${name}&amp;quot; title=&amp;quot;${name}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use it like this in .js file&lt;br /&gt;
  div = this.format_block(&#039;jstpl_ipiece&#039;, {&lt;br /&gt;
                                type : &#039;meeple&#039;,&lt;br /&gt;
                                color : &#039;ff0000&#039;,&lt;br /&gt;
                                name : &#039;Bob&#039;,&lt;br /&gt;
                            });&lt;br /&gt;
  &lt;br /&gt;
Then you do whatever you need to do with that div, this one specifically design to go to log entries, because it has embedded title (otherwise its a picture only) and no id.&lt;br /&gt;
&lt;br /&gt;
Note: you could have place this variable in js itself, but keeping it in .tpl allows you to have your js code be free of HTML. Normally it never happens but&lt;br /&gt;
it is good to strive for it.&lt;br /&gt;
Note: you can also use string concatenation, its less readable. You can also use dojo dom object creation api&#039;s but its brutally verbose and its more unreadable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create pieces dynamically (using string concatenation) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: Not recommended&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  div = &amp;quot;&amp;lt;div class=&#039;meeple &amp;quot;+color+&amp;quot;&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Create all pieces statically ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.css, ggg.view.php (optional) &lt;br /&gt;
&lt;br /&gt;
* Create ALL game pieces in html template (.tpl)&lt;br /&gt;
* ALL pieces should have unique id, and it should be meaningful, i.e. meeple_red_1&lt;br /&gt;
* Do not use inline styling&lt;br /&gt;
* Id of player&#039;s specific pieces should use some sort of &#039;color&#039; identification, since player id cannot be used in static layout, you can use english color name, hex 6 char value, or color &amp;quot;number&amp;quot; (1,2,3...)&lt;br /&gt;
* Pieces should have separated class for its color, type, etc, so it can be easily styled in groups. In example below you now can style all meeples, all red meeples or all red tokens, or all &amp;quot;first&amp;quot; meeples&lt;br /&gt;
&lt;br /&gt;
ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
  &amp;lt;div id=&amp;quot;home_red&amp;quot; class=&amp;quot;home_red home&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_1&amp;quot; class=&amp;quot;meeple red n1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_2&amp;quot; class=&amp;quot;meeple red n2&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.css:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.meeple {&lt;br /&gt;
	width: 32px;&lt;br /&gt;
	height: 39px;&lt;br /&gt;
	background-image: url(img/78_64_stand_meeples.png);&lt;br /&gt;
	background-size: 352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.meeple.red {&lt;br /&gt;
	background-position: 30% 0%;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* There should be straight forward mapping between server id and js id (or 1:1)&lt;br /&gt;
* You place objects in different zones of the layout, and setup css to take care of layout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.home .meeple{&lt;br /&gt;
   display: inline-block;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you need to have a temporary object that look like original you can use dojo.clone (and change id to some temp id)&lt;br /&gt;
* If there is lots of repetition or zone grid you can use template generator, but inject style declaration in css instead of inline style for flexibility&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
* If you use this model you cannot use premade js components such as Stock and Zone&lt;br /&gt;
* You have to use alternative methods of animation (slightly altered) since default method will leave object with inline style attributes which you don&#039;t need&lt;br /&gt;
&lt;br /&gt;
=== Use thematic fonts ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.css&lt;br /&gt;
&lt;br /&gt;
Sometime game elements use specific fonts of text, if you want to match it up you can load some specific font (IMPORTANT: from some &#039;&#039;&#039;free font&#039;&#039;&#039; source. See notes below).&lt;br /&gt;
&lt;br /&gt;
[[File:Dragonline_font.png]]&lt;br /&gt;
&lt;br /&gt;
.css&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* latin-ext */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: 400;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/2Dy1Unur1HJoklbsg4iPJ_Y6323mHUZFJMgTvxaG2iE.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;&lt;br /&gt;
}&lt;br /&gt;
/* latin */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/gThgNuQB0o5ITpgpLi4Zpw.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;&lt;br /&gt;
}&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(http://ff.static.1001fonts.net/q/w/qwigley.regular.ttf) format(&#039;ttf&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.zone_title {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	font: italic 32px/32px &amp;quot;Qwigley&amp;quot;, cursive;	   &lt;br /&gt;
	height: 32px;&lt;br /&gt;
	width: auto;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NB:&#039;&#039;&#039; if you need to include a font that&#039;s not available online, an extra action will be needed from an admin. Please include the font file(s) in your img directory, and mention it to admins when requesting your game to be moved to alpha. &#039;&#039;&#039;Please remember that the font has to be free, and include a .txt with all appropriate license information about the font.&#039;&#039;&#039;&lt;br /&gt;
You can look for free fonts (for example) on https://fonts.google.com or https://www.fontsquirrel.com/)&lt;br /&gt;
&lt;br /&gt;
=== Use player color in template ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.view.php&lt;br /&gt;
&lt;br /&gt;
.view.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function build_page($viewArgs) {&lt;br /&gt;
        // Get players &amp;amp; players number&lt;br /&gt;
        $players = $this-&amp;gt;game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        $players_nbr = count($players);&lt;br /&gt;
        /**&lt;br /&gt;
         * ********* Place your code below: ***********&lt;br /&gt;
         */&lt;br /&gt;
        &lt;br /&gt;
        // Set PCOLOR to the current player color hex&lt;br /&gt;
        global $g_user;&lt;br /&gt;
        $cplayer = $g_user-&amp;gt;get_id();&lt;br /&gt;
        if (array_key_exists($cplayer, $players)) { // may be not set if spectator&lt;br /&gt;
            $player_color = $players [$cplayer] [&#039;player_color&#039;];&lt;br /&gt;
        } else {&lt;br /&gt;
            $player_color = &#039;ffffff&#039;; // spectator&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;tpl [&#039;PCOLOR&#039;] = $player_color;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Scale to fit for big boards ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lets say you have huge game board, and lets say you want it to be 1400px wide. Besides the board there will be side bar which is 240 and trim. &lt;br /&gt;
My display is 1920 wide so it fits, but there is big chance other people won&#039;t have that width. What do you do?&lt;br /&gt;
&lt;br /&gt;
You have to decide:&lt;br /&gt;
* If board does not fit you want scale whole thing down, the best way is probably use viewport (see https://en.doc.boardgamearena.com/Your_game_mobile_version)&lt;br /&gt;
* You can leave the board as is and make sure it is scrollable horizonatally&lt;br /&gt;
* You add custom scale just for the board (can add user controls  - and hook to transform: scale())&lt;br /&gt;
&lt;br /&gt;
I tried to auto-scale but this just does work, too many variables - browser zoom, 3d mode, viewport, custom bga scaling, devicePixelRatio - all create some impossible coctail of zooming...&lt;br /&gt;
Here is scaling functing for custom user scaling&lt;br /&gt;
&lt;br /&gt;
ggg_ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   &amp;lt;div id=&amp;quot;thething&amp;quot; class=&amp;quot;thething&amp;quot;&amp;gt;&lt;br /&gt;
            ... everything else you declare ...&lt;br /&gt;
   &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onZoomPlus: function() {&lt;br /&gt;
       this.my_zoom+=0.1;&lt;br /&gt;
       this.zoommy(&#039;thething&#039;,this.my_zoom);&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    zoommy: function(node, zoom) {&lt;br /&gt;
                node=$(node);&lt;br /&gt;
		var width = 100 / zoom;&lt;br /&gt;
		node.style.transformOrigin = &amp;quot;0 0&amp;quot;;&lt;br /&gt;
		node.style.transform = &amp;quot;scale(&amp;quot; + zoom + &amp;quot;)&amp;quot;;&lt;br /&gt;
		node.style.width = width + &amp;quot;%&amp;quot;;&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dynamic tooltips ===&lt;br /&gt;
&lt;br /&gt;
If you really need a dynamic tooltip you can use this technique. (Only use it if the static tooltips provided by the BGA framework are not sufficient.)&lt;br /&gt;
&lt;br /&gt;
            new dijit.Tooltip({&lt;br /&gt;
                connectId: [&amp;quot;divItemId&amp;quot;],&lt;br /&gt;
                getContent: function(matchedNode){&lt;br /&gt;
                    return &amp;quot;... calculated ...&amp;quot;; &lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is an out-of-the-box djit.Tooltip. It has a &#039;&#039;getContent&#039;&#039; method which is called dynamically.&lt;br /&gt;
&lt;br /&gt;
The string function return becomes the innerHTML of the tooltip, so it can be anything. In this example matchedNode is a dojo node representing dom object with id of &amp;quot;divItemId&amp;quot; but there are more parameters which I am not posting here which allows more sophisticated subnode queries (i.e. you can attach tooltip to all nodes with class or whatever).&lt;br /&gt;
&lt;br /&gt;
[https://dojotoolkit.org/reference-guide/1.10/dijit/Tooltip.html dijit.Tooltip]&lt;br /&gt;
&lt;br /&gt;
It&#039;s not part of the BGA API so use at your own risk.&lt;br /&gt;
&lt;br /&gt;
=== Accessing images from js ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
     // your game resources&lt;br /&gt;
     &lt;br /&gt;
     var my_img = &#039;&amp;lt;img src=&amp;quot;&#039;+g_gamethemeurl+&#039;img/cards.jpg&amp;quot;/&amp;gt;&#039;;&lt;br /&gt;
     &lt;br /&gt;
     // shared resources&lt;br /&gt;
     var my_help_img = &amp;quot;&amp;lt;img class=&#039;imgtext&#039; src=&#039;&amp;quot; + g_themeurl + &amp;quot;img/layout/help_click.png&#039; alt=&#039;action&#039; /&amp;gt; &amp;lt;span class=&#039;tooltiptext&#039;&amp;gt;&amp;quot; +&lt;br /&gt;
                    text + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Rendering text with players color and proper background ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
This example actually writes &amp;quot;You&amp;quot; but you can replace this with player name as easily, drop translating function in this case&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        /* Implementation of proper colored You with background in case of white or light colors  */&lt;br /&gt;
 &lt;br /&gt;
        divYou : function() {&lt;br /&gt;
            var color = this.gamedatas.players[this.player_id].color;&lt;br /&gt;
            var color_bg = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.gamedatas.players[this.player_id] &amp;amp;&amp;amp; this.gamedatas.players[this.player_id].color_back) {&lt;br /&gt;
                color_bg = &amp;quot;background-color:#&amp;quot; + this.gamedatas.players[this.player_id].color_back + &amp;quot;;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            var you = &amp;quot;&amp;lt;span style=\&amp;quot;font-weight:bold;color:#&amp;quot; + color + &amp;quot;;&amp;quot; + color_bg + &amp;quot;\&amp;quot;&amp;gt;&amp;quot; + __(&amp;quot;lang_mainsite&amp;quot;, &amp;quot;You&amp;quot;) + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
            return you;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inject icon images in the log ===&lt;br /&gt;
&lt;br /&gt;
Here is an example of what was done for Terra Mystica which is simple and straightforward:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//Define the proper message&lt;br /&gt;
		$message = clienttranslate(&#039;${player_name} gets ${power_income} via Structures&#039;);&lt;br /&gt;
		if ($price &amp;gt; 0) {&lt;br /&gt;
			self::DbQuery(&amp;quot;UPDATE player SET player_score = player_score - $price WHERE player_id = $player_id&amp;quot;);&lt;br /&gt;
			$message = clienttranslate(&#039;${player_name} pays ${vp_price} and gets ${power_income} via Structures&#039;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
// Notify&lt;br /&gt;
		self::notifyAllPlayers( &amp;quot;powerViaStructures&amp;quot;, $message, array(&lt;br /&gt;
			&#039;i18n&#039; =&amp;gt; array( ),&lt;br /&gt;
			&#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
			&#039;player_name&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_name FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;power_tokens&#039; =&amp;gt; $power_tokens,&lt;br /&gt;
			&#039;vp_price&#039; =&amp;gt; self::getLogsVPAmount($price),&lt;br /&gt;
			&#039;power_income&#039; =&amp;gt; self::getLogsPowerAmount($power_income),&lt;br /&gt;
			&#039;newScore&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_score FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;counters&#039; =&amp;gt; $this-&amp;gt;getGameCounters(null),&lt;br /&gt;
		) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some functions to have the needed html added inside the substitution variable, such as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function getLogsPowerAmount( $amount ) {&lt;br /&gt;
		return &amp;quot;&amp;lt;div class=&#039;tmlogs_icon&#039; title=&#039;Power&#039;&amp;gt;&amp;lt;div class=&#039;power_amount&#039;&amp;gt;$amount&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: injecting html from php is not ideal but easy, if you want more clean solution, use method below but it is a lot more sophisticated.&lt;br /&gt;
&lt;br /&gt;
=== Inject images and styled html in the log ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php&lt;br /&gt;
&lt;br /&gt;
So you want nice pictures in the game log. What do you do? The first idea that comes to mind is to send html from php in notifications (see method above). &lt;br /&gt;
&lt;br /&gt;
This is a bad idea for many reasons:&lt;br /&gt;
&lt;br /&gt;
* It&#039;s bad architecture. ui elements leak into the server, and now you have to manage the ui in multiple places.&lt;br /&gt;
* If you decided to change something in the ui in future version, replay logs for old games and tutorials may not work, since they use stored notifications.&lt;br /&gt;
* Log previews for old games become unreadable. (This is the log state before you enter the game replay, which is useful for troubleshooting and game analysis.)&lt;br /&gt;
* It&#039;s more data to transfer and store in the db.&lt;br /&gt;
* It&#039;s a nightmare for translators.&lt;br /&gt;
&lt;br /&gt;
So what else can you do? I use this recipe for &#039;&#039;&#039;client side log injection&#039;&#039;&#039; to intercept log arguments (which come from the server) and replace them with html on the client side.&lt;br /&gt;
&lt;br /&gt;
[[File:clientloginjection.png|left]] &lt;br /&gt;
&lt;br /&gt;
ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
        /** Override this function to inject html into log items. This is a built-in BGA method.  */&lt;br /&gt;
&lt;br /&gt;
        /* @Override */&lt;br /&gt;
        format_string_recursive : function(log, args) {&lt;br /&gt;
            try {&lt;br /&gt;
                if (log &amp;amp;&amp;amp; args &amp;amp;&amp;amp; !args.processed) {&lt;br /&gt;
                    args.processed = true;&lt;br /&gt;
                    &lt;br /&gt;
&lt;br /&gt;
                    // list of special keys we want to replace with images&lt;br /&gt;
                    var keys = [&#039;place_name&#039;,&#039;token_name&#039;];&lt;br /&gt;
                    &lt;br /&gt;
                  &lt;br /&gt;
                    for ( var i in keys) {&lt;br /&gt;
                        var key = keys[i];&lt;br /&gt;
                        args[key] = this.getTokenDiv(key, args);                            &lt;br /&gt;
&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                console.error(log,args,&amp;quot;Exception thrown&amp;quot;, e.stack);&lt;br /&gt;
            }&lt;br /&gt;
            return this.inherited(arguments);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; In the &#039;&#039;format_string_recursive&#039;&#039; method, the &#039;args&#039; parameter will only contain arguments passed to it from the notify method in ggg.game.php (see below).&lt;br /&gt;
&lt;br /&gt;
The &#039;log&#039; parameter is the actual string that is inserted into the logs. You can perform additional js string manipulation on it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        getTokenDiv : function(key, args) {&lt;br /&gt;
            // ... implement whatever html you want here, example from sharedcode.js&lt;br /&gt;
            var token_id = args[key];&lt;br /&gt;
            var item_type = getPart(token_id,0);&lt;br /&gt;
            var logid = &amp;quot;log&amp;quot; + (this.globalid++) + &amp;quot;_&amp;quot; + token_id;&lt;br /&gt;
            switch (item_type) {&lt;br /&gt;
                case &#039;wcube&#039;:&lt;br /&gt;
                    var tokenDiv = this.format_block(&#039;jstpl_resource_log&#039;, {&lt;br /&gt;
                        &amp;quot;id&amp;quot; : logid,&lt;br /&gt;
                        &amp;quot;type&amp;quot; : &amp;quot;wcube&amp;quot;,&lt;br /&gt;
                        &amp;quot;color&amp;quot; : getPart(token_id,1),&lt;br /&gt;
                    });&lt;br /&gt;
                    return tokenDiv;&lt;br /&gt;
                    break;&lt;br /&gt;
                case &#039;meeple&#039;:&lt;br /&gt;
                    if ($(token_id)) {&lt;br /&gt;
                        var clone = dojo.clone($(token_id));&lt;br /&gt;
    &lt;br /&gt;
                        dojo.attr(clone, &amp;quot;id&amp;quot;, logid);&lt;br /&gt;
                        this.stripPosition(clone);&lt;br /&gt;
                        dojo.addClass(clone, &amp;quot;logitem&amp;quot;);&lt;br /&gt;
                        return clone.outerHTML;&lt;br /&gt;
                    }&lt;br /&gt;
                    break;&lt;br /&gt;
     &lt;br /&gt;
                default:&lt;br /&gt;
                    break;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return &amp;quot;&#039;&amp;quot; + this.clienttranslate_string(this.getTokenName(token_id)) + &amp;quot;&#039;&amp;quot;;&lt;br /&gt;
       },&lt;br /&gt;
       getTokenName : function(key) {&lt;br /&gt;
           return this.gamedatas.token_types[key].name; // get name for the key, from static table for example&lt;br /&gt;
       },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in this case the server simply injects token_id as a name, and the client substitutes it for the translated name or the picture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ggg.game.php:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name}&#039;),[&#039;token_name&#039;=&amp;gt;$token_id]);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; As noted above, only arguments actually passed by this method are available to the args parameter received in the client-side &#039;&#039;format_string_recursive&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is the case that you want to pass arguments that are not actually included in the output message. For example, suppose we have a method like this:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;tokenPlaced&#039;,clienttranslate(&#039;Player placed ${token_name}&#039;),array(&lt;br /&gt;
              &#039;token_name&#039; =&amp;gt; $token_id,&lt;br /&gt;
              &#039;zone_played&#039; =&amp;gt; $zone);&lt;br /&gt;
&lt;br /&gt;
This will output &amp;quot;Player placed ${token_name}&amp;quot; in the log, and if we subscribe to a notification method activated by the &amp;quot;tokenPlaced&amp;quot; event in the client-side code, that method can make use of the &#039;zone_played&#039; argument. &lt;br /&gt;
&lt;br /&gt;
Now if you want to make some really cool things with game log, most probably you would need more arguments than are included in log message. The problem with that,&lt;br /&gt;
it will work at first, but if you reload game using F5 or when the game loads in turn based mode, you will loose your additional parameters, why? Because when game reloads it does not actually send same notifications, it sends special &amp;quot;hitstorical_log&amp;quot; notification where all  parameters not listed in the message are removed. In example above, field zone_played would be removed from historical log as it is not included in message of the notification. You can till preserve specific arguments in historical log by adding special field preserve to notification arguments like this:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;tokenPlaced&#039;,clienttranslate(&#039;Player placed ${token_name}&#039;),array(&lt;br /&gt;
              &#039;token_name&#039; =&amp;gt; $token_id,&lt;br /&gt;
              &#039;zone_played&#039; =&amp;gt; $zone,&lt;br /&gt;
              &#039;preserve&#039; =&amp;gt; [ 2 =&amp;gt; &#039;zone_played&#039; ]&lt;br /&gt;
           );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now you can use zone_player in format_string_recursive even in historical logs. Note that for this to work, you currently need to define your own indexes for the &#039;preserve&#039; array and avoid using 0 or 1.&lt;br /&gt;
&lt;br /&gt;
=== High-Definition Graphics ===&lt;br /&gt;
&lt;br /&gt;
Some users will have screens which can display text and images at a greater resolution than the usual 72 dpi, e.g. the &amp;quot;Retina&amp;quot; screens on the 5k iMac, all iPads, and high-DPI screens on laptops from many manufacturers. If you can get art assets at this size, they will make your game look extra beautiful. You &#039;&#039;could&#039;&#039; just use large graphics and scale them down, but that would increase the download time and bandwidth for users who can&#039;t display them. Instead, a good way is to prepare a separate graphics file at exactly twice the size you would use otherwise, and add &amp;quot;@2x&amp;quot; at the end of the filename, e.g. if pieces.png is 240x320, then pieces@2x.png is 480x640.&lt;br /&gt;
&lt;br /&gt;
There are two changes required in order to use the separate graphics files. First in your css, where you use a file, add a media query which overrides the original definition and uses the bigger version on devices which can display them. Ensuring that the &amp;quot;background-size&amp;quot; attribute is set means that the size of the displayed object doesn&#039;t change, but only is drawn at the improved dot pitch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.piece {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    background-image: url(&#039;img/pieces.png&#039;);&lt;br /&gt;
    background-size:240px 320px;&lt;br /&gt;
    z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&lt;br /&gt;
{&lt;br /&gt;
    .piece {&lt;br /&gt;
        background-image: url(&#039;img/pieces@2x.png&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Secondly, in your setup function in javascript, you must ensure than only the appropriate one version of the file gets pre-loaded (otherwise you more than waste the bandwidth saved by maintaining the standard-resolution file). Note that the media query is the same in both cases:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            var isRetina = &amp;quot;(-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&amp;quot;;&lt;br /&gt;
            if (window.matchMedia(isRetina).matches)&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces@2x.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board@2x.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Cool realistic shadow effect with CSS ===&lt;br /&gt;
&lt;br /&gt;
==== Rectangles and circles ====&lt;br /&gt;
&lt;br /&gt;
It is often nice to have a drop shadow around tiles and tokens, to separate them from the table visually. It is very easy to add a shadow to rectangular elements, just add this to your css:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.xxx-tile {&lt;br /&gt;
    box-shadow: 3px 3px 3px #000000a0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
box-shadow obeys &#039;&#039;&#039;border-radius&#039;&#039;&#039; of the element, so it will look good for rounded rectangles, and hence also circles (if border-radius is set appropriately).&lt;br /&gt;
&lt;br /&gt;
box-shadow also supports various other parameters and can be used to achieve effects such as glowing, borders, inner shadows etc. If you need to animate a box-shadow, you may be able to get better performance (avoiding redraws) if you attach the shadow to another element (possibly an ::after pseudo-element) and change only the &#039;&#039;&#039;opacity&#039;&#039;&#039; of that element.&lt;br /&gt;
&lt;br /&gt;
==== Irregular Shapes ====&lt;br /&gt;
&lt;br /&gt;
If you wish to make a shadow effect for game pieces that are not a rectangle, but your game pieces are drawn from rectangles in a PNG image, you can apply the shadow to the piece using any art package and save it inside the image. This usually will yield the best performance. Remember to account for the size of the shadow when you lay out images in the sprite sheet.&lt;br /&gt;
&lt;br /&gt;
However that sometimes will not be an option, for example if the image needs to be rotated while the shadow remains offset in the same direction. In this case, one option is to not use box-shadow but use filter, which is supported by recent major browsers.  This way, you can use the alpha channel of your element to drop a shadow.  This even work for transparent backgrounds, so that if you are using the &amp;quot;CSS-sprite&amp;quot; method, it will work!&lt;br /&gt;
&lt;br /&gt;
For instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.xxx-token {&lt;br /&gt;
    filter: drop-shadow(0px 0px 1px #000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beware that some browsers still do not always draw drop-shadow correctly. In particular, Safari frequently leaves bits of shadow behind when objects move around the screen. In Chrome, shadows sometimes flicker badly if another element is animating close by. Some of these correctness issues can be solved by adding &#039;&#039;&#039;isolation: isolate; will-change: filter;&#039;&#039;&#039; to affected elements, but this significantly affects redraw performance.&lt;br /&gt;
&lt;br /&gt;
Beware of performance issues - particularly on Safari (MacOS, iPhone and iPad). Keep in mind that drop-shadow are very GPU intensive. This becomes noticeable once you have about 40 components with drop-shadow filter. If that is your case, you can quite easily implement a user preference to disable shadows for users on slower machines:&lt;br /&gt;
&lt;br /&gt;
gameoptions.inc.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
100 =&amp;gt; array(&lt;br /&gt;
			&#039;name&#039; =&amp;gt; totranslate(&#039;Shadows&#039;),&lt;br /&gt;
			&#039;needReload&#039; =&amp;gt; true, // after user changes this preference game interface would auto-reload&lt;br /&gt;
			&#039;values&#039; =&amp;gt; array(&lt;br /&gt;
					1 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate( &#039;Enabled&#039; ), &#039;cssPref&#039; =&amp;gt; &#039;&#039; ),&lt;br /&gt;
					2 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate( &#039;Disabled&#039; ), &#039;cssPref&#039; =&amp;gt; &#039;no-shadow&#039; )&lt;br /&gt;
			)&lt;br /&gt;
	),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[game].css&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.no-shadow * {&lt;br /&gt;
	filter: none !important; &lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Shadows with clip-path ====&lt;br /&gt;
&lt;br /&gt;
For some reason, a shadow will not work together with clip-path on one element. To use both clip-path (when for example using .svg to cut out cardboard components from your .jpg spritesheet) and drop-shadow, you need to wrap the element into another one, and apply drop-shadow to the outer one, and clip-path to the inner one.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div class=&#039;my-token-wrap&#039;&amp;gt;&lt;br /&gt;
  &amp;lt;div class=&#039;my-token&#039;&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.my-token-wrap {&lt;br /&gt;
    filter: drop-shadow(0px 0px 1px #000000);&lt;br /&gt;
}&lt;br /&gt;
.my-token-wrap .my-token {&lt;br /&gt;
    clip-path: url(#my-token-path);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Using the CSS classes from the state machine ===&lt;br /&gt;
&lt;br /&gt;
If you need to hide or show stuff depending on the state of your game, you can of course use javascript, but CSS is hand enough for that.  The #overall-content element does change class depending on the game state.  For instance, if you are in state &#039;&#039;playerTurn&#039;&#039;, it will have the class &#039;&#039;gamestate_playerTurn&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
So now, if you want to show the discard pile only during player turns, you may use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#discard_pile { display: none }&lt;br /&gt;
.gamestate_playerTurn #discard_pile { display: block }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This can be used if you want to change sizing of elements, position, layout or visual appearance.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game Model and Database design ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Database for The euro game ===&lt;br /&gt;
Lets say we have a game with workers, dice, tokens, board, resources, money and vp. Workers and dice can be placed in various zones on the board, and you can get resources, money, tokens and vp in your home zone. Also tokens can be flipped or not flipped.&lt;br /&gt;
&lt;br /&gt;
[[File:Madeira board.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now lets try to map it, we have&lt;br /&gt;
* (meeple,zone)&lt;br /&gt;
* (die, zone, sideup)&lt;br /&gt;
* (resource cube/money token/vp token,player home zone)&lt;br /&gt;
* (token, player home zone, flip state)&lt;br /&gt;
We can notice that resource and money are uncountable, and don&#039;t need to be track individually so we can replace our mapping to&lt;br /&gt;
* (resource type/money,player home zone, count)&lt;br /&gt;
And vp stored already for us in player table, so we can remove it from that list.&lt;br /&gt;
&lt;br /&gt;
Now when we get to encode it we can see that everything can be encoded as (object,zone,state) form, where object and zone is string and state is integer. The resource mapping is slightly different semantically so you can go with two table, or counting using same table with state been used as count for resources.&lt;br /&gt;
&lt;br /&gt;
So the piece mapping for non-grid based games can be in most case represented by (string: token_key, string: token_location, int: token_state), example of such database schema can be found here: [https://github.com/elaskavaia/bga-sharedcode/blob/master/dbmodel.sql dbmodel.sql] and class implementing access to it here [https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php table.game.php].&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|meeple_red_1&lt;br /&gt;
|home_red&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|dice_black_2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|dice_green_1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|bread&lt;br /&gt;
|home_red&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Now how we represent resource counters such as bread?&lt;br /&gt;
Using same table from we simply add special counter token for bread and use state to indicate the count. Note to keep first column unique we have to add player identification for that counter, i.e. ff0000 is red player.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|bread_ff0000&lt;br /&gt;
|tableau_ff0000&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
See php module for this table here https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php&lt;br /&gt;
&lt;br /&gt;
Variant 2: Additional resource table, resource count for each player id&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `resource` (&lt;br /&gt;
  `player_id` int(10) unsigned NOT NULL,&lt;br /&gt;
  `resource_key` varchar(32) NOT NULL,&lt;br /&gt;
  `resource_count` int(10) signed NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`player_id`,`resource_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
 ALTER TABLE resource ADD CONSTRAINT fk_player_id FOREIGN KEY (player_id) REFERENCES player(player_id);&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+resource&lt;br /&gt;
! player_id&lt;br /&gt;
! resource_key&lt;br /&gt;
! resource_count&lt;br /&gt;
|-&lt;br /&gt;
|123456&lt;br /&gt;
|bread&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 3: More normalised&lt;br /&gt;
&lt;br /&gt;
This version is similar to &amp;quot;card&amp;quot; table from hearts tutorial, you can also use exact cards database schema and Deck implementation for most purposes (even you not dealing with cards). &lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `token_type` varchar(16) NOT NULL,&lt;br /&gt;
  `token_arg` int(11) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_id`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_id&lt;br /&gt;
! token_type&lt;br /&gt;
! token_arg&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|22&lt;br /&gt;
|meeple&lt;br /&gt;
|123456&lt;br /&gt;
|home_123456&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|23&lt;br /&gt;
|dice&lt;br /&gt;
|2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|26&lt;br /&gt;
|dice&lt;br /&gt;
|1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|49&lt;br /&gt;
|bread&lt;br /&gt;
|0&lt;br /&gt;
|home_123456&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Advantages of this would be is a bit more straightforward to do some queries in db, disadvantage its hard to read (as you can compare with previous example, you&lt;br /&gt;
cannot just look at say, ah I know what it means). Another questionable advantage is it allows you to do id randomisation, so it hard to do crafted queries to &lt;br /&gt;
cheat, the down side of that you cannot understand it either, and handcraft db states for debugging or testing.&lt;br /&gt;
&lt;br /&gt;
=== Database for The card game ===&lt;br /&gt;
&lt;br /&gt;
Lets say you have a standard card game, player have hidden cards in hand, you can draw card from draw deck, play card on tableau and discard to discard pile.&lt;br /&gt;
We have to design database for such game.&lt;br /&gt;
&lt;br /&gt;
In real word to &amp;quot;save&amp;quot; the game we take a picture a play area, save cards from it, then put away draw deck, discard and hand of each player separately and mark it, also we will record current scoring (if any) and who&#039;s turn was it.&lt;br /&gt;
&lt;br /&gt;
* Framework handles state machine transition, so you don&#039;t have to worry about database design for that (i.e. who&#039;s turn it is, what phase of the game we are at, you still have to design it but part of state machine step)&lt;br /&gt;
* Also framework supports basic player information, color, order around the table, basic scoring, etc, so you don&#039;t have to worry about it either&lt;br /&gt;
* The only thing you need in our database is state of the &amp;quot;board&amp;quot;, which is &amp;quot;where each pieces is, and in what state&amp;quot;, or (position,rotation) pair.&lt;br /&gt;
&lt;br /&gt;
Lets see what we have for that:&lt;br /&gt;
* The card state is very simple, its usually &amp;quot;face up/face down&amp;quot;, &amp;quot;tapped/untapped&amp;quot;, &amp;quot;right side up/up side down&amp;quot;&lt;br /&gt;
* As position go we never need real coordinates x,y,z. We need to know what &amp;quot;zone&amp;quot; card was, and depending on the zone it may sometimes need an extra &amp;quot;z&amp;quot; or &amp;quot;x&amp;quot; as card order. The zone position usually static or irrelevant.&lt;br /&gt;
* So our model is: we have cards, which have some attributes, at any given point in time they belong to a &amp;quot;zone&amp;quot;, and can also have order and state&lt;br /&gt;
* Now for mapping we should consider what information changes and what information is static, later is always candidate for material file&lt;br /&gt;
* For dynamic information we should try to reduce amount of fields we need&lt;br /&gt;
**  we need at least a field for card, so its one&lt;br /&gt;
**  we need to know what zone cards belong to, its 2&lt;br /&gt;
**  and we have possibly few other fields, if you look closely at you game you may find out that most of the zone only need one attribute at a time, i.e. draw pile always have cards face down, hand always face up, also for hand and discard order does not matter at all (but for draw it does matter). So in majority of cases we can get away with one single extra integer field representing state or order&lt;br /&gt;
* In real database both card and zone will be integers as primary keys referring to additional tables, but in our case its total overkill, so they can be strings as easily&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_key` varchar(32) unsigned NOT NULL,&lt;br /&gt;
  `card_location` varchar(32) NOT NULL,&lt;br /&gt;
  `card_state` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 2: More normalised&lt;br /&gt;
&lt;br /&gt;
This version supported by Deck php class, so unless you want to rewrite db access layer go with this one&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you using this schema, some zones/locations have special semantic. The &#039;hand&#039; location is actually multiple locations - one per player, but player id is encoded as card_location_arg. If &#039;hand&#039; in your game is ordered, visible or can have some other card states, you cannot use hand location (replacement is hand_&amp;lt;player_id&amp;gt; or hand_&amp;lt;color_id&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
== Code Organization ==&lt;br /&gt;
&lt;br /&gt;
=== Including your own JavaScript module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, modules/ggg_other.js&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.js in modules/ folder and sync&lt;br /&gt;
* Modify ggg.js to include it&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  define([ &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;, &amp;quot;ebg/core/gamegui&amp;quot;, &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    // load my own module!!!&lt;br /&gt;
    g_gamethemeurl + &amp;quot;modules/ggg_other.js&amp;quot; ], function(dojo,&lt;br /&gt;
        declare) {&lt;br /&gt;
&lt;br /&gt;
=== Including your own JavaScript module (II) ===&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.js in modules/ folder and sync&lt;br /&gt;
&lt;br /&gt;
  define([], function () {&lt;br /&gt;
    return &amp;quot;value&amp;quot;;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
* Modify ggg.js to include it&lt;br /&gt;
&lt;br /&gt;
  define([ &lt;br /&gt;
    &amp;quot;dojo&amp;quot;, &lt;br /&gt;
    &amp;quot;dojo/_base/declare&amp;quot;, &lt;br /&gt;
    &amp;quot;bgagame/modules/ggg_other&amp;quot;, &lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;, &lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;&lt;br /&gt;
  ], function(dojo, declare, other) {&lt;br /&gt;
  &lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
This is maybe a little bit more the idea of the AMD Loader than the first option, although the first option should work as well.&lt;br /&gt;
&lt;br /&gt;
A little explanation to this:&lt;br /&gt;
The define function loads all the modules listed in the array and calls the following function with these loaded modules as parameters.&lt;br /&gt;
By putting your module at the third position in the array it is passed as the third parameter to the function. Be aware that the modules are resolved by position only, not by name. So you can load the module &#039;&#039;&#039;ggg_other&#039;&#039;&#039; and pass it as a parameter with the name &#039;&#039;&#039;other&#039;&#039;&#039;. &#039;&#039;&#039;gamegui&#039;&#039;&#039; and &#039;&#039;&#039;counter&#039;&#039;&#039; are passed in as well, but when the parameters are not defined they are just skipped. Because these modules put their content into the global scope it does not matter and you can use them from there.&lt;br /&gt;
&lt;br /&gt;
In the example above the string &amp;quot;value&amp;quot; is passed for the parameter &#039;&#039;&#039;other&#039;&#039;&#039;, but the function in your module can return whatever you want. It can be an object, an array, something you declared with dojo.declare, you can return even functions. &lt;br /&gt;
Your module can load other modules. Just put them in the array at the beginning and pass them as parameters to your function.&lt;br /&gt;
The advantage of passing the values as parameter is that you do not need to put these values in the global scope, so they can&#039;t be collisions with values defined in other scripts or the BGA Framework.&lt;br /&gt;
&lt;br /&gt;
The dojo toolkit provides good documentation to all of its components, the complete documentation for the AMD-Loader is here:&lt;br /&gt;
https://dojotoolkit.org/documentation/tutorials/1.10/modules/index.html It should be still correct, even as it seems to be only for version 1.10&lt;br /&gt;
&lt;br /&gt;
=== Including your own PHP module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, modules/ggg_other.php&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.php in modules/ folder and sync&lt;br /&gt;
* Modify ggg.game.php to include it&lt;br /&gt;
&lt;br /&gt;
 require_once (&#039;modules/ggg_other.php&#039;);&lt;br /&gt;
&lt;br /&gt;
=== Creating a test class to run PHP locally ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, stubs&lt;br /&gt;
For this you need stubs of other method you can use this for example&lt;br /&gt;
https://github.com/elaskavaia/bga-sharedcode/raw/master/misc/module/table/table.game.php&lt;br /&gt;
&lt;br /&gt;
Create another php files, i.e ggg_test.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
define(&amp;quot;APP_GAMEMODULE_PATH&amp;quot;, &amp;quot;misc/&amp;quot;); // include path to stubs, which defines &amp;quot;table.game.php&amp;quot; and other classes&lt;br /&gt;
require_once (&#039;eminentdomaine.game.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class MyGameTest1 extends MyGame { // this is your game class defined in ggg.game.php&lt;br /&gt;
    function __construct() {&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        include &#039;../material.inc.php&#039;;// this is how this normally included, from constructor&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // override/stub methods here that access db and stuff&lt;br /&gt;
    function getGameStateValue($var) {&lt;br /&gt;
        if ($var == &#039;round&#039;)&lt;br /&gt;
            return 3;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
$x = new MyGameTest1(); // instantiate your class&lt;br /&gt;
$p = $x-&amp;gt;getGameProgression(); // call one of the methods to test&lt;br /&gt;
if ($p != 50)&lt;br /&gt;
    echo &amp;quot;Test1: FAILED&amp;quot;;&lt;br /&gt;
else&lt;br /&gt;
    echo &amp;quot;Test1: PASSED&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run from command line like&lt;br /&gt;
 php7 ggg_test.php&lt;br /&gt;
&lt;br /&gt;
If you do it this way - you can also use local php debugger (i.e. integrated with IDE or command line).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Avoiding code in dojo declare style ===&lt;br /&gt;
Dojo class declarations are rather bizzare and do not work with most IDEs.&lt;br /&gt;
If you want to write in plain JS with classes, you can stub all the dojo define/declare stuff&lt;br /&gt;
and hook your class into that, so the classes are outside of this mess.&lt;br /&gt;
&lt;br /&gt;
NOTE: this technique is for experienced developers, do not try it if you do not understand&lt;br /&gt;
the consequences.&lt;br /&gt;
&lt;br /&gt;
This is complete example of game .js class&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Testla is game name is has to be changed&lt;br /&gt;
class Testla {&lt;br /&gt;
	constructor(game) {&lt;br /&gt;
		console.log(&#039;game constructor&#039;);&lt;br /&gt;
		this.game = game;&lt;br /&gt;
		this.varfoo = new MyFoo(); // this example of class from custom module&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	setup(gamedatas) {&lt;br /&gt;
		console.log(&amp;quot;Starting game setup&amp;quot;, this.varfoo);&lt;br /&gt;
		this.gamedatas = gamedatas;&lt;br /&gt;
		this.dojo.create(&amp;quot;div&amp;quot;, { class: &#039;whiteblock&#039;, innerHTML: _(&amp;quot;hello&amp;quot;) }, &#039;thething&#039;);&lt;br /&gt;
		console.log(&amp;quot;Ending game setup&amp;quot;);&lt;br /&gt;
	};&lt;br /&gt;
	onEnteringState(stateName, args) {&lt;br /&gt;
		console.log(&#039;onEnteringState : &#039; + stateName, args);&lt;br /&gt;
		this.game.addActionButton(&#039;b1&#039;,_(&#039;Click Me&#039;), (e)=&amp;gt;this.onButtonClick(e));&lt;br /&gt;
	};&lt;br /&gt;
	onLeavingState(stateName) {&lt;br /&gt;
		console.log(&#039;onLeavingState : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onUpdateActionButtons(stateName, args) {&lt;br /&gt;
		console.log(&#039;onUpdateActionButtons : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onButtonClick(event) {&lt;br /&gt;
		console.log(&#039;onButtonClick&#039;,event);&lt;br /&gt;
	};&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
define([&lt;br /&gt;
	&amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
	g_gamethemeurl + &#039;/modules/foo.js&#039; // custom module if needed&lt;br /&gt;
],&lt;br /&gt;
	function(dojo, declare) {&lt;br /&gt;
                // testla is game name is has to be changed&lt;br /&gt;
		return declare(&amp;quot;bgagame.testla&amp;quot;, ebg.core.gamegui, {&lt;br /&gt;
			constructor: function() {&lt;br /&gt;
				this.xapp = new Testla(this);&lt;br /&gt;
				this.xapp.dojo = dojo;&lt;br /&gt;
			},&lt;br /&gt;
			setup: function(gamedatas) {&lt;br /&gt;
				this.xapp.setup(gamedatas);&lt;br /&gt;
			},&lt;br /&gt;
			onEnteringState: function(stateName, args) {&lt;br /&gt;
				this.xapp.onEnteringState(stateName, args.args);&lt;br /&gt;
			},&lt;br /&gt;
			onLeavingState: function(stateName) {&lt;br /&gt;
				this.xapp.onLeavingState(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
			onUpdateActionButtons: function(stateName, args) {&lt;br /&gt;
				this.xapp.onUpdateActionButtons(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
		});&lt;br /&gt;
	});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== More readable JS: onEnteringState ===&lt;br /&gt;
&lt;br /&gt;
If you have a lot of states onEnteringState and friends become rather wild, you can do this trick to call some method dynamically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
     onEnteringState: function(stateName, args) {&lt;br /&gt;
       console.log(&#039;Entering state: &#039; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
       // Call appropriate method&lt;br /&gt;
       var methodName = &amp;quot;onEnteringState_&amp;quot; + stateName;&lt;br /&gt;
       if (this[methodName] !== undefined) {             &lt;br /&gt;
          console.log(&#039;Calling &#039; + methodName, args.args);&lt;br /&gt;
          this[methodName](args.args);&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerTurn: function(args) { // this is args directly, not args.args &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerSomethingElse: function(args) { &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: since its ignores the undefined functions you don&#039;t have define function for each state, but on the other hand you cannot make typos.&lt;br /&gt;
Same applies to onUpdateActionButtons except you pass &#039;args&#039; to method, not args.args, and for onLeavingState where you don&#039;t pass anything.&lt;br /&gt;
&lt;br /&gt;
=== Frameworks and Preprocessors ===&lt;br /&gt;
&lt;br /&gt;
* [[Using Vue]] - work-in-progress guide on using the modern framework Vue.js to create a game&lt;br /&gt;
* [[Using Typescript and Scss]] - How to auto-build Typescript and SCSS files to make your code cleaner&lt;br /&gt;
&lt;br /&gt;
== Assorted Stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Out-of-turn actions: Un-pass ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg.action.php, states.inc.php&lt;br /&gt;
&lt;br /&gt;
In multiplayer game sometimes players passes but than they think more and want to un-Pass and redo their choice. &lt;br /&gt;
To re-active a player who passes some trickery required.&lt;br /&gt;
&lt;br /&gt;
Define a special action that does that and hook it up.&lt;br /&gt;
&lt;br /&gt;
In states.inc.php add an action to mmultipleactiveplayer state to &amp;quot;unpass&amp;quot;, lets call it &amp;quot;actionCancel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In ggg.action.php add action hook&lt;br /&gt;
    public function actionCancel() {&lt;br /&gt;
        self::setAjaxMode();&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;actionCancel();&lt;br /&gt;
        self::ajaxResponse();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
In ggg.game.php add action handler&lt;br /&gt;
    function actionCancel() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction(&#039;actionCancel&#039;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive(array ($this-&amp;gt;getCurrentPlayerId() ), &#039;error&#039;, false);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Finally to call this in client ggg.js you would do something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 onUpdateActionButtons:  function(stateName, args) {&lt;br /&gt;
   if (this.isCurrentPlayerActive()) { &lt;br /&gt;
     // ...&lt;br /&gt;
   } else if (!this.isSpectator) { // player is NOT active but not spectatoe&lt;br /&gt;
       switch (stateName) {&lt;br /&gt;
          case &#039;playerTurnMuliPlayerState&#039;:&lt;br /&gt;
		this.addActionButton(&#039;button_unpass&#039;, _(&#039;Oh no!&#039;), &#039;onUnpass&#039;);&lt;br /&gt;
		break;&lt;br /&gt;
	}&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
				&lt;br /&gt;
 onUnpass: function(e) {&lt;br /&gt;
    this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; +  this.game_name + &amp;quot;/actionCancel.html&amp;quot;, {}, this); // no checkAction!&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Although be careful that if the turn comes back to the player while he is about to click cancel, the action buttons will be updated and the player will misclick which can be quite frustrating. To avoid this, move the cancel button to another position, like to the left of pagemaintitletext:&lt;br /&gt;
  dojo.place(&#039;button_unpass&#039;, &#039;pagemaintitletext&#039;, &#039;before&#039;);&lt;br /&gt;
Being out of the generalactions div, it won&#039;t be automatically destroyed like normal buttons, so you&#039;ll have to handle that yourself in onLeavingState. You might also want to change the button color to red (blue buttons for active player only, red buttons also for inactive players?)&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Selection ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Simple way to implement something like that without extra states is to use &amp;quot;selection&amp;quot; mechanism. When user click on worker add some sort of class into that element i.e. &#039;selected&#039; (which also have to have some indication by css i.e. outline).&lt;br /&gt;
&lt;br /&gt;
Than user can click on placement zone, you can use dojo.query for &amp;quot;selected&amp;quot; element and use it along with zone id to send data to server. If proper worker is not selected yet can give a error message using this.showMessage(...) function.&lt;br /&gt;
&lt;br /&gt;
Extra code required to properly cleanup selection between states.&lt;br /&gt;
Also when you do that sometimes you want to change the state prompt, see below &#039;Change state prompt&#039;&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Client States ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
I don&#039;t think its documented feature but there is a way to do client-only states, which is absolutely wonderful for few reasons&lt;br /&gt;
* When player interaction is two step process, such as select worker, place worker, or place worker, pick one of two resources of your choice&lt;br /&gt;
* When multi-step process can result of impossible situation and has to be undone (by rules)&lt;br /&gt;
* When multi-step process is triggered from multiple states (such as you can do same thing as activated card action, pass action or main action)&lt;br /&gt;
&lt;br /&gt;
So lets do Select Worker/Place Worker&lt;br /&gt;
&lt;br /&gt;
Define your server state as usual, i.e. playerMainTurn -&amp;gt; &amp;quot;You must pick up a worker&amp;quot;.&lt;br /&gt;
Now define a client state, we only need &amp;quot;name&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;, lets say &amp;quot;client_playerPicksLocation&amp;quot;. Always prefix names of client state with &amp;quot;client_&amp;quot; to avoid confusion. Now we have to do the following:&lt;br /&gt;
* Have a handler for onUpdateActionButtons for playerMainTurn to activate all possible workers he can pick&lt;br /&gt;
* When player clicks workers, remember the worker in one of the members of the main class, I usually use one called this.clientStateArgs.&lt;br /&gt;
* Transition to new client state&lt;br /&gt;
  onWorker: function(e) {&lt;br /&gt;
      var id = event.currentTarget.id;&lt;br /&gt;
      dojo.stopEvent(event);&lt;br /&gt;
      ... // do validity checks&lt;br /&gt;
      this.clientStateArgs.worker_id = id;&lt;br /&gt;
      this.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                                descriptionmyturn : &amp;quot;${you} must select location&amp;quot;,&lt;br /&gt;
                            });&lt;br /&gt;
   }&lt;br /&gt;
* Have a handler for onUpdateActionButtons for client_playerPicksLocation to activate all possible locations this worker can go AND add Cancel button (see below)&lt;br /&gt;
* Have a location handler which will eventually send a server request, using stored this.clientStateArgs.worker_id as worker id&lt;br /&gt;
* The cancel button should call a method to restore server state, also if you doing it for more than one state you can add this universally using this.on_client_state check&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        if (this.isCurrentPlayerActive()) {&lt;br /&gt;
          if (this.on_client_state &amp;amp;&amp;amp; !$(&#039;button_cancel&#039;)) {&lt;br /&gt;
               this.addActionButton(&#039;button_cancel&#039;, _(&#039;Cancel&#039;), dojo.hitch(this, function() {&lt;br /&gt;
                                             this.restoreServerGameState();&lt;br /&gt;
               }));&lt;br /&gt;
          }&lt;br /&gt;
        } &lt;br /&gt;
Note: usually I call my own function call this.cancelLocalStateEffects() which will do more stuff first then call restoreServerGameState(), same function is usually needs to be called when server request has failed (i.e. invalid move)&lt;br /&gt;
&lt;br /&gt;
Note: If you need more than 2 steps, you may have to do client side animation to reflect the new state, which gets trickier because you have to undo that also on cancellation.&lt;br /&gt;
&lt;br /&gt;
Code is available here [https://github.com/elaskavaia/bga-sharedcode/blob/master/sharedcode.js sharedcode.js] (its using playerTurnPlayCubes and client_selectCubeLocation).&lt;br /&gt;
=== Changing state prompt ===&lt;br /&gt;
&lt;br /&gt;
State prompt is message displayed for player which usually comes from state description.&lt;br /&gt;
Sometimes you want to change it without changing state (one way is chaneg state but locally, see client states above).&lt;br /&gt;
&lt;br /&gt;
Simple way just change the html&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setMainTitle: function(text) {&lt;br /&gt;
            var main = $(&#039;pagemaintitletext&#039;);&lt;br /&gt;
            main.innerHTML = text;&lt;br /&gt;
        },&lt;br /&gt;
         // usage&lt;br /&gt;
        onMeeple: function(event) {&lt;br /&gt;
              //... &lt;br /&gt;
              this.setMainTitle(_(&#039;You must select where meeple is going&#039;));&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This however will not work with parameters and will not draw You in color, if you want this its more sophisticated:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setDescriptionOnMyTurn : function(text) {&lt;br /&gt;
            this.gamedatas.gamestate.descriptionmyturn = text;&lt;br /&gt;
            var tpl = dojo.clone(this.gamedatas.gamestate.args);&lt;br /&gt;
            if (tpl === null) {&lt;br /&gt;
                tpl = {};&lt;br /&gt;
            }&lt;br /&gt;
            var title = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.isCurrentPlayerActive() &amp;amp;&amp;amp; text !== null) {&lt;br /&gt;
                tpl.you = this.divYou(); &lt;br /&gt;
            }&lt;br /&gt;
            title = this.format_string_recursive(text, tpl);&lt;br /&gt;
&lt;br /&gt;
            if (!title) {&lt;br /&gt;
                this.setMainTitle(&amp;quot;&amp;amp;nbsp;&amp;quot;);&lt;br /&gt;
            } else {&lt;br /&gt;
                this.setMainTitle(title);&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this method uses setMainTitle defined above and divYou defined in another section of this wiki.&lt;br /&gt;
&lt;br /&gt;
=== Assigning Player Order ===&lt;br /&gt;
Normally when game starts there is &amp;quot;natural&amp;quot; player order assigned randomly.&lt;br /&gt;
&lt;br /&gt;
If you want to deliberatly assign player order at the start of the game (for example, in a game with teams options), you can do so by retrieving the initialization-only player attribute &#039;&#039;&#039;player_table_order&#039;&#039;&#039; and using it to assign values to &#039;&#039;&#039;player_no&#039;&#039;&#039; (which is normally assigned at the start of a game in the order in which players come to the table). (See [https://en.doc.boardgamearena.com/Game_database_model:_dbmodel.sql#The_player_table Game database model] for more details.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                // Retrieve inital player order ([0=&amp;gt;playerId1, 1=&amp;gt;playerId2, ...])&lt;br /&gt;
		$playerInitialOrder = [];&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$playerInitialOrder[$player[&#039;player_table_order&#039;]] = $playerId;&lt;br /&gt;
		}&lt;br /&gt;
		ksort($playerInitialOrder);&lt;br /&gt;
		$playerInitialOrder = array_flip(array_values($playerInitialOrder));&lt;br /&gt;
&lt;br /&gt;
		// Player order based on &#039;playerTeams&#039; option&lt;br /&gt;
		$playerOrder = [0, 1, 2, 3];&lt;br /&gt;
		switch (self::getGameStateValue(&#039;playerTeams&#039;)) {&lt;br /&gt;
			case self::TEAM_1_2:&lt;br /&gt;
				$playerOrder = [0, 2, 1, 3];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_1_4:&lt;br /&gt;
				$playerOrder = [0, 1, 3, 2];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_RANDOM:&lt;br /&gt;
				shuffle($playerOrder);&lt;br /&gt;
				break;&lt;br /&gt;
			default:&lt;br /&gt;
			case self::TEAM_1_3:&lt;br /&gt;
				// Default order&lt;br /&gt;
				break;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                // Create players&lt;br /&gt;
		// Note: if you added some extra field on &amp;quot;player&amp;quot; table in the database (dbmodel.sql), you can initialize it there.&lt;br /&gt;
		$sql =&lt;br /&gt;
			&#039;INSERT INTO player (player_id, player_color, player_canal, player_name, player_avatar, player_no) VALUES &#039;;&lt;br /&gt;
		$values = [];&lt;br /&gt;
&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$color = array_shift($default_colors);&lt;br /&gt;
			$values[] =&lt;br /&gt;
				&amp;quot;(&#039;&amp;quot; .&lt;br /&gt;
				$playerId .&lt;br /&gt;
				&amp;quot;&#039;,&#039;$color&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$player[&#039;player_canal&#039;] .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_name&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_avatar&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$playerOrder[$playerInitialOrder[$playerId]] .&lt;br /&gt;
				&amp;quot;&#039;)&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
		$sql .= implode(&#039;,&#039;, $values);&lt;br /&gt;
		self::DbQuery($sql);&lt;br /&gt;
		self::reattributeColorsBasedOnPreferences(&lt;br /&gt;
			$players,&lt;br /&gt;
			$gameinfos[&#039;player_colors&#039;]&lt;br /&gt;
		);&lt;br /&gt;
		self::reloadPlayersBasicInfos();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Send different notifications to active player vs everybody else ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Hack alert. This is a hack. We were hoping for proper solution by bga framework.&lt;br /&gt;
&lt;br /&gt;
This will allow you to send notification with two message one for specific player and one for everybody else including spectators.&lt;br /&gt;
Note that this does not split the data - all data must be shared.&lt;br /&gt;
&lt;br /&gt;
Add this to .js file (if you already overriding it merge obviously)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** @Override */&lt;br /&gt;
format_string_recursive: function(log, args) {&lt;br /&gt;
   if (typeof args.log_others != &#039;undefined&#039; &amp;amp;&amp;amp; typeof args.player_id != &#039;undefined&#039; &amp;amp;&amp;amp; this.player_id != args.player_id)&lt;br /&gt;
	log = args.log_others;&lt;br /&gt;
   return this.inherited(arguments); // you must call this to call super &lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of usage (from eminentdomain)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyAllPlayers(&#039;tokenMoved&#039;, &lt;br /&gt;
             clienttranslate(&#039;${player_name} adds +2 Colonies to ${place_name}&#039;), // notification with show for player with player_id&lt;br /&gt;
             [&#039;player_id&#039;=&amp;gt;$player_id, // this is mandatory&lt;br /&gt;
             &#039;log_others&#039;=&amp;gt;clienttranslate(&#039;${player_name} adds +2 Colonies to an unknown planet&#039;), // notification will show for others&lt;br /&gt;
              ...&lt;br /&gt;
             ]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Send transient notifications without incrementing move ID ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.php&lt;br /&gt;
&lt;br /&gt;
Hack alert. This is a hack.&lt;br /&gt;
&lt;br /&gt;
Use this if you need to send some transient notification that should not create a new move ID. The notification should be idempotent -- it should have no practical effect on the game state and would be &#039;&#039;&#039;safe to drop&#039;&#039;&#039; (e.g., it would not matter if a player never received this notification). For example, in a co-op game you want all players to see a real-time preview of some action, before the active player commits their turn.&lt;br /&gt;
&lt;br /&gt;
Doing this mainly affects the instant replay &amp;amp; archive modes. During replay, the BGA framework automatically inserts a 1.5-second pause between each &amp;quot;move&amp;quot;. With this hack, your transient notifications are not considered to be a &amp;quot;move&amp;quot;, so no pause gets added.&lt;br /&gt;
&lt;br /&gt;
; In ggg.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;not_a_move_notification = true; // note: do not increase the move counter&lt;br /&gt;
$this-&amp;gt;notifyAllPlayers(&#039;cardsPreview&#039;, &#039;&#039;, $args);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ajax Call wrapper ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Note current ajaxcall is super vebosy and prone to errors, I suggest using a helper function. It does a lot of stuff you must do anyways.&lt;br /&gt;
Most beginner mistakes come from missing part of this code (which is understandstandable - this is a huge snippet to clone every time).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	ajaxcallwrapper: function(action, args, handler) {&lt;br /&gt;
		if (!args) args = []; // this allows to skip args parameter for action which do not require them&lt;br /&gt;
			&lt;br /&gt;
		args.lock = true; // this allows to avoid rapid action clicking which can cause race condition on server&lt;br /&gt;
		if (this.checkAction(action)) { // this does all the proper check that player is active and action is declared&lt;br /&gt;
			this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + action + &amp;quot;.html&amp;quot;, args, // this is mandatory fluff &lt;br /&gt;
				this, (result) =&amp;gt; { },  // success result handler is empty - it is never needed&lt;br /&gt;
                                               handler); // this is real result handler - it called both on success and error, its is optional param - you rarely need it&lt;br /&gt;
			}&lt;br /&gt;
		},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.ajaxcallwrapper(&#039;pass&#039;); // no args&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playCard&#039;, {card: card_id}); // with args&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=7566</id>
		<title>Game interface logic: Game.js</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=7566"/>
		<updated>2021-03-06T15:48:49Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Players input */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This is the main file for your game interface. Here you will define:&lt;br /&gt;
&lt;br /&gt;
* Which actions on the page will generate calls to the server.&lt;br /&gt;
* What happens when you get a notification for a change from the server and how it will show in the browser. &lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
&lt;br /&gt;
The details of how the file is structured are described below with comments on the code skeleton provided to you.&lt;br /&gt;
&lt;br /&gt;
Here is the basic structure:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;constructor&#039;&#039;&#039;: here you can define global variables for your whole interface.&lt;br /&gt;
* &#039;&#039;&#039;setup&#039;&#039;&#039;: this method is called when the page is refreshed, and sets up the game interface.&lt;br /&gt;
* &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;: this method is called when entering a new game state. You can use it to customize the view for each game state.&lt;br /&gt;
* &#039;&#039;&#039;onLeavingState&#039;&#039;&#039;: this method is called when leaving a game state.&lt;br /&gt;
* &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039;: called when entering a new state, in order to add action buttons to the status bar.&lt;br /&gt;
* &#039;&#039;(utility methods)&#039;&#039;: this is where you can define your utility methods.&lt;br /&gt;
* &#039;&#039;(player&#039;s actions)&#039;&#039;: this is where you can write your handlers for player actions on the interface (example: click on an item).&lt;br /&gt;
* &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;: this method associates notifications with notification handlers. For each game notification, you can trigger a javascript method to handle it and update the game interface.&lt;br /&gt;
* &#039;&#039;(notification handlers)&#039;&#039;: this is where you define the notifications handlers associated with notifications in &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;, above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
More details:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;onEnteringState(stateName, args)&lt;br /&gt;
This method is called each time we are entering into a new game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
To access state arguments passed via calling arg* method use args.args.&lt;br /&gt;
Typically you would do something only for active player, using this.isCurrentPlayerActive() check.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: for multipleactiveplayer states:&lt;br /&gt;
the active players are NOT actives yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/unactive status.&lt;br /&gt;
If you are doing initialization of some structure which do not depend on active player, you can just replace	&lt;br /&gt;
  if (this.isCurrentPlayerActive()) {&lt;br /&gt;
into&lt;br /&gt;
  if (!this.isSpectator) {&lt;br /&gt;
for the main switch in that method.&lt;br /&gt;
&lt;br /&gt;
;onLeavingState(stateName)&lt;br /&gt;
This method is called each time we are leaving a game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
&lt;br /&gt;
;onUpdateActionButtons(stateName, args)&lt;br /&gt;
In this method you can manage &amp;quot;action buttons&amp;quot; that are displayed in the action status bar.&lt;br /&gt;
To access state arguments passed via calling arg* method use args parameter. Note: args can be null! For game states and when you don&#039;t supply state args function it is null.&lt;br /&gt;
This method is called when active or multiactive player changes. In classic &amp;quot;activePlayer&amp;quot; state this method is called before the onEnteringState state.&lt;br /&gt;
In multipleactiveplayer state it is a mess. The sequencing of call would depends on either you get into that from transition from reloading the whole game (i.e. F5).&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Diffrence_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
== General tips ==&lt;br /&gt;
&lt;br /&gt;
; this.player_id&lt;br /&gt;
: ID of the player on whose browser the code is running.&lt;br /&gt;
&lt;br /&gt;
; this.isSpectator&lt;br /&gt;
: Flag set to true if the user at the table is a spectator (not a player).&lt;br /&gt;
: Note: This is a variable, not a function.&lt;br /&gt;
: Note: If you want to hide an element from spectators, you should use [[Game_interface_stylesheet:_yourgamename.css#spectatorMode|CSS &#039;spectatorMode&#039; class]].&lt;br /&gt;
&lt;br /&gt;
; this.gamedatas&lt;br /&gt;
: Contains the initial set of data to init the game, created at game start or by game refresh (F5).&lt;br /&gt;
: You can update it as needed to keep an up-to-date reference of the game on the client side if you need it. (Most of the time this is unnecessary).&lt;br /&gt;
&lt;br /&gt;
; this.isCurrentPlayerActive()&lt;br /&gt;
: Returns true if the player on whose browser the code is running is currently active (it&#039;s his turn to play).&lt;br /&gt;
&lt;br /&gt;
; this.getActivePlayerId()&lt;br /&gt;
: Return the ID of the active player, or null if we are not in an &amp;quot;activeplayer&amp;quot; type state.&lt;br /&gt;
&lt;br /&gt;
; this.getActivePlayers()&lt;br /&gt;
: Return an array with the IDs of players who are currently active (or an empty array if there are none).&lt;br /&gt;
&lt;br /&gt;
; this.bRealtime&lt;br /&gt;
: Return true if the game is in realtime. Note that having a distinct behavior in realtime and turn-based should be exceptional.&lt;br /&gt;
&lt;br /&gt;
; typeof g_replayFrom != &#039;undefined&#039;&lt;br /&gt;
: Returns true if the game is in replay mode &amp;lt;i&amp;gt;during the game&amp;lt;/i&amp;gt; (the game is ongoing but the user clicked &amp;quot;reply from this move&amp;quot; in the log)&lt;br /&gt;
&lt;br /&gt;
; g_archive_mode&lt;br /&gt;
: Returns true if the game is in archive mode &amp;lt;i&amp;gt;after the game&amp;lt;/i&amp;gt; (the game has ended)&lt;br /&gt;
&lt;br /&gt;
; this.instantaneousMode&lt;br /&gt;
: Returns true during replay/archive mode if animations should be skipped. Only needed if you are doing custom animations. (The BGA-provided animation functions like &amp;lt;i&amp;gt;this.slideToObject()&amp;lt;/i&amp;gt; automatically handle instantaneous mode.)&lt;br /&gt;
: Technically, when you click &amp;quot;replay from move #20&amp;quot;, the system replays the game from the very beginning with moves 0 - 19 happening in instantaneous mode and moves 20+ happening in normal mode.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
You may consider making a function like this, to detect if the game is in a read-only state:&lt;br /&gt;
&lt;br /&gt;
  // Returns true for spectators, instant replay (during game), archive mode (after game end)&lt;br /&gt;
  isReadOnly: function () {&lt;br /&gt;
    return this.isSpectator || typeof g_replayFrom != &#039;undefined&#039; || g_archive_mode;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
== Dojo framework ==&lt;br /&gt;
&lt;br /&gt;
BGA uses the [http://dojotoolkit.org/ Dojo Javascript framework].&lt;br /&gt;
&lt;br /&gt;
The Dojo framework allows us to do complex things more easily. The BGA framework uses Dojo extensively.&lt;br /&gt;
&lt;br /&gt;
To implement a game, you only need to use a few parts of the Dojo framework. All the Dojo methods you need are described on this page.&lt;br /&gt;
&lt;br /&gt;
== Javascript minimization (before July 2020) ==&lt;br /&gt;
&lt;br /&gt;
For performance reasons, when deploying a game the js code is minimized using ShrinkSafe (based on ECMASCRIPT version 3). Some advanced syntax may not be compatible with this process. In particular:&lt;br /&gt;
* You should not use reserved keywords from the javascript language as variables.&lt;br /&gt;
* You should not declare default argument values in function declarations. The following syntax is invalid for ShrinkSafe: &#039;&#039;&#039;function myFunc(requiredArg, optionalArg = &#039;defaultValue&#039;) {}&#039;&#039;&#039;&lt;br /&gt;
* You should not use &#039;&#039;&#039;let&#039;&#039;&#039; or &#039;&#039;&#039;const&#039;&#039;&#039; to declare variables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tip:&#039;&#039;&#039; a developer encountering some problems with this has successfully used [http://plugins.netbeans.org/plugin/58580/jshint JSHint] on NetBeans to evaluate code to make it compatible for ECMAScript 3. With the plugin installed, set the below options in &#039;&#039;&#039;.jshintrc&#039;&#039;&#039; file, and then open &#039;&#039;&#039;Action Items&#039;&#039;&#039; window (in NetBeans):&amp;lt;pre&amp;gt;{ &amp;quot;maxerr&amp;quot;: 999, &amp;quot;esversion&amp;quot;: 3 }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tip:&#039;&#039;&#039; some online tools also allow to convert between different versions of javascript, such as https://www.typescriptlang.org/play or https://babeljs.io/ or https://extendsclass.com/javascript-fiddle.html&lt;br /&gt;
&lt;br /&gt;
== Javascript minimization (after July 2020) ==&lt;br /&gt;
&lt;br /&gt;
For performance reasons, when deploying a game the javascript code is minimized using &#039;&#039;&#039;terser&#039;&#039;&#039; (https://github.com/terser/terser). This minifier works with modern javascript syntax. From your project &amp;quot;Manage game&amp;quot; page, you can now test a minified version of your javascript on the studio (and revert to the original).&lt;br /&gt;
&lt;br /&gt;
NB: it has been reported that there is an issue with this minifier and percentage values for opacity.&lt;br /&gt;
&lt;br /&gt;
== Accessing and manipulating the DOM ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$(&#039;some_html_element_id&#039;)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The $() function is used to get an HTML element using its &amp;quot;id&amp;quot; attribute.&lt;br /&gt;
&lt;br /&gt;
Example 1: modify the content of a &amp;quot;span&amp;quot; element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In your HTML code:&lt;br /&gt;
   &amp;lt;span id=&amp;quot;a_value_in_the_game_interface&amp;quot;&amp;gt;1234&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In your Javascript code:&lt;br /&gt;
   $(&#039;a_value_in_the_game_interface&#039;).innerHTML = &amp;quot;9999&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: $() is the standard method to access some HTML element with the BGA Framework. You should not use the &#039;&#039;&#039;getElementById&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.style&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.style you can modify the CSS property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Make an element disappear&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Give an element a 2px border&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;borderWidth&#039;, &#039;2px&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Change the background position of an element&lt;br /&gt;
     // (very practical when you are using CSS sprites to transform an element to another)&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;backgroundPosition&#039;, &#039;-20px -50px&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you must always use dojo.style to modify the CSS properties of HTML elements.&lt;br /&gt;
&lt;br /&gt;
Note²: if you have to modify several CSS properties of an element, or if you have a complex CSS transformation to do, you should consider using dojo.addClass/dojo.removeClass (see below).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.addClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.removeClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.toggleClass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In many situations, many small CSS property updates can be replaced by a CSS class change (i.e., you add a CSS class to your element instead of applying all modifications manually).&lt;br /&gt;
&lt;br /&gt;
Advantages are:&lt;br /&gt;
* All your CSS stuff remains in your CSS file.&lt;br /&gt;
* You can add/remove a list of CSS modifications with a simple function and without error.&lt;br /&gt;
* You can test whether you applied the CSS to an element with the &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Example from &#039;&#039;Reversi&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // We add &amp;quot;possibleMove&amp;quot; to an element&lt;br /&gt;
    dojo.addClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
    // In our CSS file, the class is defined as:&lt;br /&gt;
    .possibleMove {&lt;br /&gt;
      background-color: white;&lt;br /&gt;
      opacity: 0.2;&lt;br /&gt;
      filter:alpha(opacity=20); /* For IE8 and earlier */  &lt;br /&gt;
      cursor: pointer;  &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     // So we&#039;ve applied 4 CSS property changes in one line of code.&lt;br /&gt;
&lt;br /&gt;
     // ... and when we need to check if a square is a possible move on the client side:&lt;br /&gt;
     if( dojo.hasClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; ) )&lt;br /&gt;
     { ... }&lt;br /&gt;
&lt;br /&gt;
     // ... and if we want to remove all possible moves in one line of code (see &amp;quot;dojo.query&amp;quot; method):&lt;br /&gt;
     dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Conclusion: We encourage you to use &#039;&#039;&#039;dojo.addClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.removeClass&#039;&#039;&#039; and &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; to make your life easier :)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.attr&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.attr you can access or change the value of an attribute or property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Get the title of a node&lt;br /&gt;
     var title = dojo.attr( id, &#039;title&#039; );&lt;br /&gt;
     // Change the height of a node&lt;br /&gt;
     dojo.attr( &#039;img_growing_tree&#039;, &#039;height&#039;, 100 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.query&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.query, you can query a bunch of HTML elements with a single function, with a &amp;quot;CSS selector&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // All elements with class &amp;quot;possibleMove&amp;quot;:&lt;br /&gt;
     var elements = dojo.query( &#039;.possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Count number of tokens (i.e., elements of class &amp;quot;token&amp;quot;) on the board (i.e., the element with id &amp;quot;board&amp;quot;):&lt;br /&gt;
     dojo.query( &#039;#board .token&#039; ).length;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But what is really cool with dojo.query is that you can combine it with almost all methods above.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Trigger a method when the mouse enter in any element with class &amp;quot;meeple&amp;quot;:&lt;br /&gt;
     dojo.query( &#039;.meeple&#039; ).connect( &#039;onmouseenter&#039;, this, &#039;myMethodToTrigger&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Hide all meeples who are on the board&lt;br /&gt;
     dojo.query( &#039;#board .meeple&#039; ).style( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.place&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
dojo.place is the best function to insert HTML code somewhere in your game interface without breaking something. It is much better to use than the &#039;&#039;&#039;innerHTML=&#039;&#039;&#039; method if you must insert HTML tags and not only values.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Insert your HTML code as a child of a container element&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;your html code&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
     // Replace the container element with your new html&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;your html code&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot;, &amp;quot;replace&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The third parameter of dojo.place can take various interesting values:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;replace&amp;quot; : (see description above).&lt;br /&gt;
&lt;br /&gt;
&amp;quot;first&amp;quot; : Places the node as a child of the reference node. The node is placed as the first child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;last&amp;quot; (default) : Places the node as a child of the reference node. The node is placed as the last child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;before&amp;quot; : places the node right before the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;after&amp;quot; : places the node right after the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;only&amp;quot; : replaces all children of the reference node with the node.&lt;br /&gt;
&lt;br /&gt;
positif integer : This parameter can be a positif integer. In this case, the node will be placed as a child of the reference node with this number (counting from 0). If the number is more than number of children, the node will be appended to the reference node making it the last child. &lt;br /&gt;
&lt;br /&gt;
See also full doc on dojo.place : [https://dojotoolkit.org/reference-guide/1.7/dojo/place.html]&lt;br /&gt;
&lt;br /&gt;
Usually, when you want to insert some piece of HTML in your game interface, you should use &amp;quot;[[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.empty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove all children of the node element&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.destroy&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove the element&lt;br /&gt;
&lt;br /&gt;
   dojo.query(&amp;quot;.green&amp;quot;, mynode).forEach(dojo.destroy); // this remove all subnode of class green from mynode&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.create&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create element&lt;br /&gt;
&lt;br /&gt;
    dojo.create(&amp;quot;div&amp;quot;, { class: &amp;quot;yellow_arrow&amp;quot; }, parent); // this creates div with class yellow_array and places it in &amp;quot;parent&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;addStyleToClass: function( cssClassName, cssProperty, propertyValue )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as dojo.style(), but for all the nodes set with the specified cssClassName&lt;br /&gt;
&lt;br /&gt;
=== Animations ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dojo Animations&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
BGA animations is based on Dojo Animation ([http://dojotoolkit.org/documentation/tutorials/1.8/animation/ see tutorial here]).&lt;br /&gt;
&lt;br /&gt;
However, most of the time, you can just use methods below, which are built on top of Dojo Animation.&lt;br /&gt;
&lt;br /&gt;
Note: one interesting method from Dojo that could be useful from time to time is &amp;quot;Dojo.Animation&amp;quot;. It allows you to make any CSS property &amp;quot;slide&amp;quot; from one value to another.&lt;br /&gt;
&lt;br /&gt;
Note 2: the slideTo methods are not compatible with CSS transform (scale, zoom, rotate...). If possible, avoid using CSS transform on nodes that are being slided. Eventually, the only possible solution to make these 2 compatible is to disable all CSS transform properties, use slideToObjectPos/placeOnObjectPos, and then apply them again.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideToObject( mobile_obj, target_obj, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use slideToObject to &amp;quot;slide&amp;quot; an element to a target position.&lt;br /&gt;
&lt;br /&gt;
Sliding element on the game area is the recommended and the most used way to animate your game interface. Using slides allow players to figure out what is happening on the game, as if they were playing with the real boardgame.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* mobile_obj: the ID of the object to move. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned.&lt;br /&gt;
* target_obj: the ID of the target object. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned. Note that it is not mandatory that mobile_obj and target_obj have the same size. If their size are different, the system slides the center of mobile_obj to the center of target_obj.&lt;br /&gt;
* duration: (optional) defines the duration in millisecond of the slide. The default is 500 milliseconds.&lt;br /&gt;
* delay: (optional). If you defines a delay, the slide will start only after this delay. This is particularly useful when you want to slide several object from the same position to the same position: you can give a 0ms delay to the first object, a 100ms delay to the second one, a 200ms delay to the third one, ... this way they won&#039;t be superposed during the slide.&lt;br /&gt;
&lt;br /&gt;
BE CAREFUL: The method returns an dojo.fx animation, so you can combine it with other animation if you want to. It means that you have to call the &amp;quot;play()&amp;quot; method, otherwise the animation WON&#039;T START.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.slideToObject( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideToObjectPos( mobile_obj, target_obj, target_x, target_y, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method does exactly the same as &amp;quot;slideToObject&amp;quot;, except than you can specify some (x,y) coordinates. This way, &amp;quot;mobile_obj&amp;quot; will slide to the specified x,y position relatively to &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example: slide a token to some place on the board, 10 pixels to the bottom:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.slideToObjectPos( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 0, 10 ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideTemporaryObject( mobile_obj_html, mobile_obj_parent, from, to, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is useful when you want to slide a temporary HTML object from one place to another. As this object does not exists before the animation and won&#039;t remain after, it could be complex to create this object (with dojo.place), to place it at its origin (with placeOnObject) to slide it (with slideToObject) and to make it disappear at the end.&lt;br /&gt;
&lt;br /&gt;
slideTemporaryObject does all of this for you:&lt;br /&gt;
* mobile_obj_html is a piece of HTML code that represent the object to slide.&lt;br /&gt;
* mobile_obj_parent is the ID of an HTML element of your interface that will be the parent of this temporary HTML object.&lt;br /&gt;
* from is the ID of the origin of the slide.&lt;br /&gt;
* to is the ID of the target of the slide.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.slideTemporaryObject( &#039;&amp;lt;div class=&amp;quot;token_icon&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, &#039;tokens&#039;, &#039;my_origin_div&#039;, &#039;my_target_div&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideToObjectAndDestroy: function( node, to, time, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is a handy shortcut to slide an existing HTML object to some place then destroy it upon arrival. It can be used for example to move a victory token or a card from the board to the player panel to show that the player earns it, then destroy it when we don&#039;t need to keep it visible on the player panel.&lt;br /&gt;
&lt;br /&gt;
It works the same as this.slideToObject and takes the same arguments. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.slideToObjectAndDestroy( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 1000, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.fadeOutAndDestroy( node, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function fade out the target HTML node, then destroy it.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.fadeOutAndDestroy( &amp;quot;a_card_that_must_disappear&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the HTML node still exists until during few milliseconds, until the fadeOut has been completed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rotating elements&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can check here [http://jimfulton.info/demos/dojo-animated-rotate.html an example of use] of Dojo to make an element rotate.&lt;br /&gt;
&lt;br /&gt;
This example combines &amp;quot;Dojo.Animation&amp;quot; method and a CSS3 property that allow you to rotate the element.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: to asses browser compatibility, you must select the CSS property to use just like in the example (see sourcecode below):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        var transform;&lt;br /&gt;
        dojo.forEach(&lt;br /&gt;
            [&#039;transform&#039;, &#039;WebkitTransform&#039;, &#039;msTransform&#039;,&lt;br /&gt;
             &#039;MozTransform&#039;, &#039;OTransform&#039;],&lt;br /&gt;
            function (name) {&lt;br /&gt;
                if (typeof dojo.body().style[name] != &#039;undefined&#039;) {&lt;br /&gt;
                    transform = name;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        // ... and then use &amp;quot;transform&amp;quot; as the name of your CSS property for rotation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Animation Callbacks&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you wish to run some code only after an animation has completed you can do this by linking a callback method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var animation_id = this.slideToObject( mobile_obj, target_obj, duration, delay );&lt;br /&gt;
dojo.connect(animation_id, &#039;onEnd&#039;, dojo.hitch(this, &#039;callback_function&#039;, parameters));&lt;br /&gt;
animation_id.play();&lt;br /&gt;
&lt;br /&gt;
…&lt;br /&gt;
&lt;br /&gt;
callback_function: function(params) {&lt;br /&gt;
   // this will be called after the animation ends&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you wish to call a second animation after the first (rather than general code) then you can use a dojo animation chain (see tutorial referenced above).&lt;br /&gt;
&lt;br /&gt;
=== Moving elements ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.placeOnObject( mobile_obj, target_obj )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
placeOnObject works exactly like &amp;quot;slideToObject&amp;quot;, except that the effect is immediate.&lt;br /&gt;
&lt;br /&gt;
This is not really an animation, but placeOnObject is frequently used before starting an animation.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // (We just created an object &amp;quot;my_new_token&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  // Place the new token on current player board&lt;br /&gt;
  this.placeOnObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;overall_player_board_&amp;quot;+this.player_id );&lt;br /&gt;
  &lt;br /&gt;
  // Then slide it to its position on the board&lt;br /&gt;
  this.slideToObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;a_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.placeOnObjectPos( mobile_obj, target_obj, target_x, target_y )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method works exactly like placeOnObject, except than you can specify some (x,y) coordinates. This way, &amp;quot;mobile_obj&amp;quot; will be placed to the specified x,y position relatively to &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.attachToNewParent( mobile_obj, target_obj )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With this method, you change the HTML parent of &amp;quot;mobile_obj&amp;quot; element. &amp;quot;target_obj&amp;quot; is the new parent of this element. The beauty of &lt;br /&gt;
attachToNewParent is that the mobile_obj element DOES NOT MOVE during this process.&lt;br /&gt;
&lt;br /&gt;
Note: what happens is that the method calculate a relative position of mobile_obj to make sure it does not move after the HTML parent changes.&lt;br /&gt;
&lt;br /&gt;
Why using this method?&lt;br /&gt;
&lt;br /&gt;
Changing the HTML parent of an element can be useful for the following reasons:&lt;br /&gt;
* When the HTML parent moves, all its child are moving with them. If some game elements is no more linked with a parent HTML object, you may want to attach it to another place.&lt;br /&gt;
* The z_order (vertical order of display) depends on the position in the DOM, so you may need to change the parent of some game elements when they are moving in your game area.&lt;br /&gt;
&lt;br /&gt;
CAREFUL: this function destroys original object and places a clone onto a new parent, this will break all references to this HTML element (ex: dojo.connect).&lt;br /&gt;
&lt;br /&gt;
== Players input ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.connect&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
Example: associate a click on an element (&amp;quot;my_element&amp;quot;) with one of our methods (&amp;quot;onClickOnMyElement&amp;quot;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      dojo.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, this, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same idea but base on query (i.e. all element of &#039;pet&#039; class)&lt;br /&gt;
      dojo.query(&amp;quot;.pet&amp;quot;).connect(&#039;onclick&#039;, this, &#039;onPet&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: the methods described here are the only correct ways to associate a player input event to your code, and you should not use anything else.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.connect&#039;&#039;&#039;&lt;br /&gt;
function(element, event, handler)&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&lt;br /&gt;
Or you can use an in-place handler&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, (e) =&amp;gt; { console.log(&#039;boo&#039;); } );&lt;br /&gt;
&lt;br /&gt;
Note that this function stores the connection handler. That is the only real difference between &#039;&#039;&#039;this.connect&#039;&#039;&#039; and &#039;&#039;&#039;dojo.connect&#039;&#039;&#039;. If you plan to destroy the element you connected, you &#039;&#039;&#039;must&#039;&#039;&#039; call this.disconnect() to prevent memory leaks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.connectClass&#039;&#039;&#039;&lt;br /&gt;
function( cssClassName, event, handler )&lt;br /&gt;
&lt;br /&gt;
Same as connect(), but for all the nodes set with the specified cssClassName.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	this.connectClass(&#039;pet&#039;, &#039;onclick&#039;, &#039;onPet&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;this.disconnect&#039;&#039;&#039;&lt;br /&gt;
function( element, event )&lt;br /&gt;
&lt;br /&gt;
Disconnect event handler (previously registered with this.connect or this.connectClass).&lt;br /&gt;
&lt;br /&gt;
   this.disconnect( $(&#039;my_element&#039;), &#039;onclick&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: dynamic connect/disconnect is for advanced cases ONLY, you should always connect elements statically if possible, i.e. in setup() method.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.disconnectAll&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disconnect all previously registed event handlers (registered via this.connect or this.connectClass)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.checkAction&#039;&#039;&#039;&lt;br /&gt;
function( action, nomessage )&lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* current game state&lt;br /&gt;
* interface locking (a player can&#039;t do any action if an action is already in progress)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
return true if action is authorized (i.e: the action is listed as a &amp;quot;possibleaction&amp;quot; in current game state).&lt;br /&gt;
&lt;br /&gt;
return false and display an error message if not authorized (display no message if nomessage parameter is true). &lt;br /&gt;
The displayed error message could be either &amp;quot;This move is not allowed at this moment&amp;quot; or &amp;quot;An action is already in progress&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  function onClickOnGameElement( evt )  {&lt;br /&gt;
     if( this.checkAction( &amp;quot;my_action&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.checkPossibleActions&#039;&#039;&#039;&lt;br /&gt;
function( action, nomessage )&lt;br /&gt;
&lt;br /&gt;
* this is independent of the player being active, so can be used instead of this.checkAction(). This is particularly useful for multiplayer states when the player is not active in a &#039;player may like to change their mind&#039; scenario. &lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* current game state&lt;br /&gt;
* interface locking (a player can&#039;t do any action if an action is already in progress)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.ajaxcall( url, parameters, obj_callback, callback, callback_error )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method must be used to send a player input to the game server. &#039;&#039;&#039;It should not be triggered programmatically&#039;&#039;&#039;, especially not in loops, in callbacks, in notifications, or in onEnteringState/onUpdateActionButtons/onLeavingState, in order not to create race conditions.&lt;br /&gt;
&lt;br /&gt;
* url: the url of the action to perform. For a game, it must be: &amp;quot;/&amp;lt;mygame&amp;gt;/&amp;lt;mygame&amp;gt;/myAction.html&amp;quot;&lt;br /&gt;
* parameters: an array of parameter to send to the game server. &lt;br /&gt;
** Note that &amp;quot;lock: true&amp;quot; must always be specified in this list of parameters in order the interface can be locked during the server call.&lt;br /&gt;
** Note: Restricted parameter names (please don&#039;t use them):&lt;br /&gt;
*** &amp;quot;action&amp;quot;&lt;br /&gt;
*** &amp;quot;module&amp;quot;&lt;br /&gt;
*** &amp;quot;class&amp;quot;&lt;br /&gt;
* obj_callback: must be set to &amp;quot;this&amp;quot;.&lt;br /&gt;
* callback: a function to trigger when the server returns and everything went fine (not used, as all data handling is done via notifications).&lt;br /&gt;
* callback_error: (optional and rarely used) a function to trigger when the server returns an error.  if no error this function is called with parameter value false.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.ajaxcall( &#039;/mygame/mygame/myaction.html&#039;, { lock: true, &lt;br /&gt;
   arg1: myarg1, &lt;br /&gt;
   arg2: myarg2, &lt;br /&gt;
   ...&lt;br /&gt;
}, this, function( result ) {&lt;br /&gt;
   // Do some stuff after a successful call&lt;br /&gt;
   // NB : usually not needed as changes must be handled by notifications&lt;br /&gt;
   // You should NOT modify the interface in a callback or it will most likely break the framework replays (or make it inaccurate)&lt;br /&gt;
   // You should NOT make another ajaxcall in a callback in order not to create race conditions&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: to reduce the boilerplate code you can define your own wrapper, which will do checking, locking and allow to skip parameters, for example&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
		ajaxcallwrapper: function(action, args, handler) {&lt;br /&gt;
			if (!args) {&lt;br /&gt;
				args = [];&lt;br /&gt;
			}&lt;br /&gt;
			args.lock = true;&lt;br /&gt;
&lt;br /&gt;
			if (this.checkAction(action)) {&lt;br /&gt;
				this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + action + &amp;quot;.html&amp;quot;, args,// &lt;br /&gt;
					this, (result) =&amp;gt; { }, handler);&lt;br /&gt;
			}&lt;br /&gt;
		},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be called like this which is a lot more compact&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playDraw&#039;);&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playMove&#039;, {card: id})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.isInterfaceLocked()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When using &amp;quot;lock: true&amp;quot; in ajax call you can use this function to check if interface is in lock state (it will be locked during server call and notification processing).&lt;br /&gt;
This check can be used to block some other interactions which do not result in ajaxcall or if you want to suppress errors.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addActionButton( id, label, method, (opt)destination, (opt)blinking, (opt)color )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use this method to add an action button in the main action status bar.&lt;br /&gt;
&lt;br /&gt;
Arguments:&lt;br /&gt;
* id: an element ID that should be unique in your HTML DOM document.&lt;br /&gt;
* label: the text of the button. Should be translatable (use _() function).&lt;br /&gt;
* method: the name of your method that must be triggered when the player clicks on this button.&lt;br /&gt;
* destination (optional): deprecated, do not use this. Use &#039;&#039;&#039;null&#039;&#039;&#039; as value if you need to specify other arguments.&lt;br /&gt;
* blinking (optional): if set to &#039;&#039;&#039;true&#039;&#039;&#039;, the button is going blink to catch player&#039;s attention. Please don&#039;t abuse of blinking button.&lt;br /&gt;
* color: could be &#039;&#039;&#039;blue&#039;&#039;&#039; (default), &#039;&#039;&#039;red&#039;&#039;&#039; or &#039;&#039;&#039;gray&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You should only use this method in your &amp;quot;onUpdateActionButtons&amp;quot; method. Usually, you use it like this (from Hearts example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onUpdateActionButtons: function( stateName, args ) {&lt;br /&gt;
                      &lt;br /&gt;
            if (this.isCurrentPlayerActive()) {            &lt;br /&gt;
                switch( stateName ) {&lt;br /&gt;
                case &#039;giveCards&#039;:&lt;br /&gt;
                    this.addActionButton( &#039;giveCards_button&#039;, _(&#039;Give selected cards&#039;), &#039;onGiveCards&#039; ); &lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are adding a &amp;quot;Give selected cards&amp;quot; button in the case we are on game state &amp;quot;giveCards&amp;quot;. When player clicks on this button, it triggers our &amp;quot;onGiveCards&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Example using blinking red button:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     this.addActionButton( &#039;commit_button&#039;, _(&#039;Confirm&#039;), &#039;onConfirm&#039;, null, true, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: at least in studio example above will make button huge, because it sets it display of blinking things to &#039;&#039;&#039;block&#039;&#039;&#039;, &lt;br /&gt;
if you don&#039;t like it you have to change css display value&lt;br /&gt;
of the button to inline-block (the id of the button is the first argument, i.e &#039;commit_button&#039; in example above)&lt;br /&gt;
&lt;br /&gt;
== Translations ==&lt;br /&gt;
&lt;br /&gt;
See [[Translations]]&lt;br /&gt;
&lt;br /&gt;
== Notifications ==&lt;br /&gt;
&lt;br /&gt;
When something happens on the server side, your game interface Javascript logic received a notification.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can handle these notifications on the client side.&lt;br /&gt;
&lt;br /&gt;
=== Subscribe to notifications ===&lt;br /&gt;
&lt;br /&gt;
Your Javascript &amp;quot;setupNotifications&amp;quot; method is the place where you can subscribe to notifications from your PHP code.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you associate one of your Javascript method to a notification &amp;quot;playDisc&amp;quot; (from Reversi example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // In setupNotifications method:&lt;br /&gt;
   dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the &amp;quot;playDisc&amp;quot; corresponds to the name of the notification you define it in your PHP code, in your &amp;quot;notifyAllPlayers&amp;quot; or &amp;quot;notifyPlayer&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Then, you have to define your &amp;quot;notif_playDisc&amp;quot; method:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        notif_playDisc: function( notif )&lt;br /&gt;
        {&lt;br /&gt;
            // Remove current possible moves (makes the board more clear)&lt;br /&gt;
            dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );        &lt;br /&gt;
        &lt;br /&gt;
            this.addDiscOnBoard( notif.args.x, notif.args.y, notif.args.player_id );&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a notification handler like our &amp;quot;notif_playDisc&amp;quot; method, you can access to all notifications arguments with &amp;quot;notif.args&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // If you did this on PHP side:&lt;br /&gt;
    self::notifyAllPlayers( &amp;quot;myNotification&amp;quot;, &#039;&#039;, array( &amp;quot;myArgument&amp;quot; =&amp;gt; 3 ) );&lt;br /&gt;
&lt;br /&gt;
    // On Javascript side, you can access the &amp;quot;myArgument&amp;quot; like this:&lt;br /&gt;
    notif_myNotification: function( notif )&lt;br /&gt;
    {&lt;br /&gt;
       alert( &amp;quot;myArgument = &amp;quot; + notif.args.myArgument );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Synchronous notifications ===&lt;br /&gt;
&lt;br /&gt;
When several notifications are received by your game interface, these notifications are processed immediately, one after the other, in the same exact order they have been generated in your PHP game logic.&lt;br /&gt;
&lt;br /&gt;
However, sometimes, you need to give some time to the players to figure out what happened on the game before jumping to the next notification. Indeed, in many games, they are a lot of automatic actions, and the computer is going to resolve all these actions very fast if you don&#039;t tell it not to do so.&lt;br /&gt;
&lt;br /&gt;
As an example, for Reversi, when someone is playing a disc, we want to wait 500 milliseconds before doing anything else in order the opponent player can figure out what move has been played.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we do this, right after our subscription:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;playDisc&#039;, 500 );   // Wait 500 milliseconds after executing the playDisc handler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
It is also possible to control the delay timing dynamically (e.g., using notification args). As an example, maybe your notification &#039;cardPlayed&#039; should pause for a different amount of time depending on the number or type of cards played.&lt;br /&gt;
&lt;br /&gt;
For this case, use &#039;&#039;&#039;setSynchronous&#039;&#039;&#039; without specifying the duration and use &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039; within the notification callback.&lt;br /&gt;
&lt;br /&gt;
* NOTE: If you forget to invoke &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039;, the game will remain paused forever!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupNotifications: function () {&lt;br /&gt;
    dojo.subscribe( &#039;cardPlayed&#039;, this, &#039;notif_cardPlayed&#039; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;cardPlayed&#039; ); // wait time is dynamic&lt;br /&gt;
    ...&lt;br /&gt;
},&lt;br /&gt;
&lt;br /&gt;
notif_cardPlayed: function (notif) {&lt;br /&gt;
    // MUST call setSynchronousDuration&lt;br /&gt;
&lt;br /&gt;
    // Example 1: From notification args (PHP)&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(notif.args.duration);&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Or, example 2: Match the duration to a Dojo animation&lt;br /&gt;
    var anim = dojo.fx.combine([&lt;br /&gt;
        ...&lt;br /&gt;
    ]);&lt;br /&gt;
    anim.play();&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(anim.duration);&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pre-defined notification types ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tableWindow&#039;&#039;&#039; - This defines notification to display [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialogs]], see below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;message&#039;&#039;&#039; - This defines notification that shows on players log and have no other effect&lt;br /&gt;
&lt;br /&gt;
   // You can call this on php side without doing anything on client side&lt;br /&gt;
    self::notifyAllPlayers( &#039;message&#039;, &#039;hello&#039;, [] );&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;simplePause&#039;&#039;&#039; - This notification will just delay other notifications, maybe useful if you know you need some extra time for animation or something. Requires a time parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    self::notifyAllPlayers( &#039;simplePause&#039;, &#039;&#039;, [ &#039;time&#039; =&amp;gt; 500] ); // time is in milliseconds&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tooltips ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltip( nodeId, _( helpString ), _( actionString ), delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to the DOM node.&lt;br /&gt;
&lt;br /&gt;
Specify &#039;helpString&#039; to display some information about &amp;quot;what is this game element?&amp;quot;.&lt;br /&gt;
Specify &#039;actionString&#039; to display some information about &amp;quot;what happens when I click on this element?&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You must specify both helpString and actionString. Most of the time, you should use only one and specify a void string (&amp;quot;&amp;quot;) for the other one.&lt;br /&gt;
&lt;br /&gt;
Usually, _() must be used for the text to be marked for translation.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Delay&amp;quot; is an optional parameter. Usually, it is primarily used to specify a zero delay for some game element when the tooltip gives really important information for the game - but remember: no essential information must be placed in tooltips as they won&#039;t be displayed in some browsers (see [[BGA_Studio_Guidelines|Guidelines]]).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.addTooltip( &#039;cardcount&#039;, _(&#039;Number of cards in hand&#039;), &#039;&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipHtml( nodeId, html, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to the DOM node (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipToClass( cssClass, _( helpString ), _( actionString ), delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to all the DOM nodes set with this cssClass. &lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipHtmlToClass( cssClass, html, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to to all the DOM nodes set with this cssClass (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must have IDs to get tooltips&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.removeTooltip( nodeId )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove a tooltip from the DOM node.&lt;br /&gt;
&lt;br /&gt;
== Dialogs, warning messages, confirmation dialogs, ... ==&lt;br /&gt;
&lt;br /&gt;
=== Warning messages ===&lt;br /&gt;
&lt;br /&gt;
Sometimes, there is something important that is happening on the game and you have to make sure all players get the message. Most of the time, the evolution of the game situation or the game log is enough, but sometimes you need something more visible.&lt;br /&gt;
&lt;br /&gt;
Ex: someone fulfill one of the end of the game condition, so this is the last turn.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.showMessage( msg, type )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
showMessage shows a message in a big rectangular area on the top of the screen of current player.&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;msg&amp;quot; is the string to display. It should be translated.&lt;br /&gt;
* &amp;quot;type&amp;quot; can be set to &amp;quot;info&amp;quot; or &amp;quot;error&amp;quot;. If set to &amp;quot;info&amp;quot;, the message will be an informative message on a white background. If set to &amp;quot;error&amp;quot;, the message will be an error message on a red background.&lt;br /&gt;
&lt;br /&gt;
Important: the normal way to inform players about the progression of the game is the game log. &amp;quot;showMessage&amp;quot; is intrusive and should not be used often.&lt;br /&gt;
&lt;br /&gt;
=== Confirmation dialog ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;confirmationDialog( message, yesHandler, noHandler )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When an important action with a lot of consequences is triggered by the player, you may want to propose a confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the general guidelines of BGA is to AVOID the use of confirmation dialog. Confirmation dialogs slow down the game and bother players. The players knows that they have to pay attention about each move when they are playing online.&lt;br /&gt;
&lt;br /&gt;
The situation where you should use a confirmation dialog are the following:&lt;br /&gt;
* It must not happen very often during a game.&lt;br /&gt;
* It must be linked to an action that can really &amp;quot;kill a game&amp;quot; if the player do not pay attention.&lt;br /&gt;
* It must be something that can be done by mistake (ex: a link on the action status bar).&lt;br /&gt;
&lt;br /&gt;
How to display a confirmation dialog:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to bake the pie?&#039;), dojo.hitch( this, function() {&lt;br /&gt;
            this.bakeThePie();&lt;br /&gt;
        } ) ); &lt;br /&gt;
        return; // nothing should be called or done after calling this, all action must be done in the handler  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Multiple choice dialog ===&lt;br /&gt;
You can use this dialog to give user a choice with small amount of options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        var keys = [1,5,10];&lt;br /&gt;
        this.multipleChoiceDialog(&lt;br /&gt;
          _(&#039;How many bugs to fix?&#039;), keys, &lt;br /&gt;
            dojo.hitch(this, function(choice) {&lt;br /&gt;
                            var bugchoice = keys[choice];&lt;br /&gt;
                            console.log(&#039;dialog callback with &#039;+bugchoice);&lt;br /&gt;
                            this.ajaxcall( &#039;/mygame/mygame/fixBugs.html&#039;, { bugs: bugchoice}, this, function( result ) {} );                        }));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dialogs ===&lt;br /&gt;
&lt;br /&gt;
As a general rule, you shouldn&#039;t use dialogs windows.&lt;br /&gt;
&lt;br /&gt;
BGA guidelines specify that all game elements should be displayed on the main screen. Players can eventually scroll down to see game elements they don&#039;t need to see anytime, and you may eventually create anchors to move between game area section. Of course dialogs windows are very practical, but the thing is: all players know how to scroll down, and not all players know how to show up your dialog window. In addition, when the dialog shows up, players can&#039;t access the other game components.&lt;br /&gt;
&lt;br /&gt;
Sometimes although, you need to display a dialog window. Here is how you do this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  // Create the new dialog over the play zone. You should store the handler in a member variable to access it later&lt;br /&gt;
  this.myDlg = new ebg.popindialog();&lt;br /&gt;
  this.myDlg.create( &#039;myDialogUniqueId&#039; );&lt;br /&gt;
  this.myDlg.setTitle( _(&amp;quot;my dialog title to translate&amp;quot;) );&lt;br /&gt;
  this.myDlg.setMaxWidth( 500 ); // Optional&lt;br /&gt;
  &lt;br /&gt;
  // Create the HTML of my dialog. &lt;br /&gt;
  // The best practice here is to use [[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&lt;br /&gt;
  var html = this.format_block( &#039;jstpl_myDialogTemplate&#039;, { &lt;br /&gt;
                arg1: myArg1,&lt;br /&gt;
                arg2: myArg2,&lt;br /&gt;
                ...&lt;br /&gt;
            } );  &lt;br /&gt;
  &lt;br /&gt;
  // Show the dialog&lt;br /&gt;
  this.myDlg.setContent( html ); // Must be set before calling show() so that the size of the content is defined before positioning the dialog&lt;br /&gt;
  this.myDlg.show();&lt;br /&gt;
  &lt;br /&gt;
  // Now that the dialog has been displayed, you can connect your method to some dialog elements&lt;br /&gt;
  // Example, if you have an &amp;quot;OK&amp;quot; button in the HTML of your dialog:&lt;br /&gt;
  dojo.connect( $(&#039;my_ok_button&#039;), &#039;onclick&#039;, this, function(evt){&lt;br /&gt;
                evt.preventDefault();&lt;br /&gt;
                this.myDlg.destroy();&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
If necessary, you can remove the default top right corner &#039;close&#039; icon, or replace the function called when it is clicked:&lt;br /&gt;
  // Removes the default close icon&lt;br /&gt;
  this.myDlg.hideCloseIcon();&lt;br /&gt;
&lt;br /&gt;
  // Replace the function call when it&#039;s clicked&lt;br /&gt;
  this.myDlg.replaceCloseCallback( function() { ... } );&lt;br /&gt;
&lt;br /&gt;
=== Scoring dialogs ===&lt;br /&gt;
&lt;br /&gt;
Sometimes at the end of a round you want to display a big table that details the points wins in each section of the game.&lt;br /&gt;
&lt;br /&gt;
Example: in Hearts game, we display at the end of each round the number of &amp;quot;heart&amp;quot; cards collected by each player, the player who collected the Queen of Spades, and the total number of points loose by each player.&lt;br /&gt;
&lt;br /&gt;
Scoring dialogs are managed entirely on &#039;&#039;&#039;PHP side&#039;&#039;&#039;, but they are described here as their effects are visible only on client side.&lt;br /&gt;
&lt;br /&gt;
Displaying a scoring dialog is quite simple and is using a special notification type: &amp;quot;tableWindow&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // on PHP side:&lt;br /&gt;
  $this-&amp;gt;notifyAllPlayers( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table&lt;br /&gt;
        ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;table&amp;quot; argument is a 2 dimensional PHP array that describe the table you want to display, line by line and column by column.&lt;br /&gt;
&lt;br /&gt;
Example: display an 3x3 array of strings&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = array(&lt;br /&gt;
      array( &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, &amp;quot;three&amp;quot; ),    // This is my first line&lt;br /&gt;
      array( &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ),    // This is my second line&lt;br /&gt;
      array( &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; )    // This is my third line&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see above, in each &amp;quot;cell&amp;quot; of your array you can display a simple string value. But you can also display a complex value with a template and associated arguments like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = array(&lt;br /&gt;
      array( &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, array( &amp;quot;str&amp;quot; =&amp;gt; clienttranslate(&amp;quot;a string with an ${argument}&amp;quot;), &amp;quot;args&amp;quot; =&amp;gt; array( &#039;argument&#039; =&amp;gt; &#039;argument_value&#039; )  ) ),&lt;br /&gt;
      array( &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ), &lt;br /&gt;
      array( &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; )&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is especially useful when you want to display player names with colors. Example from &amp;quot;Hearts&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $firstRow = array( &#039;&#039; );&lt;br /&gt;
        foreach( $players as $player_id =&amp;gt; $player )&lt;br /&gt;
        {&lt;br /&gt;
            $firstRow[] = array( &#039;str&#039; =&amp;gt; &#039;${player_name}&#039;,&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; array( &#039;player_name&#039; =&amp;gt; $player[&#039;player_name&#039;] ),&lt;br /&gt;
                                 &#039;type&#039; =&amp;gt; &#039;header&#039;&lt;br /&gt;
                               );&lt;br /&gt;
        }&lt;br /&gt;
        $table[] = $firstRow;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use three extra attributes in the parameter array for the notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $this-&amp;gt;notifyAllPlayers( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table,&lt;br /&gt;
            &amp;quot;header&amp;quot; =&amp;gt; array(&#039;str&#039; =&amp;gt; clienttranslate(&#039;Table header with parameter ${number}&#039;),&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; array( &#039;number&#039; =&amp;gt; 3 ),&lt;br /&gt;
                               ),&lt;br /&gt;
            &amp;quot;footer&amp;quot; =&amp;gt; &#039;&amp;lt;div&amp;gt;Some footer&amp;lt;/div&amp;gt;&#039;,&lt;br /&gt;
            &amp;quot;closing&amp;quot; =&amp;gt; clienttranslate( &amp;quot;Closing button label&amp;quot; )&lt;br /&gt;
        ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;header&#039;&#039;&#039;: the content for this parameter will display before the table (also, the html will be parsed and player names will be colored according to the current game colors). &lt;br /&gt;
*&#039;&#039;&#039;footer&#039;&#039;&#039;: the content for this parameter will display after the table (no parsing for coloring the player names)&lt;br /&gt;
*&#039;&#039;&#039;closing&#039;&#039;&#039;: if this parameter is used, a button will be displayed with this label at the bottom of the popup and will allow players to close it (more easily than by clicking the top right &#039;cross&#039; icon).&lt;br /&gt;
&lt;br /&gt;
=== Scoring animated display ===&lt;br /&gt;
&lt;br /&gt;
Sometimes (Terra Mystica final scoring for example), you may want to display a score value over an element to make the scoring easier to follow for the players.&lt;br /&gt;
You can do it with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.displayScoring( anchor_id, color, score, duration, offset_x, offset_y );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;anchor_id&#039;&#039;&#039;: ID of the element to place the animated score onto (without the &#039;#&#039;) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;color&#039;&#039;&#039;: hexadecimal RGB representation of the color (should be the color of the scoring player), but without a leading &#039;#&#039;.  For instance, &#039;ff0000&#039; for red.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;score&#039;&#039;&#039;: numeric score to display, prefixed by a &#039;+&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;duration&#039;&#039;&#039;: animation duration in milliseconds&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;offset_x&#039;&#039;&#039; and &#039;&#039;&#039;offset_y&#039;&#039;&#039;: if both offset_x and offset_y are defined and not null, apply the following offset (in pixels) to the scoring animation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: if you want to display successively each score, you can use &#039;&#039;this.notifqueue.setSynchronous()&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
=== Speech bubble ===&lt;br /&gt;
&lt;br /&gt;
For better interactivity in some games (Love Letter for example), you may use comic book style speech bubbles to express the players voices.&lt;br /&gt;
This is done with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.showBubble(anchor_id, text, delay, duration, custom_class)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
text - what to put in bubble, can be html actually not just text&lt;br /&gt;
&lt;br /&gt;
delay - in milliseconds is optional (default 0)&lt;br /&gt;
&lt;br /&gt;
duration -  in milliseconds is optional (default 3000)&lt;br /&gt;
&lt;br /&gt;
custom_class - extra class to add to bubble is optional, if you need to override the default bubble style&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: if your bubble could overlap other active elements of the interface (buttons in particular), as it stays in place even after disappearing, you should use a custom class to give it the style &amp;quot;pointer-events: none;&amp;quot; in order to intercept click events.&lt;br /&gt;
&lt;br /&gt;
Note: If you want this visually, but want to take complete control over this bubble and its animation (for example to make it permanent) you can just use div with &#039;discussion_bubble&#039; class on it, and content of div is what will be shown.&lt;br /&gt;
&lt;br /&gt;
== Update players score ==&lt;br /&gt;
&lt;br /&gt;
The column player_score from the player table is automatically loaded into this.scoreCtrl and therefore into the stars location on the player board. This occurs sometime after the &amp;lt;gamename&amp;gt;.js setup() function. However this score must be updated as the game progresses through player notifications (notifs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Increase a player score (with a positive or negative number):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].incValue( score_delta );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set a player score to a specific value:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].setValue( new_score );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set a player score to a specific value with animation :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].toValue( new_score );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typical usage would be (that will process &#039;score&#039; notification):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setupNotifications : function() {&lt;br /&gt;
              ...&lt;br /&gt;
             dojo.subscribe(&#039;score&#039;, this, &amp;quot;notif_score&amp;quot;);&lt;br /&gt;
        },&lt;br /&gt;
        notif_score: function(notif) {&lt;br /&gt;
            this.scoreCtrl[notif.args.player_id].setValue(notif.args.player_score);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Players panels ==&lt;br /&gt;
&lt;br /&gt;
=== Adding stuff to player&#039;s panel ===&lt;br /&gt;
&lt;br /&gt;
At first, create a new &amp;quot;JS template&amp;quot; string in your template (tpl) file:&lt;br /&gt;
&lt;br /&gt;
(from Gomoku example)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var jstpl_player_board = &#039;\&amp;lt;div class=&amp;quot;cp_board&amp;quot;&amp;gt;\&lt;br /&gt;
    &amp;lt;div id=&amp;quot;stoneicon_p${id}&amp;quot; class=&amp;quot;gmk_stoneicon gmk_stoneicon_${color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;span id=&amp;quot;stonecount_p${id}&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;\&lt;br /&gt;
&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, you add this piece of code in your JS file to add this template to each player panel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Setting up player boards&lt;br /&gt;
            for( var player_id in gamedatas.players )&lt;br /&gt;
            {&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                         &lt;br /&gt;
                // Setting up players boards if needed&lt;br /&gt;
                var player_board_div = $(&#039;player_board_&#039;+player_id);&lt;br /&gt;
                dojo.place( this.format_block(&#039;jstpl_player_board&#039;, player ), player_board_div );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Note: the code above is of course from your &amp;quot;setup&amp;quot; function in your Javascript).&lt;br /&gt;
&lt;br /&gt;
Very often, you have to distinguish current player and others players. In this case, you just have to create another JS template (ex: jstpl_otherplayer_board) and use it when &amp;quot;player_id&amp;quot; is different than &amp;quot;this.player_id&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s panel disabling/enabling ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.disablePlayerPanel( player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disable given player panel (the panel background become gray).&lt;br /&gt;
&lt;br /&gt;
Usually, this is used to signal that this played passes, or will be inactive during a while.&lt;br /&gt;
&lt;br /&gt;
Note that the only effect of this is visual. There are no consequences on the behaviour of the panel itself.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.enablePlayerPanel( player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable a player panel that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.enableAllPlayerPanels()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable all player panels that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
== Image loading ==&lt;br /&gt;
&lt;br /&gt;
See also [[Game_art:_img_directory]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Be careful&#039;&#039;&#039;: by default, ALL images of your img directory are loaded on a player&#039;s browser when he loads the game. For this reason, don&#039;t let in your img directory images that are not useful, otherwise it&#039;s going to slowdown the game load.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dontPreloadImage( image_file_name )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using dontPreloadImage, you tell the interface to not preload a specific image in your img directory.&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is particularly useful if for example you have 2 different themes for a game. To accelerate the loading of the game, you can specify to not preload images corresponding to the other theme.&lt;br /&gt;
&lt;br /&gt;
Another example of use: in &amp;quot;Gosu&amp;quot; game with Kamakor extension, you play with 5 sets of cards among 10 available. Cards images are organized by sets, and we only preload the images corresponding to the 5 current sets with &#039;&#039;&#039;ensureSpecificGameImageLoading( image_file_names_array )&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// By default, do not preload anything&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan1.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan2.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan3.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan4.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan5.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan6.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan7.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan8.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan9.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan10.png&#039; );&lt;br /&gt;
var to_preload = [];&lt;br /&gt;
for( i in this.gamedatas.clans )&lt;br /&gt;
{&lt;br /&gt;
	var clan_id = this.gamedatas.clans[i];&lt;br /&gt;
	to_preload.push( &#039;clan&#039;+clan_id+&#039;.png&#039; );&lt;br /&gt;
}&lt;br /&gt;
if( to_preload.length == 5 )&lt;br /&gt;
{&lt;br /&gt;
	this.ensureSpecificGameImageLoading( to_preload );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; You don&#039;t need to specify to not preload game box images (game_box.png, game_box75.png...) since they are not preloaded by default.&lt;br /&gt;
&lt;br /&gt;
== Other useful stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.hitch&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.hitch, you can create a callback function that will run with your game object context whatever happen.&lt;br /&gt;
&lt;br /&gt;
Typical example: display a BGA confirmation dialog with a callback function created with dojo.hitch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), dojo.hitch( this, function() {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, function( result ) {} );&lt;br /&gt;
        } ) );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, using dojo.hitch, we ensure that the &amp;quot;this&amp;quot; object will be set when the callback is called.&lt;br /&gt;
&lt;br /&gt;
NOTE: In modern JS there are lambdas that eliminate need for that, the example above will look like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), () =&amp;gt; {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, (result) =&amp;gt; {} );&lt;br /&gt;
        } );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; updateCounters(counters)&lt;br /&gt;
: Useful for updating game counters in the player panel (such as resources). &lt;br /&gt;
: &#039;counters&#039; arg is an associative array [counter_name_value =&amp;gt; [ &#039;counter_name&#039; =&amp;gt; counter_name_value, &#039;counter_value&#039; =&amp;gt; counter_value_value], ... ]&lt;br /&gt;
: All counters must be referenced in this.gamedatas.counters and will be updated.&lt;br /&gt;
: DOM objects referenced by &#039;counter_name&#039; will have their innerHTML updated with &#039;counter_value&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;onScreenWidthChange()&#039;&#039;&#039;&lt;br /&gt;
:This function can be overridden in your game to manage some resizing on the client side when the browser window is resized. This function is also triggered at load time, so it can be used to adapt to the :viewport size at the start of the game too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;updatePageTitle()&#039;&#039;&#039;&lt;br /&gt;
:This function allows to update the current page title and turn description according to the game state. If the current game state description this.gamedatas.gamestate.descriptionmyturn is modified before :calling the function, it allows to update the turn description without changing state.&lt;br /&gt;
&lt;br /&gt;
Example from Terra Mystica:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onClickFavorTile: function( evt ) {&lt;br /&gt;
    ...&lt;br /&gt;
    if ( ... ) {&lt;br /&gt;
        this.gamedatas.gamestate.descriptionmyturn = _(&#039;Special action: &#039;) + _(&#039;Advance 1 space	on a Cult track&#039;);&lt;br /&gt;
        this.updatePageTitle();&lt;br /&gt;
        this.removeActionButtons();&lt;br /&gt;
        this.addActionButton( ... );&lt;br /&gt;
         ...&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA GUI components ==&lt;br /&gt;
&lt;br /&gt;
BGA framework provides some useful ready-to-use components for the game interface:&lt;br /&gt;
&lt;br /&gt;
[[Studio#BGA_Studio_game_components_reference]]&lt;br /&gt;
&lt;br /&gt;
Note that each time you are using an additional component, you must declare it at the top of your Javascript file in the list of modules used.&lt;br /&gt;
&lt;br /&gt;
Example if you are using &amp;quot;ebg.stock&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;  /// &amp;lt;=== we are using ebg.stock module&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA Buttons ==&lt;br /&gt;
&lt;br /&gt;
You can create a custom button, but the BGA framework provides a standard button that requires only .css classes: &#039;&#039;&#039;bgabutton&#039;&#039;&#039; and &#039;&#039;&#039;bgabutton_${color}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_blue&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My blue button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_gray&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My gray button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_red&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My red button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_red bgabutton_big&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My big red button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: To see it in action, check out &#039;&#039;Coloretto&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Sounds ==&lt;br /&gt;
&lt;br /&gt;
Add a custom sound and make it load with your interface:&lt;br /&gt;
&lt;br /&gt;
Add this in your template (.tpl) file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.mp3&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_o_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.ogg&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this is a requirement to provide both a mp3 and a ogg file.&lt;br /&gt;
&lt;br /&gt;
Play the sound (from your .js file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            playSound(&#039;&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&#039;);             &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the standard &amp;quot;move&amp;quot; sound for this move (to replace it with your custom sound):&lt;br /&gt;
&lt;br /&gt;
Add this to your notification handler:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            this.disableNextMoveSound();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: it only disable the sound for the next move.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=7565</id>
		<title>Game interface logic: Game.js</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=7565"/>
		<updated>2021-03-06T15:47:23Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Players input */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This is the main file for your game interface. Here you will define:&lt;br /&gt;
&lt;br /&gt;
* Which actions on the page will generate calls to the server.&lt;br /&gt;
* What happens when you get a notification for a change from the server and how it will show in the browser. &lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
&lt;br /&gt;
The details of how the file is structured are described below with comments on the code skeleton provided to you.&lt;br /&gt;
&lt;br /&gt;
Here is the basic structure:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;constructor&#039;&#039;&#039;: here you can define global variables for your whole interface.&lt;br /&gt;
* &#039;&#039;&#039;setup&#039;&#039;&#039;: this method is called when the page is refreshed, and sets up the game interface.&lt;br /&gt;
* &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;: this method is called when entering a new game state. You can use it to customize the view for each game state.&lt;br /&gt;
* &#039;&#039;&#039;onLeavingState&#039;&#039;&#039;: this method is called when leaving a game state.&lt;br /&gt;
* &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039;: called when entering a new state, in order to add action buttons to the status bar.&lt;br /&gt;
* &#039;&#039;(utility methods)&#039;&#039;: this is where you can define your utility methods.&lt;br /&gt;
* &#039;&#039;(player&#039;s actions)&#039;&#039;: this is where you can write your handlers for player actions on the interface (example: click on an item).&lt;br /&gt;
* &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;: this method associates notifications with notification handlers. For each game notification, you can trigger a javascript method to handle it and update the game interface.&lt;br /&gt;
* &#039;&#039;(notification handlers)&#039;&#039;: this is where you define the notifications handlers associated with notifications in &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;, above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
More details:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;onEnteringState(stateName, args)&lt;br /&gt;
This method is called each time we are entering into a new game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
To access state arguments passed via calling arg* method use args.args.&lt;br /&gt;
Typically you would do something only for active player, using this.isCurrentPlayerActive() check.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: for multipleactiveplayer states:&lt;br /&gt;
the active players are NOT actives yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/unactive status.&lt;br /&gt;
If you are doing initialization of some structure which do not depend on active player, you can just replace	&lt;br /&gt;
  if (this.isCurrentPlayerActive()) {&lt;br /&gt;
into&lt;br /&gt;
  if (!this.isSpectator) {&lt;br /&gt;
for the main switch in that method.&lt;br /&gt;
&lt;br /&gt;
;onLeavingState(stateName)&lt;br /&gt;
This method is called each time we are leaving a game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
&lt;br /&gt;
;onUpdateActionButtons(stateName, args)&lt;br /&gt;
In this method you can manage &amp;quot;action buttons&amp;quot; that are displayed in the action status bar.&lt;br /&gt;
To access state arguments passed via calling arg* method use args parameter. Note: args can be null! For game states and when you don&#039;t supply state args function it is null.&lt;br /&gt;
This method is called when active or multiactive player changes. In classic &amp;quot;activePlayer&amp;quot; state this method is called before the onEnteringState state.&lt;br /&gt;
In multipleactiveplayer state it is a mess. The sequencing of call would depends on either you get into that from transition from reloading the whole game (i.e. F5).&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Diffrence_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
== General tips ==&lt;br /&gt;
&lt;br /&gt;
; this.player_id&lt;br /&gt;
: ID of the player on whose browser the code is running.&lt;br /&gt;
&lt;br /&gt;
; this.isSpectator&lt;br /&gt;
: Flag set to true if the user at the table is a spectator (not a player).&lt;br /&gt;
: Note: This is a variable, not a function.&lt;br /&gt;
: Note: If you want to hide an element from spectators, you should use [[Game_interface_stylesheet:_yourgamename.css#spectatorMode|CSS &#039;spectatorMode&#039; class]].&lt;br /&gt;
&lt;br /&gt;
; this.gamedatas&lt;br /&gt;
: Contains the initial set of data to init the game, created at game start or by game refresh (F5).&lt;br /&gt;
: You can update it as needed to keep an up-to-date reference of the game on the client side if you need it. (Most of the time this is unnecessary).&lt;br /&gt;
&lt;br /&gt;
; this.isCurrentPlayerActive()&lt;br /&gt;
: Returns true if the player on whose browser the code is running is currently active (it&#039;s his turn to play).&lt;br /&gt;
&lt;br /&gt;
; this.getActivePlayerId()&lt;br /&gt;
: Return the ID of the active player, or null if we are not in an &amp;quot;activeplayer&amp;quot; type state.&lt;br /&gt;
&lt;br /&gt;
; this.getActivePlayers()&lt;br /&gt;
: Return an array with the IDs of players who are currently active (or an empty array if there are none).&lt;br /&gt;
&lt;br /&gt;
; this.bRealtime&lt;br /&gt;
: Return true if the game is in realtime. Note that having a distinct behavior in realtime and turn-based should be exceptional.&lt;br /&gt;
&lt;br /&gt;
; typeof g_replayFrom != &#039;undefined&#039;&lt;br /&gt;
: Returns true if the game is in replay mode &amp;lt;i&amp;gt;during the game&amp;lt;/i&amp;gt; (the game is ongoing but the user clicked &amp;quot;reply from this move&amp;quot; in the log)&lt;br /&gt;
&lt;br /&gt;
; g_archive_mode&lt;br /&gt;
: Returns true if the game is in archive mode &amp;lt;i&amp;gt;after the game&amp;lt;/i&amp;gt; (the game has ended)&lt;br /&gt;
&lt;br /&gt;
; this.instantaneousMode&lt;br /&gt;
: Returns true during replay/archive mode if animations should be skipped. Only needed if you are doing custom animations. (The BGA-provided animation functions like &amp;lt;i&amp;gt;this.slideToObject()&amp;lt;/i&amp;gt; automatically handle instantaneous mode.)&lt;br /&gt;
: Technically, when you click &amp;quot;replay from move #20&amp;quot;, the system replays the game from the very beginning with moves 0 - 19 happening in instantaneous mode and moves 20+ happening in normal mode.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
You may consider making a function like this, to detect if the game is in a read-only state:&lt;br /&gt;
&lt;br /&gt;
  // Returns true for spectators, instant replay (during game), archive mode (after game end)&lt;br /&gt;
  isReadOnly: function () {&lt;br /&gt;
    return this.isSpectator || typeof g_replayFrom != &#039;undefined&#039; || g_archive_mode;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
== Dojo framework ==&lt;br /&gt;
&lt;br /&gt;
BGA uses the [http://dojotoolkit.org/ Dojo Javascript framework].&lt;br /&gt;
&lt;br /&gt;
The Dojo framework allows us to do complex things more easily. The BGA framework uses Dojo extensively.&lt;br /&gt;
&lt;br /&gt;
To implement a game, you only need to use a few parts of the Dojo framework. All the Dojo methods you need are described on this page.&lt;br /&gt;
&lt;br /&gt;
== Javascript minimization (before July 2020) ==&lt;br /&gt;
&lt;br /&gt;
For performance reasons, when deploying a game the js code is minimized using ShrinkSafe (based on ECMASCRIPT version 3). Some advanced syntax may not be compatible with this process. In particular:&lt;br /&gt;
* You should not use reserved keywords from the javascript language as variables.&lt;br /&gt;
* You should not declare default argument values in function declarations. The following syntax is invalid for ShrinkSafe: &#039;&#039;&#039;function myFunc(requiredArg, optionalArg = &#039;defaultValue&#039;) {}&#039;&#039;&#039;&lt;br /&gt;
* You should not use &#039;&#039;&#039;let&#039;&#039;&#039; or &#039;&#039;&#039;const&#039;&#039;&#039; to declare variables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tip:&#039;&#039;&#039; a developer encountering some problems with this has successfully used [http://plugins.netbeans.org/plugin/58580/jshint JSHint] on NetBeans to evaluate code to make it compatible for ECMAScript 3. With the plugin installed, set the below options in &#039;&#039;&#039;.jshintrc&#039;&#039;&#039; file, and then open &#039;&#039;&#039;Action Items&#039;&#039;&#039; window (in NetBeans):&amp;lt;pre&amp;gt;{ &amp;quot;maxerr&amp;quot;: 999, &amp;quot;esversion&amp;quot;: 3 }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tip:&#039;&#039;&#039; some online tools also allow to convert between different versions of javascript, such as https://www.typescriptlang.org/play or https://babeljs.io/ or https://extendsclass.com/javascript-fiddle.html&lt;br /&gt;
&lt;br /&gt;
== Javascript minimization (after July 2020) ==&lt;br /&gt;
&lt;br /&gt;
For performance reasons, when deploying a game the javascript code is minimized using &#039;&#039;&#039;terser&#039;&#039;&#039; (https://github.com/terser/terser). This minifier works with modern javascript syntax. From your project &amp;quot;Manage game&amp;quot; page, you can now test a minified version of your javascript on the studio (and revert to the original).&lt;br /&gt;
&lt;br /&gt;
NB: it has been reported that there is an issue with this minifier and percentage values for opacity.&lt;br /&gt;
&lt;br /&gt;
== Accessing and manipulating the DOM ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$(&#039;some_html_element_id&#039;)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The $() function is used to get an HTML element using its &amp;quot;id&amp;quot; attribute.&lt;br /&gt;
&lt;br /&gt;
Example 1: modify the content of a &amp;quot;span&amp;quot; element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In your HTML code:&lt;br /&gt;
   &amp;lt;span id=&amp;quot;a_value_in_the_game_interface&amp;quot;&amp;gt;1234&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In your Javascript code:&lt;br /&gt;
   $(&#039;a_value_in_the_game_interface&#039;).innerHTML = &amp;quot;9999&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: $() is the standard method to access some HTML element with the BGA Framework. You should not use the &#039;&#039;&#039;getElementById&#039;&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.style&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.style you can modify the CSS property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Make an element disappear&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Give an element a 2px border&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;borderWidth&#039;, &#039;2px&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Change the background position of an element&lt;br /&gt;
     // (very practical when you are using CSS sprites to transform an element to another)&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;backgroundPosition&#039;, &#039;-20px -50px&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you must always use dojo.style to modify the CSS properties of HTML elements.&lt;br /&gt;
&lt;br /&gt;
Note²: if you have to modify several CSS properties of an element, or if you have a complex CSS transformation to do, you should consider using dojo.addClass/dojo.removeClass (see below).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.addClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.removeClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.toggleClass&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In many situations, many small CSS property updates can be replaced by a CSS class change (i.e., you add a CSS class to your element instead of applying all modifications manually).&lt;br /&gt;
&lt;br /&gt;
Advantages are:&lt;br /&gt;
* All your CSS stuff remains in your CSS file.&lt;br /&gt;
* You can add/remove a list of CSS modifications with a simple function and without error.&lt;br /&gt;
* You can test whether you applied the CSS to an element with the &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Example from &#039;&#039;Reversi&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // We add &amp;quot;possibleMove&amp;quot; to an element&lt;br /&gt;
    dojo.addClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
    // In our CSS file, the class is defined as:&lt;br /&gt;
    .possibleMove {&lt;br /&gt;
      background-color: white;&lt;br /&gt;
      opacity: 0.2;&lt;br /&gt;
      filter:alpha(opacity=20); /* For IE8 and earlier */  &lt;br /&gt;
      cursor: pointer;  &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     // So we&#039;ve applied 4 CSS property changes in one line of code.&lt;br /&gt;
&lt;br /&gt;
     // ... and when we need to check if a square is a possible move on the client side:&lt;br /&gt;
     if( dojo.hasClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; ) )&lt;br /&gt;
     { ... }&lt;br /&gt;
&lt;br /&gt;
     // ... and if we want to remove all possible moves in one line of code (see &amp;quot;dojo.query&amp;quot; method):&lt;br /&gt;
     dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Conclusion: We encourage you to use &#039;&#039;&#039;dojo.addClass&#039;&#039;&#039;, &#039;&#039;&#039;dojo.removeClass&#039;&#039;&#039; and &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; to make your life easier :)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.attr&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.attr you can access or change the value of an attribute or property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Get the title of a node&lt;br /&gt;
     var title = dojo.attr( id, &#039;title&#039; );&lt;br /&gt;
     // Change the height of a node&lt;br /&gt;
     dojo.attr( &#039;img_growing_tree&#039;, &#039;height&#039;, 100 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.query&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.query, you can query a bunch of HTML elements with a single function, with a &amp;quot;CSS selector&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // All elements with class &amp;quot;possibleMove&amp;quot;:&lt;br /&gt;
     var elements = dojo.query( &#039;.possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Count number of tokens (i.e., elements of class &amp;quot;token&amp;quot;) on the board (i.e., the element with id &amp;quot;board&amp;quot;):&lt;br /&gt;
     dojo.query( &#039;#board .token&#039; ).length;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But what is really cool with dojo.query is that you can combine it with almost all methods above.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Trigger a method when the mouse enter in any element with class &amp;quot;meeple&amp;quot;:&lt;br /&gt;
     dojo.query( &#039;.meeple&#039; ).connect( &#039;onmouseenter&#039;, this, &#039;myMethodToTrigger&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Hide all meeples who are on the board&lt;br /&gt;
     dojo.query( &#039;#board .meeple&#039; ).style( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.place&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
dojo.place is the best function to insert HTML code somewhere in your game interface without breaking something. It is much better to use than the &#039;&#039;&#039;innerHTML=&#039;&#039;&#039; method if you must insert HTML tags and not only values.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Insert your HTML code as a child of a container element&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;your html code&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
     // Replace the container element with your new html&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;your html code&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot;, &amp;quot;replace&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The third parameter of dojo.place can take various interesting values:&lt;br /&gt;
&lt;br /&gt;
&amp;quot;replace&amp;quot; : (see description above).&lt;br /&gt;
&lt;br /&gt;
&amp;quot;first&amp;quot; : Places the node as a child of the reference node. The node is placed as the first child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;last&amp;quot; (default) : Places the node as a child of the reference node. The node is placed as the last child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;before&amp;quot; : places the node right before the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;after&amp;quot; : places the node right after the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;only&amp;quot; : replaces all children of the reference node with the node.&lt;br /&gt;
&lt;br /&gt;
positif integer : This parameter can be a positif integer. In this case, the node will be placed as a child of the reference node with this number (counting from 0). If the number is more than number of children, the node will be appended to the reference node making it the last child. &lt;br /&gt;
&lt;br /&gt;
See also full doc on dojo.place : [https://dojotoolkit.org/reference-guide/1.7/dojo/place.html]&lt;br /&gt;
&lt;br /&gt;
Usually, when you want to insert some piece of HTML in your game interface, you should use &amp;quot;[[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.empty&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove all children of the node element&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.destroy&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove the element&lt;br /&gt;
&lt;br /&gt;
   dojo.query(&amp;quot;.green&amp;quot;, mynode).forEach(dojo.destroy); // this remove all subnode of class green from mynode&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.create&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create element&lt;br /&gt;
&lt;br /&gt;
    dojo.create(&amp;quot;div&amp;quot;, { class: &amp;quot;yellow_arrow&amp;quot; }, parent); // this creates div with class yellow_array and places it in &amp;quot;parent&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;addStyleToClass: function( cssClassName, cssProperty, propertyValue )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as dojo.style(), but for all the nodes set with the specified cssClassName&lt;br /&gt;
&lt;br /&gt;
=== Animations ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dojo Animations&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
BGA animations is based on Dojo Animation ([http://dojotoolkit.org/documentation/tutorials/1.8/animation/ see tutorial here]).&lt;br /&gt;
&lt;br /&gt;
However, most of the time, you can just use methods below, which are built on top of Dojo Animation.&lt;br /&gt;
&lt;br /&gt;
Note: one interesting method from Dojo that could be useful from time to time is &amp;quot;Dojo.Animation&amp;quot;. It allows you to make any CSS property &amp;quot;slide&amp;quot; from one value to another.&lt;br /&gt;
&lt;br /&gt;
Note 2: the slideTo methods are not compatible with CSS transform (scale, zoom, rotate...). If possible, avoid using CSS transform on nodes that are being slided. Eventually, the only possible solution to make these 2 compatible is to disable all CSS transform properties, use slideToObjectPos/placeOnObjectPos, and then apply them again.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideToObject( mobile_obj, target_obj, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use slideToObject to &amp;quot;slide&amp;quot; an element to a target position.&lt;br /&gt;
&lt;br /&gt;
Sliding element on the game area is the recommended and the most used way to animate your game interface. Using slides allow players to figure out what is happening on the game, as if they were playing with the real boardgame.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* mobile_obj: the ID of the object to move. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned.&lt;br /&gt;
* target_obj: the ID of the target object. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned. Note that it is not mandatory that mobile_obj and target_obj have the same size. If their size are different, the system slides the center of mobile_obj to the center of target_obj.&lt;br /&gt;
* duration: (optional) defines the duration in millisecond of the slide. The default is 500 milliseconds.&lt;br /&gt;
* delay: (optional). If you defines a delay, the slide will start only after this delay. This is particularly useful when you want to slide several object from the same position to the same position: you can give a 0ms delay to the first object, a 100ms delay to the second one, a 200ms delay to the third one, ... this way they won&#039;t be superposed during the slide.&lt;br /&gt;
&lt;br /&gt;
BE CAREFUL: The method returns an dojo.fx animation, so you can combine it with other animation if you want to. It means that you have to call the &amp;quot;play()&amp;quot; method, otherwise the animation WON&#039;T START.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.slideToObject( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideToObjectPos( mobile_obj, target_obj, target_x, target_y, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method does exactly the same as &amp;quot;slideToObject&amp;quot;, except than you can specify some (x,y) coordinates. This way, &amp;quot;mobile_obj&amp;quot; will slide to the specified x,y position relatively to &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example: slide a token to some place on the board, 10 pixels to the bottom:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.slideToObjectPos( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 0, 10 ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideTemporaryObject( mobile_obj_html, mobile_obj_parent, from, to, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is useful when you want to slide a temporary HTML object from one place to another. As this object does not exists before the animation and won&#039;t remain after, it could be complex to create this object (with dojo.place), to place it at its origin (with placeOnObject) to slide it (with slideToObject) and to make it disappear at the end.&lt;br /&gt;
&lt;br /&gt;
slideTemporaryObject does all of this for you:&lt;br /&gt;
* mobile_obj_html is a piece of HTML code that represent the object to slide.&lt;br /&gt;
* mobile_obj_parent is the ID of an HTML element of your interface that will be the parent of this temporary HTML object.&lt;br /&gt;
* from is the ID of the origin of the slide.&lt;br /&gt;
* to is the ID of the target of the slide.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.slideTemporaryObject( &#039;&amp;lt;div class=&amp;quot;token_icon&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, &#039;tokens&#039;, &#039;my_origin_div&#039;, &#039;my_target_div&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.slideToObjectAndDestroy: function( node, to, time, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is a handy shortcut to slide an existing HTML object to some place then destroy it upon arrival. It can be used for example to move a victory token or a card from the board to the player panel to show that the player earns it, then destroy it when we don&#039;t need to keep it visible on the player panel.&lt;br /&gt;
&lt;br /&gt;
It works the same as this.slideToObject and takes the same arguments. &lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.slideToObjectAndDestroy( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 1000, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.fadeOutAndDestroy( node, duration, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function fade out the target HTML node, then destroy it.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.fadeOutAndDestroy( &amp;quot;a_card_that_must_disappear&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the HTML node still exists until during few milliseconds, until the fadeOut has been completed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Rotating elements&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can check here [http://jimfulton.info/demos/dojo-animated-rotate.html an example of use] of Dojo to make an element rotate.&lt;br /&gt;
&lt;br /&gt;
This example combines &amp;quot;Dojo.Animation&amp;quot; method and a CSS3 property that allow you to rotate the element.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: to asses browser compatibility, you must select the CSS property to use just like in the example (see sourcecode below):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        var transform;&lt;br /&gt;
        dojo.forEach(&lt;br /&gt;
            [&#039;transform&#039;, &#039;WebkitTransform&#039;, &#039;msTransform&#039;,&lt;br /&gt;
             &#039;MozTransform&#039;, &#039;OTransform&#039;],&lt;br /&gt;
            function (name) {&lt;br /&gt;
                if (typeof dojo.body().style[name] != &#039;undefined&#039;) {&lt;br /&gt;
                    transform = name;&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        // ... and then use &amp;quot;transform&amp;quot; as the name of your CSS property for rotation&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Animation Callbacks&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you wish to run some code only after an animation has completed you can do this by linking a callback method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var animation_id = this.slideToObject( mobile_obj, target_obj, duration, delay );&lt;br /&gt;
dojo.connect(animation_id, &#039;onEnd&#039;, dojo.hitch(this, &#039;callback_function&#039;, parameters));&lt;br /&gt;
animation_id.play();&lt;br /&gt;
&lt;br /&gt;
…&lt;br /&gt;
&lt;br /&gt;
callback_function: function(params) {&lt;br /&gt;
   // this will be called after the animation ends&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you wish to call a second animation after the first (rather than general code) then you can use a dojo animation chain (see tutorial referenced above).&lt;br /&gt;
&lt;br /&gt;
=== Moving elements ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.placeOnObject( mobile_obj, target_obj )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
placeOnObject works exactly like &amp;quot;slideToObject&amp;quot;, except that the effect is immediate.&lt;br /&gt;
&lt;br /&gt;
This is not really an animation, but placeOnObject is frequently used before starting an animation.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // (We just created an object &amp;quot;my_new_token&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  // Place the new token on current player board&lt;br /&gt;
  this.placeOnObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;overall_player_board_&amp;quot;+this.player_id );&lt;br /&gt;
  &lt;br /&gt;
  // Then slide it to its position on the board&lt;br /&gt;
  this.slideToObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;a_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.placeOnObjectPos( mobile_obj, target_obj, target_x, target_y )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method works exactly like placeOnObject, except than you can specify some (x,y) coordinates. This way, &amp;quot;mobile_obj&amp;quot; will be placed to the specified x,y position relatively to &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.attachToNewParent( mobile_obj, target_obj )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With this method, you change the HTML parent of &amp;quot;mobile_obj&amp;quot; element. &amp;quot;target_obj&amp;quot; is the new parent of this element. The beauty of &lt;br /&gt;
attachToNewParent is that the mobile_obj element DOES NOT MOVE during this process.&lt;br /&gt;
&lt;br /&gt;
Note: what happens is that the method calculate a relative position of mobile_obj to make sure it does not move after the HTML parent changes.&lt;br /&gt;
&lt;br /&gt;
Why using this method?&lt;br /&gt;
&lt;br /&gt;
Changing the HTML parent of an element can be useful for the following reasons:&lt;br /&gt;
* When the HTML parent moves, all its child are moving with them. If some game elements is no more linked with a parent HTML object, you may want to attach it to another place.&lt;br /&gt;
* The z_order (vertical order of display) depends on the position in the DOM, so you may need to change the parent of some game elements when they are moving in your game area.&lt;br /&gt;
&lt;br /&gt;
CAREFUL: this function destroys original object and places a clone onto a new parent, this will break all references to this HTML element (ex: dojo.connect).&lt;br /&gt;
&lt;br /&gt;
== Players input ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.connect&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
Example: associate a click on an element (&amp;quot;my_element&amp;quot;) with one of our methods (&amp;quot;onClickOnMyElement&amp;quot;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      dojo.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, this, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Same idea but base on query (i.e. all element of &#039;pet&#039; class)&lt;br /&gt;
      dojo.query(&amp;quot;.pet&amp;quot;).connect(&#039;onclick&#039;, this, &#039;onPet&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: the methods described here are the only correct ways to associate a player input event to your code, and you should not use anything else.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.connect&#039;&#039;&#039;&lt;br /&gt;
function(element, event, handler)&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&lt;br /&gt;
Or you can use an in-place handler&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, (e) =&amp;gt; { console.log(&#039;boo&#039;); } );&lt;br /&gt;
&lt;br /&gt;
Note that this function stores the connection handler. That is the only real difference between &#039;&#039;&#039;this.connect&#039;&#039;&#039; and &#039;&#039;&#039;dojo.connect&#039;&#039;&#039;. If you plan to destroy the element you connected, you &#039;&#039;&#039;must&#039;&#039;&#039; call this.disconnect() to prevent memory leaks.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.connectClass&#039;&#039;&#039;&lt;br /&gt;
function( cssClassName, event, handler )&lt;br /&gt;
&lt;br /&gt;
Same as connect(), but for all the nodes set with the specified cssClassName.&lt;br /&gt;
&lt;br /&gt;
	this.connectClass(&#039;pet&#039;, &#039;onclick&#039;, &#039;onPet&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.disconnect&#039;&#039;&#039;&lt;br /&gt;
function( element, event )&lt;br /&gt;
&lt;br /&gt;
Disconnect event handler (previously registered with this.connect or this.connectClass).&lt;br /&gt;
&lt;br /&gt;
   this.disconnect( $(&#039;my_element&#039;), &#039;onclick&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: dynamic connect/disconnect is for advanced cases ONLY, you should always connect elements statically if possible, i.e. in setup() method.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.disconnectAll&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disconnect all previously registed event handlers (registered via this.connect or this.connectClass)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.checkAction&#039;&#039;&#039;&lt;br /&gt;
function( action, nomessage )&lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* current game state&lt;br /&gt;
* interface locking (a player can&#039;t do any action if an action is already in progress)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
return true if action is authorized (i.e: the action is listed as a &amp;quot;possibleaction&amp;quot; in current game state).&lt;br /&gt;
&lt;br /&gt;
return false and display an error message if not authorized (display no message if nomessage parameter is true). &lt;br /&gt;
The displayed error message could be either &amp;quot;This move is not allowed at this moment&amp;quot; or &amp;quot;An action is already in progress&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  function onClickOnGameElement( evt )  {&lt;br /&gt;
     if( this.checkAction( &amp;quot;my_action&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.checkPossibleActions&#039;&#039;&#039;&lt;br /&gt;
function( action, nomessage )&lt;br /&gt;
&lt;br /&gt;
* this is independent of the player being active, so can be used instead of this.checkAction(). This is particularly useful for multiplayer states when the player is not active in a &#039;player may like to change their mind&#039; scenario. &lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* current game state&lt;br /&gt;
* interface locking (a player can&#039;t do any action if an action is already in progress)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.ajaxcall( url, parameters, obj_callback, callback, callback_error )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method must be used to send a player input to the game server. &#039;&#039;&#039;It should not be triggered programmatically&#039;&#039;&#039;, especially not in loops, in callbacks, in notifications, or in onEnteringState/onUpdateActionButtons/onLeavingState, in order not to create race conditions.&lt;br /&gt;
&lt;br /&gt;
* url: the url of the action to perform. For a game, it must be: &amp;quot;/&amp;lt;mygame&amp;gt;/&amp;lt;mygame&amp;gt;/myAction.html&amp;quot;&lt;br /&gt;
* parameters: an array of parameter to send to the game server. &lt;br /&gt;
** Note that &amp;quot;lock: true&amp;quot; must always be specified in this list of parameters in order the interface can be locked during the server call.&lt;br /&gt;
** Note: Restricted parameter names (please don&#039;t use them):&lt;br /&gt;
*** &amp;quot;action&amp;quot;&lt;br /&gt;
*** &amp;quot;module&amp;quot;&lt;br /&gt;
*** &amp;quot;class&amp;quot;&lt;br /&gt;
* obj_callback: must be set to &amp;quot;this&amp;quot;.&lt;br /&gt;
* callback: a function to trigger when the server returns and everything went fine (not used, as all data handling is done via notifications).&lt;br /&gt;
* callback_error: (optional and rarely used) a function to trigger when the server returns an error.  if no error this function is called with parameter value false.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.ajaxcall( &#039;/mygame/mygame/myaction.html&#039;, { lock: true, &lt;br /&gt;
   arg1: myarg1, &lt;br /&gt;
   arg2: myarg2, &lt;br /&gt;
   ...&lt;br /&gt;
}, this, function( result ) {&lt;br /&gt;
   // Do some stuff after a successful call&lt;br /&gt;
   // NB : usually not needed as changes must be handled by notifications&lt;br /&gt;
   // You should NOT modify the interface in a callback or it will most likely break the framework replays (or make it inaccurate)&lt;br /&gt;
   // You should NOT make another ajaxcall in a callback in order not to create race conditions&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: to reduce the boilerplate code you can define your own wrapper, which will do checking, locking and allow to skip parameters, for example&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
		ajaxcallwrapper: function(action, args, handler) {&lt;br /&gt;
			if (!args) {&lt;br /&gt;
				args = [];&lt;br /&gt;
			}&lt;br /&gt;
			args.lock = true;&lt;br /&gt;
&lt;br /&gt;
			if (this.checkAction(action)) {&lt;br /&gt;
				this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + action + &amp;quot;.html&amp;quot;, args,// &lt;br /&gt;
					this, (result) =&amp;gt; { }, handler);&lt;br /&gt;
			}&lt;br /&gt;
		},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be called like this which is a lot more compact&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playDraw&#039;);&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playMove&#039;, {card: id})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.isInterfaceLocked()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When using &amp;quot;lock: true&amp;quot; in ajax call you can use this function to check if interface is in lock state (it will be locked during server call and notification processing).&lt;br /&gt;
This check can be used to block some other interactions which do not result in ajaxcall or if you want to suppress errors.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addActionButton( id, label, method, (opt)destination, (opt)blinking, (opt)color )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use this method to add an action button in the main action status bar.&lt;br /&gt;
&lt;br /&gt;
Arguments:&lt;br /&gt;
* id: an element ID that should be unique in your HTML DOM document.&lt;br /&gt;
* label: the text of the button. Should be translatable (use _() function).&lt;br /&gt;
* method: the name of your method that must be triggered when the player clicks on this button.&lt;br /&gt;
* destination (optional): deprecated, do not use this. Use &#039;&#039;&#039;null&#039;&#039;&#039; as value if you need to specify other arguments.&lt;br /&gt;
* blinking (optional): if set to &#039;&#039;&#039;true&#039;&#039;&#039;, the button is going blink to catch player&#039;s attention. Please don&#039;t abuse of blinking button.&lt;br /&gt;
* color: could be &#039;&#039;&#039;blue&#039;&#039;&#039; (default), &#039;&#039;&#039;red&#039;&#039;&#039; or &#039;&#039;&#039;gray&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You should only use this method in your &amp;quot;onUpdateActionButtons&amp;quot; method. Usually, you use it like this (from Hearts example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onUpdateActionButtons: function( stateName, args ) {&lt;br /&gt;
                      &lt;br /&gt;
            if (this.isCurrentPlayerActive()) {            &lt;br /&gt;
                switch( stateName ) {&lt;br /&gt;
                case &#039;giveCards&#039;:&lt;br /&gt;
                    this.addActionButton( &#039;giveCards_button&#039;, _(&#039;Give selected cards&#039;), &#039;onGiveCards&#039; ); &lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are adding a &amp;quot;Give selected cards&amp;quot; button in the case we are on game state &amp;quot;giveCards&amp;quot;. When player clicks on this button, it triggers our &amp;quot;onGiveCards&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Example using blinking red button:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     this.addActionButton( &#039;commit_button&#039;, _(&#039;Confirm&#039;), &#039;onConfirm&#039;, null, true, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: at least in studio example above will make button huge, because it sets it display of blinking things to &#039;&#039;&#039;block&#039;&#039;&#039;, &lt;br /&gt;
if you don&#039;t like it you have to change css display value&lt;br /&gt;
of the button to inline-block (the id of the button is the first argument, i.e &#039;commit_button&#039; in example above)&lt;br /&gt;
&lt;br /&gt;
== Translations ==&lt;br /&gt;
&lt;br /&gt;
See [[Translations]]&lt;br /&gt;
&lt;br /&gt;
== Notifications ==&lt;br /&gt;
&lt;br /&gt;
When something happens on the server side, your game interface Javascript logic received a notification.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can handle these notifications on the client side.&lt;br /&gt;
&lt;br /&gt;
=== Subscribe to notifications ===&lt;br /&gt;
&lt;br /&gt;
Your Javascript &amp;quot;setupNotifications&amp;quot; method is the place where you can subscribe to notifications from your PHP code.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you associate one of your Javascript method to a notification &amp;quot;playDisc&amp;quot; (from Reversi example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   // In setupNotifications method:&lt;br /&gt;
   dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the &amp;quot;playDisc&amp;quot; corresponds to the name of the notification you define it in your PHP code, in your &amp;quot;notifyAllPlayers&amp;quot; or &amp;quot;notifyPlayer&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Then, you have to define your &amp;quot;notif_playDisc&amp;quot; method:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        notif_playDisc: function( notif )&lt;br /&gt;
        {&lt;br /&gt;
            // Remove current possible moves (makes the board more clear)&lt;br /&gt;
            dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );        &lt;br /&gt;
        &lt;br /&gt;
            this.addDiscOnBoard( notif.args.x, notif.args.y, notif.args.player_id );&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a notification handler like our &amp;quot;notif_playDisc&amp;quot; method, you can access to all notifications arguments with &amp;quot;notif.args&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // If you did this on PHP side:&lt;br /&gt;
    self::notifyAllPlayers( &amp;quot;myNotification&amp;quot;, &#039;&#039;, array( &amp;quot;myArgument&amp;quot; =&amp;gt; 3 ) );&lt;br /&gt;
&lt;br /&gt;
    // On Javascript side, you can access the &amp;quot;myArgument&amp;quot; like this:&lt;br /&gt;
    notif_myNotification: function( notif )&lt;br /&gt;
    {&lt;br /&gt;
       alert( &amp;quot;myArgument = &amp;quot; + notif.args.myArgument );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Synchronous notifications ===&lt;br /&gt;
&lt;br /&gt;
When several notifications are received by your game interface, these notifications are processed immediately, one after the other, in the same exact order they have been generated in your PHP game logic.&lt;br /&gt;
&lt;br /&gt;
However, sometimes, you need to give some time to the players to figure out what happened on the game before jumping to the next notification. Indeed, in many games, they are a lot of automatic actions, and the computer is going to resolve all these actions very fast if you don&#039;t tell it not to do so.&lt;br /&gt;
&lt;br /&gt;
As an example, for Reversi, when someone is playing a disc, we want to wait 500 milliseconds before doing anything else in order the opponent player can figure out what move has been played.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we do this, right after our subscription:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;playDisc&#039;, 500 );   // Wait 500 milliseconds after executing the playDisc handler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
It is also possible to control the delay timing dynamically (e.g., using notification args). As an example, maybe your notification &#039;cardPlayed&#039; should pause for a different amount of time depending on the number or type of cards played.&lt;br /&gt;
&lt;br /&gt;
For this case, use &#039;&#039;&#039;setSynchronous&#039;&#039;&#039; without specifying the duration and use &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039; within the notification callback.&lt;br /&gt;
&lt;br /&gt;
* NOTE: If you forget to invoke &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039;, the game will remain paused forever!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupNotifications: function () {&lt;br /&gt;
    dojo.subscribe( &#039;cardPlayed&#039;, this, &#039;notif_cardPlayed&#039; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;cardPlayed&#039; ); // wait time is dynamic&lt;br /&gt;
    ...&lt;br /&gt;
},&lt;br /&gt;
&lt;br /&gt;
notif_cardPlayed: function (notif) {&lt;br /&gt;
    // MUST call setSynchronousDuration&lt;br /&gt;
&lt;br /&gt;
    // Example 1: From notification args (PHP)&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(notif.args.duration);&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Or, example 2: Match the duration to a Dojo animation&lt;br /&gt;
    var anim = dojo.fx.combine([&lt;br /&gt;
        ...&lt;br /&gt;
    ]);&lt;br /&gt;
    anim.play();&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(anim.duration);&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pre-defined notification types ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tableWindow&#039;&#039;&#039; - This defines notification to display [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialogs]], see below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;message&#039;&#039;&#039; - This defines notification that shows on players log and have no other effect&lt;br /&gt;
&lt;br /&gt;
   // You can call this on php side without doing anything on client side&lt;br /&gt;
    self::notifyAllPlayers( &#039;message&#039;, &#039;hello&#039;, [] );&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;simplePause&#039;&#039;&#039; - This notification will just delay other notifications, maybe useful if you know you need some extra time for animation or something. Requires a time parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    self::notifyAllPlayers( &#039;simplePause&#039;, &#039;&#039;, [ &#039;time&#039; =&amp;gt; 500] ); // time is in milliseconds&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tooltips ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltip( nodeId, _( helpString ), _( actionString ), delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to the DOM node.&lt;br /&gt;
&lt;br /&gt;
Specify &#039;helpString&#039; to display some information about &amp;quot;what is this game element?&amp;quot;.&lt;br /&gt;
Specify &#039;actionString&#039; to display some information about &amp;quot;what happens when I click on this element?&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You must specify both helpString and actionString. Most of the time, you should use only one and specify a void string (&amp;quot;&amp;quot;) for the other one.&lt;br /&gt;
&lt;br /&gt;
Usually, _() must be used for the text to be marked for translation.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Delay&amp;quot; is an optional parameter. Usually, it is primarily used to specify a zero delay for some game element when the tooltip gives really important information for the game - but remember: no essential information must be placed in tooltips as they won&#039;t be displayed in some browsers (see [[BGA_Studio_Guidelines|Guidelines]]).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.addTooltip( &#039;cardcount&#039;, _(&#039;Number of cards in hand&#039;), &#039;&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipHtml( nodeId, html, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to the DOM node (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipToClass( cssClass, _( helpString ), _( actionString ), delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to all the DOM nodes set with this cssClass. &lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.addTooltipHtmlToClass( cssClass, html, delay )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to to all the DOM nodes set with this cssClass (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must have IDs to get tooltips&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.removeTooltip( nodeId )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove a tooltip from the DOM node.&lt;br /&gt;
&lt;br /&gt;
== Dialogs, warning messages, confirmation dialogs, ... ==&lt;br /&gt;
&lt;br /&gt;
=== Warning messages ===&lt;br /&gt;
&lt;br /&gt;
Sometimes, there is something important that is happening on the game and you have to make sure all players get the message. Most of the time, the evolution of the game situation or the game log is enough, but sometimes you need something more visible.&lt;br /&gt;
&lt;br /&gt;
Ex: someone fulfill one of the end of the game condition, so this is the last turn.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.showMessage( msg, type )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
showMessage shows a message in a big rectangular area on the top of the screen of current player.&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;msg&amp;quot; is the string to display. It should be translated.&lt;br /&gt;
* &amp;quot;type&amp;quot; can be set to &amp;quot;info&amp;quot; or &amp;quot;error&amp;quot;. If set to &amp;quot;info&amp;quot;, the message will be an informative message on a white background. If set to &amp;quot;error&amp;quot;, the message will be an error message on a red background.&lt;br /&gt;
&lt;br /&gt;
Important: the normal way to inform players about the progression of the game is the game log. &amp;quot;showMessage&amp;quot; is intrusive and should not be used often.&lt;br /&gt;
&lt;br /&gt;
=== Confirmation dialog ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;confirmationDialog( message, yesHandler, noHandler )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When an important action with a lot of consequences is triggered by the player, you may want to propose a confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the general guidelines of BGA is to AVOID the use of confirmation dialog. Confirmation dialogs slow down the game and bother players. The players knows that they have to pay attention about each move when they are playing online.&lt;br /&gt;
&lt;br /&gt;
The situation where you should use a confirmation dialog are the following:&lt;br /&gt;
* It must not happen very often during a game.&lt;br /&gt;
* It must be linked to an action that can really &amp;quot;kill a game&amp;quot; if the player do not pay attention.&lt;br /&gt;
* It must be something that can be done by mistake (ex: a link on the action status bar).&lt;br /&gt;
&lt;br /&gt;
How to display a confirmation dialog:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to bake the pie?&#039;), dojo.hitch( this, function() {&lt;br /&gt;
            this.bakeThePie();&lt;br /&gt;
        } ) ); &lt;br /&gt;
        return; // nothing should be called or done after calling this, all action must be done in the handler  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Multiple choice dialog ===&lt;br /&gt;
You can use this dialog to give user a choice with small amount of options:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        var keys = [1,5,10];&lt;br /&gt;
        this.multipleChoiceDialog(&lt;br /&gt;
          _(&#039;How many bugs to fix?&#039;), keys, &lt;br /&gt;
            dojo.hitch(this, function(choice) {&lt;br /&gt;
                            var bugchoice = keys[choice];&lt;br /&gt;
                            console.log(&#039;dialog callback with &#039;+bugchoice);&lt;br /&gt;
                            this.ajaxcall( &#039;/mygame/mygame/fixBugs.html&#039;, { bugs: bugchoice}, this, function( result ) {} );                        }));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dialogs ===&lt;br /&gt;
&lt;br /&gt;
As a general rule, you shouldn&#039;t use dialogs windows.&lt;br /&gt;
&lt;br /&gt;
BGA guidelines specify that all game elements should be displayed on the main screen. Players can eventually scroll down to see game elements they don&#039;t need to see anytime, and you may eventually create anchors to move between game area section. Of course dialogs windows are very practical, but the thing is: all players know how to scroll down, and not all players know how to show up your dialog window. In addition, when the dialog shows up, players can&#039;t access the other game components.&lt;br /&gt;
&lt;br /&gt;
Sometimes although, you need to display a dialog window. Here is how you do this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  // Create the new dialog over the play zone. You should store the handler in a member variable to access it later&lt;br /&gt;
  this.myDlg = new ebg.popindialog();&lt;br /&gt;
  this.myDlg.create( &#039;myDialogUniqueId&#039; );&lt;br /&gt;
  this.myDlg.setTitle( _(&amp;quot;my dialog title to translate&amp;quot;) );&lt;br /&gt;
  this.myDlg.setMaxWidth( 500 ); // Optional&lt;br /&gt;
  &lt;br /&gt;
  // Create the HTML of my dialog. &lt;br /&gt;
  // The best practice here is to use [[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&lt;br /&gt;
  var html = this.format_block( &#039;jstpl_myDialogTemplate&#039;, { &lt;br /&gt;
                arg1: myArg1,&lt;br /&gt;
                arg2: myArg2,&lt;br /&gt;
                ...&lt;br /&gt;
            } );  &lt;br /&gt;
  &lt;br /&gt;
  // Show the dialog&lt;br /&gt;
  this.myDlg.setContent( html ); // Must be set before calling show() so that the size of the content is defined before positioning the dialog&lt;br /&gt;
  this.myDlg.show();&lt;br /&gt;
  &lt;br /&gt;
  // Now that the dialog has been displayed, you can connect your method to some dialog elements&lt;br /&gt;
  // Example, if you have an &amp;quot;OK&amp;quot; button in the HTML of your dialog:&lt;br /&gt;
  dojo.connect( $(&#039;my_ok_button&#039;), &#039;onclick&#039;, this, function(evt){&lt;br /&gt;
                evt.preventDefault();&lt;br /&gt;
                this.myDlg.destroy();&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
If necessary, you can remove the default top right corner &#039;close&#039; icon, or replace the function called when it is clicked:&lt;br /&gt;
  // Removes the default close icon&lt;br /&gt;
  this.myDlg.hideCloseIcon();&lt;br /&gt;
&lt;br /&gt;
  // Replace the function call when it&#039;s clicked&lt;br /&gt;
  this.myDlg.replaceCloseCallback( function() { ... } );&lt;br /&gt;
&lt;br /&gt;
=== Scoring dialogs ===&lt;br /&gt;
&lt;br /&gt;
Sometimes at the end of a round you want to display a big table that details the points wins in each section of the game.&lt;br /&gt;
&lt;br /&gt;
Example: in Hearts game, we display at the end of each round the number of &amp;quot;heart&amp;quot; cards collected by each player, the player who collected the Queen of Spades, and the total number of points loose by each player.&lt;br /&gt;
&lt;br /&gt;
Scoring dialogs are managed entirely on &#039;&#039;&#039;PHP side&#039;&#039;&#039;, but they are described here as their effects are visible only on client side.&lt;br /&gt;
&lt;br /&gt;
Displaying a scoring dialog is quite simple and is using a special notification type: &amp;quot;tableWindow&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // on PHP side:&lt;br /&gt;
  $this-&amp;gt;notifyAllPlayers( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table&lt;br /&gt;
        ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;table&amp;quot; argument is a 2 dimensional PHP array that describe the table you want to display, line by line and column by column.&lt;br /&gt;
&lt;br /&gt;
Example: display an 3x3 array of strings&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = array(&lt;br /&gt;
      array( &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, &amp;quot;three&amp;quot; ),    // This is my first line&lt;br /&gt;
      array( &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ),    // This is my second line&lt;br /&gt;
      array( &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; )    // This is my third line&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see above, in each &amp;quot;cell&amp;quot; of your array you can display a simple string value. But you can also display a complex value with a template and associated arguments like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = array(&lt;br /&gt;
      array( &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, array( &amp;quot;str&amp;quot; =&amp;gt; clienttranslate(&amp;quot;a string with an ${argument}&amp;quot;), &amp;quot;args&amp;quot; =&amp;gt; array( &#039;argument&#039; =&amp;gt; &#039;argument_value&#039; )  ) ),&lt;br /&gt;
      array( &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ), &lt;br /&gt;
      array( &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; )&lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is especially useful when you want to display player names with colors. Example from &amp;quot;Hearts&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $firstRow = array( &#039;&#039; );&lt;br /&gt;
        foreach( $players as $player_id =&amp;gt; $player )&lt;br /&gt;
        {&lt;br /&gt;
            $firstRow[] = array( &#039;str&#039; =&amp;gt; &#039;${player_name}&#039;,&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; array( &#039;player_name&#039; =&amp;gt; $player[&#039;player_name&#039;] ),&lt;br /&gt;
                                 &#039;type&#039; =&amp;gt; &#039;header&#039;&lt;br /&gt;
                               );&lt;br /&gt;
        }&lt;br /&gt;
        $table[] = $firstRow;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use three extra attributes in the parameter array for the notification:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $this-&amp;gt;notifyAllPlayers( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table,&lt;br /&gt;
            &amp;quot;header&amp;quot; =&amp;gt; array(&#039;str&#039; =&amp;gt; clienttranslate(&#039;Table header with parameter ${number}&#039;),&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; array( &#039;number&#039; =&amp;gt; 3 ),&lt;br /&gt;
                               ),&lt;br /&gt;
            &amp;quot;footer&amp;quot; =&amp;gt; &#039;&amp;lt;div&amp;gt;Some footer&amp;lt;/div&amp;gt;&#039;,&lt;br /&gt;
            &amp;quot;closing&amp;quot; =&amp;gt; clienttranslate( &amp;quot;Closing button label&amp;quot; )&lt;br /&gt;
        ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*&#039;&#039;&#039;header&#039;&#039;&#039;: the content for this parameter will display before the table (also, the html will be parsed and player names will be colored according to the current game colors). &lt;br /&gt;
*&#039;&#039;&#039;footer&#039;&#039;&#039;: the content for this parameter will display after the table (no parsing for coloring the player names)&lt;br /&gt;
*&#039;&#039;&#039;closing&#039;&#039;&#039;: if this parameter is used, a button will be displayed with this label at the bottom of the popup and will allow players to close it (more easily than by clicking the top right &#039;cross&#039; icon).&lt;br /&gt;
&lt;br /&gt;
=== Scoring animated display ===&lt;br /&gt;
&lt;br /&gt;
Sometimes (Terra Mystica final scoring for example), you may want to display a score value over an element to make the scoring easier to follow for the players.&lt;br /&gt;
You can do it with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.displayScoring( anchor_id, color, score, duration, offset_x, offset_y );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;anchor_id&#039;&#039;&#039;: ID of the element to place the animated score onto (without the &#039;#&#039;) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;color&#039;&#039;&#039;: hexadecimal RGB representation of the color (should be the color of the scoring player), but without a leading &#039;#&#039;.  For instance, &#039;ff0000&#039; for red.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;score&#039;&#039;&#039;: numeric score to display, prefixed by a &#039;+&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;duration&#039;&#039;&#039;: animation duration in milliseconds&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;offset_x&#039;&#039;&#039; and &#039;&#039;&#039;offset_y&#039;&#039;&#039;: if both offset_x and offset_y are defined and not null, apply the following offset (in pixels) to the scoring animation&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: if you want to display successively each score, you can use &#039;&#039;this.notifqueue.setSynchronous()&#039;&#039; function.&lt;br /&gt;
&lt;br /&gt;
=== Speech bubble ===&lt;br /&gt;
&lt;br /&gt;
For better interactivity in some games (Love Letter for example), you may use comic book style speech bubbles to express the players voices.&lt;br /&gt;
This is done with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.showBubble(anchor_id, text, delay, duration, custom_class)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
text - what to put in bubble, can be html actually not just text&lt;br /&gt;
&lt;br /&gt;
delay - in milliseconds is optional (default 0)&lt;br /&gt;
&lt;br /&gt;
duration -  in milliseconds is optional (default 3000)&lt;br /&gt;
&lt;br /&gt;
custom_class - extra class to add to bubble is optional, if you need to override the default bubble style&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: if your bubble could overlap other active elements of the interface (buttons in particular), as it stays in place even after disappearing, you should use a custom class to give it the style &amp;quot;pointer-events: none;&amp;quot; in order to intercept click events.&lt;br /&gt;
&lt;br /&gt;
Note: If you want this visually, but want to take complete control over this bubble and its animation (for example to make it permanent) you can just use div with &#039;discussion_bubble&#039; class on it, and content of div is what will be shown.&lt;br /&gt;
&lt;br /&gt;
== Update players score ==&lt;br /&gt;
&lt;br /&gt;
The column player_score from the player table is automatically loaded into this.scoreCtrl and therefore into the stars location on the player board. This occurs sometime after the &amp;lt;gamename&amp;gt;.js setup() function. However this score must be updated as the game progresses through player notifications (notifs).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Increase a player score (with a positive or negative number):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].incValue( score_delta );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set a player score to a specific value:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].setValue( new_score );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set a player score to a specific value with animation :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  this.scoreCtrl[ player_id ].toValue( new_score );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typical usage would be (that will process &#039;score&#039; notification):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setupNotifications : function() {&lt;br /&gt;
              ...&lt;br /&gt;
             dojo.subscribe(&#039;score&#039;, this, &amp;quot;notif_score&amp;quot;);&lt;br /&gt;
        },&lt;br /&gt;
        notif_score: function(notif) {&lt;br /&gt;
            this.scoreCtrl[notif.args.player_id].setValue(notif.args.player_score);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Players panels ==&lt;br /&gt;
&lt;br /&gt;
=== Adding stuff to player&#039;s panel ===&lt;br /&gt;
&lt;br /&gt;
At first, create a new &amp;quot;JS template&amp;quot; string in your template (tpl) file:&lt;br /&gt;
&lt;br /&gt;
(from Gomoku example)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var jstpl_player_board = &#039;\&amp;lt;div class=&amp;quot;cp_board&amp;quot;&amp;gt;\&lt;br /&gt;
    &amp;lt;div id=&amp;quot;stoneicon_p${id}&amp;quot; class=&amp;quot;gmk_stoneicon gmk_stoneicon_${color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;span id=&amp;quot;stonecount_p${id}&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;\&lt;br /&gt;
&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, you add this piece of code in your JS file to add this template to each player panel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Setting up player boards&lt;br /&gt;
            for( var player_id in gamedatas.players )&lt;br /&gt;
            {&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                         &lt;br /&gt;
                // Setting up players boards if needed&lt;br /&gt;
                var player_board_div = $(&#039;player_board_&#039;+player_id);&lt;br /&gt;
                dojo.place( this.format_block(&#039;jstpl_player_board&#039;, player ), player_board_div );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Note: the code above is of course from your &amp;quot;setup&amp;quot; function in your Javascript).&lt;br /&gt;
&lt;br /&gt;
Very often, you have to distinguish current player and others players. In this case, you just have to create another JS template (ex: jstpl_otherplayer_board) and use it when &amp;quot;player_id&amp;quot; is different than &amp;quot;this.player_id&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s panel disabling/enabling ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.disablePlayerPanel( player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disable given player panel (the panel background become gray).&lt;br /&gt;
&lt;br /&gt;
Usually, this is used to signal that this played passes, or will be inactive during a while.&lt;br /&gt;
&lt;br /&gt;
Note that the only effect of this is visual. There are no consequences on the behaviour of the panel itself.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.enablePlayerPanel( player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable a player panel that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.enableAllPlayerPanels()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable all player panels that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
== Image loading ==&lt;br /&gt;
&lt;br /&gt;
See also [[Game_art:_img_directory]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Be careful&#039;&#039;&#039;: by default, ALL images of your img directory are loaded on a player&#039;s browser when he loads the game. For this reason, don&#039;t let in your img directory images that are not useful, otherwise it&#039;s going to slowdown the game load.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dontPreloadImage( image_file_name )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using dontPreloadImage, you tell the interface to not preload a specific image in your img directory.&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is particularly useful if for example you have 2 different themes for a game. To accelerate the loading of the game, you can specify to not preload images corresponding to the other theme.&lt;br /&gt;
&lt;br /&gt;
Another example of use: in &amp;quot;Gosu&amp;quot; game with Kamakor extension, you play with 5 sets of cards among 10 available. Cards images are organized by sets, and we only preload the images corresponding to the 5 current sets with &#039;&#039;&#039;ensureSpecificGameImageLoading( image_file_names_array )&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// By default, do not preload anything&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan1.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan2.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan3.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan4.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan5.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan6.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan7.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan8.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan9.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan10.png&#039; );&lt;br /&gt;
var to_preload = [];&lt;br /&gt;
for( i in this.gamedatas.clans )&lt;br /&gt;
{&lt;br /&gt;
	var clan_id = this.gamedatas.clans[i];&lt;br /&gt;
	to_preload.push( &#039;clan&#039;+clan_id+&#039;.png&#039; );&lt;br /&gt;
}&lt;br /&gt;
if( to_preload.length == 5 )&lt;br /&gt;
{&lt;br /&gt;
	this.ensureSpecificGameImageLoading( to_preload );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; You don&#039;t need to specify to not preload game box images (game_box.png, game_box75.png...) since they are not preloaded by default.&lt;br /&gt;
&lt;br /&gt;
== Other useful stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.hitch&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.hitch, you can create a callback function that will run with your game object context whatever happen.&lt;br /&gt;
&lt;br /&gt;
Typical example: display a BGA confirmation dialog with a callback function created with dojo.hitch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), dojo.hitch( this, function() {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, function( result ) {} );&lt;br /&gt;
        } ) );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, using dojo.hitch, we ensure that the &amp;quot;this&amp;quot; object will be set when the callback is called.&lt;br /&gt;
&lt;br /&gt;
NOTE: In modern JS there are lambdas that eliminate need for that, the example above will look like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), () =&amp;gt; {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, (result) =&amp;gt; {} );&lt;br /&gt;
        } );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; updateCounters(counters)&lt;br /&gt;
: Useful for updating game counters in the player panel (such as resources). &lt;br /&gt;
: &#039;counters&#039; arg is an associative array [counter_name_value =&amp;gt; [ &#039;counter_name&#039; =&amp;gt; counter_name_value, &#039;counter_value&#039; =&amp;gt; counter_value_value], ... ]&lt;br /&gt;
: All counters must be referenced in this.gamedatas.counters and will be updated.&lt;br /&gt;
: DOM objects referenced by &#039;counter_name&#039; will have their innerHTML updated with &#039;counter_value&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;onScreenWidthChange()&#039;&#039;&#039;&lt;br /&gt;
:This function can be overridden in your game to manage some resizing on the client side when the browser window is resized. This function is also triggered at load time, so it can be used to adapt to the :viewport size at the start of the game too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;updatePageTitle()&#039;&#039;&#039;&lt;br /&gt;
:This function allows to update the current page title and turn description according to the game state. If the current game state description this.gamedatas.gamestate.descriptionmyturn is modified before :calling the function, it allows to update the turn description without changing state.&lt;br /&gt;
&lt;br /&gt;
Example from Terra Mystica:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onClickFavorTile: function( evt ) {&lt;br /&gt;
    ...&lt;br /&gt;
    if ( ... ) {&lt;br /&gt;
        this.gamedatas.gamestate.descriptionmyturn = _(&#039;Special action: &#039;) + _(&#039;Advance 1 space	on a Cult track&#039;);&lt;br /&gt;
        this.updatePageTitle();&lt;br /&gt;
        this.removeActionButtons();&lt;br /&gt;
        this.addActionButton( ... );&lt;br /&gt;
         ...&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA GUI components ==&lt;br /&gt;
&lt;br /&gt;
BGA framework provides some useful ready-to-use components for the game interface:&lt;br /&gt;
&lt;br /&gt;
[[Studio#BGA_Studio_game_components_reference]]&lt;br /&gt;
&lt;br /&gt;
Note that each time you are using an additional component, you must declare it at the top of your Javascript file in the list of modules used.&lt;br /&gt;
&lt;br /&gt;
Example if you are using &amp;quot;ebg.stock&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;  /// &amp;lt;=== we are using ebg.stock module&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA Buttons ==&lt;br /&gt;
&lt;br /&gt;
You can create a custom button, but the BGA framework provides a standard button that requires only .css classes: &#039;&#039;&#039;bgabutton&#039;&#039;&#039; and &#039;&#039;&#039;bgabutton_${color}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_blue&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My blue button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_gray&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My gray button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_red&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My red button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_red bgabutton_big&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My big red button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: To see it in action, check out &#039;&#039;Coloretto&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Sounds ==&lt;br /&gt;
&lt;br /&gt;
Add a custom sound and make it load with your interface:&lt;br /&gt;
&lt;br /&gt;
Add this in your template (.tpl) file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.mp3&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_o_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.ogg&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this is a requirement to provide both a mp3 and a ogg file.&lt;br /&gt;
&lt;br /&gt;
Play the sound (from your .js file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            playSound(&#039;&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&#039;);             &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the standard &amp;quot;move&amp;quot; sound for this move (to replace it with your custom sound):&lt;br /&gt;
&lt;br /&gt;
Add this to your notification handler:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            this.disableNextMoveSound();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: it only disable the sound for the next move.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=7564</id>
		<title>Main game logic: Game.php</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=7564"/>
		<updated>2021-03-06T15:23:27Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Only &amp;quot;winners&amp;quot; and &amp;quot;losers&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This is the main file for your game logic. Here you initialize the game, persist data, implement the rules and notify the client interface of changes.&lt;br /&gt;
&lt;br /&gt;
== File Structure ==&lt;br /&gt;
&lt;br /&gt;
The details of how the file is structured are described directly with comments in the code skeleton provided to you.&lt;br /&gt;
 &lt;br /&gt;
Here is the basic structure:&lt;br /&gt;
&lt;br /&gt;
* Constructor: where you define global variables.&lt;br /&gt;
* setupNewGame: initial setup of the game. Takes an array of players, indexed by player_id. Structure of each player includes player_name, player_canal, player_avatar, and flags indicating admin/ai/premium/order/language/beginner.&lt;br /&gt;
* getAllDatas: where you retrieve all game data during a complete reload of the game. Returned value must include [&#039;players&#039;][playerId][&#039;score&#039;] for scores to populate when F5 is pressed.&lt;br /&gt;
* getGameProgression: where you compute the game progression indicator.&lt;br /&gt;
* Utility functions: your utility functions.&lt;br /&gt;
* Player actions: the entry points for players actions. &lt;br /&gt;
* Game state arguments: methods to return additional data on specific game states ([http://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php#args more info here]).&lt;br /&gt;
* Game state actions: the logic to run when entering a new game state ([http://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php#action more info here]).&lt;br /&gt;
* zombieTurn: what to do it&#039;s the turn of a zombie player.&lt;br /&gt;
* upgradeTableDb: function to migrate database if you change it after release on production.&lt;br /&gt;
&lt;br /&gt;
== Accessing player information ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: In the following methods, be mindful of the difference between the &amp;quot;active&amp;quot; player and the &amp;quot;current&amp;quot; player. The &#039;&#039;&#039;active&#039;&#039;&#039; player is the player whose turn it is - not necessarily the player who sent a request! The &#039;&#039;&#039;current&#039;&#039;&#039; player is the player who sent the request and will see the results returned by your methods: not necessarily the player whose turn it is!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; getPlayersNumber()&lt;br /&gt;
: Returns the number of players playing at the table&lt;br /&gt;
: Note: doesn&#039;t work in setupNewGame (use count($players) instead).&lt;br /&gt;
&lt;br /&gt;
; getActivePlayerId()&lt;br /&gt;
: Get the &amp;quot;active_player&amp;quot;, whatever what is the current state type.&lt;br /&gt;
: Note: it does NOT mean that this player is active right now, because state type could be &amp;quot;game&amp;quot; or &amp;quot;multiplayer&amp;quot;&lt;br /&gt;
: Note: avoid using this method in a &amp;quot;multiplayer&amp;quot; state because it does not mean anything.&lt;br /&gt;
&lt;br /&gt;
; getActivePlayerName()&lt;br /&gt;
: Get the &amp;quot;active_player&amp;quot; name&lt;br /&gt;
: Note: avoid using this method in a &amp;quot;multiplayer&amp;quot; state because it does not mean anything.&lt;br /&gt;
&lt;br /&gt;
; loadPlayersBasicInfos()&lt;br /&gt;
: Get an associative array with generic data about players (ie: not game specific data).&lt;br /&gt;
: The key of the associative array is the player id. The returned table is cached, so ok to call multiple times without performance concerns.&lt;br /&gt;
: The content of each value is:&lt;br /&gt;
: * player_name - the name of the player&lt;br /&gt;
: * player_color (ex: ff0000) - the color code of the player&lt;br /&gt;
: * player_no - the position of the player at the start of the game in natural table order, i.e. 1,2,3&lt;br /&gt;
&lt;br /&gt;
; getCurrentPlayerId()&lt;br /&gt;
: Get the &amp;quot;current_player&amp;quot;. The current player is the one from which the action originated (the one who sent the request).&lt;br /&gt;
: &#039;&#039;&#039;Be careful&#039;&#039;&#039;: This is not necessarily the active player!&lt;br /&gt;
: In general, you shouldn&#039;t use this method, unless you are in &amp;quot;multiplayer&amp;quot; state.&lt;br /&gt;
: &#039;&#039;&#039;Very important&#039;&#039;&#039;: in your setupNewGame and zombieTurn function, you must never use getCurrentPlayerId() or getCurrentPlayerName(), otherwise it will fail with a &amp;quot;Not logged&amp;quot; error message (these actions are triggered from the main site and propagated to the gameserver from a server, not from a browser. As a consequence, there is no current player associated to these actions).&lt;br /&gt;
&lt;br /&gt;
; getCurrentPlayerName()&lt;br /&gt;
: Get the &amp;quot;current_player&amp;quot; name&lt;br /&gt;
: Be careful using this method (see above).&lt;br /&gt;
&lt;br /&gt;
; getCurrentPlayerColor()&lt;br /&gt;
: Get the &amp;quot;current_player&amp;quot; color&lt;br /&gt;
: Be careful using this method (see above).&lt;br /&gt;
&lt;br /&gt;
; isCurrentPlayerZombie()&lt;br /&gt;
: Check the &amp;quot;current_player&amp;quot; zombie status. If true, player is zombie, i.e. left or was kicked out of the game.&lt;br /&gt;
&lt;br /&gt;
; getActivePlayerColor()&lt;br /&gt;
: This function does not seems to exist in API, if you need it here is implementation&lt;br /&gt;
      function getActivePlayerColor() {&lt;br /&gt;
        $player_id = self::getActivePlayerId();&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        if( isset( $players[ $player_id ]) )&lt;br /&gt;
            return $players[ $player_id ][&#039;player_color&#039;];&lt;br /&gt;
        else&lt;br /&gt;
            return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Accessing the database ==&lt;br /&gt;
&lt;br /&gt;
The main game logic should be the only point from which you should access the game database. You access your database using SQL queries with the methods below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
BGA uses [http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html database transactions]. This means that your database changes WON&#039;T BE APPLIED to the database until your request ends normally (web request, not database request). Using transactions is in fact very useful for you; at any time, if your game logic detects that something is wrong (example: a disallowed move), you just have to throw an exception and all changes to the game situation will be removed. This also means that you need not (and in fact cannot) use your own transactions for multiple related database operations.&lt;br /&gt;
&lt;br /&gt;
; DbQuery( $sql )&lt;br /&gt;
: This is the generic method to access the database.&lt;br /&gt;
: It can execute any type of SELECT/UPDATE/DELETE/REPLACE/INSERT query on the database.&lt;br /&gt;
: You should use it for UPDATE/DELETE/REPLACE/INSERT queries. For SELECT queries, the specialized methods below are much better.&lt;br /&gt;
&lt;br /&gt;
; getUniqueValueFromDB( $sql )&lt;br /&gt;
: Returns a unique value from DB or null if no value is found.&lt;br /&gt;
: $sql must be a SELECT query.&lt;br /&gt;
: Raise an exception if more than 1 row is returned.&lt;br /&gt;
&lt;br /&gt;
; getCollectionFromDB( $sql, $bSingleValue=false )&lt;br /&gt;
: Returns an associative array of rows for a sql SELECT query.&lt;br /&gt;
: The key of the resulting associative array is the first field specified in the SELECT query.&lt;br /&gt;
: The value of the resulting associative array is an associative array with all the field specified in the SELECT query and associated values.&lt;br /&gt;
: First column must be a primary or alternate key.&lt;br /&gt;
: The resulting collection can be empty.&lt;br /&gt;
: If you specified $bSingleValue=true and if your SQL query request 2 fields A and B, the method returns an associative array &amp;quot;A=&amp;gt;B&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example 1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
self::getCollectionFromDB( &amp;quot;SELECT player_id id, player_name name, player_score score FROM player&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
array(&lt;br /&gt;
 1234 =&amp;gt; array( &#039;id&#039;=&amp;gt;1234, &#039;name&#039;=&amp;gt;&#039;myuser0&#039;, &#039;score&#039;=&amp;gt;1 ),&lt;br /&gt;
 1235 =&amp;gt; array( &#039;id&#039;=&amp;gt;1235, &#039;name&#039;=&amp;gt;&#039;myuser1&#039;, &#039;score&#039;=&amp;gt;0 )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example 2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
self::getCollectionFromDB( &amp;quot;SELECT player_id id, player_name name FROM player&amp;quot;, true );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
array(&lt;br /&gt;
 1234 =&amp;gt; &#039;myuser0&#039;,&lt;br /&gt;
 1235 =&amp;gt; &#039;myuser1&#039;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; getNonEmptyCollectionFromDB( $sql )&lt;br /&gt;
: Same as getCollectionFromDB($sdl), but raise an exception if the collection is empty. Note: this function does NOT have 2nd argument as previous one does.&lt;br /&gt;
&lt;br /&gt;
; getObjectFromDB( $sql )&lt;br /&gt;
: Returns one row for the sql SELECT query as an associative array or null if there is no result&lt;br /&gt;
: Raise an exception if the query return more than one row&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
self::getObjectFromDB( &amp;quot;SELECT player_id id, player_name name, player_score score FROM player WHERE player_id=&#039;$player_id&#039;&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
array(&lt;br /&gt;
  &#039;id&#039;=&amp;gt;1234, &#039;name&#039;=&amp;gt;&#039;myuser0&#039;, &#039;score&#039;=&amp;gt;1 &lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; getNonEmptyObjectFromDB( $sql )&lt;br /&gt;
: Similar to previous one, but raise an exception if no row is found&lt;br /&gt;
&lt;br /&gt;
; getObjectListFromDB( $sql, $bUniqueValue=false )&lt;br /&gt;
: Return an array of rows for a sql SELECT query.&lt;br /&gt;
: The result is the same than &amp;quot;getCollectionFromDB&amp;quot; except that the result is a simple array (and not an associative array).&lt;br /&gt;
: The result can be empty.&lt;br /&gt;
: If you specified $bUniqueValue=true and if your SQL query request 1 field, the method returns directly an array of values.&lt;br /&gt;
&lt;br /&gt;
Example 1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
self::getObjectListFromDB( &amp;quot;SELECT player_id id, player_name name, player_score score FROM player&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
array(&lt;br /&gt;
 array( &#039;id&#039;=&amp;gt;1234, &#039;name&#039;=&amp;gt;&#039;myuser0&#039;, &#039;score&#039;=&amp;gt;1 ),&lt;br /&gt;
 array( &#039;id&#039;=&amp;gt;1235, &#039;name&#039;=&amp;gt;&#039;myuser1&#039;, &#039;score&#039;=&amp;gt;0 )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example 2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
self::getObjectListFromDB( &amp;quot;SELECT player_name name FROM player&amp;quot;, true );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
array(&lt;br /&gt;
 &#039;myuser0&#039;,&lt;br /&gt;
 &#039;myuser1&#039;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; getDoubleKeyCollectionFromDB( $sql, $bSingleValue=false )&lt;br /&gt;
: Return an associative array of associative array, from a SQL SELECT query.&lt;br /&gt;
: First array level correspond to first column specified in SQL query.&lt;br /&gt;
: Second array level correspond to second column specified in SQL query.&lt;br /&gt;
: If bSingleValue = true, keep only third column on result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; DbGetLastId()&lt;br /&gt;
: Return the PRIMARY key of the last inserted row (see PHP mysql_insert_id function).&lt;br /&gt;
&lt;br /&gt;
; DbAffectedRow()&lt;br /&gt;
: Return the number of row affected by the last operation&lt;br /&gt;
&lt;br /&gt;
; escapeStringForDB( $string )&lt;br /&gt;
: You must use this function on every string type data in your database that contains unsafe data.&lt;br /&gt;
: (unsafe = can be modified by a player).&lt;br /&gt;
: This method makes sure that no SQL injection will be done through the string used.&lt;br /&gt;
: Note: if you using standard types in ajax actions, like AT_alphanum it is sanitized before arrival,&lt;br /&gt;
: this is only needed if you manage to get unchecked string, like in the games where user has to enter text as a response.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: see Editing [[Game database model: dbmodel.sql]] to know how to define your database model.&lt;br /&gt;
&lt;br /&gt;
== Use globals ==&lt;br /&gt;
&lt;br /&gt;
Sometimes, you want a single global integer value for your game, and you don&#039;t want to create a DB table specifically for it.&lt;br /&gt;
&lt;br /&gt;
You can do this with the BGA framework &amp;quot;global.&amp;quot; Your value will be stored in the &amp;quot;global&amp;quot; table in the database, and you can access it with simple methods.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;initGameStateLabels&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method should be located at the beginning of &#039;&#039;yourgamename.php.&#039;&#039; This is where you define the globals used in your game logic, by assigning them IDs.&lt;br /&gt;
&lt;br /&gt;
You can define up to 80 globals, with IDs from 10 to 89 (inclusive). You must &#039;&#039;&#039;not&#039;&#039;&#039; use globals outside this range, as those values are used by other components of the framework.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        self::initGameStateLabels( array( &lt;br /&gt;
                &amp;quot;my_first_global_variable&amp;quot; =&amp;gt; 10,&lt;br /&gt;
                &amp;quot;my_second_global_variable&amp;quot; =&amp;gt; 11&lt;br /&gt;
        ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setGameStateInitialValue( $value_label, $value_value )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Initialize your global value. Must be called before any use of your global, so you should call this method from your &amp;quot;setupNewGame&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getGameStateValue( $value_label )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Retrieve the current value of a global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setGameStateValue( $value_label, $value_value )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Set the current value of a global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;incGameStateValue( $value_label, $increment )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Increment the current value of a global. If increment is negative, decrement the value of the global.&lt;br /&gt;
&lt;br /&gt;
Return the final value of the global.&lt;br /&gt;
&lt;br /&gt;
== Game states and active players ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Activate player handling ===&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;activeNextPlayer()&lt;br /&gt;
: Make the next player active in the natural player order.&lt;br /&gt;
: Note: you CANNOT use this method in a &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot; state. You must use a &amp;quot;game&amp;quot; type game state for this.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;activePrevPlayer()&lt;br /&gt;
: Make the previous player active (in the natural player order).&lt;br /&gt;
: Note: you CANNOT use this method in a &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot; state. You must use a &amp;quot;game&amp;quot; type game state for this.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer( $player_id )&lt;br /&gt;
: You can call this method to make any player active.&lt;br /&gt;
: Note: you CANNOT use this method in a &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot; state. You must use a &amp;quot;game&amp;quot; type game state for this.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;getActivePlayerId()&lt;br /&gt;
: Return the &amp;quot;active_player&amp;quot; id&lt;br /&gt;
: Note: it does NOT mean that this player is active right now, because state type could be &amp;quot;game&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot;&lt;br /&gt;
: Note: avoid using this method in a &amp;quot;multipleactiveplayer&amp;quot; state because it does not mean anything.&lt;br /&gt;
&lt;br /&gt;
=== Multiple activate player handling ===&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive()&lt;br /&gt;
: All playing players are made active. Update notification is sent to all players (this will trigger &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039;).&lt;br /&gt;
: Usually, you use this method at the beginning of a game state (e.g., &amp;quot;stGameState&amp;quot;) which transitions to a &#039;&#039;multipleactiveplayer&#039;&#039; state in which multiple players have to perform some action. Do not use this method if you going to make some more changes in the active player list. (I.e., if you want to take away multipleactiveplayer status immediately afterwards, use setPlayersMultiactive instead.)&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_MultiPlayerInit() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And this is the state declaration:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurnPlace&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Other player must place ships&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must place ships (click on YOUR SHIPS board to place)&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;multipleactiveplayer&amp;quot;,&lt;br /&gt;
                &#039;action&#039; =&amp;gt; &#039;multiPlayerDoSomething&#039;,&lt;br /&gt;
                &#039;args&#039; =&amp;gt; &#039;arg_playerTurnPlace&#039;,&lt;br /&gt;
    	     	&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;actionBla&amp;quot; ),&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;next&amp;quot; =&amp;gt; 4, &amp;quot;last&amp;quot; =&amp;gt; 99)&lt;br /&gt;
    ),&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setAllPlayersNonMultiactive( $next_state )&lt;br /&gt;
: All playing players are made inactive. Transition to next state&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive( $players, $next_state, $bExclusive = false )&lt;br /&gt;
: Make a specific list of players active during a multiactive gamestate. Update notification is sent to all players whose state changed.&lt;br /&gt;
: &amp;quot;players&amp;quot; is the array of player id that should be made active.&lt;br /&gt;
: If &amp;quot;exclusive&amp;quot; parameter is not set or false it doesn&#039;t deactivate other previously active players. If its set to true, the players who will be multiactive at the end are only these in &amp;quot;$players&amp;quot; array&lt;br /&gt;
&lt;br /&gt;
: In case &amp;quot;players&amp;quot; is empty, the method trigger the &amp;quot;next_state&amp;quot; transition to go to the next game state.&lt;br /&gt;
: returns true if state transition happened, false otherwise&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive( $player_id, $next_state )&lt;br /&gt;
: During a multiactive game state, make the specified player inactive.&lt;br /&gt;
: Usually, you call this method during a multiactive game state after a player did his action. It is also possible to call it directly from multiplayer action handler.&lt;br /&gt;
: If this player was the last active player, the method trigger the &amp;quot;next_state&amp;quot; transition to go to the next game state.&lt;br /&gt;
: returns true if state transition happened, false otherwise&lt;br /&gt;
Example of usage (see state declaration of playerTurnPlace above):&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function actionBla($args) {&lt;br /&gt;
        self::checkAction(&#039;actionBla&#039;);&lt;br /&gt;
        // handle the action using $this-&amp;gt;getCurrentPlayerId()&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive( $this-&amp;gt;getCurrentPlayerId(), &#039;next&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;getActivePlayerList()&lt;br /&gt;
: With this method you can retrieve the list of the active player at any time.&lt;br /&gt;
: During a &amp;quot;game&amp;quot; type gamestate, it will return a void array.&lt;br /&gt;
: During a &amp;quot;activeplayer&amp;quot; type gamestate, it will return an array with one value (the active player id).&lt;br /&gt;
: During a &amp;quot;multipleactiveplayer&amp;quot; type gamestate, it will return an array of the active players id.&lt;br /&gt;
: Note: you should only use this method in the latter case.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;  $this-&amp;gt;gamestate-&amp;gt;updateMultiactiveOrNextState( $next_state_if_none )&lt;br /&gt;
: Sends update notification about multiplayer changes. All multiactive set* functions above do that, however if you want to change state manually using db queries for complex calculations, you have to call this yourself after. Do not call this if you calling one of the other setters above.&lt;br /&gt;
Example: you have player teams and you want to activate all players in one team&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $sql = &amp;quot;UPDATE player SET player_is_multiactive=&#039;0&#039;&amp;quot;;&lt;br /&gt;
        self::DbQuery( $sql );&lt;br /&gt;
        $sql = &amp;quot;UPDATE player SET player_is_multiactive=&#039;1&#039; WHERE player_id=&#039;$player_id&#039; AND player_team=&#039;$team_no&#039;&amp;quot;;&lt;br /&gt;
        self::DbQuery( $sql );&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;updateMultiactiveOrNextState( &#039;error&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; updating database manually&lt;br /&gt;
: Use this helper function to change multiactive state without sending notification&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Changes values of multiactivity in db, does not sent notifications.&lt;br /&gt;
     * To send notifications after use updateMultiactiveOrNextState&lt;br /&gt;
     * @param number $player_id, player id &amp;lt;=0 or null - means ALL&lt;br /&gt;
     * @param number $value - 1 multiactive, 0 non multiactive&lt;br /&gt;
     */&lt;br /&gt;
    function dbSetPlayerMultiactive($player_id = -1, $value = 1) {&lt;br /&gt;
        if (! $value)&lt;br /&gt;
            $value = 0;&lt;br /&gt;
        else&lt;br /&gt;
            $value = 1;&lt;br /&gt;
        $sql = &amp;quot;UPDATE player SET player_is_multiactive = &#039;$value&#039; WHERE player_zombie = 0 and player_eliminated = 0&amp;quot;;&lt;br /&gt;
        if ($player_id &amp;gt; 0) {&lt;br /&gt;
            $sql .= &amp;quot; AND player_id = $player_id&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== States functions ===&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextState( $transition )&lt;br /&gt;
: Change current state to a new state. Important: the $transition parameter is the name of the transition, and NOT the name of the target game state, see [[Your game state machine: states.inc.php]] for more information about states.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;checkAction( $actionName, $bThrowException=true )&lt;br /&gt;
: Check if the current player can perform a specific action in the current game state, and optionally throw an exception if they can&#039;t.&lt;br /&gt;
: The action is valid if it is listed in the &amp;quot;possibleactions&amp;quot; array for the current game state (see game state description).&lt;br /&gt;
: This method MUST be the first one called in ALL your PHP methods that handle player actions, in order to make sure a player doesn&#039;t perform an action not allowed by the rules at the point in the game.  It should not be called from methods where the current player is not necessarily the active player, otherwise it may fail with an &amp;quot;It is not your turn&amp;quot; exception.&lt;br /&gt;
: If &amp;quot;bThrowException&amp;quot; is set to &amp;quot;false&amp;quot;, the function returns &#039;&#039;&#039;false&#039;&#039;&#039; in case of failure instead of throwing an exception. This is useful when several actions are possible, in order to test each of them without throwing exceptions.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction( $action )&lt;br /&gt;
: (rarely used)&lt;br /&gt;
: This works exactly like &amp;quot;checkAction&amp;quot; (above), except that it does NOT check if the current player is active.&lt;br /&gt;
: This is used specifically in certain game states when you want to authorize additional actions for players that are not active at the moment.&lt;br /&gt;
: Example: in &#039;&#039;Libertalia&#039;&#039;, you want to authorize players to change their mind about the card played. They are of course not active at the time they change their mind, so you cannot use &amp;quot;checkAction&amp;quot;; use &amp;quot;checkPossibleAction&amp;quot; instead.&lt;br /&gt;
&lt;br /&gt;
This is how PHP action looks that returns player to active state (only for multiplayeractive states). To be able to execute on js side do not checkAction on js side for this specific one.&lt;br /&gt;
&lt;br /&gt;
   function actionUnpass() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction(&#039;actionUnpass&#039;); // player chane mind about passing while others were thinking&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive(array ($this-&amp;gt;getCurrentPlayerId() ), &#039;error&#039;, false);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;state()&lt;br /&gt;
: Get an associative array of current game state attributes, see [[Your game state machine: states.inc.php]] for state attributes.&lt;br /&gt;
  $state=$this-&amp;gt;gamestate-&amp;gt;state(); if( $state[&#039;name&#039;] == &#039;myGameState&#039; ) {...}&lt;br /&gt;
&lt;br /&gt;
== Players turn order ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getNextPlayerTable()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return an associative array which associate each player with the next player around the table.&lt;br /&gt;
&lt;br /&gt;
In addition, key 0 is associated to the first player to play.&lt;br /&gt;
&lt;br /&gt;
Example: if three player with ID 1, 2 and 3 are around the table, in this order, the method returns:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   array( &lt;br /&gt;
    1 =&amp;gt; 2, &lt;br /&gt;
    2 =&amp;gt; 3, &lt;br /&gt;
    3 =&amp;gt; 1, &lt;br /&gt;
    0 =&amp;gt; 1 &lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getPrevPlayerTable()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as above, but the associative array associate the previous player around the table. However there no 0 index here.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getPlayerAfter( $player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get player playing after given player in natural playing order.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getPlayerBefore( $player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get player playing before given player in natural playing order.&lt;br /&gt;
&lt;br /&gt;
Note: There is no API to modify this order, if you have custom player order you have to maintain it in your database&lt;br /&gt;
and have custom function to access it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;createNextPlayerTable( $players, $bLoop=true )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using $players array creates a map of current =&amp;gt; next as in example from getNextPlayerTable(), however you can use custom order here. &lt;br /&gt;
Parmeter $bLoop is true if last player points to first, false otherwise.&lt;br /&gt;
In any case index 0 points to first player (first element of $players array). $players is array of player ids in desired order.&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function getNextPlayerTableCustom() {&lt;br /&gt;
        $starting = $this-&amp;gt;getStartingPlayer(); // custom function to get starting player&lt;br /&gt;
        $player_ids = $this-&amp;gt;getPlayerIdsInOrder($starting); // custom function to create players array starting from starting player&lt;br /&gt;
        return self::createNextPlayerTable($player_ids, false); // create next player table in custom order&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Notify players ==&lt;br /&gt;
&lt;br /&gt;
To understand notifications, please read [http://www.slideshare.net/boardgamearena/the-bga-framework-at-a-glance The BGA Framework at a glance] first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Notifications are sent at the very end of the request, when it ends normally. It means that if you throw an exception for any reason (ex: move not allowed), no notifications will be sent to players.&lt;br /&gt;
Notifications sent between the game start (setupNewGame) and the end of the &amp;quot;action&amp;quot; method of the first active state will never reach their destination.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;notifyAllPlayers( $notification_type, $notification_log, $notification_args )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Send a notification to all players of the game.&lt;br /&gt;
&lt;br /&gt;
* notification_type:&lt;br /&gt;
A string that defines the type of your notification.&lt;br /&gt;
&lt;br /&gt;
Your game interface Javascript logic will use this to know what is the type of the received notification (and to trigger the corresponding method).&lt;br /&gt;
&lt;br /&gt;
* notification_log:&lt;br /&gt;
A string that defines what is to be displayed in the game log.&lt;br /&gt;
&lt;br /&gt;
You can use an empty string here (&amp;quot;&amp;quot;). In this case, nothing is displayed in the game log.&lt;br /&gt;
&lt;br /&gt;
If you define a real string here, you should use &amp;quot;clienttranslate&amp;quot; method to make sure it can be translate.&lt;br /&gt;
&lt;br /&gt;
You can use arguments in your notification_log strings, that refers to values defines in the &amp;quot;notification_args&amp;quot; argument (see below). &lt;br /&gt;
Note: Make sure you only use single quotes (&#039;), otherwise PHP will try to interpolate the variable and will ignore the values in the args array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* notification_args:&lt;br /&gt;
The arguments of your notifications, as an associative array.&lt;br /&gt;
&lt;br /&gt;
This array will be transmitted to the game interface logic, in order the game interface can be updated.&lt;br /&gt;
&lt;br /&gt;
Complete notifyAllPlayers example (from &amp;quot;Reversi&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
self::notifyAllPlayers( &amp;quot;playDisc&amp;quot;, clienttranslate( &#039;${player_name} plays a disc and turns over ${returned_nbr} disc(s)&#039; ),&lt;br /&gt;
 array(&lt;br /&gt;
        &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
        &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
        &#039;returned_nbr&#039; =&amp;gt; count( $turnedOverDiscs ),&lt;br /&gt;
        &#039;x&#039; =&amp;gt; $x,&lt;br /&gt;
        &#039;y&#039; =&amp;gt; $y&lt;br /&gt;
     ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see in the example above the use of the &amp;quot;clienttranslate&amp;quot; method, and the use of 2 arguments &amp;quot;player_name&amp;quot; and &amp;quot;returned_nbr&amp;quot; in the notification log.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: NO private data must be sent with this method, as a cheater could see it even it is not used explicitly by the game interface logic. If you want to send private information to a player, please use notifyPlayer below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: this array is serialized to be sent to the browsers, and will be saved with the notification to be able to replay the game later. If it is too big, it can make notifications slower / less reliable, and replay archives very big (to the point of failing). So as a general rule, you should send only the minimum of information necessary to update the client interface with no overhead in order to keep the notifications as light as possible.&lt;br /&gt;
&lt;br /&gt;
Note: you CAN use some HTML inside your notification log, however it not recommended for many reasons:&lt;br /&gt;
* Its bad architecture, ui elements leak into server now you have to manage ui in many places&lt;br /&gt;
* If you decided to change something in ui in future version, old games reply and tutorials may not work, since they use stored notifications&lt;br /&gt;
* When you read log preview for old games its unreadable (this is log before you enter the game reply, useful for troubleshooting or game analysis)&lt;br /&gt;
* Its more data to transfer and store in db&lt;br /&gt;
* Its nightmare for translators, at least don&#039;t put HTML tags inside the &amp;quot;clienttranslate&amp;quot; method. You can use a notification argument instead, and provide your HTML through this argument.&lt;br /&gt;
&lt;br /&gt;
If you still want to have pretty pictures in the log check this [[BGA_Studio_Cookbook#Inject_images_and_styled_html_in_the_log]].&lt;br /&gt;
&lt;br /&gt;
If your notification contains some phrases that build programmatically you may need to use recursive notifications. In this case the argument can be not only the string but&lt;br /&gt;
an array itself, which contains &#039;log&#039; and &#039;args&#039;, i.e.&lt;br /&gt;
&lt;br /&gt;
  $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name_rec}&#039;),&lt;br /&gt;
                   [&#039;token_name_rec&#039;=&amp;gt;[&#039;log&#039;=&amp;gt;&#039;${token_name} #${token_number}&#039;,&lt;br /&gt;
                                       &#039;args&#039;=&amp;gt; [&#039;token_name&#039;=&amp;gt;clienttranslate(&#039;Boo&#039;), &#039;token_number&#039;=&amp;gt;$number, &#039;i18n&#039;=&amp;gt;[&#039;token_name&#039;] ]&lt;br /&gt;
                                      ]&lt;br /&gt;
                   ]);&lt;br /&gt;
&lt;br /&gt;
Special handling of arguments:&lt;br /&gt;
* ${player_name}  - this will be wrapped in html and text shown using color of the corresponding player, some colors also have reserved background. This will apply recursively as well.&lt;br /&gt;
* ${player_name2} - same &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;notifyPlayer( $player_id, $notification_type, $notification_log, $notification_args )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as above, except that the notification is sent to one player only.&lt;br /&gt;
&lt;br /&gt;
This method must be used each time some private information must be transmitted to a player.&lt;br /&gt;
&lt;br /&gt;
Important: the variable for player name must be ${player_name} in order to be highlighted with the player color in the game log. If you want a second player name in the log, name the variable ${player_name2}, etc.&lt;br /&gt;
&lt;br /&gt;
== About random and randomness ==&lt;br /&gt;
&lt;br /&gt;
A large number of board games rely on random, most often based on dice, cards shuffling, picking some item in a bag, and so on. This is very important to ensure a high level of randomness for each of these situations.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s are a list of techniques you should use in these situations, from the best to the worst.&lt;br /&gt;
&lt;br /&gt;
=== Dice and bga_rand ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;bga_rand( min, max )&#039;&#039;&#039; &lt;br /&gt;
This is a BGA framework function that provides you a random number between &amp;quot;min&amp;quot; and &amp;quot;max&amp;quot; (inclusive), using the best available random method available on the system.&lt;br /&gt;
&lt;br /&gt;
This is the preferred function you should use, because we are updating it when a better method is introduced.&lt;br /&gt;
&lt;br /&gt;
As of now, bga_rand is based on the PHP function &amp;quot;random_int&amp;quot;, which ensures a cryptographic level of randomness.&lt;br /&gt;
&lt;br /&gt;
In particular, it is &#039;&#039;&#039;mandatory&#039;&#039;&#039; to use it for all &#039;&#039;&#039;dice throw&#039;&#039;&#039; (ie: games using other methods for dice throwing will be rejected by BGA during review).&lt;br /&gt;
&lt;br /&gt;
Note: rand() and mt_rand() are deprecated on BGA and should not be used anymore, as their randomness is not as good as &amp;quot;bga_rand&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== shuffle and cards shuffling ===&lt;br /&gt;
&lt;br /&gt;
To shuffle items, like a pile of cards, the best way is to use the BGA PHP [[Deck]] component and to use &amp;quot;shuffle&amp;quot; method. This ensures that the best available shuffling method is used, and that if in the future we improve it your game will be up to date.&lt;br /&gt;
&lt;br /&gt;
As of now, the Deck component shuffle method is based on PHP &amp;quot;shuffle&amp;quot; method, which has quite good randomness (even it is not as good as bga_rand). In consequence, we accept other shuffling methods during reviews, as long as they are based on PHP &amp;quot;shuffle&amp;quot; function (or similar, like &amp;quot;array_rand&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
=== Other methods ===&lt;br /&gt;
&lt;br /&gt;
Mysql &amp;quot;RAND()&amp;quot; function has not enough randomness to be a valid method to get a random element on BGA. This function has been used in some existing games and has given acceptable results, but now it should be avoided and you should use other methods instead.&lt;br /&gt;
&lt;br /&gt;
== Game statistics ==&lt;br /&gt;
&lt;br /&gt;
There are 2 types of statistics:&lt;br /&gt;
* a &amp;quot;player&amp;quot; statistic is a statistic associated to a player&lt;br /&gt;
* a &amp;quot;table&amp;quot; statistic is a statistic not associated to a player (global statistic for this game).&lt;br /&gt;
&lt;br /&gt;
See [[Game statistics: stats.inc.php]] to see how you define statistics for your game.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;initStat( $table_or_player, $name, $value, $player_id = null )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a statistic entry with a default value.&lt;br /&gt;
&lt;br /&gt;
This method must be called for each statistic of your game, in your setupNewGame method.&lt;br /&gt;
If you neglect to call this for a statistic, and also do not update the value during the course of a certain game using setStat or incStat, the value of the stat will be undefined rather than 0. This will result in it being ignored at the end of the game, as if it didn&#039;t apply to that particular game, and excluded from cumulative statistics. As a consequence - if do not want statistic to be applied, do not init it, or call set or inc on it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;$table_or_player&#039; must be set to &amp;quot;table&amp;quot; if this is a table statistic, or &amp;quot;player&amp;quot; if this is a player statistic.&lt;br /&gt;
&lt;br /&gt;
&#039;$name&#039; is the name of your statistic, as it has been defined in your stats.inc.php file.&lt;br /&gt;
&lt;br /&gt;
&#039;$value&#039; is the initial value of the statistic. If this is a player statistic and if the player is not specified by &amp;quot;$player_id&amp;quot; argument, the value is set for ALL players.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setStat( $value, $name, $player_id = null )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Set a statistic $name to $value.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;$player_id&amp;quot; is not specified, setStat consider it is a TABLE statistic.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;$player_id&amp;quot; is specified, setStat consider it is a PLAYER statistic.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;incStat( $delta, $name, $player_id = null )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Increment (or decrement) specified statistic value by $delta value. Same behavior as setStat function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getStat( $name, $player_id = null )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return the value of statistic specified by $name. Useful when creating derivative statistics such as average.&lt;br /&gt;
&lt;br /&gt;
== Translations ==&lt;br /&gt;
&lt;br /&gt;
See [[Translations]]&lt;br /&gt;
&lt;br /&gt;
== Manage player scores and Tie breaker ==&lt;br /&gt;
&lt;br /&gt;
=== Normal scoring ===&lt;br /&gt;
&lt;br /&gt;
At the end of the game, players automatically get a rank depending on their score: the player with the biggest score is #1, the player with the second biggest score is #2, and so on...&lt;br /&gt;
&lt;br /&gt;
During the game, you update player&#039;s score directly by updating &amp;quot;player_score&amp;quot; field of &amp;quot;player&amp;quot; table in database.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  // +2 points to active player&lt;br /&gt;
  self::DbQuery( &amp;quot;UPDATE player SET player_score=player_score+2 WHERE player_id=&#039;&amp;quot;.self::getActivePlayerId().&amp;quot;&#039;&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
  // Set score of active player to 5&lt;br /&gt;
  self::DbQuery( &amp;quot;UPDATE player SET player_score=5 WHERE player_id=&#039;&amp;quot;.self::getActivePlayerId().&amp;quot;&#039;&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: don&#039;t forget to notify the client side in order the score control can be updated accordingly.&lt;br /&gt;
&lt;br /&gt;
=== Tie breaker ===&lt;br /&gt;
&lt;br /&gt;
Tie breaker is used when two players get the same score at the end of a game.&lt;br /&gt;
&lt;br /&gt;
Tie breaker is using &amp;quot;player_score_aux&amp;quot; field of &amp;quot;player&amp;quot; table. It is updated exactly like the &amp;quot;player_score&amp;quot; field.&lt;br /&gt;
&lt;br /&gt;
Tie breaker score is displayed only for players who are tied at the end of the game. Most of the time, it is not supposed to be displayed explicitly during the game.&lt;br /&gt;
&lt;br /&gt;
When you are using &amp;quot;player_score_aux&amp;quot; functionality, you must describe the formula to use in your gameinfos.inc.php file like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
         &#039;tie_breaker_description&#039; =&amp;gt; totranslate(&amp;quot;Describe here your tie breaker formula&amp;quot;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This description will be used as a tooltip to explain to players how this auxiliary score has been calculated.&lt;br /&gt;
&lt;br /&gt;
=== Co-operative game ===&lt;br /&gt;
&lt;br /&gt;
To make everyone win/lose together in a full-coop game:&lt;br /&gt;
&lt;br /&gt;
Add the following in gameinfos.inc.php :&lt;br /&gt;
&#039;is_coop&#039; =&amp;gt; 1, // full cooperative&lt;br /&gt;
&lt;br /&gt;
Assign a score of zero to everyone if it&#039;s a loss.&lt;br /&gt;
Assign the same score &amp;gt; 0 to everyone if it&#039;s a win.&lt;br /&gt;
&lt;br /&gt;
=== Semi-coop ===&lt;br /&gt;
&lt;br /&gt;
If the game is not full-coop, then everyone loses = everyone is tied. I.e. set score to 0 to everybody.&lt;br /&gt;
&lt;br /&gt;
=== Only &amp;quot;winners&amp;quot; and &amp;quot;losers&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
For some games, there is only a group (or a single) &amp;quot;winner&amp;quot;, and everyone else is a &amp;quot;loser&amp;quot;, with no &amp;quot;end of game rank&amp;quot; (1st, 2nd, 3rd...).&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
* Coup&lt;br /&gt;
* Not Alone&lt;br /&gt;
* Werewolves&lt;br /&gt;
* Quantum&lt;br /&gt;
&lt;br /&gt;
In this case:&lt;br /&gt;
* Set the scores so that the winner has the best score, and the other players have the same (lower) score.&lt;br /&gt;
* Add the following lines to gameinfos.inc.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// If in the game, all losers are equal (no score to rank them or explicit in the rules that losers are not ranked between them), set this to true &lt;br /&gt;
// The game end result will display &amp;quot;Winner&amp;quot; for the 1st player and &amp;quot;Loser&amp;quot; for all other players&lt;br /&gt;
&#039;losers_not_ranked&#039; =&amp;gt; true,&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Werewolves and Coup are implemented like this, as you can see here:&lt;br /&gt;
* https://boardgamearena.com/#!gamepanel?game=werewolves&amp;amp;section=lastresults&lt;br /&gt;
* https://boardgamearena.com/#!gamepanel?game=coupcitystate&amp;amp;section=lastresults&lt;br /&gt;
&lt;br /&gt;
Adding this has the following effects:&lt;br /&gt;
* On game results for this game, &amp;quot;Winner&amp;quot; or &amp;quot;Loser&amp;quot; is going to appear instead of the usual &amp;quot;1st, 2nd, 3rd, ...&amp;quot;.&lt;br /&gt;
* When a game is over, the result of the game will be &amp;quot;End of game: Victory&amp;quot; or &amp;quot;End of game: Defeat&amp;quot; depending on the result of the CURRENT player (instead of the usual &amp;quot;Victory of XXX&amp;quot;).&lt;br /&gt;
* When calculating ELO points, if there is at least one &amp;quot;Loser&amp;quot;, no &amp;quot;victorious&amp;quot; player can lose ELO points, and no &amp;quot;losing&amp;quot; player can win ELO point. Usually it may happened because being tie with many players with a low rank is considered as a tie and may cost you points. If losers_not_ranked is set, we prevent this behavior and make sure you only gain/loss ELO when you get the corresponding results.&lt;br /&gt;
&lt;br /&gt;
Important: this SHOULD NOT be used for cooperative games (see is_coop parameter), or for 2 players games (it makes no sense in this case).&lt;br /&gt;
&lt;br /&gt;
=== Solo ===&lt;br /&gt;
&lt;br /&gt;
If game supports solo variant, a negative or zero score means defeat, a positive score means victory.&lt;br /&gt;
&lt;br /&gt;
=== Player elimination ===&lt;br /&gt;
&lt;br /&gt;
In some games, this is useful to eliminate a player from the game in order he/she can start another game without waiting for the current game end.&lt;br /&gt;
&lt;br /&gt;
This case should be rare. Please don&#039;t use player elimination feature if some player just has to wait the last 10% of the game for game end. This feature should be used only in games where players are eliminated all along the game (typical examples: &amp;quot;Perudo&amp;quot; or &amp;quot;The Werewolves of Miller&#039;s Hollow&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&lt;br /&gt;
* Player to eliminate should NOT be active anymore (preferably use the feature in a &amp;quot;game&amp;quot; type game state).&lt;br /&gt;
* In your PHP code:&lt;br /&gt;
  self::eliminatePlayer( &amp;lt;player_to_eliminate_id&amp;gt; );&lt;br /&gt;
* the player is informed in a dialog box that he no longer have to played and can start another game if he/she wants too (whith buttons &amp;quot;stay at this table&amp;quot; &amp;quot;quit table and back to main site&amp;quot;). In any case, the player is free to start &amp;amp; join another table from now.&lt;br /&gt;
* When your game is over, all players who have been eliminated before receive a &amp;quot;notification&amp;quot; (the small &amp;quot;!&amp;quot; icon on the top right of the BGA interface) that indicate them that &amp;quot;the game has ended&amp;quot; and invite them to review the game results.&lt;br /&gt;
&lt;br /&gt;
=== Scoring Helper functions ===&lt;br /&gt;
&lt;br /&gt;
These functions should have been API but they are not, just add them to your php game and use for every game.&lt;br /&gt;
&lt;br /&gt;
    // get score&lt;br /&gt;
    function dbGetScore($player_id) {&lt;br /&gt;
        return $this-&amp;gt;getUniqueValueFromDB(&amp;quot;SELECT player_score FROM player WHERE player_id=&#039;$player_id&#039;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // set score&lt;br /&gt;
    function dbSetScore($player_id, $count) {&lt;br /&gt;
        $this-&amp;gt;DbQuery(&amp;quot;UPDATE player SET player_score=&#039;$count&#039; WHERE player_id=&#039;$player_id&#039;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // set aux score (tie breaker)&lt;br /&gt;
    function dbSetAuxScore($player_id, $score) {&lt;br /&gt;
        $this-&amp;gt;DbQuery(&amp;quot;UPDATE player SET player_score_aux=$score WHERE player_id=&#039;$player_id&#039;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // increment score (can be negative too)&lt;br /&gt;
    function dbIncScore($player_id, $inc) {&lt;br /&gt;
        $count = $this-&amp;gt;dbGetScore($player_id);&lt;br /&gt;
        if ($inc != 0) {&lt;br /&gt;
            $count += $inc;&lt;br /&gt;
            $this-&amp;gt;dbSetScore($player_id, $count);&lt;br /&gt;
        }&lt;br /&gt;
        return $count;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Reflexion time ==&lt;br /&gt;
&lt;br /&gt;
; function giveExtraTime( $player_id, $specific_time=null )&lt;br /&gt;
: Give standard extra time to this player.&lt;br /&gt;
: Standard extra time depends on the speed of the game (small with &amp;quot;slow&amp;quot; game option, bigger with other options).&lt;br /&gt;
: You can also specify an exact time to add, in seconds, with the &amp;quot;specified_time&amp;quot; argument (rarely used).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Undo moves ==&lt;br /&gt;
&lt;br /&gt;
Please read our [[BGA Undo policy]] before.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: Before using these methods, you must also add the following to your &amp;quot;gameinfos.inc.php&amp;quot; file, otherwise these methods are ineffective:&lt;br /&gt;
  &#039;db_undo_support&#039; =&amp;gt; true&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; function undoSavepoint( )&lt;br /&gt;
: Save the whole game situation inside an &amp;quot;Undo save point&amp;quot;.&lt;br /&gt;
: There is only ONE undo save point available (see [[BGA Undo policy]]). Cannot use in multiactivate state or in game state where next state is multiactive.&lt;br /&gt;
: Note: this function does not actually do anything when it is called, it only raises the flag to store the database AFTER transaction is over. So the actual state will be saved when you exit the function  calling it (technically before first queued notification is sent, which matter if you transition to game state not to user state after), which may affect what you end up saved.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; function undoRestorePoint()&lt;br /&gt;
: Restore the situation previously saved as an &amp;quot;Undo save point&amp;quot;.&lt;br /&gt;
: You must make sure that the active player is the same after and before the undoRestorePoint (ie: this is your responsibility to ensure that the player that is active when this method is called is exactly the same than the player that was active when the undoSavePoint method has been called).&lt;br /&gt;
&lt;br /&gt;
    function actionUndo() {&lt;br /&gt;
        self::checkAction(&#039;actionUndo&#039;);&lt;br /&gt;
        $this-&amp;gt;undoRestorePoint();&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;next&#039;); // transition to single player state (i.e. beginning of player actions for this turn)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Managing errors and exceptions ==&lt;br /&gt;
&lt;br /&gt;
Note: when you throw an exception, all database changes and all notifications are cancelled immediately. This way, the game situation that existed before the request is completely restored.&lt;br /&gt;
&lt;br /&gt;
; throw new BgaUserException ( $error_message)&lt;br /&gt;
: Base class to notify a user error&lt;br /&gt;
: You must throw this exception when a player wants to do something that he is not allowed to do.&lt;br /&gt;
: The error message will be shown to the player as a &amp;quot;red message&amp;quot;, so it must be translated.&lt;br /&gt;
: Throwing such an exception is NOT considered a bug, so it is not traced in BGA error logs.&lt;br /&gt;
&lt;br /&gt;
Example from Gomoku:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     throw new BgaUserException( self::_(&amp;quot;There is already a stone on this intersection, you can&#039;t play there&amp;quot;) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; throw new BgaVisibleSystemException ( $error_message)&lt;br /&gt;
: You must throw this exception when you detect something that is not supposed to happened in your code.&lt;br /&gt;
: The error message is shown to the user as an &amp;quot;Unexpected error&amp;quot;, in order that he can report it in the forum.&lt;br /&gt;
: The error message is logged in BGA error logs. If it happens regularly, we will report it to you.&lt;br /&gt;
&lt;br /&gt;
; throw new BgaSystemException ( $error_message)&lt;br /&gt;
: Base class to notify a system exception. The message will be hidden from the user, but show in the logs. Use this if the message contains technical information.&lt;br /&gt;
: You shouldn&#039;t use this type of exception except if you think the information shown could be critical. Indeed: a generic error message will be shown to the user, so it&#039;s going to be difficult for you to see what happened.&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
When a player leaves a game for any reason (expelled, quit), he becomes a &amp;quot;zombie player&amp;quot;. In this case, the results of the game won&#039;t count for statistics, but this is cool if the other players can finish the game anyway. That&#039;s why zombie mode exists: allow the other player to finish the game, even if the situation is not ideal.&lt;br /&gt;
&lt;br /&gt;
While developing your zombie mode, keep in mind that:&lt;br /&gt;
* Do not refer to the rules, because this situation is not planned by the rules.&lt;br /&gt;
* Try to figure that you are playing with your friends and one of them has to leave: how can we finish the game without killing the spirit of the game?&lt;br /&gt;
* The idea is NOT to develop an artificial intelligence for the game.&lt;br /&gt;
* Do not try to end the game early, even in a two-player game. The zombie is there to allow the game to continue, not to end it. Trying to end the game is not supported by the framework and will likely cause unexpected errors.&lt;br /&gt;
&lt;br /&gt;
Most of the time, the best thing to do when it is zombie player turn is to jump immediately to a state where he is not active anymore. For example, if he is in a game state where he has a choice between playing A and playing B, the best thing to do is NOT to choose A or B, but to pass. So, even if there&#039;s no &amp;quot;pass&amp;quot; action in the rules, add a &amp;quot;zombiepass&amp;quot; transitition in your game state and use it.&lt;br /&gt;
&lt;br /&gt;
Each time a zombie player must play, your &amp;quot;zombieTurn&amp;quot; method is called.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
* $state: the name of the current game state.&lt;br /&gt;
* $active_player: the id of the active player.&lt;br /&gt;
&lt;br /&gt;
Most of the time, your zombieTurn method looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function zombieTurn( $state, $active_player )&lt;br /&gt;
    {&lt;br /&gt;
    	$statename = $state[&#039;name&#039;];&lt;br /&gt;
&lt;br /&gt;
        if( $statename == &#039;myFirstGameState&#039;&lt;br /&gt;
             ||  $statename == &#039;my2ndGameState&#039;&lt;br /&gt;
             ||  $statename == &#039;my3rdGameState&#039;&lt;br /&gt;
               ....&lt;br /&gt;
           )&lt;br /&gt;
        {&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextState( &amp;quot;zombiePass&amp;quot; );&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            throw new BgaVisibleSystemException( &amp;quot;Zombie mode not supported at this game state: &amp;quot;.$statename );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in the example above, all corresponding game state should implement &amp;quot;zombiePass&amp;quot; as a transition.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Very important&#039;&#039;&#039;: your zombie code will be called when the player leaves the game. This action is triggered from the main site and propagated to the gameserver from a server, not from a browser. As a consequence, there is no current player associated to this action. In your zombieTurn function, you must &#039;&#039;&#039;never&#039;&#039;&#039; use getCurrentPlayerId() or getCurrentPlayerName(), otherwise it will fail with a &amp;quot;Not logged&amp;quot; error message.&lt;br /&gt;
&lt;br /&gt;
== Player color preferences ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
BGA players (Club members) may now choose their preferred color for playing. For example, if they are used to play green for every board game, they can select &amp;quot;green&amp;quot; in their BGA preferences page.&lt;br /&gt;
&lt;br /&gt;
Making your game compatible with colors preferences is very easy and requires only 1 line of PHP and 1 configuration change :&lt;br /&gt;
&lt;br /&gt;
On your gameinfos.inc.php file, add the following lines :&lt;br /&gt;
&lt;br /&gt;
  // Favorite colors support : if set to &amp;quot;true&amp;quot;, support attribution of favorite colors based on player&#039;s preferences (see reattributeColorsBasedOnPreferences PHP method)&lt;br /&gt;
  // NB: this parameter is used only to flag games supporting this feature; you must use (or not use) reattributeColorsBasedOnPreferences PHP method to actually enable or disable the feature.&lt;br /&gt;
  &#039;favorite_colors_support&#039; =&amp;gt; true,&lt;br /&gt;
&lt;br /&gt;
Then, on your main &amp;lt;your_game&amp;gt;.game.php file, find the &amp;quot;reloadPlayersBasicInfos&amp;quot; call in your &amp;quot;setupNewGame&amp;quot; method and replace :&lt;br /&gt;
&lt;br /&gt;
        $sql .= implode( $values, &#039;,&#039; );&lt;br /&gt;
        self::DbQuery( $sql );&lt;br /&gt;
        self::reloadPlayersBasicInfos();&lt;br /&gt;
&lt;br /&gt;
By :&lt;br /&gt;
&lt;br /&gt;
        $sql .= implode( $values, &#039;,&#039; );&lt;br /&gt;
        self::DbQuery( $sql );&lt;br /&gt;
        self::reattributeColorsBasedOnPreferences( $players, array(  /* LIST HERE THE AVAILABLE COLORS OF YOUR GAME INSTEAD OF THESE ONES */&amp;quot;ff0000&amp;quot;, &amp;quot;008000&amp;quot;, &amp;quot;0000ff&amp;quot;, &amp;quot;ffa500&amp;quot;, &amp;quot;773300&amp;quot; ) );&lt;br /&gt;
        self::reloadPlayersBasicInfos();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;reattributeColorsBasedOnPreferences&amp;quot; method reattributes all colors, taking into account players color preferences and available colors.&lt;br /&gt;
&lt;br /&gt;
Note that you must update the colors to indicate the colors available for your game.&lt;br /&gt;
&lt;br /&gt;
2 important remarks :&lt;br /&gt;
* for some games (ex : Chess), the color has an influence on a mechanism of the game, most of the time by giving a special advantage to a player (ex : Starting the game). Color preference mechanism must NOT be used in such a case.&lt;br /&gt;
* your logic should NEVER consider that the first player has the color X, that the second player has the color Y, and so on. If this is the case, your game will NOT be compatible with reattributeColorsBasedOnPreferences as this method attribute colors to players based on their preferences and not based as their order at the table.&lt;br /&gt;
&lt;br /&gt;
Colours currently listed as a choice in preferences:&lt;br /&gt;
&lt;br /&gt;
* #ff0000 Red&lt;br /&gt;
* #008000 Green&lt;br /&gt;
* #0000ff Blue&lt;br /&gt;
* #ffa500 Yellow&lt;br /&gt;
* #000000 Black&lt;br /&gt;
* #ffffff White&lt;br /&gt;
* #e94190 Pink&lt;br /&gt;
* #982fff Purple&lt;br /&gt;
* #72c3b1 Cyan&lt;br /&gt;
* #f07f16 Orange&lt;br /&gt;
* #bdd002 Khaki green&lt;br /&gt;
* #7b7b7b Gray&lt;br /&gt;
&lt;br /&gt;
== Legacy games API ==&lt;br /&gt;
&lt;br /&gt;
For some very specific games (&amp;quot;legacy&amp;quot;, &amp;quot;campaign&amp;quot;), you need to keep some informations from a game to another.&lt;br /&gt;
&lt;br /&gt;
This should be an exceptional situation: the legacy API is costing resources on Board Game Arena databases, and is slowing down the game setup process + game end of game process. Please do not use it for things like:&lt;br /&gt;
* keeping a player preference/settings (=&amp;gt; player preferences and game options should be used instead)&lt;br /&gt;
* keeping a statistics, a score, or a ranking, while it is not planned in the physical board game, or while there is no added value compared to BGA statistics / rankings.&lt;br /&gt;
&lt;br /&gt;
You should use it for:&lt;br /&gt;
* legacy games: when some components of the game has been altered in a previous game and should be kept as it is.&lt;br /&gt;
* &amp;quot;campaign style&amp;quot; games: when a player is getting a &amp;quot;reward&amp;quot; at the end of a game, and should be able to use it in further games.&lt;br /&gt;
&lt;br /&gt;
Important: you cannot store more than 64k of data (serialized as JSON) per player per game. If you go over 64k, storeLegacyData function is going to FAIL, and there is a risk to create a major bug (= players blocked) in your game. You MUST make sure that no more than 64k of data is used for each player for your game. For example, if you are implementing a &amp;quot;campaign style&amp;quot; game and if you allow a player to start multiple campaign, you must LIMIT the number of different campaign so that the total data size to not go over the limit. We strongly recommend you to use this:&lt;br /&gt;
&lt;br /&gt;
  try &lt;br /&gt;
  {&lt;br /&gt;
  	$this-&amp;gt;storeLegacyTeamData( &#039;my_variable&#039;, $my_data );&lt;br /&gt;
  }&lt;br /&gt;
  catch( feException $e )&lt;br /&gt;
  {&lt;br /&gt;
  	if( $e-&amp;gt;getCode() == FEX_legacy_size_exceeded )&lt;br /&gt;
  	{&lt;br /&gt;
  		// Do something here to free some space in Legacy data (ex: by removing some variables)&lt;br /&gt;
  	}&lt;br /&gt;
  	else&lt;br /&gt;
  		throw $e;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; function storeLegacyData( $player_id, $key, $data, $ttl = 365 )&lt;br /&gt;
: Store some data associated with $key for the given user / current game&lt;br /&gt;
: In the opposite of all other game data, this data will PERSIST after the end of this table, and can be re-used&lt;br /&gt;
: in a future table with the same game.&lt;br /&gt;
: IMPORTANT: The only possible place where you can use this method is when the game is over at your table (last game action). Otherwise, there is a risk of conflicts between ongoing games.    &lt;br /&gt;
: TTL is a time-to-live: the maximum, and default, is 365 days.&lt;br /&gt;
: In any way, the total data (= all keys) you can store for a given user+game is 64k (note: data is store serialized as JSON data)&lt;br /&gt;
&lt;br /&gt;
; function retrieveLegacyData( $player_id, $key )&lt;br /&gt;
: Get data associated with $key for the current game&lt;br /&gt;
: This data is common to ALL tables from the same game for this player, and persist from one table to another.&lt;br /&gt;
: Note: calling this function has an important cost =&amp;gt; please call it few times (possibly: only ONCE) for each player for 1 game if possible&lt;br /&gt;
: Note: you can use &#039;%&#039; in $key to retrieve all keys matching the given patterns&lt;br /&gt;
&lt;br /&gt;
; function removeLegacyData( $player_id, $key )&lt;br /&gt;
: Remove some legacy data with the given key&lt;br /&gt;
: (useful to free some data to avoid going over 64k)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; function storeLegacyTeamData( $data, $ttl = 365 )&lt;br /&gt;
: Same as storeLegacyData, except that it stores some data for the whole team within the current table&lt;br /&gt;
: Ie: if players A, B and C are at a table, the legacy data will be saved for future table with (exactly) A, B and C on the table.&lt;br /&gt;
: This is useful for games which are intended to be played several time by the same team.&lt;br /&gt;
: Note: the data total size is still limited, so you must implement catch the FEX_legacy_size_exceeded exception if it happens&lt;br /&gt;
&lt;br /&gt;
; function retrieveLegacyTeamData()&lt;br /&gt;
: Same as retrieveLegacyData, except that it retrieves some data for the whole team within the current table (set by storeLegacyTeamData)&lt;br /&gt;
&lt;br /&gt;
; function removeLegacyTeamData()&lt;br /&gt;
: Same as removeLegacyData, except that it retrieves some data for the whole team within the current table (set by storeLegacyTeamData)&lt;br /&gt;
&lt;br /&gt;
== Language dependent games API ==&lt;br /&gt;
&lt;br /&gt;
This API is used for games that are heavily language dependent. Two most common use cases are:&lt;br /&gt;
* Games that have a language dependent component that are not necessarily translatable, typically a list of words. (Think of games like Codenames, Decrypto, Just One...)&lt;br /&gt;
* Games with massive communication where players would like to ensure that all participants speak the same language. (Think of games like Werewolf, The Resistance, maybe even dixit...)&lt;br /&gt;
&lt;br /&gt;
If this option is used, the table created will be limited only to users that have specific language in their profile. Player starting the game would be able to chose one of the languages he speaks.&lt;br /&gt;
&lt;br /&gt;
There is a new property language_dependency in gameinfos.inc.php which can be set like this:&lt;br /&gt;
  &#039;language_dependecy&#039; =&amp;gt; false,  //or if the property is missing, the game is not language dependent&lt;br /&gt;
  &#039;language_dependecy&#039; =&amp;gt; true, //all players at the table must speak the same language&lt;br /&gt;
  &#039;language_dependecy&#039; =&amp;gt; array( 1 =&amp;gt; &#039;en&#039;, 2 =&amp;gt; &#039;fr&#039;, 3 =&amp;gt; &#039;it&#039; ), //1-based list of supported languages&lt;br /&gt;
&lt;br /&gt;
In the gamename.game.php file, you can get the id of selected language with the method &#039;&#039;&#039;getGameLanguage&#039;&#039;&#039;.&lt;br /&gt;
; function getGameLanguage()&lt;br /&gt;
: Returns an index of the selected language as defined in gameinfos.inc.php.&lt;br /&gt;
&lt;br /&gt;
Languages currently available on BGA are:&lt;br /&gt;
  &#039;ar&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;العربية&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ar_AE&#039; ),             // Arabic&lt;br /&gt;
  &#039;be&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;беларуская мова&amp;quot;, &#039;code&#039; =&amp;gt; &#039;be_BY&#039; ),     // Belarusian&lt;br /&gt;
  &#039;bn&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;বাংলা&amp;quot;, &#039;code&#039; =&amp;gt; &#039;bn_BD&#039; ),                // Bengali&lt;br /&gt;
  &#039;bg&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;български език&amp;quot;, &#039;code&#039; =&amp;gt; &#039;bg_BG&#039; ),      // Bulgarian&lt;br /&gt;
  &#039;ca&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;català&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ca_ES&#039; ),              // Catalan&lt;br /&gt;
  &#039;cs&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;čeština&amp;quot;, &#039;code&#039; =&amp;gt; &#039;cs_CZ&#039; ),             // Czech&lt;br /&gt;
  &#039;da&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;dansk&amp;quot;, &#039;code&#039; =&amp;gt; &#039;da_DK&#039; ),               // Danish&lt;br /&gt;
  &#039;de&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;deutsch&amp;quot;, &#039;code&#039; =&amp;gt; &#039;de_DE&#039; ),             // German&lt;br /&gt;
  &#039;el&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Ελληνικά&amp;quot;, &#039;code&#039; =&amp;gt; &#039;el_GR&#039; ),            // Greek&lt;br /&gt;
  &#039;en&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;English&amp;quot;, &#039;code&#039; =&amp;gt; &#039;en_US&#039; ),             // English&lt;br /&gt;
  &#039;es&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;español&amp;quot;, &#039;code&#039; =&amp;gt; &#039;es_ES&#039; ),             // Spanish&lt;br /&gt;
  &#039;et&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;eesti keel&amp;quot;, &#039;code&#039; =&amp;gt; &#039;et_EE&#039; ),          // Estonian       &lt;br /&gt;
  &#039;fi&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;suomi&amp;quot;, &#039;code&#039; =&amp;gt; &#039;fi_FI&#039; ),               // Finnish&lt;br /&gt;
  &#039;fr&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;français&amp;quot;, &#039;code&#039; =&amp;gt; &#039;fr_FR&#039; ),            // French&lt;br /&gt;
  &#039;he&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;עברית&amp;quot;, &#039;code&#039; =&amp;gt; &#039;he_IL&#039; ),               // Hebrew       &lt;br /&gt;
  &#039;hi&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;हिन्दी&amp;quot;, &#039;code&#039; =&amp;gt; &#039;hi_IN&#039; ),                 // Hindi&lt;br /&gt;
  &#039;hr&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Hrvatski&amp;quot;, &#039;code&#039; =&amp;gt; &#039;hr_HR&#039; ),            // Croatian&lt;br /&gt;
  &#039;hu&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;magyar&amp;quot;, &#039;code&#039; =&amp;gt; &#039;hu_HU&#039; ),              // Hungarian&lt;br /&gt;
  &#039;id&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Bahasa Indonesia&amp;quot;, &#039;code&#039; =&amp;gt; &#039;id_ID&#039; ),    // Indonesian&lt;br /&gt;
  &#039;ms&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Bahasa Malaysia&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ms_MY&#039; ),     // Malaysian&lt;br /&gt;
  &#039;it&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;italiano&amp;quot;, &#039;code&#039; =&amp;gt; &#039;it_IT&#039; ),            // Italian&lt;br /&gt;
  &#039;ja&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;日本語&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ja_JP&#039; ),               // Japanese&lt;br /&gt;
  &#039;jv&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Basa Jawa&amp;quot;, &#039;code&#039; =&amp;gt; &#039;jv_JV&#039; ),           // Javanese                       &lt;br /&gt;
  &#039;ko&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;한국어&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ko_KR&#039; ),               // Korean&lt;br /&gt;
  &#039;lt&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;lietuvių&amp;quot;, &#039;code&#039; =&amp;gt; &#039;lt_LT&#039; ),            // Lithuanian&lt;br /&gt;
  &#039;lv&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;latviešu&amp;quot;, &#039;code&#039; =&amp;gt; &#039;lv_LV&#039; ),            // Latvian&lt;br /&gt;
  &#039;nl&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;nederlands&amp;quot;, &#039;code&#039; =&amp;gt; &#039;nl_NL&#039; ),          // Dutch&lt;br /&gt;
  &#039;no&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;norsk&amp;quot;, &#039;code&#039; =&amp;gt; &#039;nb_NO&#039; ),               // Norwegian&lt;br /&gt;
  &#039;oc&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;occitan&amp;quot;, &#039;code&#039; =&amp;gt; &#039;oc_FR&#039; ),             // Occitan&lt;br /&gt;
  &#039;pl&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;polski&amp;quot;, &#039;code&#039; =&amp;gt; &#039;pl_PL&#039; ),              // Polish&lt;br /&gt;
  &#039;pt&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;português&amp;quot;,  &#039;code&#039; =&amp;gt; &#039;pt_PT&#039; ),          // Portuguese&lt;br /&gt;
  &#039;ro&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;română&amp;quot;,  &#039;code&#039; =&amp;gt; &#039;ro_RO&#039;  ),            // Romanian&lt;br /&gt;
  &#039;ru&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Русский язык&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ru_RU&#039; ),        // Russian&lt;br /&gt;
  &#039;sk&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;slovenčina&amp;quot;, &#039;code&#039; =&amp;gt; &#039;sk_SK&#039; ),          // Slovak&lt;br /&gt;
  &#039;sl&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;slovenščina&amp;quot;, &#039;code&#039; =&amp;gt; &#039;sl_SI&#039; ),         // Slovenian       &lt;br /&gt;
  &#039;sr&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Српски&amp;quot;, &#039;code&#039; =&amp;gt; &#039;sr_RS&#039; ),              // Serbian       &lt;br /&gt;
  &#039;sv&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;svenska&amp;quot;, &#039;code&#039; =&amp;gt; &#039;sv_SE&#039; ),             // Swedish&lt;br /&gt;
  &#039;tr&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Türkçe&amp;quot;, &#039;code&#039; =&amp;gt; &#039;tr_TR&#039; ),              // Turkish       &lt;br /&gt;
  &#039;uk&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Українська мова&amp;quot;, &#039;code&#039; =&amp;gt; &#039;uk_UA&#039; ),     // Ukrainian&lt;br /&gt;
  &#039;zh&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;中文 (漢)&amp;quot;,  &#039;code&#039; =&amp;gt; &#039;zh_TW&#039; ),           // Traditional Chinese (Hong Kong, Macau, Taiwan)&lt;br /&gt;
  &#039;zh-cn&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;中文 (汉)&amp;quot;, &#039;code&#039; =&amp;gt; &#039;zh_CN&#039; ),         // Simplified Chinese (Mainland China, Singapore)&lt;br /&gt;
&lt;br /&gt;
== Debugging and Tracing ==&lt;br /&gt;
&lt;br /&gt;
To debug php code you can use some tracing functions available from the parent class such as debug, trace, error, warn, dump.&lt;br /&gt;
  &lt;br /&gt;
  self::debug(&amp;quot;Ahh!&amp;quot;);&lt;br /&gt;
  self::dump(&#039;my_var&#039;,$my_var);&lt;br /&gt;
&lt;br /&gt;
See [[Practical_debugging]] section for complete information about debugging interfaces and where to find logs.&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=7110</id>
		<title>BGA Studio Cookbook</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=7110"/>
		<updated>2021-01-29T23:18:21Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Avoiding code in dojo declare style */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is collection of design and implementation recipes for BGA Studio framework.&lt;br /&gt;
For tooling and usage recipes see [[Tools and tips of BGA Studio]].&lt;br /&gt;
If you have your own recipes feel free to edit this page.&lt;br /&gt;
&lt;br /&gt;
== Visual Effects, Layout and Animation ==&lt;br /&gt;
&lt;br /&gt;
=== Create pieces dynamically (using template) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: this method is recommended by BGA guildlines&lt;br /&gt;
&lt;br /&gt;
Declared js template with variables in .tpl file, like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Javascript HTML templates&lt;br /&gt;
    var jstpl_ipiece = &#039;&amp;lt;div class=&amp;quot;${type} ${type}_${color} inlineblock&amp;quot; aria-label=&amp;quot;${name}&amp;quot; title=&amp;quot;${name}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use it like this in .js file&lt;br /&gt;
  div = this.format_block(&#039;jstpl_ipiece&#039;, {&lt;br /&gt;
                                type : &#039;meeple&#039;,&lt;br /&gt;
                                color : &#039;ff0000&#039;,&lt;br /&gt;
                                name : &#039;Bob&#039;,&lt;br /&gt;
                            });&lt;br /&gt;
  &lt;br /&gt;
Then you do whatever you need to do with that div, this one specifically design to go to log entries, because it has embedded title (otherwise its a picture only) and no id.&lt;br /&gt;
&lt;br /&gt;
Note: you could have place this variable in js itself, but keeping it in .tpl allows you to have your js code be free of HTML. Normally it never happens but&lt;br /&gt;
it is good to strive for it.&lt;br /&gt;
Note: you can also use string concatenation, its less readable. You can also use dojo dom object creation api&#039;s but its brutally verbose and its more unreadable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create pieces dynamically (using string concatenation) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: Not recommended&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  div = &amp;quot;&amp;lt;div class=&#039;meeple &amp;quot;+color+&amp;quot;&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Create all pieces statically ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.css, ggg.view.php (optional) &lt;br /&gt;
&lt;br /&gt;
* Create ALL game pieces in html template (.tpl)&lt;br /&gt;
* ALL pieces should have unique id, and it should be meaningful, i.e. meeple_red_1&lt;br /&gt;
* Do not use inline styling&lt;br /&gt;
* Id of player&#039;s specific pieces should use some sort of &#039;color&#039; identification, since player id cannot be used in static layout, you can use english color name, hex 6 char value, or color &amp;quot;number&amp;quot; (1,2,3...)&lt;br /&gt;
* Pieces should have separated class for its color, type, etc, so it can be easily styled in groups. In example below you now can style all meeples, all red meeples or all red tokens, or all &amp;quot;first&amp;quot; meeples&lt;br /&gt;
&lt;br /&gt;
ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
  &amp;lt;div id=&amp;quot;home_red&amp;quot; class=&amp;quot;home_red home&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_1&amp;quot; class=&amp;quot;meeple red n1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_2&amp;quot; class=&amp;quot;meeple red n2&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.css:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.meeple {&lt;br /&gt;
	width: 32px;&lt;br /&gt;
	height: 39px;&lt;br /&gt;
	background-image: url(img/78_64_stand_meeples.png);&lt;br /&gt;
	background-size: 352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.meeple.red {&lt;br /&gt;
	background-position: 30% 0%;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* There should be straight forward mapping between server id and js id (or 1:1)&lt;br /&gt;
* You place objects in different zones of the layout, and setup css to take care of layout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.home .meeple{&lt;br /&gt;
   display: inline-block;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you need to have a temporary object that look like original you can use dojo.clone (and change id to some temp id)&lt;br /&gt;
* If there is lots of repetition or zone grid you can use template generator, but inject style declaration in css instead of inline style for flexibility&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
* If you use this model you cannot use premade js components such as Stock and Zone&lt;br /&gt;
* You have to use alternative methods of animation (slightly altered) since default method will leave object with inline style attributes which you don&#039;t need&lt;br /&gt;
&lt;br /&gt;
=== Use thematic fonts ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.css&lt;br /&gt;
&lt;br /&gt;
Sometime game elements use specific fonts of text, if you want to match it up you can load some specific font (IMPORTANT: from some &#039;&#039;&#039;free font&#039;&#039;&#039; source. See notes below).&lt;br /&gt;
&lt;br /&gt;
[[File:Dragonline_font.png]]&lt;br /&gt;
&lt;br /&gt;
.css&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* latin-ext */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: 400;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/2Dy1Unur1HJoklbsg4iPJ_Y6323mHUZFJMgTvxaG2iE.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;&lt;br /&gt;
}&lt;br /&gt;
/* latin */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/gThgNuQB0o5ITpgpLi4Zpw.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;&lt;br /&gt;
}&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(http://ff.static.1001fonts.net/q/w/qwigley.regular.ttf) format(&#039;ttf&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.zone_title {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	font: italic 32px/32px &amp;quot;Qwigley&amp;quot;, cursive;	   &lt;br /&gt;
	height: 32px;&lt;br /&gt;
	width: auto;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NB:&#039;&#039;&#039; if you need to include a font that&#039;s not available online, an extra action will be needed from an admin. Please include the font file(s) in your img directory, and mention it to admins when requesting your game to be moved to alpha. &#039;&#039;&#039;Please remember that the font has to be free, and include a .txt with all appropriate license information about the font.&#039;&#039;&#039;&lt;br /&gt;
You can look for free fonts (for example) on https://fonts.google.com or https://www.fontsquirrel.com/)&lt;br /&gt;
&lt;br /&gt;
=== Use player color in template ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.view.php&lt;br /&gt;
&lt;br /&gt;
.view.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function build_page($viewArgs) {&lt;br /&gt;
        // Get players &amp;amp; players number&lt;br /&gt;
        $players = $this-&amp;gt;game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        $players_nbr = count($players);&lt;br /&gt;
        /**&lt;br /&gt;
         * ********* Place your code below: ***********&lt;br /&gt;
         */&lt;br /&gt;
        &lt;br /&gt;
        // Set PCOLOR to the current player color hex&lt;br /&gt;
        global $g_user;&lt;br /&gt;
        $cplayer = $g_user-&amp;gt;get_id();&lt;br /&gt;
        if (array_key_exists($cplayer, $players)) { // may be not set if spectator&lt;br /&gt;
            $player_color = $players [$cplayer] [&#039;player_color&#039;];&lt;br /&gt;
        } else {&lt;br /&gt;
            $player_color = &#039;ffffff&#039;; // spectator&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;tpl [&#039;PCOLOR&#039;] = $player_color;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Scale to fit for big boards ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
Lets say you have huge game board, and lets say you want it to be 1400px wide. Besides the board there will be side bar which is 240 and trim. &lt;br /&gt;
My display is 1920 wide so it fits, but there is big chance other people won&#039;t have that width. What do you do?&lt;br /&gt;
Easiest thing I came up with is to scale whole content to fit (everything you declare in .tpl file). Tested or firefox and chrome.&lt;br /&gt;
&lt;br /&gt;
ggg_ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   &amp;lt;div id=&amp;quot;thething&amp;quot; class=&amp;quot;thething&amp;quot; style=&amp;quot;width: 1400px;&amp;quot;&amp;gt;&lt;br /&gt;
            ... everything else you declare ...&lt;br /&gt;
   &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setup : function(gamedatas) {&lt;br /&gt;
          console.log(&amp;quot;Starting game setup&amp;quot;);&lt;br /&gt;
          ...&lt;br /&gt;
          this.interface_min_width = 740;&lt;br /&gt;
          this.interface_max_width = 1400;&lt;br /&gt;
          dojo.connect(window, &amp;quot;onresize&amp;quot;, this, dojo.hitch(this, &amp;quot;adaptViewportSize&amp;quot;));&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    adaptViewportSize : function() {&lt;br /&gt;
        var pageid = &amp;quot;page-content&amp;quot;;&lt;br /&gt;
        var nodeid = &amp;quot;thething&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        var bodycoords = dojo.marginBox(pageid);&lt;br /&gt;
        var contentWidth = bodycoords.w;&lt;br /&gt;
&lt;br /&gt;
        var browserZoomLevel = window.devicePixelRatio; &lt;br /&gt;
        //console.log(&amp;quot;zoom&amp;quot;,browserZoomLevel);&lt;br /&gt;
        if (contentWidth &amp;gt;= this.interface_max_width || browserZoomLevel &amp;gt;1  || this.control3dmode3d) {&lt;br /&gt;
            dojo.style(nodeid,&#039;transform&#039;,&#039;&#039;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var percentageOn1 = contentWidth / this.interface_max_width;&lt;br /&gt;
        dojo.style(nodeid, &amp;quot;transform&amp;quot;, &amp;quot;scale(&amp;quot; + percentageOn1 + &amp;quot;)&amp;quot;);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this method does not seems to work to retina resolution displays, if you know better way let me know&lt;br /&gt;
&lt;br /&gt;
=== Dynamic tooltips ===&lt;br /&gt;
&lt;br /&gt;
If you really need a dynamic tooltip you can use this technique. (Only use it if the static tooltips provided by the BGA framework are not sufficient.)&lt;br /&gt;
&lt;br /&gt;
            new dijit.Tooltip({&lt;br /&gt;
                connectId: [&amp;quot;divItemId&amp;quot;],&lt;br /&gt;
                getContent: function(matchedNode){&lt;br /&gt;
                    return &amp;quot;... calculated ...&amp;quot;; &lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is an out-of-the-box djit.Tooltip. It has a &#039;&#039;getContent&#039;&#039; method which is called dynamically.&lt;br /&gt;
&lt;br /&gt;
The string function return becomes the innerHTML of the tooltip, so it can be anything. In this example matchedNode is a dojo node representing dom object with id of &amp;quot;divItemId&amp;quot; but there are more parameters which I am not posting here which allows more sophisticated subnode queries (i.e. you can attach tooltip to all nodes with class or whatever).&lt;br /&gt;
&lt;br /&gt;
[https://dojotoolkit.org/reference-guide/1.10/dijit/Tooltip.html dijit.Tooltip]&lt;br /&gt;
&lt;br /&gt;
It&#039;s not part of the BGA API so use at your own risk.&lt;br /&gt;
&lt;br /&gt;
=== Accessing images from js ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
     // your game resources&lt;br /&gt;
     &lt;br /&gt;
     var my_img = &#039;&amp;lt;img src=&amp;quot;&#039;+g_gamethemeurl+&#039;img/cards.jpg&amp;quot;/&amp;gt;&#039;;&lt;br /&gt;
     &lt;br /&gt;
     // shared resources&lt;br /&gt;
     var my_help_img = &amp;quot;&amp;lt;img class=&#039;imgtext&#039; src=&#039;&amp;quot; + g_themeurl + &amp;quot;img/layout/help_click.png&#039; alt=&#039;action&#039; /&amp;gt; &amp;lt;span class=&#039;tooltiptext&#039;&amp;gt;&amp;quot; +&lt;br /&gt;
                    text + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Rendering text with players color and proper background ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
This example actually writes &amp;quot;You&amp;quot; but you can replace this with player name as easily, drop translating function in this case&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        /* Implementation of proper colored You with background in case of white or light colors  */&lt;br /&gt;
 &lt;br /&gt;
        divYou : function() {&lt;br /&gt;
            var color = this.gamedatas.players[this.player_id].color;&lt;br /&gt;
            var color_bg = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.gamedatas.players[this.player_id] &amp;amp;&amp;amp; this.gamedatas.players[this.player_id].color_back) {&lt;br /&gt;
                color_bg = &amp;quot;background-color:#&amp;quot; + this.gamedatas.players[this.player_id].color_back + &amp;quot;;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            var you = &amp;quot;&amp;lt;span style=\&amp;quot;font-weight:bold;color:#&amp;quot; + color + &amp;quot;;&amp;quot; + color_bg + &amp;quot;\&amp;quot;&amp;gt;&amp;quot; + __(&amp;quot;lang_mainsite&amp;quot;, &amp;quot;You&amp;quot;) + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
            return you;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inject icon images in the log ===&lt;br /&gt;
&lt;br /&gt;
Here is an example of what was done for Terra Mystica which is simple and straightforward:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//Define the proper message&lt;br /&gt;
		$message = clienttranslate(&#039;${player_name} gets ${power_income} via Structures&#039;);&lt;br /&gt;
		if ($price &amp;gt; 0) {&lt;br /&gt;
			self::DbQuery(&amp;quot;UPDATE player SET player_score = player_score - $price WHERE player_id = $player_id&amp;quot;);&lt;br /&gt;
			$message = clienttranslate(&#039;${player_name} pays ${vp_price} and gets ${power_income} via Structures&#039;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
// Notify&lt;br /&gt;
		self::notifyAllPlayers( &amp;quot;powerViaStructures&amp;quot;, $message, array(&lt;br /&gt;
			&#039;i18n&#039; =&amp;gt; array( ),&lt;br /&gt;
			&#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
			&#039;player_name&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_name FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;power_tokens&#039; =&amp;gt; $power_tokens,&lt;br /&gt;
			&#039;vp_price&#039; =&amp;gt; self::getLogsVPAmount($price),&lt;br /&gt;
			&#039;power_income&#039; =&amp;gt; self::getLogsPowerAmount($power_income),&lt;br /&gt;
			&#039;newScore&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_score FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;counters&#039; =&amp;gt; $this-&amp;gt;getGameCounters(null),&lt;br /&gt;
		) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some functions to have the needed html added inside the substitution variable, such as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function getLogsPowerAmount( $amount ) {&lt;br /&gt;
		return &amp;quot;&amp;lt;div class=&#039;tmlogs_icon&#039; title=&#039;Power&#039;&amp;gt;&amp;lt;div class=&#039;power_amount&#039;&amp;gt;$amount&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: injecting html from php is not ideal but easy, if you want more clean solution, use method below but it is a lot more sophisticated.&lt;br /&gt;
&lt;br /&gt;
=== Inject images and styled html in the log ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php&lt;br /&gt;
&lt;br /&gt;
So you want nice pictures in the game log. What do you do? The first idea that comes to mind is to send html from php in notifications (see method above). &lt;br /&gt;
&lt;br /&gt;
This is a bad idea for many reasons:&lt;br /&gt;
&lt;br /&gt;
* It&#039;s bad architecture. ui elements leak into the server, and now you have to manage the ui in multiple places.&lt;br /&gt;
* If you decided to change something in the ui in future version, replay logs for old games and tutorials may not work, since they use stored notifications.&lt;br /&gt;
* Log previews for old games become unreadable. (This is the log state before you enter the game replay, which is useful for troubleshooting and game analysis.)&lt;br /&gt;
* It&#039;s more data to transfer and store in the db.&lt;br /&gt;
* It&#039;s a nightmare for translators.&lt;br /&gt;
&lt;br /&gt;
So what else can you do? I use this recipe for &#039;&#039;&#039;client side log injection&#039;&#039;&#039; to intercept log arguments (which come from the server) and replace them with html on the client side.&lt;br /&gt;
&lt;br /&gt;
[[File:clientloginjection.png|left]] &lt;br /&gt;
&lt;br /&gt;
ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
        /** Override this function to inject html into log items. This is a built-in BGA method.  */&lt;br /&gt;
&lt;br /&gt;
        /* @Override */&lt;br /&gt;
        format_string_recursive : function(log, args) {&lt;br /&gt;
            try {&lt;br /&gt;
                if (log &amp;amp;&amp;amp; args &amp;amp;&amp;amp; !args.processed) {&lt;br /&gt;
                    args.processed = true;&lt;br /&gt;
                    &lt;br /&gt;
&lt;br /&gt;
                    // list of special keys we want to replace with images&lt;br /&gt;
                    var keys = [&#039;place_name&#039;,&#039;token_name&#039;];&lt;br /&gt;
                    &lt;br /&gt;
                  &lt;br /&gt;
                    for ( var i in keys) {&lt;br /&gt;
                        var key = keys[i];&lt;br /&gt;
                        args[key] = this.getTokenDiv(key, args);                            &lt;br /&gt;
&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                console.error(log,args,&amp;quot;Exception thrown&amp;quot;, e.stack);&lt;br /&gt;
            }&lt;br /&gt;
            return this.inherited(arguments);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; In the &#039;&#039;format_string_recursive&#039;&#039; method, the &#039;args&#039; parameter will only contain arguments passed to it from the notify method in ggg.game.php (see below).&lt;br /&gt;
&lt;br /&gt;
The &#039;log&#039; parameter is the actual string that is inserted into the logs. You can perform additional js string manipulation on it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        getTokenDiv : function(key, args) {&lt;br /&gt;
            // ... implement whatever html you want here, example from sharedcode.js&lt;br /&gt;
            var token_id = args[key];&lt;br /&gt;
            var item_type = getPart(token_id,0);&lt;br /&gt;
            var logid = &amp;quot;log&amp;quot; + (this.globalid++) + &amp;quot;_&amp;quot; + token_id;&lt;br /&gt;
            switch (item_type) {&lt;br /&gt;
                case &#039;wcube&#039;:&lt;br /&gt;
                    var tokenDiv = this.format_block(&#039;jstpl_resource_log&#039;, {&lt;br /&gt;
                        &amp;quot;id&amp;quot; : logid,&lt;br /&gt;
                        &amp;quot;type&amp;quot; : &amp;quot;wcube&amp;quot;,&lt;br /&gt;
                        &amp;quot;color&amp;quot; : getPart(token_id,1),&lt;br /&gt;
                    });&lt;br /&gt;
                    return tokenDiv;&lt;br /&gt;
                    break;&lt;br /&gt;
                case &#039;meeple&#039;:&lt;br /&gt;
                    if ($(token_id)) {&lt;br /&gt;
                        var clone = dojo.clone($(token_id));&lt;br /&gt;
    &lt;br /&gt;
                        dojo.attr(clone, &amp;quot;id&amp;quot;, logid);&lt;br /&gt;
                        this.stripPosition(clone);&lt;br /&gt;
                        dojo.addClass(clone, &amp;quot;logitem&amp;quot;);&lt;br /&gt;
                        return clone.outerHTML;&lt;br /&gt;
                    }&lt;br /&gt;
                    break;&lt;br /&gt;
     &lt;br /&gt;
                default:&lt;br /&gt;
                    break;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return &amp;quot;&#039;&amp;quot; + this.clienttranslate_string(this.getTokenName(token_id)) + &amp;quot;&#039;&amp;quot;;&lt;br /&gt;
       },&lt;br /&gt;
       getTokenName : function(key) {&lt;br /&gt;
           return this.gamedatas.token_types[key].name; // get name for the key, from static table for example&lt;br /&gt;
       },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in this case the server simply injects token_id as a name, and the client substitutes it for the translated name or the picture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ggg.game.php:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name}&#039;),[&#039;token_name&#039;=&amp;gt;$token_id]);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; As noted above, only arguments actually passed by this method are available to the args parameter received in the client-side &#039;&#039;format_string_recursive&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is the case that you want to pass arguments that are not actually included in the output message. For example, suppose we have a method like this:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;tokenPlaced&#039;,clienttranslate(&#039;Player placed ${token_name}&#039;),array(&lt;br /&gt;
              &#039;token_name&#039; =&amp;gt; $token_id,&lt;br /&gt;
              &#039;zone_played&#039; =&amp;gt; $zone);&lt;br /&gt;
&lt;br /&gt;
This will output &amp;quot;Player placed ${token_name}&amp;quot; in the log, and if we subscribe to a notification method activated by the &amp;quot;tokenPlaced&amp;quot; event in the client-side code, that method can make use of the &#039;zone_played&#039; argument. &#039;&#039;&#039;But&#039;&#039;&#039; &#039;zone_played&#039; &#039;&#039;will not be available&#039;&#039; in the &#039;&#039;format_string_recursive&#039;&#039; method unless it is actually passed in the log message (i.e., in the string contained inside clienttranslate).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now if you don&#039;t like raw log containing id instead of name but want name, and want substitution, you can use another parameter as id. The problem with that,&lt;br /&gt;
it will work at first, but if you reload game using F5 you will loose your additional parameters, why? Because when game reloads it does not actually send same&lt;br /&gt;
notifications, it sends special &amp;quot;hitstorical_log&amp;quot; notification where all  parameters not listed in the &amp;quot;log&amp;quot; are removed. There is a hack (feature) to circumvent that,&lt;br /&gt;
called recursive parameters. I.e. you can send stuff like this:&lt;br /&gt;
 &lt;br /&gt;
             $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name_rec}&#039;),&lt;br /&gt;
                    [&#039;token_name_rec&#039;=&amp;gt;[&#039;log&#039;=&amp;gt;&#039;${token_name}&#039;,&lt;br /&gt;
                                        &#039;args&#039;=&amp;gt; [&#039;token_name&#039;=&amp;gt;clienttranslate(&#039;Boo&#039;), &#039;token_id&#039;=&amp;gt;$token_id, &#039;i18n&#039;=&amp;gt;[&#039;token_name&#039;] ]&lt;br /&gt;
                                       ]&lt;br /&gt;
                    ]);&lt;br /&gt;
&lt;br /&gt;
and in format_log_recursive&lt;br /&gt;
             var key = &#039;token_name&#039;;&lt;br /&gt;
             if (typeof args[key] == &#039;string&#039; &amp;amp;&amp;amp; typeof args[&#039;token_id&#039;] == &#039;string&#039;) {&lt;br /&gt;
                 args[key] = this.getTokenDiv(&#039;token_id&#039;, args);                            &lt;br /&gt;
             }&lt;br /&gt;
&lt;br /&gt;
=== High-Definition Graphics ===&lt;br /&gt;
&lt;br /&gt;
Some users will have screens which can display text and images at a greater resolution than the usual 72 dpi, e.g. the &amp;quot;Retina&amp;quot; screens on the 5k iMac, all iPads, and high-DPI screens on laptops from many manufacturers. If you can get art assets at this size, they will make your game look extra beautiful. You &#039;&#039;could&#039;&#039; just use large graphics and scale them down, but that would increase the download time and bandwidth for users who can&#039;t display them. Instead, a good way is to prepare a separate graphics file at exactly twice the size you would use otherwise, and add &amp;quot;@2x&amp;quot; at the end of the filename, e.g. if pieces.png is 240x320, then pieces@2x.png is 480x640.&lt;br /&gt;
&lt;br /&gt;
There are two changes required in order to use the separate graphics files. First in your css, where you use a file, add a media query which overrides the original definition and uses the bigger version on devices which can display them. Ensuring that the &amp;quot;background-size&amp;quot; attribute is set means that the size of the displayed object doesn&#039;t change, but only is drawn at the improved dot pitch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.piece {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    background-image: url(&#039;img/pieces.png&#039;);&lt;br /&gt;
    background-size:240px 320px;&lt;br /&gt;
    z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&lt;br /&gt;
{&lt;br /&gt;
    .piece {&lt;br /&gt;
        background-image: url(&#039;img/pieces@2x.png&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Secondly, in your setup function in javascript, you must ensure than only the appropriate one version of the file gets pre-loaded (otherwise you more than waste the bandwidth saved by maintaining the standard-resolution file). Note that the media query is the same in both cases:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            var isRetina = &amp;quot;(-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&amp;quot;;&lt;br /&gt;
            if (window.matchMedia(isRetina).matches)&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces@2x.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board@2x.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Cool realistic shadow effect with CSS ===&lt;br /&gt;
&lt;br /&gt;
If you wish to make a shadow effect for game pieces that are not rectangle, do not use box-shadow but use filter, which is supported by recent major browsers.  This way, you can use the alpha channel of your element to drop a shadow.  This even work for transparent backgrounds, so that if you are using the &amp;quot;CSS-sprite&amp;quot; method, it will work!&lt;br /&gt;
&lt;br /&gt;
For instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.xxx-token {&lt;br /&gt;
    filter: drop-shadow(0px 0px 1px #000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Using the CSS classes from the state machine ===&lt;br /&gt;
&lt;br /&gt;
If you need to hide or show stuff depending on the state of your game, you can of course use javascript, but CSS is hand enough for that.  The #overall-content element does change class depending on the game state.  For instance, if you are in state &#039;&#039;playerTurn&#039;&#039;, it will have the class &#039;&#039;gamestate_playerTurn&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
So now, if you want to show the discard pile only during player turns, you may use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#discard_pile { display: none }&lt;br /&gt;
.gamestate_playerTurn #discard_pile { display: block }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This can be used if you want to change sizing of elements, position, layout or visual appearance.&lt;br /&gt;
&lt;br /&gt;
=== More readable JS: onEnteringState ===&lt;br /&gt;
&lt;br /&gt;
If you have a lot of states onEnteringState and friends become rather wild, you can do this trick to call some method dynamically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
     onEnteringState: function(stateName, args) {&lt;br /&gt;
       console.log(&#039;Entering state: &#039; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
       // Call appropriate method&lt;br /&gt;
       var methodName = &amp;quot;onEnteringState_&amp;quot; + stateName;&lt;br /&gt;
       if (this[methodName] !== undefined) {             &lt;br /&gt;
          console.log(&#039;Calling &#039; + methodName, args.args);&lt;br /&gt;
          this[methodName](args.args);&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerTurn: function(args) { // this is args directly, not args.args &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerSomethingElse: function(args) { &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: since its ignores the undefined functions you don&#039;t have define function for each state, but on the other hand you cannot make typos.&lt;br /&gt;
Same applies to onUpdateActionButtons except you pass &#039;args&#039; to method, not args.args, and for onLeavingState where you don&#039;t pass anything.&lt;br /&gt;
&lt;br /&gt;
== Game Model and Database design ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Database for The euro game ===&lt;br /&gt;
Lets say we have a game with workers, dice, tokens, board, resources, money and vp. Workers and dice can be placed in various zones on the board, and you can get resources, money, tokens and vp in your home zone. Also tokens can be flipped or not flipped.&lt;br /&gt;
&lt;br /&gt;
[[File:Madeira board.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now lets try to map it, we have&lt;br /&gt;
* (meeple,zone)&lt;br /&gt;
* (die, zone, sideup)&lt;br /&gt;
* (resource cube/money token/vp token,player home zone)&lt;br /&gt;
* (token, player home zone, flip state)&lt;br /&gt;
We can notice that resource and money are uncountable, and don&#039;t need to be track individually so we can replace our mapping to&lt;br /&gt;
* (resource type/money,player home zone, count)&lt;br /&gt;
And vp stored already for us in player table, so we can remove it from that list.&lt;br /&gt;
&lt;br /&gt;
Now when we get to encode it we can see that everything can be encoded as (object,zone,state) form, where object and zone is string and state is integer. The resource mapping is slightly different semantically so you can go with two table, or counting using same table with state been used as count for resources.&lt;br /&gt;
&lt;br /&gt;
So the piece mapping for non-grid based games can be in most case represented by (string: token_key, string: token_location, int: token_state), example of such database schema can be found here: [https://github.com/elaskavaia/bga-sharedcode/blob/master/dbmodel.sql dbmodel.sql] and class implementing access to it here [https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php table.game.php].&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|meeple_red_1&lt;br /&gt;
|home_red&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|dice_black_2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|dice_green_1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|bread&lt;br /&gt;
|home_red&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Now how we represent resource counters such as bread?&lt;br /&gt;
Using same table from we simply add special counter token for bread and use state to indicate the count. Note to keep first column unique we have to add player identification for that counter, i.e. ff0000 is red player.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|bread_ff0000&lt;br /&gt;
|tableau_ff0000&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
See php module for this table here https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php&lt;br /&gt;
&lt;br /&gt;
Variant 2: Additional resource table, resource count for each player id&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `resource` (&lt;br /&gt;
  `player_id` int(10) unsigned NOT NULL,&lt;br /&gt;
  `resource_key` varchar(32) NOT NULL,&lt;br /&gt;
  `resource_count` int(10) signed NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`player_id`,`resource_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
 ALTER TABLE resource ADD CONSTRAINT fk_player_id FOREIGN KEY (player_id) REFERENCES player(player_id);&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+resource&lt;br /&gt;
! player_id&lt;br /&gt;
! resource_key&lt;br /&gt;
! resource_count&lt;br /&gt;
|-&lt;br /&gt;
|123456&lt;br /&gt;
|bread&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 3: More normalised&lt;br /&gt;
&lt;br /&gt;
This version is similar to &amp;quot;card&amp;quot; table from hearts tutorial, you can also use exact cards database schema and Deck implementation for most purposes (even you not dealing with cards). &lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `token_type` varchar(16) NOT NULL,&lt;br /&gt;
  `token_arg` int(11) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_id`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_id&lt;br /&gt;
! token_type&lt;br /&gt;
! token_arg&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|22&lt;br /&gt;
|meeple&lt;br /&gt;
|123456&lt;br /&gt;
|home_123456&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|23&lt;br /&gt;
|dice&lt;br /&gt;
|2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|26&lt;br /&gt;
|dice&lt;br /&gt;
|1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|49&lt;br /&gt;
|bread&lt;br /&gt;
|0&lt;br /&gt;
|home_123456&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Advantages of this would be is a bit more straightforward to do some queries in db, disadvantage its hard to read (as you can compare with previous example, you&lt;br /&gt;
cannot just look at say, ah I know what it means). Another questionable advantage is it allows you to do id randomisation, so it hard to do crafted queries to &lt;br /&gt;
cheat, the down side of that you cannot understand it either, and handcraft db states for debugging or testing.&lt;br /&gt;
&lt;br /&gt;
=== Database for The card game ===&lt;br /&gt;
&lt;br /&gt;
Lets say you have a standard card game, player have hidden cards in hand, you can draw card from draw deck, play card on tableau and discard to discard pile.&lt;br /&gt;
We have to design database for such game.&lt;br /&gt;
&lt;br /&gt;
In real word to &amp;quot;save&amp;quot; the game we take a picture a play area, save cards from it, then put away draw deck, discard and hand of each player separately and mark it, also we will record current scoring (if any) and who&#039;s turn was it.&lt;br /&gt;
&lt;br /&gt;
* Framework handles state machine transition, so you don&#039;t have to worry about database design for that (i.e. who&#039;s turn it is, what phase of the game we are at, you still have to design it but part of state machine step)&lt;br /&gt;
* Also framework supports basic player information, color, order around the table, basic scoring, etc, so you don&#039;t have to worry about it either&lt;br /&gt;
* The only thing you need in our database is state of the &amp;quot;board&amp;quot;, which is &amp;quot;where each pieces is, and in what state&amp;quot;, or (position,rotation) pair.&lt;br /&gt;
&lt;br /&gt;
Lets see what we have for that:&lt;br /&gt;
* The card state is very simple, its usually &amp;quot;face up/face down&amp;quot;, &amp;quot;tapped/untapped&amp;quot;, &amp;quot;right side up/up side down&amp;quot;&lt;br /&gt;
* As position go we never need real coordinates x,y,z. We need to know what &amp;quot;zone&amp;quot; card was, and depending on the zone it may sometimes need an extra &amp;quot;z&amp;quot; or &amp;quot;x&amp;quot; as card order. The zone position usually static or irrelevant.&lt;br /&gt;
* So our model is: we have cards, which have some attributes, at any given point in time they belong to a &amp;quot;zone&amp;quot;, and can also have order and state&lt;br /&gt;
* Now for mapping we should consider what information changes and what information is static, later is always candidate for material file&lt;br /&gt;
* For dynamic information we should try to reduce amount of fields we need&lt;br /&gt;
**  we need at least a field for card, so its one&lt;br /&gt;
**  we need to know what zone cards belong to, its 2&lt;br /&gt;
**  and we have possibly few other fields, if you look closely at you game you may find out that most of the zone only need one attribute at a time, i.e. draw pile always have cards face down, hand always face up, also for hand and discard order does not matter at all (but for draw it does matter). So in majority of cases we can get away with one single extra integer field representing state or order&lt;br /&gt;
* In real database both card and zone will be integers as primary keys referring to additional tables, but in our case its total overkill, so they can be strings as easily&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_key` varchar(32) unsigned NOT NULL,&lt;br /&gt;
  `card_location` varchar(32) NOT NULL,&lt;br /&gt;
  `card_state` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 2: More normalised&lt;br /&gt;
&lt;br /&gt;
This version supported by Deck php class, so unless you want to rewrite db access layer go with this one&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you using this schema, some zones/locations have special semantic. The &#039;hand&#039; location is actually multiple locations - one per player, but player id is encoded as card_location_arg. If &#039;hand&#039; in your game is ordered, visible or can have some other card states, you cannot use hand location (replacement is hand_&amp;lt;player_id&amp;gt; or hand_&amp;lt;color_id&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
== Game Modules ==&lt;br /&gt;
&lt;br /&gt;
=== Including your own JavaScript module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, modules/ggg_other.js&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.js in modules/ folder and sync&lt;br /&gt;
* Modify ggg.js to include it&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  define([ &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;, &amp;quot;ebg/core/gamegui&amp;quot;, &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    // load my own module!!!&lt;br /&gt;
    g_gamethemeurl + &amp;quot;modules/ggg_other.js&amp;quot; ], function(dojo,&lt;br /&gt;
        declare) {&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Including your own PHP module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, modules/ggg_other.php&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.php in modules/ folder and sync&lt;br /&gt;
* Modify ggg.game.php to include it&lt;br /&gt;
&lt;br /&gt;
 require_once (&#039;modules/ggg_other.php&#039;);&lt;br /&gt;
&lt;br /&gt;
=== Creating a test class to run PHP locally ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, stubs&lt;br /&gt;
For this you need stubs of other method you can use this for example&lt;br /&gt;
https://github.com/elaskavaia/bga-sharedcode/raw/master/misc/module/table/table.game.php&lt;br /&gt;
&lt;br /&gt;
Create another php files, i.e ggg_test.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
define(&amp;quot;APP_GAMEMODULE_PATH&amp;quot;, &amp;quot;misc/&amp;quot;); // include path to stubs, which defines &amp;quot;table.game.php&amp;quot; and other classes&lt;br /&gt;
require_once (&#039;eminentdomaine.game.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class MyGameTest1 extends MyGame { // this is your game class defined in ggg.game.php&lt;br /&gt;
    function __construct() {&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        include &#039;../material.inc.php&#039;;// this is how this normally included, from constructor&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // override/stub methods here that access db and stuff&lt;br /&gt;
    function getGameStateValue($var) {&lt;br /&gt;
        if ($var == &#039;round&#039;)&lt;br /&gt;
            return 3;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
$x = new MyGameTest1(); // instantiate your class&lt;br /&gt;
$p = $x-&amp;gt;getGameProgression(); // call one of the methods to test&lt;br /&gt;
if ($p != 50)&lt;br /&gt;
    echo &amp;quot;Test1: FAILED&amp;quot;;&lt;br /&gt;
else&lt;br /&gt;
    echo &amp;quot;Test1: PASSED&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run from command line like&lt;br /&gt;
 php7 ggg_test.php&lt;br /&gt;
&lt;br /&gt;
If you do it this way - you can also use local php debugger (i.e. integrated with IDE or command line).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Avoiding code in dojo declare style ===&lt;br /&gt;
Dojo class declarations are rather bizzare and do not work with most IDEs.&lt;br /&gt;
If you want to write in plain JS with classes, you can stub all the dojo define/declare stuff&lt;br /&gt;
and hook your class into that, so the classes are outside of this mess.&lt;br /&gt;
&lt;br /&gt;
NOTE: this technique is for experienced developers, do not try it if you do not understand&lt;br /&gt;
the consequences.&lt;br /&gt;
&lt;br /&gt;
This is complete example of game .js class&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Testla is game name is has to be changed&lt;br /&gt;
class Testla {&lt;br /&gt;
	constructor(game) {&lt;br /&gt;
		console.log(&#039;game constructor&#039;);&lt;br /&gt;
		this.game = game;&lt;br /&gt;
		this.varfoo = new MyFoo(); // this example of class from custom module&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	setup(gamedatas) {&lt;br /&gt;
		console.log(&amp;quot;Starting game setup&amp;quot;, this.varfoo);&lt;br /&gt;
		this.gamedatas = gamedatas;&lt;br /&gt;
		this.dojo.create(&amp;quot;div&amp;quot;, { class: &#039;whiteblock&#039;, innerHTML: _(&amp;quot;hello&amp;quot;) }, &#039;thething&#039;);&lt;br /&gt;
		console.log(&amp;quot;Ending game setup&amp;quot;);&lt;br /&gt;
	};&lt;br /&gt;
	onEnteringState(stateName, args) {&lt;br /&gt;
		console.log(&#039;onEnteringState : &#039; + stateName, args);&lt;br /&gt;
		this.game.addActionButton(&#039;b1&#039;,_(&#039;Click Me&#039;), (e)=&amp;gt;this.onButtonClick(e));&lt;br /&gt;
	};&lt;br /&gt;
	onLeavingState(stateName) {&lt;br /&gt;
		console.log(&#039;onLeavingState : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onUpdateActionButtons(stateName, args) {&lt;br /&gt;
		console.log(&#039;onUpdateActionButtons : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onButtonClick(event) {&lt;br /&gt;
		console.log(&#039;onButtonClick&#039;,event);&lt;br /&gt;
	};&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
define([&lt;br /&gt;
	&amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
	g_gamethemeurl + &#039;/modules/foo.js&#039; // custom module if needed&lt;br /&gt;
],&lt;br /&gt;
	function(dojo, declare) {&lt;br /&gt;
                // testla is game name is has to be changed&lt;br /&gt;
		return declare(&amp;quot;bgagame.testla&amp;quot;, ebg.core.gamegui, {&lt;br /&gt;
			constructor: function() {&lt;br /&gt;
				this.xapp = new Testla(this);&lt;br /&gt;
				this.xapp.dojo = dojo;&lt;br /&gt;
			},&lt;br /&gt;
			setup: function(gamedatas) {&lt;br /&gt;
				this.xapp.setup(gamedatas);&lt;br /&gt;
			},&lt;br /&gt;
			onEnteringState: function(stateName, args) {&lt;br /&gt;
				this.xapp.onEnteringState(stateName, args.args);&lt;br /&gt;
			},&lt;br /&gt;
			onLeavingState: function(stateName) {&lt;br /&gt;
				this.xapp.onLeavingState(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
			onUpdateActionButtons: function(stateName, args) {&lt;br /&gt;
				this.xapp.onUpdateActionButtons(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
		});&lt;br /&gt;
	});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Assorted Stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Out-of-turn actions: Un-pass ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg.action.php, states.inc.php&lt;br /&gt;
&lt;br /&gt;
In multiplayer game sometimes players passes but than they think more and want to un-Pass and redo their choice. &lt;br /&gt;
To re-active a player who passes some trickery required.&lt;br /&gt;
&lt;br /&gt;
Define a special action that does how and hook it up.&lt;br /&gt;
&lt;br /&gt;
In states.inc.php add an action to mmultipleactiveplayer state to &amp;quot;unpass&amp;quot;, lets call it &amp;quot;actionCancel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In ggg.action.php add action hook&lt;br /&gt;
    public function actionCancel() {&lt;br /&gt;
        self::setAjaxMode();&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;actionCancel();&lt;br /&gt;
        self::ajaxResponse();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
In ggg.game.php add action handler&lt;br /&gt;
    function actionCancel() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction(&#039;actionCancel&#039;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive(array ($this-&amp;gt;getCurrentPlayerId() ), &#039;error&#039;, false);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Finally to call this in client ggg.js you would do something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 onUpdateActionButtons:  function(stateName, args) {&lt;br /&gt;
   if (this.isCurrentPlayerActive()) { &lt;br /&gt;
     // ...&lt;br /&gt;
   } else if (!this.isSpectator) { // player is NOT active but not spectatoe&lt;br /&gt;
       switch (stateName) {&lt;br /&gt;
          case &#039;playerTurnMuliPlayerState&#039;:&lt;br /&gt;
		this.addActionButton(&#039;button_unpass&#039;, _(&#039;Oh no!&#039;), &#039;onUnpass&#039;);&lt;br /&gt;
		break;&lt;br /&gt;
	}&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
				&lt;br /&gt;
 onUnpass: function(e) {&lt;br /&gt;
    this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; +  this.game_name + &amp;quot;/actionCancel.html&amp;quot;, {}, this); // no checkAction!&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Although be careful that if the turn comes back to the player while he is about to click cancel, the action buttons will be updated and the player will misclick which can be quite frustrating. To avoid this, move the cancel button to another position, like to the left of pagemaintitletext:&lt;br /&gt;
  dojo.place(&#039;button_unpass&#039;, &#039;pagemaintitletext&#039;, &#039;before&#039;);&lt;br /&gt;
Being out of the generalactions div, it won&#039;t be automatically destroyed like normal buttons, so you&#039;ll have to handle that yourself in onLeavingState. You might also want to change the button color to red (blue buttons for active player only, red buttons also for inactive players?)&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Selection ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Simple way to implement something like that without extra states is to use &amp;quot;selection&amp;quot; mechanism. When user click on worker add some sort of class into that element i.e. &#039;selected&#039; (which also have to have some indication by css i.e. outline).&lt;br /&gt;
&lt;br /&gt;
Than user can click on placement zone, you can use dojo.query for &amp;quot;selected&amp;quot; element and use it along with zone id to send data to server. If proper worker is not selected yet can give a error message using this.showMessage(...) function.&lt;br /&gt;
&lt;br /&gt;
Extra code required to properly cleanup selection between states&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Client States ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
I don&#039;t think its documented feature but there is a way to do client-only states, which is absolutely wonderful for few reasons&lt;br /&gt;
* When player interaction is two step process, such as select worker, place worker, or place worker, pick one of two resources of your choice&lt;br /&gt;
* When multi-step process can result of impossible situation and has to be undone (by rules)&lt;br /&gt;
* When multi-step process is triggered from multiple states (such as you can do same thing as activated card action, pass action or main action)&lt;br /&gt;
&lt;br /&gt;
So lets do Select Worker/Place Worker&lt;br /&gt;
&lt;br /&gt;
Define your server state as usual, i.e. playerMainTurn -&amp;gt; &amp;quot;You must pick up a worker&amp;quot;.&lt;br /&gt;
Now define a client state, we only need &amp;quot;name&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;, lets say &amp;quot;client_playerPicksLocation&amp;quot;. Always prefix names of client state with &amp;quot;client_&amp;quot; to avoid confusion. Now we have to do the following:&lt;br /&gt;
* Have a handler for onUpdateActionButtons for playerMainTurn to activate all possible workers he can pick&lt;br /&gt;
* When player clicks workers, remember the worker in one of the members of the main class, I usually use one called this.clientStateArgs.&lt;br /&gt;
* Transition to new client state&lt;br /&gt;
  onWorker: function(e) {&lt;br /&gt;
      var id = event.currentTarget.id;&lt;br /&gt;
      dojo.stopEvent(event);&lt;br /&gt;
      ... // do validity checks&lt;br /&gt;
      this.clientStateArgs.worker_id = id;&lt;br /&gt;
      this.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                                descriptionmyturn : &amp;quot;${you} must select location&amp;quot;,&lt;br /&gt;
                            });&lt;br /&gt;
   }&lt;br /&gt;
* Have a handler for onUpdateActionButtons for client_playerPicksLocation to activate all possible locations this worker can go AND add Cancel button (see below)&lt;br /&gt;
* Have a location handler which will eventually send a server request, using stored this.clientStateArgs.worker_id as worker id&lt;br /&gt;
* The cancel button should call a method to restore server state, also if you doing it for more than one state you can add this universally using this.on_client_state check&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        if (this.isCurrentPlayerActive()) {&lt;br /&gt;
          if (this.on_client_state &amp;amp;&amp;amp; !$(&#039;button_cancel&#039;)) {&lt;br /&gt;
               this.addActionButton(&#039;button_cancel&#039;, _(&#039;Cancel&#039;), dojo.hitch(this, function() {&lt;br /&gt;
                                             this.restoreServerGameState();&lt;br /&gt;
               }));&lt;br /&gt;
          }&lt;br /&gt;
        } &lt;br /&gt;
Note: usually I call my own function call this.cancelLocalStateEffects() which will do more stuff first then call restoreServerGameState(), same function is usually needs to be called when server request has failed (i.e. invalid move)&lt;br /&gt;
&lt;br /&gt;
Note: If you need more than 2 steps, you may have to do client side animation to reflect the new state, which gets trickier because you have to undo that also on cancellation.&lt;br /&gt;
&lt;br /&gt;
Code is available here [https://github.com/elaskavaia/bga-sharedcode/blob/master/sharedcode.js sharedcode.js] (its using playerTurnPlayCubes and client_selectCubeLocation).&lt;br /&gt;
&lt;br /&gt;
=== Assigning Player Order ===&lt;br /&gt;
Normally when game starts there is &amp;quot;natural&amp;quot; player order assigned randomly.&lt;br /&gt;
&lt;br /&gt;
If you want to deliberatly assign player order at the start of the game (for example, in a game with teams options), you can do so by retrieving the initialization-only player attribute &#039;&#039;&#039;player_table_order&#039;&#039;&#039; and using it to assign values to &#039;&#039;&#039;player_no&#039;&#039;&#039; (which is normally assigned at the start of a game in the order in which players come to the table). (See [https://en.doc.boardgamearena.com/Game_database_model:_dbmodel.sql#The_player_table Game database model] for more details.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                // Retrieve inital player order ([0=&amp;gt;playerId1, 1=&amp;gt;playerId2, ...])&lt;br /&gt;
		$playerInitialOrder = [];&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$playerInitialOrder[$player[&#039;player_table_order&#039;]] = $playerId;&lt;br /&gt;
		}&lt;br /&gt;
		ksort($playerInitialOrder);&lt;br /&gt;
		$playerInitialOrder = array_flip(array_values($playerInitialOrder));&lt;br /&gt;
&lt;br /&gt;
		// Player order based on &#039;playerTeams&#039; option&lt;br /&gt;
		$playerOrder = [0, 1, 2, 3];&lt;br /&gt;
		switch (self::getGameStateValue(&#039;playerTeams&#039;)) {&lt;br /&gt;
			case self::TEAM_1_2:&lt;br /&gt;
				$playerOrder = [0, 2, 1, 3];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_1_4:&lt;br /&gt;
				$playerOrder = [0, 1, 3, 2];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_RANDOM:&lt;br /&gt;
				shuffle($playerOrder);&lt;br /&gt;
				break;&lt;br /&gt;
			default:&lt;br /&gt;
			case self::TEAM_1_3:&lt;br /&gt;
				// Default order&lt;br /&gt;
				break;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                // Create players&lt;br /&gt;
		// Note: if you added some extra field on &amp;quot;player&amp;quot; table in the database (dbmodel.sql), you can initialize it there.&lt;br /&gt;
		$sql =&lt;br /&gt;
			&#039;INSERT INTO player (player_id, player_color, player_canal, player_name, player_avatar, player_no) VALUES &#039;;&lt;br /&gt;
		$values = [];&lt;br /&gt;
&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$color = array_shift($default_colors);&lt;br /&gt;
			$values[] =&lt;br /&gt;
				&amp;quot;(&#039;&amp;quot; .&lt;br /&gt;
				$playerId .&lt;br /&gt;
				&amp;quot;&#039;,&#039;$color&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$player[&#039;player_canal&#039;] .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_name&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_avatar&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$playerOrder[$playerInitialOrder[$playerId]] .&lt;br /&gt;
				&amp;quot;&#039;)&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
		$sql .= implode(&#039;,&#039;, $values);&lt;br /&gt;
		self::DbQuery($sql);&lt;br /&gt;
		self::reattributeColorsBasedOnPreferences(&lt;br /&gt;
			$players,&lt;br /&gt;
			$gameinfos[&#039;player_colors&#039;]&lt;br /&gt;
		);&lt;br /&gt;
		self::reloadPlayersBasicInfos();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=7100</id>
		<title>BGA Code Sharing</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=7100"/>
		<updated>2021-01-29T04:17:33Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Projects hosted not in studio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is for listing of externally hosted bga projects, tools and resources, as well as internal project&lt;br /&gt;
intended for sharing&lt;br /&gt;
&lt;br /&gt;
== Projects hosted not in studio ==&lt;br /&gt;
&lt;br /&gt;
See the table a link and nickname of the developer on bga (same as used for dev forum), and short description. See [[Tools_and_tips_of_BGA_Studio#Version_Control]] for some suggestions on how and where to publish your code externally. Also see the [https://github.com/topics/boardgamearena boardgamearena] tag on github.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important notice about artwork on BGA Open Source projects: original hi-resolution images from publishers must not be published on the repositories. In addition, it is better to specify that the images derivated from publishers artwork are copyrighted and cannot be licensed under a free license like Creative Commons.&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NON-GAME PROJECTS&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| BoardGameArena Workbench (not a game)&lt;br /&gt;
| https://github.com/danielholmes/bga-workbench&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
! GAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| 99 (Trick-taking Card Game)&lt;br /&gt;
| https://github.com/ekelly/bga-ninetynine&lt;br /&gt;
| QuasarDukeDev&lt;br /&gt;
|-&lt;br /&gt;
| Assyria &lt;br /&gt;
| https://github.com/sebastien-prudhomme/bga-assyria&lt;br /&gt;
| daikinee &lt;br /&gt;
|-&lt;br /&gt;
| Bandido &lt;br /&gt;
| https://github.com/opheliehb/BandidoBGA&lt;br /&gt;
| ophelopede &amp;amp; Harkle &lt;br /&gt;
|-&lt;br /&gt;
| The Battle for Hill 218&lt;br /&gt;
| https://github.com/danielholmes/battle-for-hill-218&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
| Bonbons&lt;br /&gt;
| https://github.com/AntonioSoler/bga-bonbons&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Coinche&lt;br /&gt;
| https://github.com/drasill/bga-coinche&lt;br /&gt;
| Draasill&lt;br /&gt;
|-&lt;br /&gt;
| Coup: City State&lt;br /&gt;
| https://github.com/quietmint/bga-coupcitystate&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dungeon Roll&lt;br /&gt;
| https://github.com/MartinGoulet/bga-dungeonroll&lt;br /&gt;
| MGoulet&lt;br /&gt;
|-&lt;br /&gt;
| Egyptian Ratscrew&lt;br /&gt;
| https://github.com/0BuRner/bga-egyptianratscrew&lt;br /&gt;
| 0BuRner&lt;br /&gt;
|-&lt;br /&gt;
| Eruption&lt;br /&gt;
| https://github.com/AndyKerrison/bga-eruption&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| A Fistful Of Gold&lt;br /&gt;
| https://bitbucket.org/Joel_L/fistfulofgold&lt;br /&gt;
| Brainchild&lt;br /&gt;
|-&lt;br /&gt;
| Florenza: The Card Game&lt;br /&gt;
| https://github.com/alberto-bottarini/bga-florenza&lt;br /&gt;
| tarini &lt;br /&gt;
|-&lt;br /&gt;
| Hearts &#039;&#039;&#039;(Tutorial)&#039;&#039;&#039;&lt;br /&gt;
| https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Incan Gold&lt;br /&gt;
| https://github.com/AntonioSoler/bga-incangold&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Marco Polo&lt;br /&gt;
| https://github.com/rcitaliano/MarcoPolo&lt;br /&gt;
| rcitaliano&lt;br /&gt;
|-&lt;br /&gt;
| Nile&lt;br /&gt;
| https://github.com/AndyKerrison/bga-nile&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| Noir: Killer vs Inspector&lt;br /&gt;
| https://bitbucket.org/chhuang76/bga_noirkvi&lt;br /&gt;
| ch huang&lt;br /&gt;
|-&lt;br /&gt;
| Penny Press&lt;br /&gt;
| https://github.com/AdamNovotny/bga-blooms&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| P.I.&lt;br /&gt;
| https://gitlab.com/fa81/bga-pi, https://github.com/hellp/bga-pi (mirror)&lt;br /&gt;
| Fabian Neumann (fa81)&lt;br /&gt;
|-&lt;br /&gt;
| Santorini&lt;br /&gt;
| https://github.com/AntonioSoler/bga-santorini&lt;br /&gt;
| Morgalad, quietmint, Tisaac&lt;br /&gt;
|-&lt;br /&gt;
| Tablut&lt;br /&gt;
| https://github.com/Lucas-C/tablut&lt;br /&gt;
| Lucas-C &amp;amp; ntaffore&lt;br /&gt;
|-&lt;br /&gt;
| Takara Island&lt;br /&gt;
| https://github.com/AntonioSoler/bga-takaraisland&lt;br /&gt;
| Morgalad&lt;br /&gt;
|-&lt;br /&gt;
| Taluva&lt;br /&gt;
| https://github.com/quietmint/bga-taluva&lt;br /&gt;
| Morgalad &amp;amp; quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Teotihuacan: City of Gods&lt;br /&gt;
| https://github.com/Trompetenhut/bga-teotihuacan&lt;br /&gt;
| Trompetenhut&lt;br /&gt;
|-&lt;br /&gt;
| Via Magica&lt;br /&gt;
| https://github.com/christopherburke/bga_viamagica&lt;br /&gt;
| CuriousTerran&lt;br /&gt;
|-&lt;br /&gt;
| Just Desserts&lt;br /&gt;
| https://github.com/mizutismask/bga-just-desserts&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| The King&#039;s Guild&lt;br /&gt;
| https://github.com/AdamNovotny/BGG-KingsGuild&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| Get the MacGuffin&lt;br /&gt;
| https://github.com/mizutismask/bga-get-the-MacGuffin&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| President&lt;br /&gt;
| https://github.com/quaresma95/president&lt;br /&gt;
| quaresma95&lt;br /&gt;
|-&lt;br /&gt;
| Hardback&lt;br /&gt;
| https://github.com/quietmint/bga-hardback&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects on studio ==&lt;br /&gt;
&lt;br /&gt;
Links to studio project which owner wish share as read only.&lt;br /&gt;
Project owner please add you project here, dev nickname and short description if you would like to share it.&lt;br /&gt;
For the projects below any developer can add themselves to a project as read-only from http://en.studio.boardgamearena.com/#!projects page.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code&lt;br /&gt;
| http://en.studio.boardgamearena.com/#!studiogame?game=sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Original BGA template&lt;br /&gt;
| http://en.studio.boardgamearena.com/#!studiogame?game=template&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other useful resources ==&lt;br /&gt;
&lt;br /&gt;
Moved to [[Tools_and_tips_of_BGA_Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=7099</id>
		<title>BGA Code Sharing</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=7099"/>
		<updated>2021-01-29T04:16:49Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Projects hosted not in studio */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is for listing of externally hosted bga projects, tools and resources, as well as internal project&lt;br /&gt;
intended for sharing&lt;br /&gt;
&lt;br /&gt;
== Projects hosted not in studio ==&lt;br /&gt;
&lt;br /&gt;
See the table a link and nickname of the developer on bga (same as used for dev forum), and short description. See [[Tools_and_tips_of_BGA_Studio#Version_Control]] for some suggestions on how and where to publish your code externally. Also see the [https://github.com/topics/boardgamearena boardgamearena] tag on github.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important notice about artwork on BGA Open Source projects: original hi-resolution images from publishers must not be published on the repositories. In addition, it is better to specify that the images derivated from publishers artwork are copyrighted and cannot be licensed under a free license like Creative Commons.&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NON-GAME PROJECTS&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code (not a game)&lt;br /&gt;
| https://github.com/elaskavaia/bga-sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| BoardGameArena Workbench (not a game)&lt;br /&gt;
| https://github.com/danielholmes/bga-workbench&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
! GAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| 99 (Trick-taking Card Game)&lt;br /&gt;
| https://github.com/ekelly/bga-ninetynine&lt;br /&gt;
| QuasarDukeDev&lt;br /&gt;
|-&lt;br /&gt;
| Assyria &lt;br /&gt;
| https://github.com/sebastien-prudhomme/bga-assyria&lt;br /&gt;
| daikinee &lt;br /&gt;
|-&lt;br /&gt;
| Bandido &lt;br /&gt;
| https://github.com/opheliehb/BandidoBGA&lt;br /&gt;
| ophelopede &amp;amp; Harkle &lt;br /&gt;
|-&lt;br /&gt;
| The Battle for Hill 218&lt;br /&gt;
| https://github.com/danielholmes/battle-for-hill-218&lt;br /&gt;
| Daniel Holmes (dhau)&lt;br /&gt;
|-&lt;br /&gt;
| Bonbons&lt;br /&gt;
| https://github.com/AntonioSoler/bga-bonbons&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Coinche&lt;br /&gt;
| https://github.com/drasill/bga-coinche&lt;br /&gt;
| Draasill&lt;br /&gt;
|-&lt;br /&gt;
| Coup: City State&lt;br /&gt;
| https://github.com/quietmint/bga-coupcitystate&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Dungeon Roll&lt;br /&gt;
| https://github.com/MartinGoulet/bga-dungeonroll&lt;br /&gt;
| MGoulet&lt;br /&gt;
|-&lt;br /&gt;
| Egyptian Ratscrew&lt;br /&gt;
| https://github.com/0BuRner/bga-egyptianratscrew&lt;br /&gt;
| 0BuRner&lt;br /&gt;
|-&lt;br /&gt;
| Eruption&lt;br /&gt;
| https://github.com/AndyKerrison/bga-eruption&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| A Fistful Of Gold&lt;br /&gt;
| https://bitbucket.org/Joel_L/fistfulofgold&lt;br /&gt;
| Brainchild&lt;br /&gt;
|-&lt;br /&gt;
| Florenza: The Card Game&lt;br /&gt;
| https://github.com/alberto-bottarini/bga-florenza&lt;br /&gt;
| tarini &lt;br /&gt;
|-&lt;br /&gt;
| Hearts &#039;&#039;&#039;(Tutorial)&#039;&#039;&#039;&lt;br /&gt;
| https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Incan Gold&lt;br /&gt;
| https://github.com/AntonioSoler/bga-incangold&lt;br /&gt;
| Morgalad &lt;br /&gt;
|-&lt;br /&gt;
| Marco Polo&lt;br /&gt;
| https://github.com/rcitaliano/MarcoPolo&lt;br /&gt;
| rcitaliano&lt;br /&gt;
|-&lt;br /&gt;
| Nile&lt;br /&gt;
| https://github.com/AndyKerrison/bga-nile&lt;br /&gt;
| Andy_K&lt;br /&gt;
|-&lt;br /&gt;
| Noir: Killer vs Inspector&lt;br /&gt;
| https://bitbucket.org/chhuang76/bga_noirkvi&lt;br /&gt;
| ch huang&lt;br /&gt;
|-&lt;br /&gt;
| Penny Press&lt;br /&gt;
| https://github.com/AdamNovotny/bga-blooms&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| P.I.&lt;br /&gt;
| https://gitlab.com/fa81/bga-pi, https://github.com/hellp/bga-pi (mirror)&lt;br /&gt;
| Fabian Neumann (fa81)&lt;br /&gt;
|-&lt;br /&gt;
| Santorini&lt;br /&gt;
| https://github.com/AntonioSoler/bga-santorini&lt;br /&gt;
| Morgalad, quietmint, Tisaac&lt;br /&gt;
|-&lt;br /&gt;
| Tablut&lt;br /&gt;
| https://github.com/Lucas-C/tablut&lt;br /&gt;
| Lucas-C &amp;amp; ntaffore&lt;br /&gt;
|-&lt;br /&gt;
| Takara Island&lt;br /&gt;
| https://github.com/AntonioSoler/bga-takaraisland&lt;br /&gt;
| Morgalad&lt;br /&gt;
|-&lt;br /&gt;
| Taluva&lt;br /&gt;
| https://github.com/quietmint/bga-taluva&lt;br /&gt;
| Morgalad &amp;amp; quietmint&lt;br /&gt;
|-&lt;br /&gt;
| Teotihuacan: City of Gods&lt;br /&gt;
| https://github.com/Trompetenhut/bga-teotihuacan&lt;br /&gt;
| Trompetenhut&lt;br /&gt;
|-&lt;br /&gt;
| Via Magica&lt;br /&gt;
| https://github.com/christopherburke/bga_viamagica&lt;br /&gt;
| CuriousTerran&lt;br /&gt;
|-&lt;br /&gt;
| Just Desserts&lt;br /&gt;
| https://github.com/mizutismask/bga-just-desserts&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| The King&#039;s Guild&lt;br /&gt;
| https://github.com/AdamNovotny/BGG-KingsGuild&lt;br /&gt;
| A-dam&lt;br /&gt;
|-&lt;br /&gt;
| Get the MacGuffin&lt;br /&gt;
| https://github.com/mizutismask/bga-get-the-MacGuffin&lt;br /&gt;
| mizutismask&lt;br /&gt;
|-&lt;br /&gt;
| President&lt;br /&gt;
| https://github.com/quaresma95/president&lt;br /&gt;
| quaresma95&lt;br /&gt;
|-&lt;br /&gt;
| Hardback&lt;br /&gt;
| https://github.com/quietmint/bga-hardback&lt;br /&gt;
| quietmint&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| Trick of the Rails&lt;br /&gt;
| https://github.com/Fnordistan/trickoftherails&lt;br /&gt;
| AmadanNaBriona&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects on studio ==&lt;br /&gt;
&lt;br /&gt;
Links to studio project which owner wish share as read only.&lt;br /&gt;
Project owner please add you project here, dev nickname and short description if you would like to share it.&lt;br /&gt;
For the projects below any developer can add themselves to a project as read-only from http://en.studio.boardgamearena.com/#!projects page.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! NAME&lt;br /&gt;
! CODE LINK&lt;br /&gt;
! DEVELOPER&lt;br /&gt;
|-&lt;br /&gt;
| Shared Code&lt;br /&gt;
| http://en.studio.boardgamearena.com/#!studiogame?game=sharedcode&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
| Original BGA template&lt;br /&gt;
| http://en.studio.boardgamearena.com/#!studiogame?game=template&lt;br /&gt;
| Victoria_La&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Other useful resources ==&lt;br /&gt;
&lt;br /&gt;
Moved to [[Tools_and_tips_of_BGA_Studio]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7012</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7012"/>
		<updated>2021-01-23T17:30:36Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
=== The &#039;&#039;&#039;player&#039;&#039;&#039; table ===&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; &#039;&#039;&#039;player_table_order&#039;&#039;&#039; is not guaranteed to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
See [https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Assigning_Player_Order Assigning Player Order] in the &#039;&#039;&#039;BGA Studio Cookbook&#039;&#039;&#039; for an example.&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7011</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7011"/>
		<updated>2021-01-23T17:30:15Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
=== The &#039;&#039;&#039;player&#039;&#039;&#039; table ===&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; &#039;&#039;&#039;player_table_order&#039;&#039;&#039; is &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
See [https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Assigning_Player_Order Assigning Player Order] in the &#039;&#039;&#039;BGA Studio Cookbook&#039;&#039;&#039; for an example.&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7010</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7010"/>
		<updated>2021-01-23T17:28:47Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* The player table */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
=== The &#039;&#039;&#039;player&#039;&#039;&#039; table ===&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&amp;lt;/br/&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; This value is &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
See [https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Assigning_Player_Order Assigning Player Order] in the &#039;&#039;&#039;BGA Studio Cookbook&#039;&#039;&#039; for an example.&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=7009</id>
		<title>BGA Studio Cookbook</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=7009"/>
		<updated>2021-01-23T17:27:07Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Assigning Player Order */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is collection of design and implementation recipes for BGA Studio framework.&lt;br /&gt;
For tooling and usage recipes see [[Tools and tips of BGA Studio]].&lt;br /&gt;
If you have your own recipes feel free to edit this page.&lt;br /&gt;
&lt;br /&gt;
== Visual Effects, Layout and Animation ==&lt;br /&gt;
&lt;br /&gt;
=== Create pieces dynamically (using template) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: this method is recommended by BGA guildlines&lt;br /&gt;
&lt;br /&gt;
Declared js template with variables in .tpl file, like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Javascript HTML templates&lt;br /&gt;
    var jstpl_ipiece = &#039;&amp;lt;div class=&amp;quot;${type} ${type}_${color} inlineblock&amp;quot; aria-label=&amp;quot;${name}&amp;quot; title=&amp;quot;${name}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use it like this in .js file&lt;br /&gt;
  div = this.format_block(&#039;jstpl_ipiece&#039;, {&lt;br /&gt;
                                type : &#039;meeple&#039;,&lt;br /&gt;
                                color : &#039;ff0000&#039;,&lt;br /&gt;
                                name : &#039;Bob&#039;,&lt;br /&gt;
                            });&lt;br /&gt;
  &lt;br /&gt;
Then you do whatever you need to do with that div, this one specifically design to go to log entries, because it has embedded title (otherwise its a picture only) and no id.&lt;br /&gt;
&lt;br /&gt;
Note: you could have place this variable in js itself, but keeping it in .tpl allows you to have your js code be free of HTML. Normally it never happens but&lt;br /&gt;
it is good to strive for it.&lt;br /&gt;
Note: you can also use string concatenation, its less readable. You can also use dojo dom object creation api&#039;s but its brutally verbose and its more unreadable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create pieces dynamically (using string concatenation) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: Not recommended&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  div = &amp;quot;&amp;lt;div class=&#039;meeple &amp;quot;+color+&amp;quot;&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Create all pieces statically ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.css, ggg.view.php (optional) &lt;br /&gt;
&lt;br /&gt;
* Create ALL game pieces in html template (.tpl)&lt;br /&gt;
* ALL pieces should have unique id, and it should be meaningful, i.e. meeple_red_1&lt;br /&gt;
* Do not use inline styling&lt;br /&gt;
* Id of player&#039;s specific pieces should use some sort of &#039;color&#039; identification, since player id cannot be used in static layout, you can use english color name, hex 6 char value, or color &amp;quot;number&amp;quot; (1,2,3...)&lt;br /&gt;
* Pieces should have separated class for its color, type, etc, so it can be easily styled in groups. In example below you now can style all meeples, all red meeples or all red tokens, or all &amp;quot;first&amp;quot; meeples&lt;br /&gt;
&lt;br /&gt;
ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
  &amp;lt;div id=&amp;quot;home_red&amp;quot; class=&amp;quot;home_red home&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_1&amp;quot; class=&amp;quot;meeple red n1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_2&amp;quot; class=&amp;quot;meeple red n2&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.css:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.meeple {&lt;br /&gt;
	width: 32px;&lt;br /&gt;
	height: 39px;&lt;br /&gt;
	background-image: url(img/78_64_stand_meeples.png);&lt;br /&gt;
	background-size: 352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.meeple.red {&lt;br /&gt;
	background-position: 30% 0%;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* There should be straight forward mapping between server id and js id (or 1:1)&lt;br /&gt;
* You place objects in different zones of the layout, and setup css to take care of layout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.home .meeple{&lt;br /&gt;
   display: inline-block;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you need to have a temporary object that look like original you can use dojo.clone (and change id to some temp id)&lt;br /&gt;
* If there is lots of repetition or zone grid you can use template generator, but inject style declaration in css instead of inline style for flexibility&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
* If you use this model you cannot use premade js components such as Stock and Zone&lt;br /&gt;
* You have to use alternative methods of animation (slightly altered) since default method will leave object with inline style attributes which you don&#039;t need&lt;br /&gt;
&lt;br /&gt;
=== Use thematic fonts ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.css&lt;br /&gt;
&lt;br /&gt;
Sometime game elements use specific fonts of text, if you want to match it up you can load some specific font (IMPORTANT: from some &#039;&#039;&#039;free font&#039;&#039;&#039; source. See notes below).&lt;br /&gt;
&lt;br /&gt;
[[File:Dragonline_font.png]]&lt;br /&gt;
&lt;br /&gt;
.css&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* latin-ext */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: 400;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/2Dy1Unur1HJoklbsg4iPJ_Y6323mHUZFJMgTvxaG2iE.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;&lt;br /&gt;
}&lt;br /&gt;
/* latin */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/gThgNuQB0o5ITpgpLi4Zpw.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;&lt;br /&gt;
}&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(http://ff.static.1001fonts.net/q/w/qwigley.regular.ttf) format(&#039;ttf&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.zone_title {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	font: italic 32px/32px &amp;quot;Qwigley&amp;quot;, cursive;	   &lt;br /&gt;
	height: 32px;&lt;br /&gt;
	width: auto;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NB:&#039;&#039;&#039; if you need to include a font that&#039;s not available online, an extra action will be needed from an admin. Please include the font file(s) in your img directory, and mention it to admins when requesting your game to be moved to alpha. &#039;&#039;&#039;Please remember that the font has to be free, and include a .txt with all appropriate license information about the font.&#039;&#039;&#039;&lt;br /&gt;
You can look for free fonts (for example) on https://fonts.google.com or https://www.fontsquirrel.com/)&lt;br /&gt;
&lt;br /&gt;
=== Use player color in template ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.view.php&lt;br /&gt;
&lt;br /&gt;
.view.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function build_page($viewArgs) {&lt;br /&gt;
        // Get players &amp;amp; players number&lt;br /&gt;
        $players = $this-&amp;gt;game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        $players_nbr = count($players);&lt;br /&gt;
        /**&lt;br /&gt;
         * ********* Place your code below: ***********&lt;br /&gt;
         */&lt;br /&gt;
        &lt;br /&gt;
        // Set PCOLOR to the current player color hex&lt;br /&gt;
        global $g_user;&lt;br /&gt;
        $cplayer = $g_user-&amp;gt;get_id();&lt;br /&gt;
        if (array_key_exists($cplayer, $players)) { // may be not set if spectator&lt;br /&gt;
            $player_color = $players [$cplayer] [&#039;player_color&#039;];&lt;br /&gt;
        } else {&lt;br /&gt;
            $player_color = &#039;ffffff&#039;; // spectator&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;tpl [&#039;PCOLOR&#039;] = $player_color;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Scale to fit for big boards ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
Lets say you have huge game board, and lets say you want it to be 1400px wide. Besides the board there will be side bar which is 240 and trim. &lt;br /&gt;
My display is 1920 wide so it fits, but there is big chance other people won&#039;t have that width. What do you do?&lt;br /&gt;
Easiest thing I came up with is to scale whole content to fit (everything you declare in .tpl file). Tested or firefox and chrome.&lt;br /&gt;
&lt;br /&gt;
ggg_ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   &amp;lt;div id=&amp;quot;thething&amp;quot; class=&amp;quot;thething&amp;quot; style=&amp;quot;width: 1400px;&amp;quot;&amp;gt;&lt;br /&gt;
            ... everything else you declare ...&lt;br /&gt;
   &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setup : function(gamedatas) {&lt;br /&gt;
          console.log(&amp;quot;Starting game setup&amp;quot;);&lt;br /&gt;
          ...&lt;br /&gt;
          this.interface_min_width = 740;&lt;br /&gt;
          this.interface_max_width = 1400;&lt;br /&gt;
          dojo.connect(window, &amp;quot;onresize&amp;quot;, this, dojo.hitch(this, &amp;quot;adaptViewportSize&amp;quot;));&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    adaptViewportSize : function() {&lt;br /&gt;
        var pageid = &amp;quot;page-content&amp;quot;;&lt;br /&gt;
        var nodeid = &amp;quot;thething&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        var bodycoords = dojo.marginBox(pageid);&lt;br /&gt;
        var contentWidth = bodycoords.w;&lt;br /&gt;
&lt;br /&gt;
        var browserZoomLevel = window.devicePixelRatio; &lt;br /&gt;
        //console.log(&amp;quot;zoom&amp;quot;,browserZoomLevel);&lt;br /&gt;
        if (contentWidth &amp;gt;= this.interface_max_width || browserZoomLevel &amp;gt;1  || this.control3dmode3d) {&lt;br /&gt;
            dojo.style(nodeid,&#039;transform&#039;,&#039;&#039;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var percentageOn1 = contentWidth / this.interface_max_width;&lt;br /&gt;
        dojo.style(nodeid, &amp;quot;transform&amp;quot;, &amp;quot;scale(&amp;quot; + percentageOn1 + &amp;quot;)&amp;quot;);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this method does not seems to work to retina resolution displays, if you know better way let me know&lt;br /&gt;
&lt;br /&gt;
=== Dynamic tooltips ===&lt;br /&gt;
&lt;br /&gt;
If you really need a dynamic tooltip you can use this technique. (Only use it if the static tooltips provided by the BGA framework are not sufficient.)&lt;br /&gt;
&lt;br /&gt;
            new dijit.Tooltip({&lt;br /&gt;
                connectId: [&amp;quot;divItemId&amp;quot;],&lt;br /&gt;
                getContent: function(matchedNode){&lt;br /&gt;
                    return &amp;quot;... calculated ...&amp;quot;; &lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is an out-of-the-box djit.Tooltip. It has a &#039;&#039;getContent&#039;&#039; method which is called dynamically.&lt;br /&gt;
&lt;br /&gt;
The string function return becomes the innerHTML of the tooltip, so it can be anything. In this example matchedNode is a dojo node representing dom object with id of &amp;quot;divItemId&amp;quot; but there are more parameters which I am not posting here which allows more sophisticated subnode queries (i.e. you can attach tooltip to all nodes with class or whatever).&lt;br /&gt;
&lt;br /&gt;
[https://dojotoolkit.org/reference-guide/1.10/dijit/Tooltip.html dijit.Tooltip]&lt;br /&gt;
&lt;br /&gt;
It&#039;s not part of the BGA API so use at your own risk.&lt;br /&gt;
&lt;br /&gt;
=== Accessing images from js ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
     // your game resources&lt;br /&gt;
     &lt;br /&gt;
     var my_img = &#039;&amp;lt;img src=&amp;quot;&#039;+g_gamethemeurl+&#039;img/cards.jpg&amp;quot;/&amp;gt;&#039;;&lt;br /&gt;
     &lt;br /&gt;
     // shared resources&lt;br /&gt;
     var my_help_img = &amp;quot;&amp;lt;img class=&#039;imgtext&#039; src=&#039;&amp;quot; + g_themeurl + &amp;quot;img/layout/help_click.png&#039; alt=&#039;action&#039; /&amp;gt; &amp;lt;span class=&#039;tooltiptext&#039;&amp;gt;&amp;quot; +&lt;br /&gt;
                    text + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Rendering text with players color and proper background ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
This example actually writes &amp;quot;You&amp;quot; but you can replace this with player name as easily, drop translating function in this case&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        /* Implementation of proper colored You with background in case of white or light colors  */&lt;br /&gt;
 &lt;br /&gt;
        divYou : function() {&lt;br /&gt;
            var color = this.gamedatas.players[this.player_id].color;&lt;br /&gt;
            var color_bg = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.gamedatas.players[this.player_id] &amp;amp;&amp;amp; this.gamedatas.players[this.player_id].color_back) {&lt;br /&gt;
                color_bg = &amp;quot;background-color:#&amp;quot; + this.gamedatas.players[this.player_id].color_back + &amp;quot;;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            var you = &amp;quot;&amp;lt;span style=\&amp;quot;font-weight:bold;color:#&amp;quot; + color + &amp;quot;;&amp;quot; + color_bg + &amp;quot;\&amp;quot;&amp;gt;&amp;quot; + __(&amp;quot;lang_mainsite&amp;quot;, &amp;quot;You&amp;quot;) + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
            return you;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inject icon images in the log ===&lt;br /&gt;
&lt;br /&gt;
Here is an example of what was done for Terra Mystica which is simple and straightforward:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//Define the proper message&lt;br /&gt;
		$message = clienttranslate(&#039;${player_name} gets ${power_income} via Structures&#039;);&lt;br /&gt;
		if ($price &amp;gt; 0) {&lt;br /&gt;
			self::DbQuery(&amp;quot;UPDATE player SET player_score = player_score - $price WHERE player_id = $player_id&amp;quot;);&lt;br /&gt;
			$message = clienttranslate(&#039;${player_name} pays ${vp_price} and gets ${power_income} via Structures&#039;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
// Notify&lt;br /&gt;
		self::notifyAllPlayers( &amp;quot;powerViaStructures&amp;quot;, $message, array(&lt;br /&gt;
			&#039;i18n&#039; =&amp;gt; array( ),&lt;br /&gt;
			&#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
			&#039;player_name&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_name FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;power_tokens&#039; =&amp;gt; $power_tokens,&lt;br /&gt;
			&#039;vp_price&#039; =&amp;gt; self::getLogsVPAmount($price),&lt;br /&gt;
			&#039;power_income&#039; =&amp;gt; self::getLogsPowerAmount($power_income),&lt;br /&gt;
			&#039;newScore&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_score FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;counters&#039; =&amp;gt; $this-&amp;gt;getGameCounters(null),&lt;br /&gt;
		) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some functions to have the needed html added inside the substitution variable, such as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function getLogsPowerAmount( $amount ) {&lt;br /&gt;
		return &amp;quot;&amp;lt;div class=&#039;tmlogs_icon&#039; title=&#039;Power&#039;&amp;gt;&amp;lt;div class=&#039;power_amount&#039;&amp;gt;$amount&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: injecting html from php is not ideal but easy, if you want more clean solution, use method below but it is a lot more sophisticated.&lt;br /&gt;
&lt;br /&gt;
=== Inject images and styled html in the log ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php&lt;br /&gt;
&lt;br /&gt;
So you want nice pictures in the game log. What do you do? The first idea that comes to mind is to send html from php in notifications (see method above). &lt;br /&gt;
&lt;br /&gt;
This is a bad idea for many reasons:&lt;br /&gt;
&lt;br /&gt;
* It&#039;s bad architecture. ui elements leak into the server, and now you have to manage the ui in multiple places.&lt;br /&gt;
* If you decided to change something in the ui in future version, replay logs for old games and tutorials may not work, since they use stored notifications.&lt;br /&gt;
* Log previews for old games become unreadable. (This is the log state before you enter the game replay, which is useful for troubleshooting and game analysis.)&lt;br /&gt;
* It&#039;s more data to transfer and store in the db.&lt;br /&gt;
* It&#039;s a nightmare for translators.&lt;br /&gt;
&lt;br /&gt;
So what else can you do? I use this recipe for &#039;&#039;&#039;client side log injection&#039;&#039;&#039; to intercept log arguments (which come from the server) and replace them with html on the client side.&lt;br /&gt;
&lt;br /&gt;
[[File:clientloginjection.png|left]] &lt;br /&gt;
&lt;br /&gt;
ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
        /** Override this function to inject html into log items. This is a built-in BGA method.  */&lt;br /&gt;
&lt;br /&gt;
        /* @Override */&lt;br /&gt;
        format_string_recursive : function(log, args) {&lt;br /&gt;
            try {&lt;br /&gt;
                if (log &amp;amp;&amp;amp; args &amp;amp;&amp;amp; !args.processed) {&lt;br /&gt;
                    args.processed = true;&lt;br /&gt;
                    &lt;br /&gt;
&lt;br /&gt;
                    // list of special keys we want to replace with images&lt;br /&gt;
                    var keys = [&#039;place_name&#039;,&#039;token_name&#039;];&lt;br /&gt;
                    &lt;br /&gt;
                  &lt;br /&gt;
                    for ( var i in keys) {&lt;br /&gt;
                        var key = keys[i];&lt;br /&gt;
                        args[key] = this.getTokenDiv(key, args);                            &lt;br /&gt;
&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                console.error(log,args,&amp;quot;Exception thrown&amp;quot;, e.stack);&lt;br /&gt;
            }&lt;br /&gt;
            return this.inherited(arguments);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; In the &#039;&#039;format_string_recursive&#039;&#039; method, the &#039;args&#039; parameter will only contain arguments passed to it from the notify method in ggg.game.php (see below).&lt;br /&gt;
&lt;br /&gt;
The &#039;log&#039; parameter is the actual string that is inserted into the logs. You can perform additional js string manipulation on it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        getTokenDiv : function(key, args) {&lt;br /&gt;
            // ... implement whatever html you want here, example from sharedcode.js&lt;br /&gt;
            var token_id = args[key];&lt;br /&gt;
            var item_type = getPart(token_id,0);&lt;br /&gt;
            var logid = &amp;quot;log&amp;quot; + (this.globalid++) + &amp;quot;_&amp;quot; + token_id;&lt;br /&gt;
            switch (item_type) {&lt;br /&gt;
                case &#039;wcube&#039;:&lt;br /&gt;
                    var tokenDiv = this.format_block(&#039;jstpl_resource_log&#039;, {&lt;br /&gt;
                        &amp;quot;id&amp;quot; : logid,&lt;br /&gt;
                        &amp;quot;type&amp;quot; : &amp;quot;wcube&amp;quot;,&lt;br /&gt;
                        &amp;quot;color&amp;quot; : getPart(token_id,1),&lt;br /&gt;
                    });&lt;br /&gt;
                    return tokenDiv;&lt;br /&gt;
                    break;&lt;br /&gt;
                case &#039;meeple&#039;:&lt;br /&gt;
                    if ($(token_id)) {&lt;br /&gt;
                        var clone = dojo.clone($(token_id));&lt;br /&gt;
    &lt;br /&gt;
                        dojo.attr(clone, &amp;quot;id&amp;quot;, logid);&lt;br /&gt;
                        this.stripPosition(clone);&lt;br /&gt;
                        dojo.addClass(clone, &amp;quot;logitem&amp;quot;);&lt;br /&gt;
                        return clone.outerHTML;&lt;br /&gt;
                    }&lt;br /&gt;
                    break;&lt;br /&gt;
     &lt;br /&gt;
                default:&lt;br /&gt;
                    break;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return &amp;quot;&#039;&amp;quot; + this.clienttranslate_string(this.getTokenName(token_id)) + &amp;quot;&#039;&amp;quot;;&lt;br /&gt;
       },&lt;br /&gt;
       getTokenName : function(key) {&lt;br /&gt;
           return this.gamedatas.token_types[key].name; // get name for the key, from static table for example&lt;br /&gt;
       },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in this case the server simply injects token_id as a name, and the client substitutes it for the translated name or the picture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ggg.game.php:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name}&#039;),[&#039;token_name&#039;=&amp;gt;$token_id]);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; As noted above, only arguments actually passed by this method are available to the args parameter received in the client-side &#039;&#039;format_string_recursive&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is the case that you want to pass arguments that are not actually included in the output message. For example, suppose we have a method like this:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;tokenPlaced&#039;,clienttranslate(&#039;Player placed ${token_name}&#039;),array(&lt;br /&gt;
              &#039;token_name&#039; =&amp;gt; $token_id,&lt;br /&gt;
              &#039;zone_played&#039; =&amp;gt; $zone);&lt;br /&gt;
&lt;br /&gt;
This will output &amp;quot;Player placed ${token_name}&amp;quot; in the log, and if we subscribe to a notification method activated by the &amp;quot;tokenPlaced&amp;quot; event in the client-side code, that method can make use of the &#039;zone_played&#039; argument. &#039;&#039;&#039;But&#039;&#039;&#039; &#039;zone_played&#039; &#039;&#039;will not be available&#039;&#039; in the &#039;&#039;format_string_recursive&#039;&#039; method unless it is actually passed in the log message (i.e., in the string contained inside clienttranslate).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now if you don&#039;t like raw log containing id instead of name but want name, and want substitution, you can use another parameter as id. The problem with that,&lt;br /&gt;
it will work at first, but if you reload game using F5 you will loose your additional parameters, why? Because when game reloads it does not actually send same&lt;br /&gt;
notifications, it sends special &amp;quot;hitstorical_log&amp;quot; notification where all  parameters not listed in the &amp;quot;log&amp;quot; are removed. There is a hack (feature) to circumvent that,&lt;br /&gt;
called recursive parameters. I.e. you can send stuff like this:&lt;br /&gt;
 &lt;br /&gt;
             $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name_rec}&#039;),&lt;br /&gt;
                    [&#039;token_name_rec&#039;=&amp;gt;[&#039;log&#039;=&amp;gt;&#039;${token_name}&#039;,&lt;br /&gt;
                                        &#039;args&#039;=&amp;gt; [&#039;token_name&#039;=&amp;gt;clienttranslate(&#039;Boo&#039;), &#039;token_id&#039;=&amp;gt;$token_id, &#039;i18n&#039;=&amp;gt;[&#039;token_name&#039;] ]&lt;br /&gt;
                                       ]&lt;br /&gt;
                    ]);&lt;br /&gt;
&lt;br /&gt;
and in format_log_recursive&lt;br /&gt;
             var key = &#039;token_name&#039;;&lt;br /&gt;
             if (typeof args[key] == &#039;string&#039; &amp;amp;&amp;amp; typeof args[&#039;token_id&#039;] == &#039;string&#039;) {&lt;br /&gt;
                 args[key] = this.getTokenDiv(&#039;token_id&#039;, args);                            &lt;br /&gt;
             }&lt;br /&gt;
&lt;br /&gt;
=== High-Definition Graphics ===&lt;br /&gt;
&lt;br /&gt;
Some users will have screens which can display text and images at a greater resolution than the usual 72 dpi, e.g. the &amp;quot;Retina&amp;quot; screens on the 5k iMac, all iPads, and high-DPI screens on laptops from many manufacturers. If you can get art assets at this size, they will make your game look extra beautiful. You &#039;&#039;could&#039;&#039; just use large graphics and scale them down, but that would increase the download time and bandwidth for users who can&#039;t display them. Instead, a good way is to prepare a separate graphics file at exactly twice the size you would use otherwise, and add &amp;quot;@2x&amp;quot; at the end of the filename, e.g. if pieces.png is 240x320, then pieces@2x.png is 480x640.&lt;br /&gt;
&lt;br /&gt;
There are two changes required in order to use the separate graphics files. First in your css, where you use a file, add a media query which overrides the original definition and uses the bigger version on devices which can display them. Ensuring that the &amp;quot;background-size&amp;quot; attribute is set means that the size of the displayed object doesn&#039;t change, but only is drawn at the improved dot pitch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.piece {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    background-image: url(&#039;img/pieces.png&#039;);&lt;br /&gt;
    background-size:240px 320px;&lt;br /&gt;
    z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&lt;br /&gt;
{&lt;br /&gt;
    .piece {&lt;br /&gt;
        background-image: url(&#039;img/pieces@2x.png&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Secondly, in your setup function in javascript, you must ensure than only the appropriate one version of the file gets pre-loaded (otherwise you more than waste the bandwidth saved by maintaining the standard-resolution file). Note that the media query is the same in both cases:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            var isRetina = &amp;quot;(-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&amp;quot;;&lt;br /&gt;
            if (window.matchMedia(isRetina).matches)&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces@2x.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board@2x.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Cool realistic shadow effect with CSS ===&lt;br /&gt;
&lt;br /&gt;
If you wish to make a shadow effect for game pieces that are not rectangle, do not use box-shadow but use filter, which is supported by recent major browsers.  This way, you can use the alpha channel of your element to drop a shadow.  This even work for transparent backgrounds, so that if you are using the &amp;quot;CSS-sprite&amp;quot; method, it will work!&lt;br /&gt;
&lt;br /&gt;
For instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.xxx-token {&lt;br /&gt;
    filter: drop-shadow(0px 0px 1px #000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Using the CSS classes from the state machine ===&lt;br /&gt;
&lt;br /&gt;
If you need to hide or show stuff depending on the state of your game, you can of course use javascript, but CSS is hand enough for that.  The #overall-content element does change class depending on the game state.  For instance, if you are in state &#039;&#039;playerTurn&#039;&#039;, it will have the class &#039;&#039;gamestate_playerTurn&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
So now, if you want to show the discard pile only during player turns, you may use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#discard_pile { display: none }&lt;br /&gt;
.gamestate_playerTurn #discard_pile { display: block }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This can be used if you want to change sizing of elements, position, layout or visual appearance.&lt;br /&gt;
&lt;br /&gt;
=== More readable JS: onEnteringState ===&lt;br /&gt;
&lt;br /&gt;
If you have a lot of states onEnteringState and friends become rather wild, you can do this trick to call some method dynamically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
     onEnteringState: function(stateName, args) {&lt;br /&gt;
       console.log(&#039;Entering state: &#039; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
       // Call appropriate method&lt;br /&gt;
       var methodName = &amp;quot;onEnteringState_&amp;quot; + stateName;&lt;br /&gt;
       if (this[methodName] !== undefined) {             &lt;br /&gt;
          console.log(&#039;Calling &#039; + methodName, args.args);&lt;br /&gt;
          this[methodName](args.args);&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerTurn: function(args) { // this is args directly, not args.args &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerSomethingElse: function(args) { &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: since its ignores the undefined functions you don&#039;t have define function for each state, but on the other hand you cannot make typos.&lt;br /&gt;
Same applies to onUpdateActionButtons except you pass &#039;args&#039; to method, not args.args, and for onLeavingState where you don&#039;t pass anything.&lt;br /&gt;
&lt;br /&gt;
== Game Model and Database design ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Database for The euro game ===&lt;br /&gt;
Lets say we have a game with workers, dice, tokens, board, resources, money and vp. Workers and dice can be placed in various zones on the board, and you can get resources, money, tokens and vp in your home zone. Also tokens can be flipped or not flipped.&lt;br /&gt;
&lt;br /&gt;
[[File:Madeira board.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now lets try to map it, we have&lt;br /&gt;
* (meeple,zone)&lt;br /&gt;
* (die, zone, sideup)&lt;br /&gt;
* (resource cube/money token/vp token,player home zone)&lt;br /&gt;
* (token, player home zone, flip state)&lt;br /&gt;
We can notice that resource and money are uncountable, and don&#039;t need to be track individually so we can replace our mapping to&lt;br /&gt;
* (resource type/money,player home zone, count)&lt;br /&gt;
And vp stored already for us in player table, so we can remove it from that list.&lt;br /&gt;
&lt;br /&gt;
Now when we get to encode it we can see that everything can be encoded as (object,zone,state) form, where object and zone is string and state is integer. The resource mapping is slightly different semantically so you can go with two table, or counting using same table with state been used as count for resources.&lt;br /&gt;
&lt;br /&gt;
So the piece mapping for non-grid based games can be in most case represented by (string: token_key, string: token_location, int: token_state), example of such database schema can be found here: [https://github.com/elaskavaia/bga-sharedcode/blob/master/dbmodel.sql dbmodel.sql] and class implementing access to it here [https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php table.game.php].&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|meeple_red_1&lt;br /&gt;
|home_red&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|dice_black_2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|dice_green_1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|bread&lt;br /&gt;
|home_red&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Now how we represent resource counters such as bread?&lt;br /&gt;
Using same table from we simply add special counter token for bread and use state to indicate the count. Note to keep first column unique we have to add player identification for that counter, i.e. ff0000 is red player.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|bread_ff0000&lt;br /&gt;
|tableau_ff0000&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
See php module for this table here https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php&lt;br /&gt;
&lt;br /&gt;
Variant 2: Additional resource table, resource count for each player id&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `resource` (&lt;br /&gt;
  `player_id` int(10) unsigned NOT NULL,&lt;br /&gt;
  `resource_key` varchar(32) NOT NULL,&lt;br /&gt;
  `resource_count` int(10) signed NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`player_id`,`resource_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
 ALTER TABLE resource ADD CONSTRAINT fk_player_id FOREIGN KEY (player_id) REFERENCES player(player_id);&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+resource&lt;br /&gt;
! player_id&lt;br /&gt;
! resource_key&lt;br /&gt;
! resource_count&lt;br /&gt;
|-&lt;br /&gt;
|123456&lt;br /&gt;
|bread&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 3: More normalised&lt;br /&gt;
&lt;br /&gt;
This version is similar to &amp;quot;card&amp;quot; table from hearts tutorial, you can also use exact cards database schema and Deck implementation for most purposes (even you not dealing with cards). &lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `token_type` varchar(16) NOT NULL,&lt;br /&gt;
  `token_arg` int(11) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_id`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_id&lt;br /&gt;
! token_type&lt;br /&gt;
! token_arg&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|22&lt;br /&gt;
|meeple&lt;br /&gt;
|123456&lt;br /&gt;
|home_123456&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|23&lt;br /&gt;
|dice&lt;br /&gt;
|2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|26&lt;br /&gt;
|dice&lt;br /&gt;
|1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|49&lt;br /&gt;
|bread&lt;br /&gt;
|0&lt;br /&gt;
|home_123456&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Advantages of this would be is a bit more straightforward to do some queries in db, disadvantage its hard to read (as you can compare with previous example, you&lt;br /&gt;
cannot just look at say, ah I know what it means). Another questionable advantage is it allows you to do id randomisation, so it hard to do crafted queries to &lt;br /&gt;
cheat, the down side of that you cannot understand it either, and handcraft db states for debugging or testing.&lt;br /&gt;
&lt;br /&gt;
=== Database for The card game ===&lt;br /&gt;
&lt;br /&gt;
Lets say you have a standard card game, player have hidden cards in hand, you can draw card from draw deck, play card on tableau and discard to discard pile.&lt;br /&gt;
We have to design database for such game.&lt;br /&gt;
&lt;br /&gt;
In real word to &amp;quot;save&amp;quot; the game we take a picture a play area, save cards from it, then put away draw deck, discard and hand of each player separately and mark it, also we will record current scoring (if any) and who&#039;s turn was it.&lt;br /&gt;
&lt;br /&gt;
* Framework handles state machine transition, so you don&#039;t have to worry about database design for that (i.e. who&#039;s turn it is, what phase of the game we are at, you still have to design it but part of state machine step)&lt;br /&gt;
* Also framework supports basic player information, color, order around the table, basic scoring, etc, so you don&#039;t have to worry about it either&lt;br /&gt;
* The only thing you need in our database is state of the &amp;quot;board&amp;quot;, which is &amp;quot;where each pieces is, and in what state&amp;quot;, or (position,rotation) pair.&lt;br /&gt;
&lt;br /&gt;
Lets see what we have for that:&lt;br /&gt;
* The card state is very simple, its usually &amp;quot;face up/face down&amp;quot;, &amp;quot;tapped/untapped&amp;quot;, &amp;quot;right side up/up side down&amp;quot;&lt;br /&gt;
* As position go we never need real coordinates x,y,z. We need to know what &amp;quot;zone&amp;quot; card was, and depending on the zone it may sometimes need an extra &amp;quot;z&amp;quot; or &amp;quot;x&amp;quot; as card order. The zone position usually static or irrelevant.&lt;br /&gt;
* So our model is: we have cards, which have some attributes, at any given point in time they belong to a &amp;quot;zone&amp;quot;, and can also have order and state&lt;br /&gt;
* Now for mapping we should consider what information changes and what information is static, later is always candidate for material file&lt;br /&gt;
* For dynamic information we should try to reduce amount of fields we need&lt;br /&gt;
**  we need at least a field for card, so its one&lt;br /&gt;
**  we need to know what zone cards belong to, its 2&lt;br /&gt;
**  and we have possibly few other fields, if you look closely at you game you may find out that most of the zone only need one attribute at a time, i.e. draw pile always have cards face down, hand always face up, also for hand and discard order does not matter at all (but for draw it does matter). So in majority of cases we can get away with one single extra integer field representing state or order&lt;br /&gt;
* In real database both card and zone will be integers as primary keys referring to additional tables, but in our case its total overkill, so they can be strings as easily&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_key` varchar(32) unsigned NOT NULL,&lt;br /&gt;
  `card_location` varchar(32) NOT NULL,&lt;br /&gt;
  `card_state` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 2: More normalised&lt;br /&gt;
&lt;br /&gt;
This version supported by Deck php class, so unless you want to rewrite db access layer go with this one&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you using this schema, some zones/locations have special semantic. The &#039;hand&#039; location is actually multiple locations - one per player, but player id is encoded as card_location_arg. If &#039;hand&#039; in your game is ordered, visible or can have some other card states, you cannot use hand location (replacement is hand_&amp;lt;player_id&amp;gt; or hand_&amp;lt;color_id&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
== Game Modules ==&lt;br /&gt;
&lt;br /&gt;
=== Including your own JavaScript module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, modules/ggg_other.js&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.js in modules/ folder and sync&lt;br /&gt;
* Modify ggg.js to include it&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  define([ &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;, &amp;quot;ebg/core/gamegui&amp;quot;, &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    // load my own module!!!&lt;br /&gt;
    g_gamethemeurl + &amp;quot;modules/ggg_other.js&amp;quot; ], function(dojo,&lt;br /&gt;
        declare) {&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Including your own PHP module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, modules/ggg_other.php&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.php in modules/ folder and sync&lt;br /&gt;
* Modify ggg.game.php to include it&lt;br /&gt;
&lt;br /&gt;
 require_once (&#039;modules/ggg_other.php&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Avoiding code in dojo declare style ===&lt;br /&gt;
Dojo class declarations are rather bizzare and do not work with most IDEs.&lt;br /&gt;
If you want to write in plain JS with classes you can stub all the dojo define/declare stuff&lt;br /&gt;
and hook your class into that, so class if outside of this mess.&lt;br /&gt;
&lt;br /&gt;
NOTE: this technique is for experienced developers, do not try it if you do not understand&lt;br /&gt;
the consequences.&lt;br /&gt;
&lt;br /&gt;
This is complete example of game .js class&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Testla is game name is has to be changed&lt;br /&gt;
class Testla {&lt;br /&gt;
	constructor(game) {&lt;br /&gt;
		console.log(&#039;game constructor&#039;);&lt;br /&gt;
		this.game = game;&lt;br /&gt;
		this.varfoo = new MyFoo(); // this example of class from custom module&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	setup(gamedatas) {&lt;br /&gt;
		console.log(&amp;quot;Starting game setup&amp;quot;, this.varfoo);&lt;br /&gt;
		this.gamedatas = gamedatas;&lt;br /&gt;
		this.dojo.create(&amp;quot;div&amp;quot;, { class: &#039;whiteblock&#039;, innerHTML: _(&amp;quot;hello&amp;quot;) }, &#039;thething&#039;);&lt;br /&gt;
		console.log(&amp;quot;Ending game setup&amp;quot;);&lt;br /&gt;
	};&lt;br /&gt;
	onEnteringState(stateName, args) {&lt;br /&gt;
		console.log(&#039;onEnteringState : &#039; + stateName, args);&lt;br /&gt;
		this.game.addActionButton(&#039;b1&#039;,_(&#039;Click Me&#039;), (e)=&amp;gt;this.onButtonClick(e));&lt;br /&gt;
	};&lt;br /&gt;
	onLeavingState(stateName) {&lt;br /&gt;
		console.log(&#039;onLeavingState : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onUpdateActionButtons(stateName, args) {&lt;br /&gt;
		console.log(&#039;onUpdateActionButtons : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onButtonClick(event) {&lt;br /&gt;
		console.log(&#039;onButtonClick&#039;,event);&lt;br /&gt;
	};&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
define([&lt;br /&gt;
	&amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
	g_gamethemeurl + &#039;/modules/foo.js&#039; // custom module if needed&lt;br /&gt;
],&lt;br /&gt;
	function(dojo, declare) {&lt;br /&gt;
                // testla is game name is has to be changed&lt;br /&gt;
		return declare(&amp;quot;bgagame.testla&amp;quot;, ebg.core.gamegui, {&lt;br /&gt;
			constructor: function() {&lt;br /&gt;
				this.xapp = new Testla(this);&lt;br /&gt;
				this.xapp.dojo = dojo;&lt;br /&gt;
			},&lt;br /&gt;
			setup: function(gamedatas) {&lt;br /&gt;
				this.xapp.setup(gamedatas);&lt;br /&gt;
			},&lt;br /&gt;
			onEnteringState: function(stateName, args) {&lt;br /&gt;
				this.xapp.onEnteringState(stateName, args.args);&lt;br /&gt;
			},&lt;br /&gt;
			onLeavingState: function(stateName) {&lt;br /&gt;
				this.xapp.onLeavingState(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
			onUpdateActionButtons: function(stateName, args) {&lt;br /&gt;
				this.xapp.onUpdateActionButtons(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
		});&lt;br /&gt;
	});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Assorted Stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Out-of-turn actions: Un-pass ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg.action.php, states.inc.php&lt;br /&gt;
&lt;br /&gt;
In multiplayer game sometimes players passes but than they think more and want to un-Pass and redo their choice. &lt;br /&gt;
To re-active a player who passes some trickery required.&lt;br /&gt;
&lt;br /&gt;
Define a special action that does how and hook it up.&lt;br /&gt;
&lt;br /&gt;
In states.inc.php add an action to mmultipleactiveplayer state to &amp;quot;unpass&amp;quot;, lets call it &amp;quot;actionCancel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In ggg.action.php add action hook&lt;br /&gt;
    public function actionCancel() {&lt;br /&gt;
        self::setAjaxMode();&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;actionCancel();&lt;br /&gt;
        self::ajaxResponse();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
In ggg.game.php add action handler&lt;br /&gt;
    function actionCancel() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction(&#039;actionCancel&#039;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive(array ($this-&amp;gt;getCurrentPlayerId() ), &#039;error&#039;, false);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Finally to call this in client ggg.js you would do something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 onUpdateActionButtons:  function(stateName, args) {&lt;br /&gt;
   if (this.isCurrentPlayerActive()) { &lt;br /&gt;
     // ...&lt;br /&gt;
   } else if (!this.isSpectator) { // player is NOT active but not spectatoe&lt;br /&gt;
       switch (stateName) {&lt;br /&gt;
          case &#039;playerTurnMuliPlayerState&#039;:&lt;br /&gt;
		this.addActionButton(&#039;button_unpass&#039;, _(&#039;Oh no!&#039;), &#039;onUnpass&#039;);&lt;br /&gt;
		break;&lt;br /&gt;
	}&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
				&lt;br /&gt;
 onUnpass: function(e) {&lt;br /&gt;
    this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; +  this.game_name + &amp;quot;/actionCancel.html&amp;quot;, {}, this); // no checkAction!&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Although be careful that if the turn comes back to the player while he is about to click cancel, the action buttons will be updated and the player will misclick which can be quite frustrating. To avoid this, move the cancel button to another position, like to the left of pagemaintitletext:&lt;br /&gt;
  dojo.place(&#039;button_unpass&#039;, &#039;pagemaintitletext&#039;, &#039;before&#039;);&lt;br /&gt;
Being out of the generalactions div, it won&#039;t be automatically destroyed like normal buttons, so you&#039;ll have to handle that yourself in onLeavingState. You might also want to change the button color to red (blue buttons for active player only, red buttons also for inactive players?)&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Selection ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Simple way to implement something like that without extra states is to use &amp;quot;selection&amp;quot; mechanism. When user click on worker add some sort of class into that element i.e. &#039;selected&#039; (which also have to have some indication by css i.e. outline).&lt;br /&gt;
&lt;br /&gt;
Than user can click on placement zone, you can use dojo.query for &amp;quot;selected&amp;quot; element and use it along with zone id to send data to server. If proper worker is not selected yet can give a error message using this.showMessage(...) function.&lt;br /&gt;
&lt;br /&gt;
Extra code required to properly cleanup selection between states&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Client States ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
I don&#039;t think its documented feature but there is a way to do client-only states, which is absolutely wonderful for few reasons&lt;br /&gt;
* When player interaction is two step process, such as select worker, place worker, or place worker, pick one of two resources of your choice&lt;br /&gt;
* When multi-step process can result of impossible situation and has to be undone (by rules)&lt;br /&gt;
* When multi-step process is triggered from multiple states (such as you can do same thing as activated card action, pass action or main action)&lt;br /&gt;
&lt;br /&gt;
So lets do Select Worker/Place Worker&lt;br /&gt;
&lt;br /&gt;
Define your server state as usual, i.e. playerMainTurn -&amp;gt; &amp;quot;You must pick up a worker&amp;quot;.&lt;br /&gt;
Now define a client state, we only need &amp;quot;name&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;, lets say &amp;quot;client_playerPicksLocation&amp;quot;. Always prefix names of client state with &amp;quot;client_&amp;quot; to avoid confusion. Now we have to do the following:&lt;br /&gt;
* Have a handler for onUpdateActionButtons for playerMainTurn to activate all possible workers he can pick&lt;br /&gt;
* When player clicks workers, remember the worker in one of the members of the main class, I usually use one called this.clientStateArgs.&lt;br /&gt;
* Transition to new client state&lt;br /&gt;
  onWorker: function(e) {&lt;br /&gt;
      var id = event.currentTarget.id;&lt;br /&gt;
      dojo.stopEvent(event);&lt;br /&gt;
      ... // do validity checks&lt;br /&gt;
      this.clientStateArgs.worker_id = id;&lt;br /&gt;
      this.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                                descriptionmyturn : &amp;quot;${you} must select location&amp;quot;,&lt;br /&gt;
                            });&lt;br /&gt;
   }&lt;br /&gt;
* Have a handler for onUpdateActionButtons for client_playerPicksLocation to activate all possible locations this worker can go AND add Cancel button (see below)&lt;br /&gt;
* Have a location handler which will eventually send a server request, using stored this.clientStateArgs.worker_id as worker id&lt;br /&gt;
* The cancel button should call a method to restore server state, also if you doing it for more than one state you can add this universally using this.on_client_state check&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        if (this.isCurrentPlayerActive()) {&lt;br /&gt;
          if (this.on_client_state &amp;amp;&amp;amp; !$(&#039;button_cancel&#039;)) {&lt;br /&gt;
               this.addActionButton(&#039;button_cancel&#039;, _(&#039;Cancel&#039;), dojo.hitch(this, function() {&lt;br /&gt;
                                             this.restoreServerGameState();&lt;br /&gt;
               }));&lt;br /&gt;
          }&lt;br /&gt;
        } &lt;br /&gt;
Note: usually I call my own function call this.cancelLocalStateEffects() which will do more stuff first then call restoreServerGameState(), same function is usually needs to be called when server request has failed (i.e. invalid move)&lt;br /&gt;
&lt;br /&gt;
Note: If you need more than 2 steps, you may have to do client side animation to reflect the new state, which gets trickier because you have to undo that also on cancellation.&lt;br /&gt;
&lt;br /&gt;
Code is available here [https://github.com/elaskavaia/bga-sharedcode/blob/master/sharedcode.js sharedcode.js] (its using playerTurnPlayCubes and client_selectCubeLocation).&lt;br /&gt;
&lt;br /&gt;
=== Assigning Player Order ===&lt;br /&gt;
&lt;br /&gt;
If you want to arbitrarily assign player order at the start of the game (for example, in a game with teams options), you can do so by retrieving the initialization-only player attribute &#039;&#039;&#039;player_table_order&#039;&#039;&#039; and using it to assign values to &#039;&#039;&#039;player_no&#039;&#039;&#039; (which is normally assigned at the start of a game in the order in which players come to the table). (See [https://en.doc.boardgamearena.com/Game_database_model:_dbmodel.sql#The_player_table Game database model] for more details.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                // Retrieve inital player order ([0=&amp;gt;playerId1, 1=&amp;gt;playerId2, ...])&lt;br /&gt;
		$playerInitialOrder = [];&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$playerInitialOrder[$player[&#039;player_table_order&#039;]] = $playerId;&lt;br /&gt;
		}&lt;br /&gt;
		ksort($playerInitialOrder);&lt;br /&gt;
		$playerInitialOrder = array_flip(array_values($playerInitialOrder));&lt;br /&gt;
&lt;br /&gt;
		// Player order based on &#039;playerTeams&#039; option&lt;br /&gt;
		$playerOrder = [0, 1, 2, 3];&lt;br /&gt;
		switch (self::getGameStateValue(&#039;playerTeams&#039;)) {&lt;br /&gt;
			case self::TEAM_1_2:&lt;br /&gt;
				$playerOrder = [0, 2, 1, 3];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_1_4:&lt;br /&gt;
				$playerOrder = [0, 1, 3, 2];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_RANDOM:&lt;br /&gt;
				shuffle($playerOrder);&lt;br /&gt;
				break;&lt;br /&gt;
			default:&lt;br /&gt;
			case self::TEAM_1_3:&lt;br /&gt;
				// Default order&lt;br /&gt;
				break;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                // Create players&lt;br /&gt;
		// Note: if you added some extra field on &amp;quot;player&amp;quot; table in the database (dbmodel.sql), you can initialize it there.&lt;br /&gt;
		$sql =&lt;br /&gt;
			&#039;INSERT INTO player (player_id, player_color, player_canal, player_name, player_avatar, player_no) VALUES &#039;;&lt;br /&gt;
		$values = [];&lt;br /&gt;
&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$color = array_shift($default_colors);&lt;br /&gt;
			$values[] =&lt;br /&gt;
				&amp;quot;(&#039;&amp;quot; .&lt;br /&gt;
				$playerId .&lt;br /&gt;
				&amp;quot;&#039;,&#039;$color&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$player[&#039;player_canal&#039;] .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_name&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_avatar&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$playerOrder[$playerInitialOrder[$playerId]] .&lt;br /&gt;
				&amp;quot;&#039;)&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
		$sql .= implode(&#039;,&#039;, $values);&lt;br /&gt;
		self::DbQuery($sql);&lt;br /&gt;
		self::reattributeColorsBasedOnPreferences(&lt;br /&gt;
			$players,&lt;br /&gt;
			$gameinfos[&#039;player_colors&#039;]&lt;br /&gt;
		);&lt;br /&gt;
		self::reloadPlayersBasicInfos();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7008</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7008"/>
		<updated>2021-01-23T17:26:03Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
=== The &#039;&#039;&#039;player&#039;&#039;&#039; table ===&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&amp;lt;/br/&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; This value is &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
See [https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Assigning_Player_Order Assigning Player Order] in the &#039;&#039;&#039;BGA Studio Cookbook&#039;&#039;&#039; for an example.&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7007</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7007"/>
		<updated>2021-01-23T17:21:48Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&amp;lt;/br/&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; This value is &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
See [https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Assigning_Player_Order Assigning Player Order] in the &#039;&#039;&#039;BGA Studio Cookbook&#039;&#039;&#039; for an example.&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=7006</id>
		<title>BGA Studio Cookbook</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=7006"/>
		<updated>2021-01-23T17:17:45Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Assorted Stuff */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This page is collection of design and implementation recipes for BGA Studio framework.&lt;br /&gt;
For tooling and usage recipes see [[Tools and tips of BGA Studio]].&lt;br /&gt;
If you have your own recipes feel free to edit this page.&lt;br /&gt;
&lt;br /&gt;
== Visual Effects, Layout and Animation ==&lt;br /&gt;
&lt;br /&gt;
=== Create pieces dynamically (using template) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: this method is recommended by BGA guildlines&lt;br /&gt;
&lt;br /&gt;
Declared js template with variables in .tpl file, like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Javascript HTML templates&lt;br /&gt;
    var jstpl_ipiece = &#039;&amp;lt;div class=&amp;quot;${type} ${type}_${color} inlineblock&amp;quot; aria-label=&amp;quot;${name}&amp;quot; title=&amp;quot;${name}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use it like this in .js file&lt;br /&gt;
  div = this.format_block(&#039;jstpl_ipiece&#039;, {&lt;br /&gt;
                                type : &#039;meeple&#039;,&lt;br /&gt;
                                color : &#039;ff0000&#039;,&lt;br /&gt;
                                name : &#039;Bob&#039;,&lt;br /&gt;
                            });&lt;br /&gt;
  &lt;br /&gt;
Then you do whatever you need to do with that div, this one specifically design to go to log entries, because it has embedded title (otherwise its a picture only) and no id.&lt;br /&gt;
&lt;br /&gt;
Note: you could have place this variable in js itself, but keeping it in .tpl allows you to have your js code be free of HTML. Normally it never happens but&lt;br /&gt;
it is good to strive for it.&lt;br /&gt;
Note: you can also use string concatenation, its less readable. You can also use dojo dom object creation api&#039;s but its brutally verbose and its more unreadable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Create pieces dynamically (using string concatenation) ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: Not recommended&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  div = &amp;quot;&amp;lt;div class=&#039;meeple &amp;quot;+color+&amp;quot;&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Create all pieces statically ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.css, ggg.view.php (optional) &lt;br /&gt;
&lt;br /&gt;
* Create ALL game pieces in html template (.tpl)&lt;br /&gt;
* ALL pieces should have unique id, and it should be meaningful, i.e. meeple_red_1&lt;br /&gt;
* Do not use inline styling&lt;br /&gt;
* Id of player&#039;s specific pieces should use some sort of &#039;color&#039; identification, since player id cannot be used in static layout, you can use english color name, hex 6 char value, or color &amp;quot;number&amp;quot; (1,2,3...)&lt;br /&gt;
* Pieces should have separated class for its color, type, etc, so it can be easily styled in groups. In example below you now can style all meeples, all red meeples or all red tokens, or all &amp;quot;first&amp;quot; meeples&lt;br /&gt;
&lt;br /&gt;
ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
  &amp;lt;div id=&amp;quot;home_red&amp;quot; class=&amp;quot;home_red home&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_1&amp;quot; class=&amp;quot;meeple red n1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_2&amp;quot; class=&amp;quot;meeple red n2&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.css:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.meeple {&lt;br /&gt;
	width: 32px;&lt;br /&gt;
	height: 39px;&lt;br /&gt;
	background-image: url(img/78_64_stand_meeples.png);&lt;br /&gt;
	background-size: 352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.meeple.red {&lt;br /&gt;
	background-position: 30% 0%;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* There should be straight forward mapping between server id and js id (or 1:1)&lt;br /&gt;
* You place objects in different zones of the layout, and setup css to take care of layout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.home .meeple{&lt;br /&gt;
   display: inline-block;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you need to have a temporary object that look like original you can use dojo.clone (and change id to some temp id)&lt;br /&gt;
* If there is lots of repetition or zone grid you can use template generator, but inject style declaration in css instead of inline style for flexibility&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
* If you use this model you cannot use premade js components such as Stock and Zone&lt;br /&gt;
* You have to use alternative methods of animation (slightly altered) since default method will leave object with inline style attributes which you don&#039;t need&lt;br /&gt;
&lt;br /&gt;
=== Use thematic fonts ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.css&lt;br /&gt;
&lt;br /&gt;
Sometime game elements use specific fonts of text, if you want to match it up you can load some specific font (IMPORTANT: from some &#039;&#039;&#039;free font&#039;&#039;&#039; source. See notes below).&lt;br /&gt;
&lt;br /&gt;
[[File:Dragonline_font.png]]&lt;br /&gt;
&lt;br /&gt;
.css&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* latin-ext */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: 400;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/2Dy1Unur1HJoklbsg4iPJ_Y6323mHUZFJMgTvxaG2iE.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;&lt;br /&gt;
}&lt;br /&gt;
/* latin */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/gThgNuQB0o5ITpgpLi4Zpw.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;&lt;br /&gt;
}&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(http://ff.static.1001fonts.net/q/w/qwigley.regular.ttf) format(&#039;ttf&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.zone_title {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	font: italic 32px/32px &amp;quot;Qwigley&amp;quot;, cursive;	   &lt;br /&gt;
	height: 32px;&lt;br /&gt;
	width: auto;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NB:&#039;&#039;&#039; if you need to include a font that&#039;s not available online, an extra action will be needed from an admin. Please include the font file(s) in your img directory, and mention it to admins when requesting your game to be moved to alpha. &#039;&#039;&#039;Please remember that the font has to be free, and include a .txt with all appropriate license information about the font.&#039;&#039;&#039;&lt;br /&gt;
You can look for free fonts (for example) on https://fonts.google.com or https://www.fontsquirrel.com/)&lt;br /&gt;
&lt;br /&gt;
=== Use player color in template ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.view.php&lt;br /&gt;
&lt;br /&gt;
.view.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function build_page($viewArgs) {&lt;br /&gt;
        // Get players &amp;amp; players number&lt;br /&gt;
        $players = $this-&amp;gt;game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        $players_nbr = count($players);&lt;br /&gt;
        /**&lt;br /&gt;
         * ********* Place your code below: ***********&lt;br /&gt;
         */&lt;br /&gt;
        &lt;br /&gt;
        // Set PCOLOR to the current player color hex&lt;br /&gt;
        global $g_user;&lt;br /&gt;
        $cplayer = $g_user-&amp;gt;get_id();&lt;br /&gt;
        if (array_key_exists($cplayer, $players)) { // may be not set if spectator&lt;br /&gt;
            $player_color = $players [$cplayer] [&#039;player_color&#039;];&lt;br /&gt;
        } else {&lt;br /&gt;
            $player_color = &#039;ffffff&#039;; // spectator&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;tpl [&#039;PCOLOR&#039;] = $player_color;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Scale to fit for big boards ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
Lets say you have huge game board, and lets say you want it to be 1400px wide. Besides the board there will be side bar which is 240 and trim. &lt;br /&gt;
My display is 1920 wide so it fits, but there is big chance other people won&#039;t have that width. What do you do?&lt;br /&gt;
Easiest thing I came up with is to scale whole content to fit (everything you declare in .tpl file). Tested or firefox and chrome.&lt;br /&gt;
&lt;br /&gt;
ggg_ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   &amp;lt;div id=&amp;quot;thething&amp;quot; class=&amp;quot;thething&amp;quot; style=&amp;quot;width: 1400px;&amp;quot;&amp;gt;&lt;br /&gt;
            ... everything else you declare ...&lt;br /&gt;
   &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setup : function(gamedatas) {&lt;br /&gt;
          console.log(&amp;quot;Starting game setup&amp;quot;);&lt;br /&gt;
          ...&lt;br /&gt;
          this.interface_min_width = 740;&lt;br /&gt;
          this.interface_max_width = 1400;&lt;br /&gt;
          dojo.connect(window, &amp;quot;onresize&amp;quot;, this, dojo.hitch(this, &amp;quot;adaptViewportSize&amp;quot;));&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    adaptViewportSize : function() {&lt;br /&gt;
        var pageid = &amp;quot;page-content&amp;quot;;&lt;br /&gt;
        var nodeid = &amp;quot;thething&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        var bodycoords = dojo.marginBox(pageid);&lt;br /&gt;
        var contentWidth = bodycoords.w;&lt;br /&gt;
&lt;br /&gt;
        var browserZoomLevel = window.devicePixelRatio; &lt;br /&gt;
        //console.log(&amp;quot;zoom&amp;quot;,browserZoomLevel);&lt;br /&gt;
        if (contentWidth &amp;gt;= this.interface_max_width || browserZoomLevel &amp;gt;1  || this.control3dmode3d) {&lt;br /&gt;
            dojo.style(nodeid,&#039;transform&#039;,&#039;&#039;);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var percentageOn1 = contentWidth / this.interface_max_width;&lt;br /&gt;
        dojo.style(nodeid, &amp;quot;transform&amp;quot;, &amp;quot;scale(&amp;quot; + percentageOn1 + &amp;quot;)&amp;quot;);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this method does not seems to work to retina resolution displays, if you know better way let me know&lt;br /&gt;
&lt;br /&gt;
=== Dynamic tooltips ===&lt;br /&gt;
&lt;br /&gt;
If you really need a dynamic tooltip you can use this technique. (Only use it if the static tooltips provided by the BGA framework are not sufficient.)&lt;br /&gt;
&lt;br /&gt;
            new dijit.Tooltip({&lt;br /&gt;
                connectId: [&amp;quot;divItemId&amp;quot;],&lt;br /&gt;
                getContent: function(matchedNode){&lt;br /&gt;
                    return &amp;quot;... calculated ...&amp;quot;; &lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is an out-of-the-box djit.Tooltip. It has a &#039;&#039;getContent&#039;&#039; method which is called dynamically.&lt;br /&gt;
&lt;br /&gt;
The string function return becomes the innerHTML of the tooltip, so it can be anything. In this example matchedNode is a dojo node representing dom object with id of &amp;quot;divItemId&amp;quot; but there are more parameters which I am not posting here which allows more sophisticated subnode queries (i.e. you can attach tooltip to all nodes with class or whatever).&lt;br /&gt;
&lt;br /&gt;
[https://dojotoolkit.org/reference-guide/1.10/dijit/Tooltip.html dijit.Tooltip]&lt;br /&gt;
&lt;br /&gt;
It&#039;s not part of the BGA API so use at your own risk.&lt;br /&gt;
&lt;br /&gt;
=== Accessing images from js ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
     // your game resources&lt;br /&gt;
     &lt;br /&gt;
     var my_img = &#039;&amp;lt;img src=&amp;quot;&#039;+g_gamethemeurl+&#039;img/cards.jpg&amp;quot;/&amp;gt;&#039;;&lt;br /&gt;
     &lt;br /&gt;
     // shared resources&lt;br /&gt;
     var my_help_img = &amp;quot;&amp;lt;img class=&#039;imgtext&#039; src=&#039;&amp;quot; + g_themeurl + &amp;quot;img/layout/help_click.png&#039; alt=&#039;action&#039; /&amp;gt; &amp;lt;span class=&#039;tooltiptext&#039;&amp;gt;&amp;quot; +&lt;br /&gt;
                    text + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Rendering text with players color and proper background ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
This example actually writes &amp;quot;You&amp;quot; but you can replace this with player name as easily, drop translating function in this case&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        /* Implementation of proper colored You with background in case of white or light colors  */&lt;br /&gt;
 &lt;br /&gt;
        divYou : function() {&lt;br /&gt;
            var color = this.gamedatas.players[this.player_id].color;&lt;br /&gt;
            var color_bg = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.gamedatas.players[this.player_id] &amp;amp;&amp;amp; this.gamedatas.players[this.player_id].color_back) {&lt;br /&gt;
                color_bg = &amp;quot;background-color:#&amp;quot; + this.gamedatas.players[this.player_id].color_back + &amp;quot;;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            var you = &amp;quot;&amp;lt;span style=\&amp;quot;font-weight:bold;color:#&amp;quot; + color + &amp;quot;;&amp;quot; + color_bg + &amp;quot;\&amp;quot;&amp;gt;&amp;quot; + __(&amp;quot;lang_mainsite&amp;quot;, &amp;quot;You&amp;quot;) + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
            return you;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Inject icon images in the log ===&lt;br /&gt;
&lt;br /&gt;
Here is an example of what was done for Terra Mystica which is simple and straightforward:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//Define the proper message&lt;br /&gt;
		$message = clienttranslate(&#039;${player_name} gets ${power_income} via Structures&#039;);&lt;br /&gt;
		if ($price &amp;gt; 0) {&lt;br /&gt;
			self::DbQuery(&amp;quot;UPDATE player SET player_score = player_score - $price WHERE player_id = $player_id&amp;quot;);&lt;br /&gt;
			$message = clienttranslate(&#039;${player_name} pays ${vp_price} and gets ${power_income} via Structures&#039;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
// Notify&lt;br /&gt;
		self::notifyAllPlayers( &amp;quot;powerViaStructures&amp;quot;, $message, array(&lt;br /&gt;
			&#039;i18n&#039; =&amp;gt; array( ),&lt;br /&gt;
			&#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
			&#039;player_name&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_name FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;power_tokens&#039; =&amp;gt; $power_tokens,&lt;br /&gt;
			&#039;vp_price&#039; =&amp;gt; self::getLogsVPAmount($price),&lt;br /&gt;
			&#039;power_income&#039; =&amp;gt; self::getLogsPowerAmount($power_income),&lt;br /&gt;
			&#039;newScore&#039; =&amp;gt; self::getUniqueValueFromDb( &amp;quot;SELECT player_score FROM player WHERE player_id = $player_id&amp;quot; ),&lt;br /&gt;
			&#039;counters&#039; =&amp;gt; $this-&amp;gt;getGameCounters(null),&lt;br /&gt;
		) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some functions to have the needed html added inside the substitution variable, such as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function getLogsPowerAmount( $amount ) {&lt;br /&gt;
		return &amp;quot;&amp;lt;div class=&#039;tmlogs_icon&#039; title=&#039;Power&#039;&amp;gt;&amp;lt;div class=&#039;power_amount&#039;&amp;gt;$amount&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: injecting html from php is not ideal but easy, if you want more clean solution, use method below but it is a lot more sophisticated.&lt;br /&gt;
&lt;br /&gt;
=== Inject images and styled html in the log ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php&lt;br /&gt;
&lt;br /&gt;
So you want nice pictures in the game log. What do you do? The first idea that comes to mind is to send html from php in notifications (see method above). &lt;br /&gt;
&lt;br /&gt;
This is a bad idea for many reasons:&lt;br /&gt;
&lt;br /&gt;
* It&#039;s bad architecture. ui elements leak into the server, and now you have to manage the ui in multiple places.&lt;br /&gt;
* If you decided to change something in the ui in future version, replay logs for old games and tutorials may not work, since they use stored notifications.&lt;br /&gt;
* Log previews for old games become unreadable. (This is the log state before you enter the game replay, which is useful for troubleshooting and game analysis.)&lt;br /&gt;
* It&#039;s more data to transfer and store in the db.&lt;br /&gt;
* It&#039;s a nightmare for translators.&lt;br /&gt;
&lt;br /&gt;
So what else can you do? I use this recipe for &#039;&#039;&#039;client side log injection&#039;&#039;&#039; to intercept log arguments (which come from the server) and replace them with html on the client side.&lt;br /&gt;
&lt;br /&gt;
[[File:clientloginjection.png|left]] &lt;br /&gt;
&lt;br /&gt;
ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
        /** Override this function to inject html into log items. This is a built-in BGA method.  */&lt;br /&gt;
&lt;br /&gt;
        /* @Override */&lt;br /&gt;
        format_string_recursive : function(log, args) {&lt;br /&gt;
            try {&lt;br /&gt;
                if (log &amp;amp;&amp;amp; args &amp;amp;&amp;amp; !args.processed) {&lt;br /&gt;
                    args.processed = true;&lt;br /&gt;
                    &lt;br /&gt;
&lt;br /&gt;
                    // list of special keys we want to replace with images&lt;br /&gt;
                    var keys = [&#039;place_name&#039;,&#039;token_name&#039;];&lt;br /&gt;
                    &lt;br /&gt;
                  &lt;br /&gt;
                    for ( var i in keys) {&lt;br /&gt;
                        var key = keys[i];&lt;br /&gt;
                        args[key] = this.getTokenDiv(key, args);                            &lt;br /&gt;
&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                console.error(log,args,&amp;quot;Exception thrown&amp;quot;, e.stack);&lt;br /&gt;
            }&lt;br /&gt;
            return this.inherited(arguments);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; In the &#039;&#039;format_string_recursive&#039;&#039; method, the &#039;args&#039; parameter will only contain arguments passed to it from the notify method in ggg.game.php (see below).&lt;br /&gt;
&lt;br /&gt;
The &#039;log&#039; parameter is the actual string that is inserted into the logs. You can perform additional js string manipulation on it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        getTokenDiv : function(key, args) {&lt;br /&gt;
            // ... implement whatever html you want here, example from sharedcode.js&lt;br /&gt;
            var token_id = args[key];&lt;br /&gt;
            var item_type = getPart(token_id,0);&lt;br /&gt;
            var logid = &amp;quot;log&amp;quot; + (this.globalid++) + &amp;quot;_&amp;quot; + token_id;&lt;br /&gt;
            switch (item_type) {&lt;br /&gt;
                case &#039;wcube&#039;:&lt;br /&gt;
                    var tokenDiv = this.format_block(&#039;jstpl_resource_log&#039;, {&lt;br /&gt;
                        &amp;quot;id&amp;quot; : logid,&lt;br /&gt;
                        &amp;quot;type&amp;quot; : &amp;quot;wcube&amp;quot;,&lt;br /&gt;
                        &amp;quot;color&amp;quot; : getPart(token_id,1),&lt;br /&gt;
                    });&lt;br /&gt;
                    return tokenDiv;&lt;br /&gt;
                    break;&lt;br /&gt;
                case &#039;meeple&#039;:&lt;br /&gt;
                    if ($(token_id)) {&lt;br /&gt;
                        var clone = dojo.clone($(token_id));&lt;br /&gt;
    &lt;br /&gt;
                        dojo.attr(clone, &amp;quot;id&amp;quot;, logid);&lt;br /&gt;
                        this.stripPosition(clone);&lt;br /&gt;
                        dojo.addClass(clone, &amp;quot;logitem&amp;quot;);&lt;br /&gt;
                        return clone.outerHTML;&lt;br /&gt;
                    }&lt;br /&gt;
                    break;&lt;br /&gt;
     &lt;br /&gt;
                default:&lt;br /&gt;
                    break;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return &amp;quot;&#039;&amp;quot; + this.clienttranslate_string(this.getTokenName(token_id)) + &amp;quot;&#039;&amp;quot;;&lt;br /&gt;
       },&lt;br /&gt;
       getTokenName : function(key) {&lt;br /&gt;
           return this.gamedatas.token_types[key].name; // get name for the key, from static table for example&lt;br /&gt;
       },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in this case the server simply injects token_id as a name, and the client substitutes it for the translated name or the picture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ggg.game.php:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name}&#039;),[&#039;token_name&#039;=&amp;gt;$token_id]);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; As noted above, only arguments actually passed by this method are available to the args parameter received in the client-side &#039;&#039;format_string_recursive&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is the case that you want to pass arguments that are not actually included in the output message. For example, suppose we have a method like this:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notifyAllPlayers(&#039;tokenPlaced&#039;,clienttranslate(&#039;Player placed ${token_name}&#039;),array(&lt;br /&gt;
              &#039;token_name&#039; =&amp;gt; $token_id,&lt;br /&gt;
              &#039;zone_played&#039; =&amp;gt; $zone);&lt;br /&gt;
&lt;br /&gt;
This will output &amp;quot;Player placed ${token_name}&amp;quot; in the log, and if we subscribe to a notification method activated by the &amp;quot;tokenPlaced&amp;quot; event in the client-side code, that method can make use of the &#039;zone_played&#039; argument. &#039;&#039;&#039;But&#039;&#039;&#039; &#039;zone_played&#039; &#039;&#039;will not be available&#039;&#039; in the &#039;&#039;format_string_recursive&#039;&#039; method unless it is actually passed in the log message (i.e., in the string contained inside clienttranslate).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now if you don&#039;t like raw log containing id instead of name but want name, and want substitution, you can use another parameter as id. The problem with that,&lt;br /&gt;
it will work at first, but if you reload game using F5 you will loose your additional parameters, why? Because when game reloads it does not actually send same&lt;br /&gt;
notifications, it sends special &amp;quot;hitstorical_log&amp;quot; notification where all  parameters not listed in the &amp;quot;log&amp;quot; are removed. There is a hack (feature) to circumvent that,&lt;br /&gt;
called recursive parameters. I.e. you can send stuff like this:&lt;br /&gt;
 &lt;br /&gt;
             $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name_rec}&#039;),&lt;br /&gt;
                    [&#039;token_name_rec&#039;=&amp;gt;[&#039;log&#039;=&amp;gt;&#039;${token_name}&#039;,&lt;br /&gt;
                                        &#039;args&#039;=&amp;gt; [&#039;token_name&#039;=&amp;gt;clienttranslate(&#039;Boo&#039;), &#039;token_id&#039;=&amp;gt;$token_id, &#039;i18n&#039;=&amp;gt;[&#039;token_name&#039;] ]&lt;br /&gt;
                                       ]&lt;br /&gt;
                    ]);&lt;br /&gt;
&lt;br /&gt;
and in format_log_recursive&lt;br /&gt;
             var key = &#039;token_name&#039;;&lt;br /&gt;
             if (typeof args[key] == &#039;string&#039; &amp;amp;&amp;amp; typeof args[&#039;token_id&#039;] == &#039;string&#039;) {&lt;br /&gt;
                 args[key] = this.getTokenDiv(&#039;token_id&#039;, args);                            &lt;br /&gt;
             }&lt;br /&gt;
&lt;br /&gt;
=== High-Definition Graphics ===&lt;br /&gt;
&lt;br /&gt;
Some users will have screens which can display text and images at a greater resolution than the usual 72 dpi, e.g. the &amp;quot;Retina&amp;quot; screens on the 5k iMac, all iPads, and high-DPI screens on laptops from many manufacturers. If you can get art assets at this size, they will make your game look extra beautiful. You &#039;&#039;could&#039;&#039; just use large graphics and scale them down, but that would increase the download time and bandwidth for users who can&#039;t display them. Instead, a good way is to prepare a separate graphics file at exactly twice the size you would use otherwise, and add &amp;quot;@2x&amp;quot; at the end of the filename, e.g. if pieces.png is 240x320, then pieces@2x.png is 480x640.&lt;br /&gt;
&lt;br /&gt;
There are two changes required in order to use the separate graphics files. First in your css, where you use a file, add a media query which overrides the original definition and uses the bigger version on devices which can display them. Ensuring that the &amp;quot;background-size&amp;quot; attribute is set means that the size of the displayed object doesn&#039;t change, but only is drawn at the improved dot pitch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.piece {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    background-image: url(&#039;img/pieces.png&#039;);&lt;br /&gt;
    background-size:240px 320px;&lt;br /&gt;
    z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&lt;br /&gt;
{&lt;br /&gt;
    .piece {&lt;br /&gt;
        background-image: url(&#039;img/pieces@2x.png&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Secondly, in your setup function in javascript, you must ensure than only the appropriate one version of the file gets pre-loaded (otherwise you more than waste the bandwidth saved by maintaining the standard-resolution file). Note that the media query is the same in both cases:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            var isRetina = &amp;quot;(-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&amp;quot;;&lt;br /&gt;
            if (window.matchMedia(isRetina).matches)&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces@2x.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board@2x.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Cool realistic shadow effect with CSS ===&lt;br /&gt;
&lt;br /&gt;
If you wish to make a shadow effect for game pieces that are not rectangle, do not use box-shadow but use filter, which is supported by recent major browsers.  This way, you can use the alpha channel of your element to drop a shadow.  This even work for transparent backgrounds, so that if you are using the &amp;quot;CSS-sprite&amp;quot; method, it will work!&lt;br /&gt;
&lt;br /&gt;
For instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.xxx-token {&lt;br /&gt;
    filter: drop-shadow(0px 0px 1px #000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Using the CSS classes from the state machine ===&lt;br /&gt;
&lt;br /&gt;
If you need to hide or show stuff depending on the state of your game, you can of course use javascript, but CSS is hand enough for that.  The #overall-content element does change class depending on the game state.  For instance, if you are in state &#039;&#039;playerTurn&#039;&#039;, it will have the class &#039;&#039;gamestate_playerTurn&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
So now, if you want to show the discard pile only during player turns, you may use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#discard_pile { display: none }&lt;br /&gt;
.gamestate_playerTurn #discard_pile { display: block }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This can be used if you want to change sizing of elements, position, layout or visual appearance.&lt;br /&gt;
&lt;br /&gt;
=== More readable JS: onEnteringState ===&lt;br /&gt;
&lt;br /&gt;
If you have a lot of states onEnteringState and friends become rather wild, you can do this trick to call some method dynamically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
     onEnteringState: function(stateName, args) {&lt;br /&gt;
       console.log(&#039;Entering state: &#039; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
       // Call appropriate method&lt;br /&gt;
       var methodName = &amp;quot;onEnteringState_&amp;quot; + stateName;&lt;br /&gt;
       if (this[methodName] !== undefined) {             &lt;br /&gt;
          console.log(&#039;Calling &#039; + methodName, args.args);&lt;br /&gt;
          this[methodName](args.args);&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerTurn: function(args) { // this is args directly, not args.args &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerSomethingElse: function(args) { &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: since its ignores the undefined functions you don&#039;t have define function for each state, but on the other hand you cannot make typos.&lt;br /&gt;
Same applies to onUpdateActionButtons except you pass &#039;args&#039; to method, not args.args, and for onLeavingState where you don&#039;t pass anything.&lt;br /&gt;
&lt;br /&gt;
== Game Model and Database design ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Database for The euro game ===&lt;br /&gt;
Lets say we have a game with workers, dice, tokens, board, resources, money and vp. Workers and dice can be placed in various zones on the board, and you can get resources, money, tokens and vp in your home zone. Also tokens can be flipped or not flipped.&lt;br /&gt;
&lt;br /&gt;
[[File:Madeira board.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now lets try to map it, we have&lt;br /&gt;
* (meeple,zone)&lt;br /&gt;
* (die, zone, sideup)&lt;br /&gt;
* (resource cube/money token/vp token,player home zone)&lt;br /&gt;
* (token, player home zone, flip state)&lt;br /&gt;
We can notice that resource and money are uncountable, and don&#039;t need to be track individually so we can replace our mapping to&lt;br /&gt;
* (resource type/money,player home zone, count)&lt;br /&gt;
And vp stored already for us in player table, so we can remove it from that list.&lt;br /&gt;
&lt;br /&gt;
Now when we get to encode it we can see that everything can be encoded as (object,zone,state) form, where object and zone is string and state is integer. The resource mapping is slightly different semantically so you can go with two table, or counting using same table with state been used as count for resources.&lt;br /&gt;
&lt;br /&gt;
So the piece mapping for non-grid based games can be in most case represented by (string: token_key, string: token_location, int: token_state), example of such database schema can be found here: [https://github.com/elaskavaia/bga-sharedcode/blob/master/dbmodel.sql dbmodel.sql] and class implementing access to it here [https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php table.game.php].&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|meeple_red_1&lt;br /&gt;
|home_red&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|dice_black_2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|dice_green_1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|bread&lt;br /&gt;
|home_red&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Now how we represent resource counters such as bread?&lt;br /&gt;
Using same table from we simply add special counter token for bread and use state to indicate the count. Note to keep first column unique we have to add player identification for that counter, i.e. ff0000 is red player.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_key&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|bread_ff0000&lt;br /&gt;
|tableau_ff0000&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
See php module for this table here https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php&lt;br /&gt;
&lt;br /&gt;
Variant 2: Additional resource table, resource count for each player id&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `resource` (&lt;br /&gt;
  `player_id` int(10) unsigned NOT NULL,&lt;br /&gt;
  `resource_key` varchar(32) NOT NULL,&lt;br /&gt;
  `resource_count` int(10) signed NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`player_id`,`resource_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
 ALTER TABLE resource ADD CONSTRAINT fk_player_id FOREIGN KEY (player_id) REFERENCES player(player_id);&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+resource&lt;br /&gt;
! player_id&lt;br /&gt;
! resource_key&lt;br /&gt;
! resource_count&lt;br /&gt;
|-&lt;br /&gt;
|123456&lt;br /&gt;
|bread&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 3: More normalised&lt;br /&gt;
&lt;br /&gt;
This version is similar to &amp;quot;card&amp;quot; table from hearts tutorial, you can also use exact cards database schema and Deck implementation for most purposes (even you not dealing with cards). &lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `token_type` varchar(16) NOT NULL,&lt;br /&gt;
  `token_arg` int(11) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_id`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
! token_id&lt;br /&gt;
! token_type&lt;br /&gt;
! token_arg&lt;br /&gt;
! token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|22&lt;br /&gt;
|meeple&lt;br /&gt;
|123456&lt;br /&gt;
|home_123456&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|23&lt;br /&gt;
|dice&lt;br /&gt;
|2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|26&lt;br /&gt;
|dice&lt;br /&gt;
|1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|49&lt;br /&gt;
|bread&lt;br /&gt;
|0&lt;br /&gt;
|home_123456&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Advantages of this would be is a bit more straightforward to do some queries in db, disadvantage its hard to read (as you can compare with previous example, you&lt;br /&gt;
cannot just look at say, ah I know what it means). Another questionable advantage is it allows you to do id randomisation, so it hard to do crafted queries to &lt;br /&gt;
cheat, the down side of that you cannot understand it either, and handcraft db states for debugging or testing.&lt;br /&gt;
&lt;br /&gt;
=== Database for The card game ===&lt;br /&gt;
&lt;br /&gt;
Lets say you have a standard card game, player have hidden cards in hand, you can draw card from draw deck, play card on tableau and discard to discard pile.&lt;br /&gt;
We have to design database for such game.&lt;br /&gt;
&lt;br /&gt;
In real word to &amp;quot;save&amp;quot; the game we take a picture a play area, save cards from it, then put away draw deck, discard and hand of each player separately and mark it, also we will record current scoring (if any) and who&#039;s turn was it.&lt;br /&gt;
&lt;br /&gt;
* Framework handles state machine transition, so you don&#039;t have to worry about database design for that (i.e. who&#039;s turn it is, what phase of the game we are at, you still have to design it but part of state machine step)&lt;br /&gt;
* Also framework supports basic player information, color, order around the table, basic scoring, etc, so you don&#039;t have to worry about it either&lt;br /&gt;
* The only thing you need in our database is state of the &amp;quot;board&amp;quot;, which is &amp;quot;where each pieces is, and in what state&amp;quot;, or (position,rotation) pair.&lt;br /&gt;
&lt;br /&gt;
Lets see what we have for that:&lt;br /&gt;
* The card state is very simple, its usually &amp;quot;face up/face down&amp;quot;, &amp;quot;tapped/untapped&amp;quot;, &amp;quot;right side up/up side down&amp;quot;&lt;br /&gt;
* As position go we never need real coordinates x,y,z. We need to know what &amp;quot;zone&amp;quot; card was, and depending on the zone it may sometimes need an extra &amp;quot;z&amp;quot; or &amp;quot;x&amp;quot; as card order. The zone position usually static or irrelevant.&lt;br /&gt;
* So our model is: we have cards, which have some attributes, at any given point in time they belong to a &amp;quot;zone&amp;quot;, and can also have order and state&lt;br /&gt;
* Now for mapping we should consider what information changes and what information is static, later is always candidate for material file&lt;br /&gt;
* For dynamic information we should try to reduce amount of fields we need&lt;br /&gt;
**  we need at least a field for card, so its one&lt;br /&gt;
**  we need to know what zone cards belong to, its 2&lt;br /&gt;
**  and we have possibly few other fields, if you look closely at you game you may find out that most of the zone only need one attribute at a time, i.e. draw pile always have cards face down, hand always face up, also for hand and discard order does not matter at all (but for draw it does matter). So in majority of cases we can get away with one single extra integer field representing state or order&lt;br /&gt;
* In real database both card and zone will be integers as primary keys referring to additional tables, but in our case its total overkill, so they can be strings as easily&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_key` varchar(32) unsigned NOT NULL,&lt;br /&gt;
  `card_location` varchar(32) NOT NULL,&lt;br /&gt;
  `card_state` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 2: More normalised&lt;br /&gt;
&lt;br /&gt;
This version supported by Deck php class, so unless you want to rewrite db access layer go with this one&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you using this schema, some zones/locations have special semantic. The &#039;hand&#039; location is actually multiple locations - one per player, but player id is encoded as card_location_arg. If &#039;hand&#039; in your game is ordered, visible or can have some other card states, you cannot use hand location (replacement is hand_&amp;lt;player_id&amp;gt; or hand_&amp;lt;color_id&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
== Game Modules ==&lt;br /&gt;
&lt;br /&gt;
=== Including your own JavaScript module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, modules/ggg_other.js&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.js in modules/ folder and sync&lt;br /&gt;
* Modify ggg.js to include it&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  define([ &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;, &amp;quot;ebg/core/gamegui&amp;quot;, &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    // load my own module!!!&lt;br /&gt;
    g_gamethemeurl + &amp;quot;modules/ggg_other.js&amp;quot; ], function(dojo,&lt;br /&gt;
        declare) {&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Including your own PHP module ===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, modules/ggg_other.php&lt;br /&gt;
&lt;br /&gt;
* Create ggg_other.php in modules/ folder and sync&lt;br /&gt;
* Modify ggg.game.php to include it&lt;br /&gt;
&lt;br /&gt;
 require_once (&#039;modules/ggg_other.php&#039;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Avoiding code in dojo declare style ===&lt;br /&gt;
Dojo class declarations are rather bizzare and do not work with most IDEs.&lt;br /&gt;
If you want to write in plain JS with classes you can stub all the dojo define/declare stuff&lt;br /&gt;
and hook your class into that, so class if outside of this mess.&lt;br /&gt;
&lt;br /&gt;
NOTE: this technique is for experienced developers, do not try it if you do not understand&lt;br /&gt;
the consequences.&lt;br /&gt;
&lt;br /&gt;
This is complete example of game .js class&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Testla is game name is has to be changed&lt;br /&gt;
class Testla {&lt;br /&gt;
	constructor(game) {&lt;br /&gt;
		console.log(&#039;game constructor&#039;);&lt;br /&gt;
		this.game = game;&lt;br /&gt;
		this.varfoo = new MyFoo(); // this example of class from custom module&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	setup(gamedatas) {&lt;br /&gt;
		console.log(&amp;quot;Starting game setup&amp;quot;, this.varfoo);&lt;br /&gt;
		this.gamedatas = gamedatas;&lt;br /&gt;
		this.dojo.create(&amp;quot;div&amp;quot;, { class: &#039;whiteblock&#039;, innerHTML: _(&amp;quot;hello&amp;quot;) }, &#039;thething&#039;);&lt;br /&gt;
		console.log(&amp;quot;Ending game setup&amp;quot;);&lt;br /&gt;
	};&lt;br /&gt;
	onEnteringState(stateName, args) {&lt;br /&gt;
		console.log(&#039;onEnteringState : &#039; + stateName, args);&lt;br /&gt;
		this.game.addActionButton(&#039;b1&#039;,_(&#039;Click Me&#039;), (e)=&amp;gt;this.onButtonClick(e));&lt;br /&gt;
	};&lt;br /&gt;
	onLeavingState(stateName) {&lt;br /&gt;
		console.log(&#039;onLeavingState : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onUpdateActionButtons(stateName, args) {&lt;br /&gt;
		console.log(&#039;onUpdateActionButtons : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onButtonClick(event) {&lt;br /&gt;
		console.log(&#039;onButtonClick&#039;,event);&lt;br /&gt;
	};&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
define([&lt;br /&gt;
	&amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
	g_gamethemeurl + &#039;/modules/foo.js&#039; // custom module if needed&lt;br /&gt;
],&lt;br /&gt;
	function(dojo, declare) {&lt;br /&gt;
                // testla is game name is has to be changed&lt;br /&gt;
		return declare(&amp;quot;bgagame.testla&amp;quot;, ebg.core.gamegui, {&lt;br /&gt;
			constructor: function() {&lt;br /&gt;
				this.xapp = new Testla(this);&lt;br /&gt;
				this.xapp.dojo = dojo;&lt;br /&gt;
			},&lt;br /&gt;
			setup: function(gamedatas) {&lt;br /&gt;
				this.xapp.setup(gamedatas);&lt;br /&gt;
			},&lt;br /&gt;
			onEnteringState: function(stateName, args) {&lt;br /&gt;
				this.xapp.onEnteringState(stateName, args.args);&lt;br /&gt;
			},&lt;br /&gt;
			onLeavingState: function(stateName) {&lt;br /&gt;
				this.xapp.onLeavingState(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
			onUpdateActionButtons: function(stateName, args) {&lt;br /&gt;
				this.xapp.onUpdateActionButtons(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
		});&lt;br /&gt;
	});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Assorted Stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Out-of-turn actions: Un-pass ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg.action.php, states.inc.php&lt;br /&gt;
&lt;br /&gt;
In multiplayer game sometimes players passes but than they think more and want to un-Pass and redo their choice. &lt;br /&gt;
To re-active a player who passes some trickery required.&lt;br /&gt;
&lt;br /&gt;
Define a special action that does how and hook it up.&lt;br /&gt;
&lt;br /&gt;
In states.inc.php add an action to mmultipleactiveplayer state to &amp;quot;unpass&amp;quot;, lets call it &amp;quot;actionCancel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In ggg.action.php add action hook&lt;br /&gt;
    public function actionCancel() {&lt;br /&gt;
        self::setAjaxMode();&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;actionCancel();&lt;br /&gt;
        self::ajaxResponse();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
In ggg.game.php add action handler&lt;br /&gt;
    function actionCancel() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction(&#039;actionCancel&#039;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive(array ($this-&amp;gt;getCurrentPlayerId() ), &#039;error&#039;, false);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Finally to call this in client ggg.js you would do something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 onUpdateActionButtons:  function(stateName, args) {&lt;br /&gt;
   if (this.isCurrentPlayerActive()) { &lt;br /&gt;
     // ...&lt;br /&gt;
   } else if (!this.isSpectator) { // player is NOT active but not spectatoe&lt;br /&gt;
       switch (stateName) {&lt;br /&gt;
          case &#039;playerTurnMuliPlayerState&#039;:&lt;br /&gt;
		this.addActionButton(&#039;button_unpass&#039;, _(&#039;Oh no!&#039;), &#039;onUnpass&#039;);&lt;br /&gt;
		break;&lt;br /&gt;
	}&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
				&lt;br /&gt;
 onUnpass: function(e) {&lt;br /&gt;
    this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; +  this.game_name + &amp;quot;/actionCancel.html&amp;quot;, {}, this); // no checkAction!&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Although be careful that if the turn comes back to the player while he is about to click cancel, the action buttons will be updated and the player will misclick which can be quite frustrating. To avoid this, move the cancel button to another position, like to the left of pagemaintitletext:&lt;br /&gt;
  dojo.place(&#039;button_unpass&#039;, &#039;pagemaintitletext&#039;, &#039;before&#039;);&lt;br /&gt;
Being out of the generalactions div, it won&#039;t be automatically destroyed like normal buttons, so you&#039;ll have to handle that yourself in onLeavingState. You might also want to change the button color to red (blue buttons for active player only, red buttons also for inactive players?)&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Selection ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Simple way to implement something like that without extra states is to use &amp;quot;selection&amp;quot; mechanism. When user click on worker add some sort of class into that element i.e. &#039;selected&#039; (which also have to have some indication by css i.e. outline).&lt;br /&gt;
&lt;br /&gt;
Than user can click on placement zone, you can use dojo.query for &amp;quot;selected&amp;quot; element and use it along with zone id to send data to server. If proper worker is not selected yet can give a error message using this.showMessage(...) function.&lt;br /&gt;
&lt;br /&gt;
Extra code required to properly cleanup selection between states&lt;br /&gt;
&lt;br /&gt;
=== Multi Step Interactions: Select Worker/Place Worker - Using Client States ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
I don&#039;t think its documented feature but there is a way to do client-only states, which is absolutely wonderful for few reasons&lt;br /&gt;
* When player interaction is two step process, such as select worker, place worker, or place worker, pick one of two resources of your choice&lt;br /&gt;
* When multi-step process can result of impossible situation and has to be undone (by rules)&lt;br /&gt;
* When multi-step process is triggered from multiple states (such as you can do same thing as activated card action, pass action or main action)&lt;br /&gt;
&lt;br /&gt;
So lets do Select Worker/Place Worker&lt;br /&gt;
&lt;br /&gt;
Define your server state as usual, i.e. playerMainTurn -&amp;gt; &amp;quot;You must pick up a worker&amp;quot;.&lt;br /&gt;
Now define a client state, we only need &amp;quot;name&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;, lets say &amp;quot;client_playerPicksLocation&amp;quot;. Always prefix names of client state with &amp;quot;client_&amp;quot; to avoid confusion. Now we have to do the following:&lt;br /&gt;
* Have a handler for onUpdateActionButtons for playerMainTurn to activate all possible workers he can pick&lt;br /&gt;
* When player clicks workers, remember the worker in one of the members of the main class, I usually use one called this.clientStateArgs.&lt;br /&gt;
* Transition to new client state&lt;br /&gt;
  onWorker: function(e) {&lt;br /&gt;
      var id = event.currentTarget.id;&lt;br /&gt;
      dojo.stopEvent(event);&lt;br /&gt;
      ... // do validity checks&lt;br /&gt;
      this.clientStateArgs.worker_id = id;&lt;br /&gt;
      this.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                                descriptionmyturn : &amp;quot;${you} must select location&amp;quot;,&lt;br /&gt;
                            });&lt;br /&gt;
   }&lt;br /&gt;
* Have a handler for onUpdateActionButtons for client_playerPicksLocation to activate all possible locations this worker can go AND add Cancel button (see below)&lt;br /&gt;
* Have a location handler which will eventually send a server request, using stored this.clientStateArgs.worker_id as worker id&lt;br /&gt;
* The cancel button should call a method to restore server state, also if you doing it for more than one state you can add this universally using this.on_client_state check&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        if (this.isCurrentPlayerActive()) {&lt;br /&gt;
          if (this.on_client_state &amp;amp;&amp;amp; !$(&#039;button_cancel&#039;)) {&lt;br /&gt;
               this.addActionButton(&#039;button_cancel&#039;, _(&#039;Cancel&#039;), dojo.hitch(this, function() {&lt;br /&gt;
                                             this.restoreServerGameState();&lt;br /&gt;
               }));&lt;br /&gt;
          }&lt;br /&gt;
        } &lt;br /&gt;
Note: usually I call my own function call this.cancelLocalStateEffects() which will do more stuff first then call restoreServerGameState(), same function is usually needs to be called when server request has failed (i.e. invalid move)&lt;br /&gt;
&lt;br /&gt;
Note: If you need more than 2 steps, you may have to do client side animation to reflect the new state, which gets trickier because you have to undo that also on cancellation.&lt;br /&gt;
&lt;br /&gt;
Code is available here [https://github.com/elaskavaia/bga-sharedcode/blob/master/sharedcode.js sharedcode.js] (its using playerTurnPlayCubes and client_selectCubeLocation).&lt;br /&gt;
&lt;br /&gt;
=== Assigning Player Order ===&lt;br /&gt;
&lt;br /&gt;
If you want to arbitrarily assign player order at the start of the game (for example, in a game with teams options), you can do so by retrieving the initialization-only player attribute &#039;&#039;&#039;player_table_order&#039;&#039;&#039; and using it to assign values to &#039;&#039;&#039;player_no&#039;&#039;&#039; (which is normally assigned at the start of a game in the order in which players come to the table).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                // Retrieve inital player order ([0=&amp;gt;playerId1, 1=&amp;gt;playerId2, ...])&lt;br /&gt;
		$playerInitialOrder = [];&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$playerInitialOrder[$player[&#039;player_table_order&#039;]] = $playerId;&lt;br /&gt;
		}&lt;br /&gt;
		ksort($playerInitialOrder);&lt;br /&gt;
		$playerInitialOrder = array_flip(array_values($playerInitialOrder));&lt;br /&gt;
&lt;br /&gt;
		// Player order based on &#039;playerTeams&#039; option&lt;br /&gt;
		$playerOrder = [0, 1, 2, 3];&lt;br /&gt;
		switch (self::getGameStateValue(&#039;playerTeams&#039;)) {&lt;br /&gt;
			case self::TEAM_1_2:&lt;br /&gt;
				$playerOrder = [0, 2, 1, 3];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_1_4:&lt;br /&gt;
				$playerOrder = [0, 1, 3, 2];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_RANDOM:&lt;br /&gt;
				shuffle($playerOrder);&lt;br /&gt;
				break;&lt;br /&gt;
			default:&lt;br /&gt;
			case self::TEAM_1_3:&lt;br /&gt;
				// Default order&lt;br /&gt;
				break;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                // Create players&lt;br /&gt;
		// Note: if you added some extra field on &amp;quot;player&amp;quot; table in the database (dbmodel.sql), you can initialize it there.&lt;br /&gt;
		$sql =&lt;br /&gt;
			&#039;INSERT INTO player (player_id, player_color, player_canal, player_name, player_avatar, player_no) VALUES &#039;;&lt;br /&gt;
		$values = [];&lt;br /&gt;
&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$color = array_shift($default_colors);&lt;br /&gt;
			$values[] =&lt;br /&gt;
				&amp;quot;(&#039;&amp;quot; .&lt;br /&gt;
				$playerId .&lt;br /&gt;
				&amp;quot;&#039;,&#039;$color&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$player[&#039;player_canal&#039;] .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_name&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_avatar&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$playerOrder[$playerInitialOrder[$playerId]] .&lt;br /&gt;
				&amp;quot;&#039;)&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
		$sql .= implode(&#039;,&#039;, $values);&lt;br /&gt;
		self::DbQuery($sql);&lt;br /&gt;
		self::reattributeColorsBasedOnPreferences(&lt;br /&gt;
			$players,&lt;br /&gt;
			$gameinfos[&#039;player_colors&#039;]&lt;br /&gt;
		);&lt;br /&gt;
		self::reloadPlayersBasicInfos();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7005</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7005"/>
		<updated>2021-01-23T17:14:15Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&amp;lt;/br/&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; This value is &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                // Retrieve inital player order ([0=&amp;gt;playerId1, 1=&amp;gt;playerId2, ...])&lt;br /&gt;
		$playerInitialOrder = [];&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$playerInitialOrder[$player[&#039;player_table_order&#039;]] = $playerId;&lt;br /&gt;
		}&lt;br /&gt;
		ksort($playerInitialOrder);&lt;br /&gt;
		$playerInitialOrder = array_flip(array_values($playerInitialOrder));&lt;br /&gt;
&lt;br /&gt;
		// Player order based on &#039;playerTeams&#039; option&lt;br /&gt;
		$playerOrder = [0, 1, 2, 3];&lt;br /&gt;
		switch (self::getGameStateValue(&#039;playerTeams&#039;)) {&lt;br /&gt;
			case self::TEAM_1_2:&lt;br /&gt;
				$playerOrder = [0, 2, 1, 3];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_1_4:&lt;br /&gt;
				$playerOrder = [0, 1, 3, 2];&lt;br /&gt;
				break;&lt;br /&gt;
			case self::TEAM_RANDOM:&lt;br /&gt;
				shuffle($playerOrder);&lt;br /&gt;
				break;&lt;br /&gt;
			default:&lt;br /&gt;
			case self::TEAM_1_3:&lt;br /&gt;
				// Default order&lt;br /&gt;
				break;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                // Create players&lt;br /&gt;
		// Note: if you added some extra field on &amp;quot;player&amp;quot; table in the database (dbmodel.sql), you can initialize it there.&lt;br /&gt;
		$sql =&lt;br /&gt;
			&#039;INSERT INTO player (player_id, player_color, player_canal, player_name, player_avatar, player_no) VALUES &#039;;&lt;br /&gt;
		$values = [];&lt;br /&gt;
&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$color = array_shift($default_colors);&lt;br /&gt;
			$values[] =&lt;br /&gt;
				&amp;quot;(&#039;&amp;quot; .&lt;br /&gt;
				$playerId .&lt;br /&gt;
				&amp;quot;&#039;,&#039;$color&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$player[&#039;player_canal&#039;] .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_name&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_avatar&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$playerOrder[$playerInitialOrder[$playerId]] .&lt;br /&gt;
				&amp;quot;&#039;)&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
		$sql .= implode(&#039;,&#039;, $values);&lt;br /&gt;
		self::DbQuery($sql);&lt;br /&gt;
		self::reattributeColorsBasedOnPreferences(&lt;br /&gt;
			$players,&lt;br /&gt;
			$gameinfos[&#039;player_colors&#039;]&lt;br /&gt;
		);&lt;br /&gt;
		self::reloadPlayersBasicInfos();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7004</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7004"/>
		<updated>2021-01-23T17:11:38Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&amp;lt;/br/&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; This value is &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7003</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7003"/>
		<updated>2021-01-23T17:11:23Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&amp;lt;/br/&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; This value is &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7002</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7002"/>
		<updated>2021-01-23T17:11:08Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&amp;lt;/br/&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; This value is &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7001</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=7001"/>
		<updated>2021-01-23T17:10:48Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&lt;br /&gt;
&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; This value is &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=6990</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=6990"/>
		<updated>2021-01-23T00:05:47Z</updated>

		<summary type="html">&lt;p&gt;AmadanNaBriona: /* Default tables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you to build the tables you need with the PhpMyAdmin tool (see BGA user guide), and then to export them and to copy/paste the content inside this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you must not use for a column the same name as for the table, as the framework replay function relies on regexp substitution to save/restore a previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you dealing with games with 50-500 pieces!&lt;br /&gt;
** If you 5 tables for card game with 30 cards - it is overkill&lt;br /&gt;
* Database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: you have cards that have power, color, special abilities. In database you only need to store card type, all the other properties should not be there. Only exception - if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of game data, i.e. location, type, position, row, etc&lt;br /&gt;
** Example: do not create columns like Counry1, Country2, Country3, ...&lt;br /&gt;
* Do not store translatable string in database, use integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** I.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create separate module in php to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method handling database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE &amp;quot; . $this-&amp;gt;table;&lt;br /&gt;
        $sql .= &amp;quot; SET token_state=&#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE token_key=&#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
Important: by default, BGA creates 4 tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;must not modify&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039; or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. This is very practical to add simple values associated with players.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this date with getActivePlayerName() or loadPlayersBasicInfos() methods)&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of the player (displayed in the player panel). You must update this field to update player&#039;s scores.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; This value is currently &amp;lt;u&amp;gt;not guaranteed&amp;lt;/u&amp;gt; to be actually equal to the rank of the player in the table. For example, in a 4-player game, if the table was full but the 3rd player leaves before the game starts, the 4th player becomes 3rd on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to 4! If another player then joins, their player_table_no will then be 5...&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read that values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was 1st on the table, then &amp;lt;player A&amp;gt; then &amp;lt;player C&amp;gt; then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
you can create tables, using engine InnoDB&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `hands` &lt;br /&gt;
(&lt;br /&gt;
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, &lt;br /&gt;
`player_id` TINYINT(1) NOT NULL,&lt;br /&gt;
`1` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`2` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`4` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`5` BOOL NOT NULL DEFAULT 1,		&lt;br /&gt;
`6` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
`7` BOOL NOT NULL DEFAULT 1,	&lt;br /&gt;
PRIMARY KEY (`id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you put comments, you cannot do it in the same line as code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`3` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out `3` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== Link ==&lt;br /&gt;
You can add your Db inits in function SetupNewGame() from file &#039;gamename.game.php&#039;&lt;br /&gt;
  &lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game in production, you should consult the [[Post-release phase#Updating the database schema|related section]]&lt;/div&gt;</summary>
		<author><name>AmadanNaBriona</name></author>
	</entry>
</feed>