<?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=Nicotacotac</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=Nicotacotac"/>
	<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/Special:Contributions/Nicotacotac"/>
	<updated>2026-09-16T04:02:51Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.0</generator>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=22187</id>
		<title>Options and preferences: gameoptions.json, gamepreferences.json</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=22187"/>
		<updated>2024-08-14T20:45:38Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Listening for preference changes and updating preference from code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;gameoptions.json&amp;lt;/code&amp;gt;, you can define your game options (i.e. game variants).&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;code&amp;gt;gamepreferences.json&amp;lt;/code&amp;gt;, you can define user preferences.&lt;br /&gt;
   &lt;br /&gt;
Note: If your game has no variants or preferences, you don&#039;t have to modify these files.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; after edits to these files, you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; on Studio for your changes &#039;&#039;&#039;to take effect&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Make sure you understand difference between options and preferences:&lt;br /&gt;
* Game options - something usually in the rule book defined as &amp;quot;variant&amp;quot; (except for player count, which is automatically handled). For example, whether to include &#039;&#039;The River&#039;&#039; in Carcassonne.&lt;br /&gt;
* User preferences - personal choices of each player only visible to that specific player - i.e. layout, whether or not to prompt for action, whether or not auto-opt in in some actions, etc.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options are selected by the table creator and usually correspond to game variants, for example if the game includes expansions or certain special rules.&lt;br /&gt;
&lt;br /&gt;
These variants are defined in &amp;lt;code&amp;gt;gameoptions.json&amp;lt;/code&amp;gt; as an object:  &lt;br /&gt;
&lt;br /&gt;
  {&lt;br /&gt;
     &amp;quot;100&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;Game Setup&amp;quot;, ... },&lt;br /&gt;
     &amp;quot;101&amp;quot;: { &amp;quot;name&amp;quot;: &amp;quot;Draft&amp;quot;, ... }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Each key corresponds to the option id, and each value is that option definition, which is described below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; the file must be valid [https://www.json.org/ JSON]. That is, trailing commas and comments are not allowed. However you can use still standard json hack to add a field like &amp;quot;$comment&amp;quot;: &amp;quot;Here we go&amp;quot;&lt;br /&gt;
&#039;&#039;&#039;Note 2:&#039;&#039;&#039; the key in json file must be a string type, even its correspond to a number in other places (such as php, or other references in same json).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
All options defined in this file should have a corresponding &amp;quot;game state label&amp;quot; with the same ID (see &amp;quot;initGameStateLabels&amp;quot; in yourgame.game.php)&lt;br /&gt;
&lt;br /&gt;
             self::initGameStateLabels ([&lt;br /&gt;
                        ...&lt;br /&gt;
                        &amp;quot;my_game_variant&amp;quot; =&amp;gt; 100,&lt;br /&gt;
              ]);&lt;br /&gt;
&lt;br /&gt;
Numbers have to be exactly from 100 to 199 (there can be gaps).&lt;br /&gt;
&lt;br /&gt;
That is how you access them during runtime (by name):&lt;br /&gt;
&lt;br /&gt;
    public function isSecondVariant() {&lt;br /&gt;
        return $this-&amp;gt;getGameStateValue(&#039;my_game_variant&#039;) == 2;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Or this (by numberic id)&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;table_globals[100]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To access json data (the metadata only) can use&lt;br /&gt;
   $game_options = $this-&amp;gt;getTableOptions();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Details of game options format ===&lt;br /&gt;
&lt;br /&gt;
The following are the values of the option definition object:&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. The name of the option visible for table creator. This is automatically marked for translation.&lt;br /&gt;
* &#039;&#039;&#039;values&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. The map representing possible values of this option. The key of the map is possible value of this option, its a number but has to be string in json. The value is an object descring it.&lt;br /&gt;
** &#039;&#039;&#039;name&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. String representation of the numeric value visible to table creator. This is automatically marked for translation.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; - String description of this value to use when the name of the option is not self-explanatory. Displayed at the table under the option when this value is selected. Note: if there is no description, this should be omitted.&lt;br /&gt;
** &#039;&#039;&#039;tmdisplay&#039;&#039;&#039; - String representation of the option visible in the table description in the lobby. Usually if a variant values are On and Off (default), the tmdisplay would be same as description name when On, and nothing (empty string) when Off. (&#039;&#039;&#039;Warning&#039;&#039;&#039;: due to some caching, a change in tmdisplay may not be effective immediately in the studio, even after forcing a reload of options.) &#039;&#039;&#039;Pro Tip:&#039;&#039;&#039; You can use this as a pre-game communication by adding fake options that just do nothing in the game but make it easier to find other player wanted the same game configuration (see the crew deep sea for example).&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for beginners&lt;br /&gt;
** &#039;&#039;&#039;firstgameonly&#039;&#039;&#039; - Set to true if this option is recommended only for the first game (discovery option)&lt;br /&gt;
** &#039;&#039;&#039;beta&#039;&#039;&#039; - Set to true to indicate that this option is in &amp;quot;beta&amp;quot; development stage (there will be a warning for players starting the game)&lt;br /&gt;
** &#039;&#039;&#039;alpha&#039;&#039;&#039; - Set to true to indicate that this option is in &amp;quot;alpha&amp;quot; development stage (there will be a warning, and starting the game will be allowed only in training mode except for the developer)&lt;br /&gt;
** &#039;&#039;&#039;premium&#039;&#039;&#039; - Option can be only used by premium members&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; - indicates the default value to use for this option (optional, if not present the first value listed is the default)&lt;br /&gt;
* &#039;&#039;&#039;displaycondition&#039;&#039;&#039; - (array of conditions) - checks the conditions before displaying the option for selection. All (or any) conditions must be true for the option to be displayed. All or any depends on value of displayconditionoperand&lt;br /&gt;
Supported display condition types:&lt;br /&gt;
** &#039;&#039;minplayers&#039;&#039; condition ensures at least this many players (Note: if your game works with a disjoint interval of player counts, you can supply an array of valid counts instead of a single value)&lt;br /&gt;
** &#039;&#039;maxplayers&#039;&#039; condition ensures at most this many players&lt;br /&gt;
** &#039;&#039;otheroption&#039;&#039; condition ensures another option is set to given values. &lt;br /&gt;
** &#039;&#039;otheroptionisnot&#039;&#039; condition ensure another option is NOT set to this given values&lt;br /&gt;
* &#039;&#039;&#039;displayconditionoperand&#039;&#039;&#039; - can be &#039;and&#039; (this is the default) or &#039;or&#039;. Allows to change the behaviour to display the option if one of the conditions is true instead of all of them.&lt;br /&gt;
* &#039;&#039;&#039;startcondition&#039;&#039;&#039; - (map from value to conditions array) - checks the conditions (on options VALUES) before starting the game. All conditions must be true for the game to start, otherwise players will get a red error message when attempting to begin the game. &lt;br /&gt;
Supported start condition types:&lt;br /&gt;
** &#039;&#039;minplayers&#039;&#039; condition ensures at least this many players (an array of values is not supported here)&lt;br /&gt;
** &#039;&#039;maxplayers&#039;&#039; condition ensures at most this many players&lt;br /&gt;
** &#039;&#039;otheroption&#039;&#039; conditions ensure another option is set to this given values. That works the same as in &#039;&#039;&#039;displaycondition&#039;&#039;&#039;.&lt;br /&gt;
** &#039;&#039;otheroptionisnot&#039;&#039; conditions ensure another option is NOT set to this given value.  That works the same as in &#039;&#039;&#039;displaycondition&#039;&#039;&#039;.&lt;br /&gt;
*: For all these condition types, a &#039;&#039;gamestartonly&#039;&#039; boolean option can be added, if you have options that are exclusive. Setting this boolean to &#039;&#039;true&#039;&#039; will defer the evaluation of the startcondition to the game creation, instead of preventing the player to select options that are exclusive at all. See [[#gamestartonly|below]] for an example. &amp;lt;span style=&amp;quot;background: #FFCDD2; color: #B71C1C; padding: 2px;&amp;quot;&amp;gt;But this should never be used -- see the warning below&amp;lt;/span&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;notdisplayedmessage&#039;&#039;&#039; - if option is not suppose to be visible because of displaycondition but this is set, the text will be visible instead of combo drop down&lt;br /&gt;
* &#039;&#039;&#039;level&#039;&#039;&#039; - what kind of option it is: &#039;&#039;base&#039;&#039;, &#039;&#039;major&#039;&#039;, or &#039;&#039;additional&#039;&#039;. See [[#level|below]] for more informations.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Common (reserved) options for all tables (reserved range 200-299):&lt;br /&gt;
*201 (const GAMESTATE_RATING_MODE) - ELO OFF (aka Training mode), &lt;br /&gt;
**0 = Normal&lt;br /&gt;
**1 = Training&lt;br /&gt;
**2 = Arena&lt;br /&gt;
*200 (const GAMESTATE_CLOCK_MODE) - game speed profile&lt;br /&gt;
**[0, 1, 2] - realtime (technically &amp;lt;10 realtime but you cannot define range in php)&lt;br /&gt;
**values &amp;gt;=10 - turn based (currently 10..21)&lt;br /&gt;
**Note there are two similar values, 9 = realtime &amp;quot;no time limit with friends only&amp;quot; vs. 20 = turn-based &amp;quot;no time limit with friends only&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;100&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Game Variant&amp;quot;,&lt;br /&gt;
    &amp;quot;values&amp;quot;: {&lt;br /&gt;
      &amp;quot;1&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Learning&amp;quot;,&lt;br /&gt;
        &amp;quot;firstgameonly&amp;quot;: true,&lt;br /&gt;
        &amp;quot;tmdisplay&amp;quot;: &amp;quot;Learning&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;2&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Base&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;3&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Extended&amp;quot;,&lt;br /&gt;
        &amp;quot;nobeginner&amp;quot;: true,&lt;br /&gt;
        &amp;quot;beta&amp;quot;: true,&lt;br /&gt;
        &amp;quot;tmdisplay&amp;quot;: &amp;quot;Extended&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;default&amp;quot;: 2&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;101&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Draft variant&amp;quot;,&lt;br /&gt;
    &amp;quot;values&amp;quot;: {&lt;br /&gt;
      &amp;quot;1&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;No draft&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;2&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Draft&amp;quot;,&lt;br /&gt;
        &amp;quot;tmdisplay&amp;quot;: &amp;quot;Draft&amp;quot;,&lt;br /&gt;
        &amp;quot;premium&amp;quot;: true,&lt;br /&gt;
        &amp;quot;nobeginner&amp;quot;: true&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;displaycondition&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;otheroption&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;value&amp;quot;: [ 2, 3 ]&lt;br /&gt;
      },&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;otheroption&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;: 201,&lt;br /&gt;
        &amp;quot;value&amp;quot;: 1&lt;br /&gt;
      }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;startcondition&amp;quot;: {&lt;br /&gt;
      &amp;quot;1&amp;quot;: [],&lt;br /&gt;
      &amp;quot;2&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;type&amp;quot;: &amp;quot;maxplayers&amp;quot;,&lt;br /&gt;
          &amp;quot;value&amp;quot;: 3,&lt;br /&gt;
          &amp;quot;message&amp;quot;: &amp;quot;Draft option is available for 3 players maximum.&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
      ]&lt;br /&gt;
    }&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;102&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Takeovers&amp;quot;,&lt;br /&gt;
    &amp;quot;values&amp;quot;: {&lt;br /&gt;
      &amp;quot;2&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;No takeover&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;1&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Allow takeovers&amp;quot;,&lt;br /&gt;
        &amp;quot;tmdisplay&amp;quot;: &amp;quot;Takeovers&amp;quot;,&lt;br /&gt;
        &amp;quot;premium&amp;quot;: true,&lt;br /&gt;
        &amp;quot;nobeginner&amp;quot;: true&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;displaycondition&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;otheroption&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;value&amp;quot;: [ 3 ]&lt;br /&gt;
      }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;startcondition&amp;quot;: {&lt;br /&gt;
      &amp;quot;2&amp;quot;: [],&lt;br /&gt;
      &amp;quot;1&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;type&amp;quot;: &amp;quot;maxplayers&amp;quot;,&lt;br /&gt;
          &amp;quot;value&amp;quot;: 2,&lt;br /&gt;
          &amp;quot;message&amp;quot;: &amp;quot;Rebel vs Imperium Takeover Scenario is available for 2 players only.&amp;quot;&lt;br /&gt;
        }&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;
&#039;&#039;&#039;Example of option that condition on ELO off:&#039;&#039;&#039;&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;100&amp;quot;: {&lt;br /&gt;
     &amp;quot;name&amp;quot;: &amp;quot;Learning Game (No Research)&amp;quot;,&lt;br /&gt;
     &amp;quot;values&amp;quot;: {&lt;br /&gt;
       &amp;quot;1&amp;quot;: {&lt;br /&gt;
         &amp;quot;name&amp;quot;: &amp;quot;Off&amp;quot;,&lt;br /&gt;
         &amp;quot;tmdisplay&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
       },&lt;br /&gt;
       &amp;quot;2&amp;quot;: {&lt;br /&gt;
         &amp;quot;name&amp;quot;: &amp;quot;On&amp;quot;,&lt;br /&gt;
         &amp;quot;tmdisplay&amp;quot;: &amp;quot;Learning Game&amp;quot;&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;startcondition&amp;quot;: {&lt;br /&gt;
       &amp;quot;2&amp;quot;: {&lt;br /&gt;
         &amp;quot;type&amp;quot;: &amp;quot;otheroption&amp;quot;,&lt;br /&gt;
         &amp;quot;id&amp;quot;: 201,&lt;br /&gt;
         &amp;quot;value&amp;quot;: 1,&lt;br /&gt;
         &amp;quot;message&amp;quot;: &amp;quot;Learning variant available only in friendly mode&amp;quot;&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&#039;&#039;&#039;Example of condition that is only available for REALTIME game mode:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;displaycondition&amp;quot;: [&lt;br /&gt;
    { &amp;quot;type&amp;quot;: &amp;quot;otheroption&amp;quot;, &amp;quot;id&amp;quot;: 200, &amp;quot;value&amp;quot;: [0, 1, 2] }&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example of using condition on your own option:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;102&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Scenarios&amp;quot;,&lt;br /&gt;
    &amp;quot;values&amp;quot;: {&lt;br /&gt;
      &amp;quot;1&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Off&amp;quot;,&lt;br /&gt;
        &amp;quot;nobeginner&amp;quot;: false&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;2&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;On&amp;quot;,&lt;br /&gt;
        &amp;quot;tmdisplay&amp;quot;: &amp;quot;Scenarios&amp;quot;,&lt;br /&gt;
        &amp;quot;nobeginner&amp;quot;: true&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;displaycondition&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;otheroptionisnot&amp;quot;,&lt;br /&gt;
        &amp;quot;id&amp;quot;: 100,&lt;br /&gt;
        &amp;quot;value&amp;quot;: 1&lt;br /&gt;
      }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;notdisplayedmessage&amp;quot;: &amp;quot;Scenarios variant is not available if Learning variant is chosen&amp;quot;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example of handling solo vs multiplayer options:&#039;&#039;&#039;&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;100&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Board setup&amp;quot;,&lt;br /&gt;
    &amp;quot;values&amp;quot;: {&lt;br /&gt;
      &amp;quot;1&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Mirror setup&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;The starting player shuffles their 6 Farm Cards and randomly lays a card face up in each of the round spaces of their Fruit Island Board. The other players then lay their cards in exactly the same way, copying the order of the starting player.&amp;quot;,&lt;br /&gt;
        &amp;quot;tmdisplay&amp;quot;: &amp;quot;Mirror setup&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;2&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Random setup&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Instead of every player copying the same card configuration as the starting player, every player shuffles their Farm Cards and lays down the cards randomly on their Fruit Island Board.&amp;quot;,&lt;br /&gt;
        &amp;quot;tmdisplay&amp;quot;: &amp;quot;Random setup&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;displaycondition&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;minplayers&amp;quot;,&lt;br /&gt;
        &amp;quot;value&amp;quot;: [&lt;br /&gt;
          2,&lt;br /&gt;
          3,&lt;br /&gt;
          4&lt;br /&gt;
        ]&lt;br /&gt;
      }&lt;br /&gt;
    ]&lt;br /&gt;
  },&lt;br /&gt;
  &amp;quot;102&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Solo difficulty&amp;quot;,&lt;br /&gt;
    &amp;quot;values&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Banana-apprentice&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Do not remove any seed before starting the game.&amp;quot;,&lt;br /&gt;
        &amp;quot;tmdisplay&amp;quot;: &amp;quot;Banana-apprentice&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Pear to the Throne&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot;: &amp;quot;Remove 1 seed before starting the game.&amp;quot;,&lt;br /&gt;
        &amp;quot;tmdisplay&amp;quot;: &amp;quot;Pear to the Throne&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    ],&lt;br /&gt;
    &amp;quot;displaycondition&amp;quot;: [&lt;br /&gt;
      {&lt;br /&gt;
        &amp;quot;type&amp;quot;: &amp;quot;maxplayers&amp;quot;,&lt;br /&gt;
        &amp;quot;value&amp;quot;: 1&lt;br /&gt;
      }&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;
==== displaycondition vs startcondition ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;displaycondition&amp;lt;/code&amp;gt; should be used when an option should not be present in the list under certain conditions.&lt;br /&gt;
&lt;br /&gt;
For example, displaying the option which is consistent with the player count.&lt;br /&gt;
&lt;br /&gt;
* 2 player maps: A B C D &lt;br /&gt;
* 3 player maps: E F G H&lt;br /&gt;
* 4 player maps: I J K L&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;startcondition&amp;lt;/code&amp;gt; should be used when a specific combination of option values is invalid, but the option itself still makes sense to show.&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
&lt;br /&gt;
* Player 1 faction: A, B, C, D, E, F, G&lt;br /&gt;
* Player 2 faction: A, B, C, D, E, F, G&lt;br /&gt;
* startcondition: both players can&#039;t be the same faction&lt;br /&gt;
&lt;br /&gt;
These options should both be displayed at all times, but there are some invalid configurations.&lt;br /&gt;
&lt;br /&gt;
The other difference is displaycondition affect option itself, while startcondition affect specific values selected&lt;br /&gt;
&lt;br /&gt;
==== gamestartonly ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 1em; background: #FFCDD2; color: #B71C1C&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;b&amp;gt;WARNING:&amp;lt;/b&amp;gt; [https://studio.boardgamearena.com/bug?id=104 See studio bug #104]. You should &amp;lt;b&amp;gt;NEVER&amp;lt;/b&amp;gt; use &amp;lt;code&amp;gt;gamestartonly&amp;lt;/code&amp;gt;! Otherwise, you allow players to (unknowingly!) create a turn-based table with impossible options that can never start. Players receive no indication that the option combination they selected is invalid until the last player joins the table (hours or days later) and the game attempts to auto-start. The table won&#039;t start because of the &amp;lt;code&amp;gt;startcondition&amp;lt;/code&amp;gt;, and the table options cannot be changed because it&#039;s a turn-based table, so the table must be abandoned. This is a horrible user experience. Please don&#039;t subject players to this.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On the table configuration page, it won&#039;t let you select a combination which is invalid according to &amp;lt;code&amp;gt;startcondition&amp;lt;/code&amp;gt;. Doing so will show a red warning, and will revert the option to the previous value. This means you could end up in a situation where you can&#039;t easily change between certain options (requiring you to set or unset options in a specific order).&lt;br /&gt;
&lt;br /&gt;
The consequence of the &amp;lt;code&amp;gt;gamestartonly&amp;lt;/code&amp;gt; flag is that the player _can_ select an invalid combination. However, when clicking &amp;quot;Start&amp;quot;, an invalid combination will produce an error.&lt;br /&gt;
&lt;br /&gt;
Probably the easiest way to see what the difference is is with an example.&lt;br /&gt;
&lt;br /&gt;
With a _Clans of Caledonia_ table:&lt;br /&gt;
* set to training mode&lt;br /&gt;
* set player count to 1&lt;br /&gt;
* try setting &amp;quot;Clan Auction&amp;quot; to one of the &amp;quot;On&amp;quot; options&lt;br /&gt;
* try starting the game, there&#039;s an error! Ie. &amp;lt;code&amp;gt;&amp;quot;gamestartonly&amp;quot; =&amp;gt; true&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, with a _Sushi Go Party!_ table:&lt;br /&gt;
* set number of players to 7&lt;br /&gt;
* try setting &amp;quot;Sushi Go! / Sushi Go Party!&amp;quot; to &amp;quot;Sushi Go!&amp;quot;&lt;br /&gt;
* you can&#039;t set the option! Ie. &amp;lt;code&amp;gt;&amp;quot;gamestartonly&amp;quot; =&amp;gt; false&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;100&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Option name&amp;quot;,&lt;br /&gt;
    &amp;quot;values&amp;quot;: [],&lt;br /&gt;
    &amp;quot;startcondition&amp;quot;: {&lt;br /&gt;
      &amp;quot;1&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;type&amp;quot;: &amp;quot;maxplayers&amp;quot;,&lt;br /&gt;
          &amp;quot;value&amp;quot;: 2,&lt;br /&gt;
          &amp;quot;message&amp;quot;: &amp;quot;This option is available for 2 players only.&amp;quot;,&lt;br /&gt;
          &amp;quot;gamestartonly&amp;quot;: true&lt;br /&gt;
        }&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;
==== level ====&lt;br /&gt;
Note: at this moment this only have impact in fancy lobby mode, presentation of level or checkboxes are not avaiable via normal table creation ui (such as in studio, or when you click Play button in control panel)&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;100&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Option name&amp;quot;,&lt;br /&gt;
        &amp;quot;values&amp;quot;: [...],&lt;br /&gt;
        &amp;quot;level&amp;quot;: &amp;quot;major&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;base&#039;&#039;&#039; is the default value (you don&#039;t need to specify it).&lt;br /&gt;
* &#039;&#039;&#039;major&#039;&#039;&#039; denotes a major option, which will always be displayed on top, and with a specific UI.&lt;br /&gt;
* &#039;&#039;&#039;additional&#039;&#039;&#039; means this option will not be displayed by default, to unclutter the option panel.&lt;br /&gt;
&lt;br /&gt;
About major options:&lt;br /&gt;
* a game can only have &#039;&#039;&#039;1 major option&#039;&#039;&#039;, and of course, it must be a important game changer.&lt;br /&gt;
* the pictures will default to the standard Game Box, and can be set independently for each value, from the [[Game metadata manager]] (in the &amp;quot;Major Variants&amp;quot; section). Note: this cannot be tested from Studio as there is not studio-only Game metadata manager, to see Major Variants option - the game has to be deployed at least as alpha.&lt;br /&gt;
* the major option can have more than 2 values (there will then be an arrow to slide to the other values, carousel-like)&lt;br /&gt;
* the naming of major variant values should be concise and the values should have descriptive text (not just &amp;quot;enabled&amp;quot; or &amp;quot;disabled&amp;quot;)&lt;br /&gt;
** 👍 Option name &amp;quot;Expansion&amp;quot;, option values &amp;quot;Base game&amp;quot;, &amp;quot;Bigger is Better&amp;quot; =&amp;gt; Displayed as &#039;&#039;&amp;quot;Expansion: Base game&amp;quot;&#039;&#039; or &#039;&#039;&amp;quot;Expansion: Bigger is Better&amp;quot;&#039;&#039;&lt;br /&gt;
** 👎 Option name &amp;quot;Bigger is Better&amp;quot;, option values &amp;quot;Enabled&amp;quot;, &amp;quot;Disabled =&amp;gt; Displayed as &#039;&#039;&amp;quot;Bigger is Better: Enabled&amp;quot;&#039;&#039; or &#039;&#039;&amp;quot;Bigger is Better: Disabled&amp;quot;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
About additional options:&lt;br /&gt;
* please set each option that concerns small details in this category: advanced players will find this option anyway, and it will simplify the interface of the page of your game.&lt;br /&gt;
&lt;br /&gt;
[[File:Option-levels.png|800px|Option levels]]&lt;br /&gt;
&lt;br /&gt;
==== option presentation ====&lt;br /&gt;
&lt;br /&gt;
An option WILL be displayed as a &#039;&#039;&#039;Checkbox&#039;&#039;&#039; instead of a selector if certain conditions are met:&lt;br /&gt;
&lt;br /&gt;
* option has only &#039;&#039;&#039;2 values&#039;&#039;&#039;&lt;br /&gt;
* values are either (case insensitive):&lt;br /&gt;
** &#039;&#039;yes&#039;&#039; and &#039;&#039;no&#039;&#039;&lt;br /&gt;
** &#039;&#039;on&#039;&#039; and &#039;&#039;off&#039;&#039;&lt;br /&gt;
** &#039;&#039;enabled&#039;&#039; and &#039;&#039;disabled&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;default&amp;quot; value still has to be specified, and can be &amp;quot;on&amp;quot; or &amp;quot;off&amp;quot; (it&#039;s actually just a difference in display).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Option-display.png|800px|Example of checkbox display]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== User Preferences ==&lt;br /&gt;
&lt;br /&gt;
User preferences is something cosmetic about the game interface which however can create user wars, so you can satisfy all users&lt;br /&gt;
by giving them individual preferences. You should use this only if it significantly improves the interface for a large proportion of users.&lt;br /&gt;
These preferences appear in the three-line hamburger menu in the top corner of the bga menu (and also at the bottom on the page in the Options tab).  &lt;br /&gt;
&amp;quot;Display game logs&amp;quot; and &amp;quot;Display tooltips&amp;quot; are baked-in by default, but you can extend this list as below. &lt;br /&gt;
&lt;br /&gt;
The preference json slightly resembles options, but these are conceptually different. The numbers comes from diffrent space and do not correspond or conflict with options,&lt;br /&gt;
i.e. preference 100 has nothing to do with option 100. You can use range 100-199 with gaps.&lt;br /&gt;
&lt;br /&gt;
[[File:century_preferences_menu.PNG|400px|The user preferences menu for the game Century]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&#039;&#039;These preferences are a good place to put accessibility options - as Century did for its Colorblind Support.&#039;&#039;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;100&amp;quot;: {&lt;br /&gt;
    &amp;quot;name&amp;quot;: &amp;quot;Colorblind Support&amp;quot;,&lt;br /&gt;
    &amp;quot;needReload&amp;quot;: true,&lt;br /&gt;
    &amp;quot;values&amp;quot;: {&lt;br /&gt;
      &amp;quot;1&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;None&amp;quot;,&lt;br /&gt;
        &amp;quot;cssPref&amp;quot;: &amp;quot;colorblind_off&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;2&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Numbers&amp;quot;,&lt;br /&gt;
        &amp;quot;cssPref&amp;quot;: &amp;quot;colorblind_on&amp;quot;&lt;br /&gt;
      },&lt;br /&gt;
      &amp;quot;3&amp;quot;: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Shapes&amp;quot;,&lt;br /&gt;
        &amp;quot;cssPref&amp;quot;: &amp;quot;colorblind_shapes&amp;quot;&lt;br /&gt;
      }&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;default&amp;quot;: 1&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is two ways to check/apply this. In java Script&lt;br /&gt;
&lt;br /&gt;
  if (this.getGameUserPreference(100) == 2) ...&lt;br /&gt;
&lt;br /&gt;
This checks if preferences 100 has selected value 2.&lt;br /&gt;
&lt;br /&gt;
Second, if cssPref specified it will be applied to the &#039;&#039;&#039;&amp;lt;html&amp;gt;&#039;&#039;&#039; tag. So you can use different css styling for the preference. Note: you also need to set needReload to true for that class change to be effective.&lt;br /&gt;
&lt;br /&gt;
As user you have to select them from the Gear menu when game is started. On studio only dev0 account will have it actually working (bug?).&lt;br /&gt;
&lt;br /&gt;
The following are the parameters of preferences description array:&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. The name of the preference. This string is marked for translation.&lt;br /&gt;
* &#039;&#039;&#039;needReload&#039;&#039;&#039; - If set to true, the game interface will auto-reload after a change of the preference.&lt;br /&gt;
* &#039;&#039;&#039;values&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. The map of values with additional parameters per value.&lt;br /&gt;
** &#039;&#039;&#039;name&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. String representation of the numeric value.  This string is marked for translation.&lt;br /&gt;
** &#039;&#039;&#039;cssPref&#039;&#039;&#039; - CSS class to add to the &#039;&#039;&#039;&amp;lt;html&amp;gt;&#039;&#039;&#039; tag. Currently it is added or removed only after a reload (see needReload).&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; - Indicates the default value to use for this preference (optional, if not present the first value listed is the default).&lt;br /&gt;
&lt;br /&gt;
=== Listening for preference changes and updating preference from code ===&lt;br /&gt;
The BGA framework offers read/write and callback for user preference changes. See [[Game interface logic: yourgamename.js#User preferences]]&lt;br /&gt;
&lt;br /&gt;
=== Accessing User Preferences on the server ===&lt;br /&gt;
PHP has a variable called $this-&amp;gt;player_preferences.&lt;br /&gt;
This contains a table of player preferences, ONLY accessible in setupNewGame().&lt;br /&gt;
You can use this to populate a table that you manage yourself.&lt;br /&gt;
You have to update the table when a player changes preference (and you have to hook up a listener and initiate an AJAX call out-of-turn).&lt;br /&gt;
Check the code of Agricola for details but this should work:&lt;br /&gt;
&lt;br /&gt;
; In dbmodel.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `user_preferences` (&lt;br /&gt;
  `player_id` int(10) NOT NULL,&lt;br /&gt;
  `pref_id` int(10) NOT NULL,&lt;br /&gt;
  `pref_value` int(10) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`player_id`, `pref_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; In ggg.game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
protected function setupNewGame($players, $options = array())&lt;br /&gt;
{&lt;br /&gt;
// TODO: Save $this-&amp;gt;player_preferences: key is player_id, value is array with pref_id as key and pref_value as value&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Warning: &amp;lt;code&amp;gt;$this-&amp;gt;player_preferences[$player_id]&amp;lt;/code&amp;gt; can be null if the player has not set any player preferences.&lt;br /&gt;
&lt;br /&gt;
Note: to access json values you can call:&lt;br /&gt;
   $game_preferences = $this-&amp;gt;getTablePreferences();&lt;br /&gt;
&lt;br /&gt;
Warning: if you use bga undo system make sure this table is not restored from undo state, as this likely independed from it&lt;br /&gt;
&lt;br /&gt;
; In ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// use code for initPreferencesObserver from above example&lt;br /&gt;
&lt;br /&gt;
onGameUserPreferenceChanged(prefId, prefValue) {&lt;br /&gt;
    if (prefId === 101 /*TODO: You probably want to send only some preferences*/) {&lt;br /&gt;
        // TODO: Code your own action in ggg.action.php and send it prefId and prefValue&lt;br /&gt;
        //       The on the server side you can save it all in the user_preferences&lt;br /&gt;
        //       table you created above.&lt;br /&gt;
    }&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Translations ==&lt;br /&gt;
Note that any name or description values in these JSON files are automatically added to the translation system.&lt;br /&gt;
&lt;br /&gt;
== Migration ==&lt;br /&gt;
Previously, options and preferences were specified in a single &amp;lt;code&amp;gt;gameoptions.inc.php&amp;lt;/code&amp;gt; file.&lt;br /&gt;
&lt;br /&gt;
BGA has switched to a JSON format to make parsing easier on the server-side, and to avoid a reliance on PHP for static config.&lt;br /&gt;
&lt;br /&gt;
The PHP format will continue to work for &#039;&#039;existing&#039;&#039; games, and although preferred, there is no need to migrate unless you want to. However, newly created games must use the new format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: once a game has been committed with a &amp;lt;code&amp;gt;gameoptions.json&amp;lt;/code&amp;gt; file, however, it is not possible to go back without admin intervention.&lt;br /&gt;
&lt;br /&gt;
If you want to migrate:&lt;br /&gt;
&lt;br /&gt;
Simple method:&lt;br /&gt;
* Go to studio and press Reload game options configuration&lt;br /&gt;
* It will dump json on the log window - you can take this, format it and save into 2 files (if you have both). For gamepreference.json remove option &amp;quot;200&amp;quot; - this is default common option, it should not be in your file.&lt;br /&gt;
&lt;br /&gt;
Manual method:&lt;br /&gt;
* Remove all calls to &amp;lt;code&amp;gt;totranslate()&amp;lt;/code&amp;gt;, and replace with the plain string&lt;br /&gt;
* Remove any references to BGA&#039;s PHP constants, such as GAMESTATE_RATING_MODE, and replace with the plain value (in this case, 201)&lt;br /&gt;
* You can populate &amp;lt;code&amp;gt;gameinfos.json&amp;lt;/code&amp;gt; with the result of &amp;lt;code&amp;gt;json_encode($game_options, JSON_PRETTY_PRINT)&amp;lt;/code&amp;gt;&lt;br /&gt;
* You can populate &amp;lt;code&amp;gt;gamepreferences.json&amp;lt;/code&amp;gt; with the result of &amp;lt;code&amp;gt;json_encode($game_preferences, JSON_PRETTY_PRINT)&amp;lt;/code&amp;gt;&lt;br /&gt;
* If you include gameoptions.inc.php directly, to read the values, then replace those calls with &amp;lt;code&amp;gt;$this-&amp;gt;getTableOptions()&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;$this-&amp;gt;getTablePreferences()&amp;lt;/code&amp;gt; as appropriate which return arrays parsed from the JSON files&lt;br /&gt;
This message was posted to the developer Discord channel:&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Game options change (Optional!)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;gameoptions.inc.php&amp;lt;/code&amp;gt; is now considered legacy, and &amp;lt;code&amp;gt;gameoptions.json&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;gamepreferences.json&amp;lt;/code&amp;gt; are recommended for new projects:&lt;br /&gt;
&lt;br /&gt;
* The wiki and the template project have been updated: [[/en.doc.boardgamearena.com/Options and preferences: gameoptions.json, gamepreferences.json|https://en.doc.boardgamearena.com/Options_and_preferences:_gameoptions.json,_gamepreferences.json]]&lt;br /&gt;
* Any questions/problems can come to me, or can be asked here.&lt;br /&gt;
* The format of the json files matches the format of the old php files&lt;br /&gt;
&lt;br /&gt;
We realise there are some drawbacks (sorry!):&lt;br /&gt;
&lt;br /&gt;
* No comments in the JSON file, meaning you have to check the wiki for examples&lt;br /&gt;
* No PHP constants in the JSON file, meaning magic numbers&lt;br /&gt;
&lt;br /&gt;
However, we hope it&#039;s good for BGA because:&lt;br /&gt;
&lt;br /&gt;
* Simpler to parse (for robots and humans)&lt;br /&gt;
* Easier to check for errors (we could perhaps use an XSLT one day)&lt;br /&gt;
* No need to run game-specific PHP code on the metasite&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE&#039;&#039;&#039;: Switching is totally optional, and the legacy files will still work for existing projects, and for those who know about them. &amp;lt;/blockquote&amp;gt;&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Practical_debugging&amp;diff=17526</id>
		<title>Practical debugging</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Practical_debugging&amp;diff=17526"/>
		<updated>2023-07-19T08:32:56Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Fully automated version */ added a head with access token to loadbug notif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page gives you practical tips to debug your game during development. Don&#039;t hesitate to share your difficulties with us so that we can improve this section.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
&lt;br /&gt;
To work on BGA Studio, we recommend that you use [http://www.google.com/chrome Google Chrome] as it&#039;s currently the fastest browser for the BGA platform, and it&#039;s available for all OSes.&lt;br /&gt;
&lt;br /&gt;
Another reason to use Chrome is that it embeds all the tools you need to work on BGA Studio. You can see them by pressing &amp;quot;F12&amp;quot; or from the menu (&amp;quot;Tools &amp;gt; Development tools&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
A good practice is to use a second browser to develop the game, in order to verify that your game is working fine on this browser too.&lt;br /&gt;
&lt;br /&gt;
To debug with Firefox browser, we advise you to use these 2 extensions:&lt;br /&gt;
* [https://addons.mozilla.org/firefox/addon/firebug/ Firebug]&lt;br /&gt;
* [https://addons.mozilla.org/firefox/addon/web-developer/ Web developer]&lt;br /&gt;
&lt;br /&gt;
To debug with other browsers (IE, Edge, Opera), we advise you to use one of the most recent versions. Latest versions of the browser will likely have better development tools than the previous ones...&lt;br /&gt;
&lt;br /&gt;
== General tip for debugging ==&lt;br /&gt;
&lt;br /&gt;
=== Save &amp;amp; Restore ===&lt;br /&gt;
&lt;br /&gt;
In general for debugging, think of using the &#039;[[Tools_and_tips_of_BGA_Studio#Save_.26_restore_state|save &amp;amp; restore]] state&#039; functionality. It enables you to save the state of your game just before the issue you are investigating, then come back to that point with one click as many times as needed to understand what is going wrong.&lt;br /&gt;
&lt;br /&gt;
You can save up to 3 different states.&lt;br /&gt;
&lt;br /&gt;
=== Refresh ===&lt;br /&gt;
&lt;br /&gt;
If something does not seems to work properly even you &amp;quot;fixed it&amp;quot;, it may be refresh issue. Not all files born equal. Some require a lot more steps to get into the game.&lt;br /&gt;
&lt;br /&gt;
See https://en.doc.boardgamearena.com/Studio_file_reference for information on how to &amp;quot;refresh&amp;quot; each files.&lt;br /&gt;
&lt;br /&gt;
== Debugging my game when it cannot start ==&lt;br /&gt;
&lt;br /&gt;
If your game won&#039;t start because of an error, you are probably in one of these situations:&lt;br /&gt;
* There is a SQL error in your dbmodel.sql file.&lt;br /&gt;
* You have a syntax error in your PHP file.&lt;br /&gt;
* Your PHP &amp;quot;setupNewGame&amp;quot; generates exception&lt;br /&gt;
* You transition to new game state from the initial state which generates exception (or state is misconfigured)&lt;br /&gt;
* You transition to player state from the initial state which has excpetion in arg* or action* method (or state is misconfigured)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If the error is not explicitly displayed when you click on &amp;quot;Express start&amp;quot;, you should check the &amp;quot;Gameserver error log&amp;quot; as per [[Studio logs]].&lt;br /&gt;
However errors and logs generated by setupNewGame not always (almost never) there, so see Debug setupNewGame session.&lt;br /&gt;
More cases of why game can&#039;t start are described on the [[Troubleshooting]] page.&lt;br /&gt;
&lt;br /&gt;
== Debugging an issue with the waiting screen ==&lt;br /&gt;
&lt;br /&gt;
BGA displays a waiting screen during a few seconds inviting free players to become premium when they are playing a lot.&lt;br /&gt;
&lt;br /&gt;
This waiting screen should not in principle impact your game, but in some cases it might.&lt;br /&gt;
&lt;br /&gt;
To test the waiting screen on the studio, you can set the desired duration by adding the get parameter studioLockingDuration with the number of seconds for the lock screen to be displayed. For example to have a 10 seconds waiting screen when you launch a game on the studio:&lt;br /&gt;
https://studio.boardgamearena.com?studioLockingDuration=10&lt;br /&gt;
&lt;br /&gt;
Then you can just set it back to zero in the same way with https://studio.boardgamearena.com?studioLockingDuration=0 (or restart your browser to clear the session value).&lt;br /&gt;
&lt;br /&gt;
== Debugging my PHP game logic (or my view) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add traces to your code ===&lt;br /&gt;
&lt;br /&gt;
You can use the following functions in your game to add server side logging:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::dump( &#039;name_of_variable&#039;, $variable );&#039;&#039;&#039;  // dump variable, like var_dump but in the log debug level logging, goes to [[Studio_logs|BGA request&amp;amp;SQL logs]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::debug( $message );&#039;&#039;&#039;  // debug level logging, goes to [[Studio_logs|BGA request&amp;amp;SQL logs]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::trace( $message );&#039;&#039;&#039;  // info level logging, goes to [[Studio_logs|BGA request&amp;amp;SQL logs]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::warn( $message );&#039;&#039;&#039;   // warning level logging, goes to [[Studio_logs#BGA_unexpected_exceptions_logs|BGA unexpected exceptions log]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::error( $message );&#039;&#039;&#039;  // error level logging, goes to [[Studio_logs#BGA_unexpected_exceptions_logs|BGA unexpected exceptions log]]&lt;br /&gt;
&lt;br /&gt;
Check [[Studio logs]] for more details on how to access your logs.&lt;br /&gt;
&lt;br /&gt;
This can be useful when you need to follow the flow of your code and not just stop it to see how it goes at some point.&lt;br /&gt;
&lt;br /&gt;
Only the error log level will appear in production. This level should be used only for critical problems. &lt;br /&gt;
Other levels will show only in the development environment and can be used as you see fit.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING&#039;&#039;&#039;: tracing does not work in constructor, setupNewGame and game states immediately following starting state (not sure why). Use other method described below in this case (seciton &amp;quot;Debugging setupNewGame&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
=== Call php functions from chat ===&lt;br /&gt;
&lt;br /&gt;
This is best feature ever, you can call individual function in your game.php from chat window, see details&lt;br /&gt;
at https://en.doc.boardgamearena.com/Tools_and_tips_of_BGA_Studio#Run_PHP_functions_from_the_chat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Dump data and die ===&lt;br /&gt;
First, make sure you can reproduce the needed game situation with one click.  Use Save (&amp;quot;[[Tools_and_tips_of_BGA_Studio#Save_.26_restore_state|save &amp;amp; restore]]&amp;quot;) function before doing some &amp;quot;test actions&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you want to see what data looks like on some path you can simply throw this in exception, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$value = var_export($my_var, true);&lt;br /&gt;
throw new BgaUserException(&#039;I am here: &#039;.$value);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternately use json instead of php formaing:&lt;br /&gt;
    $value = json_encode($my_var, JSON_PRETTY_PRINT);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Another possibility for this is to place a &#039;&#039;&#039;die(&#039;ok&#039;)&#039;&#039;&#039; and &#039;&#039;&#039;var_dump(...)&#039;&#039;&#039; functions&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
 var_dump( $my_variable );&lt;br /&gt;
 echo &amp;quot;&amp;amp;lt;/pre&amp;gt;&amp;quot;;&lt;br /&gt;
 die(&#039;ok&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: since this text will be returned back to client it will usually choke on this, but you can actually see it better if you wrap it some html (hence the &amp;amp;lt;pre&amp;gt; tag)&lt;br /&gt;
&lt;br /&gt;
=== Debug at home ===&lt;br /&gt;
&lt;br /&gt;
If you develop some complex logic it is better sometimes to stub all external calls and debug it locally using command line or IDE debugger for php.&lt;br /&gt;
You can get some basic stubs here https://github.com/elaskavaia/bga-sharedcode/raw/master/misc/module/table/table.game.php&lt;br /&gt;
&lt;br /&gt;
To run php locally you need to wrap it into test or something, see example https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Creating_a_test_class_to_run_PHP_locally&lt;br /&gt;
&lt;br /&gt;
=== Debugging setupNewGame ===&lt;br /&gt;
&lt;br /&gt;
This is separate section because tracing method do not work in this function.&lt;br /&gt;
Recommended way to debug it &lt;br /&gt;
* leave  setupNewGame exactly as in template (inlcuding setting up player table and activating first player), and add a single call at the end&lt;br /&gt;
  $this-&amp;gt;initMyTables();&lt;br /&gt;
This will be your own function which you will be changing, so you don&#039;t touch setupNewGame anymore.&lt;br /&gt;
&lt;br /&gt;
Remember that this function cannot send notification or query active or current player. If you need to get player data use $this-&amp;gt;loadPlayersBasicInfos().&lt;br /&gt;
&lt;br /&gt;
    function initMyTables() {&lt;br /&gt;
        try {&lt;br /&gt;
           $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
          // ... code the function&lt;br /&gt;
        } catch ( Exception $e ) {&lt;br /&gt;
            // logging does not actually work in game init :(&lt;br /&gt;
            // but if you calling from php chat it will work&lt;br /&gt;
            $this-&amp;gt;error(&amp;quot;Fatal error while creating game&amp;quot;);&lt;br /&gt;
            $this-&amp;gt;dump(&#039;err&#039;, $e);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Create a code for this function, and if it does not work run it from the chat window of the just created game (i.e. &#039;initMyTables()&#039; without quotes). That way you can see debug output!&lt;br /&gt;
The only trick is you have to clear all your tables in the begging so when you run it multiple times your db does not puke.&lt;br /&gt;
If your game does not start at all - do not even call it from setupNewGame, comment it out and only call from chat window until it works.&lt;br /&gt;
Don&#039;t forget you can also look at tables in db using php-admin tool (link at the bottom of the game table in studio).&lt;br /&gt;
&lt;br /&gt;
The same problem exists if you game state immediately follow starting state (problem of debugging it without the logs), in this case create a dummy player state in which player just press OK that will transition&lt;br /&gt;
to you game state, after you done debugging it remove the state and shortcut the transition to your game state.&lt;br /&gt;
&lt;br /&gt;
Instead of calling initMyTables directly you can call helper function instead from chat window which will also reset the client, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function debug_initMyTables() {&lt;br /&gt;
        $this-&amp;gt;deleteAllTables(); // this suppose to delete/reset all data - you have to implement this function&lt;br /&gt;
        $this-&amp;gt;initMyTables();&lt;br /&gt;
        $newGameDatas = $this-&amp;gt;getAllTableDatas(); // this is framework function&lt;br /&gt;
        $this-&amp;gt;notifyPlayer($this-&amp;gt;getActivePlayerId(), &#039;resetInterfaceWithAllDatas&#039;, &#039;&#039;, $newGameDatas); // this is notification to reset all data &lt;br /&gt;
        $this-&amp;gt;notifyAllPlayers(&amp;quot;message&amp;quot;,&#039;setup called&#039;,[]);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;HINT: This is a great suggestion. If you make any simple mistake in any code in setupNewGame, you may see &amp;quot;BGA Service Exception&amp;quot; instead of anything very useful, since setupNewGame failed. For example, even sending a bad SQL string to self:dbQuery() will generate this error. Very hard to debug!&lt;br /&gt;
&lt;br /&gt;
=== Debugging endOfGame ===&lt;br /&gt;
&lt;br /&gt;
Debugging end of game is hard if game ends! Make sure it does not end, then you can restore to previous state using saved states.&lt;br /&gt;
In php file:&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;processEndOfGame();&lt;br /&gt;
    if ($this-&amp;gt;getBgaEnvironment() == &#039;studio&#039;)&lt;br /&gt;
       $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;debuglast&#039;); // debug end&lt;br /&gt;
    else&lt;br /&gt;
       $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;last&#039;); // real end&lt;br /&gt;
&lt;br /&gt;
You have to add a special user state in states.inc.php file (note: this snippet uses php constants instead of state numbers)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        STATE_GAME_TURN_NEXT_PLAYER =&amp;gt; array( // normal 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; &#039;&#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; array(&lt;br /&gt;
                        &amp;quot;next&amp;quot; =&amp;gt; STATE_PLAYER_TURN_ACTION,&lt;br /&gt;
                        &amp;quot;loopback&amp;quot; =&amp;gt;  STATE_GAME_TURN_NEXT_PLAYER,&lt;br /&gt;
                        &amp;quot;last&amp;quot; =&amp;gt; STATE_END_GAME,&lt;br /&gt;
                        &amp;quot;debuglast&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END // for debugging on studio&lt;br /&gt;
                        ), &lt;br /&gt;
        ),&lt;br /&gt;
        // for debugging end of game&lt;br /&gt;
        STATE_PLAYER_GAME_END =&amp;gt; array(&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;Game Over&#039;),&lt;br /&gt;
                &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;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_playerTurnAction&amp;quot;,&lt;br /&gt;
                &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;end&amp;quot;),&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt;&lt;br /&gt;
                array(&lt;br /&gt;
                        &amp;quot;next&amp;quot; =&amp;gt; STATE_END_GAME,&lt;br /&gt;
                        &amp;quot;loopback&amp;quot;=&amp;gt; STATE_PLAYER_GAME_END)&lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Debugging my HTML/CSS layout ==&lt;br /&gt;
&lt;br /&gt;
Example situations&lt;br /&gt;
&lt;br /&gt;
* Why doesn&#039;t my game element show up in the interface?&lt;br /&gt;
* Why hasn&#039;t my CSS property been applied to this element?&lt;br /&gt;
* Why is this game element displayed at this position?&lt;br /&gt;
&lt;br /&gt;
A useful tip when an element does not show up in the interface is to give it a red background:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#my_element {&lt;br /&gt;
  ... some CSS definitions ...&lt;br /&gt;
  background-color: red;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This way, you know if the element is not visible because of some CSS property or because of something else.&lt;br /&gt;
&lt;br /&gt;
Another tip: sometimes, changing a CSS property has no visible effect on your interface. In that case, add a &amp;quot;display:none&amp;quot; property. If your element does not disappear, the bug probably comes from your CSS selector and not from your CSS property.&lt;br /&gt;
&lt;br /&gt;
Using Chrome &amp;quot;Elements&amp;quot; tab (the first one), you can:&lt;br /&gt;
* See the CURRENT HTML of your page. Remember that the classical &amp;quot;show page source&amp;quot; is inefficient with BGA as you are modifying the page source with your Javascript code.&lt;br /&gt;
* Using the &amp;quot;magnifying glass&amp;quot;, you can click on any part of your game interface and check its HTML code and associated CSS styles.&lt;br /&gt;
* You can even modify directly some CSS properties and see how it looks immediately in the game interface.&lt;br /&gt;
&lt;br /&gt;
When changing css you have to force reload (Ctrl+R). But it also reloads all images which is long, if you want it faster you can define this function in js file, and call it from Browser js console&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// this goes outside dojo class - before or after&lt;br /&gt;
function reloadCss() {&lt;br /&gt;
	var links = document.getElementsByTagName(&amp;quot;link&amp;quot;);&lt;br /&gt;
	for (var cl in links) {&lt;br /&gt;
		var link = links[cl];&lt;br /&gt;
		if (link.rel === &amp;quot;stylesheet&amp;quot; &amp;amp;&amp;amp; link.href.includes(&amp;quot;99999&amp;quot;)) {&lt;br /&gt;
			var index = link.href.indexOf(&amp;quot;?timestamp=&amp;quot;);&lt;br /&gt;
			var href = link.href;&lt;br /&gt;
			if (index &amp;gt;= 0) {&lt;br /&gt;
				href = href.substring(0, index);&lt;br /&gt;
			}&lt;br /&gt;
&lt;br /&gt;
			link.href = href + &amp;quot;?timestamp=&amp;quot; + Date.now();&lt;br /&gt;
&lt;br /&gt;
			console.log(&amp;quot;reloading &amp;quot; + link.href);&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;
For mobile  its also handy to have this as button (studio only), this goes to setup() function in js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
				// add reload Css debug button&lt;br /&gt;
				var parent = document.querySelector(&#039;.debug_section&#039;);&lt;br /&gt;
				if (parent) {&lt;br /&gt;
					var butt = dojo.create(&#039;a&#039;, { class: &#039;bgabutton bgabutton_gray&#039;, innerHTML: &amp;quot;Reload CSS&amp;quot; }, parent);&lt;br /&gt;
					dojo.connect(butt, &#039;onclick&#039;, () =&amp;gt; reloadCss());&lt;br /&gt;
				}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=== Debugging Toolips CSS/Layout ===&lt;br /&gt;
&lt;br /&gt;
To inspect tooltip you need to pin it so it does not disappear.&lt;br /&gt;
* Chrome tools:&lt;br /&gt;
** Open dev tools and switch to Source tab to engage with debugger&lt;br /&gt;
** Hover over you element until tooltip showing&lt;br /&gt;
** Press F8 - that stops the JS, so tooltip should freeze&lt;br /&gt;
** Now you can go to Elements tab and find your tooltip at the botton in dijitTooltip div&lt;br /&gt;
** Don&#039;t forget to resume it again to continue (F8 again or resume button)&lt;br /&gt;
* Other method: Open the console (dev tools) large enough window, hover to make the tooltip appear and alt + tab to focus the console that will cover the tooltip. That way the onmouseout will never be triggered.&lt;br /&gt;
&lt;br /&gt;
=== Debugging my Javascript game interface logic ===&lt;br /&gt;
&lt;br /&gt;
To debug javascript you just use embedded browser debugger, usually found in Source tab of dev tools (F12)&lt;br /&gt;
&lt;br /&gt;
Modern browsers also allow you to put breakpoints in your js code. It is in source tab, but its a bit difficult to find (your code that is), see picture below on how to insert breakpoints.&lt;br /&gt;
&lt;br /&gt;
You can do this by pressing Ctrl + B when your cursor is on the line where you want to set the breakpoint, or by clicking just to the left of the line number. One thing to be aware of is that refreshing via F5 removes set breakpoints, due to some cache busting values added to the URL. This can be remedied by adding this line to the end of your javascript source file, which enables the proper source mapping:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;//# sourceURL=myjsfile.js&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Bga-debug.jpg]]&lt;br /&gt;
&lt;br /&gt;
The easier method is to add breakpoint directly into your code and reload.&lt;br /&gt;
&lt;br /&gt;
In Chrome, to add a breakpoint: add a line to your .js file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;debugger; &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Refresh the page F5, and make sure you have the Developer tools window open, press F12. &lt;br /&gt;
When the break-point is hit you can then step through your code and visualise variables, etc.&lt;br /&gt;
&lt;br /&gt;
=== Do complex things on the PHP side ===&lt;br /&gt;
&lt;br /&gt;
The most frequent case is the following: you want to compute possible moves in a game situation. Doing it in Javascript is a nightmare. Do it in PHP, and transfer the results to your client interface using the &amp;quot;args&amp;quot; game state property.&lt;br /&gt;
&lt;br /&gt;
Note: See the Reversi tutorial for an example.&lt;br /&gt;
&lt;br /&gt;
=== Add traces in your code ===&lt;br /&gt;
&lt;br /&gt;
You can use the following:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;console.log( variable_to_inspect )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It will give you the object structure of the variable in the Javascript console, without blocking the execution.&lt;br /&gt;
&lt;br /&gt;
It&#039;s often a good idea to precede this call with a console.log( &#039;### HERE ###&#039; ); to find more easily the appropriate line in the console log.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;alert( variable_to_inspect )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It will popup what you wish and pause the execution until you click ok.&lt;br /&gt;
&lt;br /&gt;
This won&#039;t be useful for complex structures; only native types will be plainly displayed. But this is sometimes useful just with messages to make sure which way the execution goes.&lt;br /&gt;
&lt;br /&gt;
== Online format checkers ==&lt;br /&gt;
Copy and paste code for a quick code sanity check like the right number of brackets.&lt;br /&gt;
&lt;br /&gt;
PHP: [https://phpcodechecker.com/ https://phpcodechecker.com/]&lt;br /&gt;
&lt;br /&gt;
JS:  [http://esprima.org/demo/validate.html http://esprima.org/demo/validate.html]&lt;br /&gt;
&lt;br /&gt;
Checks for proper attributes values and browser&#039;s compatibility&lt;br /&gt;
&lt;br /&gt;
CSS: http://jigsaw.w3.org/css-validator/&lt;br /&gt;
&lt;br /&gt;
== Some frequent errors ==&lt;br /&gt;
&lt;br /&gt;
See [[Troubleshooting]].&lt;br /&gt;
&lt;br /&gt;
== Get the database matching a bug report ==&lt;br /&gt;
&lt;br /&gt;
When a player creates a bug report in production, a snapshot of the game database is taken. You can get access to this snapshot from the studio by following the steps below:&lt;br /&gt;
* Create a table in the studio with the same game and number of players as the table for which the report has been written. Launch this table.&lt;br /&gt;
* Open another tab on the studio and go to &amp;quot;Manage game&amp;quot; page for your project (you have to be admin for this project)&lt;br /&gt;
* In the &amp;quot;Errors in production&amp;quot; section, fill up the fields &amp;quot;Bug report ID&amp;quot; (this is the ID of the bug report in production) and &amp;quot;Studio table ID&amp;quot; (this is the ID of the table you created above) then click the &amp;quot;⇨ Load bug report state into this table save slot #1&amp;quot; button.&lt;br /&gt;
* If the snapshot is correctly retrieved, you see a &amp;quot;Done!&amp;quot; message.&lt;br /&gt;
* Go back to the tab with your studio table and click &amp;quot;Load 1&amp;quot;.&lt;br /&gt;
* The page refreshes automatically and is broken. This is normal, as the player ids from the snapshot are the player ids of the production, not those of the studio. We&#039;ll need to update them.&lt;br /&gt;
** &#039;&#039;&#039;Important note:&#039;&#039;&#039; if you see a &amp;quot;Done!&amp;quot; message but clicking &amp;quot;Load 1&amp;quot; doesn&#039;t bring any change, it&#039;s that the snapshot is unfortunately not available (most likely because the bug report was declared too long after the game ended and the database had already been garbage collected to reclaim space).&lt;br /&gt;
* Click on the &amp;quot;Go to game database&amp;quot; button&lt;br /&gt;
* For each table using player_ids, you&#039;ll need to update the player_ids from the production to use the player_ids from the studio. You can see the player_ids from the table page before entering the game by hovering over the player names.&lt;br /&gt;
* Tables to update:&lt;br /&gt;
** player&lt;br /&gt;
** global (value with ID 2 is the active player)&lt;br /&gt;
** stats&lt;br /&gt;
** tables specific to your schema that use player_ids&lt;br /&gt;
* If your changes to player_ids are not taken into account, it may be a cache problem: use the &amp;quot;Clear PHP cache&amp;quot; button on your &amp;quot;Manage game&amp;quot; page.&lt;br /&gt;
* Then you should be able to play with the same state of the game as when the report was created in production.&lt;br /&gt;
* If the game has ended, you can place it again in the game state you want to debug by setting the value with ID 1 in the global table to the appropriate state value, and the value with ID 2 to the player you want active).&lt;br /&gt;
*&lt;br /&gt;
* Below is an example php function you may want to make. You can call this function from the chat window: LoadDebug()  &lt;br /&gt;
* change instances of 2308257, and 2308258 to you own BGA Studio logins YourLogin0 and YourLogin1&lt;br /&gt;
* change $id0 and $id1 to the player_ids from the table you want to debug, and have recently imported.&lt;br /&gt;
* Before you load Slot1, open a second tab with the table, because after loading the slot, that tab will be unusable. In the second tab you can call LoadDebug() in the chat window&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	public function LoadDebug()&lt;br /&gt;
	{&lt;br /&gt;
		// These are the id&#039;s from the BGAtable I need to debug.&lt;br /&gt;
		// you can get them by running this query : SELECT JSON_ARRAYAGG(`player_id`) FROM `player`&lt;br /&gt;
		$ids = [&lt;br /&gt;
			86107517,&lt;br /&gt;
			86872172,&lt;br /&gt;
			85086097,&lt;br /&gt;
			84380410,&lt;br /&gt;
			11000525&lt;br /&gt;
		];&lt;br /&gt;
                // You can also get the ids automatically with $ids = array_map(fn($dbPlayer) =&amp;gt; intval($dbPlayer[&#039;player_id&#039;]), array_values($this-&amp;gt;getCollectionFromDb(&#039;select player_id from player order by player_no&#039;)));&lt;br /&gt;
&lt;br /&gt;
		// Id of the first player in BGA Studio&lt;br /&gt;
		$sid = 2296755;&lt;br /&gt;
		&lt;br /&gt;
		foreach ($ids as $id) {&lt;br /&gt;
			// basic tables&lt;br /&gt;
			self::DbQuery(&amp;quot;UPDATE player SET player_id=$sid WHERE player_id = $id&amp;quot; );&lt;br /&gt;
			self::DbQuery(&amp;quot;UPDATE global SET global_value=$sid WHERE global_value = $id&amp;quot; );&lt;br /&gt;
			self::DbQuery(&amp;quot;UPDATE stats SET stats_player_id=$sid WHERE stats_player_id = $id&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
			// &#039;other&#039; game specific tables. example:&lt;br /&gt;
			// tables specific to your schema that use player_ids&lt;br /&gt;
			self::DbQuery(&amp;quot;UPDATE card SET card_location_arg=$sid WHERE card_location_arg = $id&amp;quot; );&lt;br /&gt;
			&lt;br /&gt;
			++$sid;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Fully automated version===&lt;br /&gt;
Thanks to quietmint for [https://boardgamearena.com/forum/viewtopic.php?f=12&amp;amp;t=16454#p63167 coming up] with that!&lt;br /&gt;
(updated and working on 05/06/2922)&lt;br /&gt;
&lt;br /&gt;
; In ggg.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  /*&lt;br /&gt;
   * loadBug: in studio, type loadBug(20762) into the table chat to load a bug report from production&lt;br /&gt;
   * client side JavaScript will fetch each URL below in sequence, then refresh the page&lt;br /&gt;
   */&lt;br /&gt;
  public function loadBug($reportId)&lt;br /&gt;
  {&lt;br /&gt;
    $db = explode(&#039;_&#039;, self::getUniqueValueFromDB(&amp;quot;SELECT SUBSTRING_INDEX(DATABASE(), &#039;_&#039;, -2)&amp;quot;));&lt;br /&gt;
    $game = $db[0];&lt;br /&gt;
    $tableId = $db[1];&lt;br /&gt;
    self::notifyAllPlayers(&#039;loadBug&#039;, &amp;quot;Trying to load &amp;lt;a href=&#039;https://boardgamearena.com/bug?id=$reportId&#039; target=&#039;_blank&#039;&amp;gt;bug report $reportId&amp;lt;/a&amp;gt;&amp;quot;, [&lt;br /&gt;
      &#039;urls&#039; =&amp;gt; [&lt;br /&gt;
        // Emulates &amp;quot;load bug report&amp;quot; in control panel&lt;br /&gt;
        &amp;quot;https://studio.boardgamearena.com/admin/studio/getSavedGameStateFromProduction.html?game=$game&amp;amp;report_id=$reportId&amp;amp;table_id=$tableId&amp;quot;,&lt;br /&gt;
        &lt;br /&gt;
        // Emulates &amp;quot;load 1&amp;quot; at this table&lt;br /&gt;
        &amp;quot;https://studio.boardgamearena.com/table/table/loadSaveState.html?table=$tableId&amp;amp;state=1&amp;quot;,&lt;br /&gt;
        &lt;br /&gt;
        // Calls the function below to update SQL&lt;br /&gt;
        &amp;quot;https://studio.boardgamearena.com/1/$game/$game/loadBugSQL.html?table=$tableId&amp;amp;report_id=$reportId&amp;quot;,&lt;br /&gt;
        &lt;br /&gt;
        // Emulates &amp;quot;clear PHP cache&amp;quot; in control panel&lt;br /&gt;
        // Needed at the end because BGA is caching player info&lt;br /&gt;
        &amp;quot;https://studio.boardgamearena.com/admin/studio/clearGameserverPhpCache.html?game=$game&amp;quot;,&lt;br /&gt;
      ]&lt;br /&gt;
    ]);&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  /*&lt;br /&gt;
   * loadBugSQL: in studio, this is one of the URLs triggered by loadBug() above&lt;br /&gt;
   */&lt;br /&gt;
  public function loadBugSQL($reportId)&lt;br /&gt;
  {&lt;br /&gt;
    $studioPlayer = self::getCurrentPlayerId();&lt;br /&gt;
    $players = self::getObjectListFromDb(&amp;quot;SELECT player_id FROM player&amp;quot;, true);&lt;br /&gt;
  &lt;br /&gt;
    // Change for your game&lt;br /&gt;
    // We are setting the current state to match the start of a player&#039;s turn if it&#039;s already game over&lt;br /&gt;
    $sql = [&lt;br /&gt;
      &amp;quot;UPDATE global SET global_value=2 WHERE global_id=1 AND global_value=99&amp;quot;&lt;br /&gt;
    ];&lt;br /&gt;
    foreach ($players as $pId) {&lt;br /&gt;
      // All games can keep this SQL&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE player SET player_id=$studioPlayer WHERE player_id=$pId&amp;quot;;&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE global SET global_value=$studioPlayer WHERE global_value=$pId&amp;quot;;&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE stats SET stats_player_id=$studioPlayer WHERE stats_player_id=$pId&amp;quot;;&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE gamelog SET gamelog_player=$studioPlayer WHERE gamelog_player=$pId&amp;quot;;&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE gamelog SET gamelog_current_player=$studioPlayer WHERE gamelog_current_player=$pId&amp;quot;;&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE gamelog SET gamelog_notification=REPLACE(gamelog_notification, $pId, $studioPlayer)&amp;quot;;&lt;br /&gt;
  &lt;br /&gt;
      // TODO Add game-specific SQL updates for the tables, everywhere players ids are used in your game &lt;br /&gt;
      $sql[] = &amp;quot;UPDATE deck SET card_location_arg=$studioPlayer WHERE card_location_arg=$pId&amp;quot;;&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE card SET card_location_arg=$studioPlayer WHERE card_location_arg=$pId&amp;quot;;&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE piece SET player_id=$studioPlayer WHERE player_id=$pId&amp;quot;;&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE log SET player_id=$studioPlayer WHERE player_id=$pId&amp;quot;;&lt;br /&gt;
      $sql[] = &amp;quot;UPDATE log SET action_arg=REPLACE(action_arg, $pId, $studioPlayer)&amp;quot;;&lt;br /&gt;
  &lt;br /&gt;
      // This could be improved, it assumes you had sequential studio accounts before loading&lt;br /&gt;
      // e.g., quietmint0, quietmint1, quietmint2, etc. are at the table&lt;br /&gt;
      $studioPlayer++;&lt;br /&gt;
    }&lt;br /&gt;
    $msg = &amp;lt;nowiki&amp;gt;&amp;quot;&amp;lt;b&amp;gt;Loaded &amp;lt;a href=&#039;https://boardgamearena.com/bug?id=$reportId&#039; target=&#039;_blank&#039;&amp;gt;bug report $reportId&amp;lt;/a&amp;gt;&amp;lt;/b&amp;gt;&amp;lt;hr&amp;gt;&amp;lt;ul&amp;gt;&amp;lt;li&amp;gt;&amp;quot; . implode(&#039;;&amp;lt;/li&amp;gt;&amp;lt;li&amp;gt;&#039;, $sql) . &#039;;&amp;lt;/li&amp;gt;&amp;lt;/ul&amp;gt;&#039;;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
    self::warn($msg);&lt;br /&gt;
    self::notifyAllPlayers(&#039;message&#039;, $msg, []);&lt;br /&gt;
  &lt;br /&gt;
    foreach ($sql as $q) {&lt;br /&gt;
      self::DbQuery($q);&lt;br /&gt;
    }&lt;br /&gt;
    self::reloadPlayersBasicInfos();&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;reloadState();&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; In ggg.action.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public function loadBugSQL() {&lt;br /&gt;
    self::setAjaxMode();&lt;br /&gt;
    $reportId = (int) self::getArg(&#039;report_id&#039;, AT_int, true);&lt;br /&gt;
    $this-&amp;gt;game-&amp;gt;loadBugSQL($reportId);&lt;br /&gt;
    self::ajaxResponse();&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; In ggg.js&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Load production bug report handler&lt;br /&gt;
  const self = this; // save the `this` context in a variable&lt;br /&gt;
  dojo.subscribe(&amp;quot;loadBug&amp;quot;, this, function loadBug(n) {&lt;br /&gt;
    function fetchNextUrl() {&lt;br /&gt;
      var url = n.args.urls.shift();&lt;br /&gt;
      console.log(&amp;quot;Fetching URL&amp;quot;, url, &amp;quot;...&amp;quot;);&lt;br /&gt;
      // all the calls have to be made with ajaxcall in order to add the csrf token, otherwise you&#039;ll get &amp;quot;Invalid session information for this action. Please try reloading the page or logging in again&amp;quot;&lt;br /&gt;
      self.ajaxcall(url,&lt;br /&gt;
      {&lt;br /&gt;
         lock: true,&lt;br /&gt;
      },&lt;br /&gt;
      self,&lt;br /&gt;
      function (success) {&lt;br /&gt;
        console.log(&amp;quot;=&amp;gt; Success &amp;quot;, success);&lt;br /&gt;
&lt;br /&gt;
        if (n.args.urls.length &amp;gt; 1) {&lt;br /&gt;
          fetchNextUrl();&lt;br /&gt;
        }&lt;br /&gt;
        else if (n.args.urls.length &amp;gt; 0) {&lt;br /&gt;
          //except the last one, clearing php cache&lt;br /&gt;
          url = n.args.urls.shift();&lt;br /&gt;
          dojo.xhrGet({&lt;br /&gt;
            url: url,&lt;br /&gt;
            headers: {&lt;br /&gt;
                &amp;quot;X-Request-Token&amp;quot;: bgaConfig.requestToken&lt;br /&gt;
            },&lt;br /&gt;
            load: function (success) {&lt;br /&gt;
              console.log(&amp;quot;Success for URL&amp;quot;, url, success);&lt;br /&gt;
              console.log(&amp;quot;Done, reloading page&amp;quot;);&lt;br /&gt;
              window.location.reload();&lt;br /&gt;
            },&lt;br /&gt;
            handleAs: &amp;quot;text&amp;quot;,&lt;br /&gt;
            error: function (error) {&lt;br /&gt;
              console.log(&amp;quot;Error while loading : &amp;quot;, error);&lt;br /&gt;
            }&lt;br /&gt;
          });&lt;br /&gt;
       }&lt;br /&gt;
     }&lt;br /&gt;
     ,&lt;br /&gt;
     function (error) {&lt;br /&gt;
       if (error)&lt;br /&gt;
          console.log(&amp;quot;=&amp;gt; Error &amp;quot;, error);&lt;br /&gt;
       }&lt;br /&gt;
     );&lt;br /&gt;
   }&lt;br /&gt;
  console.log(&amp;quot;Notif: load bug&amp;quot;, n.args);&lt;br /&gt;
  fetchNextUrl();&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Studio environment ==&lt;br /&gt;
&lt;br /&gt;
Some developers have requested a method allowing to know which environment the module is running on. While in general, your code should be the same on all environments so that the validation process makes sense, this may allow for example to display some helpers for testing during development while being sure that they&#039;ll never show up outside of the studio.&lt;br /&gt;
&lt;br /&gt;
From your &amp;lt;gamename&amp;gt;.game.php file you can use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if ($this-&amp;gt;getBgaEnvironment() == &#039;studio&#039;) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if needed from your &amp;lt;gamename&amp;gt;.view.php file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if ($this-&amp;gt;game-&amp;gt;getBgaEnvironment() == &#039;studio&#039;) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=16841</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=16841"/>
		<updated>2023-05-05T12:29:07Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* States functions */&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;
This is the main  class that implements the &amp;quot;server&amp;quot; callbacks. As it is a server it cannot initiate any data communicate with the game client (running in browser) and only can respond to client using notifications.&lt;br /&gt;
&lt;br /&gt;
Your php class instance won&#039;t be in memory between two callbacks, every time client send a request a new class will be created, constructor will be called and eventually your callback function.&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;
* &#039;&#039;&#039;__construct&#039;&#039;&#039;: the game constructor, where you define global variables and initiaze class members.&lt;br /&gt;
* &#039;&#039;&#039;setupNewGame&#039;&#039;&#039;: 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;
* &#039;&#039;&#039;getAllDatas&#039;&#039;&#039;: where you retrieve all game data during a complete reload of the game. Return value must be associative array. Value of &#039;players&#039; is reserved for returning players data from players table, if you set it it must follow certain rules &lt;br /&gt;
        $result [&#039;players&#039;] = self::getCollectionFromDb(&amp;quot;SELECT player_id id, player_score score, player_no no, player_color color FROM player&amp;quot;);&lt;br /&gt;
        // Returned value must include [&#039;players&#039;][$player_id]][&#039;score&#039;] for scores to populate when F5 is pressed.&lt;br /&gt;
* &#039;&#039;&#039;getGameProgression&#039;&#039;&#039;: where you compute the game progression indicator. Returns a number indicating percent of progression (0-100)&lt;br /&gt;
* Utility functions: your utility functions.&lt;br /&gt;
* Player actions: the entry points for players actions ([https://en.doc.boardgamearena.com/Players_actions:_yourgamename.action.php more info here]). &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;
* &#039;&#039;&#039;initTable&#039;&#039;&#039;: (not part of template) - this function is called for every php callback by the framework and it can be implement by the game (empty by default). You can use it in rare cases where you need to read database and manipulate some data before any ANY php entry functions are called (such as getAllDatas,action*,st*, etc). Note: it is not called before arg* methods &lt;br /&gt;
* &#039;&#039;&#039;zombieTurn&#039;&#039;&#039;: what to do it&#039;s the turn of a zombie player.&lt;br /&gt;
* &#039;&#039;&#039;upgradeTableDb&#039;&#039;&#039;: 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 the beggining of setupNewGame (use count($players) instead). It will work after initialization of player table.&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;
; getPlayerNameById($player_id)&lt;br /&gt;
: Get the name by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerColorById($player_id)&lt;br /&gt;
: Get the color by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerNoById($player_id)&lt;br /&gt;
: Get &#039;player_no&#039; (number) by id&lt;br /&gt;
&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 (as string)&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;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
                foreach ($players as $player_id =&amp;gt; $info) {&lt;br /&gt;
                    $player_color = $info[&#039;player_color&#039;];&lt;br /&gt;
                    ...&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: if you want array of player ids only you can do this:&lt;br /&gt;
    $player_ids =  array_keys($this-&amp;gt;loadPlayersBasicInfos());  &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;
; isSpectator()&lt;br /&gt;
: Check the &amp;quot;current_player&amp;quot; spectator status. If true, the user accessing the game is a spectator (not part of the game). For this user, the interface should display all public information, and no private information (like a friend sitting at the same table as players and just spectating 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;
; isPlayerZombie($player_id)&lt;br /&gt;
: This method does not exists, but if you need it it looks like this&lt;br /&gt;
    protected function isPlayerZombie($player_id) {&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        if (! isset($players[$player_id]))&lt;br /&gt;
            throw new BgaSystemException(&amp;quot;Player $player_id is not playing here&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        return ($players[$player_id][&#039;player_zombie&#039;] == 1);&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;
However there are sets of database operation that initite implicit commit (most common mistake is to use &amp;quot;TRUNCATE&amp;quot;), you cannot use these operations during the game, it breaks the unrolling of transactions and will lead to nasty issues&lt;br /&gt;
(https://mariadb.com/kb/en/sql-statements-that-cause-an-implicit-commit).&lt;br /&gt;
&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;
: For SELECT queries, the specialized methods below are much better.&lt;br /&gt;
: Do not use method for TUNCATE, DROP and other table altering operations. See disclamer above about implicit commits. If you really need TRUNCATE use DELETE FROM xxx instead.&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 (semantically, it does not actually have to declared in sql as such).&lt;br /&gt;
: The resulting collection can be empty (it won&#039;t be null).&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;, otherwise its A=&amp;gt;[A,B]&lt;br /&gt;
: Note: The name a bit misleading, it really return associative array, i.e. map and NOT a collection. You cannot use it to get list of values which may have duplicates (hence primary key requirement on first column). If you need simple array use getObjectListFromDB() method.&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 (you can use LIMIT 1 in the query to avoid the exception)&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 as &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;$this-&amp;gt;initGameStateLabels&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method should be located at the beginning of __construct() method of &#039;&#039;yourgamename.game.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, there can be gaps). 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;
        $this-&amp;gt;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;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $this-&amp;gt;GAMESTATELABELS = [&amp;quot;my_first_global_variable&amp;quot; =&amp;gt; 10, &amp;quot;my_second_global_variable&amp;quot; =&amp;gt; 11];&lt;br /&gt;
        $this-&amp;gt;initGameStateLabels($this-&amp;gt;GAMESTATELABELS);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is also in this method that you will define your game options. In that case, IDs need to be between 100 and 199 (inclusive, there can be gaps) Check this for more details [[Game_options_and_preferences:_gameoptions.inc.php]]&lt;br /&gt;
&lt;br /&gt;
With option set, the method will look like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $this-&amp;gt;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;
                &amp;quot;my_game_variant&amp;quot; =&amp;gt; 100&lt;br /&gt;
        ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$this-&amp;gt;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. $value_value must be an integer.&lt;br /&gt;
&lt;br /&gt;
It seems that a non initialized value will not be restored with undo system, so it is therefore advisable to initialize them all in your &amp;quot;setupNewGame&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;foreach ($this-&amp;gt;GAMESTATELABELS as $value_label=&amp;gt; $ID) if ($ID &amp;gt;= 10 &amp;amp;&amp;amp; $ID &amp;lt; 90) $this-&amp;gt;setGameStateInitialValue($value_label, 0);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$this-&amp;gt;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;
For debugging purposes, you can have labels and value pairs send to client side by inserting that line of code in your &amp;quot;getAllDatas&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;$result[&#039;labels&#039;] = array_combine(array_keys($this-&amp;gt;GAMESTATELABELS), array_map(array($this,&#039;getGameStateValue&#039;), array_keys($this-&amp;gt;GAMESTATELABELS)));&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$this-&amp;gt;setGameStateValue( $value_label, $value_value )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Set the current value of a global. $value_value must be an integer.&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;
=== BGA predefined globals ===&lt;br /&gt;
&lt;br /&gt;
BGA already defines some globals in the &#039;&#039;global&#039;&#039; database table. You should not change them directly but it can be useful to know what they mean when debugging:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! global_id !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Active state id&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Active player id&lt;br /&gt;
|-&lt;br /&gt;
| 3 || Next move number&lt;br /&gt;
|-&lt;br /&gt;
| 4 || Project id&lt;br /&gt;
|-&lt;br /&gt;
| 5 || Table creator id&lt;br /&gt;
|-&lt;br /&gt;
| 6 || Player turn number&lt;br /&gt;
|-&lt;br /&gt;
| 7 || Game progression&lt;br /&gt;
|-&lt;br /&gt;
| 8 || Initial reflection time&lt;br /&gt;
|-&lt;br /&gt;
| 9 || Additional reflection time&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Reflexion time profile&lt;br /&gt;
|-&lt;br /&gt;
| 207 || GAMESTATE_GAME_LANG&lt;br /&gt;
|-&lt;br /&gt;
| 201 || BGA ranking mode&lt;br /&gt;
|-&lt;br /&gt;
| 300 || GAMESTATE_GAMEVERSION: Current version of the game (when in production)&lt;br /&gt;
|-&lt;br /&gt;
| 301 || GAMESTATE_GAME_RESULT_NEUTRALIZED&lt;br /&gt;
|-&lt;br /&gt;
| 302 || GAMESTATE_NEUTRALIZED_PLAYER_ID&lt;br /&gt;
|-&lt;br /&gt;
| 304 || GAMESTATE_UNDO_MOVES_STORED&lt;br /&gt;
|-&lt;br /&gt;
| 305 || GAMESTATE_UNDO_MOVES_PLAYER&lt;br /&gt;
|-&lt;br /&gt;
| 306 || GAMESTATE_LOCK_TIMESTAMP&lt;br /&gt;
|}&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;
; $this-&amp;gt;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, it just calls $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive()&lt;br /&gt;
&lt;br /&gt;
This is to be used in 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;stMakeEveryoneActive&#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. If &amp;quot;players&amp;quot; is not empty the value of &amp;quot;next_state&amp;quot; will be ignored (you can put whatever you want)&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;
;$this-&amp;gt;gamestate-&amp;gt;isPlayerActive($player_id)&lt;br /&gt;
:Return true if specified player is active right now.&lt;br /&gt;
:This method take into account game state type, ie nobody is active if game state is &amp;quot;game&amp;quot; and several players can be active if game state is &amp;quot;multiplayer&amp;quot;&lt;br /&gt;
&lt;br /&gt;
;$this-&amp;gt;bIndependantMultiactiveTable&lt;br /&gt;
:This flag can be set to true in constructor of game.php to force creation of second table to handle multiplayer states (normally these are in player table), this is very advanced feature.&lt;br /&gt;
:ONLY use it after you deploy you game to production if you receive unusual amount of bug report with dead lock symptoms DURING multiactiveplayer states&lt;br /&gt;
    function __construct() {&lt;br /&gt;
      ...&lt;br /&gt;
      $this-&amp;gt;bIndependantMultiactiveTable=true;&lt;br /&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;
&#039;&#039;&#039;$this-&amp;gt;gamestate-&amp;gt;jumpToState($stateNum)&#039;&#039;&#039;&lt;br /&gt;
: Change current state to a new state. Important: the $stateNum parameter is the key of the state. See [[Your game state machine: states.inc.php]] for more information about states.&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 changed 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;
&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;
I suggest to define and use this function in your php class to access state name:&lt;br /&gt;
&lt;br /&gt;
    public function getStateName() {&lt;br /&gt;
        $state = $this-&amp;gt;gamestate-&amp;gt;state();&lt;br /&gt;
        return $state[&#039;name&#039;];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;state_id()&lt;br /&gt;
: Get the id of the current game state (rarely useful, its best to use name, unless you use constants for state ids)&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;isMutiactiveState()&lt;br /&gt;
: Return true if we are in multipleactiveplayer state, false otherwise&lt;br /&gt;
&lt;br /&gt;
=== Private parallel states ===&lt;br /&gt;
&lt;br /&gt;
See the overview of private parallel states [[Your_game_state_machine:_states.inc.php#Private_parallel_states|here]].&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers()&lt;br /&gt;
: All active players in a multiactive state are entering a first private state defined in the master state&#039;s initialprivate parameter.&lt;br /&gt;
: Every time you need to start a private parallel states you need to call this or similar methods below.&lt;br /&gt;
: Note: at least one player needs to be active (see [[#Multiple_activate_player_handling|above]]) and current game state must be a multiactive state with initialprivate parameter defined&lt;br /&gt;
: Note: initialprivate parameter of master state should be set to the id of the first private state. This private state needs to be defined in states.php with the type set to &#039;private&#039;.&lt;br /&gt;
: Note: this method is usually preceded with activating some or all players&lt;br /&gt;
: Note: initializing private state can run action or args methods of the initial private state&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function stStartPlayerTurn() {&lt;br /&gt;
        // This is usually done in master state action method&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers();&lt;br /&gt;
&lt;br /&gt;
        // in some cases you can move immediately some or all players to different private states&lt;br /&gt;
        if ($someCondition) {&lt;br /&gt;
            //move all players to different state &lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers(&amp;quot;some_transition&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($other condition) {&lt;br /&gt;
            //move single player to different state&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($specificPlayerId, &amp;quot;some_transition&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForPlayers($playerIds)&lt;br /&gt;
: Players with specified ids are entering a first private state defined in the master state initialprivate parameter.&lt;br /&gt;
: Same considerations apply as for the method above.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;initializePrivateState($playerId)&lt;br /&gt;
: Player with the specified id is entering a first private state defined in the master state initialprivate parameter.&lt;br /&gt;
: Everytime you need to start a private parallel states you need to call this or similar methods above&lt;br /&gt;
: Note: player needs to be active (see [[#Multiple_activate_player_handling|above]]) and current game state must be a multiactive state with initialprivate parameter defined&lt;br /&gt;
: Note: initialprivate parameter of master state should be set to the id of the first private state. This private state needs to be defined in states.php with the type set to &#039;private&#039;.&lt;br /&gt;
: Note: this method is usually preceded with activating that player&lt;br /&gt;
: Note: initializing private state can run action or args methods of the initial private state&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_ChangeMind() {&lt;br /&gt;
        // This player finished his move before, but now decides change something while other players are still active&lt;br /&gt;
        // We activate the player and initialize his private state&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive([$this-&amp;gt;getCurrentPlayerId()], &amp;quot;&amp;quot;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateState(this-&amp;gt;getCurrentPlayerId());&lt;br /&gt;
&lt;br /&gt;
        // It is also possible to move the player to some other specific state immediately&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;some_transition&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers($transition)&lt;br /&gt;
: All active players will transition to next private state by specified transition&lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: transition should lead to another private state (i.e. a state with type defined as &#039;private&#039;&lt;br /&gt;
: Note: transition should be defined in private state in which the players currently are. &lt;br /&gt;
: Note: this method can run action or args methods of the target state&lt;br /&gt;
: Note: this is usually used after initializing the private state to move players to specific private state according to the game logic&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function stStartPlayerTurn() {&lt;br /&gt;
        // This is usually done in master state action method&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers();&lt;br /&gt;
&lt;br /&gt;
        if ($specificOption) {&lt;br /&gt;
            //move all players to different state &lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers(&amp;quot;some_transition&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForPlayers($playerIds, $transition)&lt;br /&gt;
: Players with specified ids will transition to next private state specified by provided transition.&lt;br /&gt;
: Same considerations apply as for the method above.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($playerId, $transition)&lt;br /&gt;
: Player with specified id will transition to next private state specified by provided transition&lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: transition should lead to another private state (i.e. a state with type defined as &#039;private&#039;&lt;br /&gt;
: Note: transition should be defined in private state in which the players currently are. &lt;br /&gt;
: Note: this method can run action or args methods of the target state for specified player&lt;br /&gt;
: Note: this is usually used after some player actions to move to next private state&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function someAction() {&lt;br /&gt;
        $this-&amp;gt;checkAction(&amp;quot;someAction&amp;quot;); //needs to be defined in the current state&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;some_transition&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;unsetPrivateStateForAllPlayers()&lt;br /&gt;
: All players private state will be reset to null, which means they will get out of private parallel states and be in a master state like the private states are not used &lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: this is usually used to clean up after leaving a master state in which private states were used, but can be used in other cases when we want to exit private parallel states and use a regular multiactive state for all players&lt;br /&gt;
: Note: After unseting private state only actions on master state are possible&lt;br /&gt;
: Note: Usually it is not necessary to unset private states as they will be initialized to first private state when private states are needed again. Nevertheless it is generally better to clean private state after exiting private parallel states to avoid bugs. &lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function stNextRound() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;unsetPrivateStateForAllPlayers();&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;unsetPrivateStateForPlayers($playerIds, $transition)&lt;br /&gt;
: For players with specified ids private state will be reset to null, which means they will get out of private parallel states and be in a master state like the private states are not used.&lt;br /&gt;
: Same considerations apply as for the method above.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;unsetPrivateState($playerId)&lt;br /&gt;
: For player with specified id private state will be reset to null, which means they will get out of private parallel states and be in a master state like the private states are not used &lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: this is usually used when deactivating player to clean up their parallel state&lt;br /&gt;
: Note: After unseting private state only actions on master state are possible&lt;br /&gt;
: Note: Usually it is not necessary to unset private state as it will be initialized to first private state when private states are needed again. Nevertheless it is generally better to clean private state when not needed to avoid bugs. &lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function done() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive( $this-&amp;gt;getCurrentPlayerId(), &amp;quot;newTurn&amp;quot; );&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;unsetPrivateState($this-&amp;gt;getCurrentPlayerId());&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setPrivateState($playerId, $newStateId)&lt;br /&gt;
: For player with specified id a new private state would be set&lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: this should be rarely used as it doesn&#039;t check if the transition is allowed (it doesn&#039;t even specifies transition). This can be useful in very complex cases when standard state machine is not adequate (i.e. specific cards can lead to some micro action in various states where defining transitions back and forth can become very tedious.) &lt;br /&gt;
: Note: this method can run action or args methods of the target state for specified player&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function someAction() {&lt;br /&gt;
        $this-&amp;gt;checkAction(&amp;quot;someAction&amp;quot;); //needs to be defined in the current state&lt;br /&gt;
&lt;br /&gt;
        if ($playerHaveSpecificCard)&lt;br /&gt;
            return $this-&amp;gt;gamestate-&amp;gt;setPrivateState($this-&amp;gt;getCurrentPlayerId(), 35);&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;some_transition&amp;quot;);        &lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;getPrivateState($playerId) &lt;br /&gt;
: This return the private state or null if not initialized or not in private state&lt;br /&gt;
&lt;br /&gt;
==== State Arguments in Private parallel states ====&lt;br /&gt;
&lt;br /&gt;
The args method called for private states will have the player_id passed to it, allowing you to customise the arguments returned for that player.&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function argMyPrivateState($player_id) {&lt;br /&gt;
        return array(&lt;br /&gt;
          &#039;my_data&#039; =&amp;gt; $this-&amp;gt;getPlayerSpecificData($player_id)&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Inactive Players ====&lt;br /&gt;
&lt;br /&gt;
During Private Parallel State, active players will be managed by the private state that is current assigned to them.&lt;br /&gt;
&lt;br /&gt;
Inactive players will be managed by the master multipleactiveplayer state, so your client should respond to that state in order to display any status message advising players that they are waiting for others to have their turn, or to add any buttons that allow players to potentially &amp;quot;break in&amp;quot; and become active.&lt;br /&gt;
&lt;br /&gt;
== Players turn order ==&lt;br /&gt;
&lt;br /&gt;
When table is created the &amp;quot;natural&amp;quot; player order is assigned to player at random, and stored in &amp;quot;read-only&amp;quot; field &amp;quot;player_no&amp;quot;.&lt;br /&gt;
If you need to create a custom order you should never change natural order but have a separate data structure. &lt;br /&gt;
For example you can alter the players table to add another &amp;quot;custom_order&amp;quot; field, you can use state globals or you can use your natural board database, &lt;br /&gt;
to store meeple_color/position_location pair.&lt;br /&gt;
BGA currently does not provide any API to create/store custom player 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 1000, 2000 and 3000 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;
    1000 =&amp;gt; 2000, &lt;br /&gt;
    2000 =&amp;gt; 3000, &lt;br /&gt;
    3000 =&amp;gt; 1000, &lt;br /&gt;
    0 =&amp;gt; 1000 &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;
If parmeter $bLoop is set to true then last player will points to first (creaing a loop), 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;
Note: This function &#039;&#039;&#039;DOES NOT&#039;&#039;&#039; change the order in database, it only creates a map using key/values as descibed.&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 $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$table = $this-&amp;gt;createNextPlayerTable([3,2,1], false);&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
   [ &lt;br /&gt;
    3000 =&amp;gt; 2000, &lt;br /&gt;
    2000 =&amp;gt; 1000, &lt;br /&gt;
    1000 =&amp;gt; null,&lt;br /&gt;
    0 =&amp;gt; 3000 &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;
=== NotifyAllPlayers ===&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 translated.&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;
* 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 if 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;
&#039;&#039;&#039;Important&#039;&#039;&#039;: When the game page is reloaded (i.e. F5 or when loading turn based game) all previous notifications are replayed as history notifications. These notifications do not trigger notification handlers and are used basically to build the game log. Because of that most of the notification arguments, except i18n, player_id and all arguments used in the message, are removed from these history notifications. If you need additional arguments in history notifications you can add special field &amp;lt;b&amp;gt;preserve&amp;lt;/b&amp;gt; to notification arguments, like this:&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;
        &#039;preserve&#039; =&amp;gt; [ &#039;x&#039;, &#039;y&#039; ]&lt;br /&gt;
     ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In this example, fields x and y will be preserved when replaying history notification at the game load.&lt;br /&gt;
&lt;br /&gt;
==== HTML in Notifications ====&lt;br /&gt;
&lt;br /&gt;
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 replay 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 replay, 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;
==== Recursive Notifications ====&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_name1}, ${player_name2}, ${player_name3}, etc. - same&lt;br /&gt;
&lt;br /&gt;
==== Excluding some players ====&lt;br /&gt;
&lt;br /&gt;
Sometimes you want to notify all players of a message but not have it appear in the log of specific players (for example, have every player see &amp;quot;Player X draws a card&amp;quot; but have Player X see &amp;quot;You draw the Ace of Spades&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
To send a notification to all players but have some clients ignore it, send it as normal from the server, but implement &#039;&#039;&#039;setIgnoreNotificationCheck&#039;&#039;&#039; on the client to ignore the message under given conditions. See the X.js documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== NotifyPlayer ===&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;
Note that spectators cannot be notified using this method, because their player ID is not available via loadPlayersBasicInfos() or otherwise. You must use notifyAllPlayers() for any notification that spectators should get.&lt;br /&gt;
&lt;br /&gt;
== Randomization ==&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 if 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;
See also [https://en.doc.boardgamearena.com/Game_meta-information:_gameinfos.inc.php#Multiple_tie_breaker_management Multiple Tie Breaker Management].&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 play and can start another game if he/she wants too (with 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;
&#039;&#039;&#039;Important: this should not be used on a player who has already left the game (&amp;quot;zombie&amp;quot;) as leaving/being kicked of the game (outside of the scope of the rules) is not the same as being eliminated from the game (according to the rules), except if in the course of the game, the zombie player is eliminated according to the rules.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: When all surviving players are eliminated at the same time BGA framework causes the game to be abandoned automatically.&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;To circumvent this, the game should leave 1 player not eliminated but change final scores accordingly and end the game.&#039;&#039;&#039;&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;
; function isAsync()&lt;br /&gt;
: Returns true if game is turn based, false if it is realtime&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;
Note: if you deploy undo support after game is in production this will take into effect for new games only, old games will give user an error if user choses Undo action, but otherwise it should not affect them.&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 matters if you transition to game state not to user state after), this may affect what you end up saving.&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;
&#039;&#039;&#039;Important note&#039;&#039;&#039;: if you are reading game state variable right after restore (without changing state first) it won&#039;t work properly as the global table cache is not automatically refreshed after undoRestorePoint(). So you should either change state immediately to refresh game state values, or use $this-&amp;gt;gamestate-&amp;gt;reloadState() to refresh the state. If you choose to do the latest, be aware that this will bring the state machine back to the state during which the save point snapshot has been taken using undoSavepoint() (which means your transition you do after has to declared in the state which was saved, not in the state which was active for your actionUndo())&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 they are not allowed to do.&lt;br /&gt;
: The error message will be shown to the player as a &amp;quot;red message&amp;quot;.&lt;br /&gt;
: The error message must be translated, make sure you use self::_() or $this-&amp;gt;_() here and NOT clientranslate()&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;
&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 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 check the code of &amp;quot;setupNewGame&amp;quot;. New template already have correct code, but if you editing very old game and it may be absent.&lt;br /&gt;
&lt;br /&gt;
        $gameinfos = $this-&amp;gt;getGameinfos();&lt;br /&gt;
        ...&lt;br /&gt;
        if ($gameinfos[&#039;favorite_colors_support&#039;])&lt;br /&gt;
            $this-&amp;gt;reattributeColorsBasedOnPreferences($players, $gameinfos[&#039;player_colors&#039;]); // this should be above reloadPlayersBasicInfos()&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;
Some important remarks:&lt;br /&gt;
* for some games (i.e. Chess), the color has an influence on a mechanism of the game, most of the time by giving a special advantage to a player (i.e. 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 (Note - you don&#039;t have to pick these, the &amp;quot;closest&amp;quot; color will be found):&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( $my_data );&lt;br /&gt;
  }&lt;br /&gt;
  catch( feException $e ) // feException is a base class of BgaSystemException and others...&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;
The keys may only contain letters and numbers, underscore seems not to be allowed.&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;
: NOTICE: You can store some persistant data across all tables from your game using the specific player_id 0 which is unused. In such case, it&#039;s even more important to manage correctly the size of your data to avoid any exception or issue while storing updated data (ie. you can use this for some kind of leaderbord for solo game or contest)&lt;br /&gt;
: Note: This function cannot be called during game setup (will throw an error).&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 and does not use a key&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;
== Players text input and moderation ==&lt;br /&gt;
This section concerns only games where the players have to write some words to play: games based on words, like &amp;quot;Just one&amp;quot; or &amp;quot;Codenames&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Some players will use your game to write insults or profanities. As this is part of the game and not in the game chat, these words cannot be reported by players and moderated.&lt;br /&gt;
&lt;br /&gt;
If you met the following situation:&lt;br /&gt;
&lt;br /&gt;
* You are asking a player to type a text (word(s) or sentence)&lt;br /&gt;
* The player can enter any text (this is not a pre-selection or anything you can control)&lt;br /&gt;
* This text is visible by at least one other player&lt;br /&gt;
&lt;br /&gt;
Then, you must use the following method:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;function logTextForModeration( $player_id, $text )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
player_id = player who write the text&lt;br /&gt;
&lt;br /&gt;
text = text that has been written&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This function will have no visible consequence for your game, but will allow players to report the text to moderators if something happens.&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 they speak.&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_dependency&#039; =&amp;gt; false,  //or if the property is missing, the game is not language dependent&lt;br /&gt;
  &#039;language_dependency&#039; =&amp;gt; true, //all players at the table must speak the same language&lt;br /&gt;
  &#039;language_dependency&#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;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_metadata_manager&amp;diff=16775</id>
		<title>Game metadata manager</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_metadata_manager&amp;diff=16775"/>
		<updated>2023-04-27T10:35:17Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: max image size&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[File:Game_Metadata_Manager_Icon.png|left|100px|link=|Game Metadata Manager Icon]]&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;i&amp;gt;Game Metadata Manager&amp;lt;/i&amp;gt; is the portal for managing tags and media for your games. This page exists both on Production and Studio:&lt;br /&gt;
&lt;br /&gt;
* [https://boardgamearena.com/controlpanelgames Game Metadata Manager (production)] - manage game tags and media once the game has reached private alpha and beyond&lt;br /&gt;
* [https://studio.boardgamearena.com/controlpanelgames Game Metadata Manager (studio)] - manage game tags and media before the game reaches private alpha&lt;br /&gt;
&lt;br /&gt;
Note: once your game is in private alpha, and you are using the production Game Metagata Manager, the metadata on studio is &amp;lt;i&amp;gt;never&amp;lt;/i&amp;gt; automatically updated. On the studio game page, there is a button to pull metadata from production if you need to: &amp;quot;Sync metadata from production&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Media ==&lt;br /&gt;
&lt;br /&gt;
Game media consists of all the images which are used to represent your game on Board Game Arena, outside of the art of the actual game.&lt;br /&gt;
&lt;br /&gt;
Whilst working on your game on the studio initially, you can manage media from the studio: [https://studio.boardgamearena.com/controlpanelgames Game Metadata Manager (studio)].&lt;br /&gt;
&lt;br /&gt;
Once your game first hits private alpha, the media is copied over to the production site, and from this point on, all media changes must be effectuated over there: [https://boardgamearena.com/controlpanelgames Game Metadata Manager (production)].&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;margin:auto&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Name !! Example !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Box || [[File:Carcassonne_Box.png|frameless|Box]] ||&lt;br /&gt;
* &#039;&#039;&#039;Required for public alpha&#039;&#039;&#039;&lt;br /&gt;
* PNG&lt;br /&gt;
* It is displayed on the main site on the game description page and when creating a table (280x280 px).&lt;br /&gt;
* It should be a 3D image of a physical copy of the game box as it appears in an online shop.&lt;br /&gt;
* It is better to take the version of the game that is coherent with the game art used in the adaptation, and from the original publisher of the game.&lt;br /&gt;
* The background of the image must be transparent.&lt;br /&gt;
* If you don&#039;t have a 3D version of the game box, you can use the following website to create one: http://www.3d-pack.com/&lt;br /&gt;
* On Studio, you can only have one box image. Once deployed you can have a different box image for each language. This allows a localised image if you wish. If you don&#039;t provide a localised image, users will see the en box as a fallback.&lt;br /&gt;
|-&lt;br /&gt;
| Icon || [[File:Carcassonne_Icon.png|frameless|Icon]] ||&lt;br /&gt;
* &#039;&#039;&#039;Required for public alpha&#039;&#039;&#039;&lt;br /&gt;
* PNG&lt;br /&gt;
* It is the icon displayed in the lists of games and tables (50x50 px).&lt;br /&gt;
* The objective of this icon is to make the game recognizable among the other games. A good idea is to take a part of the game cover that is distinctive (ex: the game title).&lt;br /&gt;
* This one  does not have to be transparent. This image should not have a border &lt;br /&gt;
|-&lt;br /&gt;
| Title || [[File:Carcassonne_Title.png|frameless|Title]] ||&lt;br /&gt;
* &#039;&#039;&#039;Required for beta&#039;&#039;&#039;&lt;br /&gt;
* PNG&lt;br /&gt;
* max 2MB&lt;br /&gt;
* This is an image displayed instead of the name of the game as text&lt;br /&gt;
* Must be 2000x2000px&lt;br /&gt;
* Must look good when overlayed on top of the game box, and must be transparent&lt;br /&gt;
* On Studio, you can only have one title image. Once deployed you can have a different title image for each language. This allows a localised image if you wish (for example, &amp;quot;Stone Age&amp;quot; vs &amp;quot;L&#039;Âge de Pierre&amp;quot;). If you don&#039;t provide a localised image, users will see the en title as a fallback. In this case, if the localised name differs from en, there will also be a subtitle showing the game&#039;s name in the user&#039;s locale.&lt;br /&gt;
&lt;br /&gt;
For guidelines on the positioning of elements of the title, see: [[Media:Title_guidelines.png]].&lt;br /&gt;
|-&lt;br /&gt;
| Publisher || - ||&lt;br /&gt;
* &#039;&#039;&#039;Optional&#039;&#039;&#039; (if there is no publisher)&lt;br /&gt;
* PNG&lt;br /&gt;
* max 2MB&lt;br /&gt;
* It is the logo of the publisher of the game, displayed on the game description page.&lt;br /&gt;
* Must be 280x280px&lt;br /&gt;
* The image can be transparent.&lt;br /&gt;
* You can have up to 2 publisher images&lt;br /&gt;
|-&lt;br /&gt;
| Banner || [[File:Carcassonne_Banner.jpg|frameless|Title]] ||&lt;br /&gt;
* &#039;&#039;&#039;Required for beta&#039;&#039;&#039;&lt;br /&gt;
* JPG&lt;br /&gt;
* max 2MB&lt;br /&gt;
* size 1386x400px&lt;br /&gt;
* should not contain any text; representative of the atmosphere of the game such as a cover element or communication image; the box image covering the banner on the left should stand out&lt;br /&gt;
|-&lt;br /&gt;
| Display || - ||&lt;br /&gt;
* &#039;&#039;&#039;Required for release&#039;&#039;&#039;&lt;br /&gt;
* JPG&lt;br /&gt;
* height between 400px and 760px, width maximum 1.5 x height;&lt;br /&gt;
* These images are displayed in a carousel on the game page&lt;br /&gt;
* the idea is to make players want to play the game, so it could be a zoomed card, some detail of the board, an overview of an ongoing physical game... but NOT a screenshot of the BGA adaptation since there is already the &amp;quot;see game in action&amp;quot; replay for that&lt;br /&gt;
* You can have up to 10 display images&lt;br /&gt;
|-&lt;br /&gt;
| Major Variant || [[File:KoT Major Variant.png|frameless]]||&lt;br /&gt;
* &#039;&#039;&#039;Optional&#039;&#039;&#039;&lt;br /&gt;
* PNG&lt;br /&gt;
* size 280x280px&lt;br /&gt;
* Images used to accompany major options, see [[Game options and preferences: gameoptions.inc.php#option_level|Game options and preferences]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Tags ==&lt;br /&gt;
&lt;br /&gt;
Game tags should be managed through the Game Metadata Manager.&lt;br /&gt;
&lt;br /&gt;
Before the game is published to production, this is done on the studio [https://studio.boardgamearena.com/controlpanelgames Game Metadata Manager (studio)] .&lt;br /&gt;
&lt;br /&gt;
After release, the tags are copied over to the production site, and from this point on, all tag changes must be effectuated over there: [https://boardgamearena.com/controlpanelgames Game Metadata Manager (production)].&lt;br /&gt;
&lt;br /&gt;
== Migration ==&lt;br /&gt;
&lt;br /&gt;
Images used to be served from the[[Game art: img directory|/img]] folder of your game&#039;s repository. All of these files (those prefixed with &amp;lt;code&amp;gt;game_&amp;lt;/code&amp;gt;) are now deprecated and can be deleted from the folder. Any changes to these images will not be picked up.&lt;br /&gt;
&lt;br /&gt;
Tags used to be managed by changing the tags in [[Game meta-information: gameinfos.inc.php|gameinfos.inc.php]]. Any tags specified in this file are now ignored, and should not be specified. Tags must be edited using the [https://boardgamearena.com/controlpanelgames Game Metadata Manager].&lt;br /&gt;
&lt;br /&gt;
== Future ==&lt;br /&gt;
&lt;br /&gt;
The Game Metadata Manager will play an increasingly important role in managing a BGA implementation in the future.&lt;br /&gt;
&lt;br /&gt;
It is planned that:&lt;br /&gt;
* more metadata (such as publisher and designer names, or presentation text) be managed here&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=16386</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=16386"/>
		<updated>2023-03-24T14:37:32Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: added bigmonster and boilerplate&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: 4 sided &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/JjZNezr&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;
! colspan=&amp;quot;3&amp;quot; | Alternative implementations of BGA modules&lt;br /&gt;
|-&lt;br /&gt;
|Scrollmap with zoom&lt;br /&gt;
|https://github.com/yansnow78/bga_scrollmap&lt;br /&gt;
|you can find it in cacao an implementation in cacao (currently only changed in studio) . &amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt; improvements compare to scrollmap:&lt;br /&gt;
- add zoom capabilities &lt;br /&gt;
&lt;br /&gt;
- add possibility to adjust pan delta to tile size when clicking on arrows&lt;br /&gt;
&lt;br /&gt;
- allow zoom with scroll wheel. only allow zoom with wheel if alt or ctrl or shift are pressed by default.  add possibility to select which key need to be pressed when zooming with wheel&lt;br /&gt;
&lt;br /&gt;
- allow pan/scroll and pinch zoom on smartphone. only allow 2 fingers to start scrolling by default, one finger is for page scrolling&lt;br /&gt;
&lt;br /&gt;
- make clickable area of buttons a bit bigger on smartphone&lt;br /&gt;
&lt;br /&gt;
- improve animation between game board and player bards thanks to an animation_div&lt;br /&gt;
&lt;br /&gt;
- add support to long click on buttons (continuous scroll or zoom or enlarge/reduce until button released)&lt;br /&gt;
|-&lt;br /&gt;
|Scrollmap Plus &lt;br /&gt;
|patchwork&lt;br /&gt;
|Implementation with some bugs fixed, improved drag support and ability to use only one direction (i.e. only horizontal like carousel). Found in modules/extscrollmap.js&lt;br /&gt;
|-&lt;br /&gt;
|Zoom&lt;br /&gt;
|[https://github.com/thoun/bga-zoom/ Repo]&amp;lt;nowiki&amp;gt; | &amp;lt;/nowiki&amp;gt;[https://thoun.github.io/bga-zoom/demo/index.html Demo] (visible on Azul, Abyss, ...)&lt;br /&gt;
|Allow the user to zoom on the game board. Include the controls to zoom, and handle the scale applied to the HTML element.&lt;br /&gt;
|-&lt;br /&gt;
|Cards&lt;br /&gt;
|[https://github.com/thoun/bga-cards/ Repo]&amp;lt;nowiki&amp;gt; | &amp;lt;/nowiki&amp;gt;[https://thoun.github.io/bga-cards/demo/index.html Demo] (visible on King of Tokyo, Abyss, ...)&lt;br /&gt;
|Alternative to BGA Stock component, using CSS transitions instead of dojo animations.&lt;br /&gt;
|-&lt;br /&gt;
|Dice&lt;br /&gt;
|The next project&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Projects ==&lt;br /&gt;
&lt;br /&gt;
Add the game name, a link to repository 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] topic 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;
|BGA-boilerplate&lt;br /&gt;
|https://github.com/bga-devs/tisaac-boilerplate/&lt;br /&gt;
|Tisaac (and Vincentt ?)&lt;br /&gt;
|Main boilerplate with extended &amp;quot;basic&amp;quot; function and code structure&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;
| Abandon All Artichokes&lt;br /&gt;
| https://github.com/0-wiz-0/bga-abandonallartichokes&lt;br /&gt;
| __wiz__, rojomojo&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;
|Big Monster&lt;br /&gt;
|https://github.com/nmatton/bigmonster&lt;br /&gt;
|nicotacotac&lt;br /&gt;
|-&lt;br /&gt;
| Canosa&lt;br /&gt;
| https://github.com/HalibutGitWiz/Canosa&lt;br /&gt;
| junibegood&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;
|Copenhagen&lt;br /&gt;
|https://github.com/JoeProgram/bga-copenhagen&lt;br /&gt;
|JoeProgram&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;
| Dice Summoners&lt;br /&gt;
| https://github.com/eoincos/bga-dicesummoners&lt;br /&gt;
| eoincos&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;
| For-Ex&lt;br /&gt;
| https://github.com/Fnordistan/forex&lt;br /&gt;
| AmadanNaBriona&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;
| Hardback&lt;br /&gt;
| https://github.com/quietmint/bga-hardback&lt;br /&gt;
| quietmint&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;
| 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;
| 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;
| The Lady and the Tiger (Doors)&lt;br /&gt;
| https://github.com/Fnordistan/ladyandthetiger&lt;br /&gt;
| AmadanNaBriona&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;
| Perikles&lt;br /&gt;
| https://github.com/Fnordistan/perikles&lt;br /&gt;
| AmadanNaBriona&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;
| President&lt;br /&gt;
| https://github.com/quaresma95/president&lt;br /&gt;
| quaresma95&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;
| Trick of the Rails&lt;br /&gt;
| https://github.com/Fnordistan/trickoftherails&lt;br /&gt;
| AmadanNaBriona&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;
|}&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;
&lt;br /&gt;
If it is not visible: a) it has no bgg id b) it is already published (use radio button to switch) c) it is an old game not developed on studio.&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>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Zone&amp;diff=14400</id>
		<title>Zone</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Zone&amp;diff=14400"/>
		<updated>2022-08-19T13:51:25Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Patterns: positioning items within your zone */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
The Zone component is meant to organise items of the same type inside a predefined space.&lt;br /&gt;
&lt;br /&gt;
== Zone in action ==&lt;br /&gt;
&lt;br /&gt;
If you want to see how Zone works, please try &amp;quot;Can&#039;t Stop&amp;quot; or &amp;quot;Niagara&amp;quot; on BGA, or watch a game in progress or game replay.&lt;br /&gt;
&lt;br /&gt;
In Can&#039;t Stop, zone is used to display the bhikkus ascending the mountain when there is more than one on the same space (diagonal mode).&lt;br /&gt;
&lt;br /&gt;
In Niagara, it is used to display the canoes over the circles going down the river (custom mode).&lt;br /&gt;
&lt;br /&gt;
== How to use Zone == &lt;br /&gt;
&lt;br /&gt;
At first, don&#039;t forget to add &amp;quot;ebg/zone&amp;quot; as a dependency:&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/zone&amp;quot;     /// &amp;lt;==== HERE&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, declare a new variable in your class for the Zone object:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        constructor: function(){&lt;br /&gt;
        console.log(&#039;yourgame constructor&#039;);&lt;br /&gt;
              &lt;br /&gt;
        // Zone control        	&lt;br /&gt;
        this.myZone = new ebg.zone();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, in your template file, you must add a div that will host this zone:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;my_zone&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And set its width (and optionally, height and position) in CSS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#my_zone {&lt;br /&gt;
  width: 100px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then in your Javascript setup, attach your Zone component to the div and define its properties :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            zone.create( this, &#039;my_zone&#039;, &amp;lt;item_width&amp;gt;, &amp;lt;item_height&amp;gt; );&lt;br /&gt;
            zone.setPattern( &amp;lt;mode&amp;gt; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;item_width&amp;gt; is an integer for the width of the objects you want to organise in the zone&lt;br /&gt;
* &amp;lt;item_height&amp;gt; is an integer for the height of the objects you want to organise in the zone &lt;br /&gt;
* &amp;lt;mode&amp;gt; is one of &#039;grid&#039; (objects will be put on lines from top left to bottom right, wrapping when there is not enough space left on the line, relatively to the width you have defined) &#039;diagonal&#039; (objects will be organised on a top left to bottom right diagonal, overlapping each other) or &#039;custom&#039; (objects will be organised depending upon their number and the coordinates that you provide - see below)&lt;br /&gt;
&lt;br /&gt;
Since the width of the Zone is defined statically, beware of not letting items overflow on small screens. If you need a design-responsive component, consider using the Stock component instead.&lt;br /&gt;
&lt;br /&gt;
Now your zone is ready to be used!&lt;br /&gt;
&lt;br /&gt;
After creating an object that you want to add to the zone as a classic HTML template (dojo.place / this.format_block), you can simply use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   zone.placeInZone( &amp;lt;object_id&amp;gt;, &amp;lt;weight&amp;gt; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;object_id&amp;gt; is the string identifier for your object &#039;my_object_id&#039;&lt;br /&gt;
* &amp;lt;weight&amp;gt; is an optional parameter used to sort items&lt;br /&gt;
&lt;br /&gt;
To remove an item, use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   zone.removeFromZone( &amp;lt;object_id&amp;gt;, &amp;lt;destroy?&amp;gt;, &amp;lt;to&amp;gt; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;object_id&amp;gt; is the string identifier for your object &#039;my_object_id&#039;&lt;br /&gt;
* &amp;lt;destroy?&amp;gt; is a boolean indicating if the object should be destroyed after being removed&lt;br /&gt;
* &amp;lt;to&amp;gt; is the destination the object must be slided to when being removed (before being eventually destroyed)&lt;br /&gt;
&lt;br /&gt;
You can also:&lt;br /&gt;
* remove all items from the zone (and destroy them) using zone.removeAll();&lt;br /&gt;
* get the number of items in your zone using zone.getItemNumber();&lt;br /&gt;
* get an array of the ids of all the items using zone.getAllItems();&lt;br /&gt;
&lt;br /&gt;
== Patterns: positioning items within your zone ==&lt;br /&gt;
&lt;br /&gt;
full source is available here : https://x.boardgamearena.net/data/themereleases/220811-1000/js/modules/zone.js&lt;br /&gt;
&lt;br /&gt;
The zone package comes with many positioning patterns pre-coded; these allow your items to take on a variety of arrangements. To set a pattern for your zone, call the following method on your zone object (once the zone has already been created, of course):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  zone.setPattern(&#039;pattern_name&#039;)  // ...where &#039;pattern_name&#039; is actually one of the many pre-formatted patterns of the package&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The patterns that are currently available as part of the ebg/zone package are: &lt;br /&gt;
* &#039;grid&#039; (which is the default, if you never actually call setPattern)&lt;br /&gt;
* &#039;diagonal&#039;&lt;br /&gt;
* &#039;verticalfit&#039;&lt;br /&gt;
* &#039;horizontalfit&#039;&lt;br /&gt;
* &#039;ellipticalfit&#039;&lt;br /&gt;
* &#039;custom&#039;&lt;br /&gt;
&lt;br /&gt;
=== grid ===&lt;br /&gt;
&lt;br /&gt;
This is the default pattern for all zones when they are created. With enough horizontal space to fit all items in the zone, this pattern will simply arrange the items in a single horizontal row (as in the first zone in the image below). &lt;br /&gt;
&lt;br /&gt;
However, if the zone is not allotted enough horizontal space to display all zone items in a single horizontal row, then the items will wrap to the next line as in the second zone in the image below). In the example image, restricting the zone width was done via:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;dojo.style(&#039;grid_zone_2&#039;, &#039;max-width&#039;, &#039;175px&#039;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Zone_grid.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== diagonal ===&lt;br /&gt;
&lt;br /&gt;
This pattern is great for creating the illusion of stacks (e.g., decks, counters, etc), because it will place each successive item in the zone a certain number of pixels below, and that same number of pixels to the right of the previous item in the zone. The exact number of pixels that are used for these offsets are controlled by the zone object attribute &#039;item_margin&#039; (which defaults to 5, as in the first zone in the image below). The behavior of this pattern does not appear to be affected by whether or not the zone is allotted enough horizontal or vertical space to display all items, as is demonstrated in the second zone of the image below, which was allotted less vertical and horizontal space (49px by 49px) than is required for displaying just one of the components (50px by 50px).&lt;br /&gt;
&lt;br /&gt;
Reducing the zone&#039;s item_margin will make each item in the zone be closer together, making it appear as if each item in the stack is thinner (as in the third zone in the image below), and increasing this value will make the items in your stack be further apart, giving an illusion of thicker components (as in the fourth zone in the image below). Here&#039;s how to alter item_margin for your zone:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// For the third diagonal example:&lt;br /&gt;
this.zone.diagonal_zone_3.item_margin = 2;&lt;br /&gt;
&lt;br /&gt;
// For the fourth diagonal example (with enough margin to fully display each component):&lt;br /&gt;
this.zone.diagonal_zone_4.item_margin = 36;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Zone_diagonal.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== verticalfit ===&lt;br /&gt;
&lt;br /&gt;
This pattern is useful if you want all items in your zone to be arranged in a single column, regardless of whether there is enough space to display each item fully. In the first zone in the image below, no min-height or max-height was set for the zone (thus, the zone has the max-height of its first component), so all items were stacked upward on top of the original component, with item_margin (5px by default) vertical distance between each component, similar to how it was done for the diagonal pattern zones.  &lt;br /&gt;
&lt;br /&gt;
If the zone is explicitly allotted more space than is required to display one component, but less than is required to show all fully (usually, this value is the sum of the component&#039;s heights, unless you are using sprites with strange transparency portions), then the items will overlap each other just enough to allow all of the items to fit into a single column of the allotted height (as in the second zone in the image below). However, with enough vertical space to fit all items fully in the zone, this pattern will simply arrange the items in a single vertical column (as in the third zone of the image below). Here is how the vertical distances were set for those two examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// For the second verticalfit example, with overlap:&lt;br /&gt;
dojo.style(&#039;verticalfit_zone_2&#039;, &#039;max-height&#039;, &#039;100px&#039;);&lt;br /&gt;
&lt;br /&gt;
// For the third verticalfit example, with just enough space to display all components:&lt;br /&gt;
// (component height = 50px, multiplied by 5 components = 250px)&lt;br /&gt;
dojo.style(&#039;verticalfit_zone_3&#039;, &#039;min-height&#039;, &#039;250px&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Zone_verticalfit_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
If the amount of vertical space for the zone is greater than what is required by the items and the margins between them, then the column of items will be centered within the &#039;min-height&#039; of their container element (as in the image below, which has min-height set to 450px).&lt;br /&gt;
&lt;br /&gt;
[[File:Zone_verticalfit_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== horizontalfit ===&lt;br /&gt;
&lt;br /&gt;
This pattern is useful if you want all items in your zone to be arranged in a single row, regardless of whether there is enough space to display each item fully. If the width of this type of zone is not explicitly set, then it will be assumed to be then same as its parent element (which could lead to the items being centered within another one of your divs, as in the first zone of the image below). &lt;br /&gt;
&lt;br /&gt;
If the zone&#039;s width is explicitly set, but it is not allotted enough horizontal space to fully display each zone item in a single row, then the items will overlap each other just enough to allow all items to fit into a single row of the allotted width (as in the second zone of the image below). However, with enough horizontal space to fit all items fully in the zone, this pattern will simply arrange the items in a single horizontal row (as in the third zone of the image below; nearly identically to the &#039;grid&#039; pattern with enough horizontal space, although without margins between items by default). Here&#039;s how the zone&#039;s width can be set:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// For the second horizontalfit example:&lt;br /&gt;
dojo.style(&#039;horizontalfit_zone_2&#039;, &#039;max-width&#039;, &#039;100px&#039;);&lt;br /&gt;
&lt;br /&gt;
// For the third horizontalfit example:&lt;br /&gt;
dojo.style(&#039;horizontalfit_zone_3&#039;, &#039;min-width&#039;, &#039;250px&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And, just as in the example for the default of this pattern, if the allotted horizontal space for the zone is greater than what is required by the items, then the row of items will be centered within the &#039;min-width&#039; of the zone (as shown in the fourth zone of the image below, which has a max-width of 450px).&lt;br /&gt;
&lt;br /&gt;
[[File:Zone_horizontalfit.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== ellipticalfit ===&lt;br /&gt;
&lt;br /&gt;
This pattern will arrange all items in the zone in a circular (or elliptical) arrangement, with equal radial distance between each item. With enough vertical and horizontal space to fit all items in the zone into a single non-overlapping circle, this pattern will do just that. &lt;br /&gt;
&lt;br /&gt;
[[File:Zone_ellipticalfit_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
However, if the zone is not allotted enough vertical and horizontal space to fully display each zone item in a single circle, then the items that do not fit into the original circle will begin to form an additional concentric circle around the original circle.&lt;br /&gt;
&lt;br /&gt;
[[File:Zone_ellipticalfit_2.jpg]]&lt;br /&gt;
&lt;br /&gt;
In this second circle, items *will* overlap if there is not enough space for them all to be fully displayed.&lt;br /&gt;
&lt;br /&gt;
[[File:Zone_ellipticalfit_3.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== custom ===&lt;br /&gt;
&lt;br /&gt;
If you want complete control on how your objects are laid out inside the Zone, you can determine their coordinates after their number when being added to the zone. &lt;br /&gt;
&lt;br /&gt;
[[File:Zone_custom.jpg]]&lt;br /&gt;
&lt;br /&gt;
Here is how to do it, when defining your Zone properties in the javascript setup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                this.zone.setPattern( &#039;custom&#039; );&lt;br /&gt;
                &lt;br /&gt;
                this.zone.itemIdToCoords = function( i, control_width ) {&lt;br /&gt;
                    if( i%8==0 )&lt;br /&gt;
                    {   return {  x:1,y:19, w:60, h:30 }; }&lt;br /&gt;
                    else if( i%8==1 )&lt;br /&gt;
                    {   return {  x:30,y:38, w:60, h:30 }; }&lt;br /&gt;
                    else if( i%8==2 )&lt;br /&gt;
                    {   return {  x:42,y:8, w:60, h:30 }; }&lt;br /&gt;
                    else if( i%8==3 )&lt;br /&gt;
                    {   return {  x:5,y:58, w:60, h:30 }; }&lt;br /&gt;
                    else if( i%8==4 )&lt;br /&gt;
                    {   return {  x:5,y:24, w:60, h:30 }; }&lt;br /&gt;
                    else if( i%8==5 )&lt;br /&gt;
                    {   return {  x:35,y:43, w:60, h:30 }; }&lt;br /&gt;
                    else if( i%8==6 )&lt;br /&gt;
                    {   return {  x:47,y:13, w:60, h:30 }; }&lt;br /&gt;
                    else if( i%8==7 )&lt;br /&gt;
                    {   return {  x:10,y:63, w:60, h:30 }; }&lt;br /&gt;
                };&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Stock&amp;diff=14399</id>
		<title>Stock</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Stock&amp;diff=14399"/>
		<updated>2022-08-19T13:37:56Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Complete stock component reference */&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;
for interest, the source is available here : https://x.boardgamearena.net/data/themereleases/220811-1000/js/modules/stock.js&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>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=13914</id>
		<title>Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=13914"/>
		<updated>2022-07-08T10:15:44Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Other errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Describing common errors which is hard to understand and debug &lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game does not start at all ==&lt;br /&gt;
&lt;br /&gt;
=== Undefined offset: 0 in table/table.game.php on line 1417 ===&lt;br /&gt;
&lt;br /&gt;
Do not call self::getActivePlayerName() during setupNewGame()&lt;br /&gt;
&lt;br /&gt;
Ensure you&#039;re calling $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer() at the end of your game setup. You must always have at least one active player.&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload n is null ===&lt;br /&gt;
&lt;br /&gt;
When calling dojo.place(), the name of the container (second parameter) to place the new block into is not defined in the page template.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: createGame): ... ===&lt;br /&gt;
&lt;br /&gt;
This is generic message usually followed by exact position in your source code, and usually its syntax error in one of yours php script&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Not logged ===&lt;br /&gt;
&lt;br /&gt;
Calling self::getCurrentPlayerId () or using $g_user from &#039;args&#039; state function, see also below&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Unknow player statistic: ===&lt;br /&gt;
&lt;br /&gt;
Calling self::incStat() with second parameter which is an empty string&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats ... ===&lt;br /&gt;
&lt;br /&gt;
Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats (stats_type, stats_player_id, stats_value) VALUES (&#039;10&#039;,&#039;2300663&#039;,&#039;0&#039;),(&#039;10&#039;,&#039;2300662&#039;,&#039;0&#039;)&lt;br /&gt;
Duplicate entry &#039;10-2300663&#039; for key &#039;stats_table_id&#039;&lt;br /&gt;
&lt;br /&gt;
Why? In the stats.inc.php you declared two keys with the same integer &amp;quot;id&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: BGA main website do not respond ===&lt;br /&gt;
&lt;br /&gt;
Check if other games work; if not, it&#039;s a problem with BGA Studio; if so, your game likely reaches an end state immediately. Check your states.inc.php and your transitions.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): BGA service error ===&lt;br /&gt;
&lt;br /&gt;
You may have a syntax error in your dbmodel.sql.&lt;br /&gt;
&lt;br /&gt;
Or, you may be calling self::initStat() for a statistic that does not exist. Check the statistic name, and make sure you clicked &amp;quot;Reload statistics configuration&amp;quot; button in the admin console after making changes to stats.inc.php&lt;br /&gt;
&lt;br /&gt;
Or you may not have your states.inc.php set up correctly.&lt;br /&gt;
&lt;br /&gt;
You may have an error in your table.game.php file in setupNewGame (such as &amp;lt;code&amp;gt;$result[&#039;x&#039;] = y;&amp;lt;/code&amp;gt; when $result is not an array).&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Table status of a starting game should be &#039;setup&#039; ===&lt;br /&gt;
&lt;br /&gt;
This error message appears when you start a one player game using the &amp;quot;Express Start&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
In normal situation, the game starts just after this message and everything should works normally. In this case, you can just ignore this message.&lt;br /&gt;
&lt;br /&gt;
If the games does not start, it is most probable that there is a syntax error in any of your php code (Check your states.inc.php and X.game.php)&lt;br /&gt;
&lt;br /&gt;
=== Fatal error during creation of database ebd_quoridor_389 Not logged ===&lt;br /&gt;
&lt;br /&gt;
Check that you didn&#039;t use $g_user or getCurrentPlayerId() in setupNewGame() function or in an &#039;args&#039; function of your state.&lt;br /&gt;
&lt;br /&gt;
As these functions are not consequences of a user action, there is no current player defined.&lt;br /&gt;
&lt;br /&gt;
As a general rule, you should use getActivePlayerId() and not getCurrentPlayerId(). See the [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine presentation on the game state machine] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Warning: Invalid argument supplied for foreach() in table.game.php ===&lt;br /&gt;
&lt;br /&gt;
   Warning: Invalid argument supplied for foreach() in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 129 &lt;br /&gt;
   Fatal error: Cannot unset string offsets in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 143&lt;br /&gt;
&lt;br /&gt;
That appears when your arg* function that suppose to return array of state arguments returns a scalar (a non-array) value&lt;br /&gt;
&lt;br /&gt;
=== The server reported an error ===&lt;br /&gt;
&lt;br /&gt;
During table creation: &amp;quot;The server reported an error&amp;quot; error shown and nothing else.&lt;br /&gt;
&lt;br /&gt;
If you cannot even create a table - there is syntax error in gameinfos.php, check it, reload it from management panel.&lt;br /&gt;
If still no luck copy clean version from template https://github.com/elaskavaia/bga-sharedcode/blob/master/gameinfos.inc.php&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Error : Invalid player number for this game : 4 ===&lt;br /&gt;
&lt;br /&gt;
This error may comes when trying to change the player number configuration in gameinfos.inc.php from a higher to lower number of players (for example from 4 to 2).&lt;br /&gt;
&lt;br /&gt;
The following steps will help to change a player config from array(4) to array(2) :&lt;br /&gt;
&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2,3,4 )&lt;br /&gt;
* In game management page (Control Panel &amp;gt; Manage Games &amp;gt; &amp;quot;Your Game&amp;quot;), press the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
* create a new table&lt;br /&gt;
* reduce the number of players to 2 and start the game&lt;br /&gt;
* (express) Stop the game&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2 )&lt;br /&gt;
* press again the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
&lt;br /&gt;
=== Blank page ===&lt;br /&gt;
If you see no html at all check &lt;br /&gt;
* if you have syntax error in your view.php file &lt;br /&gt;
* class name of your view.php file  does not match the project name (should be view_foo_foo if project is foo)&lt;br /&gt;
* game name return by getGameName() does not match the project name  (should be &amp;quot;foo&amp;quot; if project is foo)&lt;br /&gt;
&lt;br /&gt;
    class view_russianrailroads_russianrailroads extends game_view {&lt;br /&gt;
    function getGameName() {&lt;br /&gt;
        return &amp;quot;russianrailroads&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Game starts but I can&#039;t make a move ==&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I got &amp;quot;Move recorded, waiting for update ...&amp;quot; forever ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Move recorded&amp;quot; means that your ajaxcall request has been sent to the server and returned normally.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Waiting for update&amp;quot; means that your client interface is waiting for some notifications from the server that correspond to the move we just did.&lt;br /&gt;
&lt;br /&gt;
If this message stays forever, it is probably that your PHP code does not send any notification when the move happens, which is abnormal. To fix this: add a notifyAllPlayers or a notifyPlayer call in your PHP code.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Sending move to server...&amp;quot; then nothing and game resets to state before the move ===&lt;br /&gt;
&lt;br /&gt;
Its possible that server code get into infinite loops or thinks too much, in which case it will timeout and will be aborted without any extra logs (and db transaction you saw in the log won&#039;t be committed). You will usually see &amp;quot;Unable to connect to server&amp;quot; message on console in this case. You have to put more logging into server&lt;br /&gt;
to trace where it hangs.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Ajaxcall error: empty answer&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You either have missing self::ajaxResponse(); in your [[Players actions: yourgamename.action.php|game.action.php]] method, or there is some problem with getting arguments (check that you are using btoa() on client when using AT_base64 arg type in action.php)&lt;br /&gt;
&lt;br /&gt;
=== Some player action is triggered randomly when I click somewhere on the game area ===&lt;br /&gt;
&lt;br /&gt;
You probably used &amp;quot;dojo.connect&amp;quot; on a null object. In this case, dojo.connect associate the event (ex: &amp;quot;onclick&amp;quot;) to the whole game area.&lt;br /&gt;
&lt;br /&gt;
Most of the time it happens in this situation, when my_object element does not exists:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   dojo.connect( $(&amp;quot;my_object&amp;quot;), &amp;quot;onclick&amp;quot;, this, (event)=&amp;gt;{})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To determine if this is the case, place &amp;quot;alert( $(&amp;quot;my_object&amp;quot;) )&amp;quot; before the dojo.connect to check if the object exists or not.&lt;br /&gt;
&lt;br /&gt;
=== Error: This is not your turn ===&lt;br /&gt;
&lt;br /&gt;
This happens when checkAction() is called and current player is NOT the active player.&lt;br /&gt;
&lt;br /&gt;
You can change the active player in studio by clicking the red arrow next to their name in the player panel (right side of the page).&lt;br /&gt;
&lt;br /&gt;
[[File:Change_active_player.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Error: Please wait, an action is already in progress ===&lt;br /&gt;
Its followed by error &amp;quot;(Generated by checkAction / XXX)&amp;quot; on studio.&lt;br /&gt;
&lt;br /&gt;
This error is triggered in the JS by the checkAction function for XXX action.&lt;br /&gt;
&lt;br /&gt;
This can happen when the player sent an Ajax request action earlier, and:&lt;br /&gt;
* action is not complete yet - i.e. takes some time, and user clicked something again &lt;br /&gt;
* if there is bug in interface where MULTIPLE handlers are fired on same click. To debug this add some console.trace() in place this specific checkAction is called.&lt;br /&gt;
* did not get any notification from the PHP side. To avoid this, put an empty notifyPlayer in the PHP side of the Ajax handler to ensure the client receives a response. This line of code should do it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyPlayer($this-&amp;gt;getCurrentPlayerId(), &#039;message&#039;, &#039;&#039;, []); // sent to current player, who originated the action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error: This move is not authorized now ===&lt;br /&gt;
This is generic error message generated by this.showMoveUnauthorized() function. If you did not call this function yourself, check the console log, it may have additional information.&lt;br /&gt;
If you see &amp;quot;Move not authorized now : XXX&amp;quot; in the log, where XXX is your action name - this means that action XXX is not defined in list of possible actions for your current state. This error generated by checkAction() function.&lt;br /&gt;
&lt;br /&gt;
=== Error: You are not connected - after waiting for the submitted move ===&lt;br /&gt;
In the log you may find: &lt;br /&gt;
  Query execution was interrupted, maximum statement execution time exceeded - Request: SELECT global_id, global_value FROM global WHERE 1&lt;br /&gt;
&lt;br /&gt;
The error message above is because of failed attempt to lock a table, which happens because of infinite loop in you game.&lt;br /&gt;
* Check that don&#039;t enter same game state over and over again&lt;br /&gt;
* Check that you reverse for loop actually descrease counter or other loop issues&lt;br /&gt;
* Check that recursive function ends&lt;br /&gt;
&lt;br /&gt;
== Predefined server errors ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Unexpected final game state (XX) ===&lt;br /&gt;
&lt;br /&gt;
The action function does not transition to any state, i.e.&lt;br /&gt;
  function selectField($field) {&lt;br /&gt;
    self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
    if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
  }&lt;br /&gt;
Here if $field is 0 there is no transition&lt;br /&gt;
&lt;br /&gt;
=== This game action is impossible right now ===&lt;br /&gt;
&lt;br /&gt;
Check the game log. Usually your state does not define the action you trying to perform in &#039;possibleactions&#039; array.&lt;br /&gt;
&lt;br /&gt;
Also check your onActionName javascript function. Make sure you are calling the right &amp;quot;actionname.html&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: This transition (playerTurn) is impossible at this state (42) ===&lt;br /&gt;
&lt;br /&gt;
This is pretty self explanatory. Function nextState() takes transition name not a state name, so you probably did not&lt;br /&gt;
define this transition that the given state&lt;br /&gt;
&lt;br /&gt;
== Game interface hangs during reload or on start ==&lt;br /&gt;
&lt;br /&gt;
Showing &amp;quot;Application Loading...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload undefined no_stack_avail Script: ===&lt;br /&gt;
&lt;br /&gt;
This error usually has no useful data, but it means you called somes API that require a callback and did not define callback function, i.e&lt;br /&gt;
in dojo.connect, this.connectClass, dojo.subscribe, etc&lt;br /&gt;
   &lt;br /&gt;
      this.connectClass(&#039;field&#039;, &#039;onclick&#039;, &#039;onField&#039;); // &amp;lt;-- onField is not defined&lt;br /&gt;
&lt;br /&gt;
=== Other errors with &amp;quot;Application loading...&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You probably have a syntax error in your Javascript code, and the interface refuses to load.&lt;br /&gt;
&lt;br /&gt;
To find this error, check if there is an error message in the Javascript console (F12).&lt;br /&gt;
&lt;br /&gt;
If there is really nothing on the log, it&#039;s probably that the system was unable to load your Javascript because of an syntax error that affect the structure of the Javascript file, typically a missing &amp;quot;}&amp;quot; or a missing &amp;quot;,&amp;quot; after a method definition.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;Uncaught ReferenceError: bgagame is not defined&amp;quot; you have major syntax error in your js file, you should see some other clues in the log where the errors is.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;dojo.publish is not defined&amp;quot; or something similar, this could be caused by another error earlier. For example, a syntax error caused by a malformed generated file (such as using newlines in tiebreaker description). Also you might have left some images in the /img directory with special characters in the name which must be removed. If you edited images for the game box and website, ensure that you have not left any unnecessary files there.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Syntax Error: ===&lt;br /&gt;
&lt;br /&gt;
No further details in the log. When log is filling with some social connect errors.&lt;br /&gt;
&lt;br /&gt;
Possible Reason: Syntax error in of the php script which is loaded before the start, such as gameoptions.inc.php, gameinfos.inc.php and such.&lt;br /&gt;
&lt;br /&gt;
=== Game interface spins in a loop throwing error ===&lt;br /&gt;
&lt;br /&gt;
Errors is something like &amp;quot;Cannot read property &#039;is_ai&#039; of undefined&amp;quot;. Cannot restart the game because cannot access UI to stop.&lt;br /&gt;
Likely you get in actplayer state with player id == 0. The only way to fix it is to edit database, globals index == 2 set player id to one of your test dudes&lt;br /&gt;
(can copy from row 5 for example).&lt;br /&gt;
&lt;br /&gt;
=== Unable to find table database (1): ebd_yourgame_112222 ===&lt;br /&gt;
&lt;br /&gt;
Its either temporarily server error especially on studio it timeouts sometimes, just try reloading again.&lt;br /&gt;
Or check if you have syntax errors in your php game file or sql.&lt;br /&gt;
&lt;br /&gt;
== Type conversion / juggling errors ==&lt;br /&gt;
&lt;br /&gt;
=== On php side I get a number instead of string I expect ===&lt;br /&gt;
&lt;br /&gt;
 $num = 3;&lt;br /&gt;
 $meeple = &amp;quot;meeple_&amp;quot; + $num; // &amp;lt;-- suppose to be &amp;quot;meeple_3&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
When you switch between JS and PHP it easy to type this and not notice the +. Plus sign (+) in php does not mean string concatenation (in javascript does!),&lt;br /&gt;
in php + means integer arithmetic. So change + to . (dot)&lt;br /&gt;
&lt;br /&gt;
=== On php side my string comparison does not work ===&lt;br /&gt;
&lt;br /&gt;
   if ($color == &#039;4baae2&#039; || $color == &#039;000000&#039;) { &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Apparently you should not be using &#039;==&#039; in php to compare strings! You should use &#039;===&#039;. The (==) operator will typecast the strings &lt;br /&gt;
to numbers then do comparison!&lt;br /&gt;
Its not very apparent because usually you can get away with it, but not when strings resemble numbers like hex &#039;colors&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Integer columns in the database are returned as strings ===&lt;br /&gt;
&lt;br /&gt;
This is normal PHP behavior. All fields are returned as string type, regardless of their actual type in the database. This also applies to global variables accessed via getGameStateValue(), since they are stored in a database table.&lt;br /&gt;
&lt;br /&gt;
You can use type-casting to convert them to the correct type after they come out of the database.&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = (int)self::getGameStateValue(GLOBAL_ROUND_NUMBER);&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = self::getGameStateValue(GLOBAL_ROUND_NUMBER) + 0; // adding 0 casts to int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
same with direct qdb ueries&lt;br /&gt;
   $sql = &amp;quot;SELECT my_int_column FROM my_table WHERE my_condition&amp;quot;;&lt;br /&gt;
   $myResult = self::getUniqueValueFromDB($sql); &amp;lt;-- this is a string&lt;br /&gt;
   $myResultAsInt = (int)$myResult;&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/5323146/mysql-integer-field-is-returned-as-string-in-php&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: zombie): Not logged ===&lt;br /&gt;
&lt;br /&gt;
You are probably calling getCurrentPlayerId() or getCurrentPlayerName() in your zombieTurn method or any of the methods it uses. Instead, use the $active_player_id provided as parameter to zombieTurn().&lt;br /&gt;
&lt;br /&gt;
If you do not see these commands within &amp;quot;function zombieTurn( $state, $active_player ){}&amp;quot;, check all the functions called from zombieTurn, also &amp;quot;function getGameProgression(){}&amp;quot; and all the functions THAT calls.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Can&#039;t manage zombie player in this game state ===&lt;br /&gt;
&lt;br /&gt;
The state the game was in at the time the error was generated didn&#039;t have &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;zombiePass&amp;quot; =&amp;gt; 27 )&amp;quot; in states.inc.php (27 was an arbitrary example, but everything else must be spelled exactly that way.)&lt;br /&gt;
&lt;br /&gt;
To correct this error, either add &amp;quot;zombiePass&amp;quot; =&amp;gt; ## to the transitions array or work out why the game is in a state it should not be in.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: zombie): ===&lt;br /&gt;
&lt;br /&gt;
This is almost certainly an undefined value in PHP code. Look for a warning or error message in the game replay log on the right side of the table UI.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: BGA gameserver 1 do not respond (method: zombie) (timeout: cluster) ===&lt;br /&gt;
&lt;br /&gt;
You are trying to end the game from a zombie method. This is not allowed. The zombie logic must continue the game as best it can. See [[Main_game_logic:_yourgamename.game.php#Zombie_mode|Zombie mode]] for more info.&lt;br /&gt;
&lt;br /&gt;
=== Game unexpectedly ends when one player becomes zombie ===&lt;br /&gt;
&lt;br /&gt;
There is an error in handling zombie mode, check error log. Example: if the zombie turn is called again, framework detects a infinite loop and cancels the game. On the studio there is a notification called ZombieTurnFailed&lt;br /&gt;
&lt;br /&gt;
== Other errors ==&lt;br /&gt;
&lt;br /&gt;
=== Javascript does not know how to sum two numbers ===&lt;br /&gt;
&lt;br /&gt;
Be careful when you manipulate integers returned by notifications: most of the time, Javascript considers they are Strings and not Integers.&lt;br /&gt;
&lt;br /&gt;
As a result:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += notif.args.increment;  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=11 instead of 2 !! Javascript concatenate 2 strings !&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To solve this, you should use the &amp;quot;toint&amp;quot; function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += toint( notif.args.increment );  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=2 :)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Javascript: do not use substr with negative numbers ===&lt;br /&gt;
&lt;br /&gt;
To get the last characters of a string, use &amp;quot;slice&amp;quot; instead of &amp;quot;substr&amp;quot; which has a bug on IE:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var three_last_characters = string.substr( -3 );   // Wrong&lt;br /&gt;
    var three_last_characters = string.slice( -3 );    // Correct&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Game &amp;quot;spontaneously&amp;quot; transition to a new state without user input ===&lt;br /&gt;
&lt;br /&gt;
Make sure on php side you have no code after   $this-&amp;gt;gamestate-&amp;gt;nextState(...) code.&lt;br /&gt;
Because if you do accidentally have code that goes to another state it will cause another state transition without user interaction.&lt;br /&gt;
&lt;br /&gt;
 function selectField($field) {&lt;br /&gt;
   self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
   if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
   $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;last&#039; ); // &amp;lt;-- here is missing else, so it will cause double state transition&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Message &amp;quot;Invalid or missing substitution argument for log message: ${actplayer} ... &amp;quot; when entering a state ===&lt;br /&gt;
&lt;br /&gt;
You probably have an args function defined for that state that does &#039;&#039;&#039;not&#039;&#039;&#039; return an array&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Server syntax error: Warning: count(): Parameter must be an array or an object that implements Countable in /var/tournoi/release/tournoi-220308-1000-gs/www/game/module/table/gamestate.game.php on line 823 ===&lt;br /&gt;
&lt;br /&gt;
Generally comes with that syntax error : Warning: implode(): Invalid arguments passed in /var/tournoi/release/tournoi-220308-1000-gs/www/game/module/table/gamestate.game.php on line 845&lt;br /&gt;
&lt;br /&gt;
It is most probable that you used setPlayersMultiactive method with id of a single player not included in an array -&amp;gt; you should use: ... setPlayersMultiactive( array($player_id), ...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Red banner &amp;quot;Uncaught EvalError: Possible side-effect in debug-evaluate&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
This is a known issue that can be ignored (for most of case). Generally happening when working on devtool.&lt;br /&gt;
A workaround is to disable the &amp;quot;error&amp;quot; event listener. To do so, you can temporarily disable the event listener in DevTools, like this:&lt;br /&gt;
&lt;br /&gt;
 - At the top of DevTools, open the &amp;quot;Elements&amp;quot; tab&lt;br /&gt;
 - Press &amp;quot;»&amp;quot;, on the right of &amp;quot;Styles&amp;quot;, &amp;quot;Computed&amp;quot;, &amp;quot;Layout&amp;quot;&lt;br /&gt;
 - Choose &amp;quot;Event listeners&amp;quot;&lt;br /&gt;
 - Find and expand &amp;quot;error&amp;quot;&lt;br /&gt;
 - Click &amp;quot;Remove&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This will remove the event listener, but the issue will return after you refresh the page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=12279</id>
		<title>Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=12279"/>
		<updated>2022-03-14T12:26:22Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Server syntax error: Warning: count(): Parameter must be an array or an object that implements Countable in /var/tournoi/release/tournoi-220308-1000-gs/www/game/module/table/gamestate.game.php on line 823 = */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Describing common errors which is hard to understand and debug &lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game does not start at all ==&lt;br /&gt;
&lt;br /&gt;
=== Undefined offset: 0 in table/table.game.php on line 830 ===&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re calling self::getActivePlayerName () during setupNewGame() - you should not be.&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re NOT calling self::activeNextPlayer() at the end of your game setup (you should be). You must always have at least one active player.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: createGame): ... ===&lt;br /&gt;
&lt;br /&gt;
This is generic message usually followed by exact position in your source code, and usually its syntax error in one of yours php script&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Not logged ===&lt;br /&gt;
&lt;br /&gt;
Calling self::getCurrentPlayerId () or using $g_user from &#039;args&#039; state function, see also below&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Unknow player statistic: ===&lt;br /&gt;
&lt;br /&gt;
Calling self::incStat() with second parameter which is an empty string&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats ... ===&lt;br /&gt;
&lt;br /&gt;
Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats (stats_type, stats_player_id, stats_value) VALUES (&#039;10&#039;,&#039;2300663&#039;,&#039;0&#039;),(&#039;10&#039;,&#039;2300662&#039;,&#039;0&#039;)&lt;br /&gt;
Duplicate entry &#039;10-2300663&#039; for key &#039;stats_table_id&#039;&lt;br /&gt;
&lt;br /&gt;
Why? In the stats.inc.php you declared two keys with the same integer &amp;quot;id&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: BGA main website do not respond ===&lt;br /&gt;
&lt;br /&gt;
Check if other games work; if not, it&#039;s a problem with BGA Studio; if so, your game likely reaches an end state immediately. Check your states.inc.php and your transitions.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): BGA service error ===&lt;br /&gt;
&lt;br /&gt;
You may have a syntax error in your dbmodel.sql.&lt;br /&gt;
&lt;br /&gt;
Or, you may be calling self::initStat() for a statistic that does not exist. Check the statistic name, and make sure you clicked &amp;quot;Reload statistics configuration&amp;quot; button in the admin console after making changes to stats.inc.php&lt;br /&gt;
&lt;br /&gt;
Or you may not have your states.inc.php set up correctly.&lt;br /&gt;
&lt;br /&gt;
You may have an error in your table.game.php file in setupNewGame (such as &amp;lt;code&amp;gt;$result[&#039;x&#039;] = y;&amp;lt;/code&amp;gt; when $result is not an array).&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Table status of a starting game should be &#039;setup&#039; ===&lt;br /&gt;
&lt;br /&gt;
This error message appears when you start a one player game using the &amp;quot;Express Start&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
In normal situation, the game starts just after this message and everything should works normally. In this case, you can just ignore this message.&lt;br /&gt;
&lt;br /&gt;
If the games does not start, it is most probable that there is a syntax error in any of your php code (Check your states.inc.php and X.game.php)&lt;br /&gt;
&lt;br /&gt;
=== Fatal error during creation of database ebd_quoridor_389 Not logged ===&lt;br /&gt;
&lt;br /&gt;
Check that you didn&#039;t use $g_user or getCurrentPlayerId() in setupNewGame() function or in an &#039;args&#039; function of your state.&lt;br /&gt;
&lt;br /&gt;
As these functions are not consequences of a user action, there is no current player defined.&lt;br /&gt;
&lt;br /&gt;
As a general rule, you should use getActivePlayerId() and not getCurrentPlayerId(). See the [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine presentation on the game state machine] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Warning: Invalid argument supplied for foreach() in table.game.php ===&lt;br /&gt;
&lt;br /&gt;
   Warning: Invalid argument supplied for foreach() in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 129 &lt;br /&gt;
   Fatal error: Cannot unset string offsets in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 143&lt;br /&gt;
&lt;br /&gt;
That appears when your arg* function that suppose to return array of state arguments returns a scalar (a non-array) value&lt;br /&gt;
&lt;br /&gt;
=== The server reported an error ===&lt;br /&gt;
&lt;br /&gt;
During table creation: &amp;quot;The server reported an error&amp;quot; error shown and nothing else.&lt;br /&gt;
&lt;br /&gt;
If you cannot even create a table - there is syntax error in gameinfos.php, check it, reload it from management panel.&lt;br /&gt;
If still no luck copy clean version from template https://github.com/elaskavaia/bga-sharedcode/blob/master/gameinfos.inc.php&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Error : Invalid player number for this game : 4 ===&lt;br /&gt;
&lt;br /&gt;
This error may comes when trying to change the player number configuration in gameinfos.inc.php from a higher to lower number of players (for example from 4 to 2).&lt;br /&gt;
&lt;br /&gt;
The following steps will help to change a player config from array(4) to array(2) :&lt;br /&gt;
&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2,3,4 )&lt;br /&gt;
* In game management page (Control Panel &amp;gt; Manage Games &amp;gt; &amp;quot;Your Game&amp;quot;), press the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
* create a new table&lt;br /&gt;
* reduce the number of players to 2 and start the game&lt;br /&gt;
* (express) Stop the game&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2 )&lt;br /&gt;
* press again the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
&lt;br /&gt;
=== Blank page ===&lt;br /&gt;
If you see no html at all check &lt;br /&gt;
* if you have syntax error in your view.php file &lt;br /&gt;
* class name of your view.php file  does not match the project name (should be view_foo_foo if project is foo)&lt;br /&gt;
* game name return by getGameName() does not match the project name  (should be &amp;quot;foo&amp;quot; if project is foo)&lt;br /&gt;
&lt;br /&gt;
    class view_russianrailroads_russianrailroads extends game_view {&lt;br /&gt;
    function getGameName() {&lt;br /&gt;
        return &amp;quot;russianrailroads&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Game starts but I can&#039;t make a move ==&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I got &amp;quot;Move recorded, waiting for update ...&amp;quot; forever ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Move recorded&amp;quot; means that your ajaxcall request has been sent to the server and returned normally.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Waiting for update&amp;quot; means that your client interface is waiting for some notifications from the server that correspond to the move we just did.&lt;br /&gt;
&lt;br /&gt;
If this message stays forever, it is probably that your PHP code does not send any notification when the move happens, which is abnormal. To fix this: add a notifyAllPlayers or a notifyPlayer call in your PHP code.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Sending move to server...&amp;quot; then nothing and game resets to state before the move ===&lt;br /&gt;
&lt;br /&gt;
Its possible that server code get into infinite loops or thinks too much, in which case it will timeout and will be aborted without any extra logs (and db transaction you saw in the log won&#039;t be committed). You will usually see &amp;quot;Unable to connect to server&amp;quot; message on console in this case. You have to put more logging into server&lt;br /&gt;
to trace where it hangs.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Ajaxcall error: empty answer&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You either have missing self::ajaxResponse(); in your [[Players actions: yourgamename.action.php|game.action.php]] method, or there is some problem with getting arguments (check that you are using btoa() on client when using AT_base64 arg type in action.php)&lt;br /&gt;
&lt;br /&gt;
=== Some player action is triggered randomly when I click somewhere on the game area ===&lt;br /&gt;
&lt;br /&gt;
You probably used &amp;quot;dojo.connect&amp;quot; on a null object. In this case, dojo.connect associate the event (ex: &amp;quot;onclick&amp;quot;) to the whole game area.&lt;br /&gt;
&lt;br /&gt;
Most of the time it happens in this situation, when my_object element does not exists:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   dojo.connect( $(&amp;quot;my_object&amp;quot;), &amp;quot;onclick&amp;quot;, this, (event)=&amp;gt;{})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To determine if this is the case, place &amp;quot;alert( $(&amp;quot;my_object&amp;quot;) )&amp;quot; before the dojo.connect to check if the object exists or not.&lt;br /&gt;
&lt;br /&gt;
=== Error: This is not your turn ===&lt;br /&gt;
&lt;br /&gt;
This happens when checkAction() is called and current player is NOT the active player.&lt;br /&gt;
&lt;br /&gt;
You can change the active player in studio by clicking the red arrow next to their name in the player panel (right side of the page).&lt;br /&gt;
&lt;br /&gt;
[[File:Change_active_player.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Error: Please wait, an action is already in progress ===&lt;br /&gt;
Its followed by error &amp;quot;(Generated by checkAction / XXX)&amp;quot; on studio.&lt;br /&gt;
&lt;br /&gt;
This error is triggered in the JS by the checkAction function for XXX action.&lt;br /&gt;
&lt;br /&gt;
This can happen when the player sent an Ajax request action earlier, and:&lt;br /&gt;
* action is not complete yet - i.e. takes some time, and user clicked something again &lt;br /&gt;
* if there is bug in interface where MULTIPLE handlers are fired on same click. To debug this add some console.trace() in place this specific checkAction is called.&lt;br /&gt;
* did not get any notification from the PHP side. To avoid this, put an empty notifyPlayer in the PHP side of the Ajax handler to ensure the client receives a response. This line of code should do it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyPlayer($this-&amp;gt;getCurrentPlayerId(), &#039;message&#039;, &#039;&#039;, []); // sent to current player, who originated the action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error: This move is not authorized now ===&lt;br /&gt;
This is generic error message generated by this.showMoveUnauthorized() function. If you did not call this function yourself, check the console log, it may have additional information.&lt;br /&gt;
If you see &amp;quot;Move not authorized now : XXX&amp;quot; in the log, where XXX is your action name - this means that action XXX is not defined in list of possible actions for your current state. This error generated by checkAction() function.&lt;br /&gt;
&lt;br /&gt;
=== Error: You are not connected - after waiting for the submitted move ===&lt;br /&gt;
In the log you may find: &lt;br /&gt;
  Query execution was interrupted, maximum statement execution time exceeded - Request: SELECT global_id, global_value FROM global WHERE 1&lt;br /&gt;
&lt;br /&gt;
The error message above is because of failed attempt to lock a table, which happens because of infinite loop in you game.&lt;br /&gt;
* Check that don&#039;t enter same game state over and over again&lt;br /&gt;
* Check that you reverse for loop actually descrease counter or other loop issues&lt;br /&gt;
* Check that recursive function ends&lt;br /&gt;
&lt;br /&gt;
== Predefined server errors ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Unexpected final game state (XX) ===&lt;br /&gt;
&lt;br /&gt;
The action function does not transition to any state, i.e.&lt;br /&gt;
  function selectField($field) {&lt;br /&gt;
    self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
    if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
  }&lt;br /&gt;
Here if $field is 0 there is no transition&lt;br /&gt;
&lt;br /&gt;
=== This game action is impossible right now ===&lt;br /&gt;
&lt;br /&gt;
Check the game log. Usually your state does not define the action you trying to perform in &#039;possibleactions&#039; array.&lt;br /&gt;
&lt;br /&gt;
Also check your onActionName javascript function. Make sure you are calling the right &amp;quot;actionname.html&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: This transition (playerTurn) is impossible at this state (42) ===&lt;br /&gt;
&lt;br /&gt;
This is pretty self explanatory. Function nextState() takes transition name not a state name, so you probably did not&lt;br /&gt;
define this transition that the given state&lt;br /&gt;
&lt;br /&gt;
== Game interface hangs during reload or on start ==&lt;br /&gt;
&lt;br /&gt;
Showing &amp;quot;Application Loading...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload undefined no_stack_avail Script: ===&lt;br /&gt;
&lt;br /&gt;
This error usually has no useful data, but it means you called somes API that require a callback and did not define callback function, i.e&lt;br /&gt;
in dojo.connect, this.connectClass, dojo.subscribe, etc&lt;br /&gt;
   &lt;br /&gt;
      this.connectClass(&#039;field&#039;, &#039;onclick&#039;, &#039;onField&#039;); // &amp;lt;-- onField is not defined&lt;br /&gt;
&lt;br /&gt;
=== Other errors with &amp;quot;Application loading...&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You probably have a syntax error in your Javascript code, and the interface refuses to load.&lt;br /&gt;
&lt;br /&gt;
To find this error, check if there is an error message in the Javascript console (F12).&lt;br /&gt;
&lt;br /&gt;
If there is really nothing on the log, it&#039;s probably that the system was unable to load your Javascript because of an syntax error that affect the structure of the Javascript file, typically a missing &amp;quot;}&amp;quot; or a missing &amp;quot;,&amp;quot; after a method definition.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;Uncaught ReferenceError: bgagame is not defined&amp;quot; you have major syntax error in your js file, you should see some other clues in the log where the errors is.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;dojo.publish is not defined&amp;quot; or something similar, this could be caused by another error earlier. For example, a syntax error caused by a malformed generated file (such as using newlines in tiebreaker description). Also you might have left some images in the /img directory with special characters in the name which must be removed. If you edited images for the game box and website, ensure that you have not left any unnecessary files there.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Syntax Error: ===&lt;br /&gt;
&lt;br /&gt;
No further details in the log. When log is filling with some social connect errors.&lt;br /&gt;
&lt;br /&gt;
Possible Reason: Syntax error in of the php script which is loaded before the start, such as gameoptions.inc.php, gameinfos.inc.php and such.&lt;br /&gt;
&lt;br /&gt;
=== Game interface spins in a loop throwing error ===&lt;br /&gt;
&lt;br /&gt;
Errors is something like &amp;quot;Cannot read property &#039;is_ai&#039; of undefined&amp;quot;. Cannot restart the game because cannot access UI to stop.&lt;br /&gt;
Likely you get in actplayer state with player id == 0. The only way to fix it is to edit database, globals index == 2 set player id to one of your test dudes&lt;br /&gt;
(can copy from row 5 for example).&lt;br /&gt;
&lt;br /&gt;
=== Unable to find table database (1): ebd_yourgame_112222 ===&lt;br /&gt;
&lt;br /&gt;
Its either temporarily server error especially on studio it timeouts sometimes, just try reloading again.&lt;br /&gt;
Or check if you have syntax errors in your php game file or sql.&lt;br /&gt;
&lt;br /&gt;
== Type conversion / juggling errors ==&lt;br /&gt;
&lt;br /&gt;
=== On php side I get a number instead of string I expect ===&lt;br /&gt;
&lt;br /&gt;
 $num = 3;&lt;br /&gt;
 $meeple = &amp;quot;meeple_&amp;quot; + $num; // &amp;lt;-- suppose to be &amp;quot;meeple_3&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
When you switch between JS and PHP it easy to type this and not notice the +. Plus sign (+) in php does not mean string concatenation (in javascript does!),&lt;br /&gt;
in php + means integer arithmetic. So change + to . (dot)&lt;br /&gt;
&lt;br /&gt;
=== On php side my string comparison does not work ===&lt;br /&gt;
&lt;br /&gt;
   if ($color == &#039;4baae2&#039; || $color == &#039;000000&#039;) { &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Apparently you should not be using &#039;==&#039; in php to compare strings! You should use &#039;===&#039;. The (==) operator will typecast the strings &lt;br /&gt;
to numbers then do comparison!&lt;br /&gt;
Its not very apparent because usually you can get away with it, but not when strings resemble numbers like hex &#039;colors&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Integer columns in the database are returned as strings ===&lt;br /&gt;
&lt;br /&gt;
This is normal PHP behavior. All fields are returned as string type, regardless of their actual type in the database. This also applies to global variables accessed via getGameStateValue(), since they are stored in a database table.&lt;br /&gt;
&lt;br /&gt;
You can use type-casting to convert them to the correct type after they come out of the database.&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = (int)self::getGameStateValue(GLOBAL_ROUND_NUMBER);&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = self::getGameStateValue(GLOBAL_ROUND_NUMBER) + 0; // adding 0 casts to int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
same with direct qdb ueries&lt;br /&gt;
   $sql = &amp;quot;SELECT my_int_column FROM my_table WHERE my_condition&amp;quot;;&lt;br /&gt;
   $myResult = self::getUniqueValueFromDB($sql); &amp;lt;-- this is a string&lt;br /&gt;
   $myResultAsInt = (int)$myResult;&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/5323146/mysql-integer-field-is-returned-as-string-in-php&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: zombie): Not logged ===&lt;br /&gt;
&lt;br /&gt;
You are probably calling getCurrentPlayerId() or getCurrentPlayerName() in your zombieTurn method or any of the methods it uses. Instead, use the $active_player_id provided as parameter to zombieTurn().&lt;br /&gt;
&lt;br /&gt;
If you do not see these commands within &amp;quot;function zombieTurn( $state, $active_player ){}&amp;quot;, check all the functions called from zombieTurn, also &amp;quot;function getGameProgression(){}&amp;quot; and all the functions THAT calls.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Can&#039;t manage zombie player in this game state ===&lt;br /&gt;
&lt;br /&gt;
The state the game was in at the time the error was generated didn&#039;t have &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;zombiePass&amp;quot; =&amp;gt; 27 )&amp;quot; in states.inc.php (27 was an arbitrary example, but everything else must be spelled exactly that way.)&lt;br /&gt;
&lt;br /&gt;
To correct this error, either add &amp;quot;zombiePass&amp;quot; =&amp;gt; ## to the transitions array or work out why the game is in a state it should not be in.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: zombie): ===&lt;br /&gt;
&lt;br /&gt;
This is almost certainly an undefined value in PHP code. Look for a warning or error message in the game replay log on the right side of the table UI.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: BGA gameserver 1 do not respond (method: zombie) (timeout: cluster) ===&lt;br /&gt;
&lt;br /&gt;
You are trying to end the game from a zombie method. This is not allowed. The zombie logic must continue the game as best it can. See [[Main_game_logic:_yourgamename.game.php#Zombie_mode|Zombie mode]] for more info.&lt;br /&gt;
&lt;br /&gt;
=== Game unexpectedly ends when one player becomes zombie ===&lt;br /&gt;
&lt;br /&gt;
There is an error in handling zombie mode, check error log. Example: if the zombie turn is called again, framework detects a infinite loop and cancels the game. On the studio there is a notification called ZombieTurnFailed&lt;br /&gt;
&lt;br /&gt;
== Other errors ==&lt;br /&gt;
&lt;br /&gt;
=== Javascript does not know how to sum two numbers ===&lt;br /&gt;
&lt;br /&gt;
Be careful when you manipulate integers returned by notifications: most of the time, Javascript considers they are Strings and not Integers.&lt;br /&gt;
&lt;br /&gt;
As a result:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += notif.args.increment;  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=11 instead of 2 !! Javascript concatenate 2 strings !&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To solve this, you should use the &amp;quot;toint&amp;quot; function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += toint( notif.args.increment );  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=2 :)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Javascript: do not use substr with negative numbers ===&lt;br /&gt;
&lt;br /&gt;
To get the last characters of a string, use &amp;quot;slice&amp;quot; instead of &amp;quot;substr&amp;quot; which has a bug on IE:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var three_last_characters = string.substr( -3 );   // Wrong&lt;br /&gt;
    var three_last_characters = string.slice( -3 );    // Correct&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Game &amp;quot;spontaneously&amp;quot; transition to a new state without user input ===&lt;br /&gt;
&lt;br /&gt;
Make sure on php side you have no code after   $this-&amp;gt;gamestate-&amp;gt;nextState(...) code.&lt;br /&gt;
Because if you do accidentally have code that goes to another state it will cause another state transition without user interaction.&lt;br /&gt;
&lt;br /&gt;
 function selectField($field) {&lt;br /&gt;
   self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
   if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
   $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;last&#039; ); // &amp;lt;-- here is missing else, so it will cause double state transition&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Message &amp;quot;Invalid or missing substitution argument for log message: ${actplayer} ... &amp;quot; when entering a state ===&lt;br /&gt;
&lt;br /&gt;
You probably have an args function defined for that state that does &#039;&#039;&#039;not&#039;&#039;&#039; return an array&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Server syntax error: Warning: count(): Parameter must be an array or an object that implements Countable in /var/tournoi/release/tournoi-220308-1000-gs/www/game/module/table/gamestate.game.php on line 823 ===&lt;br /&gt;
&lt;br /&gt;
Generally comes with that syntax error : Warning: implode(): Invalid arguments passed in /var/tournoi/release/tournoi-220308-1000-gs/www/game/module/table/gamestate.game.php on line 845&lt;br /&gt;
&lt;br /&gt;
It is most probable that you used setPlayersMultiactive method with id of a single player not included in an array -&amp;gt; you should use : ... setPlayersMultiactive( array($player_id), ...&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=12278</id>
		<title>Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=12278"/>
		<updated>2022-03-14T12:25:43Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Other errors */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Describing common errors which is hard to understand and debug &lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game does not start at all ==&lt;br /&gt;
&lt;br /&gt;
=== Undefined offset: 0 in table/table.game.php on line 830 ===&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re calling self::getActivePlayerName () during setupNewGame() - you should not be.&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re NOT calling self::activeNextPlayer() at the end of your game setup (you should be). You must always have at least one active player.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: createGame): ... ===&lt;br /&gt;
&lt;br /&gt;
This is generic message usually followed by exact position in your source code, and usually its syntax error in one of yours php script&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Not logged ===&lt;br /&gt;
&lt;br /&gt;
Calling self::getCurrentPlayerId () or using $g_user from &#039;args&#039; state function, see also below&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Unknow player statistic: ===&lt;br /&gt;
&lt;br /&gt;
Calling self::incStat() with second parameter which is an empty string&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats ... ===&lt;br /&gt;
&lt;br /&gt;
Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats (stats_type, stats_player_id, stats_value) VALUES (&#039;10&#039;,&#039;2300663&#039;,&#039;0&#039;),(&#039;10&#039;,&#039;2300662&#039;,&#039;0&#039;)&lt;br /&gt;
Duplicate entry &#039;10-2300663&#039; for key &#039;stats_table_id&#039;&lt;br /&gt;
&lt;br /&gt;
Why? In the stats.inc.php you declared two keys with the same integer &amp;quot;id&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: BGA main website do not respond ===&lt;br /&gt;
&lt;br /&gt;
Check if other games work; if not, it&#039;s a problem with BGA Studio; if so, your game likely reaches an end state immediately. Check your states.inc.php and your transitions.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): BGA service error ===&lt;br /&gt;
&lt;br /&gt;
You may have a syntax error in your dbmodel.sql.&lt;br /&gt;
&lt;br /&gt;
Or, you may be calling self::initStat() for a statistic that does not exist. Check the statistic name, and make sure you clicked &amp;quot;Reload statistics configuration&amp;quot; button in the admin console after making changes to stats.inc.php&lt;br /&gt;
&lt;br /&gt;
Or you may not have your states.inc.php set up correctly.&lt;br /&gt;
&lt;br /&gt;
You may have an error in your table.game.php file in setupNewGame (such as &amp;lt;code&amp;gt;$result[&#039;x&#039;] = y;&amp;lt;/code&amp;gt; when $result is not an array).&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Table status of a starting game should be &#039;setup&#039; ===&lt;br /&gt;
&lt;br /&gt;
This error message appears when you start a one player game using the &amp;quot;Express Start&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
In normal situation, the game starts just after this message and everything should works normally. In this case, you can just ignore this message.&lt;br /&gt;
&lt;br /&gt;
If the games does not start, it is most probable that there is a syntax error in any of your php code (Check your states.inc.php and X.game.php)&lt;br /&gt;
&lt;br /&gt;
=== Fatal error during creation of database ebd_quoridor_389 Not logged ===&lt;br /&gt;
&lt;br /&gt;
Check that you didn&#039;t use $g_user or getCurrentPlayerId() in setupNewGame() function or in an &#039;args&#039; function of your state.&lt;br /&gt;
&lt;br /&gt;
As these functions are not consequences of a user action, there is no current player defined.&lt;br /&gt;
&lt;br /&gt;
As a general rule, you should use getActivePlayerId() and not getCurrentPlayerId(). See the [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine presentation on the game state machine] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Warning: Invalid argument supplied for foreach() in table.game.php ===&lt;br /&gt;
&lt;br /&gt;
   Warning: Invalid argument supplied for foreach() in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 129 &lt;br /&gt;
   Fatal error: Cannot unset string offsets in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 143&lt;br /&gt;
&lt;br /&gt;
That appears when your arg* function that suppose to return array of state arguments returns a scalar (a non-array) value&lt;br /&gt;
&lt;br /&gt;
=== The server reported an error ===&lt;br /&gt;
&lt;br /&gt;
During table creation: &amp;quot;The server reported an error&amp;quot; error shown and nothing else.&lt;br /&gt;
&lt;br /&gt;
If you cannot even create a table - there is syntax error in gameinfos.php, check it, reload it from management panel.&lt;br /&gt;
If still no luck copy clean version from template https://github.com/elaskavaia/bga-sharedcode/blob/master/gameinfos.inc.php&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Error : Invalid player number for this game : 4 ===&lt;br /&gt;
&lt;br /&gt;
This error may comes when trying to change the player number configuration in gameinfos.inc.php from a higher to lower number of players (for example from 4 to 2).&lt;br /&gt;
&lt;br /&gt;
The following steps will help to change a player config from array(4) to array(2) :&lt;br /&gt;
&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2,3,4 )&lt;br /&gt;
* In game management page (Control Panel &amp;gt; Manage Games &amp;gt; &amp;quot;Your Game&amp;quot;), press the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
* create a new table&lt;br /&gt;
* reduce the number of players to 2 and start the game&lt;br /&gt;
* (express) Stop the game&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2 )&lt;br /&gt;
* press again the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
&lt;br /&gt;
=== Blank page ===&lt;br /&gt;
If you see no html at all check &lt;br /&gt;
* if you have syntax error in your view.php file &lt;br /&gt;
* class name of your view.php file  does not match the project name (should be view_foo_foo if project is foo)&lt;br /&gt;
* game name return by getGameName() does not match the project name  (should be &amp;quot;foo&amp;quot; if project is foo)&lt;br /&gt;
&lt;br /&gt;
    class view_russianrailroads_russianrailroads extends game_view {&lt;br /&gt;
    function getGameName() {&lt;br /&gt;
        return &amp;quot;russianrailroads&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Game starts but I can&#039;t make a move ==&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I got &amp;quot;Move recorded, waiting for update ...&amp;quot; forever ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Move recorded&amp;quot; means that your ajaxcall request has been sent to the server and returned normally.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Waiting for update&amp;quot; means that your client interface is waiting for some notifications from the server that correspond to the move we just did.&lt;br /&gt;
&lt;br /&gt;
If this message stays forever, it is probably that your PHP code does not send any notification when the move happens, which is abnormal. To fix this: add a notifyAllPlayers or a notifyPlayer call in your PHP code.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Sending move to server...&amp;quot; then nothing and game resets to state before the move ===&lt;br /&gt;
&lt;br /&gt;
Its possible that server code get into infinite loops or thinks too much, in which case it will timeout and will be aborted without any extra logs (and db transaction you saw in the log won&#039;t be committed). You will usually see &amp;quot;Unable to connect to server&amp;quot; message on console in this case. You have to put more logging into server&lt;br /&gt;
to trace where it hangs.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Ajaxcall error: empty answer&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You either have missing self::ajaxResponse(); in your [[Players actions: yourgamename.action.php|game.action.php]] method, or there is some problem with getting arguments (check that you are using btoa() on client when using AT_base64 arg type in action.php)&lt;br /&gt;
&lt;br /&gt;
=== Some player action is triggered randomly when I click somewhere on the game area ===&lt;br /&gt;
&lt;br /&gt;
You probably used &amp;quot;dojo.connect&amp;quot; on a null object. In this case, dojo.connect associate the event (ex: &amp;quot;onclick&amp;quot;) to the whole game area.&lt;br /&gt;
&lt;br /&gt;
Most of the time it happens in this situation, when my_object element does not exists:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   dojo.connect( $(&amp;quot;my_object&amp;quot;), &amp;quot;onclick&amp;quot;, this, (event)=&amp;gt;{})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To determine if this is the case, place &amp;quot;alert( $(&amp;quot;my_object&amp;quot;) )&amp;quot; before the dojo.connect to check if the object exists or not.&lt;br /&gt;
&lt;br /&gt;
=== Error: This is not your turn ===&lt;br /&gt;
&lt;br /&gt;
This happens when checkAction() is called and current player is NOT the active player.&lt;br /&gt;
&lt;br /&gt;
You can change the active player in studio by clicking the red arrow next to their name in the player panel (right side of the page).&lt;br /&gt;
&lt;br /&gt;
[[File:Change_active_player.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Error: Please wait, an action is already in progress ===&lt;br /&gt;
Its followed by error &amp;quot;(Generated by checkAction / XXX)&amp;quot; on studio.&lt;br /&gt;
&lt;br /&gt;
This error is triggered in the JS by the checkAction function for XXX action.&lt;br /&gt;
&lt;br /&gt;
This can happen when the player sent an Ajax request action earlier, and:&lt;br /&gt;
* action is not complete yet - i.e. takes some time, and user clicked something again &lt;br /&gt;
* if there is bug in interface where MULTIPLE handlers are fired on same click. To debug this add some console.trace() in place this specific checkAction is called.&lt;br /&gt;
* did not get any notification from the PHP side. To avoid this, put an empty notifyPlayer in the PHP side of the Ajax handler to ensure the client receives a response. This line of code should do it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyPlayer($this-&amp;gt;getCurrentPlayerId(), &#039;message&#039;, &#039;&#039;, []); // sent to current player, who originated the action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error: This move is not authorized now ===&lt;br /&gt;
This is generic error message generated by this.showMoveUnauthorized() function. If you did not call this function yourself, check the console log, it may have additional information.&lt;br /&gt;
If you see &amp;quot;Move not authorized now : XXX&amp;quot; in the log, where XXX is your action name - this means that action XXX is not defined in list of possible actions for your current state. This error generated by checkAction() function.&lt;br /&gt;
&lt;br /&gt;
=== Error: You are not connected - after waiting for the submitted move ===&lt;br /&gt;
In the log you may find: &lt;br /&gt;
  Query execution was interrupted, maximum statement execution time exceeded - Request: SELECT global_id, global_value FROM global WHERE 1&lt;br /&gt;
&lt;br /&gt;
The error message above is because of failed attempt to lock a table, which happens because of infinite loop in you game.&lt;br /&gt;
* Check that don&#039;t enter same game state over and over again&lt;br /&gt;
* Check that you reverse for loop actually descrease counter or other loop issues&lt;br /&gt;
* Check that recursive function ends&lt;br /&gt;
&lt;br /&gt;
== Predefined server errors ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Unexpected final game state (XX) ===&lt;br /&gt;
&lt;br /&gt;
The action function does not transition to any state, i.e.&lt;br /&gt;
  function selectField($field) {&lt;br /&gt;
    self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
    if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
  }&lt;br /&gt;
Here if $field is 0 there is no transition&lt;br /&gt;
&lt;br /&gt;
=== This game action is impossible right now ===&lt;br /&gt;
&lt;br /&gt;
Check the game log. Usually your state does not define the action you trying to perform in &#039;possibleactions&#039; array.&lt;br /&gt;
&lt;br /&gt;
Also check your onActionName javascript function. Make sure you are calling the right &amp;quot;actionname.html&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: This transition (playerTurn) is impossible at this state (42) ===&lt;br /&gt;
&lt;br /&gt;
This is pretty self explanatory. Function nextState() takes transition name not a state name, so you probably did not&lt;br /&gt;
define this transition that the given state&lt;br /&gt;
&lt;br /&gt;
== Game interface hangs during reload or on start ==&lt;br /&gt;
&lt;br /&gt;
Showing &amp;quot;Application Loading...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload undefined no_stack_avail Script: ===&lt;br /&gt;
&lt;br /&gt;
This error usually has no useful data, but it means you called somes API that require a callback and did not define callback function, i.e&lt;br /&gt;
in dojo.connect, this.connectClass, dojo.subscribe, etc&lt;br /&gt;
   &lt;br /&gt;
      this.connectClass(&#039;field&#039;, &#039;onclick&#039;, &#039;onField&#039;); // &amp;lt;-- onField is not defined&lt;br /&gt;
&lt;br /&gt;
=== Other errors with &amp;quot;Application loading...&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You probably have a syntax error in your Javascript code, and the interface refuses to load.&lt;br /&gt;
&lt;br /&gt;
To find this error, check if there is an error message in the Javascript console (F12).&lt;br /&gt;
&lt;br /&gt;
If there is really nothing on the log, it&#039;s probably that the system was unable to load your Javascript because of an syntax error that affect the structure of the Javascript file, typically a missing &amp;quot;}&amp;quot; or a missing &amp;quot;,&amp;quot; after a method definition.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;Uncaught ReferenceError: bgagame is not defined&amp;quot; you have major syntax error in your js file, you should see some other clues in the log where the errors is.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;dojo.publish is not defined&amp;quot; or something similar, this could be caused by another error earlier. For example, a syntax error caused by a malformed generated file (such as using newlines in tiebreaker description). Also you might have left some images in the /img directory with special characters in the name which must be removed. If you edited images for the game box and website, ensure that you have not left any unnecessary files there.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Syntax Error: ===&lt;br /&gt;
&lt;br /&gt;
No further details in the log. When log is filling with some social connect errors.&lt;br /&gt;
&lt;br /&gt;
Possible Reason: Syntax error in of the php script which is loaded before the start, such as gameoptions.inc.php, gameinfos.inc.php and such.&lt;br /&gt;
&lt;br /&gt;
=== Game interface spins in a loop throwing error ===&lt;br /&gt;
&lt;br /&gt;
Errors is something like &amp;quot;Cannot read property &#039;is_ai&#039; of undefined&amp;quot;. Cannot restart the game because cannot access UI to stop.&lt;br /&gt;
Likely you get in actplayer state with player id == 0. The only way to fix it is to edit database, globals index == 2 set player id to one of your test dudes&lt;br /&gt;
(can copy from row 5 for example).&lt;br /&gt;
&lt;br /&gt;
=== Unable to find table database (1): ebd_yourgame_112222 ===&lt;br /&gt;
&lt;br /&gt;
Its either temporarily server error especially on studio it timeouts sometimes, just try reloading again.&lt;br /&gt;
Or check if you have syntax errors in your php game file or sql.&lt;br /&gt;
&lt;br /&gt;
== Type conversion / juggling errors ==&lt;br /&gt;
&lt;br /&gt;
=== On php side I get a number instead of string I expect ===&lt;br /&gt;
&lt;br /&gt;
 $num = 3;&lt;br /&gt;
 $meeple = &amp;quot;meeple_&amp;quot; + $num; // &amp;lt;-- suppose to be &amp;quot;meeple_3&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
When you switch between JS and PHP it easy to type this and not notice the +. Plus sign (+) in php does not mean string concatenation (in javascript does!),&lt;br /&gt;
in php + means integer arithmetic. So change + to . (dot)&lt;br /&gt;
&lt;br /&gt;
=== On php side my string comparison does not work ===&lt;br /&gt;
&lt;br /&gt;
   if ($color == &#039;4baae2&#039; || $color == &#039;000000&#039;) { &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Apparently you should not be using &#039;==&#039; in php to compare strings! You should use &#039;===&#039;. The (==) operator will typecast the strings &lt;br /&gt;
to numbers then do comparison!&lt;br /&gt;
Its not very apparent because usually you can get away with it, but not when strings resemble numbers like hex &#039;colors&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Integer columns in the database are returned as strings ===&lt;br /&gt;
&lt;br /&gt;
This is normal PHP behavior. All fields are returned as string type, regardless of their actual type in the database. This also applies to global variables accessed via getGameStateValue(), since they are stored in a database table.&lt;br /&gt;
&lt;br /&gt;
You can use type-casting to convert them to the correct type after they come out of the database.&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = (int)self::getGameStateValue(GLOBAL_ROUND_NUMBER);&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = self::getGameStateValue(GLOBAL_ROUND_NUMBER) + 0; // adding 0 casts to int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
same with direct qdb ueries&lt;br /&gt;
   $sql = &amp;quot;SELECT my_int_column FROM my_table WHERE my_condition&amp;quot;;&lt;br /&gt;
   $myResult = self::getUniqueValueFromDB($sql); &amp;lt;-- this is a string&lt;br /&gt;
   $myResultAsInt = (int)$myResult;&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/5323146/mysql-integer-field-is-returned-as-string-in-php&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: zombie): Not logged ===&lt;br /&gt;
&lt;br /&gt;
You are probably calling getCurrentPlayerId() or getCurrentPlayerName() in your zombieTurn method or any of the methods it uses. Instead, use the $active_player_id provided as parameter to zombieTurn().&lt;br /&gt;
&lt;br /&gt;
If you do not see these commands within &amp;quot;function zombieTurn( $state, $active_player ){}&amp;quot;, check all the functions called from zombieTurn, also &amp;quot;function getGameProgression(){}&amp;quot; and all the functions THAT calls.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Can&#039;t manage zombie player in this game state ===&lt;br /&gt;
&lt;br /&gt;
The state the game was in at the time the error was generated didn&#039;t have &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;zombiePass&amp;quot; =&amp;gt; 27 )&amp;quot; in states.inc.php (27 was an arbitrary example, but everything else must be spelled exactly that way.)&lt;br /&gt;
&lt;br /&gt;
To correct this error, either add &amp;quot;zombiePass&amp;quot; =&amp;gt; ## to the transitions array or work out why the game is in a state it should not be in.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: zombie): ===&lt;br /&gt;
&lt;br /&gt;
This is almost certainly an undefined value in PHP code. Look for a warning or error message in the game replay log on the right side of the table UI.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: BGA gameserver 1 do not respond (method: zombie) (timeout: cluster) ===&lt;br /&gt;
&lt;br /&gt;
You are trying to end the game from a zombie method. This is not allowed. The zombie logic must continue the game as best it can. See [[Main_game_logic:_yourgamename.game.php#Zombie_mode|Zombie mode]] for more info.&lt;br /&gt;
&lt;br /&gt;
=== Game unexpectedly ends when one player becomes zombie ===&lt;br /&gt;
&lt;br /&gt;
There is an error in handling zombie mode, check error log. Example: if the zombie turn is called again, framework detects a infinite loop and cancels the game. On the studio there is a notification called ZombieTurnFailed&lt;br /&gt;
&lt;br /&gt;
== Other errors ==&lt;br /&gt;
&lt;br /&gt;
=== Javascript does not know how to sum two numbers ===&lt;br /&gt;
&lt;br /&gt;
Be careful when you manipulate integers returned by notifications: most of the time, Javascript considers they are Strings and not Integers.&lt;br /&gt;
&lt;br /&gt;
As a result:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += notif.args.increment;  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=11 instead of 2 !! Javascript concatenate 2 strings !&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To solve this, you should use the &amp;quot;toint&amp;quot; function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += toint( notif.args.increment );  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=2 :)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Javascript: do not use substr with negative numbers ===&lt;br /&gt;
&lt;br /&gt;
To get the last characters of a string, use &amp;quot;slice&amp;quot; instead of &amp;quot;substr&amp;quot; which has a bug on IE:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var three_last_characters = string.substr( -3 );   // Wrong&lt;br /&gt;
    var three_last_characters = string.slice( -3 );    // Correct&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Game &amp;quot;spontaneously&amp;quot; transition to a new state without user input ===&lt;br /&gt;
&lt;br /&gt;
Make sure on php side you have no code after   $this-&amp;gt;gamestate-&amp;gt;nextState(...) code.&lt;br /&gt;
Because if you do accidentally have code that goes to another state it will cause another state transition without user interaction.&lt;br /&gt;
&lt;br /&gt;
 function selectField($field) {&lt;br /&gt;
   self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
   if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
   $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;last&#039; ); // &amp;lt;-- here is missing else, so it will cause double state transition&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Message &amp;quot;Invalid or missing substitution argument for log message: ${actplayer} ... &amp;quot; when entering a state ===&lt;br /&gt;
&lt;br /&gt;
You probably have an args function defined for that state that does &#039;&#039;&#039;not&#039;&#039;&#039; return an array&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Server syntax error: Warning: count(): Parameter must be an array or an object that implements Countable in /var/tournoi/release/tournoi-220308-1000-gs/www/game/module/table/gamestate.game.php on line 823 ===&lt;br /&gt;
&lt;br /&gt;
Generally comes with that syntax error : Warning: implode(): Invalid arguments passed in /var/tournoi/release/tournoi-220308-1000-gs/www/game/module/table/gamestate.game.php on line 845&lt;br /&gt;
&lt;br /&gt;
It is most probable that you used setPlayersMultiactive method with id of a single player not included in an array -&amp;gt; you should use : ... setPlayersMultiactive( array($player_id), ...&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=12242</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=12242"/>
		<updated>2022-03-11T11:18:53Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Multiple activate player handling */&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. Returns a number indicating percent of progression (0-100)&lt;br /&gt;
* Utility functions: your utility functions.&lt;br /&gt;
* Player actions: the entry points for players actions ([https://en.doc.boardgamearena.com/Players_actions:_yourgamename.action.php more info here]). &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;
; getPlayerNameById($player_id)&lt;br /&gt;
: Get the name by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerColorById($player_id)&lt;br /&gt;
: Get the color by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerNoById($player_id)&lt;br /&gt;
: Get &#039;player_no&#039; (number) by id&lt;br /&gt;
&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;
: &amp;lt;code&amp;gt;array_keys($this-&amp;gt;loadPlayersBasicInfos())&amp;lt;/code&amp;gt; will therefore returns an array containing players id&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;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
                foreach ($players as $player_id =&amp;gt; $info) {&lt;br /&gt;
                    $player_color = $info[&#039;player_color&#039;];&lt;br /&gt;
                    ...&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: if you want array of player ids only you can do this:&lt;br /&gt;
    $player_ids =  array_keys($this-&amp;gt;loadPlayersBasicInfos());  &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;
; isSpectator()&lt;br /&gt;
: Check the &amp;quot;current_player&amp;quot; spectator status. If true, the user accessing the game is a spectator (not part of the game). For this user, the interface should display all public information, and no private information (like a friend sitting at the same table as players and just spectating 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;
; isPlayerZombie($player_id)&lt;br /&gt;
: This method does not exists, but if you need it it looks like this&lt;br /&gt;
    protected function isPlayerZombie($player_id) {&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        if (! isset($players[$player_id]))&lt;br /&gt;
            throw new feException(&amp;quot;Player $player_id is not playing here&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        return ($players[$player_id][&#039;player_zombie&#039;] == 1);&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;
However there are sets of database operation that initite implicit commit (most common mistake is to use &amp;quot;TRUNCATE&amp;quot;), you cannot use these operations during the game, it breaks the unrolling of transactions and will lead to nasty issues&lt;br /&gt;
(https://mariadb.com/kb/en/sql-statements-that-cause-an-implicit-commit).&lt;br /&gt;
&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;
: For SELECT queries, the specialized methods below are much better.&lt;br /&gt;
: Do not use method for TUNCATE, DROP and other table altering operations. See disclamer above about implicit commits. If you really need TRUNCATE use DELETE FROM xxx instead.&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 (semantically, it does not actually have to declared in sql as such).&lt;br /&gt;
: The resulting collection can be empty (it won&#039;t be null).&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;, otherwise its A=&amp;gt;[A,B]&lt;br /&gt;
: Note: The name a bit misleading, it really return associative array, i.e. map and NOT a collection. You cannot use it to get list of values which may have duplicates (hence primary key requirement on first column). If you need simple array use getObjectListFromDB() method.&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 (you can use LIMIT 1 in the query to avoid the exception)&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 __construct() method of &#039;&#039;yourgamename.game.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, there can be gaps). 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;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $this-&amp;gt;GAMESTATELABELS = [&amp;quot;my_first_global_variable&amp;quot; =&amp;gt; 10, &amp;quot;my_second_global_variable&amp;quot; =&amp;gt; 11];&lt;br /&gt;
        self::initGameStateLabels($this-&amp;gt;GAMESTATELABELS);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is also in this method that you will define your game options. In that case, IDs need to be between 100 and 199 (inclusive, there can be gaps) Check this for more details [[Game_options_and_preferences:_gameoptions.inc.php]]&lt;br /&gt;
&lt;br /&gt;
With option set, the method will look like&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;
                &amp;quot;my_game_variant&amp;quot; =&amp;gt; 100&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. $value_value must be an integer.&lt;br /&gt;
&lt;br /&gt;
It seems that a non initialized value will not be restored with undo system, so it is therefore advisable to initialize them all in your &amp;quot;setupNewGame&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;foreach ($this-&amp;gt;GAMESTATELABELS as $value_label=&amp;gt; $ID) if ($ID &amp;gt;= 10 &amp;amp;&amp;amp; $ID &amp;lt; 90) self::setGameStateInitialValue($value_label, 0);&amp;lt;/pre&amp;gt;&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;
For debugging purposes, you can have labels and value pairs send to client side by inserting that line of code in your &amp;quot;getAllDatas&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;$result[&#039;labels&#039;] = array_combine(array_keys($this-&amp;gt;GAMESTATELABELS), array_map(&#039;self::getGameStateValue&#039;, array_keys($this-&amp;gt;GAMESTATELABELS)));&amp;lt;/pre&amp;gt;&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. $value_value must be an integer.&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;
; $this-&amp;gt;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, it just calls $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive()&lt;br /&gt;
&lt;br /&gt;
This is to be used in 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;stMakeEveryoneActive&#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. If &amp;quot;players&amp;quot; is not empty the value of &amp;quot;next_state&amp;quot; will be ignored (you can put whatever you want)&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;
;$this-&amp;gt;gamestate-&amp;gt;isPlayerActive($player_id)&lt;br /&gt;
:Return true if specified player is active right now.&lt;br /&gt;
:This method take into account game state type, ie nobody is active if game state is &amp;quot;game&amp;quot; and several players can be active if game state is &amp;quot;multiplayer&amp;quot;&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 changed 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;
&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;
I suggest to define and use this function in your php class to access state name:&lt;br /&gt;
&lt;br /&gt;
    public function getStateName() {&lt;br /&gt;
        $state = $this-&amp;gt;gamestate-&amp;gt;state();&lt;br /&gt;
        return $state[&#039;name&#039;];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;state_id()&lt;br /&gt;
: Get the id of the current game state (rarely useful, its best to use name, unless you use constants for state ids)&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;isMutiactiveState()&lt;br /&gt;
: Return true if we are in multipleactiveplayer state, false otherwise&lt;br /&gt;
&lt;br /&gt;
=== Private parallel states ===&lt;br /&gt;
&lt;br /&gt;
See the overview of private parallel states [[Your_game_state_machine:_states.inc.php#Private_parallel_states|here]].&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers()&lt;br /&gt;
: All active players in a multiactive state are entering a first private state defined in the master state&#039;s initialprivate parameter.&lt;br /&gt;
: Every time you need to start a private parallel states you need to call this or similar methods below.&lt;br /&gt;
: Note: at least one player needs to be active (see [[#Multiple_activate_player_handling|above]]) and current game state must be a multiactive state with initialprivate parameter defined&lt;br /&gt;
: Note: initialprivate parameter of master state should be set to the id of the first private state. This private state needs to be defined in states.php with the type set to &#039;private&#039;.&lt;br /&gt;
: Note: this method is usually preceded with activating some or all players&lt;br /&gt;
: Note: initializing private state can run action or args methods of the initial private state&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function stStartPlayerTurn() {&lt;br /&gt;
        // This is usually done in master state action method&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers();&lt;br /&gt;
&lt;br /&gt;
        // in some cases you can move immediately some or all players to different private states&lt;br /&gt;
        if ($someCondition) {&lt;br /&gt;
            //move all players to different state &lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers(&amp;quot;some_transition&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($other condition) {&lt;br /&gt;
            //move single player to different state&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($specificPlayerId, &amp;quot;some_transition&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForPlayers($playerIds)&lt;br /&gt;
: Players with specified ids are entering a first private state defined in the master state initialprivate parameter.&lt;br /&gt;
: Same considerations apply as for the method above.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;initializePrivateState($playerId)&lt;br /&gt;
: Player with the specified id is entering a first private state defined in the master state initialprivate parameter.&lt;br /&gt;
: Everytime you need to start a private parallel states you need to call this or similar methods above&lt;br /&gt;
: Note: player needs to be active (see [[#Multiple_activate_player_handling|above]]) and current game state must be a multiactive state with initialprivate parameter defined&lt;br /&gt;
: Note: initialprivate parameter of master state should be set to the id of the first private state. This private state needs to be defined in states.php with the type set to &#039;private&#039;.&lt;br /&gt;
: Note: this method is usually preceded with activating that player&lt;br /&gt;
: Note: initializing private state can run action or args methods of the initial private state&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_ChangeMind() {&lt;br /&gt;
        // This player finished his move before, but now decides change something while other players are still active&lt;br /&gt;
        // We activate the player and initialize his private state&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive([$this-&amp;gt;getCurrentPlayerId()], &amp;quot;&amp;quot;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateState(this-&amp;gt;getCurrentPlayerId());&lt;br /&gt;
&lt;br /&gt;
        // It is also possible to move the player to some other specific state immediately&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;some_transition&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers($transition)&lt;br /&gt;
: All active players will transition to next private state by specified transition&lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: transition should lead to another private state (i.e. a state with type defined as &#039;private&#039;&lt;br /&gt;
: Note: transition should be defined in private state in which the players currently are. &lt;br /&gt;
: Note: this method can run action or args methods of the target state&lt;br /&gt;
: Note: this is usually used after initializing the private state to move players to specific private state according to the game logic&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function stStartPlayerTurn() {&lt;br /&gt;
        // This is usually done in master state action method&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers();&lt;br /&gt;
&lt;br /&gt;
        if ($specificOption) {&lt;br /&gt;
            //move all players to different state &lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers(&amp;quot;some_transition&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForPlayers($playerIds, $transition)&lt;br /&gt;
: Players with specified ids will transition to next private state specified by provided transition.&lt;br /&gt;
: Same considerations apply as for the method above.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($playerId, $transition)&lt;br /&gt;
: Player with specified id will transition to next private state specified by provided transition&lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: transition should lead to another private state (i.e. a state with type defined as &#039;private&#039;&lt;br /&gt;
: Note: transition should be defined in private state in which the players currently are. &lt;br /&gt;
: Note: this method can run action or args methods of the target state for specified player&lt;br /&gt;
: Note: this is usually used after some player actions to move to next private state&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function someAction() {&lt;br /&gt;
        $this-&amp;gt;checkAction(&amp;quot;someAction&amp;quot;); //needs to be defined in the current state&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;some_transition&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;unsetPrivateStateForAllPlayers()&lt;br /&gt;
: All players private state will be reset to null, which means they will get out of private parallel states and be in a master state like the private states are not used &lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: this is usually used to clean up after leaving a master state in which private states were used, but can be used in other cases when we want to exit private parallel states and use a regular multiactive state for all players&lt;br /&gt;
: Note: After unseting private state only actions on master state are possible&lt;br /&gt;
: Note: Usually it is not necessary to unset private states as they will be initialized to first private state when private states are needed again. Nevertheless it is generally better to clean private state after exiting private parallel states to avoid bugs. &lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function stNextRound() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;unsetPrivateStateForAllPlayers();&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;unsetPrivateStateForPlayers($playerIds, $transition)&lt;br /&gt;
: For players with specified ids private state will be reset to null, which means they will get out of private parallel states and be in a master state like the private states are not used.&lt;br /&gt;
: Same considerations apply as for the method above.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;unsetPrivateState($playerId)&lt;br /&gt;
: For player with specified id private state will be reset to null, which means they will get out of private parallel states and be in a master state like the private states are not used &lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: this is usually used when deactivating player to clean up their parallel state&lt;br /&gt;
: Note: After unseting private state only actions on master state are possible&lt;br /&gt;
: Note: Usually it is not necessary to unset private state as it will be initialized to first private state when private states are needed again. Nevertheless it is generally better to clean private state when not needed to avoid bugs. &lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function done() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive( $this-&amp;gt;getCurrentPlayerId(), &amp;quot;newTurn&amp;quot; );&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;unsetPrivateState($this-&amp;gt;getCurrentPlayerId());&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setPrivateState($playerId, $newStateId)&lt;br /&gt;
: For player with specified id a new private state would be set&lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: this should be rarely used as it doesn&#039;t check if the transition is allowed (it doesn&#039;t even specifies transition). This can be useful in very complex cases when standard state machine is not adequate (i.e. specific cards can lead to some micro action in various states where defining transitions back and forth can become very tedious.) &lt;br /&gt;
: Note: this method can run action or args methods of the target state for specified player&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function someAction() {&lt;br /&gt;
        $this-&amp;gt;checkAction(&amp;quot;someAction&amp;quot;); //needs to be defined in the current state&lt;br /&gt;
&lt;br /&gt;
        if ($playerHaveSpecificCard)&lt;br /&gt;
            return $this-&amp;gt;gamestate-&amp;gt;setPrivateState($this-&amp;gt;getCurrentPlayerId(), 35);&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;some_transition&amp;quot;);        &lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Players turn order ==&lt;br /&gt;
&lt;br /&gt;
When table is created the &amp;quot;natural&amp;quot; player order is assigned to player at random, and stored in &amp;quot;read-only&amp;quot; field &amp;quot;player_no&amp;quot;.&lt;br /&gt;
If you need to create a custom order you should never change natural order but have a separate data structure. &lt;br /&gt;
For example you can alter the players table to add another &amp;quot;custom_order&amp;quot; field, you can use state globals or you can use your natural board database, &lt;br /&gt;
to store meeple_color/position_location pair.&lt;br /&gt;
BGA currently does not provide any API to create/store custom player 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;
If parmeter $bLoop is set to true then last player will points to first (creaing a loop), 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;
Note: This function &#039;&#039;&#039;DOES NOT&#039;&#039;&#039; change the order in database, it only creates a map using key/values as descibed.&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 $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$table = $this-&amp;gt;createNextPlayerTable([3,2,1], false);&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
   [ &lt;br /&gt;
    3 =&amp;gt; 2, &lt;br /&gt;
    2 =&amp;gt; 1, &lt;br /&gt;
    1 =&amp;gt; null,&lt;br /&gt;
    0 =&amp;gt; 3 &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;
=== NotifyAllPlayers ===&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 translated.&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;
* 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 if 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;
&#039;&#039;&#039;Important&#039;&#039;&#039;: When the game page is reloaded (i.e. F5 or when loading turn based game) all previous notifications are replayed as history notifications. These notifications do not trigger notification handlers and are used basically to build the game log. Because of that most of the notification arguments, except i18n, player_id and all arguments used in the message, are removed from these history notifications. If you need additional arguments in history notifications you can add special field &amp;lt;b&amp;gt;preserve&amp;lt;/b&amp;gt; to notification arguments, like this:&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;
        &#039;preserve&#039; =&amp;gt; [ &#039;x&#039;, &#039;y&#039; ]&lt;br /&gt;
     ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In this example, fields x and y will be preserved when replaying history notification at the game load.&lt;br /&gt;
&lt;br /&gt;
==== HTML in Notifications ====&lt;br /&gt;
&lt;br /&gt;
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 replay 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 replay, 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;
==== Recursive Notifications ====&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;
==== Excluding some players ====&lt;br /&gt;
&lt;br /&gt;
Sometimes you want to notify all players of a message but not have it appear in the log of specific players (for example, have every player see &amp;quot;Player X draws a card&amp;quot; but have Player X see &amp;quot;You draw the Ace of Spades&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
To send a notification to all players but have some clients ignore it, send it as normal from the server, but implement &#039;&#039;&#039;setIgnoreNotificationCheck&#039;&#039;&#039; on the client to ignore the message under given conditions. See the X.js documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== NotifyPlayer ===&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;
Note that spectators cannot be notified using this method, because their player ID is not available via loadPlayersBasicInfos() or otherwise. You must use notifyAllPlayers() for any notification that spectators should get.&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 play and can start another game if he/she wants too (with 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;
&#039;&#039;&#039;Important: this should not be used on a player who has already left the game (&amp;quot;zombie&amp;quot;) as leaving/being kicked of the game (outside of the scope of the rules) is not the same as being eliminated from the game (according to the rules), except if in the course of the game, the zombie player is eliminated according to the rules.&#039;&#039;&#039;&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;
; function isAsync()&lt;br /&gt;
: Returns true if game is turn based, false if it is realtime&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;
Note: if you deploy undo support after game is in production this will take into effect for new games only, old games will give user an error if user choses Undo action, but otherwise it should not affect them.&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 matters if you transition to game state not to user state after), this may affect what you end up saving.&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;
&#039;&#039;&#039;Important note&#039;&#039;&#039;: if you are reading game state variable right after restore (without changing state first) it won&#039;t work properly as the global table cache is not automatically refreshed after undoRestorePoint(). So you should either change state immediately to refresh game state values, or use $this-&amp;gt;gamestate-&amp;gt;reloadState() to refresh the state. If you choose to do the latest, be aware that this will bring the state machine back to the state during which the save point snapshot has been taken using undoSavepoint() (which means your transition you do after has to declared in the state which was saved, not in the state which was active for your actionUndo())&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 they are not allowed to do.&lt;br /&gt;
: The error message will be shown to the player as a &amp;quot;red message&amp;quot;.&lt;br /&gt;
: The error message must be translated, make sure you use self::_() or $this-&amp;gt;_() here and NOT clientranslate()&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;
&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 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 check the code of &amp;quot;setupNewGame&amp;quot;. New template already have correct code, but if you editing very old game and it may be absent.&lt;br /&gt;
&lt;br /&gt;
        $gameinfos = $this-&amp;gt;getGameinfos();&lt;br /&gt;
        ...&lt;br /&gt;
        if ($gameinfos[&#039;favorite_colors_support&#039;])&lt;br /&gt;
            $this-&amp;gt;reattributeColorsBasedOnPreferences($players, $gameinfos[&#039;player_colors&#039;]); // this should be above reloadPlayersBasicInfos()&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;
Some important remarks:&lt;br /&gt;
* for some games (i.e. Chess), the color has an influence on a mechanism of the game, most of the time by giving a special advantage to a player (i.e. 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 (Note - you don&#039;t have to pick these, the &amp;quot;closest&amp;quot; color will be found):&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;
The keys may only contain letters and numbers, underscore seems not to be allowed.&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( $key, $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($key)&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_dependency&#039; =&amp;gt; false,  //or if the property is missing, the game is not language dependent&lt;br /&gt;
  &#039;language_dependency&#039; =&amp;gt; true, //all players at the table must speak the same language&lt;br /&gt;
  &#039;language_dependency&#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>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_statistics:_stats.json&amp;diff=12091</id>
		<title>Game statistics: stats.json</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_statistics:_stats.json&amp;diff=12091"/>
		<updated>2022-02-25T13:23:48Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file, you are describing game statistics, that will be displayed at the end of the&lt;br /&gt;
game.&lt;br /&gt;
&lt;br /&gt;
After modifying this file, you must use &amp;quot;Reload  statistics configuration&amp;quot; &lt;br /&gt;
in BGA Studio Control Panel -&amp;gt; Manage Games (&amp;quot;Game Configuration&amp;quot; section):&lt;br /&gt;
&lt;br /&gt;
https://studio.boardgamearena.com/#!studio&lt;br /&gt;
&lt;br /&gt;
There are 2 types of statistics:&lt;br /&gt;
* table statistics, that are not associated to a specific player (i.e.: one value for each game).&lt;br /&gt;
* player statistics, that are associated to each players (i.e.: one value for each player in the game).&lt;br /&gt;
&lt;br /&gt;
Statistics types can be &amp;quot;int&amp;quot; for integer, &amp;quot;float&amp;quot; for floating point values, and &amp;quot;bool&amp;quot; for boolean.&lt;br /&gt;
&lt;br /&gt;
Once you defined your statistics there, you can start using &amp;quot;initStat&amp;quot;, &amp;quot;setStat&amp;quot; and &amp;quot;incStat&amp;quot; methods&lt;br /&gt;
in your game logic, using statistics names defined below.&lt;br /&gt;
See API https://en.doc.boardgamearena.com/Main_game_logic:_yourgamename.game.php#Game_statistics.&lt;br /&gt;
&lt;br /&gt;
If you want to skip some of your statistics according to game variants, do not init it, or call set or inc on it. It will be displayed as &amp;quot;-&amp;quot; (instead of 0 if you init it and don&#039;t update it afterwards)&lt;br /&gt;
&lt;br /&gt;
!! It is not a good idea to modify this file when a game is running !!&lt;br /&gt;
&lt;br /&gt;
If your game is already public on BGA, please read the following before any change:&lt;br /&gt;
https://en.doc.boardgamearena.com/Post-release_phase#Changes_that_breaks_the_games_in_progress&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
* Statistic index is the reference used in setStat/incStat/initStat PHP method&lt;br /&gt;
* Statistic index must contains alphanumerical characters and no space. Example: &#039;turn_played&#039;&lt;br /&gt;
* Statistics IDs must be &amp;gt;=10&lt;br /&gt;
* Two table statistics can&#039;t share the same ID, two player statistics can&#039;t share the same ID&lt;br /&gt;
* A table statistic can have the same ID as a player statistics, however its not recommended unless it is same conceptually (like turns_number is same statistic in both per table and per player)&lt;br /&gt;
* Statistics ID is the reference used by BGA website. If you change the ID, you lost all historical statistic data. Do NOT re-use an ID of a deleted statistic.&lt;br /&gt;
* Statistic name is the English description of the statistic as shown to players&lt;br /&gt;
* The order in which the stats will appear in the endscreen is determined by the order in the array, NOT by the ID. That is helpful for stats which getting added later but need to be higher up in the list.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $stats_type = array(&lt;br /&gt;
&lt;br /&gt;
    // Statistics global to table&lt;br /&gt;
    &amp;quot;table&amp;quot; =&amp;gt; array(&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;turns_number&amp;quot; =&amp;gt; array(&amp;quot;id&amp;quot;=&amp;gt; 10,&lt;br /&gt;
                    &amp;quot;name&amp;quot; =&amp;gt; totranslate(&amp;quot;Number of turns&amp;quot;),&lt;br /&gt;
                    &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;int&amp;quot; ),&lt;br /&gt;
    ),&lt;br /&gt;
    &lt;br /&gt;
    // Statistics existing for each player&lt;br /&gt;
    &amp;quot;player&amp;quot; =&amp;gt; array(&lt;br /&gt;
&lt;br /&gt;
        &amp;quot;turns_number&amp;quot; =&amp;gt; array(&amp;quot;id&amp;quot;=&amp;gt; 10,&lt;br /&gt;
                    &amp;quot;name&amp;quot; =&amp;gt; totranslate(&amp;quot;Number of turns&amp;quot;),&lt;br /&gt;
                    &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;int&amp;quot; ),&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
        &amp;quot;player_teststat1&amp;quot; =&amp;gt; array(   &amp;quot;id&amp;quot;=&amp;gt; 11,&lt;br /&gt;
                                &amp;quot;name&amp;quot; =&amp;gt; totranslate(&amp;quot;player test stat 1&amp;quot;), &lt;br /&gt;
                                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;int&amp;quot; ),&lt;br /&gt;
                                &lt;br /&gt;
        &amp;quot;player_teststat2&amp;quot; =&amp;gt; array(   &amp;quot;id&amp;quot;=&amp;gt; 12,&lt;br /&gt;
                                &amp;quot;name&amp;quot; =&amp;gt; totranslate(&amp;quot;player test stat 2&amp;quot;), &lt;br /&gt;
                                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;float&amp;quot; )&lt;br /&gt;
&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;
Sometimes you may want to display a label instead of a number (for instance if you want to indicate the winning faction as a table statistic, and the faction chosen by each player as a player statistic in a game like Terra Mystica).&lt;br /&gt;
&lt;br /&gt;
You can do this by adding a &amp;quot;value_labels&amp;quot; array following the &amp;quot;table&amp;quot; and &amp;quot;players&amp;quot; array. Please note that the labels apply to both table and player statistics, so you should pay attention to use the same statistic number for the same type of statistic (or to skip one number if labelling should not be applied for both)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;value_labels&amp;quot; =&amp;gt; array(&lt;br /&gt;
		11 =&amp;gt; array( &lt;br /&gt;
			0 =&amp;gt; totranslate(&amp;quot;None (or tied)&amp;quot;),&lt;br /&gt;
			1 =&amp;gt; totranslate(&amp;quot;Auren&amp;quot;), &lt;br /&gt;
			2 =&amp;gt; totranslate(&amp;quot;Witches&amp;quot;), &lt;br /&gt;
			3 =&amp;gt; totranslate(&amp;quot;Fakirs&amp;quot;), &lt;br /&gt;
			4 =&amp;gt; totranslate(&amp;quot;Nomads&amp;quot;), &lt;br /&gt;
			5 =&amp;gt; totranslate(&amp;quot;Chaos Magicians&amp;quot;), &lt;br /&gt;
			6 =&amp;gt; totranslate(&amp;quot;Giants&amp;quot;), &lt;br /&gt;
			7 =&amp;gt; totranslate(&amp;quot;Swarmlings&amp;quot;), &lt;br /&gt;
			8 =&amp;gt; totranslate(&amp;quot;Mermaids&amp;quot;), &lt;br /&gt;
			9 =&amp;gt; totranslate(&amp;quot;Dwarves&amp;quot;), &lt;br /&gt;
			10 =&amp;gt; totranslate(&amp;quot;Engineers&amp;quot;), &lt;br /&gt;
			11 =&amp;gt; totranslate(&amp;quot;Halflings&amp;quot;), &lt;br /&gt;
			12 =&amp;gt; totranslate(&amp;quot;Cultists&amp;quot;), &lt;br /&gt;
			13 =&amp;gt; totranslate(&amp;quot;Alchemists&amp;quot;), &lt;br /&gt;
			14 =&amp;gt; totranslate(&amp;quot;Darklings&amp;quot;), &lt;br /&gt;
		),&lt;br /&gt;
	)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to consider some internal game statistics for game developer, publisher or admins&#039;s purppose only, simply add the following extra property : &amp;quot;display&amp;quot; =&amp;gt; &amp;quot;limited&amp;quot;. For instance :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        &amp;quot;player_teststat2&amp;quot; =&amp;gt; array(   &amp;quot;id&amp;quot;=&amp;gt; 12,&lt;br /&gt;
                                &amp;quot;name&amp;quot; =&amp;gt; totranslate(&amp;quot;player test stat 2&amp;quot;), &lt;br /&gt;
                                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;float&amp;quot;,&lt;br /&gt;
                                &amp;quot;display&amp;quot; =&amp;gt; &amp;quot;limited&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=11506</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=11506"/>
		<updated>2022-01-20T14:02:52Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Projects on 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 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/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;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Studio&amp;diff=11475</id>
		<title>Studio</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Studio&amp;diff=11475"/>
		<updated>2022-01-19T12:47:38Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Other resources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
[[File:Bga_studio_small.jpg]]&lt;br /&gt;
&lt;br /&gt;
Note: Please DO NOT translate Studio Documentation, so that there can be one place where you can find the latest information available.&lt;br /&gt;
&lt;br /&gt;
== What is Board Game Arena Studio? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Board Game Arena Studio&#039;&#039;&#039; is a platform to build online board game adaptations using the Board Game Arena platform.&lt;br /&gt;
&lt;br /&gt;
It is open to any gamer with software development skills :)&lt;br /&gt;
&lt;br /&gt;
BGA Studio website: https://studio.boardgamearena.com&lt;br /&gt;
&lt;br /&gt;
Original announcement on BGA forum: https://forum.boardgamearena.com/viewtopic.php?f=10&amp;amp;t=1973&lt;br /&gt;
&lt;br /&gt;
== Discover BGA Studio in 5 presentations ==&lt;br /&gt;
&lt;br /&gt;
Why, how, what... to start discovering BGA Studio, we prepared 5 &amp;quot;powerpoint&amp;quot; presentations for you:&lt;br /&gt;
&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/5-reasons-why-you-should-use-bga-studio-for-your-online-board-game 5 reasons why you should use BGA Studio for your online board game] (or [http://en.doc.boardgamearena.com/images/5/58/1-why-developing.pdf ‎Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/the-8-steps-to-create-a-board-game-on-board-game-arena The 8 steps to create a board game on Board Game Arena] (or [http://en.doc.boardgamearena.com/images/1/1e/2-8-steps-to-realize.pdf Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/the-bga-framework-at-a-glance The BGA Framework at a glance] (or [http://en.doc.boardgamearena.com/images/7/79/3-thebgaframework.pdf Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine Focus on BGA game state machine] (or [http://en.doc.boardgamearena.com/images/9/98/4-gamestates.pdf Download as PDF])&lt;br /&gt;
* [http://www.slideshare.net/boardgamearena/bga-studio-guidelines BGA developers guidelines] (or [http://en.doc.boardgamearena.com/images/7/76/5-guidelines.pdf ‎Download as PDF])&lt;br /&gt;
&lt;br /&gt;
== How to join the BGA developer team? ==&lt;br /&gt;
&lt;br /&gt;
Please see this page: [[How to join BGA developer team?]]&lt;br /&gt;
&lt;br /&gt;
== Great, I&#039;m in! ... How should I start? ==&lt;br /&gt;
&lt;br /&gt;
If you didn&#039;t already, check the presentations at the top of this page to get the basics.&lt;br /&gt;
&lt;br /&gt;
Then, you should checkout the [[First steps with BGA Studio]] to make sure that runs fine.&lt;br /&gt;
&lt;br /&gt;
After that, we strongly advise you to take one of these game creation tutorials:&lt;br /&gt;
* [[Tutorial reversi]] - an abstract strategy game played on an 8×8 uncheckered board for 2 players&lt;br /&gt;
* [[Tutorial gomoku]] - an abstract strategy game tic-tac-toe style for 2 players&lt;br /&gt;
* [[Tutorial hearts]] - a card game for 4 players&lt;br /&gt;
&lt;br /&gt;
Then start editing files and see what happens! ;)&lt;br /&gt;
&lt;br /&gt;
Once you&#039;re done with tutorials, you can start a real game (or join existing project)&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]] &lt;br /&gt;
&lt;br /&gt;
If you have any questions, please check out the &#039;&#039;&#039;[[Studio FAQ]]&#039;&#039;&#039; first, then if you didn&#039;t find the answer you were looking for, please post your question on the [http://forum.boardgamearena.com/viewforum.php?f=12 &#039;&#039;&#039;development forum&#039;&#039;&#039;].&lt;br /&gt;
&lt;br /&gt;
== BGA Studio documentation ==&lt;br /&gt;
&lt;br /&gt;
=== BGA Studio Framework reference ===&lt;br /&gt;
&lt;br /&gt;
This part of the documentation focuses on the development framework itself: functions and methods available to build your game.&lt;br /&gt;
&lt;br /&gt;
[[Studio file reference|File structure of a BGA game]]&lt;br /&gt;
&lt;br /&gt;
==== Game logic (Server side) ====&lt;br /&gt;
&lt;br /&gt;
* [[Main game logic: yourgamename.game.php]]&lt;br /&gt;
* [[Your game state machine: states.inc.php]]&lt;br /&gt;
* [[Game database model: dbmodel.sql]]&lt;br /&gt;
* [[Players actions: yourgamename.action.php]]&lt;br /&gt;
* [[Game material description: material.inc.php]]&lt;br /&gt;
* [[Game statistics: stats.inc.php]]&lt;br /&gt;
&lt;br /&gt;
==== Game interface (Client side) ====&lt;br /&gt;
&lt;br /&gt;
* [[Game interface logic: yourgamename.js]]&lt;br /&gt;
* [[Game art: img directory]]&lt;br /&gt;
* [[Game interface stylesheet: yourgamename.css]]&lt;br /&gt;
* [[Game layout: view and template: yourgamename.view.php and yourgamename_yourgamename.tpl]]&lt;br /&gt;
* [[Your game mobile version]]&lt;br /&gt;
&lt;br /&gt;
==== Other components ====&lt;br /&gt;
&lt;br /&gt;
* [[Translations]] (how to make your game translatable)&lt;br /&gt;
* [[Game options and preferences: gameoptions.inc.php]]&lt;br /&gt;
* [[Game meta-information: gameinfos.inc.php]]&lt;br /&gt;
* [[Game replay]]&lt;br /&gt;
* [[3D]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== BGA Studio game components reference ===&lt;br /&gt;
&lt;br /&gt;
Game components are useful tools you can use in your game adaptations.&lt;br /&gt;
&lt;br /&gt;
JS:&lt;br /&gt;
&lt;br /&gt;
* [[Counter]]: a JS component to manage a counter that can increase/decrease (ex: player&#039;s score).&lt;br /&gt;
* [[Scrollmap]]: a JS component to manage a scrollable game area (useful when the game area can be infinite. Examples:  Saboteur or Takenoko games).&lt;br /&gt;
* [[Stock]]: a JS component to manage and display a set of game elements displayed at a position.&lt;br /&gt;
* [[Zone]]: a JS component to manage a zone of the board where several game elements can come and leave, but should be well displayed together (See for example: token&#039;s places at Can&#039;t Stop).&lt;br /&gt;
* [[Draggable]]: a JS component to manage drag&#039;n&#039;drop actions.&lt;br /&gt;
* [[ExpandableSection]]: a JS component to manage a rectangular block of HTML than can be displayed/hidden.&lt;br /&gt;
* [[Anti-Stock]]:Code snippets in ValinaJS/HTML5 to do what stock does (that is if you cannot beat Stock into submission)&lt;br /&gt;
&lt;br /&gt;
PHP:&lt;br /&gt;
* [[Deck]]: a PHP component to manage cards (deck, hands, picking cards, moving cards, shuffle deck, ...).&lt;br /&gt;
&lt;br /&gt;
Reference for classes in game class hierarchy&lt;br /&gt;
&lt;br /&gt;
* [[Table]]: a PHP class that you inherit from for the game php&lt;br /&gt;
&lt;br /&gt;
=== BGA Studio user guide ===&lt;br /&gt;
&lt;br /&gt;
This part of the documentation is a user guide for the BGA Studio online development environment.&lt;br /&gt;
&lt;br /&gt;
Lifecycle&lt;br /&gt;
&lt;br /&gt;
* [[BGA game Lifecycle]]&lt;br /&gt;
* [[Create a game in BGA Studio: Complete Walkthrough]]&lt;br /&gt;
* [[Pre-release checklist]] - Go throught this list if you think you done development&lt;br /&gt;
* [[Post-release phase]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tools and Advice&lt;br /&gt;
* [[BGA Studio Guidelines]]&lt;br /&gt;
* [[I wish I knew this when I started]] - one liners on most common missed features, mistakes, etc with further doc references&lt;br /&gt;
* [[Tools and tips of BGA Studio]] - Tips and instructions on setting up development environment&lt;br /&gt;
** [[Practical debugging]] - Tips focused on debugging&lt;br /&gt;
** [[Studio logs]] - Instructions for log access&lt;br /&gt;
** [[Troubleshooting]] - Most common &amp;quot;I am really stuck&amp;quot; situations&lt;br /&gt;
* [[BGA Studio Cookbook]] - Tips and instructions on using API&#039;s, libraries and frameworks&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;
* [[Studio FAQ]]&lt;br /&gt;
&lt;br /&gt;
Sharing&lt;br /&gt;
* [[Common board game elements image resources]] - Dice, meeples, cubes, etc&lt;br /&gt;
* [[BGA Code Sharing]] - Shared resources, projects on git hub, common code, other links&lt;br /&gt;
&lt;br /&gt;
== Other resources ==&lt;br /&gt;
&lt;br /&gt;
[http://forum.boardgamearena.com/viewforum.php?f=12 Development forum]&lt;br /&gt;
&lt;br /&gt;
[https://studio.boardgamearena.com/bugs Bug tracking system FOR STUDIO issues and APIs]&lt;br /&gt;
&lt;br /&gt;
DISCORD chat server/room invite link https://discord.gg/YxEUacY if it does not work check this topic https://forum.boardgamearena.com/viewtopic.php?f=12&amp;amp;t=17403&amp;amp;hilit=discord&lt;br /&gt;
&lt;br /&gt;
== Current Running versions of framework and tools ==&lt;br /&gt;
&lt;br /&gt;
Versions currently used by BGA framework on STUDIO (as of May 2020):&lt;br /&gt;
&lt;br /&gt;
Dojo Toolkit 1.15&lt;br /&gt;
&lt;br /&gt;
PHP version: 7.2.12&lt;br /&gt;
&lt;br /&gt;
SQL: MySQL 5.7&lt;br /&gt;
&lt;br /&gt;
JS/CSS/HTML: limited by what minimization tools support,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PHP Version on Prod is 7.4&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=11425</id>
		<title>Options and preferences: gameoptions.json, gamepreferences.json</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=11425"/>
		<updated>2022-01-13T10:02:19Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Game Options */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file, you can define your game options (i.e. game variants) and user preferences.&lt;br /&gt;
   &lt;br /&gt;
Note: If your game has no variants or preferences, you don&#039;t have to modify this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; after you edited this file and syncronized to ftp folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes &#039;&#039;&#039;to take effect&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Make sure you understand difference bettween options and preferences:&lt;br /&gt;
* Game options - something usually in the rule book defined as &amp;quot;variant&amp;quot; (except for 2,3,X people - that is automatically handled - you can query it)&lt;br /&gt;
* User preferences - personal choices of each player only visible to that specific player - i.e. layout, either or not to prompt for action, ether or not auto-opt in in some actions, etc&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options are selected by the table creator and usually correspond to game variants, for example if the game includes expansions or certain special rules.&lt;br /&gt;
&lt;br /&gt;
These variants are defined in gameoptions.inc.php as the $game_options variable:  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is a pair in the format: number =&amp;gt; &#039;option description array&#039;. &lt;br /&gt;
&lt;br /&gt;
All options defined in this file should have a corresponding &amp;quot;game state label&amp;quot; with the same ID (see &amp;quot;initGameStateLabels&amp;quot; in yourgame.game.php)&lt;br /&gt;
&lt;br /&gt;
             self::initGameStateLabels ( array (&lt;br /&gt;
                        ...&lt;br /&gt;
                        &amp;quot;my_game_variant&amp;quot; =&amp;gt; 100,&lt;br /&gt;
              ) );&lt;br /&gt;
&lt;br /&gt;
Numbers have to be exactly from 100 to 199 (there can be gaps).&lt;br /&gt;
&lt;br /&gt;
That is how you access them during runtime:&lt;br /&gt;
&lt;br /&gt;
    public function isSecondVariant() {&lt;br /&gt;
        return $this-&amp;gt;getGameStateValue(&#039;my_game_variant&#039;) == 2;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Or this&lt;br /&gt;
    $this-&amp;gt;gamestate-&amp;gt;table_globals[100]&lt;br /&gt;
&lt;br /&gt;
The following are the parameters of option description array:&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. The name of the option visible for table creator. Value must be wrapped in totranslate function.&lt;br /&gt;
* &#039;&#039;&#039;values&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. The array (map) of values with additional parameters per value.&lt;br /&gt;
** &#039;&#039;&#039;name&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. String representation of the numeric value visible to table creator. Value must be wrapped in totranslate function.&lt;br /&gt;
** &#039;&#039;&#039;description&#039;&#039;&#039; - String description of this value to use when the name of the option is not self-explanatory. Displayed at the table under the option when this value is selected.&lt;br /&gt;
** &#039;&#039;&#039;tmdisplay&#039;&#039;&#039; - String representation of the option visible in the table description in the lobby. Usually if a variant values are On and Off (default), the tmdisplay would be same as description name when On, and nothing (empty string) when Off. (&#039;&#039;&#039;Warning&#039;&#039;&#039;: due to some caching, a change in tmdisplay may not be effective immediately in the studio, even after forcing a reload of gameoptions.inc.php.) &#039;&#039;&#039;Pro Tip:&#039;&#039;&#039; You can use this as a pre-game communication by adding fake options that just do nothing in the game but make it easier to find other player wanted the same game configuration (see the crew deep sea for example).&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&lt;br /&gt;
** &#039;&#039;&#039;firstgameonly&#039;&#039;&#039; - Set to true if this option is recommended only for the first game (discovery option)&lt;br /&gt;
** &#039;&#039;&#039;beta&#039;&#039;&#039; - Option in beta stage on development&lt;br /&gt;
** &#039;&#039;&#039;premium&#039;&#039;&#039; - Option can be only used by premium members&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; - indicates the default value to use for this option (optional, if not present the first value listed is the default)&lt;br /&gt;
* &#039;&#039;&#039;displaycondition&#039;&#039;&#039; - checks the conditions before displaying the option for selection. All conditions must be true for the option to display. Supported condition types:&lt;br /&gt;
** &#039;&#039;minplayers&#039;&#039; condition ensures at least this many players&lt;br /&gt;
** &#039;&#039;maxplayers&#039;&#039; conditions ensure at most this many players&lt;br /&gt;
** &#039;&#039;otheroption&#039;&#039; condition ensures another option is set to this given values. &lt;br /&gt;
** &#039;&#039;otheroptionisnot&#039;&#039; conditions ensure another option is NOT set to this given values&lt;br /&gt;
* &#039;&#039;&#039;displayconditionoperand&#039;&#039;&#039; - can be &#039;and&#039; (this is the default) or &#039;or&#039;. Allows to change the behaviour to display the option if one of the conditions is true instead of all of them.&lt;br /&gt;
* &#039;&#039;&#039;startcondition&#039;&#039;&#039; - checks the conditions (on options VALUES) before starting the game. All conditions must be true for the game to start, otherwise players will get a red error message when attempting to begin the game. Supported condition types:&lt;br /&gt;
** &#039;&#039;minplayers&#039;&#039; condition ensures at least this many players&lt;br /&gt;
** &#039;&#039;maxplayers&#039;&#039; conditions ensure at most this many players&lt;br /&gt;
** &#039;&#039;otheroption&#039;&#039; conditions ensure another option is set to this given values. That works the same as in &#039;&#039;&#039;displaycondition&#039;&#039;&#039;.&lt;br /&gt;
** &#039;&#039;otheroptionisnot&#039;&#039; conditions ensure another option is NOT set to this given value.  That works the same as in &#039;&#039;&#039;displaycondition&#039;&#039;&#039;.&lt;br /&gt;
** &#039;&#039;gamestartonly&#039;&#039; if you have options that are exclusive, for example for a solo mode: you can have a maxplayer of 1 for one option and a minplayer of 2 for an other option and you will be stuck. See below for an example.&lt;br /&gt;
* &#039;&#039;&#039;notdisplayedmessage&#039;&#039;&#039; - if option is not suppose to be visible because of displaycondition but this is set, the text will be visible instead of combo drop down&lt;br /&gt;
&lt;br /&gt;
Common options for all tables (reserved range 200-299):&lt;br /&gt;
*201 (const GAMESTATE_RATING_MODE) - ELO OFF (aka Training mode), &lt;br /&gt;
*200 (const GAMESTATE_CLOCK_MODE) - game speed profile, array(0,1,2) - realtime (technically &amp;lt;10 realtime but you cannot define range in php), values &amp;gt;=10 - turn based (currently 10..21)&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 $game_options = array(&lt;br /&gt;
     100 =&amp;gt; array(&lt;br /&gt;
         &#039;name&#039; =&amp;gt; totranslate(&#039;my game option&#039;),&lt;br /&gt;
         &#039;values&#039; =&amp;gt; array(&lt;br /&gt;
             // A simple value for this option:&lt;br /&gt;
             1 =&amp;gt; array(&lt;br /&gt;
                 &#039;name&#039; =&amp;gt; totranslate(&#039;option 1&#039;)&lt;br /&gt;
             ),&lt;br /&gt;
&lt;br /&gt;
             // A simple value for this option.&lt;br /&gt;
             // If this value is chosen, the value of &amp;quot;tmdisplay&amp;quot; is displayed in the game lobby&lt;br /&gt;
             2 =&amp;gt; array(&lt;br /&gt;
                 &#039;name&#039; =&amp;gt; totranslate(&#039;option 2&#039;),&lt;br /&gt;
                 &#039;tmdisplay&#039; =&amp;gt; totranslate(&#039;option 2&#039;)&lt;br /&gt;
             ),&lt;br /&gt;
&lt;br /&gt;
             // Another value, with other options:&lt;br /&gt;
             //  beta=true =&amp;gt; this option is in beta version right now.&lt;br /&gt;
             //  nobeginner=true  =&amp;gt;  this option is not recommended for beginners&lt;br /&gt;
             3 =&amp;gt; array(&lt;br /&gt;
                 &#039;name&#039; =&amp;gt; totranslate(&#039;option 3&#039;),&lt;br /&gt;
                 &#039;beta&#039; =&amp;gt; true,&lt;br /&gt;
                 &#039;nobeginner&#039; =&amp;gt; true&lt;br /&gt;
             ),&lt;br /&gt;
         ),&lt;br /&gt;
         &#039;default&#039; =&amp;gt; 1&lt;br /&gt;
     ),&lt;br /&gt;
     &lt;br /&gt;
     101 =&amp;gt; array(&lt;br /&gt;
         &#039;name&#039; =&amp;gt; totranslate(&#039;Draft variant&#039;),&lt;br /&gt;
         &#039;values&#039; =&amp;gt; array(&lt;br /&gt;
             1 =&amp;gt; array(&lt;br /&gt;
                 &#039;name&#039; =&amp;gt; totranslate(&#039;No draft&#039;)&lt;br /&gt;
             ),&lt;br /&gt;
             2 =&amp;gt; array(&lt;br /&gt;
                 &#039;name&#039; =&amp;gt; totranslate(&#039;Draft&#039;),&lt;br /&gt;
                 &#039;tmdisplay&#039; =&amp;gt; totranslate(&#039;Draft&#039;),&lt;br /&gt;
                 &#039;premium&#039; =&amp;gt; true,&lt;br /&gt;
                 &#039;nobeginner&#039; =&amp;gt; true&lt;br /&gt;
             ),&lt;br /&gt;
         ),&lt;br /&gt;
         &#039;displaycondition&#039; =&amp;gt; array( &lt;br /&gt;
             // Note: do not display this option unless these conditions are met&lt;br /&gt;
             array(&lt;br /&gt;
                 &#039;type&#039; =&amp;gt; &#039;otheroption&#039;,&lt;br /&gt;
                 &#039;id&#039; =&amp;gt; 100, // Game specific option defined in the same array above&lt;br /&gt;
                 &#039;value&#039; =&amp;gt; array(2, 3, 4)&lt;br /&gt;
             ),&lt;br /&gt;
             // Note: do not display this option unless these conditions are met&lt;br /&gt;
            array( &#039;type&#039; =&amp;gt; &#039;otheroption&#039;, &lt;br /&gt;
                 &#039;id&#039; =&amp;gt; 201, // ELO OFF hardcoded framework option&lt;br /&gt;
                 &#039;value&#039; =&amp;gt; 1 // 1 if OFF&lt;br /&gt;
            )&lt;br /&gt;
         ),&lt;br /&gt;
&lt;br /&gt;
         &#039;startcondition&#039; =&amp;gt; array(&lt;br /&gt;
             1 =&amp;gt; array(),&lt;br /&gt;
             2 =&amp;gt; array(&lt;br /&gt;
                 array(&lt;br /&gt;
                     &#039;type&#039; =&amp;gt; &#039;maxplayers&#039;,&lt;br /&gt;
                     &#039;value&#039; =&amp;gt; 3,&lt;br /&gt;
                     &#039;message&#039; =&amp;gt; totranslate(&#039;Draft option is available for 3 players maximum.&#039;)&lt;br /&gt;
                 )&lt;br /&gt;
             ),&lt;br /&gt;
         ),&lt;br /&gt;
     ),&lt;br /&gt;
     &lt;br /&gt;
     102 =&amp;gt; array(&lt;br /&gt;
         &#039;name&#039; =&amp;gt; totranslate(&#039;Takeovers&#039;),&lt;br /&gt;
         &#039;values&#039; =&amp;gt; array(&lt;br /&gt;
             2 =&amp;gt; array(&lt;br /&gt;
                 &#039;name&#039; =&amp;gt; totranslate(&#039;No takeover&#039;)&lt;br /&gt;
             ),&lt;br /&gt;
             1 =&amp;gt; array(&lt;br /&gt;
                 &#039;name&#039; =&amp;gt; totranslate(&#039;Allow takeovers&#039;),&lt;br /&gt;
                 &#039;tmdisplay&#039; =&amp;gt; totranslate(&#039;Takeovers&#039;),&lt;br /&gt;
                 &#039;premium&#039; =&amp;gt; true,&lt;br /&gt;
                 &#039;nobeginner&#039; =&amp;gt; true&lt;br /&gt;
             ),&lt;br /&gt;
         ),&lt;br /&gt;
         &#039;displaycondition&#039; =&amp;gt; array( // Note: do not display this option unless these conditions are met&lt;br /&gt;
             array(&lt;br /&gt;
                 &#039;type&#039; =&amp;gt; &#039;otheroption&#039;,&lt;br /&gt;
                 &#039;id&#039; =&amp;gt; 100,&lt;br /&gt;
                 &#039;value&#039; =&amp;gt; array(3, 4)&lt;br /&gt;
             )&lt;br /&gt;
         ),&lt;br /&gt;
         &#039;startcondition&#039; =&amp;gt; array(&lt;br /&gt;
             2 =&amp;gt; array(),&lt;br /&gt;
             1 =&amp;gt; array(&lt;br /&gt;
                 array(&lt;br /&gt;
                     &#039;type&#039; =&amp;gt; &#039;maxplayers&#039;,&lt;br /&gt;
                     &#039;value&#039; =&amp;gt; 2,&lt;br /&gt;
                     &#039;message&#039; =&amp;gt; totranslate(&#039;Rebel vs Imperium Takeover Scenario is available for 2 players only.&#039;)&lt;br /&gt;
                 )&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;
Example of option that condition on ELO off&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$game_options = array(&lt;br /&gt;
&lt;br /&gt;
        100 =&amp;gt; array(&lt;br /&gt;
                &#039;name&#039; =&amp;gt; totranslate(&#039;Learning Game (No Research)&#039;),&lt;br /&gt;
                &#039;values&#039; =&amp;gt; array(&lt;br /&gt;
                        &lt;br /&gt;
                        1 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate(&#039;Off&#039;), &#039;tmdisplay&#039; =&amp;gt; totranslate(&#039;&#039;) ),&lt;br /&gt;
                        2 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate(&#039;On&#039;), &#039;tmdisplay&#039; =&amp;gt; totranslate(&#039;Learning Game&#039;) ),&lt;br /&gt;
                        &lt;br /&gt;
                ),&lt;br /&gt;
                &#039;displaycondition&#039; =&amp;gt; array(&lt;br /&gt;
                        // Note: do not display this option unless these conditions are met&lt;br /&gt;
                        array( &#039;type&#039; =&amp;gt; &#039;otheroption&#039;,&lt;br /&gt;
                                &#039;id&#039; =&amp;gt; 201, // ELO OFF hardcoded framework option&lt;br /&gt;
                                &#039;value&#039; =&amp;gt; 1, // 1 if OFF&lt;br /&gt;
&lt;br /&gt;
                        )&lt;br /&gt;
                ),&lt;br /&gt;
                &#039;notdisplayedmessage&#039; =&amp;gt; totranslate(&#039;Learning variant available only with ELO off&#039;)&lt;br /&gt;
                ),&lt;br /&gt;
&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of condition that is only available for REALTIME game mode&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&#039;displaycondition&#039; =&amp;gt; array(&lt;br /&gt;
    // Note: do not display this option until these conditions are met - game speed is selected as realtime&lt;br /&gt;
    array( &#039;type&#039; =&amp;gt; &#039;otheroption&#039;, &#039;id&#039; =&amp;gt; GAMESTATE_CLOCK_MODE, &#039;value&#039; =&amp;gt; array(0,1,2) )&lt;br /&gt;
),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of using condition on your own option&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        102 =&amp;gt; array(&lt;br /&gt;
                &#039;name&#039; =&amp;gt; totranslate(&#039;Scenarios&#039;),&lt;br /&gt;
                &#039;values&#039; =&amp;gt; array(&lt;br /&gt;
                        1 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate(&#039;Off&#039;),&lt;br /&gt;
                                &#039;nobeginner&#039; =&amp;gt; false  ),&lt;br /&gt;
                        2 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate(&#039;On&#039;), &#039;tmdisplay&#039; =&amp;gt; totranslate(&#039;Scenarios&#039;),&lt;br /&gt;
                                &#039;nobeginner&#039; =&amp;gt; true  ),&lt;br /&gt;
                        &lt;br /&gt;
                ),&lt;br /&gt;
                &#039;displaycondition&#039; =&amp;gt; array(&lt;br /&gt;
                        // Note: do not display this option unless these conditions are met&lt;br /&gt;
                        array( &#039;type&#039; =&amp;gt; &#039;otheroptionisnot&#039;,&lt;br /&gt;
                                &#039;id&#039; =&amp;gt; 100, // learning variant&lt;br /&gt;
                                &#039;value&#039; =&amp;gt; 2, // 1 if OFF,2 is ON&lt;br /&gt;
                                &lt;br /&gt;
                        )&lt;br /&gt;
                ),&lt;br /&gt;
                &#039;notdisplayedmessage&#039; =&amp;gt; totranslate(&#039;Scenarios variant is not available if Learning variant is chosen&#039;)&lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of &#039;&#039;gamestartonly&#039;&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     102 =&amp;gt; array(&lt;br /&gt;
         &#039;name&#039; =&amp;gt; totranslate(&#039;Mode&#039;),&lt;br /&gt;
         &#039;values&#039; =&amp;gt; array(&lt;br /&gt;
             1 =&amp;gt; array(&lt;br /&gt;
                 &#039;name&#039; =&amp;gt; totranslate(&#039;Normal&#039;)&lt;br /&gt;
             ),&lt;br /&gt;
             2 =&amp;gt; array(&lt;br /&gt;
                 &#039;name&#039; =&amp;gt; totranslate(&#039;Solo&#039;),&lt;br /&gt;
             ),&lt;br /&gt;
         ),&lt;br /&gt;
         &#039;startcondition&#039; =&amp;gt; array(&lt;br /&gt;
             1 =&amp;gt; array(&lt;br /&gt;
                 array(&lt;br /&gt;
                     &#039;type&#039; =&amp;gt; &#039;minplayers&#039;,&lt;br /&gt;
                     &#039;value&#039; =&amp;gt; 2,&lt;br /&gt;
                     &#039;message&#039; =&amp;gt; totranslate(&#039;Normal mode is 2 for players or more&#039;)&lt;br /&gt;
                     &#039;gamestartonly&#039; =&amp;gt; true,&lt;br /&gt;
                 )&lt;br /&gt;
             ),&lt;br /&gt;
             1 =&amp;gt; array(&lt;br /&gt;
                 array(&lt;br /&gt;
                     &#039;type&#039; =&amp;gt; &#039;maxplayers&#039;,&lt;br /&gt;
                     &#039;value&#039; =&amp;gt; 1,&lt;br /&gt;
                     &#039;message&#039; =&amp;gt; totranslate(&#039;Solo mode is for 1 player&#039;)&lt;br /&gt;
                     &#039;gamestartonly&#039; =&amp;gt; true,&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;
== User Preferences ==&lt;br /&gt;
&lt;br /&gt;
User preferences is something cosmetic about the game interface which however can create user wars, so you can satisfy all users&lt;br /&gt;
by giving them individual preferences. You should use this only if it significantly improves the interface for a large proportion of users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$game_preferences = array(&lt;br /&gt;
    100 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; totranslate(&#039;Notation style&#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;Classic&#039; ), &#039;cssPref&#039; =&amp;gt; &#039;notation_classic&#039; ),&lt;br /&gt;
            2 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate( &#039;Tournament&#039; ), &#039;cssPref&#039; =&amp;gt; &#039;notation_tournament&#039; )&lt;br /&gt;
        ),&lt;br /&gt;
        &#039;default&#039; =&amp;gt; 2&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is two ways to check/apply this. In java Script&lt;br /&gt;
&lt;br /&gt;
  if (this.prefs[100].value == 2) ...&lt;br /&gt;
&lt;br /&gt;
This checks if preferences 100 has selected value 2.&lt;br /&gt;
&lt;br /&gt;
Second, if cssPref specified it will be applied to the &#039;&#039;&#039;&amp;lt;html&amp;gt;&#039;&#039;&#039; tag. So you can use different css styling for the preference. Note: it seems needed to set needReload to true for that class change to be effective.&lt;br /&gt;
&lt;br /&gt;
As user you have to select them from the Gear menu when game is started. On studio only user0 will have it actually working (bug?).&lt;br /&gt;
&lt;br /&gt;
The following are the parameters of preferences description array:&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. The name of the preference. Value will be automatically wrapped in totranslate if you don&#039;t.&lt;br /&gt;
* &#039;&#039;&#039;needReload&#039;&#039;&#039; - If set to true, the game interface will auto-reload after a change of the preference.&lt;br /&gt;
* &#039;&#039;&#039;values&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. The array (map) of values with additional parameters per value.&lt;br /&gt;
** &#039;&#039;&#039;name&#039;&#039;&#039; - &#039;&#039;&#039;mandatory&#039;&#039;&#039;. String representation of the numeric value. Value will be automatically wrapped in totranslate if you don&#039;t.&lt;br /&gt;
** &#039;&#039;&#039;cssPref&#039;&#039;&#039; - CSS class to add to the &#039;&#039;&#039;&amp;lt;html&amp;gt;&#039;&#039;&#039; tag. Currently it is added or removed only after a reload (see needReload).&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; - Indicates the default value to use for this preference (optional, if not present the first value listed is the default).&lt;br /&gt;
&lt;br /&gt;
=== Listening for preference changes ===&lt;br /&gt;
&lt;br /&gt;
The BGA framework lacks any callback to notify your game when a user preference is changed (see [https://studio.boardgamearena.com/bug?id=36 proposal #36]), but you can create your own if you need to run some UI code in response to a preference change.&lt;br /&gt;
&lt;br /&gt;
; In ggg.js&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setup: function (gamedatas) {&lt;br /&gt;
      ... // your setup code here&lt;br /&gt;
      this.setupPreference();&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
    setupPreference: function () {&lt;br /&gt;
      // Extract the ID and value from the UI control&lt;br /&gt;
      var _this = this;&lt;br /&gt;
      function onchange(e) {&lt;br /&gt;
        var match = e.target.id.match(/^preference_[cf]ontrol_(\d+)$/);&lt;br /&gt;
        if (!match) {&lt;br /&gt;
          return;&lt;br /&gt;
        }&lt;br /&gt;
        var prefId = +match[1];&lt;br /&gt;
        var prefValue = +e.target.value;&lt;br /&gt;
        _this.prefs[prefId].value = prefValue;&lt;br /&gt;
        _this.onPreferenceChange(prefId, prefValue);&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      // Call onPreferenceChange() when any value changes&lt;br /&gt;
      dojo.query(&amp;quot;.preference_control&amp;quot;).connect(&amp;quot;onchange&amp;quot;, onchange);&lt;br /&gt;
      &lt;br /&gt;
      // Call onPreferenceChange() now&lt;br /&gt;
      dojo.forEach(&lt;br /&gt;
        dojo.query(&amp;quot;#ingame_menu_content .preference_control&amp;quot;),&lt;br /&gt;
        function (el) {&lt;br /&gt;
          onchange({ target: el });&lt;br /&gt;
        }&lt;br /&gt;
      );&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
    onPreferenceChange: function (prefId, prefValue) {&lt;br /&gt;
      console.log(&amp;quot;Preference changed&amp;quot;, prefId, prefValue);&lt;br /&gt;
      ... // your code here to handle the change&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Updating preference from code ===&lt;br /&gt;
The BGA framework lacks any method to update a user preference from the code (see [https://studio.boardgamearena.com/bug?id=36 proposal #36]), but you can create your own if you need to.&lt;br /&gt;
&lt;br /&gt;
; In ggg.js&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    updatePreference: function(prefId, newValue) {&lt;br /&gt;
        // Select preference value in control:&lt;br /&gt;
        dojo.query(&#039;#preference_control_&#039; + prefId + &#039; &amp;gt; option[value=&amp;quot;&#039; + newValue&lt;br /&gt;
        // Also select fontrol to fix a BGA framework bug:&lt;br /&gt;
            + &#039;&amp;quot;], #preference_fontrol_&#039; + prefId + &#039; &amp;gt; option[value=&amp;quot;&#039; + newValue&lt;br /&gt;
            + &#039;&amp;quot;]&#039;).forEach((value) =&amp;gt; dojo.attr(value, &#039;selected&#039;, true));&lt;br /&gt;
        // Generate change event on control to trigger callbacks:&lt;br /&gt;
        const newEvt = document.createEvent(&#039;HTMLEvents&#039;);&lt;br /&gt;
        newEvt.initEvent(&#039;change&#039;, false, true);&lt;br /&gt;
        $(&#039;preference_control_&#039; + prefId).dispatchEvent(newEvt);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Accessing User Preferences on the server ===&lt;br /&gt;
Surprise, surprise - this is lacking too. Mostly.&lt;br /&gt;
There is a variable you can acesses called $this-&amp;gt;player_preferences.&lt;br /&gt;
This contains table of user preferences, ONLY accessible in setupNewGame().&lt;br /&gt;
You can use this to populate a table that you manage yourself.&lt;br /&gt;
The table has to be updated when user changes preference (and you have to hook up a lister and initiate a special axac call out-of-turn).&lt;br /&gt;
Check the code of Agricola for details but this should work:.&lt;br /&gt;
&lt;br /&gt;
; In dbmodel.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `user_preferences` (&lt;br /&gt;
  `player_id` int(10) NOT NULL,&lt;br /&gt;
  `pref_id` int(10) NOT NULL,&lt;br /&gt;
  `pref_value` int(10) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`player_id`, `pref_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; In ggg.game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
protected function setupNewGame($players, $options = array())&lt;br /&gt;
{&lt;br /&gt;
// TODO: Save $this-&amp;gt;player_preferences: key is player_id, value is array with pref_id as key and pref_value as value&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; In ggg.js&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setup(gamedatas) {&lt;br /&gt;
...&lt;br /&gt;
this.initPreferencesObserver();&lt;br /&gt;
},&lt;br /&gt;
initPreferencesObserver() {&lt;br /&gt;
    dojo.query(&#039;.preference_control&#039;).on(&#039;change&#039;, (e) =&amp;gt; {&lt;br /&gt;
        const match = e.target.id.match(/^preference_[cf]ontrol_(\d+)$/);&lt;br /&gt;
        if (!match) {&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        const pref = match[1];&lt;br /&gt;
        const newValue = e.target.value;&lt;br /&gt;
        this.prefs[pref].value = newValue;&lt;br /&gt;
        this.onPreferenceChange(pref, newValue);&lt;br /&gt;
    });&lt;br /&gt;
},&lt;br /&gt;
onPreferenceChange(prefId, prefValue) {&lt;br /&gt;
    prefId = parseInt(prefId);&lt;br /&gt;
    if (prefId === 101 /*TODO: You probably want to send only some preferences*/) {&lt;br /&gt;
        // TODO: Code your own action in ggg.action.php and send it prefId and prefValue&lt;br /&gt;
        //       The on the server side you can save it all in the user_preferences&lt;br /&gt;
        //       table you created above.&lt;br /&gt;
    }&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=9930</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=9930"/>
		<updated>2021-10-28T11:44:32Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: added game option info in initGameStateLabels&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. Returns a number indicating percent of progression (0-100)&lt;br /&gt;
* Utility functions: your utility functions.&lt;br /&gt;
* Player actions: the entry points for players actions ([https://en.doc.boardgamearena.com/Players_actions:_yourgamename.action.php more info here]). &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;
; getPlayerNameById($player_id)&lt;br /&gt;
: Get the name by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerColorById($player_id)&lt;br /&gt;
: Get the color by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerNoById($player_id)&lt;br /&gt;
: Get &#039;player_no&#039; (number) by id&lt;br /&gt;
&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;
: &amp;lt;code&amp;gt;array_keys($this-&amp;gt;loadPlayersBasicInfos())&amp;lt;/code&amp;gt; will therefore returns an array containing players id&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;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
                foreach ($players as $player_id =&amp;gt; $info) {&lt;br /&gt;
                    $player_color = $info[&#039;player_color&#039;];&lt;br /&gt;
                    ...&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: if you want array of player ids only you can do this:&lt;br /&gt;
    $player_ids =  array_keys($this-&amp;gt;loadPlayersBasicInfos());  &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;
; isSpectator()&lt;br /&gt;
: Check the &amp;quot;current_player&amp;quot; spectator status. If true, the user accessing the game is a spectator (not part of the game). For this user, the interface should display all public information, and no private information (like a friend sitting at the same table as players and just spectating 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;
; isPlayerZombie($player_id)&lt;br /&gt;
: This method does not exists, but if you need it it looks like this&lt;br /&gt;
    protected function isPlayerZombie($player_id) {&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        if (! isset($players[$player_id]))&lt;br /&gt;
            throw new feException(&amp;quot;Player $player_id is not playing here&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        return ($players[$player_id][&#039;player_zombie&#039;] == 1);&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;
However there are sets of database operation that initite implicit commit (most common mistake is to use &amp;quot;TRUNCATE&amp;quot;), you cannot use these operations during the game, it breaks the unrolling of transactions and will lead to nasty issues&lt;br /&gt;
(https://mariadb.com/kb/en/sql-statements-that-cause-an-implicit-commit).&lt;br /&gt;
&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 __construct() method of &#039;&#039;yourgamename.game.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, there can be gaps). 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;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $this-&amp;gt;GAMESTATELABELS = [&amp;quot;my_first_global_variable&amp;quot; =&amp;gt; 10, &amp;quot;my_second_global_variable&amp;quot; =&amp;gt; 11];&lt;br /&gt;
        self::initGameStateLabels($this-&amp;gt;GAMESTATELABELS);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is also in this method that you will define your game options. In that case, IDs need to be between 100 and 199 (inclusive, there can be gaps) Check this for more details [[Game_options_and_preferences:_gameoptions.inc.php]]&lt;br /&gt;
&lt;br /&gt;
With option set, the method will look like&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;
                &amp;quot;my_game_variant&amp;quot; =&amp;gt; 100&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. $value_value must be an integer.&lt;br /&gt;
&lt;br /&gt;
It seems that a non initialized value will not be restored with undo system, so it is therefore advisable to initialize them all in your &amp;quot;setupNewGame&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;foreach ($this-&amp;gt;GAMESTATELABELS as $value_label=&amp;gt; $ID) if ($ID &amp;gt;= 10 &amp;amp;&amp;amp; $ID &amp;lt; 90) self::setGameStateInitialValue($value_label, 0);&amp;lt;/pre&amp;gt;&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;
For debugging purposes, you can have labels and value pairs send to client side by inserting that line of code in your &amp;quot;getAllDatas&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;$result[&#039;labels&#039;] = array_combine(array_keys($this-&amp;gt;GAMESTATELABELS), array_map(&#039;self::getGameStateValue&#039;, array_keys($this-&amp;gt;GAMESTATELABELS)));&amp;lt;/pre&amp;gt;&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. $value_value must be an integer.&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;
; $this-&amp;gt;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, it just calls $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive()&lt;br /&gt;
&lt;br /&gt;
This is to be used in 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;stMakeEveryoneActive&#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;
;$this-&amp;gt;gamestate-&amp;gt;isPlayerActive($player_id)&lt;br /&gt;
:Return true if specified player is active right now.&lt;br /&gt;
:This method take into account game state type, ie nobody is active if game state is &amp;quot;game&amp;quot; and several players can be active if game state is &amp;quot;multiplayer&amp;quot;&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 changed 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;
&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;
I suggest to define and use this function in your php class to access state name:&lt;br /&gt;
&lt;br /&gt;
    public function getStateName() {&lt;br /&gt;
        $state = $this-&amp;gt;gamestate-&amp;gt;state();&lt;br /&gt;
        return $state[&#039;name&#039;];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;state_id()&lt;br /&gt;
: Get the id of the current game state (rarely useful, its best to use name, unless you use constants for state ids)&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;isMutiactiveState()&lt;br /&gt;
: Return true if we are in multipleactiveplayer state, false otherwise&lt;br /&gt;
&lt;br /&gt;
== Players turn order ==&lt;br /&gt;
&lt;br /&gt;
When table is created the &amp;quot;natural&amp;quot; player order is assigned to player at random, and stored in &amp;quot;read-only&amp;quot; field &amp;quot;player_no&amp;quot;.&lt;br /&gt;
If you need to create a custom order you should never change natural order but have a separate data structure. &lt;br /&gt;
For example you can alter the players table to add another &amp;quot;custom_order&amp;quot; field, you can use state globals or you can use your natural board database, &lt;br /&gt;
to store meeple_color/position_location pair.&lt;br /&gt;
BGA currently does not provide any API to create/store custom player 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;
If parmeter $bLoop is set to true then last player will points to first (creaing a loop), 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;
Note: This function &#039;&#039;&#039;DOES NOT&#039;&#039;&#039; change the order in database, it only creates a map using key/values as descibed.&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 $this-&amp;gt;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;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$table = $this-&amp;gt;createNextPlayerTable([3,2,1], false);&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
   [ &lt;br /&gt;
    3 =&amp;gt; 2, &lt;br /&gt;
    2 =&amp;gt; 1, &lt;br /&gt;
    1 =&amp;gt; null,&lt;br /&gt;
    0 =&amp;gt; 3 &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;
=== NotifyAllPlayers ===&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 translated.&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;
* 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 if 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;
&#039;&#039;&#039;Important&#039;&#039;&#039;: When the game page is reloaded (i.e. F5 or when loading turn based game) all previous notifications are replayed as history notifications. These notifications do not trigger notification handlers and are used basically to build the game log. Because of that most of the notification arguments, except i18n, player_id and all arguments used in the message, are removed from these history notifications. If you need additional arguments in history notifications you can add special field &amp;lt;b&amp;gt;preserve&amp;lt;/b&amp;gt; to notification arguments, like this:&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;
        &#039;preserve&#039; =&amp;gt; [ &#039;x&#039;, &#039;y&#039; ]&lt;br /&gt;
     ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In this example, fields x and y will be preserved when replaying history notification at the game load.&lt;br /&gt;
&lt;br /&gt;
==== HTML in Notifications ====&lt;br /&gt;
&lt;br /&gt;
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 replay 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 replay, 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;
==== Recursive Notifications ====&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;
==== Excluding some players ====&lt;br /&gt;
&lt;br /&gt;
Sometimes you want to notify all players of a message but not have it appear in the log of specific players (for example, have every player see &amp;quot;Player X draws a card&amp;quot; but have Player X see &amp;quot;You draw the Ace of Spades&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
To send a notification to all players but have some clients ignore it, send it as normal from the server, but implement &#039;&#039;&#039;setIgnoreNotificationCheck&#039;&#039;&#039; on the client to ignore the message under given conditions. See the X.js documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== NotifyPlayer ===&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;
Note that spectators cannot be notified using this method, because their player ID is not available via loadPlayersBasicInfos() or otherwise. You must use notifyAllPlayers() for any notification that spectators should get.&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 play and can start another game if he/she wants too (with 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;
&#039;&#039;&#039;Important: this should not be used on a player who has already left the game (&amp;quot;zombie&amp;quot;) as leaving/being kicked of the game (outside of the scope of the rules) is not the same as being eliminated from the game (according to the rules), except if in the course of the game, the zombie player is eliminated according to the rules.&#039;&#039;&#039;&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;
; function isAsync()&lt;br /&gt;
: Returns true if game is turn based, false if it is realtime&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;
Note: if you deploy undo support after game is in production this will take into effect for new games only, old games will give user an error if user choses Undo action, but otherwise it should not affect them.&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 matters if you transition to game state not to user state after), this may affect what you end up saving.&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;
Note: if you reading global state variable right after restore - it won&#039;t work properly as global tables is not re-synctonize after reload of db values happen, so best is to transition to next state and exit php handler without any other processing&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 they are not allowed to do.&lt;br /&gt;
: The error message will be shown to the player as a &amp;quot;red message&amp;quot;.&lt;br /&gt;
: The error message must be translated, make sure you use self::_() or $this-&amp;gt;_() here and NOT clientranslate()&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;
&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 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 check the code of &amp;quot;setupNewGame&amp;quot;. New template already have correct code, but if you editing very old game and it may be absent.&lt;br /&gt;
&lt;br /&gt;
        $gameinfos = $this-&amp;gt;getGameinfos();&lt;br /&gt;
        ...&lt;br /&gt;
        if ($gameinfos[&#039;favorite_colors_support&#039;])&lt;br /&gt;
            $this-&amp;gt;reattributeColorsBasedOnPreferences($players, $gameinfos[&#039;player_colors&#039;]); // this should be above reloadPlayersBasicInfos()&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;
Some important remarks:&lt;br /&gt;
* for some games (i.e. Chess), the color has an influence on a mechanism of the game, most of the time by giving a special advantage to a player (i.e. 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 (Note - you don&#039;t have to pick these, the &amp;quot;closest&amp;quot; color will be found):&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;
The keys may only contain letters and numbers, underscore seems not to be allowed.&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( $key, $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($key)&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_dependency&#039; =&amp;gt; false,  //or if the property is missing, the game is not language dependent&lt;br /&gt;
  &#039;language_dependency&#039; =&amp;gt; true, //all players at the table must speak the same language&lt;br /&gt;
  &#039;language_dependency&#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>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=9859</id>
		<title>Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=9859"/>
		<updated>2021-10-21T12:43:19Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: Invalid or missing substitution argument for log message: ${actplayer} ...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Describing common errors which is hard to understand and debug &lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game does not start at all ==&lt;br /&gt;
&lt;br /&gt;
=== Undefined offset: 0 in table/table.game.php on line 830 ===&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re calling self::getActivePlayerName () during setupNewGame()&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re NOT calling self::activeNextPlayer() at the end of your game setup. You must always have at least one active player.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: createGame): ... ===&lt;br /&gt;
&lt;br /&gt;
This is generic message usually followed by exact position in your source code, and usually its syntax error in one of yours php script&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Not logged ===&lt;br /&gt;
&lt;br /&gt;
Calling self::getCurrentPlayerId () or using $g_user from &#039;args&#039; state function, see also below&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Unknow player statistic: ===&lt;br /&gt;
&lt;br /&gt;
Calling self::incStat() with second parameter which is an empty string&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats ... ===&lt;br /&gt;
&lt;br /&gt;
Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats (stats_type, stats_player_id, stats_value) VALUES (&#039;10&#039;,&#039;2300663&#039;,&#039;0&#039;),(&#039;10&#039;,&#039;2300662&#039;,&#039;0&#039;)&lt;br /&gt;
Duplicate entry &#039;10-2300663&#039; for key &#039;stats_table_id&#039;&lt;br /&gt;
&lt;br /&gt;
Why? In the stats.inc.php you declared two keys with the same integer &amp;quot;id&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: BGA main website do not respond ===&lt;br /&gt;
&lt;br /&gt;
Check if other games work; if not, it&#039;s a problem with BGA Studio; if so, your game likely reaches an end state immediately. Check your states.inc.php and your transitions.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): BGA service error ===&lt;br /&gt;
&lt;br /&gt;
You may have a syntax error in your dbmodel.sql.&lt;br /&gt;
&lt;br /&gt;
Or, you may be calling self::initStat() for a statistic that does not exist. Check the statistic name, and make sure you clicked &amp;quot;Reload statistics configuration&amp;quot; button in the admin console after making changes to stats.inc.php&lt;br /&gt;
&lt;br /&gt;
Or you may not have your states.inc.php set up correctly.&lt;br /&gt;
&lt;br /&gt;
You may have an error in your table.game.php file (such as &amp;lt;code&amp;gt;$result[&#039;x&#039;] = y;&amp;lt;/code&amp;gt; when $result is not an array).&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Table status of a starting game should be &#039;setup&#039; ===&lt;br /&gt;
&lt;br /&gt;
This error message appears when you start a one player game using the &amp;quot;Express Start&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
In normal situation, the game starts just after this message and everything should works normally. In this case, you can just ignore this message.&lt;br /&gt;
&lt;br /&gt;
If the games does not start, it is most probable that there is a syntax error in any of your php code (Check your states.inc.php and X.game.php)&lt;br /&gt;
&lt;br /&gt;
=== Fatal error during creation of database ebd_quoridor_389 Not logged ===&lt;br /&gt;
&lt;br /&gt;
Check that you didn&#039;t use $g_user or getCurrentPlayerId() in setupNewGame() function or in an &#039;args&#039; function of your state.&lt;br /&gt;
&lt;br /&gt;
As these functions are not consequences of a user action, there is no current player defined.&lt;br /&gt;
&lt;br /&gt;
As a general rule, you should use getActivePlayerId() and not getCurrentPlayerId(). See the [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine presentation on the game state machine] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Warning: Invalid argument supplied for foreach() in table.game.php ===&lt;br /&gt;
&lt;br /&gt;
   Warning: Invalid argument supplied for foreach() in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 129 &lt;br /&gt;
   Fatal error: Cannot unset string offsets in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 143&lt;br /&gt;
&lt;br /&gt;
That appears when your arg* function that suppose to return array of state arguments returns a scalar (a non-array) value&lt;br /&gt;
&lt;br /&gt;
=== The server reported an error ===&lt;br /&gt;
&lt;br /&gt;
During table creation: &amp;quot;The server reported an error&amp;quot; error shown and nothing else.&lt;br /&gt;
&lt;br /&gt;
If you cannot even create a table - there is syntax error in gameinfos.php, check it, reload it from management panel.&lt;br /&gt;
If still no luck copy clean version from template https://github.com/elaskavaia/bga-sharedcode/blob/master/gameinfos.inc.php&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Error : Invalid player number for this game : 4 ===&lt;br /&gt;
&lt;br /&gt;
This error may comes when trying to change the player number configuration in gameinfos.inc.php from a higher to lower number of players (for example from 4 to 2).&lt;br /&gt;
&lt;br /&gt;
The following steps will help to change a player config from array(4) to array(2) :&lt;br /&gt;
&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2,3,4 )&lt;br /&gt;
* In game management page (Control Panel &amp;gt; Manage Games &amp;gt; &amp;quot;Your Game&amp;quot;), press the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
* create a new table&lt;br /&gt;
* reduce the number of players to 2 and start the game&lt;br /&gt;
* (express) Stop the game&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2 )&lt;br /&gt;
* press again the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game starts but I can&#039;t make a move ==&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I got &amp;quot;Move recorded, waiting for update ...&amp;quot; forever ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Move recorded&amp;quot; means that your ajaxcall request has been sent to the server and returned normally.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Waiting for update&amp;quot; means that your client interface is waiting for some notifications from the server that correspond to the move we just did.&lt;br /&gt;
&lt;br /&gt;
If this message stays forever, it is probably that your PHP code does not send any notification when the move happens, which is abnormal. To fix this: add a notifyAllPlayers or a notifyPlayer call in your PHP code.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Sending move to server...&amp;quot; then nothing and game resets to state before the move ===&lt;br /&gt;
&lt;br /&gt;
Its possible that server code get into infinite loops or thinks too much, in which case it will timeout and will be aborted without any extra logs (and db transaction you saw in the log won&#039;t be committed). You will usually see &amp;quot;Unable to connect to server&amp;quot; message on console in this case. You have to put more logging into server&lt;br /&gt;
to trace where it hangs.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Ajaxcall error: empty answer&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You either have missing self::ajaxResponse(); in your game.action.php method, or there is some problem with getting arguments (check that you are using btoa() on client when using AT_base64 arg type in action.php)&lt;br /&gt;
&lt;br /&gt;
=== Some player action is triggered randomly when I click somewhere on the game area ===&lt;br /&gt;
&lt;br /&gt;
You probably used &amp;quot;dojo.connect&amp;quot; on a null object. In this case, dojo.connect associate the event (ex: &amp;quot;onclick&amp;quot;) to the whole game area.&lt;br /&gt;
&lt;br /&gt;
Most of the time it happens in this situation, when my_object element does not exists:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   dojo.connect( $(&amp;quot;my_object&amp;quot;), &amp;quot;onclick&amp;quot;, this, (event)=&amp;gt;{})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To determine if this is the case, place &amp;quot;alert( $(&amp;quot;my_object&amp;quot;) )&amp;quot; before the dojo.connect to check if the object exists or not.&lt;br /&gt;
&lt;br /&gt;
=== Error: This is not your turn ===&lt;br /&gt;
&lt;br /&gt;
This happens when checkAction() is called and current player is NOT the active player.&lt;br /&gt;
&lt;br /&gt;
You can change the active player in studio by clicking the red arrow next to their name in the player panel (right side of the page).&lt;br /&gt;
&lt;br /&gt;
[[File:Change_active_player.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Error: Please wait, an action is already in progress ===&lt;br /&gt;
Its followed by error &amp;quot;(Generated by checkAction / XXX)&amp;quot; on studio.&lt;br /&gt;
&lt;br /&gt;
This error is triggered in the JS by the checkAction function for XXX action.&lt;br /&gt;
&lt;br /&gt;
This can happen when the player sent an Ajax request action earlier, and:&lt;br /&gt;
* action is not complete yet - i.e. takes some time, and user clicked something again &lt;br /&gt;
* if there is bug in interface where MULTIPLE handlers are fired on same click. To debug this add some console.trace() in place this specific checkAction is called.&lt;br /&gt;
* did not get any notification from the PHP side. To avoid this, put an empty notifyPlayer in the PHP side of the Ajax handler to ensure the client receives a response. This line of code should do it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyPlayer($this-&amp;gt;getCurrentPlayerId(), &#039;message&#039;, &#039;&#039;, []); // sent to current player, who originated the action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error: This move is not authorized now ===&lt;br /&gt;
This is generic error message generated by this.showMoveUnauthorized() function. If you did not call this function yourself, check the console log, it may have additional information.&lt;br /&gt;
If you see &amp;quot;Move not authorized now : XXX&amp;quot; in the log, where XXX is your action name - this means that action XXX is not defined in list of possible actions for your current state. This error generated by checkAction() function.&lt;br /&gt;
&lt;br /&gt;
== Predefined server errors ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Unexpected final game state (XX) ===&lt;br /&gt;
&lt;br /&gt;
The action function does not transition to any state, i.e.&lt;br /&gt;
  function selectField($field) {&lt;br /&gt;
    self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
    if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
  }&lt;br /&gt;
Here if $field is 0 there is no transition&lt;br /&gt;
&lt;br /&gt;
=== This game action is impossible right now ===&lt;br /&gt;
&lt;br /&gt;
Check the game log. Usually your state does not define the action you trying to perform in &#039;possibleactions&#039; array.&lt;br /&gt;
&lt;br /&gt;
Also check your onActionName javascript function. Make sure you are calling the right &amp;quot;actionname.html&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: This transition (playerTurn) is impossible at this state (42) ===&lt;br /&gt;
&lt;br /&gt;
This is pretty self explanatory. Function nextState() takes transition name not a state name, so you probably did not&lt;br /&gt;
define this transition that the given state&lt;br /&gt;
&lt;br /&gt;
== Game interface hangs during reload or on start ==&lt;br /&gt;
&lt;br /&gt;
Showing &amp;quot;Application Loading...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload undefined no_stack_avail Script: ===&lt;br /&gt;
&lt;br /&gt;
This error usually has no useful data, but it means you called somes API that require a callback and did not define callback function, i.e&lt;br /&gt;
in dojo.connect, this.connectClass, dojo.subscribe, etc&lt;br /&gt;
   &lt;br /&gt;
      this.connectClass(&#039;field&#039;, &#039;onclick&#039;, &#039;onField&#039;); // &amp;lt;-- onField is not defined&lt;br /&gt;
&lt;br /&gt;
=== Other errors with &amp;quot;Application loading...&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You probably have a syntax error in your Javascript code, and the interface refuses to load.&lt;br /&gt;
&lt;br /&gt;
To find this error, check if there is an error message in the Javascript console (F12).&lt;br /&gt;
&lt;br /&gt;
If there is really nothing on the log, it&#039;s probably that the system was unable to load your Javascript because of an syntax error that affect the structure of the Javascript file, typically a missing &amp;quot;}&amp;quot; or a missing &amp;quot;,&amp;quot; after a method definition.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;Uncaught ReferenceError: bgagame is not defined&amp;quot; you have major syntax error in your js file, you should see some other clues in the log where the errors is.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;dojo.publish is not defined&amp;quot; or something similar, this could be caused by another error earlier. For example, a syntax error caused by a malformed generated file (such as using newlines in tiebreaker description). Also you might have left some images in the /img directory with special characters in the name which must be removed. If you edited images for the game box and website, ensure that you have not left any unnecessary files there.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Syntax Error: ===&lt;br /&gt;
&lt;br /&gt;
No further details in the log. When log is filling with some social connect errors.&lt;br /&gt;
&lt;br /&gt;
Possible Reason: Syntax error in of the php script which is loaded before the start, such as gameoptions.inc.php, gameinfos.inc.php and such.&lt;br /&gt;
&lt;br /&gt;
=== Game interface spins in a loop throwing error ===&lt;br /&gt;
&lt;br /&gt;
Errors is something like &amp;quot;Cannot read property &#039;is_ai&#039; of undefined&amp;quot;. Cannot restart the game because cannot access UI to stop.&lt;br /&gt;
Likely you get in actplayer state with player id == 0. The only way to fix it is to edit database, globals index == 2 set player id to one of your test dudes&lt;br /&gt;
(can copy from row 5 for example).&lt;br /&gt;
&lt;br /&gt;
=== Unable to find table database (1): ebd_yourgame_112222 ===&lt;br /&gt;
&lt;br /&gt;
Its either temporarily server error especially on studio it timeouts sometimes, just try reloading again.&lt;br /&gt;
Or check if you have syntax errors in your php game file or sql.&lt;br /&gt;
&lt;br /&gt;
== Type conversion / juggling errors ==&lt;br /&gt;
&lt;br /&gt;
=== On php side I get a number instead of string I expect ===&lt;br /&gt;
&lt;br /&gt;
 $num = 3;&lt;br /&gt;
 $meeple = &amp;quot;meeple_&amp;quot; + $num; // &amp;lt;-- suppose to be &amp;quot;meeple_3&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
When you switch between JS and PHP it easy to type this and not notice the +. Plus sign (+) in php does not mean string concatenation (in javascript does!),&lt;br /&gt;
in php + means integer arithmetic. So change + to . (dot)&lt;br /&gt;
&lt;br /&gt;
=== On php side my string comparison does not work ===&lt;br /&gt;
&lt;br /&gt;
   if ($color == &#039;4baae2&#039; || $color == &#039;000000&#039;) { &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Apparently you should not be using &#039;==&#039; in php to compare strings! You should use &#039;===&#039;. The (==) operator will typecast the strings &lt;br /&gt;
to numbers then do comparison!&lt;br /&gt;
Its not very apparent because usually you can get away with it, but not when strings resemble numbers like hex &#039;colors&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Integer columns in the database are returned as strings ===&lt;br /&gt;
&lt;br /&gt;
This is normal PHP behavior. All fields are returned as string type, regardless of their actual type in the database. This also applies to global variables accessed via getGameStateValue(), since they are stored in a database table.&lt;br /&gt;
&lt;br /&gt;
You can use type-casting to convert them to the correct type after they come out of the database.&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = (int)self::getGameStateValue(GLOBAL_ROUND_NUMBER);&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = self::getGameStateValue(GLOBAL_ROUND_NUMBER) + 0; // adding 0 casts to int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
same with direct qdb ueries&lt;br /&gt;
   $sql = &amp;quot;SELECT my_int_column FROM my_table WHERE my_condition&amp;quot;;&lt;br /&gt;
   $myResult = self::getUniqueValueFromDB($sql); &amp;lt;-- this is a string&lt;br /&gt;
   $myResultAsInt = (int)$myResult;&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/5323146/mysql-integer-field-is-returned-as-string-in-php&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: zombie): Not logged ===&lt;br /&gt;
&lt;br /&gt;
You are probably calling getCurrentPlayerId() or getCurrentPlayerName() in your zombieTurn method or any of the methods it uses. Instead, use the $active_player_id provided as parameter to zombieTurn().&lt;br /&gt;
&lt;br /&gt;
If you do not see these commands within &amp;quot;function zombieTurn( $state, $active_player ){}&amp;quot;, check all the functions called from zombieTurn, also &amp;quot;function getGameProgression(){}&amp;quot; and all the functions THAT calls.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Can&#039;t manage zombie player in this game state ===&lt;br /&gt;
&lt;br /&gt;
The state the game was in at the time the error was generated didn&#039;t have &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;zombiePass&amp;quot; =&amp;gt; 27 )&amp;quot; in states.inc.php (27 was an arbitrary example, but everything else must be spelled exactly that way.)&lt;br /&gt;
&lt;br /&gt;
To correct this error, either add &amp;quot;zombiePass&amp;quot; =&amp;gt; ## to the transitions array or work out why the game is in a state it should not be in.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: zombie): ===&lt;br /&gt;
&lt;br /&gt;
This is almost certainly an undefined value in PHP code. Look for a warning or error message in the game replay log on the right side of the table UI.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: BGA gameserver 1 do not respond (method: zombie) (timeout: cluster) ===&lt;br /&gt;
&lt;br /&gt;
You are trying to end the game from a zombie method. This is not allowed. The zombie logic must continue the game as best it can. See [[Main_game_logic:_yourgamename.game.php#Zombie_mode|Zombie mode]] for more info.&lt;br /&gt;
&lt;br /&gt;
=== Game unexpectedly ends when one player becomes zombie ===&lt;br /&gt;
&lt;br /&gt;
There is an error in handling zombie mode, check error log. Example: if the zombie turn is called again, framework detects a infinite loop and cancels the game. On the studio there is a notification called ZombieTurnFailed&lt;br /&gt;
&lt;br /&gt;
== Other errors ==&lt;br /&gt;
&lt;br /&gt;
=== Javascript does not know how to sum two numbers ===&lt;br /&gt;
&lt;br /&gt;
Be careful when you manipulate integers returned by notifications: most of the time, Javascript considers they are Strings and not Integers.&lt;br /&gt;
&lt;br /&gt;
As a result:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += notif.args.increment;  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=11 instead of 2 !! Javascript concatenate 2 strings !&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To solve this, you should use the &amp;quot;toint&amp;quot; function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += toint( notif.args.increment );  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=2 :)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Javascript: do not use substr with negative numbers ===&lt;br /&gt;
&lt;br /&gt;
To get the last characters of a string, use &amp;quot;slice&amp;quot; instead of &amp;quot;substr&amp;quot; which has a bug on IE:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var three_last_characters = string.substr( -3 );   // Wrong&lt;br /&gt;
    var three_last_characters = string.slice( -3 );    // Correct&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Game &amp;quot;spontaneously&amp;quot; transition to a new state without user input ===&lt;br /&gt;
&lt;br /&gt;
Make sure on php side you have no code after   $this-&amp;gt;gamestate-&amp;gt;nextState(...) code.&lt;br /&gt;
Because if you do accidentally have code that goes to another state it will cause another state transition without user interaction.&lt;br /&gt;
&lt;br /&gt;
 function selectField($field) {&lt;br /&gt;
   self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
   if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
   $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;last&#039; ); // &amp;lt;-- here is missing else, so it will cause double state transition&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Message &amp;quot;Invalid or missing substitution argument for log message: ${actplayer} ... &amp;quot; when entering a state ===&lt;br /&gt;
&lt;br /&gt;
You probably have an args function defined for that state that does &#039;&#039;&#039;not&#039;&#039;&#039; return an array&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=9845</id>
		<title>Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=9845"/>
		<updated>2021-10-21T09:28:55Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Describing common errors which is hard to understand and debug &lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game does not start at all ==&lt;br /&gt;
&lt;br /&gt;
=== Undefined offset: 0 in table/table.game.php on line 830 ===&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re calling self::getActivePlayerName () during setupNewGame()&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re NOT calling self::activeNextPlayer() at the end of your game setup. You must always have at least one active player.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: createGame): ... ===&lt;br /&gt;
&lt;br /&gt;
This is generic message usually followed by exact position in your source code, and usually its syntax error in one of yours php script&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Not logged ===&lt;br /&gt;
&lt;br /&gt;
Calling self::getCurrentPlayerId () or using $g_user from &#039;args&#039; state function, see also below&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Unknow player statistic: ===&lt;br /&gt;
&lt;br /&gt;
Calling self::incStat() with second parameter which is an empty string&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats ... ===&lt;br /&gt;
&lt;br /&gt;
Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats (stats_type, stats_player_id, stats_value) VALUES (&#039;10&#039;,&#039;2300663&#039;,&#039;0&#039;),(&#039;10&#039;,&#039;2300662&#039;,&#039;0&#039;)&lt;br /&gt;
Duplicate entry &#039;10-2300663&#039; for key &#039;stats_table_id&#039;&lt;br /&gt;
&lt;br /&gt;
Why? In the stats.inc.php you declared two keys with the same integer &amp;quot;id&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: BGA main website do not respond ===&lt;br /&gt;
&lt;br /&gt;
Check if other games work; if not, it&#039;s a problem with BGA Studio; if so, your game likely reaches an end state immediately. Check your states.inc.php and your transitions.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): BGA service error ===&lt;br /&gt;
&lt;br /&gt;
You may have a syntax error in your dbmodel.sql.&lt;br /&gt;
&lt;br /&gt;
Or, you may be calling self::initStat() for a statistic that does not exist. Check the statistic name, and make sure you clicked &amp;quot;Reload statistics configuration&amp;quot; button in the admin console after making changes to stats.inc.php&lt;br /&gt;
&lt;br /&gt;
Or you may not have your states.inc.php set up correctly.&lt;br /&gt;
&lt;br /&gt;
You may have an error in your table.game.php file (such as &amp;lt;code&amp;gt;$result[&#039;x&#039;] = y;&amp;lt;/code&amp;gt; when $result is not an array).&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Table status of a starting game should be &#039;setup&#039; ===&lt;br /&gt;
&lt;br /&gt;
This error message appears when you start a one player game using the &amp;quot;Express Start&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
In normal situation, the game starts just after this message and everything should works normally. In this case, you can just ignore this message.&lt;br /&gt;
&lt;br /&gt;
If the games does not start, it is most probable that there is a syntax error in any of your php code (Check your states.inc.php and X.game.php)&lt;br /&gt;
&lt;br /&gt;
=== Fatal error during creation of database ebd_quoridor_389 Not logged ===&lt;br /&gt;
&lt;br /&gt;
Check that you didn&#039;t use $g_user or getCurrentPlayerId() in setupNewGame() function or in an &#039;args&#039; function of your state.&lt;br /&gt;
&lt;br /&gt;
As these functions are not consequences of a user action, there is no current player defined.&lt;br /&gt;
&lt;br /&gt;
As a general rule, you should use getActivePlayerId() and not getCurrentPlayerId(). See the [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine presentation on the game state machine] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Warning: Invalid argument supplied for foreach() in table.game.php ===&lt;br /&gt;
&lt;br /&gt;
   Warning: Invalid argument supplied for foreach() in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 129 &lt;br /&gt;
   Fatal error: Cannot unset string offsets in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 143&lt;br /&gt;
&lt;br /&gt;
That appears when your arg* function that suppose to return array of state arguments returns a scalar (a non-array) value&lt;br /&gt;
&lt;br /&gt;
=== The server reported an error ===&lt;br /&gt;
&lt;br /&gt;
During table creation: &amp;quot;The server reported an error&amp;quot; error shown and nothing else.&lt;br /&gt;
&lt;br /&gt;
If you cannot even create a table - there is syntax error in gameinfos.php, check it, reload it from management panel.&lt;br /&gt;
If still no luck copy clean version from template https://github.com/elaskavaia/bga-sharedcode/blob/master/gameinfos.inc.php&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Error : Invalid player number for this game : 4 ===&lt;br /&gt;
&lt;br /&gt;
This error may comes when trying to change the player number configuration in gameinfos.inc.php from a higher to lower number of players (for example from 4 to 2).&lt;br /&gt;
&lt;br /&gt;
The following steps will help to change a player config from array(4) to array(2) :&lt;br /&gt;
&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2,3,4 )&lt;br /&gt;
* In game management page (Control Panel &amp;gt; Manage Games &amp;gt; &amp;quot;Your Game&amp;quot;), press the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
* create a new table&lt;br /&gt;
* reduce the number of players to 2 and start the game&lt;br /&gt;
* (express) Stop the game&lt;br /&gt;
* change in gameinfos.inc.php the entry to &#039;players&#039; =&amp;gt; array( 2 )&lt;br /&gt;
* press again the &amp;quot;Reload Game information&amp;quot; button&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game starts but I can&#039;t make a move ==&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I got &amp;quot;Move recorded, waiting for update ...&amp;quot; forever ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Move recorded&amp;quot; means that your ajaxcall request has been sent to the server and returned normally.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Waiting for update&amp;quot; means that your client interface is waiting for some notifications from the server that correspond to the move we just did.&lt;br /&gt;
&lt;br /&gt;
If this message stays forever, it is probably that your PHP code does not send any notification when the move happens, which is abnormal. To fix this: add a notifyAllPlayers or a notifyPlayer call in your PHP code.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Sending move to server...&amp;quot; then nothing and game resets to state before the move ===&lt;br /&gt;
&lt;br /&gt;
Its possible that server code get into infinite loops or thinks too much, in which case it will timeout and will be aborted without any extra logs (and db transaction you saw in the log won&#039;t be committed). You will usually see &amp;quot;Unable to connect to server&amp;quot; message on console in this case. You have to put more logging into server&lt;br /&gt;
to trace where it hangs.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Ajaxcall error: empty answer&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You either have missing self::ajaxResponse(); in your game.action.php method, or there is some problem with getting arguments (check that you are using btoa() on client when using AT_base64 arg type in action.php)&lt;br /&gt;
&lt;br /&gt;
=== Some player action is triggered randomly when I click somewhere on the game area ===&lt;br /&gt;
&lt;br /&gt;
You probably used &amp;quot;dojo.connect&amp;quot; on a null object. In this case, dojo.connect associate the event (ex: &amp;quot;onclick&amp;quot;) to the whole game area.&lt;br /&gt;
&lt;br /&gt;
Most of the time it happens in this situation, when my_object element does not exists:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   dojo.connect( $(&amp;quot;my_object&amp;quot;), &amp;quot;onclick&amp;quot;, this, (event)=&amp;gt;{})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To determine if this is the case, place &amp;quot;alert( $(&amp;quot;my_object&amp;quot;) )&amp;quot; before the dojo.connect to check if the object exists or not.&lt;br /&gt;
&lt;br /&gt;
=== Error: This is not your turn ===&lt;br /&gt;
&lt;br /&gt;
This happens when checkAction() is called and current player is NOT the active player.&lt;br /&gt;
&lt;br /&gt;
You can change the active player in studio by clicking the red arrow next to their name in the player panel (right side of the page).&lt;br /&gt;
&lt;br /&gt;
[[File:Change_active_player.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Error: Please wait, an action is already in progress ===&lt;br /&gt;
Its followed by error &amp;quot;(Generated by checkAction / XXX)&amp;quot; on studio.&lt;br /&gt;
&lt;br /&gt;
This error is triggered in the JS by the checkAction function for XXX action.&lt;br /&gt;
&lt;br /&gt;
This can happen when the player sent an Ajax request action earlier, and:&lt;br /&gt;
* action is not complete yet - i.e. takes some time, and user clicked something again &lt;br /&gt;
* if there is bug in interface where MULTIPLE handlers are fired on same click. To debug this add some console.trace() in place this specific checkAction is called.&lt;br /&gt;
* did not get any notification from the PHP side. To avoid this, put an empty notifyPlayer in the PHP side of the Ajax handler to ensure the client receives a response. This line of code should do it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyPlayer($this-&amp;gt;getCurrentPlayerId(), &#039;message&#039;, &#039;&#039;, []); // sent to current player, who originated the action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error: This move is not authorized now ===&lt;br /&gt;
This is generic error message generated by this.showMoveUnauthorized() function. If you did not call this function yourself, check the console log, it may have additional information.&lt;br /&gt;
If you see &amp;quot;Move not authorized now : XXX&amp;quot; in the log, where XXX is your action name - this means that action XXX is not defined in list of possible actions for your current state. This error generated by checkAction() function.&lt;br /&gt;
&lt;br /&gt;
== Predefined server errors ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Unexpected final game state (XX) ===&lt;br /&gt;
&lt;br /&gt;
The action function does not transition to any state, i.e.&lt;br /&gt;
  function selectField($field) {&lt;br /&gt;
    self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
    if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
  }&lt;br /&gt;
Here if $field is 0 there is no transition&lt;br /&gt;
&lt;br /&gt;
=== This game action is impossible right now ===&lt;br /&gt;
&lt;br /&gt;
Check the game log. Usually your state does not define the action you trying to perform in &#039;possibleactions&#039; array.&lt;br /&gt;
&lt;br /&gt;
Also check your onActionName javascript function. Make sure you are calling the right &amp;quot;actionname.html&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: This transition (playerTurn) is impossible at this state (42) ===&lt;br /&gt;
&lt;br /&gt;
This is pretty self explanatory. Function nextState() takes transition name not a state name, so you probably did not&lt;br /&gt;
define this transition that the given state&lt;br /&gt;
&lt;br /&gt;
== Game interface hangs during reload or on start ==&lt;br /&gt;
&lt;br /&gt;
Showing &amp;quot;Application Loading...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload undefined no_stack_avail Script: ===&lt;br /&gt;
&lt;br /&gt;
This error usually has no useful data, but it means you called somes API that require a callback and did not define callback function, i.e&lt;br /&gt;
in dojo.connect, this.connectClass, dojo.subscribe, etc&lt;br /&gt;
   &lt;br /&gt;
      this.connectClass(&#039;field&#039;, &#039;onclick&#039;, &#039;onField&#039;); // &amp;lt;-- onField is not defined&lt;br /&gt;
&lt;br /&gt;
=== Other errors with &amp;quot;Application loading...&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You probably have a syntax error in your Javascript code, and the interface refuses to load.&lt;br /&gt;
&lt;br /&gt;
To find this error, check if there is an error message in the Javascript console (F12).&lt;br /&gt;
&lt;br /&gt;
If there is really nothing on the log, it&#039;s probably that the system was unable to load your Javascript because of an syntax error that affect the structure of the Javascript file, typically a missing &amp;quot;}&amp;quot; or a missing &amp;quot;,&amp;quot; after a method definition.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;Uncaught ReferenceError: bgagame is not defined&amp;quot; you have major syntax error in your js file, you should see some other clues in the log where the errors is.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;dojo.publish is not defined&amp;quot; or something similar, this could be caused by another error earlier. For example, a syntax error caused by a malformed generated file (such as using newlines in tiebreaker description). Also you might have left some images in the /img directory with special characters in the name which must be removed. If you edited images for the game box and website, ensure that you have not left any unnecessary files there.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Syntax Error: ===&lt;br /&gt;
&lt;br /&gt;
No further details in the log. When log is filling with some social connect errors.&lt;br /&gt;
&lt;br /&gt;
Possible Reason: Syntax error in of the php script which is loaded before the start, such as gameoptions.inc.php, gameinfos.inc.php and such.&lt;br /&gt;
&lt;br /&gt;
=== Game interface spins in a loop throwing error ===&lt;br /&gt;
&lt;br /&gt;
Errors is something like &amp;quot;Cannot read property &#039;is_ai&#039; of undefined&amp;quot;. Cannot restart the game because cannot access UI to stop.&lt;br /&gt;
Likely you get in actplayer state with player id == 0. The only way to fix it is to edit database, globals index == 2 set player id to one of your test dudes&lt;br /&gt;
(can copy from row 5 for example).&lt;br /&gt;
&lt;br /&gt;
=== Unable to find table database (1): ebd_yourgame_112222 ===&lt;br /&gt;
&lt;br /&gt;
Its either temporarily server error especially on studio it timeouts sometimes, just try reloading again.&lt;br /&gt;
Or check if you have syntax errors in your php game file or sql.&lt;br /&gt;
&lt;br /&gt;
== Type conversion / juggling errors ==&lt;br /&gt;
&lt;br /&gt;
=== On php side I get a number instead of string I expect ===&lt;br /&gt;
&lt;br /&gt;
 $num = 3;&lt;br /&gt;
 $meeple = &amp;quot;meeple_&amp;quot; + $num; // &amp;lt;-- suppose to be &amp;quot;meeple_3&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
When you switch between JS and PHP it easy to type this and not notice the +. Plus sign (+) in php does not mean string concatenation (in javascript does!),&lt;br /&gt;
in php + means integer arithmetic. So change + to . (dot)&lt;br /&gt;
&lt;br /&gt;
=== On php side my string comparison does not work ===&lt;br /&gt;
&lt;br /&gt;
   if ($color == &#039;4baae2&#039; || $color == &#039;000000&#039;) { &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Apparently you should not be using &#039;==&#039; in php to compare strings! You should use &#039;===&#039;. The (==) operator will typecast the strings &lt;br /&gt;
to numbers then do comparison!&lt;br /&gt;
Its not very apparent because usually you can get away with it, but not when strings resemble numbers like hex &#039;colors&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Integer columns in the database are returned as strings ===&lt;br /&gt;
&lt;br /&gt;
This is normal PHP behavior. All fields are returned as string type, regardless of their actual type in the database. This also applies to global variables accessed via getGameStateValue(), since they are stored in a database table.&lt;br /&gt;
&lt;br /&gt;
You can use type-casting to convert them to the correct type after they come out of the database.&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = (int)self::getGameStateValue(GLOBAL_ROUND_NUMBER);&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = self::getGameStateValue(GLOBAL_ROUND_NUMBER) + 0; // adding 0 casts to int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
same with direct qdb ueries&lt;br /&gt;
   $sql = &amp;quot;SELECT my_int_column FROM my_table WHERE my_condition&amp;quot;;&lt;br /&gt;
   $myResult = self::getUniqueValueFromDB($sql); &amp;lt;-- this is a string&lt;br /&gt;
   $myResultAsInt = (int)$myResult;&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/5323146/mysql-integer-field-is-returned-as-string-in-php&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: zombie): Not logged ===&lt;br /&gt;
&lt;br /&gt;
You are probably calling getCurrentPlayerId() or getCurrentPlayerName() in your zombieTurn method or any of the methods it uses. Instead, use the $active_player_id provided as parameter to zombieTurn().&lt;br /&gt;
&lt;br /&gt;
If you do not see these commands within &amp;quot;function zombieTurn( $state, $active_player ){}&amp;quot;, check all the functions called from zombieTurn, also &amp;quot;function getGameProgression(){}&amp;quot; and all the functions THAT calls.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Can&#039;t manage zombie player in this game state ===&lt;br /&gt;
&lt;br /&gt;
The state the game was in at the time the error was generated didn&#039;t have &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;zombiePass&amp;quot; =&amp;gt; 27 )&amp;quot; in states.inc.php (27 was an arbitrary example, but everything else must be spelled exactly that way.)&lt;br /&gt;
&lt;br /&gt;
To correct this error, either add &amp;quot;zombiePass&amp;quot; =&amp;gt; ## to the transitions array or work out why the game is in a state it should not be in.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: zombie): ===&lt;br /&gt;
&lt;br /&gt;
This is almost certainly an undefined value in PHP code. Look for a warning or error message in the game replay log on the right side of the table UI.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: BGA gameserver 1 do not respond (method: zombie) (timeout: cluster) ===&lt;br /&gt;
&lt;br /&gt;
You are trying to end the game from a zombie method. This is not allowed. The zombie logic must continue the game as best it can. See [[Main_game_logic:_yourgamename.game.php#Zombie_mode|Zombie mode]] for more info.&lt;br /&gt;
&lt;br /&gt;
=== Game unexpectedly ends when one player becomes zombie ===&lt;br /&gt;
&lt;br /&gt;
There is an error in handling zombie mode, check error log. Example: if the zombie turn is called again, framework detects a infinite loop and cancels the game. On the studio there is a notification called ZombieTurnFailed&lt;br /&gt;
&lt;br /&gt;
== Other errors ==&lt;br /&gt;
&lt;br /&gt;
=== Javascript does not know how to sum two numbers ===&lt;br /&gt;
&lt;br /&gt;
Be careful when you manipulate integers returned by notifications: most of the time, Javascript considers they are Strings and not Integers.&lt;br /&gt;
&lt;br /&gt;
As a result:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += notif.args.increment;  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=11 instead of 2 !! Javascript concatenate 2 strings !&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To solve this, you should use the &amp;quot;toint&amp;quot; function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += toint( notif.args.increment );  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=2 :)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Javascript: do not use substr with negative numbers ===&lt;br /&gt;
&lt;br /&gt;
To get the last characters of a string, use &amp;quot;slice&amp;quot; instead of &amp;quot;substr&amp;quot; which has a bug on IE:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var three_last_characters = string.substr( -3 );   // Wrong&lt;br /&gt;
    var three_last_characters = string.slice( -3 );    // Correct&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Game &amp;quot;spontaneously&amp;quot; transition to a new state without user input ===&lt;br /&gt;
&lt;br /&gt;
Make sure on php side you have no code after   $this-&amp;gt;gamestate-&amp;gt;nextState(...) code.&lt;br /&gt;
Because if you do accidentally have code that goes to another state it will cause another state transition without user interaction.&lt;br /&gt;
&lt;br /&gt;
 function selectField($field) {&lt;br /&gt;
   self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
   if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
   $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;last&#039; ); // &amp;lt;-- here is missing else, so it will cause double state transition&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=9835</id>
		<title>Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=9835"/>
		<updated>2021-10-20T12:30:07Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Unexpected error: Table status of a starting game should be &amp;#039;setup&amp;#039; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Describing common errors which is hard to understand and debug &lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game does not start at all ==&lt;br /&gt;
&lt;br /&gt;
=== Undefined offset: 0 in table/table.game.php on line 830 ===&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re calling self::getActivePlayerName () during setupNewGame()&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re NOT calling self::activeNextPlayer() at the end of your game setup. You must always have at least one active player.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: createGame): ... ===&lt;br /&gt;
&lt;br /&gt;
This is generic message usually followed by exact position in your source code, and usually its syntax error in one of yours php script&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Not logged ===&lt;br /&gt;
&lt;br /&gt;
Calling self::getCurrentPlayerId () or using $g_user from &#039;args&#039; state function, see also below&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Unknow player statistic: ===&lt;br /&gt;
&lt;br /&gt;
Calling self::incStat() with second parameter which is an empty string&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats ... ===&lt;br /&gt;
&lt;br /&gt;
Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats (stats_type, stats_player_id, stats_value) VALUES (&#039;10&#039;,&#039;2300663&#039;,&#039;0&#039;),(&#039;10&#039;,&#039;2300662&#039;,&#039;0&#039;)&lt;br /&gt;
Duplicate entry &#039;10-2300663&#039; for key &#039;stats_table_id&#039;&lt;br /&gt;
&lt;br /&gt;
Why? In the stats.inc.php you declared two keys with the same integer &amp;quot;id&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: BGA main website do not respond ===&lt;br /&gt;
&lt;br /&gt;
Check if other games work; if not, it&#039;s a problem with BGA Studio; if so, your game likely reaches an end state immediately. Check your states.inc.php and your transitions.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): BGA service error ===&lt;br /&gt;
&lt;br /&gt;
You may have a syntax error in your dbmodel.sql.&lt;br /&gt;
&lt;br /&gt;
Or, you may be calling self::initStat() for a statistic that does not exist. Check the statistic name, and make sure you clicked &amp;quot;Reload statistics configuration&amp;quot; button in the admin console after making changes to stats.inc.php&lt;br /&gt;
&lt;br /&gt;
Or you may not have your states.inc.php set up correctly.&lt;br /&gt;
&lt;br /&gt;
You may have an error in your table.game.php file (such as &amp;lt;code&amp;gt;$result[&#039;x&#039;] = y;&amp;lt;/code&amp;gt; when $result is not an array).&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Table status of a starting game should be &#039;setup&#039; ===&lt;br /&gt;
&lt;br /&gt;
This error message appears when you start a one player game using the &amp;quot;Express Start&amp;quot; button.&lt;br /&gt;
&lt;br /&gt;
In normal situation, the game starts just after this message and everything should works normally. In this case, you can just ignore this message.&lt;br /&gt;
&lt;br /&gt;
If the games does not start, it is most probable that there is a syntax error in any of your php code (Check your states.inc.php and X.game.php)&lt;br /&gt;
&lt;br /&gt;
=== Fatal error during creation of database ebd_quoridor_389 Not logged ===&lt;br /&gt;
&lt;br /&gt;
Check that you didn&#039;t use $g_user or getCurrentPlayerId() in setupNewGame() function or in an &#039;args&#039; function of your state.&lt;br /&gt;
&lt;br /&gt;
As these functions are not consequences of a user action, there is no current player defined.&lt;br /&gt;
&lt;br /&gt;
As a general rule, you should use getActivePlayerId() and not getCurrentPlayerId(). See the [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine presentation on the game state machine] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Warning: Invalid argument supplied for foreach() in table.game.php ===&lt;br /&gt;
&lt;br /&gt;
   Warning: Invalid argument supplied for foreach() in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 129 &lt;br /&gt;
   Fatal error: Cannot unset string offsets in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 143&lt;br /&gt;
&lt;br /&gt;
That appears when your arg* function that suppose to return array of state arguments returns a scalar (a non-array) value&lt;br /&gt;
&lt;br /&gt;
=== The server reported an error ===&lt;br /&gt;
&lt;br /&gt;
During table creation: &amp;quot;The server reported an error&amp;quot; error shown and nothing else.&lt;br /&gt;
&lt;br /&gt;
If you cannot even create a table - there is syntax error in gameinfos.php, check it, reload it from management panel.&lt;br /&gt;
If still no luck copy clean version from template https://github.com/elaskavaia/bga-sharedcode/blob/master/gameinfos.inc.php&lt;br /&gt;
&lt;br /&gt;
== Game starts but I can&#039;t make a move ==&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I got &amp;quot;Move recorded, waiting for update ...&amp;quot; forever ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Move recorded&amp;quot; means that your ajaxcall request has been sent to the server and returned normally.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Waiting for update&amp;quot; means that your client interface is waiting for some notifications from the server that correspond to the move we just did.&lt;br /&gt;
&lt;br /&gt;
If this message stays forever, it is probably that your PHP code does not send any notification when the move happens, which is abnormal. To fix this: add a notifyAllPlayers or a notifyPlayer call in your PHP code.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Sending move to server...&amp;quot; then nothing and game resets to state before the move ===&lt;br /&gt;
&lt;br /&gt;
Its possible that server code get into infinite loops or thinks too much, in which case it will timeout and will be aborted without any extra logs (and db transaction you saw in the log won&#039;t be committed). You will usually see &amp;quot;Unable to connect to server&amp;quot; message on console in this case. You have to put more logging into server&lt;br /&gt;
to trace where it hangs.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Ajaxcall error: empty answer&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You either have missing self::ajaxResponse(); in your game.action.php method, or there is some problem with getting arguments (check that you are using btoa() on client when using AT_base64 arg type in action.php)&lt;br /&gt;
&lt;br /&gt;
=== Some player action is triggered randomly when I click somewhere on the game area ===&lt;br /&gt;
&lt;br /&gt;
You probably used &amp;quot;dojo.connect&amp;quot; on a null object. In this case, dojo.connect associate the event (ex: &amp;quot;onclick&amp;quot;) to the whole game area.&lt;br /&gt;
&lt;br /&gt;
Most of the time it happens in this situation, when my_object element does not exists:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   dojo.connect( $(&amp;quot;my_object&amp;quot;), &amp;quot;onclick&amp;quot;, this, (event)=&amp;gt;{})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To determine if this is the case, place &amp;quot;alert( $(&amp;quot;my_object&amp;quot;) )&amp;quot; before the dojo.connect to check if the object exists or not.&lt;br /&gt;
&lt;br /&gt;
=== Error: This is not your turn ===&lt;br /&gt;
&lt;br /&gt;
This happens when checkAction() is called and current player is NOT the active player.&lt;br /&gt;
&lt;br /&gt;
You can change the active player in studio by clicking the red arrow next to their name in the player panel (right side of the page).&lt;br /&gt;
&lt;br /&gt;
[[File:Change_active_player.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Error: Please wait, an action is already in progress ===&lt;br /&gt;
Its followed by error &amp;quot;(Generated by checkAction / XXX)&amp;quot; on studio.&lt;br /&gt;
&lt;br /&gt;
This error is triggered in the JS by the checkAction function for XXX action.&lt;br /&gt;
&lt;br /&gt;
This can happen when the player sent an Ajax request action earlier, and:&lt;br /&gt;
* action is not complete yet - i.e. takes some time, and user clicked something again &lt;br /&gt;
* if there is bug in interface where MULTIPLE handlers are fired on same click. To debug this add some console.trace() in place this specific checkAction is called.&lt;br /&gt;
* did not get any notification from the PHP side. To avoid this, put an empty notifyPlayer in the PHP side of the Ajax handler to ensure the client receives a response. This line of code should do it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyPlayer($this-&amp;gt;getCurrentPlayerId(), &#039;message&#039;, &#039;&#039;, []); // sent to current player, who originated the action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error: This move is not authorized now ===&lt;br /&gt;
This is generic error message generated by this.showMoveUnauthorized() function. If you did not call this function yourself, check the console log, it may have additional information.&lt;br /&gt;
If you see &amp;quot;Move not authorized now : XXX&amp;quot; in the log, where XXX is your action name - this means that action XXX is not defined in list of possible actions for your current state. This error generated by checkAction() function.&lt;br /&gt;
&lt;br /&gt;
== Predefined server errors ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Unexpected final game state (XX) ===&lt;br /&gt;
&lt;br /&gt;
The action function does not transition to any state, i.e.&lt;br /&gt;
  function selectField($field) {&lt;br /&gt;
    self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
    if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
  }&lt;br /&gt;
Here if $field is 0 there is no transition&lt;br /&gt;
&lt;br /&gt;
=== This game action is impossible right now ===&lt;br /&gt;
&lt;br /&gt;
Check the game log. Usually your state does not define the action you trying to perform in &#039;possibleactions&#039; array.&lt;br /&gt;
&lt;br /&gt;
Also check your onActionName javascript function. Make sure you are calling the right &amp;quot;actionname.html&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: This transition (playerTurn) is impossible at this state (42) ===&lt;br /&gt;
&lt;br /&gt;
This is pretty self explanatory. Function nextState() takes transition name not a state name, so you probably did not&lt;br /&gt;
define this transition that the given state&lt;br /&gt;
&lt;br /&gt;
== Game interface hangs during reload or on start ==&lt;br /&gt;
&lt;br /&gt;
Showing &amp;quot;Application Loading...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload undefined no_stack_avail Script: ===&lt;br /&gt;
&lt;br /&gt;
This error usually has no useful data, but it means you called somes API that require a callback and did not define callback function, i.e&lt;br /&gt;
in dojo.connect, this.connectClass, dojo.subscribe, etc&lt;br /&gt;
   &lt;br /&gt;
      this.connectClass(&#039;field&#039;, &#039;onclick&#039;, &#039;onField&#039;); // &amp;lt;-- onField is not defined&lt;br /&gt;
&lt;br /&gt;
=== Other errors with &amp;quot;Application loading...&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You probably have a syntax error in your Javascript code, and the interface refuses to load.&lt;br /&gt;
&lt;br /&gt;
To find this error, check if there is an error message in the Javascript console (F12).&lt;br /&gt;
&lt;br /&gt;
If there is really nothing on the log, it&#039;s probably that the system was unable to load your Javascript because of an syntax error that affect the structure of the Javascript file, typically a missing &amp;quot;}&amp;quot; or a missing &amp;quot;,&amp;quot; after a method definition.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;Uncaught ReferenceError: bgagame is not defined&amp;quot; you have major syntax error in your js file, you should see some other clues in the log where the errors is.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;dojo.publish is not defined&amp;quot; or something similar, this could be caused by another error earlier. For example, a syntax error caused by a malformed generated file (such as using newlines in tiebreaker description). Also you might have left some images in the /img directory with special characters in the name which must be removed. If you edited images for the game box and website, ensure that you have not left any unnecessary files there.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Syntax Error: ===&lt;br /&gt;
&lt;br /&gt;
No further details in the log. When log is filling with some social connect errors.&lt;br /&gt;
&lt;br /&gt;
Possible Reason: Syntax error in of the php script which is loaded before the start, such as gameoptions.inc.php, gameinfos.inc.php and such.&lt;br /&gt;
&lt;br /&gt;
=== Game interface spins in a loop throwing error ===&lt;br /&gt;
&lt;br /&gt;
Errors is something like &amp;quot;Cannot read property &#039;is_ai&#039; of undefined&amp;quot;. Cannot restart the game because cannot access UI to stop.&lt;br /&gt;
Likely you get in actplayer state with player id == 0. The only way to fix it is to edit database, globals index == 2 set player id to one of your test dudes&lt;br /&gt;
(can copy from row 5 for example).&lt;br /&gt;
&lt;br /&gt;
=== Unable to find table database (1): ebd_yourgame_112222 ===&lt;br /&gt;
&lt;br /&gt;
Its either temporarily server error especially on studio it timeouts sometimes, just try reloading again.&lt;br /&gt;
Or check if you have syntax errors in your php game file or sql.&lt;br /&gt;
&lt;br /&gt;
== Type conversion / juggling errors ==&lt;br /&gt;
&lt;br /&gt;
=== On php side I get a number instead of string I expect ===&lt;br /&gt;
&lt;br /&gt;
 $num = 3;&lt;br /&gt;
 $meeple = &amp;quot;meeple_&amp;quot; + $num; // &amp;lt;-- suppose to be &amp;quot;meeple_3&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
When you switch between JS and PHP it easy to type this and not notice the +. Plus sign (+) in php does not mean string concatenation (in javascript does!),&lt;br /&gt;
in php + means integer arithmetic. So change + to . (dot)&lt;br /&gt;
&lt;br /&gt;
=== On php side my string comparison does not work ===&lt;br /&gt;
&lt;br /&gt;
   if ($color == &#039;4baae2&#039; || $color == &#039;000000&#039;) { &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Apparently you should not be using &#039;==&#039; in php to compare strings! You should use &#039;===&#039;. The (==) operator will typecast the strings &lt;br /&gt;
to numbers then do comparison!&lt;br /&gt;
Its not very apparent because usually you can get away with it, but not when strings resemble numbers like hex &#039;colors&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Integer columns in the database are returned as strings ===&lt;br /&gt;
&lt;br /&gt;
This is normal PHP behavior. All fields are returned as string type, regardless of their actual type in the database. This also applies to global variables accessed via getGameStateValue(), since they are stored in a database table.&lt;br /&gt;
&lt;br /&gt;
You can use type-casting to convert them to the correct type after they come out of the database.&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = (int)self::getGameStateValue(GLOBAL_ROUND_NUMBER);&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = self::getGameStateValue(GLOBAL_ROUND_NUMBER) + 0; // adding 0 casts to int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
same with direct qdb ueries&lt;br /&gt;
   $sql = &amp;quot;SELECT my_int_column FROM my_table WHERE my_condition&amp;quot;;&lt;br /&gt;
   $myResult = self::getUniqueValueFromDB($sql); &amp;lt;-- this is a string&lt;br /&gt;
   $myResultAsInt = (int)$myResult;&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/5323146/mysql-integer-field-is-returned-as-string-in-php&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: zombie): Not logged ===&lt;br /&gt;
&lt;br /&gt;
You are probably calling getCurrentPlayerId() or getCurrentPlayerName() in your zombieTurn method or any of the methods it uses. Instead, use the $active_player_id provided as parameter to zombieTurn().&lt;br /&gt;
&lt;br /&gt;
If you do not see these commands within &amp;quot;function zombieTurn( $state, $active_player ){}&amp;quot;, check all the functions called from zombieTurn, also &amp;quot;function getGameProgression(){}&amp;quot; and all the functions THAT calls.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Can&#039;t manage zombie player in this game state ===&lt;br /&gt;
&lt;br /&gt;
The state the game was in at the time the error was generated didn&#039;t have &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;zombiePass&amp;quot; =&amp;gt; 27 )&amp;quot; in states.inc.php (27 was an arbitrary example, but everything else must be spelled exactly that way.)&lt;br /&gt;
&lt;br /&gt;
To correct this error, either add &amp;quot;zombiePass&amp;quot; =&amp;gt; ## to the transitions array or work out why the game is in a state it should not be in.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: zombie): ===&lt;br /&gt;
&lt;br /&gt;
This is almost certainly an undefined value in PHP code. Look for a warning or error message in the game replay log on the right side of the table UI.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: BGA gameserver 1 do not respond (method: zombie) (timeout: cluster) ===&lt;br /&gt;
&lt;br /&gt;
You are trying to end the game from a zombie method. This is not allowed. The zombie logic must continue the game as best it can. See [[Main_game_logic:_yourgamename.game.php#Zombie_mode|Zombie mode]] for more info.&lt;br /&gt;
&lt;br /&gt;
=== Game unexpectedly ends when one player becomes zombie ===&lt;br /&gt;
&lt;br /&gt;
There is an error in handling zombie mode, check error log. Example: if the zombie turn is called again, framework detects a infinite loop and cancels the game. On the studio there is a notification called ZombieTurnFailed&lt;br /&gt;
&lt;br /&gt;
== Other errors ==&lt;br /&gt;
&lt;br /&gt;
=== Javascript does not know how to sum two numbers ===&lt;br /&gt;
&lt;br /&gt;
Be careful when you manipulate integers returned by notifications: most of the time, Javascript considers they are Strings and not Integers.&lt;br /&gt;
&lt;br /&gt;
As a result:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += notif.args.increment;  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=11 instead of 2 !! Javascript concatenate 2 strings !&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To solve this, you should use the &amp;quot;toint&amp;quot; function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += toint( notif.args.increment );  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=2 :)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Javascript: do not use substr with negative numbers ===&lt;br /&gt;
&lt;br /&gt;
To get the last characters of a string, use &amp;quot;slice&amp;quot; instead of &amp;quot;substr&amp;quot; which has a bug on IE:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var three_last_characters = string.substr( -3 );   // Wrong&lt;br /&gt;
    var three_last_characters = string.slice( -3 );    // Correct&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Game &amp;quot;spontaneously&amp;quot; transition to a new state without user input ===&lt;br /&gt;
&lt;br /&gt;
Make sure on php side you have no code after   $this-&amp;gt;gamestate-&amp;gt;nextState(...) code.&lt;br /&gt;
Because if you do accidentally have code that goes to another state it will cause another state transition without user interaction.&lt;br /&gt;
&lt;br /&gt;
 function selectField($field) {&lt;br /&gt;
   self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
   if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
   $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;last&#039; ); // &amp;lt;-- here is missing else, so it will cause double state transition&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=9834</id>
		<title>Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=9834"/>
		<updated>2021-10-20T12:29:47Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: adding error on setup with one player express start&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
Describing common errors which is hard to understand and debug &lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Game does not start at all ==&lt;br /&gt;
&lt;br /&gt;
=== Undefined offset: 0 in table/table.game.php on line 830 ===&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re calling self::getActivePlayerName () during setupNewGame()&lt;br /&gt;
&lt;br /&gt;
Check if you&#039;re NOT calling self::activeNextPlayer() at the end of your game setup. You must always have at least one active player.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: createGame): ... ===&lt;br /&gt;
&lt;br /&gt;
This is generic message usually followed by exact position in your source code, and usually its syntax error in one of yours php script&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Not logged ===&lt;br /&gt;
&lt;br /&gt;
Calling self::getCurrentPlayerId () or using $g_user from &#039;args&#039; state function, see also below&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Unknow player statistic: ===&lt;br /&gt;
&lt;br /&gt;
Calling self::incStat() with second parameter which is an empty string&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats ... ===&lt;br /&gt;
&lt;br /&gt;
Fatal error during yourgame setup: Error while processing SQL request: INSERT INTO stats (stats_type, stats_player_id, stats_value) VALUES (&#039;10&#039;,&#039;2300663&#039;,&#039;0&#039;),(&#039;10&#039;,&#039;2300662&#039;,&#039;0&#039;)&lt;br /&gt;
Duplicate entry &#039;10-2300663&#039; for key &#039;stats_table_id&#039;&lt;br /&gt;
&lt;br /&gt;
Why? In the stats.inc.php you declared two keys with the same integer &amp;quot;id&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error:  Propagating error from GS 1 (method: createGame): Fatal error during yourgame setup: BGA main website do not respond ===&lt;br /&gt;
&lt;br /&gt;
Check if other games work; if not, it&#039;s a problem with BGA Studio; if so, your game likely reaches an end state immediately. Check your states.inc.php and your transitions.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: createGame): BGA service error ===&lt;br /&gt;
&lt;br /&gt;
You may have a syntax error in your dbmodel.sql.&lt;br /&gt;
&lt;br /&gt;
Or, you may be calling self::initStat() for a statistic that does not exist. Check the statistic name, and make sure you clicked &amp;quot;Reload statistics configuration&amp;quot; button in the admin console after making changes to stats.inc.php&lt;br /&gt;
&lt;br /&gt;
Or you may not have your states.inc.php set up correctly.&lt;br /&gt;
&lt;br /&gt;
You may have an error in your table.game.php file (such as &amp;lt;code&amp;gt;$result[&#039;x&#039;] = y;&amp;lt;/code&amp;gt; when $result is not an array).&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Table status of a starting game should be &#039;setup&#039; ===&lt;br /&gt;
&lt;br /&gt;
This error message appears when you start a one player game using the &amp;quot;Express Start&amp;quot; button.&lt;br /&gt;
In normal situation, the game starts just after this message and everything should works normally. In this case, you can just ignore this message.&lt;br /&gt;
If the games does not start, it is most probable that there is a syntax error in any of your php code (Check your states.inc.php and X.game.php)&lt;br /&gt;
&lt;br /&gt;
=== Fatal error during creation of database ebd_quoridor_389 Not logged ===&lt;br /&gt;
&lt;br /&gt;
Check that you didn&#039;t use $g_user or getCurrentPlayerId() in setupNewGame() function or in an &#039;args&#039; function of your state.&lt;br /&gt;
&lt;br /&gt;
As these functions are not consequences of a user action, there is no current player defined.&lt;br /&gt;
&lt;br /&gt;
As a general rule, you should use getActivePlayerId() and not getCurrentPlayerId(). See the [http://www.slideshare.net/boardgamearena/bga-studio-focus-on-bga-game-state-machine presentation on the game state machine] for more information.&lt;br /&gt;
&lt;br /&gt;
=== Warning: Invalid argument supplied for foreach() in table.game.php ===&lt;br /&gt;
&lt;br /&gt;
   Warning: Invalid argument supplied for foreach() in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 129 &lt;br /&gt;
   Fatal error: Cannot unset string offsets in /var/tournoi/release/tournoi-151226-1240-gs/www/game/module/table/table.game.php on line 143&lt;br /&gt;
&lt;br /&gt;
That appears when your arg* function that suppose to return array of state arguments returns a scalar (a non-array) value&lt;br /&gt;
&lt;br /&gt;
=== The server reported an error ===&lt;br /&gt;
&lt;br /&gt;
During table creation: &amp;quot;The server reported an error&amp;quot; error shown and nothing else.&lt;br /&gt;
&lt;br /&gt;
If you cannot even create a table - there is syntax error in gameinfos.php, check it, reload it from management panel.&lt;br /&gt;
If still no luck copy clean version from template https://github.com/elaskavaia/bga-sharedcode/blob/master/gameinfos.inc.php&lt;br /&gt;
&lt;br /&gt;
== Game starts but I can&#039;t make a move ==&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I got &amp;quot;Move recorded, waiting for update ...&amp;quot; forever ===&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Move recorded&amp;quot; means that your ajaxcall request has been sent to the server and returned normally.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Waiting for update&amp;quot; means that your client interface is waiting for some notifications from the server that correspond to the move we just did.&lt;br /&gt;
&lt;br /&gt;
If this message stays forever, it is probably that your PHP code does not send any notification when the move happens, which is abnormal. To fix this: add a notifyAllPlayers or a notifyPlayer call in your PHP code.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Sending move to server...&amp;quot; then nothing and game resets to state before the move ===&lt;br /&gt;
&lt;br /&gt;
Its possible that server code get into infinite loops or thinks too much, in which case it will timeout and will be aborted without any extra logs (and db transaction you saw in the log won&#039;t be committed). You will usually see &amp;quot;Unable to connect to server&amp;quot; message on console in this case. You have to put more logging into server&lt;br /&gt;
to trace where it hangs.&lt;br /&gt;
&lt;br /&gt;
=== When I do a move, I get &amp;quot;Ajaxcall error: empty answer&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You either have missing self::ajaxResponse(); in your game.action.php method, or there is some problem with getting arguments (check that you are using btoa() on client when using AT_base64 arg type in action.php)&lt;br /&gt;
&lt;br /&gt;
=== Some player action is triggered randomly when I click somewhere on the game area ===&lt;br /&gt;
&lt;br /&gt;
You probably used &amp;quot;dojo.connect&amp;quot; on a null object. In this case, dojo.connect associate the event (ex: &amp;quot;onclick&amp;quot;) to the whole game area.&lt;br /&gt;
&lt;br /&gt;
Most of the time it happens in this situation, when my_object element does not exists:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   dojo.connect( $(&amp;quot;my_object&amp;quot;), &amp;quot;onclick&amp;quot;, this, (event)=&amp;gt;{})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To determine if this is the case, place &amp;quot;alert( $(&amp;quot;my_object&amp;quot;) )&amp;quot; before the dojo.connect to check if the object exists or not.&lt;br /&gt;
&lt;br /&gt;
=== Error: This is not your turn ===&lt;br /&gt;
&lt;br /&gt;
This happens when checkAction() is called and current player is NOT the active player.&lt;br /&gt;
&lt;br /&gt;
You can change the active player in studio by clicking the red arrow next to their name in the player panel (right side of the page).&lt;br /&gt;
&lt;br /&gt;
[[File:Change_active_player.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Error: Please wait, an action is already in progress ===&lt;br /&gt;
Its followed by error &amp;quot;(Generated by checkAction / XXX)&amp;quot; on studio.&lt;br /&gt;
&lt;br /&gt;
This error is triggered in the JS by the checkAction function for XXX action.&lt;br /&gt;
&lt;br /&gt;
This can happen when the player sent an Ajax request action earlier, and:&lt;br /&gt;
* action is not complete yet - i.e. takes some time, and user clicked something again &lt;br /&gt;
* if there is bug in interface where MULTIPLE handlers are fired on same click. To debug this add some console.trace() in place this specific checkAction is called.&lt;br /&gt;
* did not get any notification from the PHP side. To avoid this, put an empty notifyPlayer in the PHP side of the Ajax handler to ensure the client receives a response. This line of code should do it:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notifyPlayer($this-&amp;gt;getCurrentPlayerId(), &#039;message&#039;, &#039;&#039;, []); // sent to current player, who originated the action&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Error: This move is not authorized now ===&lt;br /&gt;
This is generic error message generated by this.showMoveUnauthorized() function. If you did not call this function yourself, check the console log, it may have additional information.&lt;br /&gt;
If you see &amp;quot;Move not authorized now : XXX&amp;quot; in the log, where XXX is your action name - this means that action XXX is not defined in list of possible actions for your current state. This error generated by checkAction() function.&lt;br /&gt;
&lt;br /&gt;
== Predefined server errors ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Unexpected final game state (XX) ===&lt;br /&gt;
&lt;br /&gt;
The action function does not transition to any state, i.e.&lt;br /&gt;
  function selectField($field) {&lt;br /&gt;
    self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
    if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
  }&lt;br /&gt;
Here if $field is 0 there is no transition&lt;br /&gt;
&lt;br /&gt;
=== This game action is impossible right now ===&lt;br /&gt;
&lt;br /&gt;
Check the game log. Usually your state does not define the action you trying to perform in &#039;possibleactions&#039; array.&lt;br /&gt;
&lt;br /&gt;
Also check your onActionName javascript function. Make sure you are calling the right &amp;quot;actionname.html&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: This transition (playerTurn) is impossible at this state (42) ===&lt;br /&gt;
&lt;br /&gt;
This is pretty self explanatory. Function nextState() takes transition name not a state name, so you probably did not&lt;br /&gt;
define this transition that the given state&lt;br /&gt;
&lt;br /&gt;
== Game interface hangs during reload or on start ==&lt;br /&gt;
&lt;br /&gt;
Showing &amp;quot;Application Loading...&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Javascript error: During pageload undefined no_stack_avail Script: ===&lt;br /&gt;
&lt;br /&gt;
This error usually has no useful data, but it means you called somes API that require a callback and did not define callback function, i.e&lt;br /&gt;
in dojo.connect, this.connectClass, dojo.subscribe, etc&lt;br /&gt;
   &lt;br /&gt;
      this.connectClass(&#039;field&#039;, &#039;onclick&#039;, &#039;onField&#039;); // &amp;lt;-- onField is not defined&lt;br /&gt;
&lt;br /&gt;
=== Other errors with &amp;quot;Application loading...&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
You probably have a syntax error in your Javascript code, and the interface refuses to load.&lt;br /&gt;
&lt;br /&gt;
To find this error, check if there is an error message in the Javascript console (F12).&lt;br /&gt;
&lt;br /&gt;
If there is really nothing on the log, it&#039;s probably that the system was unable to load your Javascript because of an syntax error that affect the structure of the Javascript file, typically a missing &amp;quot;}&amp;quot; or a missing &amp;quot;,&amp;quot; after a method definition.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;Uncaught ReferenceError: bgagame is not defined&amp;quot; you have major syntax error in your js file, you should see some other clues in the log where the errors is.&lt;br /&gt;
&lt;br /&gt;
If you have &amp;quot;dojo.publish is not defined&amp;quot; or something similar, this could be caused by another error earlier. For example, a syntax error caused by a malformed generated file (such as using newlines in tiebreaker description). Also you might have left some images in the /img directory with special characters in the name which must be removed. If you edited images for the game box and website, ensure that you have not left any unnecessary files there.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected Syntax Error: ===&lt;br /&gt;
&lt;br /&gt;
No further details in the log. When log is filling with some social connect errors.&lt;br /&gt;
&lt;br /&gt;
Possible Reason: Syntax error in of the php script which is loaded before the start, such as gameoptions.inc.php, gameinfos.inc.php and such.&lt;br /&gt;
&lt;br /&gt;
=== Game interface spins in a loop throwing error ===&lt;br /&gt;
&lt;br /&gt;
Errors is something like &amp;quot;Cannot read property &#039;is_ai&#039; of undefined&amp;quot;. Cannot restart the game because cannot access UI to stop.&lt;br /&gt;
Likely you get in actplayer state with player id == 0. The only way to fix it is to edit database, globals index == 2 set player id to one of your test dudes&lt;br /&gt;
(can copy from row 5 for example).&lt;br /&gt;
&lt;br /&gt;
=== Unable to find table database (1): ebd_yourgame_112222 ===&lt;br /&gt;
&lt;br /&gt;
Its either temporarily server error especially on studio it timeouts sometimes, just try reloading again.&lt;br /&gt;
Or check if you have syntax errors in your php game file or sql.&lt;br /&gt;
&lt;br /&gt;
== Type conversion / juggling errors ==&lt;br /&gt;
&lt;br /&gt;
=== On php side I get a number instead of string I expect ===&lt;br /&gt;
&lt;br /&gt;
 $num = 3;&lt;br /&gt;
 $meeple = &amp;quot;meeple_&amp;quot; + $num; // &amp;lt;-- suppose to be &amp;quot;meeple_3&amp;quot;!&lt;br /&gt;
&lt;br /&gt;
When you switch between JS and PHP it easy to type this and not notice the +. Plus sign (+) in php does not mean string concatenation (in javascript does!),&lt;br /&gt;
in php + means integer arithmetic. So change + to . (dot)&lt;br /&gt;
&lt;br /&gt;
=== On php side my string comparison does not work ===&lt;br /&gt;
&lt;br /&gt;
   if ($color == &#039;4baae2&#039; || $color == &#039;000000&#039;) { &lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
Apparently you should not be using &#039;==&#039; in php to compare strings! You should use &#039;===&#039;. The (==) operator will typecast the strings &lt;br /&gt;
to numbers then do comparison!&lt;br /&gt;
Its not very apparent because usually you can get away with it, but not when strings resemble numbers like hex &#039;colors&#039;.&lt;br /&gt;
&lt;br /&gt;
=== Integer columns in the database are returned as strings ===&lt;br /&gt;
&lt;br /&gt;
This is normal PHP behavior. All fields are returned as string type, regardless of their actual type in the database. This also applies to global variables accessed via getGameStateValue(), since they are stored in a database table.&lt;br /&gt;
&lt;br /&gt;
You can use type-casting to convert them to the correct type after they come out of the database.&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = (int)self::getGameStateValue(GLOBAL_ROUND_NUMBER);&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
   $myValueInt = self::getGameStateValue(GLOBAL_ROUND_NUMBER) + 0; // adding 0 casts to int&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
same with direct qdb ueries&lt;br /&gt;
   $sql = &amp;quot;SELECT my_int_column FROM my_table WHERE my_condition&amp;quot;;&lt;br /&gt;
   $myResult = self::getUniqueValueFromDB($sql); &amp;lt;-- this is a string&lt;br /&gt;
   $myResultAsInt = (int)$myResult;&lt;br /&gt;
&lt;br /&gt;
https://stackoverflow.com/questions/5323146/mysql-integer-field-is-returned-as-string-in-php&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Propagating error from GS 1 (method: zombie): Not logged ===&lt;br /&gt;
&lt;br /&gt;
You are probably calling getCurrentPlayerId() or getCurrentPlayerName() in your zombieTurn method or any of the methods it uses. Instead, use the $active_player_id provided as parameter to zombieTurn().&lt;br /&gt;
&lt;br /&gt;
If you do not see these commands within &amp;quot;function zombieTurn( $state, $active_player ){}&amp;quot;, check all the functions called from zombieTurn, also &amp;quot;function getGameProgression(){}&amp;quot; and all the functions THAT calls.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Can&#039;t manage zombie player in this game state ===&lt;br /&gt;
&lt;br /&gt;
The state the game was in at the time the error was generated didn&#039;t have &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;zombiePass&amp;quot; =&amp;gt; 27 )&amp;quot; in states.inc.php (27 was an arbitrary example, but everything else must be spelled exactly that way.)&lt;br /&gt;
&lt;br /&gt;
To correct this error, either add &amp;quot;zombiePass&amp;quot; =&amp;gt; ## to the transitions array or work out why the game is in a state it should not be in.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: Wrong formatted data from BGA gameserver 1 (method: zombie): ===&lt;br /&gt;
&lt;br /&gt;
This is almost certainly an undefined value in PHP code. Look for a warning or error message in the game replay log on the right side of the table UI.&lt;br /&gt;
&lt;br /&gt;
=== Unexpected error: BGA gameserver 1 do not respond (method: zombie) (timeout: cluster) ===&lt;br /&gt;
&lt;br /&gt;
You are trying to end the game from a zombie method. This is not allowed. The zombie logic must continue the game as best it can. See [[Main_game_logic:_yourgamename.game.php#Zombie_mode|Zombie mode]] for more info.&lt;br /&gt;
&lt;br /&gt;
=== Game unexpectedly ends when one player becomes zombie ===&lt;br /&gt;
&lt;br /&gt;
There is an error in handling zombie mode, check error log. Example: if the zombie turn is called again, framework detects a infinite loop and cancels the game. On the studio there is a notification called ZombieTurnFailed&lt;br /&gt;
&lt;br /&gt;
== Other errors ==&lt;br /&gt;
&lt;br /&gt;
=== Javascript does not know how to sum two numbers ===&lt;br /&gt;
&lt;br /&gt;
Be careful when you manipulate integers returned by notifications: most of the time, Javascript considers they are Strings and not Integers.&lt;br /&gt;
&lt;br /&gt;
As a result:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += notif.args.increment;  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=11 instead of 2 !! Javascript concatenate 2 strings !&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To solve this, you should use the &amp;quot;toint&amp;quot; function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var i=1;&lt;br /&gt;
    i += toint( notif.args.increment );  // With notif.args.increment=&#039;1&#039;&lt;br /&gt;
    alert( i );                 // i=2 :)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Javascript: do not use substr with negative numbers ===&lt;br /&gt;
&lt;br /&gt;
To get the last characters of a string, use &amp;quot;slice&amp;quot; instead of &amp;quot;substr&amp;quot; which has a bug on IE:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var three_last_characters = string.substr( -3 );   // Wrong&lt;br /&gt;
    var three_last_characters = string.slice( -3 );    // Correct&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Game &amp;quot;spontaneously&amp;quot; transition to a new state without user input ===&lt;br /&gt;
&lt;br /&gt;
Make sure on php side you have no code after   $this-&amp;gt;gamestate-&amp;gt;nextState(...) code.&lt;br /&gt;
Because if you do accidentally have code that goes to another state it will cause another state transition without user interaction.&lt;br /&gt;
&lt;br /&gt;
 function selectField($field) {&lt;br /&gt;
   self::checkAction ( &#039;selectField&#039; );&lt;br /&gt;
   if ($field!=0) $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;next&#039; );&lt;br /&gt;
   $this-&amp;gt;gamestate-&amp;gt;nextState ( &#039;last&#039; ); // &amp;lt;-- here is missing else, so it will cause double state transition&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=9461</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=9461"/>
		<updated>2021-09-24T08:23:43Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* States functions */&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. Returns a number indicating percent of progression (0-100)&lt;br /&gt;
* Utility functions: your utility functions.&lt;br /&gt;
* Player actions: the entry points for players actions ([https://en.doc.boardgamearena.com/Players_actions:_yourgamename.action.php more info here]). &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;
; getPlayerNameById($player_id)&lt;br /&gt;
: Get the name by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerColorById($player_id)&lt;br /&gt;
: Get the color by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerNoById($player_id)&lt;br /&gt;
: Get &#039;player_no&#039; (number) by id&lt;br /&gt;
&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;
: &amp;lt;code&amp;gt;array_keys($this-&amp;gt;loadPlayersBasicInfos())&amp;lt;/code&amp;gt; will therefore returns an array containing players id&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;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
                foreach ($players as $player_id =&amp;gt; $info) {&lt;br /&gt;
                    $player_color = $info[&#039;player_color&#039;];&lt;br /&gt;
                    ...&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: if you want array of player ids only you can do this:&lt;br /&gt;
    $player_ids =  array_keys($this-&amp;gt;loadPlayersBasicInfos());  &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;
; isSpectator()&lt;br /&gt;
: Check the &amp;quot;current_player&amp;quot; spectator status. If true, the user accessing the game is a spectator (not part of the game). For this user, the interface should display all public information, and no private information (like a friend sitting at the same table as players and just spectating 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;
; isPlayerZombie($player_id)&lt;br /&gt;
: This method does not exists, but if you need it it looks like this&lt;br /&gt;
    protected function isPlayerZombie($player_id) {&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        if (! isset($players[$player_id]))&lt;br /&gt;
            throw new feException(&amp;quot;Player $player_id is not playing here&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        return ($players[$player_id][&#039;player_zombie&#039;] == 1);&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;
However there sets of database operation that initite implicit commit (most common mistake is to use &amp;quot;TRUNCATE&amp;quot;), you cannot use these operations during the game, it breaks the unrolling of transactions and will lead to nasty issues&lt;br /&gt;
(https://mariadb.com/kb/en/sql-statements-that-cause-an-implicit-commit).&lt;br /&gt;
&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 __construct() method of &#039;&#039;yourgamename.game.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;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $this-&amp;gt;GAMESTATELABELS = [&amp;quot;my_first_global_variable&amp;quot; =&amp;gt; 10, &amp;quot;my_second_global_variable&amp;quot; =&amp;gt; 11];&lt;br /&gt;
        self::initGameStateLabels($this-&amp;gt;GAMESTATELABELS);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&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. $value_value must be an integer.&lt;br /&gt;
&lt;br /&gt;
It seems that a non initialized value will not be restored with undo system, so it is therefore advisable to initialize them all in your &amp;quot;setupNewGame&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;foreach ($this-&amp;gt;GAMESTATELABELS as $value_label=&amp;gt; $ID) if ($ID &amp;gt;= 10 &amp;amp;&amp;amp; $ID &amp;lt; 90) self::setGameStateInitialValue($value_label, 0);&amp;lt;/pre&amp;gt;&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;
For debugging purposes, you can have labels and value pairs send to client side by inserting that line of code in your &amp;quot;getAllDatas&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;$result[&#039;labels&#039;] = array_combine(array_keys($this-&amp;gt;GAMESTATELABELS), array_map(&#039;self::getGameStateValue&#039;, array_keys($this-&amp;gt;GAMESTATELABELS)));&amp;lt;/pre&amp;gt;&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. $value_value must be an integer.&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;
; $this-&amp;gt;gamestate-&amp;gt;state_id()&lt;br /&gt;
: Get the id of the current game state&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;
N.B: This function &#039;&#039;&#039;DOES NOT&#039;&#039;&#039; allow to change players turn 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;
=== NotifyAllPlayers ===&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 translated.&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;
* 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 if 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;
&#039;&#039;&#039;Important&#039;&#039;&#039;: When the game page is reloaded (i.e. F5 or when loading turn based game) all previous notifications are replayed as history notifications. These notifications do not trigger notification handlers and are used basically to build the game log. Because of that most of the notification arguments, except i18n, player_id and all arguments used in the message, are removed from these history notifications. If you need additional arguments in history notifications you can add special field &amp;lt;b&amp;gt;preserve&amp;lt;/b&amp;gt; to notification arguments, like this:&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;
        &#039;preserve&#039; =&amp;gt; [ &#039;x&#039;, &#039;y&#039; ]&lt;br /&gt;
     ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In this example, fields x and y will be preserved when replaying history notification at the game load.&lt;br /&gt;
&lt;br /&gt;
==== HTML in Notifications ====&lt;br /&gt;
&lt;br /&gt;
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 replay 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 replay, 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;
==== Recursive Notifications ====&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;
==== Excluding some players ====&lt;br /&gt;
&lt;br /&gt;
Sometimes you want to notify all players of a message but not have it appear in the log of specific players (for example, have every player see &amp;quot;Player X draws a card&amp;quot; but have Player X see &amp;quot;You draw the Ace of Spades&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
To send a notification to all players but have some clients ignore it, send it as normal from the server, but implement &#039;&#039;&#039;setIgnoreNotificationCheck&#039;&#039;&#039; on the client to ignore the message under given conditions. See the X.js documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== NotifyPlayer ===&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;
Note that spectators cannot be notified using this method, because their player ID is not available via loadPlayersBasicInfos() or otherwise. You must use notifyAllPlayers() for any notification that spectators should get.&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 play and can start another game if he/she wants too (with 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;
&#039;&#039;&#039;Important: this should not be used on a player who has already left the game (&amp;quot;zombie&amp;quot;) as leaving/being kicked of the game (outside of the scope of the rules) is not the same as being eliminated from the game (according to the rules), except if in the course of the game, the zombie player is eliminated according to the rules.&#039;&#039;&#039;&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;
Note: if you deploy undo support after game is in production this will take into effect for new games only, old games will give user an error if user choses Undo action, but otherwise it should not affect them.&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 they are not allowed to do.&lt;br /&gt;
: The error message will be shown to the player as a &amp;quot;red message&amp;quot;.&lt;br /&gt;
: The error message must be translated, make sure you use self::_() or $this-&amp;gt;_() here and NOT clientranslate()&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;
&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 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 check the code of &amp;quot;setupNewGame&amp;quot;. New template already have correct code, but if you editing very old game and it may be absent.&lt;br /&gt;
&lt;br /&gt;
        $gameinfos = $this-&amp;gt;getGameinfos();&lt;br /&gt;
        ...&lt;br /&gt;
        if ($gameinfos[&#039;favorite_colors_support&#039;])&lt;br /&gt;
            $this-&amp;gt;reattributeColorsBasedOnPreferences($players, $gameinfos[&#039;player_colors&#039;]); // this should be above reloadPlayersBasicInfos()&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;
Some important remarks:&lt;br /&gt;
* for some games (i.e. Chess), the color has an influence on a mechanism of the game, most of the time by giving a special advantage to a player (i.e. 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 (Note - you don&#039;t have to pick these, the &amp;quot;closest&amp;quot; color will be found):&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;
The keys may only contain letters and numbers, underscore seems not to be allowed.&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( $key, $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($key)&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>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=9457</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=9457"/>
		<updated>2021-09-23T10:30:13Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Notifications */ added info on the notification object received on client&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#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). 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 )&#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;
&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;
== 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;
  .bgaimagebutton {&lt;br /&gt;
	padding: 0px 12px;&lt;br /&gt;
	min-height: 28px;&lt;br /&gt;
        border: none;&lt;br /&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;
			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^2: You can also create button using addActionButton() method, then move anywhere&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;
&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>Nicotacotac</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=9433</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=9433"/>
		<updated>2021-09-21T13:26:25Z</updated>

		<summary type="html">&lt;p&gt;Nicotacotac: /* Accessing player information */ adding snippet for player&amp;#039;s id in array (to be used in loop for example)&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. Returns a number indicating percent of progression (0-100)&lt;br /&gt;
* Utility functions: your utility functions.&lt;br /&gt;
* Player actions: the entry points for players actions ([https://en.doc.boardgamearena.com/Players_actions:_yourgamename.action.php more info here]). &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;
; getPlayerNameById($player_id)&lt;br /&gt;
: Get the name by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerColorById($player_id)&lt;br /&gt;
: Get the color by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerNoById($player_id)&lt;br /&gt;
: Get &#039;player_no&#039; (number) by id&lt;br /&gt;
&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;
: &amp;lt;code&amp;gt;array_keys($this-&amp;gt;loadPlayersBasicInfos())&amp;lt;/code&amp;gt; will therefore returns an array containing players id&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;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
                foreach ($players as $player_id =&amp;gt; $info) {&lt;br /&gt;
                    $player_color = $info[&#039;player_color&#039;];&lt;br /&gt;
                    ...&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: if you want array of player ids only you can do this:&lt;br /&gt;
    $player_ids =  array_keys($this-&amp;gt;loadPlayersBasicInfos());  &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;
; isSpectator()&lt;br /&gt;
: Check the &amp;quot;current_player&amp;quot; spectator status. If true, the user accessing the game is a spectator (not part of the game). For this user, the interface should display all public information, and no private information (like a friend sitting at the same table as players and just spectating 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;
; isPlayerZombie($player_id)&lt;br /&gt;
: This method does not exists, but if you need it it looks like this&lt;br /&gt;
    protected function isPlayerZombie($player_id) {&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        if (! isset($players[$player_id]))&lt;br /&gt;
            throw new feException(&amp;quot;Player $player_id is not playing here&#039;);&lt;br /&gt;
        &lt;br /&gt;
        return ($players[$player_id][&#039;player_zombie&#039;] == 1);&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;
However there sets of database operation that initite implicit commit (most common mistake is to use &amp;quot;TRUNCATE&amp;quot;), you cannot use these operations during the game, it breaks the unrolling of transactions and will lead to nasty issues&lt;br /&gt;
(https://mariadb.com/kb/en/sql-statements-that-cause-an-implicit-commit).&lt;br /&gt;
&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 __construct() method of &#039;&#039;yourgamename.game.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;
or&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $this-&amp;gt;GAMESTATELABELS = [&amp;quot;my_first_global_variable&amp;quot; =&amp;gt; 10, &amp;quot;my_second_global_variable&amp;quot; =&amp;gt; 11];&lt;br /&gt;
        self::initGameStateLabels($this-&amp;gt;GAMESTATELABELS);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&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. $value_value must be an integer.&lt;br /&gt;
&lt;br /&gt;
It seems that a non initialized value will not be restored with undo system, so it is therefore advisable to initialize them all in your &amp;quot;setupNewGame&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;foreach ($this-&amp;gt;GAMESTATELABELS as $value_label=&amp;gt; $ID) if ($ID &amp;gt;= 10 &amp;amp;&amp;amp; $ID &amp;lt; 90) self::setGameStateInitialValue($value_label, 0);&amp;lt;/pre&amp;gt;&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;
For debugging purposes, you can have labels and value pairs send to client side by inserting that line of code in your &amp;quot;getAllDatas&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;$result[&#039;labels&#039;] = array_combine(array_keys($this-&amp;gt;GAMESTATELABELS), array_map(&#039;self::getGameStateValue&#039;, array_keys($this-&amp;gt;GAMESTATELABELS)));&amp;lt;/pre&amp;gt;&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. $value_value must be an integer.&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;
N.B: This function &#039;&#039;&#039;DOES NOT&#039;&#039;&#039; allow to change players turn 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;
=== NotifyAllPlayers ===&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 translated.&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;
* 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 if 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;
&#039;&#039;&#039;Important&#039;&#039;&#039;: When the game page is reloaded (i.e. F5 or when loading turn based game) all previous notifications are replayed as history notifications. These notifications do not trigger notification handlers and are used basically to build the game log. Because of that most of the notification arguments, except i18n, player_id and all arguments used in the message, are removed from these history notifications. If you need additional arguments in history notifications you can add special field &amp;lt;b&amp;gt;preserve&amp;lt;/b&amp;gt; to notification arguments, like this:&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;
        &#039;preserve&#039; =&amp;gt; [ &#039;x&#039;, &#039;y&#039; ]&lt;br /&gt;
     ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In this example, fields x and y will be preserved when replaying history notification at the game load.&lt;br /&gt;
&lt;br /&gt;
==== HTML in Notifications ====&lt;br /&gt;
&lt;br /&gt;
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 replay 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 replay, 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;
==== Recursive Notifications ====&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;
==== Excluding some players ====&lt;br /&gt;
&lt;br /&gt;
Sometimes you want to notify all players of a message but not have it appear in the log of specific players (for example, have every player see &amp;quot;Player X draws a card&amp;quot; but have Player X see &amp;quot;You draw the Ace of Spades&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
To send a notification to all players but have some clients ignore it, send it as normal from the server, but implement &#039;&#039;&#039;setIgnoreNotificationCheck&#039;&#039;&#039; on the client to ignore the message under given conditions. See the X.js documentation for more details.&lt;br /&gt;
&lt;br /&gt;
=== NotifyPlayer ===&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;
Note that spectators cannot be notified using this method, because their player ID is not available via loadPlayersBasicInfos() or otherwise. You must use notifyAllPlayers() for any notification that spectators should get.&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 play and can start another game if he/she wants too (with 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;
&#039;&#039;&#039;Important: this should not be used on a player who has already left the game (&amp;quot;zombie&amp;quot;) as leaving/being kicked of the game (outside of the scope of the rules) is not the same as being eliminated from the game (according to the rules), except if in the course of the game, the zombie player is eliminated according to the rules.&#039;&#039;&#039;&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;
Note: if you deploy undo support after game is in production this will take into effect for new games only, old games will give user an error if user choses Undo action, but otherwise it should not affect them.&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 they are not allowed to do.&lt;br /&gt;
: The error message will be shown to the player as a &amp;quot;red message&amp;quot;.&lt;br /&gt;
: The error message must be translated, make sure you use self::_() or $this-&amp;gt;_() here and NOT clientranslate()&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;
&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 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 check the code of &amp;quot;setupNewGame&amp;quot;. New template already have correct code, but if you editing very old game and it may be absent.&lt;br /&gt;
&lt;br /&gt;
        $gameinfos = $this-&amp;gt;getGameinfos();&lt;br /&gt;
        ...&lt;br /&gt;
        if ($gameinfos[&#039;favorite_colors_support&#039;])&lt;br /&gt;
            $this-&amp;gt;reattributeColorsBasedOnPreferences($players, $gameinfos[&#039;player_colors&#039;]); // this should be above reloadPlayersBasicInfos()&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;
Some important remarks:&lt;br /&gt;
* for some games (i.e. Chess), the color has an influence on a mechanism of the game, most of the time by giving a special advantage to a player (i.e. 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 (Note - you don&#039;t have to pick these, the &amp;quot;closest&amp;quot; color will be found):&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;
The keys may only contain letters and numbers, underscore seems not to be allowed.&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( $key, $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($key)&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>Nicotacotac</name></author>
	</entry>
</feed>