<?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=Inaofr</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=Inaofr"/>
	<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/Special:Contributions/Inaofr"/>
	<updated>2026-10-12T06:35:14Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.0</generator>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpstoneage&amp;diff=30428</id>
		<title>Gamehelpstoneage</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpstoneage&amp;diff=30428"/>
		<updated>2026-06-28T17:19:28Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* Mammoth Herd */ Indicate the cancelling of 2p/3p limitation at the mammoth position&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
You are the leader of a tribe during the Stone Age and must decide where to allocate your members to gather resources, build huts, and grow your civilization. While you advance, don&#039;t forget to keep your tribe fed or you will lose points.&lt;br /&gt;
&lt;br /&gt;
==Gameplay==&lt;br /&gt;
&lt;br /&gt;
Each player starts with 5 people and 12 food. &lt;br /&gt;
&lt;br /&gt;
Each round has 3 phases. &lt;br /&gt;
&lt;br /&gt;
==== Phase 1: Place Workers ====&lt;br /&gt;
&lt;br /&gt;
In turn order, each player assigns one or more workers to a place. Each place (except for the Hunting Grounds) has a set capacity. Only one tribe can occupy a place at a time. And if your tribe occupies the space, you cannot add more people from your tribe later. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;Variations Based on Number of Players&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Two Players&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Only 2 out of 3 places in the village (&#039;&#039;Tool Maker (tools)&#039;&#039;, &#039;&#039;Hut (gain worker)&#039;&#039;, and &#039;&#039;Field (increase food production)&#039;&#039;) may be occupied per turn. &lt;br /&gt;
&lt;br /&gt;
Only 1 player may place people in any of the resource areas (&#039;&#039;Forest&#039;&#039; (wood), &#039;&#039;Clay Pit&#039;&#039; (brick), &#039;&#039;Quarry&#039;&#039; (stone), and &#039;&#039;River&#039;&#039; (gold)).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Three Players&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Only 2 out of 3 places in the village (&#039;&#039;Tool Maker (tools)&#039;&#039;, &#039;&#039;Hut (gain worker)&#039;&#039;, and &#039;&#039;Field (increase food production)&#039;&#039;) may be occupied per turn (like a two-player game).&lt;br /&gt;
&lt;br /&gt;
Only 2 player may place people in any of the resource areas (&#039;&#039;Forest&#039;&#039; (wood), &#039;&#039;Clay Pit&#039;&#039; (brick), &#039;&#039;Quarry&#039;&#039; (stone), and &#039;&#039;River&#039;&#039; (gold)).&lt;br /&gt;
&lt;br /&gt;
==== Phase 2: Remove People and Gain Resources====&lt;br /&gt;
&lt;br /&gt;
In turn order, each player removes their people from each place and gains/pays for the benefits of that place. &lt;br /&gt;
&lt;br /&gt;
The following formula determines the number of resources received: For each worker placed, a die is rolled. The total of all dice is divided by the resource&#039;s &amp;quot;value&amp;quot; (the rarer the resource, the higher the number). The resulting whole number (remainder ignored) is the total resources received.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;Places&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:auto;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
!| Name || Resource || Capacity || Description&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Hunting Grounds&#039;&#039;&#039; || Food || -- || Roll dice equal to # of workers placed. Dice total ÷ &#039;&#039;&#039;2&#039;&#039;&#039; = # of food received&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Forest&#039;&#039;&#039; || Wood || 7 || Roll dice equal to # of workers placed. Dice total ÷ &#039;&#039;&#039;3&#039;&#039;&#039; = # of wood received&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Clay Pit&#039;&#039;&#039; || Brick || 7|| Roll dice equal to # of workers placed. Dice total ÷ &#039;&#039;&#039;4&#039;&#039;&#039; = # of bricks received&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Quarry&#039;&#039;&#039; || Stone || 7 || Roll dice equal to # of workers placed. Dice total ÷ &#039;&#039;&#039;5&#039;&#039;&#039; = # of stones received&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;River&#039;&#039;&#039; || Gold || 7 || Roll dice equal to # of workers placed. Dice total ÷ &#039;&#039;&#039;6&#039;&#039;&#039; = # of gold bars received&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Tool maker&#039;&#039;&#039; ||Tool || 1 || Gain a tool. Each player can only have 3 tools, but each can be upgraded (up to 3 times) by placing a worker here. &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Hut&#039;&#039;&#039; ||+1 Worker || 2 || Gain 1 worker. &#039;&#039;Exactly&#039;&#039; 2 people must be placed here. Max of 10 workers.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Field&#039;&#039;&#039; ||+1 food production || 1 || Increase your food production by 1. &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Buildings&#039;&#039;&#039; ||Buy buildings || 7 || Buy buildings with resources. Buildings are worth VP.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Civilization&#039;&#039;&#039; || Civilization card || 1 || Pay the # of resources based on its slot to gain its immediate effect and scoring benefits. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;Tools&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Tools are used to increase the number of resources gained. By using the tool, its value (1-4) is added to the dice total. Each tool can only be used once per turn. The whole value of the tool must be used (i.e. you cannot add less than 4 to a total when using a level 4 tool). Some Civilization cards grant &amp;quot;single-use&amp;quot; tools. These are lost after use and don&#039;t count for scoring.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;Buildings&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Pay the cost to gain the Building and receive the points listed in the top-left corner. If this number is a ?, points are equal to the total value of the resources used to acquire this building. &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:auto;&amp;quot; border=&amp;quot;2&amp;quot;&lt;br /&gt;
!| Resource || Value &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Wood&#039;&#039;&#039; || 3&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Brick&#039;&#039;&#039; || 4&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Stone&#039;&#039;&#039; || 5&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Gold&#039;&#039;&#039; || 6&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;u&amp;gt;Civilization Cards&amp;lt;/u&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Each card has an &#039;&#039;immediate effect&#039;&#039; (usually granting a resource) and a &#039;&#039;scoring multiplier&#039;&#039;. See &#039;&#039;&#039;End Game&#039;&#039;&#039; for how Civilization Cards are scored. &lt;br /&gt;
&lt;br /&gt;
==== Phase 3: Feed People====&lt;br /&gt;
&lt;br /&gt;
To feed your people, you must be able to discard enough food equal to # of workers minus food production number. If you have less food than this, you may substitute any resource. If you still don&#039;t have enough for your workers, you lose all food and are given a -10 point penalty.&lt;br /&gt;
&lt;br /&gt;
====Ending the Round====&lt;br /&gt;
&lt;br /&gt;
All Civilization Cards are moved to the right and new cards are put in the empty spaces. The next player becomes the starting player and a new round begins. &lt;br /&gt;
&lt;br /&gt;
==Game End==&lt;br /&gt;
&lt;br /&gt;
The game ends when either:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;margin:1em 0;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;One stack of buildings is empty when a round ends. (The number of building stacks is equal to the number of players).&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;There are insufficient Civilization Cards to fill each slot when a round begins.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Scoring====&lt;br /&gt;
&lt;br /&gt;
Civilization Cards with a &#039;&#039;&#039;green&#039;&#039;&#039; lower background are culture cards. They have 1 of 8 different symbols. At the end of the game, score is determined by grouping cards into sets with all different symbols, squaring the number of cards in each set, and adding them together. For example, a player has 1 card with a tablet, 1 card with pottery, 2 cards with a sundial, and 3 cards with a loom. This forms one set of four symbols (tablet, pottery, sundial, loom), one set of two symbols (sundial, loom) and one set of one symbol (the third loom). The player scores 16 (4&amp;amp;sup2;) for the first set, 4 (2&amp;amp;sup2;) for the second set and 1 for the third set, for a total of 21 points.&lt;br /&gt;
&lt;br /&gt;
Civilization Cards with a &#039;&#039;&#039;sand&#039;&#039;&#039; background are specialized workers: farmers, tool makers, hut builders, and shamans. These are scored as follows: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;margin:1em 0;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;# of cards with &#039;&#039;farmers&#039;&#039; x food production number&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;# of cards with &#039;&#039;tool makers&#039;&#039; x total value of tools&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;# of cards with &#039;&#039;hut builders&#039;&#039; x # of buildings&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;# of cards with &#039;&#039;shamans&#039;&#039; x workers&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The total from Civilization Cards is added to the VP printed on your buildings, plus 1 point for each remaining resource.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
====Harsh Winter====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;margin:1em 0;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Certain buildings allow you to spend an extra stone to score 5 points.&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;You can spend an extra gold when purchasing a Civilization Card to score 6 points.&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Wild Animals====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;margin:1em 0;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Four &amp;quot;wild animal&amp;quot; cards are shuffled into the Civilization Cards.&lt;br /&gt;
  &amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;When revealed, wild animals subtract 1, 2, or 3 from all dice rolls.&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Players must collectively place X people on the card to drive it off, where X = number of players.&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;After driving off a wild animal, each player rolls 1 die per person placed on it and receives the rewards.&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Igloos====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;margin:1em 0;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Spend 3 resources of the same type to buy an igloo, which awards points like a building but does not count for the end-game building bonus.&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====The New Huts====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;margin:1em 0;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Adds new buildings that grant fewer points when built but grant a bonus, such as gaining a resource each round or +1 worker/tool/food production). These do count for the end-game building bonus.&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Mammoth Herd====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;margin:1em 0;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;At the beginning of each round, a mammoth appears on the place shown by the top-most bonus tile.&lt;br /&gt;
  &amp;lt;li&amp;gt;Players who place people there can spend 1 food or resource per person to try to tame the mammoth.&lt;br /&gt;
  &amp;lt;li&amp;gt;Each player who places people to tame the mammoth rolls 1 die per person.&lt;br /&gt;
  &amp;lt;li&amp;gt;The player with the highest single die is the &amp;quot;mammoth tamer&amp;quot;. The mammoth tamer can choose to take the &amp;quot;1&amp;quot; or &amp;quot;all&amp;quot; bonus, as shown on the back of the bonus tile. &lt;br /&gt;
  &amp;lt;li&amp;gt;The other players who rolled are &amp;quot;challengers&amp;quot;. Challengers take the &amp;quot;all&amp;quot; bonus.&lt;br /&gt;
  &amp;lt;li&amp;gt;At the end of the game, the player with the most mammoth tiles scores 10 points.&amp;lt;li&amp;gt;2 or 3 players game: all players might place workers at the mammoth location (the 2p/3p game limitation is cancelled at the mammoth location).&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====The Expansion====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;margin:1em 0;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;&#039;&#039;&#039;New Good:&#039;&#039;&#039; Jewelry &lt;br /&gt;
  &amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;1 tooth = 1 jewelry, 1 ring = 3 jewelry&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Jewelry does not count as a resource or food&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;A player can trade resources &#039;&#039;&#039;or&#039;&#039;&#039; jewelry for buildings and Civilization Cards&lt;br /&gt;
    &amp;lt;li&amp;gt;Jewelry is acquired at the Hunting Grounds and has the same value as food. You &#039;&#039;can&#039;&#039; gain a combination of food and jewelry&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;&#039;&#039;&#039;New Place:&#039;&#039;&#039; Merchant&lt;br /&gt;
  &amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;Like the hut, this place requires exactly 2 people and is worth no points at the end of the game.&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;When this place is used, you gain 2 jewelry and your merchant level increases by 2. This represents the player&#039;s ability to trade.&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;The merchant exists in the village. In a 4-player game, only 3 of the 4 places can be visited. Rules for the 2-3 player game remain the same (only 2 village spaces can be visited per round).&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;&#039;&#039;&#039;New Mechanic:&#039;&#039;&#039; Trading&lt;br /&gt;
  &amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;A player can trade resources/jewelry once per round, regardless of whether they put any workers on the merchant&lt;br /&gt;
    &amp;lt;li&amp;gt;A player can only trade in order to buy a Civilization Card or a building (except for an igloo)&lt;br /&gt;
    &amp;lt;li&amp;gt;If also playing with the &#039;&#039;Harsh Winter&#039;&#039; variant, the extra stone/gold cannot be obtained with a trade&lt;br /&gt;
    &amp;lt;li&amp;gt;The ratio of goods traded depends on your merchant level. &lt;br /&gt;
    &amp;lt;li&amp;gt;A player cannot trade if their merchant level is 0. (Meaning the merchant must be visited at least once before any trading can occur.)&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;&#039;&#039;&#039;New Civilization Card slot&#039;&#039;&#039; &lt;br /&gt;
  &amp;lt;ul class=&amp;quot;bulletlist&amp;quot; style=&amp;quot;padding-inline-start:40px;&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;li&amp;gt;There is now a fifth slot for Civilization Cards. Cards here cost 3 jewelry. &lt;br /&gt;
    &amp;lt;li&amp;gt;A player can spend 3 more jewelry to buy the topmost face-down Civilization Card without applying its immediate effect.&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Code_Sharing&amp;diff=29514</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=29514"/>
		<updated>2026-04-21T17:05:28Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* Projects on studio */ Add d case (Stone Age case, een asked me to not make it public for this reason)&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  ; 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 ; https://codepen.io/VictoriaLa/pen/QWBBbwz&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| Die: 8 sided &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/YzMPeGq&lt;br /&gt;
| code pen&lt;br /&gt;
|-&lt;br /&gt;
| Die: 12 sided (dodecahedron) &lt;br /&gt;
| https://codepen.io/VictoriaLa/pen/xxLLxOP &amp;lt;nowiki/&amp;gt;  https://codepen.io/hoursgoby/pen/GRwQzxo&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, zoom and navigation 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;
|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 Knarr, 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;
|Jump to&lt;br /&gt;
|[https://github.com/thoun/bga-jump-to/ Repo]&amp;lt;nowiki&amp;gt; | &amp;lt;/nowiki&amp;gt;[https://thoun.github.io/bga-jump-to/demo/index.html Demo] (visible on Knarr, Elawa)&lt;br /&gt;
|Add floating controls to quickly jump to a player&#039;s table&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;
| Dijkstra&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, ginkgopilis, sagani, bigmonster,dominoes, Carcassonne hunters and gatherers and many others. &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;
! colspan=&amp;quot;3&amp;quot; | Assorted stuff&lt;br /&gt;
|-&lt;br /&gt;
|Help&lt;br /&gt;
|[https://github.com/thoun/bga-help/ Repo]&amp;lt;nowiki&amp;gt; | &amp;lt;/nowiki&amp;gt;[https://thoun.github.io/bga-help/demo/index.html Demo] (visible on Knarr)&lt;br /&gt;
|Add floating help buttons at the bottom left corner of the screen&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;
|BGA Type Safe Template&lt;br /&gt;
|https://github.com/NevinAF/bga-ts-template&lt;br /&gt;
|NevinAF&lt;br /&gt;
|Full typing of all BGA Framework components.&lt;br /&gt;
|-&lt;br /&gt;
|Undo functionality&lt;br /&gt;
|https://github.com/Ginso/UndoFunctions&lt;br /&gt;
|Ginso&lt;br /&gt;
|Code for adding undo functionality that also allows undoing single actions and not just the whole turn.&lt;br /&gt;
Also contains a class that wraps DB functions and adds a parsing functionality for numbers, bools and json&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;
| Bonsai&lt;br /&gt;
| https://github.com/PhilipDavis/BGA-Bonsai&lt;br /&gt;
| Philip Davis (pdw3)&lt;br /&gt;
| Action stack for client-side undo system; generator functions to model complex turn workflows; infinite hex grid with auto resizing; all data in a single JSON blob; animated scorepad&lt;br /&gt;
|-&lt;br /&gt;
| Canosa&lt;br /&gt;
| https://codeberg.org/halibut/Canosa&lt;br /&gt;
| junibegood&lt;br /&gt;
|-&lt;br /&gt;
|Cóatl&lt;br /&gt;
|https://github.com/AbelTiborToth/bga-coatl&lt;br /&gt;
|Doctor Neo Cortex&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;
|Deep Regrets&lt;br /&gt;
|https://github.com/JamesGames7/bga-deepRegrets&lt;br /&gt;
|JamesGames7&lt;br /&gt;
|-&lt;br /&gt;
|Dice Hospital : Emergency Roll&lt;br /&gt;
|https://github.com/firgon/dicehospitaler&lt;br /&gt;
|firgon&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;
| Fled&lt;br /&gt;
| https://github.com/PhilipDavis/BGA-Fled&lt;br /&gt;
| Philip Davis (pdw3)&lt;br /&gt;
| All data in a single JSON blob&lt;br /&gt;
|-&lt;br /&gt;
|Flip Freighters&lt;br /&gt;
|https://github.com/joesimpson/bga-flipfreighters&lt;br /&gt;
|joesimpson&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;
|-&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;
| 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;
|-&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;
|Linkage&lt;br /&gt;
|https://github.com/ShaPhi7/linkage&lt;br /&gt;
|ShaPhi7&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Love Letter&lt;br /&gt;
|https://github.com/ShaPhi7/loveletter&lt;br /&gt;
|ShaPhi7&lt;br /&gt;
|&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;
|-&lt;br /&gt;
| Monster Lands&lt;br /&gt;
| https://github.com/JamesGames7/bga-monsterlands&lt;br /&gt;
| James_Games&lt;br /&gt;
|&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;
|Ninjan&lt;br /&gt;
|https://github.com/dorukkicikoglu/bga-ninjan&lt;br /&gt;
|fenadoruk&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;
|Now Boarding&lt;br /&gt;
|https://github.com/quietmint/bga-nowboarding&lt;br /&gt;
|quietmint&lt;br /&gt;
|-&lt;br /&gt;
|Odin&lt;br /&gt;
|https://github.com/dorukkicikoglu/bga-odin&lt;br /&gt;
|fenadoruk&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;
|-&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 d) it is an old game which code should not be copied.&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>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Bugsclarification_stoneage&amp;diff=29277</id>
		<title>Bugsclarification stoneage</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Bugsclarification_stoneage&amp;diff=29277"/>
		<updated>2026-04-04T15:45:32Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Please do not report if your bug match one of the followings.&lt;br /&gt;
&lt;br /&gt;
A frequent &amp;quot;won’t fix&amp;quot;: sometimes you are not notified of a game update because of a lost message over the Internet. It can results in wrong situation display and in not being notified that it is your turn to play. These is linked to BGA framework and will not be fixed at the Stone Age code level. Please upvote this BGA website [https://boardgamearena.com/bug?id=201639 report].&lt;br /&gt;
&lt;br /&gt;
Here is a list of frequent &amp;quot;not a bug&amp;quot; reports: the user was just not knowing the actual rule.&lt;br /&gt;
* Can not put a worker at x place: check the placement limitation rules for two or three players game (and even four players if you are using the trade expansion).&lt;br /&gt;
* Did not get the two (might be one with the trade expansion) wild resources of the civilization card: you got it on your player board, you have to click on the wild resource icon to choose them.&lt;br /&gt;
* Did not get the card bonus in game: when buying a card face down, you receive only the end game bonus, not the in game bonus.&lt;br /&gt;
* Did not get the free wood/clay/stone of the bought hut (new huts expansion): the free resource is not granted at buy but at start of each following turns.&lt;br /&gt;
* Could not insulate bought hut (harsh winter variant): only huts of the standard game and costing three defined resources (not wild resources) can be insulated.&lt;br /&gt;
* Can not trade to buy an igloo: trade is allowed to buy a hut or a card, igloos are not huts nor cards.&lt;br /&gt;
* Can not trade to buy hut or card, different normal causes here:&lt;br /&gt;
** you can trade only one time per game turn (a game turn ends when all workers have been removed from playing area),&lt;br /&gt;
** the 2:1, 1:1 or 1:2 trade indicator (depending on your trade level) is not a trade rate, but a trade possibility: for instance for the 1:1, you can trade one resource and only one against another one, you can not trade two or more against the same number,&lt;br /&gt;
** you can not trade one resource against itself, even at trade level 9 or 10 (1:2 trade possibility: you can not trade one wood against one wood and one stone for instance).&lt;br /&gt;
* Did not get the second resource in my 1:2 trade: all resources gain in a trade are used in the linked buy, even if not needed for it, and it does not add points and can not be used to insulate or pay an extra gold in harsh winter variant.&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Migration_Guide&amp;diff=28682</id>
		<title>BGA Studio Migration Guide</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Migration_Guide&amp;diff=28682"/>
		<updated>2026-02-24T22:30:25Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* Deprecated translation functions */  clienttranslate is not working in view.php file, all formatting have to be done through notify or UserException formatting or be removed from PHP and rewrote in JavaScript.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is only for people who started long time ago and now need to re-write older projects into more modern versions.&lt;br /&gt;
Also if you trying to fix older game you may have to look here.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
See announcement here https://studio.boardgamearena.com/forum/viewtopic.php?f=12&amp;amp;t=45248&lt;br /&gt;
&lt;br /&gt;
📌 This symbol: direct information about migration&lt;br /&gt;
== Structural changes==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;gameoptions.inc.php&#039;&#039;&#039;&#039;&#039; =&amp;gt; gameoptions.json, gamepreferences.json&lt;br /&gt;
&lt;br /&gt;
Previously, options and preferences were specified in a single gameoptions.inc.php file.&lt;br /&gt;
&lt;br /&gt;
Now options and preferences are 2 json files, follow Migration steps on this page  https://en.doc.boardgamearena.com/Options_and_preferences:_gameoptions.json,_gamepreferences.json#Migration&lt;br /&gt;
&lt;br /&gt;
See [[#User preferences]] and [[#Game options]] for API changes.&lt;br /&gt;
&lt;br /&gt;
When building the game with this file you will see deprecation warning: The file gameoptions.inc.php is deprecated. click &amp;quot;Reload game options configuration&amp;quot; to generate the JSON content you can then put on a gameoptions.json and gamepreferences.json file. Then you can safely delete the gameoptions.inc.php file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;&amp;lt;gamename&amp;gt;.game.php&#039;&#039;&#039;&#039;&#039; =&amp;gt; modules/php/Game.php&lt;br /&gt;
&lt;br /&gt;
Move and refactor, see section [[BGA Studio Migration Guide#Namespaced game class|Namespaced game class]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;gamename&amp;gt;.action.php =&amp;gt; remove&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See section [[BGA Studio Migration Guide#Autowire game actions|Autowire game actions]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;&amp;lt;gamename&amp;gt;.view.php, &amp;lt;gamename&amp;gt;_&amp;lt;gamename&amp;gt;.tpl&#039;&#039;&#039;&#039;&#039; =&amp;gt; remove&lt;br /&gt;
&lt;br /&gt;
See section [[BGA Studio Migration Guide#Removal of view and template|Removal of view and template]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gameinfos.inc.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
File still there. Deprecated keys &#039;&#039;&#039;designer&#039;&#039;&#039;, &#039;&#039;&#039;artist&#039;&#039;&#039;, &#039;&#039;&#039;year&#039;&#039;&#039;, &#039;&#039;&#039;presentation&#039;&#039;&#039;, &#039;&#039;&#039;tags&#039;&#039;&#039;, &#039;&#039;&#039;complexity&#039;&#039;&#039;, &#039;&#039;&#039;strategy&#039;&#039;&#039;, &#039;&#039;&#039;luck&#039;&#039;&#039;, &#039;&#039;&#039;diplomacy&#039;&#039;&#039;, &#039;&#039;&#039;is_beta&#039;&#039;&#039; are no longer in use. Please remove these keys and use the Game Metadata Manager instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;material.inc.php&#039;&#039;&#039;&#039;&#039; =&amp;gt; optional&lt;br /&gt;
&lt;br /&gt;
See section [[#Material]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;states.inc.php&#039;&#039;&#039;&#039;&#039; =&amp;gt; modules/php/States&lt;br /&gt;
&lt;br /&gt;
See section [[#States]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;stats.inc.php&#039;&#039;&#039; =&amp;gt; stats.json&lt;br /&gt;
&lt;br /&gt;
Deprecation warning: The file stats.inc.php is deprecated. click &amp;quot;Reload statistics configuration&amp;quot; to generate the JSON content you can then put on a stats.json file. Then you can safely delete the stats.inc.php file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;gamename&amp;gt;.js&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Equivalent file is in modules/js/Game.js, it is ES6 js class (yay) and no dojo mess. &lt;br /&gt;
There are also massive API changes, see bottom sections&lt;br /&gt;
&lt;br /&gt;
==IDE Support==&lt;br /&gt;
A new _ide_helper.php file is now provided in every project dir, allowing IDE to provide syntax error highlighting for the framework functions. This file is regularly updated to match the latest framework updates.&lt;br /&gt;
&lt;br /&gt;
Same with bga-framework.d.ts for those using TypeScript.&lt;br /&gt;
&lt;br /&gt;
📌 Sync the files from the FTP dir to your local copy to benefit from it. Most of the IDE like Visual Studio Code should handle _ide_helper.php if you already followed https://en.doc.boardgamearena.com/Setting_up_BGA_Development_environment_using_VSCode&lt;br /&gt;
&lt;br /&gt;
==Game configuration ==&lt;br /&gt;
&lt;br /&gt;
===User preferences===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Access to user preferences and listener: https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#User_preferences&lt;br /&gt;
&lt;br /&gt;
📌 &lt;br /&gt;
*If you had a custom function called &amp;lt;code&amp;gt;setupPreferences()&amp;lt;/code&amp;gt; reading the &amp;lt;select&amp;gt; values, you can now use &amp;lt;code&amp;gt;onGameUserPreferenceChanged&amp;lt;/code&amp;gt; instead.&lt;br /&gt;
*If you had a copy of the user preferences on a DB table, it&#039;s not needed anymore. Remove all support of writing to this table. Replace access to this table with&lt;br /&gt;
        $pref = $this-&amp;gt;userPreferences-&amp;gt;get($playerId, $prefCode) ?? $defaultValue;&lt;br /&gt;
*If you used $this-&amp;gt;player_preferences - replace the use with use of proper API&lt;br /&gt;
&lt;br /&gt;
====Instant cssPref on user preferences====&lt;br /&gt;
A reload is not needed anymore to apply cssPref on a user preference change.&lt;br /&gt;
&lt;br /&gt;
📌 Remove forceReload: true if it was only set to update the cssPref. The player will appreciate to not reload the whole page!&lt;br /&gt;
&lt;br /&gt;
===Game options===&lt;br /&gt;
&lt;br /&gt;
New functions to access the table options (game options) without hassle&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Options_and_preferences:_gameoptions.json,_gamepreferences.json#Game_Options&lt;br /&gt;
&lt;br /&gt;
📌 &lt;br /&gt;
*Remove declaration of game options  from &amp;quot;&amp;lt;code&amp;gt;initGameStateLabels&amp;lt;/code&amp;gt;&amp;quot;&lt;br /&gt;
* Instead of using &amp;lt;code&amp;gt;$this-&amp;gt;getGameStateValue&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;$this-&amp;gt;gamestate-&amp;gt;table_globals&amp;lt;/code&amp;gt; use&lt;br /&gt;
 $this-&amp;gt;tableOptions-&amp;gt;get(int $optionId)&lt;br /&gt;
&lt;br /&gt;
This new object can also return the Real-time/Turn-based setting: https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Reflexion_time&lt;br /&gt;
&lt;br /&gt;
==Server parts (php, sql, etc)==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===PHP migration===&lt;br /&gt;
&lt;br /&gt;
Oct 2025: The migration was made from PHP7.4 to PHP8.4 new syntax and functions.&lt;br /&gt;
&lt;br /&gt;
New projects are generated using the strict mode&lt;br /&gt;
&lt;br /&gt;
📌 &lt;br /&gt;
&lt;br /&gt;
*Replace all &amp;lt;code&amp;gt;self::&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;$this-&amp;gt;&amp;lt;/code&amp;gt;   - The new project template has been updated to remove this bad practice (that may be unsupported in a future PHP version)&lt;br /&gt;
&lt;br /&gt;
*Add &amp;lt;code&amp;gt;declare(strict_types=1);&amp;lt;/code&amp;gt; to all .php files and fix compiler warnings (if you use IDE it will detect it before upload).&lt;br /&gt;
&lt;br /&gt;
===Namespaced game class===&lt;br /&gt;
Game class from &#039;&#039;&#039;&#039;&#039;&amp;lt;gamename&amp;gt;.game.php&#039;&#039;&#039;&#039;&#039; are now namespaced (and moved to modules/php/Game.php) and can autoload other classes of the same namespace&lt;br /&gt;
&lt;br /&gt;
[[Main game logic: Game.php#Creating other classes]]&lt;br /&gt;
&lt;br /&gt;
📌 The class file should be moved to modules/php/Game.php and adopted&lt;br /&gt;
&lt;br /&gt;
(In examples below YourGameName is NOT verbatim its your game name)&lt;br /&gt;
&lt;br /&gt;
* Move YourGameName.game.php to modules/php (create this dir if does not exists)&lt;br /&gt;
* Rename to Game.php&lt;br /&gt;
* Find the place below the copyright and add&lt;br /&gt;
&lt;br /&gt;
      declare(strict_types=1);&lt;br /&gt;
      namespace Bga\Games\YourGameName;&lt;br /&gt;
&lt;br /&gt;
* Remove &lt;br /&gt;
  require_once APP_GAMEMODULE_PATH . &amp;quot;module/table/table.game.php&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
* Find you class declaration change YouGameName to Game (verbatim) and change extends&lt;br /&gt;
&lt;br /&gt;
   class Game extends \Bga\GameFramework\Table&lt;br /&gt;
&lt;br /&gt;
* All references to non-namespaced classes in this file should be defined on top of the file with &amp;quot;use&amp;quot;, for example &amp;quot;use \BgaUserException;&amp;quot; as it is this non-namespaced exception is used in the zombieTurn function.&lt;br /&gt;
&lt;br /&gt;
* All includes with relative path will need to be updated too.&lt;br /&gt;
&lt;br /&gt;
* The material.inc.php to have be moved and included directly (see below)&lt;br /&gt;
&lt;br /&gt;
Multiple functions of &amp;quot;Table&amp;quot; base class are now deprecated, see how to migrate in corresponding section&lt;br /&gt;
&lt;br /&gt;
* notifyAllPlayers&lt;br /&gt;
* notifyPlayer&lt;br /&gt;
* mysql_fetch_assoc&lt;br /&gt;
** Deprecation warning:  mysql_fetch_assoc function detected. It is deprecated, and may be removed someday. Please replace it by standard framework DB functions!&lt;br /&gt;
* Table (class access without namespace)&lt;br /&gt;
* isMutiactiveState (misspelled version)&lt;br /&gt;
* State management functions (getState, state, getPrivateState)&lt;br /&gt;
* Player information functions (getActivePlayerName, getCurrentPlayerName, getCurrentPlayerColor)&lt;br /&gt;
* Game mode functions (isAsync, isRealtime)&lt;br /&gt;
* Exception classes (feException, BgaUserException, etc.)&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
===Material===&lt;br /&gt;
Material file &#039;&#039;&#039;material.inc.php&#039;&#039;&#039; is now optional. You can define all your material directly in php class. If you still like to keep it, and using namespaced Game.php you have to move it to subfolder and include directly [[Game material description: material.inc.php#Move it to modules/php]]&lt;br /&gt;
&lt;br /&gt;
=== Autowire game actions===&lt;br /&gt;
Simplify the action calls by removing  &#039;&#039;&#039;&amp;lt;gamename&amp;gt;.action.php&#039;&#039;&#039;  file&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Actions_%28autowired%29&lt;br /&gt;
&lt;br /&gt;
📌 Autowired actions needs to start with &amp;quot;act&amp;quot;, so it&#039;s risky to change them (if you change all actions names in the states.php, game, action and JS file, Real-time players will call the old name until they refresh. So, it needs to be done in two steps with duplicates on back side, or to be deployed when there is no Realt-time table running.&lt;br /&gt;
&lt;br /&gt;
When migration is done, the action.php file can be deleted.&lt;br /&gt;
&lt;br /&gt;
Deprecation warning: Actions detected on .action.php file. You can now use [[Main game logic: Game.php#Actions (autowired)|Auto-wired actions]] to avoid pass-through functions in .action.php file. If you transform your project to use only auto-wired actions, you can then delete the .action.php file.&lt;br /&gt;
&lt;br /&gt;
=== Notifications===&lt;br /&gt;
Functions notifyAllPlayers and notifyPlayer from main game.php are deprecated&lt;br /&gt;
&lt;br /&gt;
📌 Replace &amp;lt;code&amp;gt;$this-&amp;gt;notifyAllPlayers&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;bga-&amp;gt;notify-&amp;gt;all&amp;lt;/code&amp;gt; &lt;br /&gt;
and Replace &amp;lt;code&amp;gt;$this-&amp;gt;notifyPlayer&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;bga-&amp;gt;notify-&amp;gt;player&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Notification Decorators====&lt;br /&gt;
New notify function that handles decorators, reducing the duplicate code on notification args.&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Notification_decorators&lt;br /&gt;
&lt;br /&gt;
====Notification args consistency====&lt;br /&gt;
Previously, when you sent an arg that was transformed by format_string_recursive or bgaFormatText, the args object was mutated and you got the transformed value in the notif_ handler.&lt;br /&gt;
&lt;br /&gt;
The solution was to send the values in 2 different names like this:&lt;br /&gt;
&lt;br /&gt;
 [&lt;br /&gt;
  &#039;roundNumber&#039; =&amp;gt; $roundNumber, // number, to update the round counter&lt;br /&gt;
  &#039;round_number&#039; =&amp;gt; $roundNumber, // number that will be transformed to string by bgaFormatText, when shown in bold in the logs&lt;br /&gt;
 ]&lt;br /&gt;
📌 Do not duplicate the value, as the notif_ handler will now get unmutated args&lt;br /&gt;
&lt;br /&gt;
===Deprecated getGameName===&lt;br /&gt;
The getGameName() function is now useless in the Game PHP file and can be deleted&lt;br /&gt;
&lt;br /&gt;
📌 Delete the getGameName function in the Game PHP file.&lt;br /&gt;
&lt;br /&gt;
Deprecation warning: getGameName function detected. It is deprecated. You can delete it, it is not used anymore&lt;br /&gt;
&lt;br /&gt;
===State Management Functions===&lt;br /&gt;
Several state-related functions have been deprecated in favor of more explicit methods:&lt;br /&gt;
&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;gamestate-&amp;gt;state()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;getCurrentMainState()&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;$this-&amp;gt;getCurrentState(int $playerId)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;getState()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;getCurrentMainStateId()&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;$this-&amp;gt;getCurrentStateId(int $playerId)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;getPrivateState($playerId)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;getCurrentState($playerId)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;gamestate-&amp;gt;states&amp;lt;/code&amp;gt; access with &amp;lt;code&amp;gt;$this-&amp;gt;getCurrentMainState()&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;$this-&amp;gt;getCurrentState(int $playerId)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;isMutiactiveState()&amp;lt;/code&amp;gt; (misspelled) with &amp;lt;code&amp;gt;$this-&amp;gt;isMultiactiveState()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Player Information Functions===&lt;br /&gt;
Several functions for getting player information are deprecated in favor of more flexible methods:&lt;br /&gt;
&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;getActivePlayerName()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;getPlayerNameById($activePlayerId)&amp;lt;/code&amp;gt; using $activePlayerId magic parameter&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;getCurrentPlayerName()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;getPlayerNameById($currentPlayerId)&amp;lt;/code&amp;gt; using $currentPlayerId magic parameter&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;getCurrentPlayerColor()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;getPlayerColorById($currentPlayerId)&amp;lt;/code&amp;gt; using $currentPlayerId magic parameter&lt;br /&gt;
&lt;br /&gt;
===Game Mode Functions===&lt;br /&gt;
Functions to check game mode (turn-based vs real-time) have been moved to tableOptions:&lt;br /&gt;
&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;isAsync()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;tableOptions-&amp;gt;isTurnBased()&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;$this-&amp;gt;isRealtime()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;$this-&amp;gt;tableOptions-&amp;gt;isRealTime()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Exception Classes===&lt;br /&gt;
Old exception classes are deprecated in favor of namespaced versions:&lt;br /&gt;
&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;feException&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;\Bga\GameFramework\UserException&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;\Bga\GameFramework\SystemException&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;\Bga\GameFramework\VisibleSystemException&amp;lt;/code&amp;gt; depending on your need&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;BgaUserException&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;\Bga\GameFramework\UserException&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;BgaSystemException&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;\Bga\GameFramework\SystemException&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;BgaVisibleSystemException&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;\Bga\GameFramework\VisibleSystemException&amp;lt;/code&amp;gt;&lt;br /&gt;
* Remove usage of &amp;lt;code&amp;gt;FEX_NOCODE&amp;lt;/code&amp;gt; constant - new exception classes don&#039;t need error codes&lt;br /&gt;
&lt;br /&gt;
===Namespace for Base Classes===&lt;br /&gt;
Old class references without namespaces are deprecated:&lt;br /&gt;
&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;extends Table&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;extends \Bga\GameFramework\Table&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;Deck&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;\Bga\GameFramework\Components\Deck&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Deprecated APP_* Classes ===&lt;br /&gt;
Deprecation warning:&lt;br /&gt;
&lt;br /&gt;
Reference to old APP_* class detected.&lt;br /&gt;
&lt;br /&gt;
We recommend you to use composition instead of extend:&lt;br /&gt;
&lt;br /&gt;
Pass `private Game $game` in the constructor of your object that need to access Table functions&lt;br /&gt;
&lt;br /&gt;
If it&#039;s too complicated, at least replace APP_Object/APP_GameClass by APP_DbObject as APP_Object/APP_GameClass may be removed soon and don&#039;t contain anything more than APP_DbObject.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t hesitate to ask for help in the Dev Discord or in the Dev forum if you don&#039;t know how to do it!&lt;br /&gt;
 class Tokens extends APP_GameClass {  &lt;br /&gt;
becomes:&lt;br /&gt;
 class Tokens extends \APP_DbObject { &lt;br /&gt;
&lt;br /&gt;
=== Deprecated translation functions ===&lt;br /&gt;
&lt;br /&gt;
On php side translation story is simplified&lt;br /&gt;
&lt;br /&gt;
* totranslate function is not longer needed and can be replaced with clienttranslate&lt;br /&gt;
* $this-&amp;gt;_() (or self::_()) can also be replaced with clienttranslate when use for non parameterized strings (but not in deprecated &amp;lt;game&amp;gt;.view.php file):&lt;br /&gt;
&lt;br /&gt;
  throw new UserException(clienttranslate(&#039;You must choose 3 cards&#039;));&lt;br /&gt;
&lt;br /&gt;
UserException is also handling parameterized strings like the notify functions.&lt;br /&gt;
&lt;br /&gt;
All parameterized strings on PHP side have to use either the notify or the UserException formatting. If some parameterized strings are none of these, you have to remove them from PHP and rewrote them in JavaScript using dojo.string.substitute.&lt;br /&gt;
&lt;br /&gt;
See [[Translations]]&lt;br /&gt;
&lt;br /&gt;
=== Deprecated getNew ===&lt;br /&gt;
Function getNew that was only used to create new deck object is now deprecated, use $this-&amp;gt;deckFactory-&amp;gt;createDeck(&#039;&#039;) instead&lt;br /&gt;
&lt;br /&gt;
=== Stats ===&lt;br /&gt;
&lt;br /&gt;
The stats function such as initStat, setStat and getStat are also deprecated in favor of access via the objects &amp;lt;code&amp;gt;$this-&amp;gt;tableStats and $this-&amp;gt;playerStats&amp;lt;/code&amp;gt;&lt;br /&gt;
See https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php#Game_statistics&lt;br /&gt;
&lt;br /&gt;
===Legacy===&lt;br /&gt;
New object to access the legacy functions, removing the need to manually decode the JSON result when getting the values.&lt;br /&gt;
&lt;br /&gt;
[[Main game logic: Game.php#Legacy games API|https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Legacy_games_API]]&lt;br /&gt;
&lt;br /&gt;
📌 Use $this-&amp;gt;legacy-&amp;gt;actionname instead of $this-&amp;gt;actionnameLegacy and remove JSON decoding on getters&lt;br /&gt;
&lt;br /&gt;
===Any Globals===&lt;br /&gt;
New database table and API to handle any type variables instead of numerical values only&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Use_globals&lt;br /&gt;
&lt;br /&gt;
📌 If you had custom tables just for that you can drop them and use standard table&lt;br /&gt;
&lt;br /&gt;
=== Server Counters ===&lt;br /&gt;
2 new counter classes have been added to easily handle the various counters your game might have. You also have 2 prebuilt counters: playerScore and playerScoreAux, to handle the scoring values, so you don&#039;t need to update manually the DB when setting the scores.&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/PlayerCounter_and_TableCounter&lt;br /&gt;
&lt;br /&gt;
📌 Replace setting player_score/player_score_aux using db queries with use of $this-&amp;gt;playerScore and $this-&amp;gt;playerScoreAux. Remove the notifications, or part of notifications, updating the player panel score counter (if you had some custom notification you may still need them).&lt;br /&gt;
===Updated Zombie Mode documentation and recommendations===&lt;br /&gt;
We now recommend making the zombie player playing randomly, instead of passing as a default. A new &amp;quot;Zombie Mode level&amp;quot; field has been added to the Game Metadata Manager, to indicated the Zombie Mode you implemented in your game.&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Zombie_Mode&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===View and template files: deprecated===&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;&amp;lt;gamename&amp;gt;.view.php, &amp;lt;gamename&amp;gt;_&amp;lt;gamename&amp;gt;.tpl&#039;&#039;&#039;&#039;&#039; are now optional and are not generated anymore on a new project. The new project templates demonstrate how to work without them.&lt;br /&gt;
&lt;br /&gt;
📌 The DOM should be built on the JS side to remove the view/template files, so it can be complicated for old projects using them intensively. It would look like this:&lt;br /&gt;
 this.getGameAreaElement().insertAdjacentHTML(&#039;beforeend&#039;, `&lt;br /&gt;
   &amp;lt;nowiki&amp;gt;&amp;lt;span&amp;gt;${_(&#039;My translated text&#039;)}&amp;lt;/span&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;div id=&amp;quot;player-tables&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 `);&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
See more in [[#Access template elements]]&lt;br /&gt;
&lt;br /&gt;
====Forbid access to global BGA variables and direct DB access on action/view files====&lt;br /&gt;
If you did not remove action and view files, you cannot longer use some stuff in them, such $g_user global and db access functions.&lt;br /&gt;
&lt;br /&gt;
A new getCurrentPlayerId() function has been added to those action/view classes for easier migration&lt;br /&gt;
&lt;br /&gt;
📌 Replace $g_user-&amp;gt;get_id() by $this-&amp;gt; getCurrentPlayerId()&lt;br /&gt;
&lt;br /&gt;
Replace DB calls by $this-&amp;gt;game-&amp;gt;DbQuery() (and such...)&lt;br /&gt;
&lt;br /&gt;
===States===&lt;br /&gt;
There is now a way to describe each game state in a State class, that will handle all logic and description of the state. It helps splitting the code into multiple files, instead of one big Game.php file.&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/State_classes:_State_directory&lt;br /&gt;
&lt;br /&gt;
📌 Create a State class for each state of the game (except 1 and 99 if they are still described in states.inc.php), move the state definition in it, and adapt the &amp;quot;st&amp;quot;, &amp;quot;arg&amp;quot;, &amp;quot;actXXX&amp;quot; and &amp;quot;zombie&amp;quot; functions in the class. When all classes are migrated, you can remove the states.inc.php file in the FTP folder.&lt;br /&gt;
&lt;br /&gt;
==== If still using states.php====&lt;br /&gt;
The new class GameStateBuilder helps you build the state machine, allowing auto-completion, and avoid typo errors on state types. Complete example: 📌 https://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php&lt;br /&gt;
&lt;br /&gt;
States 1 and 99, that must not be changed, are now optional.&lt;br /&gt;
&lt;br /&gt;
📌 Replace the array definition by GameStateBuilder use. You can remove the declaration of states 1 and 99.&lt;br /&gt;
&lt;br /&gt;
Note: it&#039;s only useful if you don&#039;t migrate to State classes described above&lt;br /&gt;
&lt;br /&gt;
==Client parts (js, html, css) ==&lt;br /&gt;
===Main class===&lt;br /&gt;
File is moved from yourgamename.js to modules/js/Game.js and has a different structure&lt;br /&gt;
https://en.doc.boardgamearena.com/Game_interface_logic:_Game.js&lt;br /&gt;
It won&#039;t be easy to convert this, maybe best just to use old one which still works, but move when you write a new game.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Deprecated ajaxcall ===&lt;br /&gt;
Introduced function bgaPerformAction to replace ajaxcall and checkAction combination, with a simpler syntax:&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Game_interface_logic:_Game.js#Actions&lt;br /&gt;
&lt;br /&gt;
Deprecation warning: The &amp;lt;code&amp;gt;ajaxcall&amp;lt;/code&amp;gt;  function is deprecated, check [[/en.doc.boardgamearena.com/Game interface logic: yourgamename.js#Actions|the]] &amp;lt;code&amp;gt;bgaPerformAction&amp;lt;/code&amp;gt; [[/en.doc.boardgamearena.com/Game interface logic: yourgamename.js#Actions|function]].&lt;br /&gt;
&lt;br /&gt;
📌 Replace combination of checkAction/ajaxcall by bgaPerformAction. Beware of the options (3rd param) if it was an ajaxcall without checkAction.&lt;br /&gt;
&lt;br /&gt;
===New this.bga.* API Structure===&lt;br /&gt;
Many client-side functions have been reorganized into namespaced objects under &amp;lt;code&amp;gt;this.bga&amp;lt;/code&amp;gt; for better organization and discoverability:&lt;br /&gt;
&lt;br /&gt;
====Player Functions (this.bga.players)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.isSpectator&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.players.isCurrentPlayerSpectator()&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.isCurrentPlayerActive()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.players.isCurrentPlayerActive()&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.isPlayerActive(player_id)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.players.isPlayerActive(player_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.getActivePlayers()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.players.getActivePlayerIds()&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.getActivePlayerId()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.players.getActivePlayerId()&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.getFormattedPlayerName(...)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.players.getFormattedPlayerName(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.addAutomataPlayerPanel(...)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.players.addAutomataPlayerPanel(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====State Functions (this.bga.states)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.on_client_state&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.states.isOnClientState()&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.setClientState(stateName, args)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.states.setClientState(stateName, args)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.restoreServerGameState()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.states.restoreServerGameState()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Status Bar Functions (this.bga.statusBar)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.updatePageTitle()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.statusBar.setTitle(title, args)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.removeActionButtons()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.statusBar.removeActionButtons()&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Action Functions (this.bga.actions)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.checkAction(action, nomessage)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.actions.checkAction(action, nomessage)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.checkPossibleActions(action)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.actions.checkPossibleActions(action)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.bgaPerformAction(...)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.actions.performAction(...)&amp;lt;/code&amp;gt; - Note: catch result is now &amp;lt;code&amp;gt;{ message, args }&amp;lt;/code&amp;gt; instead of just &amp;lt;code&amp;gt;message&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Dialog Functions (this.bga.dialogs)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.showMoveUnauthorized()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.dialogs.showMoveUnauthorized()&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.showMessage(msg, type)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.dialogs.showMessage(msg, type)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.confirmationDialog(text, callback, callback_cancel)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.dialogs.confirmation(text)&amp;lt;/code&amp;gt; - Note: now returns a Promise instead of using callbacks&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.multipleChoiceDialog(text, choices, callback)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.dialogs.multipleChoice(text, choices)&amp;lt;/code&amp;gt; - Note: now returns a Promise instead of using callbacks&lt;br /&gt;
&lt;br /&gt;
====Image Functions (this.bga.images)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.dontPreloadImage(image)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.images.dontPreloadImage(image)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;this.bga.images.dontPreloadImages([...])&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.ensureSpecificGameImageLoading(imagelist)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.images.preloadImage(image)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;this.bga.images.preloadImages([...])&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Game Area Functions (this.bga.gameArea)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.getGameAreaElement()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.gameArea.getElement()&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.addLastTurnBanner(message, args)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.gameArea.addLastTurnBanner(message, args)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.removeLastTurnBanner()&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.gameArea.removeLastTurnBanner()&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.addWinConditionBanner(message, args)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.gameArea.addWinConditionBanner(message, args)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Player Panel Functions (this.bga.playerPanels)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.getPlayerPanelElement(playerId)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.playerPanels.getElement(playerId)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.scoreCtrl[player_id]&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.playerPanels.getScoreCounter(player_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====User Preferences (this.bga.userPreferences)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.getGameUserPreference(pref_id)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.userPreferences.get(pref_id)&amp;lt;/code&amp;gt;&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.setGameUserPreference(pref_id, value)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.userPreferences.set(pref_id, value)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Notification Functions (this.bga.notifications)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.bgaSetupPromiseNotifications(...)&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.notifications.setupPromiseNotifications(...)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Animation Functions (this.bga.gameui)====&lt;br /&gt;
📌&lt;br /&gt;
* Replace &amp;lt;code&amp;gt;this.instantaneousMode&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;this.bga.gameui.bgaAnimationsActive()&amp;lt;/code&amp;gt; - Note: logic is reversed (instantaneousMode was true when animations should be skipped, bgaAnimationsActive() returns true when animations should play)&lt;br /&gt;
&lt;br /&gt;
===Access to DOM elements ===&lt;br /&gt;
New functions getPlayerPanelElement(player_id) and this.getGameAreaElement()&lt;br /&gt;
&lt;br /&gt;
Note: These functions are now deprecated in favor of &amp;lt;code&amp;gt;this.bga.playerPanels.getElement(playerId)&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;this.bga.gameArea.getElement()&amp;lt;/code&amp;gt;. See [[#New this.bga.* API Structure]] above.&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Game_interface_logic:_Game.js#Adding_stuff_to_player%27s_panel&lt;br /&gt;
&lt;br /&gt;
📌 Code like dojo.place(html, player_board_${player.id}); would be replaced by this.bga.gameArea.getElement().insertAdjacentHTML(&#039;beforeend&#039;, html);&lt;br /&gt;
===Notification setup===&lt;br /&gt;
Notifications can now be automatically scanned and called without needing to register them one by one. They&#039;ll handle Promises, so they end synchronously when the Promise resolves.&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;bgaSetupPromiseNotifications&amp;lt;/code&amp;gt; is now deprecated in favor of &amp;lt;code&amp;gt;this.bga.notifications.setupPromiseNotifications&amp;lt;/code&amp;gt;. See [[#New this.bga.* API Structure]] above.&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Game_interface_logic:_Game.js#Notifications&lt;br /&gt;
&lt;br /&gt;
A wait function has been added to return a Promise when a delay is passed (compatible with fast-replay mode)&lt;br /&gt;
&lt;br /&gt;
A new utility function has been added to support Promises for old Dojo animations&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Game_interface_logic:_Game.js#Animation_Callbacks&lt;br /&gt;
&lt;br /&gt;
📌 Dojo.subscribe calls in setupNotifications must be removed if using promise-based notification setup. Notif_ function should be async and return a Promise, make sure they wait for the expected amount of time if the sync setup was using a numerical duration&lt;br /&gt;
&lt;br /&gt;
If you used Dojo animation, make them Promise compatible with &amp;quot;await this.bgaPlayDojoAnimation(dojoAnim);&amp;quot;&lt;br /&gt;
&lt;br /&gt;
===Status bar manipulation===&lt;br /&gt;
Function to change the title from the JS&lt;br /&gt;
&lt;br /&gt;
Note: &amp;lt;code&amp;gt;this.statusBar.*&amp;lt;/code&amp;gt; methods are now available via &amp;lt;code&amp;gt;this.bga.statusBar.*&amp;lt;/code&amp;gt; for consistency. See [[#New this.bga.* API Structure]] above.&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Title_bar&lt;br /&gt;
&lt;br /&gt;
📌 Replace direct title div manipulation with this.bga.statusBar.setTitle(title: string, args?: object), and benefit from replacement of ${actplayer}/${you}/... (see example in the link above).&lt;br /&gt;
&lt;br /&gt;
This also includes a new function to create action buttons, that are more screen-reader compatible than the previous version. The new button parameters also allow you to set a confirm popin or an autoclick for confirmation buttons&lt;br /&gt;
&lt;br /&gt;
📌 Replace this.addActionButton by this.bga.statusBar.addActionButton. Notice the parameters have changed, so they need to be adapted too! Remove manual setActionTimer or manual confirm with the new parameters.&lt;br /&gt;
&lt;br /&gt;
===Dojo usage===&lt;br /&gt;
Dojo usage has been reduced to minimum in the new project template and the doc, as native JS is now able to do almost the same things, with better performance and more knowledge for newcomers of the native (vanilla) JS.&lt;br /&gt;
&lt;br /&gt;
📌 Replace dojo by vanilla JS where possible&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Dojo API &lt;br /&gt;
! Category&lt;br /&gt;
! Description&lt;br /&gt;
! Vanilla JS Replacement&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.byId(&amp;quot;id&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| DOM Selection&lt;br /&gt;
| Selects a single DOM element by its ID.&lt;br /&gt;
| &amp;lt;code&amp;gt;document.getElementById(&amp;quot;id&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.query(&amp;quot;selector&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| DOM Selection&lt;br /&gt;
| Selects a collection of DOM elements using CSS selectors.&lt;br /&gt;
| &amp;lt;code&amp;gt;document.querySelectorAll(&amp;quot;selector&amp;quot;)&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;document.querySelector(&amp;quot;selector&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.connect(node, &amp;quot;onclick&amp;quot;, fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Event Handling&lt;br /&gt;
| Connects an event handler to a DOM element.&lt;br /&gt;
| &amp;lt;code&amp;gt;node.addEventListener(&amp;quot;click&amp;quot;, fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.disconnect(handle)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Event Handling&lt;br /&gt;
| Removes an event handler created with &amp;lt;code&amp;gt;dojo.connect&amp;lt;/code&amp;gt;.&lt;br /&gt;
| &amp;lt;code&amp;gt;handle.remove()&amp;lt;/code&amp;gt; for event listeners, or &amp;lt;code&amp;gt;node.removeEventListener(&amp;quot;click&amp;quot;, fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.stopEvent(evt)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Event Handling&lt;br /&gt;
| Prevents propagation and default action for an event.&lt;br /&gt;
| &amp;lt;code&amp;gt;evt.preventDefault(); evt.stopPropagation();&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.place(node, parent, &amp;quot;last&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| DOM Manipulation&lt;br /&gt;
| Places a DOM node inside a parent node at a specific position.&lt;br /&gt;
| &amp;lt;code&amp;gt;parent.appendChild(node)&amp;lt;/code&amp;gt;, when using raw html &amp;lt;code&amp;gt;parent.insertAdjacentHTML(&#039;beforeend&#039;, html)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.create(&amp;quot;tag&amp;quot;, props, parent)&amp;lt;/code&amp;gt;&lt;br /&gt;
| DOM Manipulation&lt;br /&gt;
| Creates a new DOM element with optional properties.&lt;br /&gt;
| &amp;lt;code&amp;gt;document.createElement(&amp;quot;tag&amp;quot;)&amp;lt;/code&amp;gt;, then set properties and use &amp;lt;code&amp;gt;parent.appendChild()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.style(node, &amp;quot;color&amp;quot;, &amp;quot;red&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Styling&lt;br /&gt;
| Sets an inline CSS property on a DOM node. &amp;lt;b&amp;gt;CAUTION:&amp;lt;/b&amp;gt; &amp;lt;code&amp;gt;dojo.style(node, &amp;quot;left&amp;quot;)&amp;lt;/code&amp;gt; (and &amp;quot;right&amp;quot;, &amp;quot;width&amp;quot;, etc) return lengths in pixels as numbers, not the set CSS style.&lt;br /&gt;
| &amp;lt;code&amp;gt;node.style.color = &amp;quot;red&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.hasClass(node, &amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Styling&lt;br /&gt;
| Checks if a DOM node has a specific CSS class.&lt;br /&gt;
| &amp;lt;code&amp;gt;node.classList.contains(&amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.addClass(node, &amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Styling&lt;br /&gt;
| Adds a CSS class to a DOM node.&lt;br /&gt;
| &amp;lt;code&amp;gt;node.classList.add(&amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.removeClass(node, &amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Styling&lt;br /&gt;
| Removes a CSS class from a DOM node.&lt;br /&gt;
| &amp;lt;code&amp;gt;node.classList.remove(&amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.forEach(array, fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Array Utilities&lt;br /&gt;
| Iterates over an array.&lt;br /&gt;
| &amp;lt;code&amp;gt;array.forEach(fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.map(array, fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Array Utilities&lt;br /&gt;
| Transforms an array by applying a function to each element.&lt;br /&gt;
| &amp;lt;code&amp;gt;array.map(fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.fadeOut, dojo.fadeIn&amp;lt;/code&amp;gt;&lt;br /&gt;
| Animations&lt;br /&gt;
| Various animations&lt;br /&gt;
| Use https://en.doc.boardgamearena.com/BgaAnimations or CSS animations&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;dojo.hitch(this, &amp;quot;functionName&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| Variable scoping&lt;br /&gt;
| Binds &amp;lt;code&amp;gt;this&amp;lt;/code&amp;gt; (or other variable) in a callback&lt;br /&gt;
| &amp;lt;code&amp;gt;functionName.bind(this)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;dojo.destroy(node)&amp;lt;/code&amp;gt;&lt;br /&gt;
|DOM Manipulation&lt;br /&gt;
|Destroys a DOM element&lt;br /&gt;
|&amp;lt;code&amp;gt;node.remove()&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;dojo.indexof(array,value)&amp;lt;/code&amp;gt;&lt;br /&gt;
|Array Utilities&lt;br /&gt;
|index of the item in the array,&lt;br /&gt;
|&amp;lt;code&amp;gt;array.indexof(value) or array.indexof(test)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;dojo.string.substitute&amp;lt;/code&amp;gt;&lt;br /&gt;
|String Utilities&lt;br /&gt;
|template substitution&lt;br /&gt;
|&amp;lt;code&amp;gt;Use JS template strings, i.e. `&amp;lt;div id=${id}&amp;gt;&amp;lt;/div&amp;gt;`. Note: not suitable for translations if variables are used inside&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Sound loading===&lt;br /&gt;
New functions load/play have been added for the sounds:&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Sounds&lt;br /&gt;
&lt;br /&gt;
📌 Replace template loading of sounds and global function playSound&lt;br /&gt;
&lt;br /&gt;
===Formatting of log message using bgaFormatText===&lt;br /&gt;
This function, if defined, will allow you to insert HTML in the logs without overriding format_string_recursive. Example: 📌https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Define_this.bgaFormatText%28%29_method&lt;br /&gt;
&lt;br /&gt;
📌 Replace the override of format_string_recursive by bgaFormatText (the last line will change)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Automata player panel===&lt;br /&gt;
A new framework function to add a player panel for your game automas https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Adding_a_player_panel_for_an_automata&lt;br /&gt;
&lt;br /&gt;
📌 Replace manually created automata player panel with this new function&lt;br /&gt;
&lt;br /&gt;
===New JS libraries===&lt;br /&gt;
New JS libraries are created to help you design your games, especially for components that you will find on numerous games. See [[Studio#BGA Studio game components reference]]&lt;br /&gt;
&lt;br /&gt;
📌 Replace manually created animation, stocks, etc with components (check the link above, don&#039;t want to duplicate it here)&lt;br /&gt;
&lt;br /&gt;
===CSS imports===&lt;br /&gt;
Default BGA imports are auto-included, if you find this code and comment in .css you can delete it&lt;br /&gt;
  @import url(../../../css/csslayer.css);&lt;br /&gt;
  /* Note: you must not use any @import directive other than this one */&lt;br /&gt;
&lt;br /&gt;
===Future support of dark mode===&lt;br /&gt;
BGA doesn&#039;t support dark mode yet. To have some games compatible when we do, we added a theme data tag you can use as described here:&lt;br /&gt;
&lt;br /&gt;
https://en.doc.boardgamearena.com/Game_interface_stylesheet:_yourgamename.css#Support_of_the_Dark_mode&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Bugsclarification_stoneage&amp;diff=28306</id>
		<title>Bugsclarification stoneage</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Bugsclarification_stoneage&amp;diff=28306"/>
		<updated>2026-01-29T21:30:13Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Add a link on a report on the website.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Please do not report if your bug match one of the followings.&lt;br /&gt;
&lt;br /&gt;
A frequent &amp;quot;won’t fix&amp;quot;: sometimes you are not notified of a game update because of a lost message over the Internet. It can results in wrong situation display and in not being notified that it is your turn to play. These is linked to BGA framework and will not be fixed at the Stone Age code level. Please upvote this BGA website [https://boardgamearena.com/bug?id=201639 report].&lt;br /&gt;
&lt;br /&gt;
Here is a list of frequent &amp;quot;not a bug&amp;quot; reports: the user was just not knowing the actual rule.&lt;br /&gt;
* Can not put a worker at x place: check the placement limitation rules for two or three players game (and even four players if you are using the trade expansion).&lt;br /&gt;
* Did not get the two (might be one with the trade expansion) wild resources of the civilization card: you got it on your player board, you have to click on the wild resource icon to choose them.&lt;br /&gt;
* Did not get the free wood/clay/stone of the bought hut (new huts expansion): the free resource is not granted at buy but at start of each following turns.&lt;br /&gt;
* Could not insulate bought hut (harsh winter variant): only huts of the standard game and costing three defined resources (not wild resources) can be insulated.&lt;br /&gt;
* Can not trade to buy an igloo: trade is allowed to buy a hut or a card, igloos are not huts nor cards.&lt;br /&gt;
* Can not trade to buy hut or card, different normal causes here:&lt;br /&gt;
** you can trade only one time per game turn (a game turn ends when all workers have been removed from playing area),&lt;br /&gt;
** the 2:1, 1:1 or 1:2 trade indicator (depending on your trade level) is not a trade rate, but a trade possibility: for instance for the 1:1, you can trade one resource and only one against another one, you can not trade two or more against the same number,&lt;br /&gt;
** you can not trade one resource against itself, even at trade level 9 or 10 (1:2 trade possibility: you can not trade one wood against one wood and one stone for instance).&lt;br /&gt;
* Did not get the second resource in my 1:2 trade: all resources gain in a trade are used in the linked buy, even if not needed for it, and it does not add points and can not be used to insulate or pay an extra gold in harsh winter variant.&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Bugsclarification_stoneage&amp;diff=28305</id>
		<title>Bugsclarification stoneage</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Bugsclarification_stoneage&amp;diff=28305"/>
		<updated>2026-01-29T21:24:38Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Please do not report if your bug match one of the followings.&lt;br /&gt;
&lt;br /&gt;
A frequent &amp;quot;won’t fix&amp;quot;: sometimes you are not notified of a game update because of a lost message over the Internet. It can results in wrong situation display and in not being notified that it is your turn to play. These is linked to BGA framework and will not be fixed at the Stone Age code level.&lt;br /&gt;
&lt;br /&gt;
Here is a list of frequent &amp;quot;not a bug&amp;quot; reports: the user was just not knowing the actual rule.&lt;br /&gt;
* Can not put a worker at x place: check the placement limitation rules for two or three players game (and even four players if you are using the trade expansion).&lt;br /&gt;
* Did not get the two (might be one with the trade expansion) wild resources of the civilization card: you got it on your player board, you have to click on the wild resource icon to choose them.&lt;br /&gt;
* Did not get the free wood/clay/stone of the bought hut (new huts expansion): the free resource is not granted at buy but at start of each following turns.&lt;br /&gt;
* Could not insulate bought hut (harsh winter variant): only huts of the standard game and costing three defined resources (not wild resources) can be insulated.&lt;br /&gt;
* Can not trade to buy an igloo: trade is allowed to buy a hut or a card, igloos are not huts nor cards.&lt;br /&gt;
* Can not trade to buy hut or card, different normal causes here:&lt;br /&gt;
** you can trade only one time per game turn (a game turn ends when all workers have been removed from playing area),&lt;br /&gt;
** the 2:1, 1:1 or 1:2 trade indicator (depending on your trade level) is not a trade rate, but a trade possibility: for instance for the 1:1, you can trade one resource and only one against another one, you can not trade two or more against the same number,&lt;br /&gt;
** you can not trade one resource against itself, even at trade level 9 or 10 (1:2 trade possibility: you can not trade one wood against one wood and one stone for instance).&lt;br /&gt;
* Did not get the second resource in my 1:2 trade: all resources gain in a trade are used in the linked buy, even if not needed for it, and it does not add points and can not be used to insulate or pay an extra gold in harsh winter variant.&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=27924</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=27924"/>
		<updated>2026-01-01T18:38:09Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* Game Options */ Formatting&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;
&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;
&#039;&#039;&#039;$this-&amp;gt;tableOptions-&amp;gt;get(int $optionId): int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To get the value of a table option from the Game class, using the JSON key.&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;
=== 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;
GAMESTATE_RATING_MODE and GAMESTATE_CLOCK_MODE are PHP global constants usable in your PHP game code (ex: &amp;lt;code&amp;gt;$this-&amp;gt;tableOptions-&amp;gt;get(GAMESTATE_CLOCK_MODE)&amp;lt;/code&amp;gt;) but not in json.&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;
&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 has an impact in fancy lobby mode; The presentation of level or checkboxes is not available 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;
== 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 a different 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 javascript&lt;br /&gt;
&lt;br /&gt;
  if (this.userPreferences.get(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 is 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 an object called &#039;&#039;&#039;$this-&amp;gt;userPreferences&#039;&#039;&#039;, and you simply have to use its method get (&#039;&#039;&#039;get($playerId, $prefId): ?$int&#039;&#039;&#039;) to know the preference value of a specific player : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if ($this-&amp;gt;userPreferences-&amp;gt;get($playerId, $prefId) == $prefValue) {&lt;br /&gt;
....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: it is stored in database table bga_user_preferences&lt;br /&gt;
&lt;br /&gt;
See also: [[Main game logic: Game.php#User preferences]]&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;gameoptions.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: [[Options and preferences: gameoptions.json, gamepreferences.json#User Preferences|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>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=27923</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=27923"/>
		<updated>2026-01-01T18:36:17Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Indicate how to use GAMESTATE_RATING_MODE and GAMESTATE_CLOCK_MODE.&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;
&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;
&#039;&#039;&#039;$this-&amp;gt;tableOptions-&amp;gt;get(int $optionId): int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To get the value of a table option from the Game class, using the JSON key.&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;
=== 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;
GAMESTATE_RATING_MODE and GAMESTATE_CLOCK_MODE are PHP global constants usable in your PHP game code (ex: $this-&amp;gt;tableOptions-&amp;gt;get(GAMESTATE_CLOCK_MODE)) but not in json.&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;
&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 has an impact in fancy lobby mode; The presentation of level or checkboxes is not available 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 a different 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 javascript&lt;br /&gt;
&lt;br /&gt;
  if (this.userPreferences.get(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 is 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 an object called &#039;&#039;&#039;$this-&amp;gt;userPreferences&#039;&#039;&#039;, and you simply have to use its method get (&#039;&#039;&#039;get($playerId, $prefId): ?$int&#039;&#039;&#039;) to know the preference value of a specific player : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if ($this-&amp;gt;userPreferences-&amp;gt;get($playerId, $prefId) == $prefValue) {&lt;br /&gt;
....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: it is stored in database table bga_user_preferences&lt;br /&gt;
&lt;br /&gt;
See also: [[Main game logic: Game.php#User preferences]]&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;gameoptions.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: [[Options and preferences: gameoptions.json, gamepreferences.json#User Preferences|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>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Bugsclarification_stoneage&amp;diff=27880</id>
		<title>Bugsclarification stoneage</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Bugsclarification_stoneage&amp;diff=27880"/>
		<updated>2025-12-28T20:01:38Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Page creation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here is a list of frequent &amp;quot;not a bug&amp;quot; reports, where the bug is in fact on the user side: the user was just not knowing the actual rule.&lt;br /&gt;
* Can not put a worker at x place: check the placement limitation rules for two or three players game (and even four players if you are using the trade expansion).&lt;br /&gt;
* Did not get the two (might be one with the trade expansion) wild resources of the civilization card: you got it on your player board, you have to click on the wild resource icon to choose them.&lt;br /&gt;
* Did not get the free wood/clay/stone of the bought hut (new huts expansion): the free resource is not granted at buy but at start of each following turns.&lt;br /&gt;
* Could not insulate bought hut (harsh winter variant): only huts of the standard game and costing three defined resources (not wild resources) can be insulated.&lt;br /&gt;
* Can not trade to buy an igloo: trade is allowed to buy a hut or a card, igloos are not huts nor cards.&lt;br /&gt;
* Can not trade to buy hut or card, different normal causes here:&lt;br /&gt;
** you can trade only one time per game turn (a game turn ends when all workers have been removed from playing area),&lt;br /&gt;
** the 2:1, 1:1 or 1:2 trade indicator (depending on your trade level) is not a trade rate, but a trade possibility: for instance for the 1:1, you can trade one resource and only one against another one, you can not trade two or more against the same number,&lt;br /&gt;
** you can not trade one resource against itself, even at trade level 9 or 10 (1:2 trade possibility: you can not trade one wood against one wood and one stone for instance).&lt;br /&gt;
* Did not get the second resource in my 1:2 trade: all resources gain in a trade are used in the linked buy, even if not needed for it, and it does not add points and can not be used to insulate or pay an extra gold in harsh winter variant.&lt;br /&gt;
&lt;br /&gt;
Also a frequent &amp;quot;won’t fix&amp;quot;: sometimes you are not notified of a game update because of a lost message over the Internet. It can results in wrong situation display and in not being notified that it is your turn to play. These is linked to BGA framework and will not be fixed at the Stone Age code level (it could but it would be excessively complicated and unstable toward BGA framework changes).&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_meta-information:_gameinfos.jsonc&amp;diff=9562</id>
		<title>Game meta-information: gameinfos.jsonc</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_meta-information:_gameinfos.jsonc&amp;diff=9562"/>
		<updated>2021-10-01T20:44:36Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Fix doc on the boolean value effect.&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;
From this file, you can edit the various meta-information of your game.&lt;br /&gt;
&lt;br /&gt;
Once you modified the file, don&#039;t forget to click on &amp;quot;Reload game informations&amp;quot; from the Control Panel in order in can be taken into account.&lt;br /&gt;
&lt;br /&gt;
Most information provided in this file are self-explainable.&lt;br /&gt;
&lt;br /&gt;
See sections below for specific cases.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Publisher/Designer fields ==&lt;br /&gt;
&lt;br /&gt;
These fields should match the publisher/designer for the game. In the case of a public domain name, they should be left empty (empty string &#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
== Beta ==&lt;br /&gt;
&lt;br /&gt;
You are not allowed to set the &amp;quot;&#039;&#039;&#039;is_beta&#039;&#039;&#039;&amp;quot; to 0 before the game has been released on BGA and stabilized.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Time Profiles ==&lt;br /&gt;
&#039;&#039;&#039;fast/medium/slow_additional_time&#039;&#039;&#039;: please set high values here: after the game has been released, we will lower these value to match the real game duration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Number of players ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;players&#039;&#039;&#039;&lt;br /&gt;
  &#039;players&#039; =&amp;gt; array( 3, 4, 6 ),&lt;br /&gt;
&lt;br /&gt;
* during the first step of development of a game, it is recommended to have &amp;quot;1 player&amp;quot; configuration: much easy to start/stop a game this way, don&#039;t need to switch players.&lt;br /&gt;
* if you change the minimum number of players from for example 1 to 2, make sure the new tables you create are not restricted from 1 to 1 player otherwise when you create a new table and this account setting is used, there will be a conflict with the new minimum number of players allowed and you will be blocked from creating the game.&lt;br /&gt;
But you can also unblock yourself by changing player number again, launching a game with a larger number, and then getting back to the numbers you want.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;suggest_player_number&#039;&#039;&#039; / &#039;&#039;&#039;not_recommend_player_number&#039;&#039;&#039;&lt;br /&gt;
don&#039;t specify anything here if there is no configuration that is REALLY better/worst than another one. You can check player&#039;s poll on BoardGameGeek game page if you have any doubt. &#039;&#039;&#039;Important exception:&#039;&#039;&#039; in the automatic lobby, if &#039;suggest_player_number&#039; is not specified, the system will try first the lowest. So if the lowest player number is not compatible with the default options for your game (especially if there is a Solo mode that can only be played in training mode) you have to specify a suggest_player_number of your choice, so that players launching a game in the automatic lobby without checking the option don&#039;t get an error with the default configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Colors ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;player_colors&#039;&#039;&#039;&lt;br /&gt;
   &#039;player_colors&#039; =&amp;gt; array( &amp;quot;ff0000&amp;quot;, &amp;quot;008000&amp;quot;, &amp;quot;0000ff&amp;quot;, &amp;quot;ffa500&amp;quot;, &amp;quot;ffffff&amp;quot; ),&lt;br /&gt;
&lt;br /&gt;
This array defines the default player colors, theoretically this can be bigger then maximum number of players but you have to support all of the in your game.&lt;br /&gt;
Your setupNewGame in php is responsible for attributing these values to players. See section &amp;quot;Player color preferences&amp;quot; in [[Main_game_logic:_yourgamename.game.php]] for details.&lt;br /&gt;
&lt;br /&gt;
== Losers not ranked between themselves ==&lt;br /&gt;
&lt;br /&gt;
By default, all player are ranked, but in some games, the rules say that there is only one winner and that all the other players are losers and not ranked between themselves. You can set this option to true so that for your game, there is only one winner and losers, without a full ranking of all players.&lt;br /&gt;
&lt;br /&gt;
The score in this case should be 1 for the winner and 0 for the losers.&lt;br /&gt;
&lt;br /&gt;
 // If in the game, all losers are equal (no score to rank them or explicit in the rules that losers are not ranked between them), set this to true &lt;br /&gt;
 // The game end result will display &amp;quot;Winner&amp;quot; for the 1st player and &amp;quot;Loser&amp;quot; for all other players&lt;br /&gt;
 &#039;losers_not_ranked&#039; =&amp;gt; false,&lt;br /&gt;
&lt;br /&gt;
== Disable player rotation in case of rematch ==&lt;br /&gt;
&lt;br /&gt;
By default, in case of a rematch players are rotated so that the first player changes. If for your game it&#039;s better to always have a random player order you can change this option.&lt;br /&gt;
&lt;br /&gt;
 // When doing a rematch, the player order is swapped using a &amp;quot;rotation&amp;quot; so the starting player is not the same&lt;br /&gt;
 // If you want to disable this, set this to true (even if the comment in your game file say the opposite).&lt;br /&gt;
 &#039;disable_player_order_swap_on_rematch&#039; =&amp;gt; false,&lt;br /&gt;
&lt;br /&gt;
== Custom &amp;quot;buy this game&amp;quot; button ==&lt;br /&gt;
&lt;br /&gt;
By default, the &amp;quot;buy this game&amp;quot; button is a link to an Amazon search with the name of the game.&lt;br /&gt;
&lt;br /&gt;
You can replace it by a different URL / game button label with :&lt;br /&gt;
&lt;br /&gt;
 &#039;custom_buy_button&#039; =&amp;gt; array(&lt;br /&gt;
    &#039;url&#039; =&amp;gt; &#039;http://yoururl.com&#039;,&lt;br /&gt;
    &#039;label&#039; =&amp;gt; &#039;Name of the website&#039;&lt;br /&gt;
 ),&lt;br /&gt;
&lt;br /&gt;
Note : button label will be &amp;quot;Buy on &amp;lt;Name of the website&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== Tags ==&lt;br /&gt;
&lt;br /&gt;
Any number of &#039;&#039;&#039;Tags&#039;&#039;&#039; can be attribute to your game. Tags are useful to place your game in the correct place and to give a good quick overview of what the game is about to players.&lt;br /&gt;
&lt;br /&gt;
Main game category (you MUST specify one tag AND ONLY ONE from this category):&lt;br /&gt;
* 1: Abstract game&lt;br /&gt;
* 2: Casual games&lt;br /&gt;
* 3: For regular players&lt;br /&gt;
* 4: For core gamers&lt;br /&gt;
&lt;br /&gt;
Other tags (you can specify any numbers of tags):&lt;br /&gt;
* 10: Short game (&amp;lt;10 minutes)&lt;br /&gt;
* 11: Medium length game (10 minutes to 30 minutes)&lt;br /&gt;
* 12: Long game (&amp;gt;30mn)&lt;br /&gt;
* 20: Awarded game (Win a prestigious award) (the game must have been at the &#039;&#039;&#039;first&#039;&#039;&#039; place of one the [http://boardgamegeek.com/wiki/page/Gaming_Industry_Awards# following major awards list]).&lt;br /&gt;
* 22: Prototype (This game has not been published yet)&lt;br /&gt;
* 23: Classic (This game is a classic from Public Domain)&lt;br /&gt;
* 30: 2 players (2p game / best with 2 players)&lt;br /&gt;
* 100: Fantasy theme&lt;br /&gt;
* 101: Science Fiction them&lt;br /&gt;
* 102: Historical theme&lt;br /&gt;
* 103: Adventure&lt;br /&gt;
* 104: Exploration&lt;br /&gt;
* 105: Conquest&lt;br /&gt;
* 106: Building&lt;br /&gt;
* 200: Card game (Cards plays a central role in this game)&lt;br /&gt;
* 201: Dice&lt;br /&gt;
* 202: Solo game&lt;br /&gt;
* 203: Worker placement&lt;br /&gt;
* 204: Hand management&lt;br /&gt;
* 205: Bluff&lt;br /&gt;
* 206: Tile placement&lt;br /&gt;
* 207: Combinations&lt;br /&gt;
* 208: Majority&lt;br /&gt;
* 209: Race&lt;br /&gt;
* 210: Collection&lt;br /&gt;
* 211: Cooperative game&lt;br /&gt;
&lt;br /&gt;
== Game Presentation ==&lt;br /&gt;
&lt;br /&gt;
Short game presentation text that will appear on the game description page, structured as an array of paragraphs.&lt;br /&gt;
&lt;br /&gt;
Each paragraph must be wrapped with totranslate() for translation and should not contain html (plain text without formatting). A good length for this text is between 100 and 150 words (about 6 to 9 lines on a standard display)&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 &#039;presentation&#039; =&amp;gt; array(&lt;br /&gt;
    totranslate(&amp;quot;This wonderful game is about geometric shapes!&amp;quot;),&lt;br /&gt;
    totranslate(&amp;quot;It was awarded best triangle game of the year in 2005 and nominated for the Spiel des Jahres.&amp;quot;),&lt;br /&gt;
    ...&lt;br /&gt;
 ),&lt;br /&gt;
&lt;br /&gt;
== Tie breaker description ==&lt;br /&gt;
Describe tie breaker score calculation (player_score_aux in player table).&lt;br /&gt;
&lt;br /&gt;
Important: This is used in the javascript too, which is automatically generated. Using newlines in here will cause errors in the javascript, which will cause the game to not load.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 &#039;tie_breaker_description&#039; =&amp;gt; totranslate(&amp;quot;Number of remaining cards in hand&amp;quot;),&lt;br /&gt;
&lt;br /&gt;
== Language dependency ==&lt;br /&gt;
&lt;br /&gt;
If you have a game that is language dependent, you can use the option described here: [[Main_game_logic:_yourgamename.game.php#Language_dependent_games_API]]&lt;br /&gt;
&lt;br /&gt;
== Coop Elo Mode ==&lt;br /&gt;
&lt;br /&gt;
For cooperative games, by default players will earn as many Elo points as the score. &lt;br /&gt;
&lt;br /&gt;
For games where there is no variable difficulty (such as for example Bandido) we keep that setting, but for all coop games where we have options to change the difficulty level and/or where the score reached indicates a higher level of skill and/or where the number of players has a significant impact on the difficulty, we have to set up a reference scale for Elo points (between 1300 and 2500). Players regularly winning with a specific difficulty setting will have their Elo nearing this value asymptotically over time.&lt;br /&gt;
&lt;br /&gt;
For this, you have to set up the coop_elo_mode parameter.&lt;br /&gt;
&lt;br /&gt;
Here is an example using options and win/loss (score 1/0):&lt;br /&gt;
&lt;br /&gt;
    &#039;coop_elo_mode&#039; =&amp;gt; [&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;points_references&#039;,&lt;br /&gt;
        &#039;references&#039; =&amp;gt; [&lt;br /&gt;
            // Difficulty 1&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1400]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1470]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1350]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1400]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1400]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 1, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1470]],&lt;br /&gt;
            // Difficulty 2&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1540]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1450]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1540]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1540]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 2, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            // Difficulty 3&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1910]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1540]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1690]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 3, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1910]],&lt;br /&gt;
            // Difficulty 4&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1830]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 2120]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1640]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1830]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1830]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 4, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 2120]],&lt;br /&gt;
            // Difficulty 5&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1980]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 2, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 2340]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1740]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 3, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1980]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 0], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 1980]],&lt;br /&gt;
            [&#039;players_nbr&#039; =&amp;gt; 4, &#039;options&#039; =&amp;gt; [100 =&amp;gt; 5, 101 =&amp;gt; 1], &#039;elo&#039; =&amp;gt; [0 =&amp;gt; 1000, 1 =&amp;gt; 2340]],&lt;br /&gt;
        ],&lt;br /&gt;
    ],&lt;br /&gt;
&lt;br /&gt;
Here is an example using different scoring values to indicate the level of difficulty mastered by the players winning the game:&lt;br /&gt;
&lt;br /&gt;
    &#039;coop_elo_mode&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;type&#039; =&amp;gt; &#039;points_references&#039;,&lt;br /&gt;
        &#039;references&#039; =&amp;gt; array(&lt;br /&gt;
            array(&lt;br /&gt;
                &#039;players_nbr&#039; =&amp;gt; 2,&lt;br /&gt;
                //&#039;options&#039; =&amp;gt; array( ),&lt;br /&gt;
                &#039;elo&#039; =&amp;gt; array(&lt;br /&gt;
                    0 =&amp;gt; 1000,&lt;br /&gt;
                    1 =&amp;gt; 1350,&lt;br /&gt;
                    2 =&amp;gt; 1425,&lt;br /&gt;
                    3 =&amp;gt; 1500,&lt;br /&gt;
                    4 =&amp;gt; 1576,&lt;br /&gt;
                    5 =&amp;gt; 1651,&lt;br /&gt;
                    6 =&amp;gt; 1727,&lt;br /&gt;
                    7 =&amp;gt; 1802,&lt;br /&gt;
                    8 =&amp;gt; 1878,&lt;br /&gt;
                    9 =&amp;gt; 1953,&lt;br /&gt;
                    10 =&amp;gt; 2029,&lt;br /&gt;
                    11 =&amp;gt; 2104,&lt;br /&gt;
                    12 =&amp;gt; 2180&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
            array(&lt;br /&gt;
                &#039;players_nbr&#039; =&amp;gt; 3,&lt;br /&gt;
                //&#039;options&#039; =&amp;gt; array( ),&lt;br /&gt;
                &#039;elo&#039; =&amp;gt; array(&lt;br /&gt;
                    0 =&amp;gt; 1000,&lt;br /&gt;
                    1 =&amp;gt; 1400,&lt;br /&gt;
                    2 =&amp;gt; 1470,&lt;br /&gt;
                    3 =&amp;gt; 1541,&lt;br /&gt;
                    4 =&amp;gt; 1612,&lt;br /&gt;
                    5 =&amp;gt; 1683,&lt;br /&gt;
                    6 =&amp;gt; 1754,&lt;br /&gt;
                    7 =&amp;gt; 1825,&lt;br /&gt;
                    8 =&amp;gt; 1895,&lt;br /&gt;
                    9 =&amp;gt; 1966,&lt;br /&gt;
                    10 =&amp;gt; 2018,&lt;br /&gt;
                    11 =&amp;gt; 2095,&lt;br /&gt;
                    12 =&amp;gt; 2250&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
            array(&lt;br /&gt;
                &#039;players_nbr&#039; =&amp;gt; 4,&lt;br /&gt;
                //&#039;options&#039; =&amp;gt; array( ),&lt;br /&gt;
                &#039;elo&#039; =&amp;gt; array(&lt;br /&gt;
                    0 =&amp;gt; 1000,&lt;br /&gt;
                    1 =&amp;gt; 1430,&lt;br /&gt;
                    2 =&amp;gt; 1505,&lt;br /&gt;
                    3 =&amp;gt; 1580,&lt;br /&gt;
                    4 =&amp;gt; 1655,&lt;br /&gt;
                    5 =&amp;gt; 1730,&lt;br /&gt;
                    6 =&amp;gt; 1805,&lt;br /&gt;
                    7 =&amp;gt; 1880,&lt;br /&gt;
                    8 =&amp;gt; 1955,&lt;br /&gt;
                    9 =&amp;gt; 2030,&lt;br /&gt;
                    10 =&amp;gt; 2105,&lt;br /&gt;
                    11 =&amp;gt; 2180,&lt;br /&gt;
                    12 =&amp;gt; 2330&lt;br /&gt;
                )&lt;br /&gt;
            ),&lt;br /&gt;
            array(&lt;br /&gt;
                &#039;players_nbr&#039; =&amp;gt; 5,&lt;br /&gt;
                // &#039;options&#039; =&amp;gt; array( ),&lt;br /&gt;
                &#039;elo&#039; =&amp;gt; array(&lt;br /&gt;
                    0 =&amp;gt; 1000,&lt;br /&gt;
                    1 =&amp;gt; 1480,&lt;br /&gt;
                    2 =&amp;gt; 1558,&lt;br /&gt;
                    3 =&amp;gt; 1636,&lt;br /&gt;
                    4 =&amp;gt; 1714,&lt;br /&gt;
                    5 =&amp;gt; 1792,&lt;br /&gt;
                    6 =&amp;gt; 1870,&lt;br /&gt;
                    7 =&amp;gt; 1949,&lt;br /&gt;
                    8 =&amp;gt; 2027,&lt;br /&gt;
                    9 =&amp;gt; 2105,&lt;br /&gt;
                    10 =&amp;gt; 2183,&lt;br /&gt;
                    11 =&amp;gt; 2261,&lt;br /&gt;
                    12 =&amp;gt; 2340&lt;br /&gt;
                )&lt;br /&gt;
            )&lt;br /&gt;
        )&lt;br /&gt;
    ),&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpstoneage&amp;diff=8217</id>
		<title>Gamehelpstoneage</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpstoneage&amp;diff=8217"/>
		<updated>2021-05-09T14:32:35Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Describe more precisely the rules for trading (see https://boardgamearena.com/bug?id=35396).&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Goal ==&lt;br /&gt;
&lt;br /&gt;
Gain the most Victory Points by the end of the game. &lt;br /&gt;
&lt;br /&gt;
There are two ways to gain points:&lt;br /&gt;
&lt;br /&gt;
* Acquiring buildings during the game for either a fixed or variable amount&lt;br /&gt;
* Acquiring Civilization cards during the game that give extra points at the end of the game&lt;br /&gt;
&lt;br /&gt;
== Rules summary ==&lt;br /&gt;
&lt;br /&gt;
Each round is divided into 3 phases, which are executed in the order described:&lt;br /&gt;
* The players take turns placing their people on the game board.&lt;br /&gt;
* The players use the actions of their placed people all at once in turn order.&lt;br /&gt;
* The players feed their people.&lt;br /&gt;
&lt;br /&gt;
== Phase 1: ==&lt;br /&gt;
===Place People on the Board===&lt;br /&gt;
&lt;br /&gt;
In turn order, one area at a time, players place one or more of their people in the different areas of the board. Each &amp;quot;ring&amp;quot; in each area of the board can only be occupied by one person. The exception to this rule is the hunting ground which can be occupied by as many people of any color every turn.&lt;br /&gt;
&lt;br /&gt;
====Special Considerations When Playing With Fewer Than 4 Players====&lt;br /&gt;
&lt;br /&gt;
When playing with &#039;&#039;&#039;2 or 3 players&#039;&#039;&#039;: Of the non-resource areas (Tool Maker, Hut and Field) only two may be occupied per turn. The third place remains empty until the next round. &lt;br /&gt;
&lt;br /&gt;
With &#039;&#039;&#039;3 players&#039;&#039;&#039;: Of the resource areas (Forest, Clay Pit, Quarry and River) only 2 players may place people in each round, even if there are additional spaces for additional people.&lt;br /&gt;
&lt;br /&gt;
With &#039;&#039;&#039;2 players&#039;&#039;&#039;: Of the resource areas (Forest, Clay Pit, Quarry and River) only 1 player may place people in each round, even if there are additional spaces for additional people.&lt;br /&gt;
&lt;br /&gt;
All remaining rules remain unchanged when playing with fewer than 4 players.&lt;br /&gt;
&lt;br /&gt;
== Phase 2: ==&lt;br /&gt;
===Use the Actions of Your Placed People===&lt;br /&gt;
&lt;br /&gt;
In turn order each player uses all of his placed people in any order. During this phase, the following actions may be used:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Hunting Grounds (Food), Forest (Wood), Clay Pit (Brick), Quarry (Stone), and River (Gold)&#039;&#039;&#039;: Roll 1 dice per person placed and acquire resources according to the number rolled (1 Food for each full 2 on Hunting Grounds, 1 Wood for each full 3 on Forest, 1 Brick for each full 4 on Clay Pit, 1 Stone for each full 5 on Quarry, 1 Gold for each full 6 on River).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Field&#039;&#039;&#039;: Placing a person in the Field increases your Agriculture Level. Each turn during the Feeding Phase, your Agriculture Level is subtracted from the amount of people you have. A higher agriculture level allows you to more easily sustain your population.  You may have a maximum agriculture level of 10.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tool Maker&#039;&#039;&#039;: Placing a person on the Tool Maker adds one new Tool to your player board. You only have 3 tools on your player board, and each subsequent person placed on the Tool Maker upgrades one of your tools to the next level. You have a maximum of 3 level 4 tools.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Hut&#039;&#039;&#039;: Place two People on the Hut to gain an extra Person to place (and feed) for the rest of the game.  You may have a maximum of 10 people.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Building Card&#039;&#039;&#039;: Buy the building with the resources shown on the Building Card, scoring the point value shown in the top-left corner (A question mark in the top-left corner is explained below).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Civilization Card&#039;&#039;&#039;: Buy the card with a number of resources (of any kind) depending on its position in the Civilization Card Track (1 to 4 resources depicted above the card). The immediate effect of the card is applied when purchase. The bottom half of Civilization Card is used for scoring at the end of the game.&lt;br /&gt;
&lt;br /&gt;
===Resources===&lt;br /&gt;
&lt;br /&gt;
Hunting Grounds, Forest, Clay Pit, Quarry, and River:&lt;br /&gt;
Roll 1 dice per Person placed in that area and take the corresponding resources:&lt;br /&gt;
&lt;br /&gt;
* 1 Food for each full 2 on Hunting Grounds,&lt;br /&gt;
* 1 Wood for each full 3 on Forest,&lt;br /&gt;
* 1 Brick for each full 4 on Clay Pit,&lt;br /&gt;
* 1 Stone for each full 5 on Quarry,&lt;br /&gt;
* 1 Gold for each full 6 on River.&lt;br /&gt;
&lt;br /&gt;
You may use tools to increase the dice result and take more resources.  Each of your tool must be used all at once, and can be used once per turn.  Some cards give you single-use tools which are lost after they are used, and don&#039;t count for final scoring.&lt;br /&gt;
&lt;br /&gt;
===Buildings===&lt;br /&gt;
&lt;br /&gt;
Pay the building cost to get the Building and receive the Point Value listed in the top-left corner of the card.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If the building cost is Not Fixed&#039;&#039;: If there is a question mark in the corner of the card, you win points for each of the resources used to acquire this building. The values of each resource correspond to the numbers it requires when people are placed on them:&lt;br /&gt;
* Each Wood is worth 3 Points,&lt;br /&gt;
* Each Brick is worth 4 Points,&lt;br /&gt;
* Each Stone is worth 5 Points,&lt;br /&gt;
* Each Gold is worth 6 Points.&lt;br /&gt;
&lt;br /&gt;
===Civilization Card Details===&lt;br /&gt;
&lt;br /&gt;
Each Civilization Card acquired brings an immediate advantage (depicted on the top half of the card) and some multiplier for final scoring (depicted on the bottom half of the card).&lt;br /&gt;
&lt;br /&gt;
Place the mouse cursor on each card to see details in the tooltip. &lt;br /&gt;
&lt;br /&gt;
Note that at the list of your acquired civilization cards you will see only the bottom half of each card, for the top half is no longer relevant.&lt;br /&gt;
&lt;br /&gt;
== Phase 3: ==&lt;br /&gt;
===Feed Your People===&lt;br /&gt;
&lt;br /&gt;
Each Agriculture Level automatically counts as 1 Food during this phase.&lt;br /&gt;
&lt;br /&gt;
You must provide 1 Food per Person.&lt;br /&gt;
&lt;br /&gt;
In the event that you don&#039;t have enough food, you may use any resource to feed your people.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t manage (or choose not) to feed your people by the means above, you lose all of your food and 10 points as a penalty.&lt;br /&gt;
&lt;br /&gt;
===Game End===&lt;br /&gt;
&lt;br /&gt;
The game ends when either:&lt;br /&gt;
&lt;br /&gt;
* One Building Stack is empty at the end of a round, or&lt;br /&gt;
* There are insufficient Civilization cards to fill the 4 spots at the beginning of a round.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The final number of points for each player is decided by the conditions below: &lt;br /&gt;
&lt;br /&gt;
* Points earned during the game by acquiring Buildings or Civilization, minus Food Penalties,&lt;br /&gt;
* Multipliers denoted at the bottom halves of Civilization Cards collected,&lt;br /&gt;
* Each Resource that a Player has leftover on his Player Board Scores 1 Point.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
===Harsh Winter===&lt;br /&gt;
* Spend an extra stone when building certain buildings to score 5 points.&lt;br /&gt;
* Spend an extra gold when purchasing cards to score 6 points.&lt;br /&gt;
&lt;br /&gt;
===Wild Animals===&lt;br /&gt;
* Four animal cards are shuffled into the civilization deck. When revealed, animals stay in play until driven off, subtracting 1, 2, or 3 from all dice rolls. &lt;br /&gt;
* Players must collectively place a total of X people on the card to drive it off (X = number of players). &lt;br /&gt;
* After driving off a wild animal, each player rolls 1 dice per person placed on it and receive the rewards.&lt;br /&gt;
&lt;br /&gt;
===Igloos===&lt;br /&gt;
* Spend 3 resources of the same type to buy an igloo, which awards points like a building but does not count for the end-game building bonus.&lt;br /&gt;
&lt;br /&gt;
===The New Huts===&lt;br /&gt;
* Adds new buildings that grant fewer points when built in exchange for a bonus (gain a wood/brick/stone each round, or +1 worker/tool/agriculture level). These do count for the end-game building bonus.&lt;br /&gt;
&lt;br /&gt;
===Mammoth Herd===&lt;br /&gt;
* At the beginning of each round, a mammoth appears on the resource shown by the top-most bonus tile.&lt;br /&gt;
* Players who place their people there can also spend 1 food or resource per person to tame the mammoth.&lt;br /&gt;
* Each player who place people to tame the mammoth roll 1 dice per person.&lt;br /&gt;
* The player with the highest single dice is the mammoth tamer. Others are challengers.&lt;br /&gt;
* The mammoth tamer can choose to take the 1 or all bonus. Others take the all bonus.&lt;br /&gt;
* At the end of the game, the player with the most mammoth tile scores 10 points.&lt;br /&gt;
&lt;br /&gt;
===The Expansion===&lt;br /&gt;
* A new location is available on the board: Merchant. 2 people are needed to use this place. When using, increase the merchant level by 2 and gain 2 jewelry.&lt;br /&gt;
* Once per round, for buying a card or a building, players can trade resources or jewelry to receive one or two resources or jewelry, depending on their levels. However, a player cannot trade if he is on space 0.&lt;br /&gt;
* The rules for Hunting Grounds has changed: for each full 2, 1 food or 1 jewelry can be taken.&lt;br /&gt;
* There is a new space for civilization cards: 3 jewelry is needed to buy a card on that space. After that, 3 extra jewelry can be spent to buy the topmost face down civilization card without applying its immediate effect.&lt;br /&gt;
* Jewelry is not a resource, therefore it can not be used to feed people and is worth nothing at the end of the game.&lt;br /&gt;
* When there are only 4 people, only 3 non-resource places are available each round. When there are only 2-3, 2 are available.&lt;br /&gt;
* Trade is not allowed for buying an igloo.&lt;br /&gt;
* The extra stone and extra gold of the Harsh Winter variant can not be obtained with a trade.&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpstoneage&amp;diff=8216</id>
		<title>Gamehelpstoneage</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpstoneage&amp;diff=8216"/>
		<updated>2021-05-09T14:16:23Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* Mammoth Herd */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Goal ==&lt;br /&gt;
&lt;br /&gt;
Gain the most Victory Points by the end of the game. &lt;br /&gt;
&lt;br /&gt;
There are two ways to gain points:&lt;br /&gt;
&lt;br /&gt;
* Acquiring buildings during the game for either a fixed or variable amount&lt;br /&gt;
* Acquiring Civilization cards during the game that give extra points at the end of the game&lt;br /&gt;
&lt;br /&gt;
== Rules summary ==&lt;br /&gt;
&lt;br /&gt;
Each round is divided into 3 phases, which are executed in the order described:&lt;br /&gt;
* The players take turns placing their people on the game board.&lt;br /&gt;
* The players use the actions of their placed people all at once in turn order.&lt;br /&gt;
* The players feed their people.&lt;br /&gt;
&lt;br /&gt;
== Phase 1: ==&lt;br /&gt;
===Place People on the Board===&lt;br /&gt;
&lt;br /&gt;
In turn order, one area at a time, players place one or more of their people in the different areas of the board. Each &amp;quot;ring&amp;quot; in each area of the board can only be occupied by one person. The exception to this rule is the hunting ground which can be occupied by as many people of any color every turn.&lt;br /&gt;
&lt;br /&gt;
====Special Considerations When Playing With Fewer Than 4 Players====&lt;br /&gt;
&lt;br /&gt;
When playing with &#039;&#039;&#039;2 or 3 players&#039;&#039;&#039;: Of the non-resource areas (Tool Maker, Hut and Field) only two may be occupied per turn. The third place remains empty until the next round. &lt;br /&gt;
&lt;br /&gt;
With &#039;&#039;&#039;3 players&#039;&#039;&#039;: Of the resource areas (Forest, Clay Pit, Quarry and River) only 2 players may place people in each round, even if there are additional spaces for additional people.&lt;br /&gt;
&lt;br /&gt;
With &#039;&#039;&#039;2 players&#039;&#039;&#039;: Of the resource areas (Forest, Clay Pit, Quarry and River) only 1 player may place people in each round, even if there are additional spaces for additional people.&lt;br /&gt;
&lt;br /&gt;
All remaining rules remain unchanged when playing with fewer than 4 players.&lt;br /&gt;
&lt;br /&gt;
== Phase 2: ==&lt;br /&gt;
===Use the Actions of Your Placed People===&lt;br /&gt;
&lt;br /&gt;
In turn order each player uses all of his placed people in any order. During this phase, the following actions may be used:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Hunting Grounds (Food), Forest (Wood), Clay Pit (Brick), Quarry (Stone), and River (Gold)&#039;&#039;&#039;: Roll 1 dice per person placed and acquire resources according to the number rolled (1 Food for each full 2 on Hunting Grounds, 1 Wood for each full 3 on Forest, 1 Brick for each full 4 on Clay Pit, 1 Stone for each full 5 on Quarry, 1 Gold for each full 6 on River).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Field&#039;&#039;&#039;: Placing a person in the Field increases your Agriculture Level. Each turn during the Feeding Phase, your Agriculture Level is subtracted from the amount of people you have. A higher agriculture level allows you to more easily sustain your population.  You may have a maximum agriculture level of 10.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tool Maker&#039;&#039;&#039;: Placing a person on the Tool Maker adds one new Tool to your player board. You only have 3 tools on your player board, and each subsequent person placed on the Tool Maker upgrades one of your tools to the next level. You have a maximum of 3 level 4 tools.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Hut&#039;&#039;&#039;: Place two People on the Hut to gain an extra Person to place (and feed) for the rest of the game.  You may have a maximum of 10 people.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Building Card&#039;&#039;&#039;: Buy the building with the resources shown on the Building Card, scoring the point value shown in the top-left corner (A question mark in the top-left corner is explained below).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Civilization Card&#039;&#039;&#039;: Buy the card with a number of resources (of any kind) depending on its position in the Civilization Card Track (1 to 4 resources depicted above the card). The immediate effect of the card is applied when purchase. The bottom half of Civilization Card is used for scoring at the end of the game.&lt;br /&gt;
&lt;br /&gt;
===Resources===&lt;br /&gt;
&lt;br /&gt;
Hunting Grounds, Forest, Clay Pit, Quarry, and River:&lt;br /&gt;
Roll 1 dice per Person placed in that area and take the corresponding resources:&lt;br /&gt;
&lt;br /&gt;
* 1 Food for each full 2 on Hunting Grounds,&lt;br /&gt;
* 1 Wood for each full 3 on Forest,&lt;br /&gt;
* 1 Brick for each full 4 on Clay Pit,&lt;br /&gt;
* 1 Stone for each full 5 on Quarry,&lt;br /&gt;
* 1 Gold for each full 6 on River.&lt;br /&gt;
&lt;br /&gt;
You may use tools to increase the dice result and take more resources.  Each of your tool must be used all at once, and can be used once per turn.  Some cards give you single-use tools which are lost after they are used, and don&#039;t count for final scoring.&lt;br /&gt;
&lt;br /&gt;
===Buildings===&lt;br /&gt;
&lt;br /&gt;
Pay the building cost to get the Building and receive the Point Value listed in the top-left corner of the card.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If the building cost is Not Fixed&#039;&#039;: If there is a question mark in the corner of the card, you win points for each of the resources used to acquire this building. The values of each resource correspond to the numbers it requires when people are placed on them:&lt;br /&gt;
* Each Wood is worth 3 Points,&lt;br /&gt;
* Each Brick is worth 4 Points,&lt;br /&gt;
* Each Stone is worth 5 Points,&lt;br /&gt;
* Each Gold is worth 6 Points.&lt;br /&gt;
&lt;br /&gt;
===Civilization Card Details===&lt;br /&gt;
&lt;br /&gt;
Each Civilization Card acquired brings an immediate advantage (depicted on the top half of the card) and some multiplier for final scoring (depicted on the bottom half of the card).&lt;br /&gt;
&lt;br /&gt;
Place the mouse cursor on each card to see details in the tooltip. &lt;br /&gt;
&lt;br /&gt;
Note that at the list of your acquired civilization cards you will see only the bottom half of each card, for the top half is no longer relevant.&lt;br /&gt;
&lt;br /&gt;
== Phase 3: ==&lt;br /&gt;
===Feed Your People===&lt;br /&gt;
&lt;br /&gt;
Each Agriculture Level automatically counts as 1 Food during this phase.&lt;br /&gt;
&lt;br /&gt;
You must provide 1 Food per Person.&lt;br /&gt;
&lt;br /&gt;
In the event that you don&#039;t have enough food, you may use any resource to feed your people.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t manage (or choose not) to feed your people by the means above, you lose all of your food and 10 points as a penalty.&lt;br /&gt;
&lt;br /&gt;
===Game End===&lt;br /&gt;
&lt;br /&gt;
The game ends when either:&lt;br /&gt;
&lt;br /&gt;
* One Building Stack is empty at the end of a round, or&lt;br /&gt;
* There are insufficient Civilization cards to fill the 4 spots at the beginning of a round.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The final number of points for each player is decided by the conditions below: &lt;br /&gt;
&lt;br /&gt;
* Points earned during the game by acquiring Buildings or Civilization, minus Food Penalties,&lt;br /&gt;
* Multipliers denoted at the bottom halves of Civilization Cards collected,&lt;br /&gt;
* Each Resource that a Player has leftover on his Player Board Scores 1 Point.&lt;br /&gt;
&lt;br /&gt;
== Variants ==&lt;br /&gt;
===Harsh Winter===&lt;br /&gt;
* Spend an extra stone when building certain buildings to score 5 points.&lt;br /&gt;
* Spend an extra gold when purchasing cards to score 6 points.&lt;br /&gt;
&lt;br /&gt;
===Wild Animals===&lt;br /&gt;
* Four animal cards are shuffled into the civilization deck. When revealed, animals stay in play until driven off, subtracting 1, 2, or 3 from all dice rolls. &lt;br /&gt;
* Players must collectively place a total of X people on the card to drive it off (X = number of players). &lt;br /&gt;
* After driving off a wild animal, each player rolls 1 dice per person placed on it and receive the rewards.&lt;br /&gt;
&lt;br /&gt;
===Igloos===&lt;br /&gt;
* Spend 3 resources of the same type to buy an igloo, which awards points like a building but does not count for the end-game building bonus.&lt;br /&gt;
&lt;br /&gt;
===The New Huts===&lt;br /&gt;
* Adds new buildings that grant fewer points when built in exchange for a bonus (gain a wood/brick/stone each round, or +1 worker/tool/agriculture level). These do count for the end-game building bonus.&lt;br /&gt;
&lt;br /&gt;
===Mammoth Herd===&lt;br /&gt;
* At the beginning of each round, a mammoth appears on the resource shown by the top-most bonus tile.&lt;br /&gt;
* Players who place their people there can also spend 1 food or resource per person to tame the mammoth.&lt;br /&gt;
* Each player who place people to tame the mammoth roll 1 dice per person.&lt;br /&gt;
* The player with the highest single dice is the mammoth tamer. Others are challengers.&lt;br /&gt;
* The mammoth tamer can choose to take the 1 or all bonus. Others take the all bonus.&lt;br /&gt;
* At the end of the game, the player with the most mammoth tile scores 10 points.&lt;br /&gt;
&lt;br /&gt;
===The Expansion===&lt;br /&gt;
* A new location is avaliable on the board: Merchant. 2 people are needed to use this place. When using, increase the merchant level by 2 and gain 2 jewelry.&lt;br /&gt;
* Once per round, players can trade with the rate on their levels. However, a player cannot trade if he is on space 0.&lt;br /&gt;
* The rules for Hunting Grounds has changed: for each full 2, 1 food or 1 jewelry can be taken.&lt;br /&gt;
* There is a new space for civilization cards: 3 jewelry is needed to buy a card on that space. After that, 3 extra jewelry can be spent to buy the topmost facedown civilization card without applying its immediate effect.&lt;br /&gt;
* Jewelry is not a resource, therefore it can not be used to feed people and is worth nothing at the end of the game.&lt;br /&gt;
* When there are only 4 people, only 3 non-resource places are avaliable each round. When there are only 2-3, 2 are avaliable.&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=8089</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=8089"/>
		<updated>2021-04-27T17:09:58Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Remove assertion on displaycondition, now it seems to be effect less.&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 (= 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 in your SFTP folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes to take effect.&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options is something selected by table creator and usually correspond to game variant, for example if game includes expansion or certain special rule.&lt;br /&gt;
&lt;br /&gt;
These variants defined in gameoptions.inc.php as variable  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is pair 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;
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, usually if variant &amp;quot;names&amp;quot; are On and Off, but the description would be same as option name when On, and nothing 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.)&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&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;&#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, values 11-21 - turn based&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;
== 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;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=8086</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=8086"/>
		<updated>2021-04-27T12:41:08Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* User Preferences */&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 (= 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 in your SFTP folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes to take effect.&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options is something selected by table creator and usually correspond to game variant, for example if game includes expansion or certain special rule.&lt;br /&gt;
&lt;br /&gt;
These variants defined in gameoptions.inc.php as variable  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is pair 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;
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, usually if variant &amp;quot;names&amp;quot; are On and Off, but the description would be same as option name when On, and nothing 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.)&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&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;&#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, values 11-21 - turn based&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;
== 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;
If you try to use a displaycondition like for an option, your preference will always be hidden (bug).&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;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=8085</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=8085"/>
		<updated>2021-04-27T12:39:26Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* User Preferences */&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 (= 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 in your SFTP folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes to take effect.&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options is something selected by table creator and usually correspond to game variant, for example if game includes expansion or certain special rule.&lt;br /&gt;
&lt;br /&gt;
These variants defined in gameoptions.inc.php as variable  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is pair 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;
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, usually if variant &amp;quot;names&amp;quot; are On and Off, but the description would be same as option name when On, and nothing 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.)&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&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;&#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, values 11-21 - turn based&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;
== 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 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;
If you try to use a displaycondition like for an option, your preference will always be hidden (bug).&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;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=8084</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=8084"/>
		<updated>2021-04-27T12:38:47Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Add missing parameters&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 (= 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 in your SFTP folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes to take effect.&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options is something selected by table creator and usually correspond to game variant, for example if game includes expansion or certain special rule.&lt;br /&gt;
&lt;br /&gt;
These variants defined in gameoptions.inc.php as variable  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is pair 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;
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, usually if variant &amp;quot;names&amp;quot; are On and Off, but the description would be same as option name when On, and nothing 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.)&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&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;&#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, values 11-21 - turn based&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;
== 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 would 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 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;
If you try to use a displaycondition like for an option, your preference will always be hidden (bug).&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;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=8083</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=8083"/>
		<updated>2021-04-27T12:28:22Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* Updating preference from code */&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 (= 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 in your SFTP folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes to take effect.&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options is something selected by table creator and usually correspond to game variant, for example if game includes expansion or certain special rule.&lt;br /&gt;
&lt;br /&gt;
These variants defined in gameoptions.inc.php as variable  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is pair 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;
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, usually if variant &amp;quot;names&amp;quot; are On and Off, but the description would be same as option name when On, and nothing 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.)&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&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;&#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, values 11-21 - turn based&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;
== 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;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;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;
If you try to use a displaycondition like for an option, your preference will always be hidden (bug).&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;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=8082</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=8082"/>
		<updated>2021-04-27T12:27:43Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Add how to update a preference from the code.&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 (= 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 in your SFTP folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes to take effect.&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options is something selected by table creator and usually correspond to game variant, for example if game includes expansion or certain special rule.&lt;br /&gt;
&lt;br /&gt;
These variants defined in gameoptions.inc.php as variable  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is pair 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;
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, usually if variant &amp;quot;names&amp;quot; are On and Off, but the description would be same as option name when On, and nothing 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.)&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&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;&#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, values 11-21 - turn based&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;
== 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;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;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;
If you try to use a displaycondition like for an option, your preference will always be hidden (bug).&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(&amp;quot;HTMLEvents&amp;quot;);&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;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=8081</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=8081"/>
		<updated>2021-04-27T12:11:11Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Add preferences parameters description.&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 (= 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 in your SFTP folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes to take effect.&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options is something selected by table creator and usually correspond to game variant, for example if game includes expansion or certain special rule.&lt;br /&gt;
&lt;br /&gt;
These variants defined in gameoptions.inc.php as variable  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is pair 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;
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, usually if variant &amp;quot;names&amp;quot; are On and Off, but the description would be same as option name when On, and nothing 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.)&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&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;&#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, values 11-21 - turn based&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;
== 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;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;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;
If you try to use a displaycondition like for an option, your preference will always be hidden.&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;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=8080</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=8080"/>
		<updated>2021-04-27T11:44:40Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Fix sample formatting&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 (= 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 in your SFTP folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes to take effect.&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options is something selected by table creator and usually correspond to game variant, for example if game includes expansion or certain special rule.&lt;br /&gt;
&lt;br /&gt;
These variants defined in gameoptions.inc.php as variable  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is pair 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;
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, usually if variant &amp;quot;names&amp;quot; are On and Off, but the description would be same as option name when On, and nothing 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.)&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&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;&#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, values 11-21 - turn based&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;
== 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;
&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;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Options_and_preferences:_gameoptions.json,_gamepreferences.json&amp;diff=8054</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=8054"/>
		<updated>2021-04-23T19:08:54Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Add default parameter&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 (= 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 in your SFTP folder you have to go to the control panel and press &amp;quot;Reload game options configuration&amp;quot; for your changes to take effect.&lt;br /&gt;
&lt;br /&gt;
== Game Options ==&lt;br /&gt;
&lt;br /&gt;
Game options is something selected by table creator and usually correspond to game variant, for example if game includes expansion or certain special rule.&lt;br /&gt;
&lt;br /&gt;
These variants defined in gameoptions.inc.php as variable  &lt;br /&gt;
  $game_options = array(...); // exactly named that&lt;br /&gt;
&lt;br /&gt;
Each option is pair 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;
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, usually if variant &amp;quot;names&amp;quot; are On and Off, but the description would be same as option name when On, and nothing 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.)&lt;br /&gt;
** &#039;&#039;&#039;nobeginner&#039;&#039;&#039; - Set to true if not recommended for begginers&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;&#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, values 11-21 - turn based&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;
&lt;br /&gt;
&#039;displaycondition&#039; =&amp;gt; array(    // 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;
&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;
== 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;
&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;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=6104</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=6104"/>
		<updated>2020-11-08T13:29:52Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* On server side (PHP) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
== How translation works? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Before the release of the game, BGA team will do the French translation of the game.&lt;br /&gt;
&lt;br /&gt;
After the release of the game, the BGA players community will translate the game in every language.&lt;br /&gt;
&lt;br /&gt;
== What should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages, ...&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final dot &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final dot&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final dot.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final dot:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current action in the status bar&lt;br /&gt;
** Final dot:&lt;br /&gt;
*** complete explanation sentence, that can be chained with another sentence&lt;br /&gt;
** We can tolerate a dot or no dot (but it should be consistent inside the game) for:&lt;br /&gt;
*** isolated tooltip / isolated small sentence&lt;br /&gt;
*** game log (no dot is usually preferable)&lt;br /&gt;
*** error messages (except if more than one sentence in the error message =&amp;gt; final dot mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the English rulebook and game material of the game.&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== WARNING: how to make sure your strings will be translated ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool is doing a full scan of the code, looking for translator markers like &amp;quot;_()&amp;quot; or &amp;quot;clientranslate()&amp;quot;... (see below the list of translation markers).&lt;br /&gt;
&lt;br /&gt;
If your original string is not &amp;quot;physically&amp;quot; inside one of this marker, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not bordered by a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Same thing&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* When you need the same string twice, try to reuse exactly the same string (with the same case) to minimize the number of strings.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (ex: if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The more the string is a short insignificant string, the more difficult is the task for them. As a rule of thumb, try to avoid insignificant short strings. You can also leave a comment on what is the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar... We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing nice strings like &amp;quot;With the effect of ZZZ, player XXX gets a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past, i.e. &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;&lt;br /&gt;
* Avoid using gender specific pronouns, i.e.  instead of &amp;quot;player returns card to *his* hand&amp;quot; use &amp;quot;player returns card to *their* hand&amp;quot; or just avoid using it, i.e. &amp;quot;player picks up the card&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;&#039;transparent&#039;&#039;&#039;: it will return the original English string without any change. It&#039;s only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* On your states.inc.php, for field &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* On &amp;quot;material.inc.php&amp;quot;, when defining texts for game material that must be displayed on client side.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Air&amp;quot;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &amp;quot;notifyAllPlayers&amp;quot; or &amp;quot;notifyPlayer&amp;quot;, for the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&amp;quot;Everyone draw cards from his library&amp;quot;), array() );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;; self::notifyAllPlayers( &#039;log&#039;, clienttraslate(notif)); // BAD&lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;); self::notifyAllPlayers( &#039;log&#039;, notif); // GOOD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. It is using the &amp;quot;i18n&amp;quot; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Fire&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using &#039;i18n&#039; argument when translating argument for client : do NOT use same argument for both translation AND key code for client side action (like using &#039;card_name&#039; to move it on player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument name like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with clienttranslate, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following 3 situations:&lt;br /&gt;
* When throwing an exception because the player did a forbidden move.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Eventually, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Eventually, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=6103</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=6103"/>
		<updated>2020-11-08T13:29:37Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* On server side (PHP) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
== How translation works? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Before the release of the game, BGA team will do the French translation of the game.&lt;br /&gt;
&lt;br /&gt;
After the release of the game, the BGA players community will translate the game in every language.&lt;br /&gt;
&lt;br /&gt;
== What should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages, ...&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final dot &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final dot&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final dot.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final dot:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current action in the status bar&lt;br /&gt;
** Final dot:&lt;br /&gt;
*** complete explanation sentence, that can be chained with another sentence&lt;br /&gt;
** We can tolerate a dot or no dot (but it should be consistent inside the game) for:&lt;br /&gt;
*** isolated tooltip / isolated small sentence&lt;br /&gt;
*** game log (no dot is usually preferable)&lt;br /&gt;
*** error messages (except if more than one sentence in the error message =&amp;gt; final dot mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the English rulebook and game material of the game.&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== WARNING: how to make sure your strings will be translated ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool is doing a full scan of the code, looking for translator markers like &amp;quot;_()&amp;quot; or &amp;quot;clientranslate()&amp;quot;... (see below the list of translation markers).&lt;br /&gt;
&lt;br /&gt;
If your original string is not &amp;quot;physically&amp;quot; inside one of this marker, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not bordered by a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Same thing&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* When you need the same string twice, try to reuse exactly the same string (with the same case) to minimize the number of strings.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (ex: if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The more the string is a short insignificant string, the more difficult is the task for them. As a rule of thumb, try to avoid insignificant short strings. You can also leave a comment on what is the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar... We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing nice strings like &amp;quot;With the effect of ZZZ, player XXX gets a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past, i.e. &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;&lt;br /&gt;
* Avoid using gender specific pronouns, i.e.  instead of &amp;quot;player returns card to *his* hand&amp;quot; use &amp;quot;player returns card to *their* hand&amp;quot; or just avoid using it, i.e. &amp;quot;player picks up the card&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;&#039;transparent&#039;&#039;&#039;: it will return the original English string without any change. It&#039;s only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* On your states.inc.php, for field &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* On &amp;quot;material.inc.php&amp;quot;, when defining texts for game material that must be displayed on client side.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Air&amp;quot;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &amp;quot;notifyAllPlayers&amp;quot; or &amp;quot;notifyPlayer&amp;quot;, for the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&amp;quot;Everyone draw cards from his library&amp;quot;), array() );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;; self::notifyAllPlayers( &#039;log&#039;, clienttraslate(notif)); // BAD&lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;); self::notifyAllPlayers( &#039;log&#039;, notif); // GOOD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. It is using the &amp;quot;i18n&amp;quot; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
...&lt;br /&gt;
     8 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Air&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using &#039;i18n&#039; argument when translating argument for client : do NOT use same argument for both translation AND key code for client side action (like using &#039;card_name&#039; to move it on player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument name like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with clienttranslate, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following 3 situations:&lt;br /&gt;
* When throwing an exception because the player did a forbidden move.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Eventually, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Eventually, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=6102</id>
		<title>Translations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Translations&amp;diff=6102"/>
		<updated>2020-11-08T13:28:45Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* On server side (PHP) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Using BGA Studio, the game you create is ready to be translated to each language by the BGA community. To make this possible, you only need to specify which string must be translated and how to combine them.&lt;br /&gt;
&lt;br /&gt;
== How translation works? ==&lt;br /&gt;
&lt;br /&gt;
When developing your game, all strings must be in English. Strings must be coherent with the English version of the game.&lt;br /&gt;
&lt;br /&gt;
Before the release of the game, BGA team will do the French translation of the game.&lt;br /&gt;
&lt;br /&gt;
After the release of the game, the BGA players community will translate the game in every language.&lt;br /&gt;
&lt;br /&gt;
== What should be translated? ==&lt;br /&gt;
&lt;br /&gt;
Every text that can be visible by the player when the game is running normally. This includes tooltips, texts on cards, error messages, ...&lt;br /&gt;
&lt;br /&gt;
This does NOT include error messages that are not supposed to happen (unexpected errors).&lt;br /&gt;
&lt;br /&gt;
== What rules should I follow for the original English strings? ==&lt;br /&gt;
&lt;br /&gt;
For a coherent and homogeneous interface, here are some rules about ending a sentence with a final dot &#039;.&#039;&lt;br /&gt;
&lt;br /&gt;
* As a general rule:&lt;br /&gt;
** If a sentence is displayed isolated in the interface =&amp;gt; no final dot&lt;br /&gt;
** If a sentence is followed or could be followed by another sentence in the same interface space =&amp;gt; final dot.&lt;br /&gt;
&lt;br /&gt;
* In detail:&lt;br /&gt;
** No final dot:&lt;br /&gt;
*** button labels&lt;br /&gt;
*** section titles&lt;br /&gt;
*** menu elements&lt;br /&gt;
*** links triggering an isolated action&lt;br /&gt;
*** anything that is not a full sentence&lt;br /&gt;
*** current action in the status bar&lt;br /&gt;
** Final dot:&lt;br /&gt;
*** complete explanation sentence, that can be chained with another sentence&lt;br /&gt;
** We can tolerate a dot or no dot (but it should be consistent inside the game) for:&lt;br /&gt;
*** isolated tooltip / isolated small sentence&lt;br /&gt;
*** game log (no dot is usually preferable)&lt;br /&gt;
*** error messages (except if more than one sentence in the error message =&amp;gt; final dot mandatory in this case)&lt;br /&gt;
&lt;br /&gt;
Otherwise, you should try to follow as closely as possible the general style and format (including capitalization) used in the English rulebook and game material of the game.&lt;br /&gt;
&lt;br /&gt;
== Focus on translating notifications ==&lt;br /&gt;
&lt;br /&gt;
Usually, translating a website is simple: you just call a function on every string you have to translate, and the string is translated in the player&#039;s language. On Board Game Arena, this is exactly the same with the &amp;quot;_( string )&amp;quot; function.&lt;br /&gt;
&lt;br /&gt;
However, there is one difference on BGA: notifications. The server is sending notifications to players, and most of the time the notifications are the same for every players, no matter what language each player is using. This is why notifications are translated on client side in the proper language, even if the strings are defined on server side.&lt;br /&gt;
&lt;br /&gt;
== WARNING: how to make sure your strings will be translated ==&lt;br /&gt;
&lt;br /&gt;
For each game, our translation tool is doing a full scan of the code, looking for translator markers like &amp;quot;_()&amp;quot; or &amp;quot;clientranslate()&amp;quot;... (see below the list of translation markers).&lt;br /&gt;
&lt;br /&gt;
If your original string is not &amp;quot;physically&amp;quot; inside one of this marker, it won&#039;t be translated.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Examples: the following strings will be translated:&lt;br /&gt;
    var mystring_translated = _(&amp;quot;my string&amp;quot;);       // JS&lt;br /&gt;
    $mystring_translated = self::_(&amp;quot;my string&amp;quot;);    // PHP&lt;br /&gt;
    $mystring_translated = sprintf( self::_(&amp;quot;my string with an %s argument&amp;quot;), $argument );   // PHP&lt;br /&gt;
&lt;br /&gt;
    // Examples: the following strings WILL NOT be translated:&lt;br /&gt;
    $my_string = &amp;quot;my string&amp;quot;;&lt;br /&gt;
    $not_translated = self::_( $my_string );   // The original string is not bordered by a translator marker =&amp;gt; no translation&lt;br /&gt;
    $not_translated = self::_( sprintf( &amp;quot;my string with a %s argument&amp;quot;, $argument ) ); // Same thing&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== How to not make translators crazy ;) ==&lt;br /&gt;
&lt;br /&gt;
* When you need the same string twice, try to reuse exactly the same string (with the same case) to minimize the number of strings.&lt;br /&gt;
* Do not mark as translatable a game element that does not have to be translated (ex: if the name of a monster on a card is &amp;quot;Zzzzz&amp;quot;, maybe there&#039;s no need to translate it).&lt;br /&gt;
* Words does not come in the same order in each language. Thus, when you have to translate a string with an argument, do not write something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;self::_(&amp;quot;First part of the string, &amp;quot;).$argument.&#039; &#039;.self::_(&amp;quot;second part of the string&amp;quot;)&amp;lt;/pre&amp;gt;&lt;br /&gt;
Write instead:&lt;br /&gt;
&amp;lt;pre&amp;gt;sprintf( self::_(&amp;quot;First part of the string, %s second part of the string&amp;quot;), $argument )&amp;lt;/pre&amp;gt;&lt;br /&gt;
(or the equivalent &amp;quot;dojo.string.substitute&amp;quot; in Javascript)&lt;br /&gt;
* When translators are going to translate your game, the most difficult task for them is to get the context of the string to be translated. The more the string is a short insignificant string, the more difficult is the task for them. As a rule of thumb, try to avoid insignificant short strings. You can also leave a comment on what is the context of the string in the translation program (English to English) if you are the developer of the game.&lt;br /&gt;
* The BGA translation policy is to be flexible on grammar... We prefer to write &amp;quot;player gets 1 coin(s)&amp;quot; than write two versions of the same string for plural and singular - it reduces the number of strings to translate.&lt;br /&gt;
* Instead of writing nice strings like &amp;quot;With the effect of ZZZ, player XXX gets a new YYY&amp;quot;, which is very difficult to translate, write strings like &amp;quot;ZZZ: XXX gets YYY&amp;quot;.&lt;br /&gt;
* Use present tense instead of past, i.e. &amp;quot;player gets wood&amp;quot; instead of &amp;quot;player got wood&amp;quot;&lt;br /&gt;
* Avoid using gender specific pronouns, i.e.  instead of &amp;quot;player returns card to *his* hand&amp;quot; use &amp;quot;player returns card to *their* hand&amp;quot; or just avoid using it, i.e. &amp;quot;player picks up the card&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== On client side (Javascript) ==&lt;br /&gt;
&lt;br /&gt;
On client side, things are quite simple: you just have to use the &amp;quot;_()&amp;quot; function for all strings you want to translate.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get a string in player&#039;s language:&lt;br /&gt;
var translated = _(&amp;quot;original english string&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// Get a string in player&#039;s language with parameter:&lt;br /&gt;
var translated = dojo.string.substitute( _(&amp;quot;You can pick ${p} cards and discard ${d}&amp;quot;), {&lt;br /&gt;
    p: 2,&lt;br /&gt;
    d: 4&lt;br /&gt;
} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; in Javascript strings to translate, you should never use &#039;\n&#039;, &#039;\t&#039; or such, as it will break the translation bundle and result in all the Javascript translation to fail. In any case, the strings will result in HTML code, and such character codes won&#039;t have any impact on the HTML rendering. You should use HTML markup instead.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ANOTHER WARNING:&#039;&#039;&#039; you cannot use this function _() in the javascript object constructor, but you can achieve the same if you use it the setup method&lt;br /&gt;
&lt;br /&gt;
== On server side (PHP) ==&lt;br /&gt;
&lt;br /&gt;
On PHP side, you can use 3 different functions to specify that a string must be translated.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;clienttranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function is &#039;&#039;&#039;transparent&#039;&#039;&#039;: it will return the original English string without any change. It&#039;s only purpose is to mark this string as &amp;quot;must be translated&amp;quot;, and to make sure the translated version of the string will be available on client side.&lt;br /&gt;
&lt;br /&gt;
In general, you use clienttranslate:&lt;br /&gt;
* On your states.inc.php, for field &amp;quot;description&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${card_name}: ${actplayer} must discard 4 identical energies&#039;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* On &amp;quot;material.inc.php&amp;quot;, when defining texts for game material that must be displayed on client side.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Air&amp;quot;), // Thus, we can use &amp;quot;_( card_name )&amp;quot; on Javascript side.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* When sending a notification with &amp;quot;notifyAllPlayers&amp;quot; or &amp;quot;notifyPlayer&amp;quot;, for the game log string and all game log arguments that need a translation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // A game log string with no argument:&lt;br /&gt;
     self::notifyAllPlayers( &#039;pickLibraryCards&#039;, clienttranslate(&amp;quot;Everyone draw cards from his library&amp;quot;), array() );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As a consequence there is no point passing variables to this function, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif=&amp;quot;foo&amp;quot;; self::notifyAllPlayers( &#039;log&#039;, clienttraslate(notif)); // BAD&lt;br /&gt;
    notif=clienttranslate(&amp;quot;foo&amp;quot;); self::notifyAllPlayers( &#039;log&#039;, notif); // GOOD&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Translating arguments is a little bit more complex. It is using the &amp;quot;i18n&amp;quot; special argument as below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 // In the following example, we translate the game log itself, but also the &amp;quot;card_name&amp;quot; argument:&lt;br /&gt;
&lt;br /&gt;
 self::notifyAllPlayers( &#039;winPoints&#039;, clienttranslate(&#039;${card_name}: ${player_name} gains ${points} point(s)&#039;), array(&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array( &#039;card_name&#039; ),     // &amp;lt;===== We specify here that &amp;quot;card_name&amp;quot; argument must be translated&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
                &#039;points&#039; =&amp;gt; $points,&lt;br /&gt;
                &#039;card_name&#039; =&amp;gt; $this-&amp;gt;card_types[8][&#039;name&#039;] // &amp;lt;==== Here, we provide original English string.&lt;br /&gt;
            ) ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To ensure the translation of the i18n argument will be made, clienttranslate must have been used somewhere, for instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;card_types = array(&lt;br /&gt;
     1 =&amp;gt; array(&lt;br /&gt;
        &#039;name&#039; =&amp;gt; clienttranslate(&amp;quot;Amulet of Air&amp;quot;),&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Pay attention when using &#039;i18n&#039; argument when translating argument for client : do NOT use same argument for both translation AND key code for client side action (like using &#039;card_name&#039; to move it on player board as described in the example). It&#039;s pretty obvious in the example, but it can be very tricky when translation is made at the end of the development (which is often the case). Use explicit argument name like &#039;card_name_translated&#039; by example.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; you should NEVER use concatenation with clienttranslate, as it would result in a different string to translate at runtime than the one retrieved statically in the translation system, and so translation would not be applied. If you need to compose a string, use substitution and the i18n parameter (but you also have to pay attention not to compose sentences in a way that is dependent upon the English language specific syntax, or it may be impossible to translate correctly in another language: sometimes, you need multiple full sentences rather than relying on substitution).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;self::_( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function returns a string translated in the language of CURRENT user (i.e. player who send the request to the server) (be careful, this is NOT the active player).&lt;br /&gt;
&lt;br /&gt;
Most of the time, you don&#039;t need to translate strings on server side, except on the following 3 situations:&lt;br /&gt;
* When throwing an exception because the player did a forbidden move.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// This will display a translatable red message to the player that just did some wrong action:&lt;br /&gt;
throw new BgaUserException( self::_(&#039;You must choose 3 cards&#039;) );&lt;br /&gt;
&lt;br /&gt;
// ... notice the use of BgaUserException that signals that this exception is &amp;quot;expected&amp;quot;. In theory, all exception that are expected should be translated.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* In &amp;quot;yourgame.view.php&amp;quot;, when creating the labels for the game interface used in your template (.tpl) file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;tpl[&#039;CARDS_FOR_YEAR_2&#039;] = self::_(&amp;quot;Your cards for year II&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Eventually, in your material.inc.php, if for example you need to use some string elements in your exceptions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// In material.inc.php, $this-&amp;gt;energies[n][&#039;nametr&#039;] has been created with the self::_() method. Now we can do this:&lt;br /&gt;
throw new BgaUserException( self::_(&amp;quot;To execute this action you need more: &amp;quot;).&#039; &#039;.$this-&amp;gt;energies[$resource_id][&#039;nametr&#039;] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Eventually, in your &amp;quot;getAllDatas&amp;quot; PHP method, as the data return by this method is used only by current user.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;totranslate( &amp;quot;my string to translate&amp;quot; ):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function works exactly like &#039;clienttranslate&#039;, except it tells BGA that the string is not needed on client side.&lt;br /&gt;
&lt;br /&gt;
You should not use this function, except on the following cases:&lt;br /&gt;
* Statistics name in stats.inc.php&lt;br /&gt;
* Option names and option values name in gameoptions.inc.php&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl&amp;diff=5993</id>
		<title>Game layout: view and template: yourgamename.view.php and yourgamename yourgamename.tpl</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl&amp;diff=5993"/>
		<updated>2020-10-27T19:10:04Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* Variables */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
These 2 files work together to provide the HTML layout of your game.&lt;br /&gt;
&lt;br /&gt;
Using these 2 files, you specify what HTML is rendered in your game client interface.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;yourgame.tpl&amp;gt;, you can directly write raw HTML that will be displayed by the browser.&lt;br /&gt;
&lt;br /&gt;
Example: extract of &amp;quot;hearts_hearts.tpl&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;myhand_wrap&amp;quot; class=&amp;quot;whiteblock&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3&amp;gt;{MY_HAND}&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WARNING ==&lt;br /&gt;
&lt;br /&gt;
Your view and your template are supposed to generate only the BASE layout of the game&lt;br /&gt;
&lt;br /&gt;
You shouldn&#039;t try to setup the current game situation in the view: this is the role of your Javascript code. Why? Because you&#039;ll have to write Javascript code to put game elements in place anyway, and you don&#039;t want to write it twice :)&lt;br /&gt;
&lt;br /&gt;
Example of things to generate in your view:&lt;br /&gt;
* The overall layout of your game interface (what is displayed where).&lt;br /&gt;
* The board and fixed elements on the board (ex: places for cards, squares, ...).&lt;br /&gt;
&lt;br /&gt;
Example of things that shouldn&#039;t be generate by your view:&lt;br /&gt;
* Game elements that come and go from the game area.&lt;br /&gt;
* Game elements that normally hidden from players (other players cards, cards in the deck).&lt;br /&gt;
&lt;br /&gt;
== phplib template system ==&lt;br /&gt;
&lt;br /&gt;
BGA is using the phplib template system, used for example in PHPbb forums.&lt;br /&gt;
&lt;br /&gt;
More details about how to use phplib template system here:&lt;br /&gt;
https://web.archive.org/web/20170506065401/http://www.phpbuilder.com:80/columns/david20000512.php3&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
&lt;br /&gt;
In your template (&amp;quot;tpl&amp;quot;) file, you can use variables. Then in your view (&amp;quot;.view.php&amp;quot;) file, you fill these variables with value.&lt;br /&gt;
&lt;br /&gt;
In the example above, &amp;quot;{MY_HAND}&amp;quot; is a variable. As you can see, a variable is uppercase characters border by &amp;quot;{&amp;quot; and &amp;quot;}&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
To give a value to this variable in your view.php:&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   // Display a translated version of &amp;quot;My hand&amp;quot; at the place of the variable in the template&lt;br /&gt;
   $this-&amp;gt;tpl[&#039;MY_HAND&#039;] = self::_(&amp;quot;My hand&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   // Display some raw HTML material at the place of the variable&lt;br /&gt;
   $this-&amp;gt;tpl[&#039;MY_HAND&#039;] = self::raw( &amp;quot;&amp;lt;div class=&#039;myhand_icon&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
WARNING: do not use a variable called {id} as it will interfere with action buttons.&lt;br /&gt;
&lt;br /&gt;
WARNING: do not use a variable called {LB_[whatever]} as any variable starting with LB_ will interfere with the translation system.&lt;br /&gt;
&lt;br /&gt;
== Blocks ==&lt;br /&gt;
&lt;br /&gt;
Using &amp;quot;blocks&amp;quot;, you can repeat a piece of HTML from your template several time.&lt;br /&gt;
&lt;br /&gt;
You should use &amp;quot;blocks&amp;quot; whenever you have a block of HTML that must be repeated many times. For example, for &#039;&#039;Reversi&#039;&#039;, we have to generate 64 (8x8) squares:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(in reversi_reversi.tpl)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;board&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- BEGIN square --&amp;gt;&lt;br /&gt;
        &amp;lt;div id=&amp;quot;square_{X}_{Y}&amp;quot; class=&amp;quot;square&amp;quot; style=&amp;quot;left: {LEFT}px; top: {TOP}px;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;!-- END square --&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;div id=&amp;quot;discs&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(in reversi.view.php)&lt;br /&gt;
&lt;br /&gt;
 $this-&amp;gt;page-&amp;gt;begin_block( &amp;quot;reversi_reversi&amp;quot;, &amp;quot;square&amp;quot; );&lt;br /&gt;
        &lt;br /&gt;
 $hor_scale = 64.8;&lt;br /&gt;
 $ver_scale = 64.4;&lt;br /&gt;
 for( $x=1; $x&amp;lt;=8; $x++ )&lt;br /&gt;
 {&lt;br /&gt;
    for( $y=1; $y&amp;lt;=8; $y++ )&lt;br /&gt;
    {&lt;br /&gt;
       $this-&amp;gt;page-&amp;gt;insert_block( &amp;quot;square&amp;quot;, array(&lt;br /&gt;
         &#039;X&#039; =&amp;gt; $x,&lt;br /&gt;
         &#039;Y&#039; =&amp;gt; $y,&lt;br /&gt;
         &#039;LEFT&#039; =&amp;gt; round( ($x-1)*$hor_scale+10 ),&lt;br /&gt;
         &#039;TOP&#039; =&amp;gt; round( ($y-1)*$ver_scale+7 )&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;
Explanations:&lt;br /&gt;
* You specify a block in your template file, using &amp;quot;BEGIN&amp;quot; and &amp;quot;END&amp;quot; keywords. In the example above, we are creating a block named &amp;quot;square&amp;quot;.&lt;br /&gt;
* In your view, you declare your block using &amp;quot;begin_block&amp;quot; method.&lt;br /&gt;
* Then, you can insert as many block as you want to, using &amp;quot;insert_block&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
The insert_block method takes 2 parameters:&lt;br /&gt;
* the name of the block to insert.&lt;br /&gt;
* an associative array you can use to assign values to template variables of this block. In the example above, there are 4 parameters in the block (X, Y, LEFT and TOP).&lt;br /&gt;
&lt;br /&gt;
== Nested blocks ==&lt;br /&gt;
&lt;br /&gt;
You can use nested blocks. In the example below, we are going to add a mini-board for each player of the game, with 4 card places on each of it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(In template file)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- BEGIN player --&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;miniboard&amp;quot; id=&amp;quot;miniboard_{PLAYER_ID}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;card_places&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- BEGIN card_place --&amp;gt;&lt;br /&gt;
            &amp;lt;div id=&amp;quot;card_place_{PLAYER_ID}_{PLACE_ID}&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;!-- END card_place --&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;!-- END player --&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
(In view file)&lt;br /&gt;
&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;begin_block( &amp;quot;mygame_mygame.tpl&amp;quot;, &amp;quot;card_place&amp;quot; ); // Nested block must be declared first&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;begin_block( &amp;quot;mygame_mygame.tpl&amp;quot;, &amp;quot;player&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
foreach( $players as $player_id =&amp;gt; $player )&lt;br /&gt;
{&lt;br /&gt;
    // Important: nested block must be reset here, otherwise the second player miniboard will&lt;br /&gt;
    //  have 8 card_place, the third will have 12 card_place, and so one...&lt;br /&gt;
    $this-&amp;gt;page-&amp;gt;reset_subblocks( &#039;card_place&#039; ); &lt;br /&gt;
&lt;br /&gt;
    for( $i=1; $i&amp;lt;=4; $i++ )&lt;br /&gt;
    {&lt;br /&gt;
       $this-&amp;gt;page-&amp;gt;insert_block( &amp;quot;card_place&amp;quot;, array( &lt;br /&gt;
             &#039;PLAYER_ID&#039; =&amp;gt; $player_id,&lt;br /&gt;
             &#039;PLACE_ID&#039; =&amp;gt; $i&lt;br /&gt;
          )&lt;br /&gt;
       );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;page-&amp;gt;insert_block( &#039;player&#039;, array( &#039;PLAYER_ID&#039; =&amp;gt; $player_id );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Javascript templates ==&lt;br /&gt;
&lt;br /&gt;
For game elements that come and go from the game area, we suggest you to define a Javascript template.&lt;br /&gt;
&lt;br /&gt;
A Javascript template is defined in your template file like this:&lt;br /&gt;
&lt;br /&gt;
(Reversi Token from Reversi example):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Templates&lt;br /&gt;
&lt;br /&gt;
var jstpl_disc=&#039;&amp;lt;div class=&amp;quot;disc disccolor_${color}&amp;quot; id=&amp;quot;disc_${xy}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/script&amp;gt;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: a section for javascript templates is already available at the end of your template skeleton file.&lt;br /&gt;
&lt;br /&gt;
Then, you can use this javascript template to insert this piece of HTML in your game interface, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.place( this.format_block( &#039;jstpl_disc&#039;, {&lt;br /&gt;
           xy: x+&#039;&#039;+y,&lt;br /&gt;
           color: color&lt;br /&gt;
    } ) , &#039;discs&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
WARNING: always use lowercase for substitution variables in your Javascript templates, in order to avoid collision with phplib template variables (in particular, do not use ${ID}).&lt;br /&gt;
&lt;br /&gt;
Note that &#039;&#039;&#039;you must translate&#039;&#039;&#039; any text arguments passed to &#039;&#039;this.format_block()&#039;&#039; that will be rendered on the screen, for example [[Translations#On_client_side_.28Javascript.29|using &amp;quot;_()&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
== How to access game information from .view.php? ==&lt;br /&gt;
&lt;br /&gt;
From your .view.php, you can access the following:&lt;br /&gt;
&lt;br /&gt;
=== Access current player id===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  global $g_user;&lt;br /&gt;
  $current_player_id = $g_user-&amp;gt;get_id();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Access game object ===&lt;br /&gt;
&lt;br /&gt;
In your view file, &amp;quot;$this-&amp;gt;game&amp;quot; contains an instance of your main game class.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   // Access to some game elements description described in your &amp;quot;material.inc.php&amp;quot;:&lt;br /&gt;
   $my_cards_types = $this-&amp;gt;game-&amp;gt;card_types;&lt;br /&gt;
&lt;br /&gt;
   // Access to any (public) method defined in my .game.php file:&lt;br /&gt;
   $result = $this-&amp;gt;game-&amp;gt;myMethod();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tips: displaying a nice button ==&lt;br /&gt;
&lt;br /&gt;
From time to time, you need to display a standard button in your interface. BGA framework provides you a standard button that you can use directly in your interface:&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;
Note: To see it in action, check for example a Coloretto game&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl&amp;diff=5992</id>
		<title>Game layout: view and template: yourgamename.view.php and yourgamename yourgamename.tpl</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl&amp;diff=5992"/>
		<updated>2020-10-27T19:09:50Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: Add a warning on variable name.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
These 2 files work together to provide the HTML layout of your game.&lt;br /&gt;
&lt;br /&gt;
Using these 2 files, you specify what HTML is rendered in your game client interface.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;yourgame.tpl&amp;gt;, you can directly write raw HTML that will be displayed by the browser.&lt;br /&gt;
&lt;br /&gt;
Example: extract of &amp;quot;hearts_hearts.tpl&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;myhand_wrap&amp;quot; class=&amp;quot;whiteblock&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3&amp;gt;{MY_HAND}&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== WARNING ==&lt;br /&gt;
&lt;br /&gt;
Your view and your template are supposed to generate only the BASE layout of the game&lt;br /&gt;
&lt;br /&gt;
You shouldn&#039;t try to setup the current game situation in the view: this is the role of your Javascript code. Why? Because you&#039;ll have to write Javascript code to put game elements in place anyway, and you don&#039;t want to write it twice :)&lt;br /&gt;
&lt;br /&gt;
Example of things to generate in your view:&lt;br /&gt;
* The overall layout of your game interface (what is displayed where).&lt;br /&gt;
* The board and fixed elements on the board (ex: places for cards, squares, ...).&lt;br /&gt;
&lt;br /&gt;
Example of things that shouldn&#039;t be generate by your view:&lt;br /&gt;
* Game elements that come and go from the game area.&lt;br /&gt;
* Game elements that normally hidden from players (other players cards, cards in the deck).&lt;br /&gt;
&lt;br /&gt;
== phplib template system ==&lt;br /&gt;
&lt;br /&gt;
BGA is using the phplib template system, used for example in PHPbb forums.&lt;br /&gt;
&lt;br /&gt;
More details about how to use phplib template system here:&lt;br /&gt;
https://web.archive.org/web/20170506065401/http://www.phpbuilder.com:80/columns/david20000512.php3&lt;br /&gt;
&lt;br /&gt;
== Variables ==&lt;br /&gt;
&lt;br /&gt;
In your template (&amp;quot;tpl&amp;quot;) file, you can use variables. Then in your view (&amp;quot;.view.php&amp;quot;) file, you fill these variables with value.&lt;br /&gt;
&lt;br /&gt;
In the example above, &amp;quot;{MY_HAND}&amp;quot; is a variable. As you can see, a variable is uppercase characters border by &amp;quot;{&amp;quot; and &amp;quot;}&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
To give a value to this variable in your view.php:&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   // Display a translated version of &amp;quot;My hand&amp;quot; at the place of the variable in the template&lt;br /&gt;
   $this-&amp;gt;tpl[&#039;MY_HAND&#039;] = self::_(&amp;quot;My hand&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
   // Display some raw HTML material at the place of the variable&lt;br /&gt;
   $this-&amp;gt;tpl[&#039;MY_HAND&#039;] = self::raw( &amp;quot;&amp;lt;div class=&#039;myhand_icon&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
WARNING: do not use a variable called {id} as it will interfere with action buttons.&lt;br /&gt;
WARNING: do not use a variable called {LB_[whatever]} as any variable starting with LB_ will interfere with the translation system.&lt;br /&gt;
&lt;br /&gt;
== Blocks ==&lt;br /&gt;
&lt;br /&gt;
Using &amp;quot;blocks&amp;quot;, you can repeat a piece of HTML from your template several time.&lt;br /&gt;
&lt;br /&gt;
You should use &amp;quot;blocks&amp;quot; whenever you have a block of HTML that must be repeated many times. For example, for &#039;&#039;Reversi&#039;&#039;, we have to generate 64 (8x8) squares:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(in reversi_reversi.tpl)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;board&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;!-- BEGIN square --&amp;gt;&lt;br /&gt;
        &amp;lt;div id=&amp;quot;square_{X}_{Y}&amp;quot; class=&amp;quot;square&amp;quot; style=&amp;quot;left: {LEFT}px; top: {TOP}px;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;!-- END square --&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;div id=&amp;quot;discs&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(in reversi.view.php)&lt;br /&gt;
&lt;br /&gt;
 $this-&amp;gt;page-&amp;gt;begin_block( &amp;quot;reversi_reversi&amp;quot;, &amp;quot;square&amp;quot; );&lt;br /&gt;
        &lt;br /&gt;
 $hor_scale = 64.8;&lt;br /&gt;
 $ver_scale = 64.4;&lt;br /&gt;
 for( $x=1; $x&amp;lt;=8; $x++ )&lt;br /&gt;
 {&lt;br /&gt;
    for( $y=1; $y&amp;lt;=8; $y++ )&lt;br /&gt;
    {&lt;br /&gt;
       $this-&amp;gt;page-&amp;gt;insert_block( &amp;quot;square&amp;quot;, array(&lt;br /&gt;
         &#039;X&#039; =&amp;gt; $x,&lt;br /&gt;
         &#039;Y&#039; =&amp;gt; $y,&lt;br /&gt;
         &#039;LEFT&#039; =&amp;gt; round( ($x-1)*$hor_scale+10 ),&lt;br /&gt;
         &#039;TOP&#039; =&amp;gt; round( ($y-1)*$ver_scale+7 )&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;
Explanations:&lt;br /&gt;
* You specify a block in your template file, using &amp;quot;BEGIN&amp;quot; and &amp;quot;END&amp;quot; keywords. In the example above, we are creating a block named &amp;quot;square&amp;quot;.&lt;br /&gt;
* In your view, you declare your block using &amp;quot;begin_block&amp;quot; method.&lt;br /&gt;
* Then, you can insert as many block as you want to, using &amp;quot;insert_block&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
The insert_block method takes 2 parameters:&lt;br /&gt;
* the name of the block to insert.&lt;br /&gt;
* an associative array you can use to assign values to template variables of this block. In the example above, there are 4 parameters in the block (X, Y, LEFT and TOP).&lt;br /&gt;
&lt;br /&gt;
== Nested blocks ==&lt;br /&gt;
&lt;br /&gt;
You can use nested blocks. In the example below, we are going to add a mini-board for each player of the game, with 4 card places on each of it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(In template file)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- BEGIN player --&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;miniboard&amp;quot; id=&amp;quot;miniboard_{PLAYER_ID}&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;div class=&amp;quot;card_places&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;!-- BEGIN card_place --&amp;gt;&lt;br /&gt;
            &amp;lt;div id=&amp;quot;card_place_{PLAYER_ID}_{PLACE_ID}&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;!-- END card_place --&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;!-- END player --&amp;gt;&lt;br /&gt;
  &lt;br /&gt;
(In view file)&lt;br /&gt;
&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;begin_block( &amp;quot;mygame_mygame.tpl&amp;quot;, &amp;quot;card_place&amp;quot; ); // Nested block must be declared first&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;begin_block( &amp;quot;mygame_mygame.tpl&amp;quot;, &amp;quot;player&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
foreach( $players as $player_id =&amp;gt; $player )&lt;br /&gt;
{&lt;br /&gt;
    // Important: nested block must be reset here, otherwise the second player miniboard will&lt;br /&gt;
    //  have 8 card_place, the third will have 12 card_place, and so one...&lt;br /&gt;
    $this-&amp;gt;page-&amp;gt;reset_subblocks( &#039;card_place&#039; ); &lt;br /&gt;
&lt;br /&gt;
    for( $i=1; $i&amp;lt;=4; $i++ )&lt;br /&gt;
    {&lt;br /&gt;
       $this-&amp;gt;page-&amp;gt;insert_block( &amp;quot;card_place&amp;quot;, array( &lt;br /&gt;
             &#039;PLAYER_ID&#039; =&amp;gt; $player_id,&lt;br /&gt;
             &#039;PLACE_ID&#039; =&amp;gt; $i&lt;br /&gt;
          )&lt;br /&gt;
       );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;page-&amp;gt;insert_block( &#039;player&#039;, array( &#039;PLAYER_ID&#039; =&amp;gt; $player_id );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Javascript templates ==&lt;br /&gt;
&lt;br /&gt;
For game elements that come and go from the game area, we suggest you to define a Javascript template.&lt;br /&gt;
&lt;br /&gt;
A Javascript template is defined in your template file like this:&lt;br /&gt;
&lt;br /&gt;
(Reversi Token from Reversi example):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Templates&lt;br /&gt;
&lt;br /&gt;
var jstpl_disc=&#039;&amp;lt;div class=&amp;quot;disc disccolor_${color}&amp;quot; id=&amp;quot;disc_${xy}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/script&amp;gt;  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: a section for javascript templates is already available at the end of your template skeleton file.&lt;br /&gt;
&lt;br /&gt;
Then, you can use this javascript template to insert this piece of HTML in your game interface, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.place( this.format_block( &#039;jstpl_disc&#039;, {&lt;br /&gt;
           xy: x+&#039;&#039;+y,&lt;br /&gt;
           color: color&lt;br /&gt;
    } ) , &#039;discs&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
WARNING: always use lowercase for substitution variables in your Javascript templates, in order to avoid collision with phplib template variables (in particular, do not use ${ID}).&lt;br /&gt;
&lt;br /&gt;
Note that &#039;&#039;&#039;you must translate&#039;&#039;&#039; any text arguments passed to &#039;&#039;this.format_block()&#039;&#039; that will be rendered on the screen, for example [[Translations#On_client_side_.28Javascript.29|using &amp;quot;_()&amp;quot;]].&lt;br /&gt;
&lt;br /&gt;
== How to access game information from .view.php? ==&lt;br /&gt;
&lt;br /&gt;
From your .view.php, you can access the following:&lt;br /&gt;
&lt;br /&gt;
=== Access current player id===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  global $g_user;&lt;br /&gt;
  $current_player_id = $g_user-&amp;gt;get_id();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Access game object ===&lt;br /&gt;
&lt;br /&gt;
In your view file, &amp;quot;$this-&amp;gt;game&amp;quot; contains an instance of your main game class.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
   // Access to some game elements description described in your &amp;quot;material.inc.php&amp;quot;:&lt;br /&gt;
   $my_cards_types = $this-&amp;gt;game-&amp;gt;card_types;&lt;br /&gt;
&lt;br /&gt;
   // Access to any (public) method defined in my .game.php file:&lt;br /&gt;
   $result = $this-&amp;gt;game-&amp;gt;myMethod();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Tips: displaying a nice button ==&lt;br /&gt;
&lt;br /&gt;
From time to time, you need to display a standard button in your interface. BGA framework provides you a standard button that you can use directly in your interface:&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;
Note: To see it in action, check for example a Coloretto game&lt;/div&gt;</summary>
		<author><name>Inaofr</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=4308</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=4308"/>
		<updated>2020-05-07T21:18:05Z</updated>

		<summary type="html">&lt;p&gt;Inaofr: /* Multiactivate 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;
* EmptyGame (constructor): where you define global variables.&lt;br /&gt;
* setupNewGame: initial setup of the game.&lt;br /&gt;
* getAllDatas: where you retrieve all game data during a complete reload of the game.&lt;br /&gt;
* getGameProgression: where you compute the game progression indicator.&lt;br /&gt;
* Utility functions: your utility functions.&lt;br /&gt;
* Player actions: the entry points for players actions. &lt;br /&gt;
* Game state arguments: methods to return additional data on specific game states ([http://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php#args more info here]).&lt;br /&gt;
* Game state actions: the logic to run when entering a new game state ([http://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php#action more info here]).&lt;br /&gt;
* zombieTurn: what to do it&#039;s the turn of a zombie player.&lt;br /&gt;
&lt;br /&gt;
== Accessing player information ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: In the following methods, be mindful of the difference between the &amp;quot;active&amp;quot; player and the &amp;quot;current&amp;quot; player. The &#039;&#039;&#039;active&#039;&#039;&#039; player is the player whose turn it is - not necessarily the player who sent a request! The &#039;&#039;&#039;current&#039;&#039;&#039; player is the player who sent the request and will see the results returned by your methods: not necessarily the player whose turn it is!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; getPlayersNumber()&lt;br /&gt;
: Returns the number of players playing at the table&lt;br /&gt;
: Note: doesn&#039;t work in setupNewGame (use count($players) instead).&lt;br /&gt;
&lt;br /&gt;
; getActivePlayerId()&lt;br /&gt;
: Get the &amp;quot;active_player&amp;quot;, whatever what is the current state type.&lt;br /&gt;
: Note: it does NOT mean that this player is active right now, because state type could be &amp;quot;game&amp;quot; or &amp;quot;multiplayer&amp;quot;&lt;br /&gt;
: Note: avoid using this method in a &amp;quot;multiplayer&amp;quot; state because it does not mean anything.&lt;br /&gt;
&lt;br /&gt;
; getActivePlayerName()&lt;br /&gt;
: Get the &amp;quot;active_player&amp;quot; name&lt;br /&gt;
: Note: avoid using this method in a &amp;quot;multiplayer&amp;quot; state because it does not mean anything.&lt;br /&gt;
&lt;br /&gt;
; loadPlayersBasicInfos()&lt;br /&gt;
: Get an associative array with generic data about players (ie: not game specific data).&lt;br /&gt;
: The key of the associative array is the player id. The returned table is cached, so ok to call multiple times without performance concerns.&lt;br /&gt;
: The content of each value is:&lt;br /&gt;
: * player_name - the name of the player&lt;br /&gt;
: * player_color (ex: ff0000) - the color code of the player&lt;br /&gt;
: * player_no - the position of the player at the start of the game in natural table order, i.e. 1,2,3&lt;br /&gt;
&lt;br /&gt;
; getCurrentPlayerId()&lt;br /&gt;
: Get the &amp;quot;current_player&amp;quot;. The current player is the one from which the action originated (the one who sent the request).&lt;br /&gt;
: &#039;&#039;&#039;Be careful&#039;&#039;&#039;: This is not necessarily the active player!&lt;br /&gt;
: In general, you shouldn&#039;t use this method, unless you are in &amp;quot;multiplayer&amp;quot; state.&lt;br /&gt;
: &#039;&#039;&#039;Very important&#039;&#039;&#039;: in your setupNewGame and zombieTurn function, you must never use getCurrentPlayerId() or getCurrentPlayerName(), otherwise it will fail with a &amp;quot;Not logged&amp;quot; error message (these actions are triggered from the main site and propagated to the gameserver from a server, not from a browser. As a consequence, there is no current player associated to these actions).&lt;br /&gt;
&lt;br /&gt;
; getCurrentPlayerName()&lt;br /&gt;
: Get the &amp;quot;current_player&amp;quot; name&lt;br /&gt;
: Be careful using this method (see above).&lt;br /&gt;
&lt;br /&gt;
; getCurrentPlayerColor()&lt;br /&gt;
: Get the &amp;quot;current_player&amp;quot; color&lt;br /&gt;
: Be careful using this method (see above).&lt;br /&gt;
&lt;br /&gt;
; isCurrentPlayerZombie()&lt;br /&gt;
: Check the &amp;quot;current_player&amp;quot; zombie status. If true, player is zombie, i.e. left or was kicked out of the game.&lt;br /&gt;
&lt;br /&gt;
== 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. 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.&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 query on the database.&lt;br /&gt;
: You should use it for UPDATE/DELETE/REPLACE 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 if 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;
: Idem than previous one, but raise an exception if the collection is empty&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;
: Idem than 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 if the same than &amp;quot;getCollectionFromDB&amp;quot; except that the result is a simple array (and not an associative array).&lt;br /&gt;
: The result can be empty.&lt;br /&gt;
: If you specified $bUniqueValue=true and if your SQL query request 1 field, the method returns directly an array of values.&lt;br /&gt;
&lt;br /&gt;
Example 1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
self::getObjectListFromDB( &amp;quot;SELECT player_id id, player_name name, player_score score FROM player&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
array(&lt;br /&gt;
 array( &#039;id&#039;=&amp;gt;1234, &#039;name&#039;=&amp;gt;&#039;myuser0&#039;, &#039;score&#039;=&amp;gt;1 ),&lt;br /&gt;
 array( &#039;id&#039;=&amp;gt;1235, &#039;name&#039;=&amp;gt;&#039;myuser1&#039;, &#039;score&#039;=&amp;gt;0 )&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example 2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
self::getObjectListFromDB( &amp;quot;SELECT player_name name FROM player&amp;quot;, true );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
array(&lt;br /&gt;
 &#039;myuser0&#039;,&lt;br /&gt;
 &#039;myuser1&#039;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; getDoubleKeyCollectionFromDB( $sql, $bSingleValue=false )&lt;br /&gt;
: Return an associative array of associative array, from a SQL SELECT query.&lt;br /&gt;
: First array level correspond to first column specified in SQL query.&lt;br /&gt;
: Second array level correspond to second column specified in SQL query.&lt;br /&gt;
: If bSingleValue = true, keep only third column on result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; DbGetLastId()&lt;br /&gt;
: Return the PRIMARY key of the last inserted row (see PHP mysql_insert_id function).&lt;br /&gt;
&lt;br /&gt;
; DbAffectedRow()&lt;br /&gt;
: Return the number of row affected by the last operation&lt;br /&gt;
&lt;br /&gt;
; escapeStringForDB( $string )&lt;br /&gt;
: You must use this function on every string type data in your database that contains unsafe data.&lt;br /&gt;
: (unsafe = can be modified by a player).&lt;br /&gt;
: This method makes sure that no SQL injection will be done through the string used.&lt;br /&gt;
: Note: if you using standard types in ajax actions, like AT_alphanum it is sanitized before arrival,&lt;br /&gt;
: this is only needed if you manage to get unchecked string, like in the games where user has to enter text as a response.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: see Editing [[Game database model: dbmodel.sql]] to know how to define your database model.&lt;br /&gt;
&lt;br /&gt;
== Use globals ==&lt;br /&gt;
&lt;br /&gt;
Sometimes, you want a single global integer value for your game, and you don&#039;t want to create a DB table specifically for it.&lt;br /&gt;
&lt;br /&gt;
You can do this with the BGA framework &amp;quot;global.&amp;quot; Your value will be stored in the &amp;quot;global&amp;quot; table in the database, and you can access it with simple methods.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;initGameStateLabels&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method should be located at the beginning of &#039;&#039;yourgamename.php.&#039;&#039; This is where you define the globals used in your game logic, by assigning them IDs.&lt;br /&gt;
&lt;br /&gt;
You can define up to 79 globals, with IDs from 10 to 89 (inclusive). You must &#039;&#039;&#039;not&#039;&#039;&#039; use globals outside this range, as those values are used by other components of the framework.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        self::initGameStateLabels( array( &lt;br /&gt;
                &amp;quot;my_first_global_variable&amp;quot; =&amp;gt; 10,&lt;br /&gt;
                &amp;quot;my_second_global_variable&amp;quot; =&amp;gt; 11&lt;br /&gt;
        ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setGameStateInitialValue( $value_label, $value_value )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Initialize your global value. Must be called before any use of your global, so you should call this method from your &amp;quot;setupNewGame&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getGameStateValue( $value_label )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Retrieve the current value of a global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setGameStateValue( $value_label, $value_value )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Set the current value of a global.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;incGameStateValue( $value_label, $increment )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Increment the current value of a global. If increment is negative, decrement the value of the global.&lt;br /&gt;
&lt;br /&gt;
Return the final value of the global.&lt;br /&gt;
&lt;br /&gt;
== Game states and active players ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Activate player handling ===&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;activeNextPlayer()&lt;br /&gt;
: Make the next player active in the natural player order.&lt;br /&gt;
: Note: you CANT 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 CANT 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 CANT 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;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;
=== Multiactivate 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 (triggers onUpdateActionButtons).&lt;br /&gt;
: Usually, you use this method at the beginning (ex: &amp;quot;st&amp;quot; action method) of a multiplayer game state when all players have to do some action.&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 who&#039;s 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.&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;
&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;
; $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;
=== 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 an action is valid for the current game state, and optionally, throw an exception if it isn&#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.&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-&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.&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;
== Notify players ==&lt;br /&gt;
&lt;br /&gt;
To understand notifications, please read [http://www.slideshare.net/boardgamearena/the-bga-framework-at-a-glance The BGA Framework at a glance] first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Notifications are sent at the very end of the request, when it ends normally. It means that if you throw an exception for any reason (ex: move not allowed), no notifications will be sent to players.&lt;br /&gt;
Notifications sent between the game start (setupNewGame) and the end of the &amp;quot;action&amp;quot; method of the first active state will never reach their destination.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;notifyAllPlayers( $notification_type, $notification_log, $notification_args )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Send a notification to all players of the game.&lt;br /&gt;
&lt;br /&gt;
* notification_type:&lt;br /&gt;
A string that defines the type of your notification.&lt;br /&gt;
&lt;br /&gt;
Your game interface Javascript logic will use this to know what is the type of the received notification (and to trigger the corresponding method).&lt;br /&gt;
&lt;br /&gt;
* notification_log:&lt;br /&gt;
A string that defines what is to be displayed in the game log.&lt;br /&gt;
&lt;br /&gt;
You can use an empty string here (&amp;quot;&amp;quot;). In this case, nothing is displayed in the game log.&lt;br /&gt;
&lt;br /&gt;
If you define a real string here, you should use &amp;quot;clienttranslate&amp;quot; method to make sure it can be translate.&lt;br /&gt;
&lt;br /&gt;
You can use arguments in your notification_log strings, that refers to values defines in the &amp;quot;notification_args&amp;quot; argument (see below). &lt;br /&gt;
Note: Make sure you only use single quotes (&#039;), otherwise PHP will try to interpolate the variable and will ignore the values in the args array.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* notification_args:&lt;br /&gt;
The arguments of your notifications, as an associative array.&lt;br /&gt;
&lt;br /&gt;
This array will be transmitted to the game interface logic, in order the game interface can be updated.&lt;br /&gt;
&lt;br /&gt;
Complete notifyAllPlayers example (from &amp;quot;Reversi&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
self::notifyAllPlayers( &amp;quot;playDisc&amp;quot;, clienttranslate( &#039;${player_name} plays a disc and turns over ${returned_nbr} disc(s)&#039; ),&lt;br /&gt;
 array(&lt;br /&gt;
        &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
        &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
        &#039;returned_nbr&#039; =&amp;gt; count( $turnedOverDiscs ),&lt;br /&gt;
        &#039;x&#039; =&amp;gt; $x,&lt;br /&gt;
        &#039;y&#039; =&amp;gt; $y&lt;br /&gt;
     ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see in the example above the use of the &amp;quot;clienttranslate&amp;quot; method, and the use of 2 arguments &amp;quot;player_name&amp;quot; and &amp;quot;returned_nbr&amp;quot; in the notification log.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: NO private data must be sent with this method, as a cheater could see it even it is not used explicitly by the game interface logic. If you want to send private information to a player, please use notifyPlayer below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: this array is serialized to be sent to the browsers, and will be saved with the notification to be able to replay the game later. If it is too big, it can make notifications slower / less reliable, and replay archives very big (to the point of failing). So as a general rule, you should send only the minimum of information necessary to update the client interface with no overhead in order to keep the notifications as light as possible.&lt;br /&gt;
&lt;br /&gt;
Note: you CAN use some HTML inside your notification log, however it not recommended for many reasons:&lt;br /&gt;
* Its bad architecture, ui elements leak into server now you have to manage ui in many places&lt;br /&gt;
* If you decided to change something in ui in future version, old games reply and tutorials may not work, since they use stored notifications&lt;br /&gt;
* When you read log preview for old games its unreadable (this is log before you enter the game reply, useful for troubleshooting or game analysis)&lt;br /&gt;
* Its more data to transfer and store in db&lt;br /&gt;
* Its nightmare for translators, at least don&#039;t put HTML tags inside the &amp;quot;clienttranslate&amp;quot; method. You can use a notification argument instead, and provide your HTML through this argument.&lt;br /&gt;
&lt;br /&gt;
If you still want to have pretty pictures in the log check this [[BGA_Studio_Cookbook#Inject_images_and_styled_html_in_the_log]].&lt;br /&gt;
&lt;br /&gt;
If your notification contains some phrases that build programmatically you may need to use recursive notifications. In this case the argument can be not only the string but&lt;br /&gt;
an array itself, which contains &#039;log&#039; and &#039;args&#039;, i.e.&lt;br /&gt;
&lt;br /&gt;
  $this-&amp;gt;notifyAllPlayers(&#039;playerLog&#039;,clienttranslate(&#039;Game moves ${token_name_rec}&#039;),&lt;br /&gt;
                   [&#039;token_name_rec&#039;=&amp;gt;[&#039;log&#039;=&amp;gt;&#039;${token_name} #${token_number}&#039;,&lt;br /&gt;
                                       &#039;args&#039;=&amp;gt; [&#039;token_name&#039;=&amp;gt;clienttranslate(&#039;Boo&#039;), &#039;token_number&#039;=&amp;gt;$number, &#039;i18n&#039;=&amp;gt;[&#039;token_name&#039;] ]&lt;br /&gt;
                                      ]&lt;br /&gt;
                   ]);&lt;br /&gt;
&lt;br /&gt;
&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&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;
=== Dices 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; (included), 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;
At now, bga_rand is based on the PHP function &amp;quot;random_int&amp;quot;, which ensure 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 ensure you 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;
At now, the Deck component shuffle method is based on PHP &amp;quot;shuffle&amp;quot; method, which has a quite good randomness (even it is not as good as bga_rand). In consequence, we accept other shuffling methods during reviews, as long as their 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; statistics 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 defines 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;
This method must be called for each statistics of your game, in your setupNewGame method.&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 statistics, or &amp;quot;player&amp;quot; if this is a player statistics.&lt;br /&gt;
&lt;br /&gt;
&#039;$name&#039; is the name of your statistics, 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 statistics. If this is a player statistics 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 lose in 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;
And score zero to everyone.&lt;br /&gt;
&lt;br /&gt;
=== Semi-coop ===&lt;br /&gt;
&lt;br /&gt;
If the game is not full-coop, then everyone lose = everyone is tie. I.e. set score to 0 to everybody.&lt;br /&gt;
&lt;br /&gt;
=== Only &amp;quot;winners&amp;quot; and &amp;quot;losers ===&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.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 score means defeat, a positive score means victory.&lt;br /&gt;
&lt;br /&gt;
=== Player elimination ===&lt;br /&gt;
&lt;br /&gt;
In some games, this is useful to eliminate a player from the game in order he/she can start another game without waiting for the current game end.&lt;br /&gt;
&lt;br /&gt;
This case should be rare. Please don&#039;t use player elimination feature if some player just has to wait the last 10% of the game for game end. This feature should be used only in games where players are eliminated all along the game (typical examples: &amp;quot;Perudo&amp;quot; or &amp;quot;The Werewolves of Miller&#039;s Hollow&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&lt;br /&gt;
* Player to eliminate should NOT be active anymore (preferably use the feature in a &amp;quot;game&amp;quot; type game state).&lt;br /&gt;
* In your PHP code:&lt;br /&gt;
  self::eliminatePlayer( &amp;lt;player_to_eliminate_id&amp;gt; );&lt;br /&gt;
* the player is informed in a dialog box that he no longer have to played and can start another game if he/she wants too (whith buttons &amp;quot;stay at this table&amp;quot; &amp;quot;quit table and back to main site&amp;quot;). In any case, the player is free to start &amp;amp; join another table from now.&lt;br /&gt;
* When your game is over, all players who have been eliminated before receive a &amp;quot;notification&amp;quot; (the small &amp;quot;!&amp;quot; icon on the top right of the BGA interface) that indicate them that &amp;quot;the game has ended&amp;quot; and invite them to review the game results.&lt;br /&gt;
&lt;br /&gt;
=== Scoring Helper functions ===&lt;br /&gt;
&lt;br /&gt;
    // get score&lt;br /&gt;
    function dbGetScore($player_id) {&lt;br /&gt;
        return $this-&amp;gt;getUniqueValueFromDB(&amp;quot;SELECT player_score FROM player WHERE player_id=&#039;$player_id&#039;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // set score&lt;br /&gt;
    function dbSetScore($player_id, $count) {&lt;br /&gt;
        $this-&amp;gt;DbQuery(&amp;quot;UPDATE player SET player_score=&#039;$count&#039; WHERE player_id=&#039;$player_id&#039;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // set aux score (tie breaker)&lt;br /&gt;
    function dbSetAuxScore($player_id, $score) {&lt;br /&gt;
        $this-&amp;gt;DbQuery(&amp;quot;UPDATE player SET player_score_aux=$score WHERE player_id=&#039;$player_id&#039;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // increment score (can be negative too)&lt;br /&gt;
    function dbIncScore($player_id, $inc) {&lt;br /&gt;
        $count = $this-&amp;gt;dbGetScore($player_id);&lt;br /&gt;
        if ($inc != 0) {&lt;br /&gt;
            $count += $inc;&lt;br /&gt;
            $this-&amp;gt;dbSetScore($player_id, $count);&lt;br /&gt;
        }&lt;br /&gt;
        return $count;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Reflexion time ==&lt;br /&gt;
&lt;br /&gt;
; function giveExtraTime( $player_id, $specific_time=null )&lt;br /&gt;
: Give standard extra time to this player.&lt;br /&gt;
: Standard extra time depends on the speed of the game (small with &amp;quot;slow&amp;quot; game option, bigger with other options).&lt;br /&gt;
: You can also specify an exact time to add, in seconds, with the &amp;quot;specified_time&amp;quot; argument (rarely used).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Undo moves ==&lt;br /&gt;
&lt;br /&gt;
Please read our [[BGA Undo policy]] before.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: Before using these methods, you must also add the following to your &amp;quot;gameinfos.inc.php&amp;quot; file, otherwise these methods are ineffective:&lt;br /&gt;
  &#039;db_undo_support&#039; =&amp;gt; true&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; function undoSavepoint( )&lt;br /&gt;
: Save the whole game situation inside an &amp;quot;Undo save point&amp;quot;.&lt;br /&gt;
: There is only ONE undo save point available (see BGA Undo policy).&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;
== Managing errors and exceptions ==&lt;br /&gt;
&lt;br /&gt;
Note: when you throw an exception, all database changes and all notifications are cancelled immediately. This way, the game situation that existed before the request is completely restored.&lt;br /&gt;
&lt;br /&gt;
; throw new BgaUserException ( $error_message)&lt;br /&gt;
: Base class to notify a user error&lt;br /&gt;
: You must throw this exception when a player wants to do something that he is not allowed to do.&lt;br /&gt;
: The error message will be shown to the player as a &amp;quot;red message&amp;quot;, so it must be translated.&lt;br /&gt;
: Throwing such an exception is NOT considered a bug, so it is not traced in BGA error logs.&lt;br /&gt;
&lt;br /&gt;
Example from Gomoku:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     throw new BgaUserException( self::_(&amp;quot;There is already a stone on this intersection, you can&#039;t play there&amp;quot;) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; throw new BgaVisibleSystemException ( $error_message)&lt;br /&gt;
: You must throw this exception when you detect something that is not supposed to happened in your code.&lt;br /&gt;
: The error message is shown to the user as an &amp;quot;Unexpected error&amp;quot;, in order that he can report it in the forum.&lt;br /&gt;
: The error message is logged in BGA error logs. If it happens regularly, we will report it to you.&lt;br /&gt;
&lt;br /&gt;
; throw new BgaSystemException ( $error_message)&lt;br /&gt;
: Base class to notify a system exception. The message will be hidden from the user, but show in the logs. Use this if the message contains technical information.&lt;br /&gt;
: You shouldn&#039;t use this type of exception except if you think the information shown could be critical. Indeed: a generic error message will be shown to the user, so it&#039;s going to be difficult for you to see what happened.&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
When a player leaves a game for any reason (expelled, quit), he becomes a &amp;quot;zombie player&amp;quot;. In this case, the results of the game won&#039;t count for statistics, but this is cool if the other players can finish the game anyway. That&#039;s why zombie mode exists: allow the other player to finish the game, even if the situation is not ideal.&lt;br /&gt;
&lt;br /&gt;
While developing your zombie mode, keep in mind that:&lt;br /&gt;
* Do not refer to the rules, because this situation is not planned by the rules.&lt;br /&gt;
* Try to figure that you are playing with your friends and one of them has to leave: how can we finish the game without killing the spirit of the game?&lt;br /&gt;
* The idea is NOT to develop an artificial intelligence for the game.&lt;br /&gt;
&lt;br /&gt;
Most of the time, the best thing to do when it is zombie player turn is to jump immediately to a state where he is not active anymore. For example, if he is in a game state where he has a choice between playing A and playing B, the best thing to do is NOT to choose A or B, but to pass. So, even if there&#039;s no &amp;quot;pass&amp;quot; action in the rules, add a &amp;quot;zombiepass&amp;quot; transitition in your game state and use it.&lt;br /&gt;
&lt;br /&gt;
Each time a zombie player must play, your &amp;quot;zombieTurn&amp;quot; method is called.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
* $state: the name of the current game state.&lt;br /&gt;
* $active_player: the id of the active player.&lt;br /&gt;
&lt;br /&gt;
Most of the time, your zombieTurn method looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function zombieTurn( $state, $active_player )&lt;br /&gt;
    {&lt;br /&gt;
    	$statename = $state[&#039;name&#039;];&lt;br /&gt;
&lt;br /&gt;
        if( $statename == &#039;myFirstGameState&#039;&lt;br /&gt;
             ||  $statename == &#039;my2ndGameState&#039;&lt;br /&gt;
             ||  $statename == &#039;my3rdGameState&#039;&lt;br /&gt;
               ....&lt;br /&gt;
           )&lt;br /&gt;
        {&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextState( &amp;quot;zombiePass&amp;quot; );&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            throw new BgaVisibleSystemException( &amp;quot;Zombie mode not supported at this game state: &amp;quot;.$statename );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in the example above, all corresponding game state should implement &amp;quot;zombiePass&amp;quot; as a transition.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Very important&#039;&#039;&#039;: your zombie code will be called when the player leaves the game. This action is triggered from the main site and propagated to the gameserver from a server, not from a browser. As a consequence, there is no current player associated to this action. In your zombieTurn function, you must &#039;&#039;&#039;never&#039;&#039;&#039; use getCurrentPlayerId() or getCurrentPlayerName(), otherwise it will fail with a &amp;quot;Not logged&amp;quot; error message.&lt;br /&gt;
&lt;br /&gt;
== Player color preferences ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
BGA players (Club members) may now choose their preferred color for playing. For example, if they are used to play green for every board game, they can select &amp;quot;green&amp;quot; in their BGA preferences page.&lt;br /&gt;
&lt;br /&gt;
Making your game compatible with colors preferences is very easy and requires only 1 line of PHP and 1 configuration change :&lt;br /&gt;
&lt;br /&gt;
On your gameinfos.inc.php file, add the following lines :&lt;br /&gt;
&lt;br /&gt;
  // Favorite colors support : if set to &amp;quot;true&amp;quot;, support attribution of favorite colors based on player&#039;s preferences (see reattributeColorsBasedOnPreferences PHP method)&lt;br /&gt;
  &#039;favorite_colors_support&#039; =&amp;gt; true,&lt;br /&gt;
&lt;br /&gt;
Then, on your main &amp;lt;your_game&amp;gt;.game.php file, find the &amp;quot;reloadPlayersBasicInfos&amp;quot; call in your &amp;quot;setupNewGame&amp;quot; method and replace :&lt;br /&gt;
&lt;br /&gt;
        $sql .= implode( $values, &#039;,&#039; );&lt;br /&gt;
        self::DbQuery( $sql );&lt;br /&gt;
        self::reloadPlayersBasicInfos();&lt;br /&gt;
&lt;br /&gt;
By :&lt;br /&gt;
&lt;br /&gt;
        $sql .= implode( $values, &#039;,&#039; );&lt;br /&gt;
        self::DbQuery( $sql );&lt;br /&gt;
        self::reattributeColorsBasedOnPreferences( $players, array(  /* LIST HERE THE AVAILABLE COLORS OF YOUR GAME INSTEAD OF THESE ONES */&amp;quot;ff0000&amp;quot;, &amp;quot;008000&amp;quot;, &amp;quot;0000ff&amp;quot;, &amp;quot;ffa500&amp;quot;, &amp;quot;773300&amp;quot; ) );&lt;br /&gt;
        self::reloadPlayersBasicInfos();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;reattributeColorsBasedOnPreferences&amp;quot; method reattributes all colors, taking into account players color preferences and available colors.&lt;br /&gt;
&lt;br /&gt;
Note that you must update the colors to indicate the colors available for your game.&lt;br /&gt;
&lt;br /&gt;
2 important remarks :&lt;br /&gt;
* for some games (ex : Chess), the color has an influence on a mechanism of the game, most of the time by giving a special advantage to a player (ex : Starting the game). Color preference mechanism must NOT be used in such a case.&lt;br /&gt;
* your logic should NEVER consider that the first player has the color X, that the second player has the color Y, and so on. If this is the case, your game will NOT be compatible with reattributeColorsBasedOnPreferences as this method attribute colors to players based on their preferences and not based as their order at the table.&lt;br /&gt;
&lt;br /&gt;
Colours currently listed as a choice in preferences:&lt;br /&gt;
&lt;br /&gt;
* #ff0000 Red&lt;br /&gt;
* #008000 Green&lt;br /&gt;
* #0000ff Blue&lt;br /&gt;
* #ffa500 Yellow&lt;br /&gt;
* #000000 Black&lt;br /&gt;
* #ffffff White&lt;br /&gt;
* #e94190 Pink&lt;br /&gt;
* #982fff Purple&lt;br /&gt;
* #72c3b1 Cyan&lt;br /&gt;
* #f07f16 Orange&lt;br /&gt;
* #bdd002 Khaki green&lt;br /&gt;
* #7b7b7b Gray&lt;br /&gt;
&lt;br /&gt;
== 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>Inaofr</name></author>
	</entry>
</feed>