<?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=Vagabond</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=Vagabond"/>
	<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/Special:Contributions/Vagabond"/>
	<updated>2026-11-02T16:18:32Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.11</generator>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Using_Typescript_and_Scss&amp;diff=28320</id>
		<title>Using Typescript and Scss</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Using_Typescript_and_Scss&amp;diff=28320"/>
		<updated>2026-02-01T15:31:10Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: Add note that the switch to ES modules means the global JS game object changes.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will help you set up your project to use Typescript client file and Scss style files, and automatically build Javascript (in ES5) files and CSS files so your project stay compatible to BGA framework requirements.&lt;br /&gt;
You can use only TS or only SCSS part if you want, they are not linked.&lt;br /&gt;
&lt;br /&gt;
The following document is geared towards setting up a custom project where you will be in charge of typing all components that you want to use.&lt;br /&gt;
There is also untested 3rd party project that aims to automate some of the steps below, you can look at this instead [[BGA Type Safe Template]]. &lt;br /&gt;
&lt;br /&gt;
== Install and configure ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Install dev stack  ===&lt;br /&gt;
Install node/npm.  Here is an example to activate auto-build in Visual Studio Code, if you use another tool I strongly recommend to find an equivalent so you don&#039;t have to launch build manually after each modification.&lt;br /&gt;
&lt;br /&gt;
=== Configure package.json and tsconfig.json ===&lt;br /&gt;
&lt;br /&gt;
Create a file named &amp;lt;code&amp;gt;package.json&amp;lt;/code&amp;gt; on the root folder, not on the src folder.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;package.json&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;name&amp;quot;: &amp;quot;yourgamename&amp;quot;,&lt;br /&gt;
   &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,&lt;br /&gt;
   &amp;quot;description&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
   &amp;quot;main&amp;quot;: &amp;quot;YourGameName.js&amp;quot;,&lt;br /&gt;
   &amp;quot;scripts&amp;quot;: {&lt;br /&gt;
     &amp;quot;build:ts&amp;quot;: &amp;quot;rollup -c&amp;quot;,&lt;br /&gt;
     &amp;quot;build:scss&amp;quot;: &amp;quot;sass --no-source-map src/yourgamename.scss yourgamename.css&amp;quot;,&lt;br /&gt;
     &amp;quot;watch:ts&amp;quot;: &amp;quot;rollup -c -w&amp;quot;,&lt;br /&gt;
     &amp;quot;watch:scss&amp;quot;: &amp;quot;sass --watch src/yourgamename.scss yourgamename.css&amp;quot;,&lt;br /&gt;
     &amp;quot;watch&amp;quot;: &amp;quot;npm run watch:ts &amp;amp;&amp;amp; npm run watch:scss&amp;quot;,&lt;br /&gt;
     &amp;quot;build&amp;quot;: &amp;quot;npm run build:ts &amp;amp;&amp;amp; npm run build:scss&amp;quot;&lt;br /&gt;
   },&lt;br /&gt;
   &amp;quot;author&amp;quot;: &amp;quot;yourname&amp;quot;,&lt;br /&gt;
   &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,&lt;br /&gt;
   &amp;quot;devDependencies&amp;quot;: {&lt;br /&gt;
    &amp;quot;@rollup/plugin-typescript&amp;quot;: &amp;quot;^12.3.0&amp;quot;,&lt;br /&gt;
    &amp;quot;rollup&amp;quot;: &amp;quot;^4.53.3&amp;quot;,&lt;br /&gt;
    &amp;quot;sass&amp;quot;: &amp;quot;^1.71.0&amp;quot;,&lt;br /&gt;
    &amp;quot;tslib&amp;quot;: &amp;quot;^2.8.1&amp;quot;,&lt;br /&gt;
    &amp;quot;typescript&amp;quot;: &amp;quot;^5.3.3&amp;quot;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you not using scss - remove corresponding scripts and deps.&lt;br /&gt;
&lt;br /&gt;
When package.json is created, run &amp;lt;code&amp;gt;npm i&amp;lt;/code&amp;gt; on the root folder to install builders (will generate a node_modules folder).&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: exclude node_modules/ subfolder from auto-sync to remote folder (whatever system you use for that).&lt;br /&gt;
&lt;br /&gt;
For Typescript compilation we also need to set up &amp;lt;code&amp;gt;rollup.config.mjs&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;tsconfig.json&amp;lt;/code&amp;gt; on the root folder.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;rollup.config.mjs&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  import typescript from &#039;@rollup/plugin-typescript&#039;;&lt;br /&gt;
&lt;br /&gt;
  export default {&lt;br /&gt;
    input: &#039;src/&amp;lt;yourgamename&amp;gt;.ts&#039;,&lt;br /&gt;
    output: {&lt;br /&gt;
      file: &#039;modules/js/Game.js&#039;,&lt;br /&gt;
      format: &#039;es&#039;,&lt;br /&gt;
      sourcemap: false,&lt;br /&gt;
      inlineDynamicImports: true,&lt;br /&gt;
    },&lt;br /&gt;
    plugins: [&lt;br /&gt;
      typescript({&lt;br /&gt;
        tsconfig: &#039;./tsconfig.json&#039;,&lt;br /&gt;
      }),&lt;br /&gt;
    ],&lt;br /&gt;
    treeshake: false,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tsconfig.json&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  {&lt;br /&gt;
    &amp;quot;compilerOptions&amp;quot;: {&lt;br /&gt;
      &amp;quot;target&amp;quot;: &amp;quot;ES2020&amp;quot;,&lt;br /&gt;
      &amp;quot;module&amp;quot;: &amp;quot;ES2022&amp;quot;,&lt;br /&gt;
      &amp;quot;moduleResolution&amp;quot;: &amp;quot;node&amp;quot;,&lt;br /&gt;
      &amp;quot;lib&amp;quot;: [&amp;quot;dom&amp;quot;, &amp;quot;esnext&amp;quot;],&lt;br /&gt;
      &amp;quot;sourceMap&amp;quot;: false,&lt;br /&gt;
      &amp;quot;rootDir&amp;quot;: &amp;quot;src&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;include&amp;quot;: [&lt;br /&gt;
      &amp;quot;*.d.ts&amp;quot;,&lt;br /&gt;
      &amp;quot;src/**/*.d.ts&amp;quot;,&lt;br /&gt;
      &amp;quot;src/**/*.ts&amp;quot;&lt;br /&gt;
    ]&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Create skeleton ==&lt;br /&gt;
When you create your game in BGA Studio, a JS and CSS file are generated. As we will overwrite them with autobuild. You can put the TS/SCSS files on a &amp;lt;code&amp;gt;src&amp;lt;/code&amp;gt; folder to separate them from built files, but that&#039;s not mandatory.&lt;br /&gt;
Note to myself: check if &#039;src&#039; dir will be svn version control, if not cannot really use it (even if duplicated in git).&lt;br /&gt;
&lt;br /&gt;
Note: if you&#039;re using SFTP and have &amp;quot;bga-framework.d.ts&amp;quot; in the ignore list - remove it and resync. You will need this file. &lt;br /&gt;
&lt;br /&gt;
=== Typescript file skeleton ===&lt;br /&gt;
Typescript example here have been stripped down of all comments for clarity. &lt;br /&gt;
Your TS code can be splitted in multiple files, you can have a look at [https://studio.boardgamearena.com/projects castlecombo] code for inspiration.&lt;br /&gt;
To make this page concise, I removed comments and code samples. If it&#039;s your first game, well - don&#039;t do it if your first game - you won&#039;t be able to apply other code samples from docs, they all using dojo style and have to completely rewritten.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;src/yourgamename.d.ts&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
interface YourGameNamePlayer extends Player {&lt;br /&gt;
    cards: Card[]; // any information you add on each result[&#039;players&#039;]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
interface YourGameNameGamedatas extends Gamedatas&amp;lt;YourGameNamePlayer&amp;gt; {&lt;br /&gt;
    // Add here variables you set up in getAllDatas&lt;br /&gt;
    discardedCards: { [row: number]: Card[] };&lt;br /&gt;
    remainingCardsInDecks: { [row: number]: number };&lt;br /&gt;
    tableCards: { [row: number]: Card[] };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Not: the Generic typing is optional.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;src/yourgamename.ts&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class Game {&lt;br /&gt;
&lt;br /&gt;
    public bga: Bga;&lt;br /&gt;
    private gamedatas: YourGameNameGamedatas;&lt;br /&gt;
&lt;br /&gt;
     constructor(bga: Bga&amp;lt;YourGameNameGamedatas&amp;gt;) {&lt;br /&gt;
        this.bga = bga;&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     public setup(gamedatas: YourGameNameGamedatas) {&lt;br /&gt;
         this.gamedatas = gamedatas; &lt;br /&gt;
         this.setupNotifications();&lt;br /&gt;
     } &lt;br /&gt;
     public setupNotifications() {}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to sync the bga-framework.d.ts from your FTP folder regularly to get the last version.&lt;br /&gt;
&lt;br /&gt;
=== SCSS file ===&lt;br /&gt;
Nothing special here, just write classic SCSS (will be compiled by Dart scss) and name it &#039;&#039;&#039;src/yourgamename.scss&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  @use &#039;variables&#039; as v;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  /* the other files */&lt;br /&gt;
  @use &amp;quot;./Animations&amp;quot;;&lt;br /&gt;
  @use &amp;quot;./Board&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  #ebd-body {&lt;br /&gt;
    background-image: url(img/woodbg.jpg);&lt;br /&gt;
    background-repeat: repeat;&lt;br /&gt;
  }&lt;br /&gt;
  @each $key, $val in v.$colors-list {&lt;br /&gt;
    .fgcolor#{$key} {&lt;br /&gt;
      color: #{$val};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Your SCSS code can be (should be) splitted in multiple files, for example:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;variables.scss&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$colors-list: (&lt;br /&gt;
  _6cd0f6: #6cd0f6, // blue&lt;br /&gt;
  _ef58a2: #ef58a2, // pink&lt;br /&gt;
  _ffcc02: #ffcc02, // yellow&lt;br /&gt;
  _a0d28c: #a0d28c // green&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Auto build and auto upload ==&lt;br /&gt;
&lt;br /&gt;
=== Auto build JS and CSS files ===&lt;br /&gt;
&lt;br /&gt;
To build and watch (i.e. re-build continuously changed files) run in terminal:&lt;br /&gt;
  npm run watch&lt;br /&gt;
&lt;br /&gt;
Alternately you can make vscode to do it for you by installing Run on Save extension, see details in [[Setting_up_BGA_Development_environment_using_VSCode]]&lt;br /&gt;
&lt;br /&gt;
Note: to build without watch&lt;br /&gt;
  npm run build&lt;br /&gt;
&lt;br /&gt;
=== Auto-upload generated files ===&lt;br /&gt;
You can setup standard file sync or use vscode SFTP extension, see details in [[Setting_up_BGA_Development_environment_using_VSCode]]&lt;br /&gt;
&lt;br /&gt;
Make sure that your sftp.json file has a &amp;quot;watcher&amp;quot; section to detect and upload changes made outside of the VSCode IDE.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;quot;watcher&amp;quot;: {&lt;br /&gt;
        &amp;quot;files&amp;quot;: &amp;quot;**/*.{js,css}&amp;quot;,&lt;br /&gt;
        &amp;quot;autoUpload&amp;quot;: true,&lt;br /&gt;
        &amp;quot;autoDelete&amp;quot;: true&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Exclusions from auto-upload ===&lt;br /&gt;
Make sure &amp;lt;code&amp;gt;.vscode&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;node_modules&amp;lt;/code&amp;gt; are in &amp;lt;code&amp;gt;.gitignore&amp;lt;/code&amp;gt; if you commit your project somewhere.&lt;br /&gt;
&lt;br /&gt;
=== Code completion ===&lt;br /&gt;
To have a code completion for framework classes, dojo, stock, etc, you&#039;ll need to make sure bga-framework.d.ts file is added to your tsconfig.&lt;br /&gt;
&lt;br /&gt;
== Using the new libs ==&lt;br /&gt;
To use the new front libs (bga-autofit, bga-score-sheet, ...), it&#039;s recommended to created a dedicated file that will be responsible of all imports, than you&#039;ll import when you need it&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;libs.ts&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import type { BgaAnimations as BgaAnimationsType } from &amp;quot;../bga-animations&amp;quot;;&lt;br /&gt;
import type { BgaCards as BgaCardsType } from &amp;quot;../bga-cards&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
const BgaAnimations: typeof BgaAnimationsType = await globalThis.importEsmLib(&#039;bga-animations&#039;, &#039;1.x&#039;);&lt;br /&gt;
const BgaCards: typeof BgaCardsType = await globalThis.importEsmLib(&#039;bga-cards&#039;, &#039;1.x&#039;);&lt;br /&gt;
&lt;br /&gt;
export { BgaAnimations, BgaCards };&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you can use them in your files using import:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import { BgaCards } from &#039;./libs&#039;;&lt;br /&gt;
export class MyCardManager extends BgaCards.Manager&amp;lt;Card&amp;gt; { ... }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For class property typings, use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public animationManager: InstanceType&amp;lt;typeof BgaAnimations.Manager&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
    // in your setup:&lt;br /&gt;
    this.animationManager = new BgaAnimations.Manager({ ... });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need to load old libs, you can do it this way:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const [Counter, Stock] = await importDojoLibs([&amp;quot;ebg/counter&amp;quot;, &amp;quot;ebg/stock&amp;quot;]);&lt;br /&gt;
&lt;br /&gt;
export { Counter, Stock };&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== migrating from old way (ES5 build to gamename.js) ==&lt;br /&gt;
&lt;br /&gt;
the new setup described in this page use explicit import/export that were not used before. But we don&#039;t need to explicitely list all files anymore.&lt;br /&gt;
&lt;br /&gt;
For example, if you have a file for MyCardManager and a file for MyGame, you&#039;ll need to do this:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MyCardManager.ts&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export class MyCardManager { ... }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MyGame.ts&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import { MyCardManager } from &amp;quot;./MyCardManager&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
export class Game implements Bga {&lt;br /&gt;
    public cardManager: MyCardManager;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Browser console info ==&lt;br /&gt;
&lt;br /&gt;
Using ES modules, your game object is no longer merged into the &amp;lt;code&amp;gt;gameui&amp;lt;/code&amp;gt; global. Instead, your game object is available as &amp;lt;code&amp;gt;gameui.GameModule&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Referenced Projects ==&lt;br /&gt;
&lt;br /&gt;
* https://github.com/thoun/bga-ts-example&lt;br /&gt;
* https://github.com/elaskavaia/bga-dojoless&lt;br /&gt;
* https://github.com/NevinAF/bga-ts-template&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=I_wish_I_knew_this_when_I_started&amp;diff=28319</id>
		<title>I wish I knew this when I started</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=I_wish_I_knew_this_when_I_started&amp;diff=28319"/>
		<updated>2026-02-01T14:57:39Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: Update browser console access for module-based games&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page contains most &amp;quot;I wish I knew this before...&amp;quot; moments (in regards to BGA studio game development). One line per statement please with doc references. Docs link can be outside of BGA wiki.&lt;br /&gt;
Most of this is already documented on BGA wiki in details, search wiki or google for generic subject to find more info.&lt;br /&gt;
&lt;br /&gt;
* Browser caches images and css, to force re-cache use Ctrl+F5 or Ctrl+Shift+R, and sometimes it&#039;s not enough so go to the web console &amp;gt; Network &amp;gt; check &amp;quot;disable cache&amp;quot;&lt;br /&gt;
* Browser has powerful embeded dev tools for inspection of dom, css and js, you can debug js right in browser (F12)&lt;br /&gt;
* You don&#039;t have to login with another dev account to play test the game under development, little colored arrows on studio player panel switch between test accounts&lt;br /&gt;
* You can run PHP functions from chat&lt;br /&gt;
* You can change style of elements (css) depending on their parent, sibling or other properties of the element&lt;br /&gt;
* You cannot save php state in global variables between actions, all data has to be stored in db&lt;br /&gt;
* Ajax actions in BGA do not use the traditional request-response model of a normal application. The ajax response does not contain any payload and instead you must send a notification ($this-&amp;gt;notify-&amp;gt;all) to communicate the response to appropriate players.&lt;br /&gt;
* Almost every change you make to the game via sending notifications must also be included in getAllDatas (e.g., in case a player loads/refreshes the game during the middle of play).&lt;br /&gt;
* You can easily scale elements by using &amp;quot;em&amp;quot; as unit for width/height and varying font-size, i.e. .meeple {width: 2em;height: 2.5em;font-size: 20px;}&lt;br /&gt;
* You can access your javascript methods / properties in the browser console using &#039;&#039;&#039;&#039;&#039;gameui.GameModule.&amp;lt;yourMethod&amp;gt;&#039;&#039;&#039;&#039;&#039; (or &#039;&#039;&#039;&#039;&#039;gameui.&amp;lt;yourMethod&amp;gt;&#039;&#039;&#039;&#039;&#039; for older games not using JS modules, i.e. not using &amp;lt;code&amp;gt;modules/js/Game.js&amp;lt;/code&amp;gt;)&lt;br /&gt;
* To interactively debug JS issues you can put &#039;&#039;&#039;&#039;&#039;debugger;&#039;&#039;&#039;&#039;&#039; statement in your code, enable dev tools (F12) and reload. It will hit breakpoint.&lt;br /&gt;
* To quickly try a fix you can edit css, js and html directly in browser dev tool window, no reload required (just don&#039;t forget to copy it back to your code after)&lt;br /&gt;
* To spell check all your translatable strings use Project Check from control panel - it will generate all strings, you can cut &amp;amp; paste this in online spell checker (or just use Firefox - it has embedded spell checker).&lt;br /&gt;
* To remove inline style property from dom node $(token).style.removeProperty(&amp;quot;position&amp;quot;); or dojo.style(&#039;token&#039;, &#039;position&#039;, null);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=28145</id>
		<title>Game interface logic: Game.js</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=28145"/>
		<updated>2026-01-20T13:35:45Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: added a &amp;quot;bga.&amp;quot; where it was needed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
This is the main file for your game interface. Here you will define:&lt;br /&gt;
&lt;br /&gt;
* Which actions on the page will generate calls to the server.&lt;br /&gt;
* What happens when you get a notification for a change from the server and how it will show in the browser. &lt;br /&gt;
* Setup user interface&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; this file is now named Game.js, located in the modules/js directory. If you see it named yourgamename.js in the root dir, it&#039;s the legacy usage. In the legacy usage, the declaration is a bit different, as it uses define and declare to instanciate a JS object, while the new way exports a class (using ES Modules).&lt;br /&gt;
The new class doesn&#039;t extends gameui, so if you need to access some things from gameui that don&#039;t exist in the sub-components described above, you must use this.gameui.xx.&lt;br /&gt;
&lt;br /&gt;
== Framework sub-components ==&lt;br /&gt;
The framework is now split into multiple sub-components to group the related functions : statusBar, sounds, gameArea, playerPanels, images, userPreferences, players, actions, notifications, dialogs. All are available in the bga object sent to the constructor (or in this.bga for the legacy way).&lt;br /&gt;
&lt;br /&gt;
To make it accessible on the Game class, make it a property like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        constructor(bga){&lt;br /&gt;
            this.bga = bga;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;mygamename&amp;gt;.js (the obsolete filename), this.bga is already set.&lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
&lt;br /&gt;
The details of how the file is structured are described below with comments in the code skeleton provided to you.&lt;br /&gt;
&lt;br /&gt;
Here is the basic structure:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;constructor&#039;&#039;&#039;: here you can define global variables for your whole interface.&lt;br /&gt;
* &#039;&#039;&#039;setup&#039;&#039;&#039;: this method is called when the page is refreshed, and sets up the game interface.&lt;br /&gt;
* &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;: this method is called when entering a new game state. You can use it to customize the view for each game state. &amp;lt;i&amp;gt;The function is optional, and not needed if you use JS State classes.&amp;lt;/i&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;onLeavingState&#039;&#039;&#039;: this method is called when leaving a game state. &amp;lt;i&amp;gt;The function is optional, and not needed if you use JS State classes.&amp;lt;/i&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039;: called on state changes, in order to add action buttons to the status bar. Note: in a MULTIPLE_ACTIVE_PLAYER state, it will be called when another player has become inactive. &amp;lt;i&amp;gt;The function is optional, and not needed if you use JS State classes.&amp;lt;/i&amp;gt;&lt;br /&gt;
* &#039;&#039;(utility methods)&#039;&#039;: this is where you can define your utility methods.&lt;br /&gt;
* &#039;&#039;(player&#039;s actions)&#039;&#039;: this is where you can write your handlers for player actions on the interface (example: click on an item).&lt;br /&gt;
* &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;: this method associates notifications with notification handlers. For each game notification, you can trigger a javascript method to handle it and update the game interface.&lt;br /&gt;
* &#039;&#039;(notification handlers)&#039;&#039;: this is where you define the notifications handlers associated with notifications in &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;, above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
More details:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setup(gamedatas: object)            &#039;&#039;&#039;&lt;br /&gt;
This method must set up the game user interface according to current game situation specified in parameters.&lt;br /&gt;
The method is called each time the game interface is displayed to a player, ie:&lt;br /&gt;
&lt;br /&gt;
* when the game starts&lt;br /&gt;
* when a player opens a game in the browser later &lt;br /&gt;
* when a player refreshes the game page (F5)&lt;br /&gt;
* when player does a server side Undo&lt;br /&gt;
&lt;br /&gt;
&amp;quot;gamedatas&amp;quot; argument contains all data retrieved by your &amp;quot;getAllDatas&amp;quot; PHP method and some more.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onEnteringState(stateName: string, args: { args: any } | null): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is called each time we enter a new game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
To access state arguments passed via calling php arg* method use args?.args.&lt;br /&gt;
Typically you would do something only for active player, using this.players.isCurrentPlayerActive() check.&lt;br /&gt;
It is also called (for the current game state only) when doing a browser refresh (after the setup method is called).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: for MULTIPLE_ACTIVE_PLAYER states:&lt;br /&gt;
the active players are NOT active yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/inactive status.&lt;br /&gt;
If you are doing initialization of some structures which do not depend on the active player, you can just replace (this.players.isCurrentPlayerActive()) with (!this.players.isCurrentPlayerSpectator()) &lt;br /&gt;
for the main switch in that method.&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Difference_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onLeavingState(stateName: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is called each time we leave a game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this point (i.e. cleanup).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onUpdateActionButtons(stateName: string, args: object | null): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this method you can manage &amp;quot;action buttons&amp;quot; that are displayed in the action status bar and highlight active UI elements.&lt;br /&gt;
To access state arguments passed via calling php arg* method use &#039;&#039;&#039;args&#039;&#039;&#039; parameter. Note: args can be null! For &#039;&#039;&#039;game&#039;&#039;&#039; states and when you don&#039;t supply state args function - it is null.&lt;br /&gt;
This method is called when the active or multiactive player changes. In a classic ACTIVE_PLAYER state this method is called before the onEnteringState state.&lt;br /&gt;
In MULTIPLE_ACTIVE_PLAYER state it is a mess. The sequencing of calls depends on whether you get into that state from transitions OR from reloading the whole game (i.e. F5).&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Difference_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
== States ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== JS State classes ===&lt;br /&gt;
To split the code of the Game class, you can create dedicated classes for each state you handle on the front side (some states like NextPlayer don&#039;t need to be handled on the JS side).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.register(stateIdOrName: string|number, stateClass: Object): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method links a state class to a state name. It should be used in the Game constructor like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Declare the State classes&lt;br /&gt;
        this.bga.states.register(&#039;PlayerTurn&#039;, new PlayerTurn(this, this.bga));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a state class is declared like this, the framework will call its onEnteringState... functions automatically. Example of JS State class:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class PlayerTurn {&lt;br /&gt;
    constructor(game, bga) {&lt;br /&gt;
        this.game = game;&lt;br /&gt;
        this.bga = bga;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This method is called each time we are entering the game state. You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
     */&lt;br /&gt;
    onEnteringState(args, isCurrentPlayerActive) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This method is called each time we are leaving the game state. You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
     */&lt;br /&gt;
    onLeavingState(args, isCurrentPlayerActive) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This method is called each time the current player becomes active or inactive in a MULTIPLE_ACTIVE_PLAYER state. You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
     * on MULTIPLE_ACTIVE_PLAYER states, you may want to call this function in onEnteringState using `this.onPlayerActivationChange(args, isCurrentPlayerActive)` at the end of onEnteringState.&lt;br /&gt;
     * If your state is not a MULTIPLE_ACTIVE_PLAYER one, you can delete this function.&lt;br /&gt;
     */&lt;br /&gt;
    onPlayerActivationChange(args, isCurrentPlayerActive) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // put custom functions only use on this state here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getCurrentMainStateName(): string;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the current main state name (ignoring private states)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getCurrentPlayerStateName(): string;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the current player state name (private state name if there is one)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.logger: Function&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can write &amp;lt;code&amp;gt;this.bga.states.logger = console.log&amp;lt;/code&amp;gt; to show debug information about state changes in the console. Remove before going to production!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getStateClass(stateName: string): Object&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get a state class (instance) by state name.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getCurrentMainStateClass(): Object;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the current main state class (instance) (ignoring private states)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getCurrentPlayerStateClass(): Object;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the current player state class (instance) (private state if there is one)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getStateClasses(): Object[];&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns the registered state classes (instances)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Client states===&lt;br /&gt;
&lt;br /&gt;
Client states is a way to simulate the state transition but without actually going to server. It is useful when you need to ask user multiple questions before you send things to server.&lt;br /&gt;
&lt;br /&gt;
Client states don&#039;t have a matching PHP class. They can be used with JS State classes, as long as the stateName declared in setClientState matches the registered JS State class.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.setClientState(stateName: string, args: Object): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
     this.bga.states.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                               descriptionmyturn : _(&amp;quot;${you} must select location&amp;quot;),&lt;br /&gt;
                           });&lt;br /&gt;
&lt;br /&gt;
For more information see [[BGA_Studio_Cookbook#Multi_Step_Interactions:_Select_Worker.2FPlace_Worker_-_Using_Client_States]]&lt;br /&gt;
&lt;br /&gt;
To add custom string interpolation for the state title, you can add them by using the args object like so:&lt;br /&gt;
     this.bga.states.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                              descriptionmyturn : _(&amp;quot;${you} must select location for card {$card_number}&amp;quot;),&lt;br /&gt;
                              args: { card_number: 5 },&lt;br /&gt;
                          });&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.restoreServerGameState(): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you are in client state it will restore the current server state (cheap undo)&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.isOnClientState(): boolean;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns if the current state is a client state&lt;br /&gt;
&lt;br /&gt;
== Dojo framework ==&lt;br /&gt;
&lt;br /&gt;
BGA uses the [http://dojotoolkit.org/ Dojo Javascript framework] internally.&lt;br /&gt;
&lt;br /&gt;
To implement a game, you don&#039;t need to use the outdated Dojo framework, as vanilla JS is now able to do the same things. Some example of Dojo will stay on this page to help you read old games code.&lt;br /&gt;
&lt;br /&gt;
== Javascript minimization (after July 2020) ==&lt;br /&gt;
&lt;br /&gt;
For performance reasons, when deploying a game the javascript code is minimized using &#039;&#039;&#039;terser&#039;&#039;&#039; (https://github.com/terser/terser). This minifier works with modern javascript syntax. From your project &amp;quot;Manage game&amp;quot; page, you can now test a minified version of your javascript on the studio (and revert to the original).&lt;br /&gt;
&lt;br /&gt;
NB: it has been reported that there is an issue with this minifier and percentage values for opacity.&lt;br /&gt;
&lt;br /&gt;
== Accessing Players Information ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getCurrentPlayerId(): number&#039;&#039;&#039;&lt;br /&gt;
id of the player who is looking at the game. The player may not be part of the game (i.e. spectator)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.isCurrentPlayerSpectator(): boolean&#039;&#039;&#039;&lt;br /&gt;
Flag set to true if the user at the table is a spectator (not a player).&lt;br /&gt;
&lt;br /&gt;
Note: If you want to hide an element from spectators, you should use [[Game_interface_stylesheet:_yourgamename.css#spectatorMode|CSS &#039;spectatorMode&#039; class]].&lt;br /&gt;
&lt;br /&gt;
You may consider making a function like this, to detect if the game is in a read-only state (i.e. non-interactive):&lt;br /&gt;
  // Returns true for spectators, instant replay (during game), archive mode (after game end)&lt;br /&gt;
  isReadOnly: function () {&lt;br /&gt;
    return this.bga.players.isCurrentPlayerSpectator() || typeof g_replayFrom != &#039;undefined&#039; || g_archive_mode;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.isCurrentPlayerActive(): boolean&#039;&#039;&#039;&lt;br /&gt;
Returns true if the player on whose browser the code is running is currently active (it&#039;s his turn to play). Note: see remarks above about usage of this function inside onEnteringState method.&lt;br /&gt;
  if (this.bga.players.isCurrentPlayerActive()) ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getActivePlayerId(): number&#039;&#039;&#039;&lt;br /&gt;
Return the ID of the active player, or null if we are not in an ACTIVE_PLAYER type state.&lt;br /&gt;
  if (args.player_id == this.bga.players.getActivePlayerId()) ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getActivePlayerIds(): number[]&#039;&#039;&#039;&lt;br /&gt;
Return an array with the IDs of players who are currently active (or an empty array if there are none).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getFormattedPlayerName(playerId): string&#039;&#039;&#039;&lt;br /&gt;
Get the HTML code to display the player name, in bold, with color (and color_back if needed)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.gamedatas: object&#039;&#039;&#039;&lt;br /&gt;
Contains the initial set of data to init the game, created at game start or by game refresh (F5).&lt;br /&gt;
You can update it as needed to keep an up-to-date reference of the game on the client side if you need it, however most of the time this is unnecessary.&lt;br /&gt;
&lt;br /&gt;
Note: In hotseat mode, the framework does not keep this.gamedatas of hotseat players and shares the same set as the main player to store data.&lt;br /&gt;
&lt;br /&gt;
Note: be careful when you update this data structurally, many framework functions expect data to be certain way and they will break if they see something else.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getPlayer(playerId): object&#039;&#039;&#039;&lt;br /&gt;
Return the player data stored in gamedatas.players. Can be undefined, if the player isn&#039;t at this table (spectator).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getActivePlayer(): object&#039;&#039;&#039;&lt;br /&gt;
Same as getPlayer for the active player.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getCurrentPlayer(): object&#039;&#039;&#039;&lt;br /&gt;
Same as getPlayer for the current player.&lt;br /&gt;
&lt;br /&gt;
== Accessing and manipulating the DOM ==&lt;br /&gt;
&lt;br /&gt;
=== Main game area ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameAre.getElement(): HTMLElement&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns the div of the game area to put the game template into.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
Add this piece of code in your JS file, at the beginning of the setup function, to set the template :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                const html = `&amp;lt;div&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;round-counter&amp;quot;&amp;gt;${_(&#039;Round&#039;)} ${gamedatas.currentRound}/${gamedatas.totalRound}&amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;div&amp;gt;...anything else in your game template...&amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;`;&lt;br /&gt;
                this.bga.gameAre.getElement().insertAdjacentHTML(&#039;beforeend&#039;, html);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Element by Id ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$(elementId: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The $ function is used to get an HTML element using its &amp;quot;id&amp;quot; attribute.&lt;br /&gt;
&lt;br /&gt;
Example: modify the content of a &amp;quot;span&amp;quot; element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In your HTML code:&lt;br /&gt;
   &amp;lt;span id=&amp;quot;a_value_in_the_game_interface&amp;quot;&amp;gt;1234&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In your Javascript code:&lt;br /&gt;
   $(&#039;a_value_in_the_game_interface&#039;).innerHTML = &amp;quot;9999&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: It is safe to use if you don&#039;t know if variable is string (id of element) or element itself, i.e. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  foo: function(card) {&lt;br /&gt;
       card = $(card); // now its node, no need to write if (typeof card === &#039;string&#039;) ...&lt;br /&gt;
       // but its good idea to check for null here&lt;br /&gt;
       ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getElementById(elementId: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note: $() is the standard method to access some HTML element with the BGA Framework. You can use &#039;&#039;&#039;getElementById&#039;&#039;&#039; but it is longer to type and less handy as it does not do some checks.&lt;br /&gt;
&lt;br /&gt;
=== Style ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.style(node: ElementOrId, styleName: string, styleValue: any): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.style you can modify the CSS property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Make an element disappear&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Give an element a 2px border&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;borderWidth&#039;, &#039;2px&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Change the background position of an element&lt;br /&gt;
     // (very practical when you are using CSS sprites to transform an element to another)&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;backgroundPosition&#039;, &#039;-20px -50px&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you have to modify several CSS properties of an element, or if you have a complex CSS transformation to do, you should consider using dojo.addClass/dojo.removeClass (see below).&lt;br /&gt;
&lt;br /&gt;
You can also use object to set multiple values&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dojo.setStyle(&amp;quot;thinger&amp;quot;, {&lt;br /&gt;
  &amp;quot;opacity&amp;quot;: 0.5,&lt;br /&gt;
  &amp;quot;border&amp;quot;: &amp;quot;3px solid black&amp;quot;,&lt;br /&gt;
  &amp;quot;height&amp;quot;: &amp;quot;300px&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addStyleToClass(cssClassName: string, styleName: string, styleValue: any):&#039;&#039;&#039; &#039;&#039;&#039;void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as dojo.style(), but for all the nodes set with the specified cssClassName&lt;br /&gt;
Equivalent of &lt;br /&gt;
  &lt;br /&gt;
  dojo.query(`.${aclass}`).style(styleName, styleValue)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dojo.query(&amp;quot;#baz &amp;gt; div&amp;quot;).style({&lt;br /&gt;
  opacity:0.75,&lt;br /&gt;
  fontSize:&amp;quot;13pt&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanilla JS style&#039;&#039;&#039;&lt;br /&gt;
  $(&#039;my_element&#039;).style.display=&#039;none&#039;; // set&lt;br /&gt;
  var display = $(&#039;my_element&#039;).style.display; // get&lt;br /&gt;
  $(&#039;my_element&#039;).style.removeProperty(&#039;display&#039;); // remove&lt;br /&gt;
&lt;br /&gt;
=== Classes ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.addClass(node: ElementOrId, classes: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.removeClass(node: ElementOrId, classes: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.hasClass(node: ElementOrId, aclass: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.toggleClass(node: ElementOrId, aclass: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In many situations, many small CSS property updates can be replaced by a CSS class change (i.e., you add a CSS class to your element instead of applying all modifications manually).&lt;br /&gt;
&lt;br /&gt;
Advantages are:&lt;br /&gt;
* All your CSS stuff remains in your CSS file.&lt;br /&gt;
* You can add/remove a list of CSS modifications with a simple function and without error.&lt;br /&gt;
* You can test whether you applied the CSS to an element with the &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Example from &#039;&#039;Reversi&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // We add &amp;quot;possibleMove&amp;quot; to an element&lt;br /&gt;
    dojo.addClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
    // In our CSS file, the class is defined as:&lt;br /&gt;
    .possibleMove {&lt;br /&gt;
      background-color: white;&lt;br /&gt;
      opacity: 0.2;&lt;br /&gt;
      filter:alpha(opacity=20); /* For IE8 and earlier */  &lt;br /&gt;
      cursor: pointer;  &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     // So we&#039;ve applied 4 CSS property changes in one line of code.&lt;br /&gt;
&lt;br /&gt;
     // ... and when we need to check if a square is a possible move on the client side:&lt;br /&gt;
     if( dojo.hasClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; ) )&lt;br /&gt;
     { ... }&lt;br /&gt;
&lt;br /&gt;
     // ... and if we want to remove all possible moves in one line of code (see &amp;quot;dojo.query&amp;quot; method):&lt;br /&gt;
     dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanilla JS classList&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is the only exception where dojo versions are better&lt;br /&gt;
  // add class&lt;br /&gt;
  $(token_id).classList.addClass(&#039;possibleMove&#039;);&lt;br /&gt;
  // remove class&lt;br /&gt;
  $(token_id).classList.removeClass(&#039;possibleMove&#039;);&lt;br /&gt;
  // add 2 classes&lt;br /&gt;
  const myclasses = [&#039;a&#039;,&#039;b&#039;];&lt;br /&gt;
  $(token_id).classList.addClass(...myclasses);&lt;br /&gt;
  // add classes to query result&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.hand .card&amp;quot;).forEach((node)=&amp;gt;node.classList.addClass(&#039;possibleMove&#039;));&lt;br /&gt;
&lt;br /&gt;
=== Attributes ===&lt;br /&gt;
&lt;br /&gt;
;dojo.attr&lt;br /&gt;
&lt;br /&gt;
With dojo.attr you can access or change the value of an attribute or property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Get the title of a node&lt;br /&gt;
     var title = dojo.attr( id, &#039;title&#039; );&lt;br /&gt;
     // Change the height of a node&lt;br /&gt;
     dojo.attr( &#039;img_growing_tree&#039;, &#039;height&#039;, 100 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanilla JS attr&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
   $(token).id=new_id; // set attr for &amp;quot;id&amp;quot;&lt;br /&gt;
   var id = $(token).id; // get&lt;br /&gt;
&lt;br /&gt;
=== Queries ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.query(cssSelector: string): Element[]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.query, you can query a bunch of HTML elements with a single function, with a &amp;quot;CSS selector&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // All elements with class &amp;quot;possibleMove&amp;quot;:&lt;br /&gt;
     var elements = dojo.query( &#039;.possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Count number of tokens (i.e., elements of class &amp;quot;token&amp;quot;) on the board (i.e., the element with id &amp;quot;board&amp;quot;):&lt;br /&gt;
     dojo.query( &#039;#board .token&#039; ).length;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But what is really cool with dojo.query is that you can combine it with almost all methods above.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Trigger a method when the mouse enter in any element with class &amp;quot;meeple&amp;quot;:&lt;br /&gt;
     dojo.query( &#039;.meeple&#039; ).connect( &#039;onmouseenter&#039;, this, &#039;myMethodToTrigger&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Hide all meeples who are on the board&lt;br /&gt;
     dojo.query( &#039;#board .meeple&#039; ).style( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanilla JS query&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  var cards=document.querySelectorAll(&amp;quot;.hand .card&amp;quot;);// all cards in all hands&lt;br /&gt;
  var cards=$(&#039;hand&#039;).querySelectorAll(&amp;quot;.card&amp;quot;);// all cards in specific hand&lt;br /&gt;
  var card=document.querySelector(&amp;quot;.hand .card&amp;quot;);// first card or null if none (super handy)&lt;br /&gt;
&lt;br /&gt;
=== Creating and Destroying elements ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.empty(node: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove all children of the node element&lt;br /&gt;
   dojo.empty(&#039;my_hand&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.destroy(node: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove the element&lt;br /&gt;
   dojo.destroy(&#039;my_token&#039;);&lt;br /&gt;
&lt;br /&gt;
   dojo.query(&amp;quot;.green&amp;quot;, mynode).forEach(dojo.destroy); // this remove all subnode of class green from mynode&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.create(tag: string, attributes?: obj, parent?: ElementOrId): Element&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create element&lt;br /&gt;
&lt;br /&gt;
    dojo.create(&amp;quot;div&amp;quot;, { class: &amp;quot;yellow_arrow&amp;quot; }, parent); // this creates div with class yellow_array and places it in &amp;quot;parent&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.format_block(name: string, args: object): string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This bga function that takes global var from template file and substitute variables, typical use would be&lt;br /&gt;
&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                var div = this.bga.gameui.format_block(&#039;jstpl_player_board&#039;, player ); // var jstpl_player_board = ... is defined in .tpl file &lt;br /&gt;
Note: result is trimmed&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.format_string(name: string, args: object): string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This bga function just substitute variables in a string, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     var div = this.bga.gameui.format_string(&#039;&amp;lt;div color=&amp;quot;${player_color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, {player_color: &#039;#ff0000&#039;} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: result is trimmed&lt;br /&gt;
&lt;br /&gt;
Note: this can be replaced by using backquoted string now: &lt;br /&gt;
     const player_color =  &#039;#ff0000&#039;;&lt;br /&gt;
&lt;br /&gt;
    const div = ``;&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.format_string_recursive&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This bga function is similar to this.gameui.bga.format_string but is capable of processing recursive argument structures and translations. It is used to format server notifications.&lt;br /&gt;
&lt;br /&gt;
TODO: find better place for these function docs&lt;br /&gt;
&lt;br /&gt;
=== Moving elements ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.place(node: string | Element, refNode: ElementOrId, pos?: string | number): Element&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
dojo.place is the best function to insert HTML code somewhere in your game interface without breaking something. It is much better to use than the &#039;&#039;&#039;innerHTML=&#039;&#039;&#039; method if you must insert HTML tags and not only values.&lt;br /&gt;
&lt;br /&gt;
node: can be a string or a DOM node. If it is a string starting with “&amp;lt;”, it is assumed to be an HTML fragment, which will be created. Otherwise it is assumed to be an id of a DOM node. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Insert your HTML code as a child of a container element&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;div class=&#039;foo&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
pos: optional argument. Can be a number or one of the following strings: “before”, “after”, “replace”, “only”, “first”, or “last”. If omitted, “last” is assumed.&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;replace&amp;quot;: replace the container element with my_node element&lt;br /&gt;
* &amp;quot;first&amp;quot;: places the node as a child of the reference node. The node is placed as the first child.&lt;br /&gt;
* &amp;quot;last&amp;quot; (default): places the node as a child of the reference node. The node is placed as the last child.&lt;br /&gt;
* &amp;quot;before&amp;quot;: places the node right before the reference node.&lt;br /&gt;
* &amp;quot;after&amp;quot;: places the node right after the reference node.&lt;br /&gt;
* &amp;quot;only&amp;quot;: replaces all children of the reference node with the node.&lt;br /&gt;
&lt;br /&gt;
this parameter can be a positive integer. In this case, the node will be placed as a child of the reference node with this number (counting from 0). If the number is more than number of children, the node will be appended to the reference node making it the last child. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Replace all children of container with my_node &lt;br /&gt;
     dojo.place( $(&#039;my_node&#039;), &amp;quot;your_container_element_id&amp;quot;, &amp;quot;only&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also full doc on dojo.place: [https://dojotoolkit.org/reference-guide/1.7/dojo/place.html]&lt;br /&gt;
&lt;br /&gt;
Usually, when you want to insert some piece of HTML in your game interface, you should use &amp;quot;[[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
But you can also relocate elements like that. Note: it won&#039;t animate if you do that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.placeOnObject(mobile_obj: ElementOrId, target_obj: ElementOrId): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
places mobile_obj on target_obj, set the absolute positions and centers the mobile_obj on target_obj,&lt;br /&gt;
effect is immediate&lt;br /&gt;
&lt;br /&gt;
This is not really an animation, but placeOnObject is frequently used before starting an animation.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // (We just created an object &amp;quot;my_new_token&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  // Place the new token on current player board&lt;br /&gt;
  this.bga.gameui.placeOnObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;overall_player_board_&amp;quot;+this.bga.players.getCurrentPlayerId() );&lt;br /&gt;
  &lt;br /&gt;
  // Then slide it to its position on the board&lt;br /&gt;
  this.bga.gameui.slideToObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;a_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.placeOnObjectPos(mobile_obj: ElementOrId, target_obj: ElementOrId, target_x: number, target_y: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method works exactly like placeOnObject, except than you can specify some (x,y) coordinates (in px). This way, the center of &amp;quot;mobile_obj&amp;quot; will be placed to the specified x,y position relatively to the center of &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: the placement works differently from this.bga.gameui.slideToObjectPos&#039;&#039;, since coordinates are calculated based on the center of objects.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.attachToNewParent(mobile_obj: ElementOrId, target_obj: ElementOrId): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With this method, you change the HTML parent of &amp;quot;mobile_obj&amp;quot; element without moving it. &lt;br /&gt;
&amp;quot;target_obj&amp;quot; is the new parent of this element. The beauty of &lt;br /&gt;
attachToNewParent is that the mobile_obj element DOES NOT MOVE during this process.&lt;br /&gt;
&lt;br /&gt;
What happens is that the method calculate a relative position of mobile_obj to make sure it does not move after the HTML parent changes.&lt;br /&gt;
&lt;br /&gt;
Why using this method?&lt;br /&gt;
&lt;br /&gt;
Changing the HTML parent of an element can be useful for the following reasons:&lt;br /&gt;
* When the HTML parent moves, all its child are moving with them. If some game elements is no more linked with a parent HTML object, you may want to attach it to another place.&lt;br /&gt;
* The z_order (vertical order of display) depends on the position in the DOM, so you may need to change the parent of some game elements when they are moving in your game area.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CAREFUL&#039;&#039;&#039;: this function destroys original object and places a clone onto a new parent, this will break all references to this HTML element (ex: dojo.connect).&lt;br /&gt;
If you need version that does not destroy the object but the same otherwise see [[BGA_Studio_Cookbook#Attach_to_new_parent_without_destroying_the_object]]&lt;br /&gt;
&lt;br /&gt;
== Animations ==&lt;br /&gt;
&amp;lt;big&amp;gt;A new lib for animations has been added to the framework: &#039;&#039;&#039;[[BgaAnimations]]&#039;&#039;&#039;. &#039;&#039;We recommend to use it instead of the animations listed above.&#039;&#039;&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.bgaAnimationsActive()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Function to know if animations should be played. Animations should not be played in instantaneousMode (fast-replay mode), or if the tab is not displayed in the browser.&lt;br /&gt;
Returns a boolean saying if animations should be played.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  if (this.bga.gameui.bgaAnimationsActive()) {&lt;br /&gt;
    // play an animation&lt;br /&gt;
  } else {&lt;br /&gt;
    // just apply the end situation of the animation&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you use framework animation functions listed above, they already handle this check so you don&#039;t need it. It&#039;s useful if you write custom animations.&lt;br /&gt;
&lt;br /&gt;
===Dojo Animations===&lt;br /&gt;
&lt;br /&gt;
BGA animations is based on Dojo Animation ([http://dojotoolkit.org/documentation/tutorials/1.8/animation/ see tutorial here]).&lt;br /&gt;
&lt;br /&gt;
However, most of the time, you can just use methods below, which are built on top of Dojo Animation.&lt;br /&gt;
&lt;br /&gt;
Note: one interesting method from Dojo that could be useful from time to time is &amp;quot;Dojo.Animation&amp;quot;. It allows you to make any CSS property &amp;quot;slide&amp;quot; from one value to another.&lt;br /&gt;
&lt;br /&gt;
Note 2: the slideTo methods are not compatible with CSS transform (scale, zoom, rotate...). If possible, avoid using CSS transform on nodes that are being slided. Eventually, the only possible solution to make these 2 compatible is to disable all CSS transform properties, use slideToObjectPos/placeOnObjectPos, and then apply them again.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sliding===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.slideToObject(mobile_obj: ElementOrId, target_obj: ElementOrId, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use slideToObject to &amp;quot;slide&amp;quot; an element to a target position.&lt;br /&gt;
&lt;br /&gt;
Sliding element on the game area is the recommended and the most used way to animate your game interface. Using slides allow players to figure out what is happening on the game, as if they were playing with the real boardgame.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* mobile_obj: the ID of the object to move. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned.&lt;br /&gt;
* target_obj: the ID of the target object. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned. Note that it is not mandatory that mobile_obj and target_obj have the same size. If their size are different, the system slides the center of mobile_obj to the center of target_obj.&lt;br /&gt;
* duration: (optional) defines the duration in millisecond of the slide. The default is 500 milliseconds.&lt;br /&gt;
* delay: (optional). If you defines a delay, the slide will start only after this delay. This is particularly useful when you want to slide several object from the same position to the same position: you can give a 0ms delay to the first object, a 100ms delay to the second one, a 200ms delay to the third one, ... this way they won&#039;t be superposed during the slide.&lt;br /&gt;
&lt;br /&gt;
BE CAREFUL: The method returns an dojo.fx animation, so you can combine it with other animation if you want to. It means that you have to call the &amp;quot;play()&amp;quot; method, otherwise the animation WON&#039;T START.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.slideToObject( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.slideToObjectPos(mobile_obj: ElementOrId, target_obj: ElementOrId, target_x: number, target_y: number, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method does exactly the same as &amp;quot;slideToObject&amp;quot;, except than you can specify some (x,y) coordinates. This way, &amp;quot;mobile_obj&amp;quot; will slide to the specified x,y position relatively to &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example: slide a token to some place on the board, 10 pixels from the top:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.slideToObjectPos( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 0, 10 ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.slideTemporaryObject(mobile_obj_html: string, parent: ElementOrId, from: ElementOrId, to: ElementOrId, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is useful when you want to slide a temporary HTML object from one place to another. As this object does not exists before the animation and won&#039;t remain after, it could be complex to create this object (with dojo.place), to place it at its origin (with placeOnObject) to slide it (with slideToObject) and to make it disappear at the end.&lt;br /&gt;
&lt;br /&gt;
slideTemporaryObject does all of this for you:&lt;br /&gt;
* mobile_obj_html is a piece of HTML code that represent the object to slide.&lt;br /&gt;
* parent is the ID of an HTML element of your interface that will be the parent of this temporary HTML object.&lt;br /&gt;
* from is the ID of the origin of the slide.&lt;br /&gt;
* to is the ID of the target of the slide.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.slideTemporaryObject( &#039;&amp;lt;div class=&amp;quot;token_icon&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, &#039;tokens&#039;, &#039;my_origin_div&#039;, &#039;my_target_div&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: slideTemporaryObject triggers the animation, you don&#039;t have to call &amp;lt;code&amp;gt;.play()&amp;lt;/code&amp;gt; on it. It returns an Dojo animation with an extra `promise` field, allowing you to do &amp;lt;code&amp;gt;await this.bga.gameui.slideTemporaryObject(...).promise&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Destroy===&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.slideToObjectAndDestroy(mobile_obj: ElementOrId, target_obj: ElementOrId, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is a handy shortcut to slide an existing HTML object to some place then destroy it upon arrival. It can be used for example to move a victory token or a card from the board to the player panel to show that the player earns it, then destroy it when we don&#039;t need to keep it visible on the player panel.&lt;br /&gt;
&lt;br /&gt;
It works the same as this.bga.gameui.slideToObject and takes the same arguments, but it starts the animation. &lt;br /&gt;
&lt;br /&gt;
CAREFUL: Make sure nothing is creating the same object at the same time the animation is running, because this will cause some random disappearing effects&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.slideToObjectAndDestroy( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 1000, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: slideToObjectAndDestroy triggers the animation, you don&#039;t have to call &amp;lt;code&amp;gt;.play()&amp;lt;/code&amp;gt; on it. It returns an Dojo animation with an extra `promise` field, allowing you to do &amp;lt;code&amp;gt;await this.bga.gameui.slideToObjectAndDestroy(...).promise&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.fadeOutAndDestroy( node: string | Element, duration?: number, delay?: number):&#039;&#039;&#039; &#039;&#039;&#039;Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function fade out the target node, then destroy it. Its starts the animation.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.fadeOutAndDestroy( &amp;quot;a_card_that_must_disappear&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the HTML node still exists until during few milliseconds, until the fadeOut has been completed.&lt;br /&gt;
Make sure nothing is creating same object at the same time as animation is running, because you will be some random dissapearing effects&lt;br /&gt;
&lt;br /&gt;
Note: fadeOutAndDestroy triggers the animation, you don&#039;t have to call &amp;lt;code&amp;gt;.play()&amp;lt;/code&amp;gt; on it. It returns an Dojo animation with an extra `promise` field, allowing you to do &amp;lt;code&amp;gt;await this.bga.gameui.fadeOutAndDestroy(...).promise&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Rotating elements===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This example combines &amp;quot;Dojo.Animation&amp;quot; method and a CSS property transform that allow you to rotate the element.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// node is Element we rotating&lt;br /&gt;
		    var animation = new dojo.Animation({&lt;br /&gt;
			    curve: [fromDegree, toDegree],&lt;br /&gt;
			    onAnimate: (v) =&amp;gt; {&lt;br /&gt;
				    node.style.transform = &#039;rotate(&#039; + v + &#039;deg)&#039;;&lt;br /&gt;
			    } &lt;br /&gt;
		    });&lt;br /&gt;
		    &lt;br /&gt;
		    animation.play();  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BGA has its own interface to rotate&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.rotateTo(node: string | Element, degree: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It starts the animation, and stored the rotation degree in the class, so next time you rotate object - it is additive.&lt;br /&gt;
There is no animation hooks in this one, if you need to change any parameters use dojo animation above.&lt;br /&gt;
&lt;br /&gt;
There is also &#039;&#039;&#039;this.bga.gameui.rotateInstantTo&#039;&#039;&#039; with same signature which does not animate&lt;br /&gt;
&lt;br /&gt;
Note: rotateTo triggers the animation, you don&#039;t have to call &amp;lt;code&amp;gt;.play()&amp;lt;/code&amp;gt; on it. It returns an Dojo animation with an extra `promise` field, allowing you to do &amp;lt;code&amp;gt;await this.bga.gameui.rotateTo(...).promise&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Animation Callbacks===&lt;br /&gt;
&lt;br /&gt;
If you wish to run some code only after an animation has completed you can do this by linking a callback method to &#039;onEnd&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var animation_id = this.bga.gameui.slideToObject( mobile_obj, target_obj, 500 );&lt;br /&gt;
dojo.connect(animation_id, &#039;onEnd&#039;, () =&amp;gt; {&lt;br /&gt;
   // do something here&lt;br /&gt;
});&lt;br /&gt;
animation_id.play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you wish to call a second animation after the first (rather than general code) then you can use a dojo animation chain (see tutorial referenced above).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.bgaPlayDojoAnimation(anim)&#039;&#039;&#039;&lt;br /&gt;
* anim - the dojo animation&lt;br /&gt;
Play a dojo animation and returns a promise resolved when it ends.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  const anim = this.bga.gameui.slideToObject(`disc_${x}${y}`, `square${x}_${y}`);&lt;br /&gt;
  await this.bga.gameui.bgaPlayDojoAnimation(anim);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  const anim = dojo.fx.chain([&lt;br /&gt;
    dojo.fadeOut( { node: discDiv } ),&lt;br /&gt;
    dojo.fadeIn( { node: discDiv } ),&lt;br /&gt;
  ]);&lt;br /&gt;
  await this.bga.gameui.bgaPlayDojoAnimation(anim);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Players input ==&lt;br /&gt;
&lt;br /&gt;
=== Connecting ===&lt;br /&gt;
&#039;&#039;&#039;dojo.connect(element: Element, event: string, context: object, method: eventHandler): any&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.connect(element: Element, event: string, handler: eventHandler): any&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
Example: associate a click on an element (&amp;quot;my_element&amp;quot;) with one of our methods (&amp;quot;onClickOnMyElement&amp;quot;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      dojo.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, this, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same idea but based on query (i.e. all element of &#039;pet&#039; class)&lt;br /&gt;
      dojo.query(&amp;quot;.pet&amp;quot;).connect(&#039;onclick&#039;, this, &#039;onPet&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: if you need to disconnect the handler you have to store handler returned from this method, i.e.&lt;br /&gt;
   &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var handler = dojo.connect(...);&lt;br /&gt;
    ...&lt;br /&gt;
    dojo.disconnect(handler);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t store the handler - you have to destroy the object to disconnect it&lt;br /&gt;
&lt;br /&gt;
Typical function that implements the input handler will look like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onPet: function(event) {&lt;br /&gt;
    var id = event.currentTarget.id;&lt;br /&gt;
    console.log(&#039;onPet &#039; + id);&lt;br /&gt;
    dojo.stopEvent(event);&lt;br /&gt;
    if (this.gamedatas.gamestate.name == &#039;playerTurnPet&#039;) {&lt;br /&gt;
          this.bga.actions.performAction(&#039;actPlayPet&#039;, {card: id});&lt;br /&gt;
    } else {&lt;br /&gt;
          this.bga.dialogs.showMoveUnauthorized();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.connect(element: ElementOrId, event: string, method: eventHandler): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
      this.bga.gameui.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&lt;br /&gt;
Or you can use an in-place handler&lt;br /&gt;
&lt;br /&gt;
      this.bga.gameui.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, (e) =&amp;gt; { console.log(&#039;boo&#039;); } );&lt;br /&gt;
&lt;br /&gt;
Note that this function stores the connection handler. That is the only real difference between &#039;&#039;&#039;this.bga.gameui.connect&#039;&#039;&#039; and &#039;&#039;&#039;dojo.connect&#039;&#039;&#039;. If you plan to destroy the element you connected, you &#039;&#039;&#039;must&#039;&#039;&#039; call this.bga.gameui.disconnect() to prevent memory leaks.&lt;br /&gt;
This function is mainly for permanent objects - if you just want to connect the temp object you should probably not use this method but use dojo.connect which won&#039;t require any clean-up.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.connectClass(cssClassName: string, event: string, method: eventHandler): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as connect(), but for all the nodes set with the specified cssClassName.&lt;br /&gt;
 this.bga.gameui.connectClass(&#039;pet&#039;, &#039;onclick&#039;, &#039;onPet&#039;);&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.disconnect(element: ElementOrId, event: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disconnect event handler (previously registered with this.bga.gameui.connect or this.bga.gameui.connectClass).&lt;br /&gt;
&lt;br /&gt;
   this.bga.gameui.disconnect( $(&#039;my_element&#039;), &#039;onclick&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: dynamic connect/disconnect is for advanced cases ONLY, you should always connect elements statically if possible, i.e. in setup() method.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.disconnectAll(): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disconnect all previously registed event handlers (registered via this.bga.gameui.connect or this.bga.gameui.connectClass)&lt;br /&gt;
&lt;br /&gt;
  this.bga.gameui.disconnectAll();&lt;br /&gt;
&lt;br /&gt;
=== Actions ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.actions.performAction(action: string, args?: object, options: { lock: boolean, checkAction: boolean, checkPossibleActions?: boolean, ignoreDefaultErrorHandler?: boolean }): Promise&amp;lt;void&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Triggers an asynchronous action call in the php backend. Check more of what actions and arguments are possible in [[Main_game_logic:_Game.php#Actions_(autowired)]] docs.&lt;br /&gt;
&lt;br /&gt;
This method must be used to send a player&#039;s input to the game server. &#039;&#039;&#039;It should not be triggered programmatically&#039;&#039;&#039;, especially not in loops, in callbacks, in notifications, or in onEnteringState/onUpdateActionButtons/onLeavingState, in order not to create race conditions or break replay game and tutorial features. It should be used only in reaction to a user action in the interface.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
&lt;br /&gt;
* action: name of the action, as it is written in &amp;quot;possibleactions&amp;quot; of the current state.&lt;br /&gt;
* args: an object containing the call parameters to send to the action, can be undefined/omitted if action has no parameters. Note: the following arg names are forbidden : &amp;lt;code&amp;gt;$args / $activePlayerId/ $active_player_id / $currentPlayerId / $current_player_id&amp;lt;/code&amp;gt; to not mess with [https://en.doc.boardgamearena.com/State_classes:_State_directory#Functions_act* magic params].&lt;br /&gt;
* options: options to tweak the call with some defaults. Default is &amp;lt;code&amp;gt;{ lock: true, checkAction: true }&amp;lt;/code&amp;gt;.&lt;br /&gt;
** lock: (true by default) locks the user interface before any other action can be executed, that prevents user clicking on more buttons while this action is in progress. Set to false if you want to handle locking by yourself.&lt;br /&gt;
** checkAction: (true by default) check that action specified by &amp;quot;action&amp;quot; parameter in list of possible actions and user is active, only set to false in rare cases when some special out of turn actions are allowed.&lt;br /&gt;
&lt;br /&gt;
Important: this is asynchronous action, this means you should not be doing anything after this line of code except returning; If you want to do something after the call is resolved, use promise handlers - catch and then, see examples below.&lt;br /&gt;
&lt;br /&gt;
Example of a standard call without args:&lt;br /&gt;
  this.bga.actions.performAction(&#039;pass&#039;);&lt;br /&gt;
&lt;br /&gt;
Example of a standard call with action args:&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlayCard&#039;, { id: this.selectedCardId });&lt;br /&gt;
&lt;br /&gt;
Example of a call without checking action (because player is inactive in a multiactive state):&lt;br /&gt;
  this.bga.actions.performAction(&#039;actChangeMind&#039;, {}, { checkAction: false, checkPossibleActions: true });&lt;br /&gt;
&lt;br /&gt;
Example of a call without lock (because of a special action not directly related to the game flow):&lt;br /&gt;
  this.bga.actions.performAction(&#039;actSetAutoBid&#039;, { alwaysBidUntil: 500 }, { lock: false, checkAction: false });&lt;br /&gt;
&lt;br /&gt;
Example of call with an array of ids (to be used with #[IntArrayParam]) :&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlayCards&#039;, { ids: this.selectedCardIds });&lt;br /&gt;
&lt;br /&gt;
Example of call with aJSON object  (to be used with #[JsonParam], note the &amp;quot;stringify&amp;quot;) :&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlanComplexStuff&#039;, { answer: JSON.stringify(this.theJsonObject) });&lt;br /&gt;
&lt;br /&gt;
Example of call with reaction to exception:&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlayCard&#039;, { id: this.selectedCardId }).catch(()=&amp;gt;{ this.selectedCardId = undefined; });&lt;br /&gt;
&lt;br /&gt;
Example of call with reaction to success:&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlayCard&#039;, { id: this.selectedCardId }).then(()=&amp;gt;{ this.unselectAll(); });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technical note:&lt;br /&gt;
* This is a combination of checkAction and ajaxcall, returning a Promise which resolves when ajaxcall ends.&lt;br /&gt;
* The function return void promise - the php callback cannot return any result, any results must be handled via the notification mechanism if needed&lt;br /&gt;
* In case there is an error - error message itself handled by framework, you can use error in catch({ message, args }) but you should not be showing it - this is done already, except if you&#039;ve set ignoreDefaultErrorHandler: true&lt;br /&gt;
* If you migrate from this.bgaPerformAction and are using catch on the promise, the result will now be { message, args } instead of args, allowing you to get the args you sent in the exception.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.actions.ajaxcall(url, parameters, obj_callback, callback, callback_anycase?, ajax_method?: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: this.bga.actions.performAction is a simpler way to use ajax calls, ajaxcall stays in the doc for legacy reasons only and should not be used in new projects.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same warning as &#039;&#039;&#039;this.bga.actions.performAction&#039;&#039;&#039; about using on user action only.&lt;br /&gt;
&lt;br /&gt;
* url: the url of the action to perform. For a game, it must be: &amp;quot;/&amp;lt;mygame&amp;gt;/&amp;lt;mygame&amp;gt;/myAction.html&amp;quot;&lt;br /&gt;
* parameters: an array of parameter to send to the game server. &lt;br /&gt;
** Note that &amp;quot;lock: true&amp;quot; must always be specified in this list of parameters in order the interface can be locked during the server call. Cannot use lock: false - to not lock it has to be undefined.&lt;br /&gt;
** Note: Restricted parameter names (please don&#039;t use them):&lt;br /&gt;
*** &amp;quot;action&amp;quot;&lt;br /&gt;
*** &amp;quot;module&amp;quot;&lt;br /&gt;
*** &amp;quot;class&amp;quot;&lt;br /&gt;
* obj_callback: must be set to &amp;quot;this&amp;quot;.&lt;br /&gt;
* callback (non-optional but rarely used): a function to trigger when the server returns result and everything went fine (not used, as all data handling is done via notifications).&lt;br /&gt;
* callback_anycase: (optional) a function to trigger when the server returns ok OR error.  If no error this function is called with parameter value false. If an error occurred, the first parameter will be set to true, the second will contain the error message sent by the PHP back-end, and the third will contain an error code.&lt;br /&gt;
* ajax_method: (optional and rarely used) if you need to send large amounts of data (over 2048 bytes), you can set this parameter to &#039;post&#039; (all lower-case) to send a POST request as opposed to the default GET. This works, but was not officially documented, so only use if you really need to.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.actions.ajaxcall( &#039;/mygame/mygame/actMyAction.html&#039;, { lock: true, &lt;br /&gt;
   arg1: myarg1, &lt;br /&gt;
   arg2: myarg2&lt;br /&gt;
}, this, (result)=&amp;gt;{} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.actions.checkAction(action: string, nomessage?: boolean): boolean &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* if interface is locked it will return false and show message &amp;quot;An action is already in progress&amp;quot;, unless nomessage set to true &lt;br /&gt;
* if player is not active it will return false and show message &amp;quot;This is not your turn&amp;quot;, unless nomessage set to true &lt;br /&gt;
* if action is not in list of possible actions (defined by &amp;quot;possibleaction&amp;quot; in current game state) it will return false and show &amp;quot;This move is not authorized now&amp;quot; error (unconditionally).&lt;br /&gt;
* otherwise returns true&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  function onClickOnGameElement( evt )  {&lt;br /&gt;
     if( this.bga.actions.checkAction( &amp;quot;actMyAction&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.actions.checkPossibleActions(action: string): boolean&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* this is independent of the player being active, so can be used instead of this.bga.actions.checkAction(). This is particularly useful for multiplayer states when the player is not active in a &#039;player may like to change their mind&#039; scenario. Unlike this.bga.actions.checkAction, this function does NOT take interface locking into account &lt;br /&gt;
&lt;br /&gt;
* if action is not in list of possible actions (defined by &amp;quot;possibleaction&amp;quot; in current game state) it will return false and show &amp;quot;This move is not authorized now&amp;quot; error (unconditionally).&lt;br /&gt;
* otherwise returns true&lt;br /&gt;
&lt;br /&gt;
  function onChangeMyMind( evt )  {&lt;br /&gt;
     if( this.bga.actions.checkPossibleActions( &amp;quot;actMyAction&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.checkLock(nomessage?: boolean): boolean&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When using &amp;quot;lock: true&amp;quot; in ajax call you can use this function to check if the interface is in lock state (it will be locked during server call and notification processing).&lt;br /&gt;
This check can be used to block some other interactions which do not result in ajaxcall or if you want to suppress errors. Note: normally you only need to use this.bga.actions.checkAction(...), this is for advanced cases.&lt;br /&gt;
&lt;br /&gt;
It will also show error unless nomessage is set to true&lt;br /&gt;
&lt;br /&gt;
  function onChangeMyMind( evt )  {&lt;br /&gt;
     if( this.bga.gameui.checkLock() ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
== Notifications ==&lt;br /&gt;
&lt;br /&gt;
When something happens on the server side, your game interface Javascript logic received a notification.&lt;br /&gt;
If you have not done so yet check what notification are in [[Main_game_logic:_yourgamename.game.php#Notifications]]&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can handle these notifications on the client side.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.notifications.setupPromiseNotifications(params = undefined)&#039;&#039;&#039;&lt;br /&gt;
* params - the call parameters, by default { prefix: &#039;notif_&#039;, minDuration: 500, minDurationNoText: 1, logger: null, ignoreNotifications: [], onStart: undefined, onEnd: undefined, }.&lt;br /&gt;
Auto-detect all notifications declared on the game object (functions starting with `notif_`)  and register them with dojo.subscribe.&lt;br /&gt;
&lt;br /&gt;
Registered notifications will be synchronous and will have a minimum duration (if animations are active, by default 500ms with text and 1ms without).&lt;br /&gt;
&lt;br /&gt;
If the notification function returns a Promise, the notification will end when the promise AND the minimum durations are over.&lt;br /&gt;
If the notification function does not return a promise, it is considered as already resolved as soon as the minimum durations are over.&lt;br /&gt;
&lt;br /&gt;
In case of a notification function returning a Promise, the dev is responsible to make it resolve instantaneously if animations are not active.&lt;br /&gt;
&lt;br /&gt;
See `bgaAnimationsActive` to know if animations are active : https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Animations&lt;br /&gt;
&lt;br /&gt;
See `bgaPlayDojoAnimation` to handle dojo animations with promises : https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Animation_Callbacks&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  setupNotifications: function() {&lt;br /&gt;
    this.bga.notifications.setupPromiseNotifications();&lt;br /&gt;
  },    &lt;br /&gt;
  notif_playedCard: async function(args) {&lt;br /&gt;
    await this.getPlayerTable(args.playerId).playCard(args.card);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of setting custom values for all params :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  setupNotifications: function() {&lt;br /&gt;
    this.bga.notifications.setupPromiseNotifications({ &lt;br /&gt;
      prefix: &#039;notif_&#039;, // default is &#039;notif_&#039;&lt;br /&gt;
      minDuration: 1200, // for longer animations (500 by default)&lt;br /&gt;
      minDurationNoText: 1,&lt;br /&gt;
      handlers: [this.notificationsManager], // if you write your notif function in a subclass instead of this (default this)&lt;br /&gt;
      logger: console.log, // show notif debug informations on console. Could be console.warn or any custom debug function (default null = no logs)&lt;br /&gt;
      ignoreNotifications: [&#039;updateAutoPlay&#039;], // the notif_updateAutoPlay function will be ignored by bgaSetupPromiseNotifications. You&#039;ll need to subscribe to it manually&lt;br /&gt;
      onStart: (notifName, msg, args) =&amp;gt; $(&#039;pagemaintitletext&#039;).innerHTML = `${_(&#039;Animation for:&#039;)} ${msg}`, &lt;br /&gt;
      onEnd: (notifName, msg, args) =&amp;gt; $(&#039;pagemaintitletext&#039;).innerHTML = &#039;&#039;,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.wait(delay)&#039;&#039;&#039;&lt;br /&gt;
* delay - the time to wait, in milliseconds&lt;br /&gt;
Return a Promise that resolves at the end of a given number of ms. If animations are not active, resolve instantaneously.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  await this.bga.gameui.wait(500); // wait 500ms before continuing in an async function&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Subscribe to notifications manually ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.subscribe(notif_type: string, callback_obj: Object, handler: string|handler)&#039;&#039;&#039;&lt;br /&gt;
* notif_type - notification type/name send by php server&lt;br /&gt;
* callback_obj - usually this&lt;br /&gt;
* handler - if string method of callback_obj with name name is called, when notification is called, with notification object as parameter (see below)&lt;br /&gt;
&lt;br /&gt;
Your Javascript &amp;quot;setupNotifications&amp;quot; method is the place where you can subscribe to notifications from your PHP code.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you associate one of your Javascript method to a notification &amp;quot;playDisc&amp;quot; (from Reversi example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   setupNotifications: function() {&lt;br /&gt;
      ...&lt;br /&gt;
      dojo.subscribe(&#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot;);&lt;br /&gt;
   },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the &amp;quot;playDisc&amp;quot; corresponds to the name of the notification you define it in your PHP code, in your &amp;quot;notify-&amp;gt;all&amp;quot; or &amp;quot;notify-&amp;gt;player&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Then, you have to define your &amp;quot;notif_playDisc&amp;quot; method:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   notif_playDisc: function(notif) {&lt;br /&gt;
     // Remove current possible moves (makes the board more clear)&lt;br /&gt;
     dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );          &lt;br /&gt;
     this.addDiscOnBoard( notif.args.x, notif.args.y, notif.args.player_id );&lt;br /&gt;
   },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a notification handler like our &amp;quot;notif_playDisc&amp;quot; method, you can access all notifications arguments with &amp;quot;notif.args&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
PHP&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notify-&amp;gt;all( &amp;quot;apples&amp;quot;, clienttranslate(&#039;player takes ${count} apples&#039;), [ &amp;quot;count&amp;quot; =&amp;gt; 3 ] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
JavaScript&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setupNotifications: function() {&lt;br /&gt;
       dojo.subscribe( &#039;apples&#039;, this, &#039;notif_apples&#039; );&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    notif_apples: function(notif) {&lt;br /&gt;
      //You can access the &amp;quot;count&amp;quot; like this:&lt;br /&gt;
       alert(&amp;quot;count = &amp;quot; + notif.args.count);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The notification Object received by client ===&lt;br /&gt;
&lt;br /&gt;
When sending a notification on your PHP, the client side will receive an Object with the following attributes:&lt;br /&gt;
&lt;br /&gt;
* type - type of the notification (as passed by php function)&lt;br /&gt;
* log - the log string passed from php notification&lt;br /&gt;
* args - This is the arguments that you passed on your notification method on php&lt;br /&gt;
* bIsTableMsg - is true when you use [[Main_game_logic:_yourgamename.game.php#NotifyAllPlayers|Notify-&amp;gt;all]] method (false otherwise)&lt;br /&gt;
* channelorig - information about table ID (formatted as : &amp;quot;/table/t[TABLE_NUMBER]&amp;quot;)&lt;br /&gt;
* gamenameorig - name of the game&lt;br /&gt;
* move_id - ID of the move associated with the notification&lt;br /&gt;
* table_id - ID of the table (comes as string)&lt;br /&gt;
* time - UNIX GMT timestamp&lt;br /&gt;
* uid - unique identifier of the notification&lt;br /&gt;
* h - unknown&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; Note that those information were inferred from observation on console log. If an Admin can confirm/correct (and remove this line), you&#039;re welcome :)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ignoring notifications ===&lt;br /&gt;
&lt;br /&gt;
NOTE: With the new &amp;lt;code&amp;gt;_private&amp;lt;/code&amp;gt; arg in $this-&amp;gt;notify-&amp;gt;all, you should not need to ignore notifications anymore. See https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Sending_private_data_to_some_players for the new way of handling private data in notifications.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setIgnoreNotificationCheck(notif_type: string, predicate: ((notif: Notif)=&amp;gt;boolean))&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;If you need this function and you are in the Dev Discord, please read [https://discord.com/channels/753304735615811584/1448596273081876530/1448596273081876530 This thread] that might avoid the usage of &#039;&#039;&#039;setIgnoreNotificationCheck.&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method will set a check whether any of notifications of specific type should be ignored.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* notif_type: type of the notification &lt;br /&gt;
* predicate (notif =&amp;gt; boolean): a function that will receive notif object and will return true if this specific notification should be ignored&lt;br /&gt;
&lt;br /&gt;
Before dispatching any notification of this type, the framework will call predicate to check whether notification should be ignored, if it return true - the notification will be dispatched, i.e. logged or handled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.bga.gameui.notifqueue.setIgnoreNotificationCheck( &#039;dealCard&#039;, (notif) =&amp;gt; notif.args.player_id == this.bga.players.getCurrentPlayerId() );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: Remember that this notification is ignored on the client side, but was still received by the client. Therefore it shouldn&#039;t contain any private information as cheaters can get it. In other words this is not a way to hide information.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: When a game is reloaded with F5 or when opening a turn based game, old notifications are replayed as history notification. They are used just to update the game log and are stripped of all arguments except player_id, i18n and any argument present in message. If you use and other argument in your predicate you should &#039;&#039;&#039;preserve&#039;&#039;&#039; it as explained [[Main_game_logic:_yourgamename.game.php#Notify_players|here]].&lt;br /&gt;
&lt;br /&gt;
=== Handle manually synchronous notifications ===&lt;br /&gt;
&lt;br /&gt;
When several notifications are received by your game interface, these notifications are processed immediately, one after the other, in the same exact order they have been generated in your PHP game logic.&lt;br /&gt;
&lt;br /&gt;
However, sometimes, you need to give some time to the players to figure out what happened on the game before jumping to the next notification. Indeed, in many games, there are a lot of automatic actions, and the computer is going to resolve all these actions very fast if you don&#039;t tell it not to do so.&lt;br /&gt;
&lt;br /&gt;
As an example, for Reversi, when someone is playing a disc, we want to wait 500 milliseconds before doing anything else in order the opponent player can figure out what move has been played.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we do this, right after our subscription:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
    this.bga.gameui.notifqueue.setSynchronous( &#039;playDisc&#039;, 500 );   // Wait 500 milliseconds after executing the playDisc handler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
It is also possible to control the delay timing dynamically (e.g., using notification args). As an example, maybe your notification &#039;cardPlayed&#039; should pause for a different amount of time depending on the number or type of cards played.&lt;br /&gt;
&lt;br /&gt;
For this case, use &#039;&#039;&#039;setSynchronous&#039;&#039;&#039; without specifying the duration and use &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039; within the notification callback.&lt;br /&gt;
&lt;br /&gt;
* NOTE: If you forget to invoke &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039;, the game will remain paused forever!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupNotifications: function () {&lt;br /&gt;
    dojo.subscribe( &#039;cardPlayed&#039;, this, &#039;notif_cardPlayed&#039; );&lt;br /&gt;
    this.bga.gameui.notifqueue.setSynchronous( &#039;cardPlayed&#039; ); // wait time is dynamic&lt;br /&gt;
    ...&lt;br /&gt;
},&lt;br /&gt;
&lt;br /&gt;
notif_cardPlayed: function (notif) {&lt;br /&gt;
    // MUST call setSynchronousDuration&lt;br /&gt;
&lt;br /&gt;
    // Example 1: From notification args (PHP)&lt;br /&gt;
    this.bga.gameui.notifqueue.setSynchronousDuration(notif.args.duration);&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Or, example 2: Match the duration to a Dojo animation&lt;br /&gt;
    var anim = dojo.fx.combine([&lt;br /&gt;
        ...&lt;br /&gt;
    ]);&lt;br /&gt;
    anim.play();&lt;br /&gt;
    this.bga.gameui.notifqueue.setSynchronousDuration(anim.duration);&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also manually call this.bga.gameui.notifqueue.setSynchronousDuration(0) once client operations are finished, but be careful that even fast replay still has a path to call it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING: combining synchronous and ignored notifications&#039;&#039;&#039;&lt;br /&gt;
You must be careful when combining dynamic synchronous durations (as described above) with ignored notifications. If you have a conditionally ignored notification like this (see below section):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.bga.gameui.notifqueue.setIgnoreNotificationCheck( &#039;myNotif&#039;, (notif) =&amp;gt; (notif.args.player_id == this.bga.players.getCurrentPlayerId()) /* or any other condition */ )&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then you CANNOT do&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.bga.gameui.notifqueue.setSynchronous(&#039;myNotif&#039;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as, when the ignored check passes, the notification handler, in which `this.bga.gameui.notifqueue.setSychronousDuration` is called, is never called and so the duration is never set and interface locking results.&lt;br /&gt;
&lt;br /&gt;
The workaround is to set a &amp;quot;dummy&amp;quot; time:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.bga.gameui.notifqueue.setSynchronous(&#039;myNotif&#039;, 5000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whose value is irrelevant but must be large enough to cover the time before the notification handler is called. The large value never actually comes into play because the notification is either ignored, or the synchronous duration is reset to a sensible value inside the handler.&lt;br /&gt;
&lt;br /&gt;
=== Pre-defined notification types ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tableWindow&#039;&#039;&#039; - This defines notification to display [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialogs]], see below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;message&#039;&#039;&#039; - This defines notification that shows on players log and have no other effect (technically any unhandled notification will do the same but its recommended to use this keyword for consistency)&lt;br /&gt;
&lt;br /&gt;
   // You can call this on php side without doing anything on client side&lt;br /&gt;
    $this-&amp;gt;notify-&amp;gt;all( &#039;message&#039;, clienttranslate(&#039;hello&#039;), [] );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;simplePause&#039;&#039;&#039; - This notification will just delay other notifications, maybe useful if you know you need some extra time for animation or something. Requires a time parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notify-&amp;gt;all( &#039;simplePause&#039;, &#039;&#039;, [ &#039;time&#039; =&amp;gt; 500] ); // time is in milliseconds&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the following types are RESERVED by framework, do not use:&lt;br /&gt;
&lt;br /&gt;
gameStateChange gameStateChangePrivateArg gameStateMultipleActiveUpdate newActivePlayer playerstatus yourturnack clockalert tableInfosChanged playerEliminated tableDecision  archivewaitingdelay end_archivewaitingdelay replaywaitingdelay end_replaywaitingdelay replayinitialwaitingdelay end_replayinitialwaitingdelay aiPlayerWaitingDelay replay_has_ended updateSpectatorList  wouldlikethink updateReflexionTime undoRestorePoint resetInterfaceWithAllDatas zombieModeFail zombieModeFailWarning aiError skipTurnOfPlayer zombieBack allPlayersAreZombie gameResultNeutralized playerConcedeGame showTutorial showCursor showCursorClick skipTurnOfPlayerWarning  banFromTable resultsAvailable switchToTurnbased newPrivateState infomsg&lt;br /&gt;
&lt;br /&gt;
== Tooltips ==&lt;br /&gt;
&lt;br /&gt;
=== Adding static tooltips ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addTooltip(nodeId: string, helpStringTranslated: string, actionStringTranslated: string, delay?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to the DOM node.&lt;br /&gt;
&lt;br /&gt;
Specify &#039;helpStringTranslated&#039; to display some information about &amp;quot;what is this game element?&amp;quot;.&lt;br /&gt;
Specify &#039;actionStringTranslated&#039; to display some information about &amp;quot;what happens when I click on this element?&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You must specify both of the strings. You can only use one and specify an empty string (&#039;&#039;) for the other one.&lt;br /&gt;
&lt;br /&gt;
When you pass text directly function _() must be used for the text to be marked for translation! Except for empty string.&lt;br /&gt;
&lt;br /&gt;
Parameter &amp;quot;delay&amp;quot; is optional. It is primarily used to specify a zero delay for some game element when the tooltip gives really important information for the game - but remember: no essential information must be placed in tooltips as they won&#039;t be displayed in some browsers (see [[BGA_Studio_Guidelines|Guidelines]]).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.addTooltip( &#039;cardcount&#039;, _(&#039;Number of cards in hand&#039;), &#039;&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this generates static tooltip and attaches to existing dom element, if you need to generate tooltip more dynamically you have to call that method every time information about object is updated or use completely different tehnique, see dynamic tooltips below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addTooltipHtml(nodeId: string, html: string, delay?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to the DOM node (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addTooltipToClass(cssClass: string, helpStringTranslated: string, actionStringTranslated: string, delay?: number ): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to all the DOM nodes set with this cssClass. See more details above for this.bga.gameui.addTooltip.&lt;br /&gt;
     this.bga.gameui.addTooltipToClass( &#039;meeple&#039;, _(&#039;This is A Meeple&#039;), _(&#039;Click to tickle&#039;) );&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must exist and have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addTooltipHtmlToClass(cssClass: string, html: string, delay?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to to all the DOM nodes set with this cssClass (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must exist and have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
=== Removing static tooltips ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.removeTooltip(nodeId: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove a tooltip from the DOM node with given id.&lt;br /&gt;
&lt;br /&gt;
=== Advanced tooltips ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;force tooltip to open&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you want to force tooltip to open in reaction to some other action, i.e. click you can do this&lt;br /&gt;
&lt;br /&gt;
   this.bga.gameui.tooltips[id].open(id)&lt;br /&gt;
&lt;br /&gt;
where id is the id of the tooltip node where tooltip was installed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dynamic tooltips&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See [[BGA_Studio_Cookbook#Dynamic_tooltips]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tooltips on mobile&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Tooltips is very unreliable on mobile, it is recommended to implement some other method to obtaining same information,&lt;br /&gt;
such as simple click handler in dedicated &amp;quot;Help&amp;quot; mode or provide dedicated clickable areas such as corner of card.&lt;br /&gt;
&lt;br /&gt;
== Banners ==&lt;br /&gt;
&lt;br /&gt;
The framework comes with predefined banners.&lt;br /&gt;
&lt;br /&gt;
=== Last turn banner ===&lt;br /&gt;
When someone fulfills one of the end of the game conditions, so this is the last turn.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameArea.addLastTurnBanner(message?: string, args?: any): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If message is unset, default is &amp;quot;This is the last turn!&amp;quot;. For args example, see the addWinConditionBanner example that works the same way.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.bga.gameArea.addLastTurnBanner(&lt;br /&gt;
        _(&#039;This is the last turn! (deck is empty)&#039;)&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[File:Last turn banner example.png|center]]&lt;br /&gt;
&lt;br /&gt;
If the action triggering the last turn banner is cancelled, you can remove the banner by using&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameArea.removeLastTurnBanner(): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Win condition banner ===&lt;br /&gt;
When the game has multiple win conditions, use this function to display a message detailing which win condition was reached.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameArea.addWinConditionBanner(message?: string, args?: any): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    const winConditionText = _(&#039;${player_name} reached the Victory space of the Fame track and wins the game by being the most celebrated Monster!&#039;);&lt;br /&gt;
    this.bga.gameArea.addWinConditionBanner(&lt;br /&gt;
        winConditionText,&lt;br /&gt;
        { &#039;player_name&#039;: this.bga.players.getFormattedPlayerName(winnerId) }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[File:Win condition banner example.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Warning messages ==&lt;br /&gt;
&lt;br /&gt;
Sometimes, there is something important that is happening in the game and you have to make sure the player get the message. For example, explain why the player cannot do an action he can usually do when he clicks an element, if you don&#039;t need the PHP to validate the possibility.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.dialogs.showMessage(msg: string, type: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
showMessage shows a message in a big rectangular area on the top of the screen of the current player, and it disappears after few seconds (also it will be in the log in some cases).&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;msg&amp;quot; is the string to display. It should be translated.&lt;br /&gt;
* &amp;quot;type&amp;quot; can be set to &amp;quot;info&amp;quot;, &amp;quot;error&amp;quot;, &amp;quot;only_to_log&amp;quot; or custom string. If set to &amp;quot;info&amp;quot;, the message will be an informative message on a white background. If set to &amp;quot;error&amp;quot;, the message will be an error message on a red background and it will be added to log. If set to &amp;quot;only_to_log&amp;quot;, the message will be added to the game log but will not popup at the top of the screen.&lt;br /&gt;
If set to custom string, it will be transparent, to use custom type define &amp;quot;head_xxx&amp;quot; in css, where xxx is the type. For example if you want yellow warning, use &amp;quot;warning&amp;quot; as type and add this to css:&lt;br /&gt;
 .head_warning {&lt;br /&gt;
    background-color: #e6c66e;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Important: the normal way to inform players about the progression of the game is the game log. The &amp;quot;showMessage&amp;quot; is intrusive and should not be used often.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif_messageinfo: function(notif) {&lt;br /&gt;
	if (!g_archive_mode) {&lt;br /&gt;
        	var message = this.bga.gameui.format_string_recursive(notif.log, notif.args);&lt;br /&gt;
		this.bga.dialogs.showMessage(_(&#039;Announcement:&#039;) + &amp;quot; &amp;quot; + message, &#039;info&#039;);		&lt;br /&gt;
         }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Show message could be used on the client side to prevent user wrong moves before it is send to server.&lt;br /&gt;
Example from &#039;battleship&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onGrid: function(event) {&lt;br /&gt;
     if (checkIfPlayerTriesToFireOnThemselves(event)) {&lt;br /&gt;
        this.bga.dialogs.showMessage(_(&#039;This is your own board silly!&#039;), &#039;error&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
     }&lt;br /&gt;
     ...&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.dialogs.showMoveUnauthorized(): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Shows predefined user error that move is unauthorized now&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onPet: function(event) {&lt;br /&gt;
     if (checkPet(event)==false) {&lt;br /&gt;
        this.bga.dialogs.showMoveUnauthorized();&lt;br /&gt;
        return;&lt;br /&gt;
     }&lt;br /&gt;
     ...&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dialogs ==&lt;br /&gt;
&lt;br /&gt;
=== Confirmation dialog ===&lt;br /&gt;
&lt;br /&gt;
When an important action with a lot of consequences is triggered by the player, you may want to propose a confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the general guideline of BGA is to AVOID the use of confirmation dialogs. Confirmation dialogs slow down the game and bother players. The players know that they have to pay attention to each move when they are playing online.&lt;br /&gt;
&lt;br /&gt;
The situations where you should use a confirmation dialog are the following:&lt;br /&gt;
* It must not happen very often during a game.&lt;br /&gt;
* It must be linked to an action that can really &amp;quot;kill a game&amp;quot; if the player does not pay attention.&lt;br /&gt;
* It must be something that can be done by mistake (ex: a link on the action status bar).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.dialogs.confirmation(message: string): Promise&amp;lt;boolean&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* message - message will be shown to user, use _() to translate&lt;br /&gt;
NOTE: this is an async function, you must handle the consequence in the result of the promise&lt;br /&gt;
&lt;br /&gt;
How to display a confirmation dialog:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.bga.dialogs.confirmation(_(&amp;quot;Are you sure you want to bake a pie?&amp;quot;)).then(result =&amp;gt; {&lt;br /&gt;
      if (result) { &lt;br /&gt;
        this.bakeThePie();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
    return; // nothing should be called or done after calling this, all action must be done in the handler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you&#039;re migrating from this.confirmationDialog,  you&#039;ll need to move the callback function into the &amp;lt;code&amp;gt;then&amp;lt;/code&amp;gt; as it&#039;s now Promise-based&lt;br /&gt;
&lt;br /&gt;
=== Multiple choice dialog ===&lt;br /&gt;
&lt;br /&gt;
You can use this dialog to give user a choice with small amount of options&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.dialogs.multipleChoice(message: string, choices: string[]): Promise&amp;lt;string | null&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
* message - message will be shown to user, use _() to translate&lt;br /&gt;
* choices - array of choices&lt;br /&gt;
&lt;br /&gt;
NOTE: this is an async function, you must handle the consequence in the result of the promise. If the user cancels, it returns null.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    const keys = [&amp;quot;0&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;5&amp;quot;, &amp;quot;10&amp;quot;];&lt;br /&gt;
    this.bga.dialogs.multipleChoice(_(&amp;quot;How many bugs to fix?&amp;quot;), keys).then(choice =&amp;gt; {&lt;br /&gt;
      if (choice === null) { return; } // cancel operation, do not call server action&lt;br /&gt;
      const bugchoice = keys[choice]; // choice will be 0,1,2,3 here&lt;br /&gt;
      this.bga.actions.performAction(&amp;quot;fixBugs&amp;quot;, { number: bugchoice });&lt;br /&gt;
    });&lt;br /&gt;
    return; // must return here&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you&#039;re migrating from this.multipleChoiceDialog, you&#039;ll need to move the callback function into the &amp;lt;code&amp;gt;then&amp;lt;/code&amp;gt; as it&#039;s now Promise-based&lt;br /&gt;
&lt;br /&gt;
=== Generic Dialogs ===&lt;br /&gt;
&lt;br /&gt;
As a general rule, you shouldn&#039;t use dialogs windows.&lt;br /&gt;
&lt;br /&gt;
BGA guidelines specify that all game elements should be displayed on the main screen. Players can eventually scroll down to see game elements they don&#039;t need to see anytime, and you may eventually create anchors to move between game area section. Of course dialogs windows are very practical, but the thing is: all players know how to scroll down, and not all players know how to show up your dialog window. In addition, when the dialog shows up, players can&#039;t access the other game components.&lt;br /&gt;
&lt;br /&gt;
Sometimes although, you need to display a dialog window. Here is how you do this:&lt;br /&gt;
&lt;br /&gt;
  // Create the new dialog over the play zone. You should store the handler in a member variable to access it later&lt;br /&gt;
  this.myDlg = new ebg.popindialog();&lt;br /&gt;
  this.myDlg.create( &#039;myDialogUniqueId&#039; );&lt;br /&gt;
  this.myDlg.setTitle( _(&amp;quot;my dialog title to translate&amp;quot;) );&lt;br /&gt;
  this.myDlg.setMaxWidth( 500 ); // Optional&lt;br /&gt;
  &lt;br /&gt;
  // Create the HTML of my dialog. &lt;br /&gt;
  // The best practice here is to use [[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&lt;br /&gt;
  var html = this.gameui.format_block( &#039;jstpl_myDialogTemplate&#039;, { &lt;br /&gt;
                arg1: myArg1,&lt;br /&gt;
                arg2: myArg2,&lt;br /&gt;
                ...&lt;br /&gt;
            } );  &lt;br /&gt;
  &lt;br /&gt;
  // Show the dialog&lt;br /&gt;
  this.myDlg.setContent( html ); // Must be set before calling show() so that the size of the content is defined before positioning the dialog&lt;br /&gt;
  this.myDlg.show();&lt;br /&gt;
  &lt;br /&gt;
  // Now that the dialog has been displayed, you can connect your method to some dialog elements&lt;br /&gt;
  // Example, if you have an &amp;quot;OK&amp;quot; button in the HTML of your dialog:&lt;br /&gt;
  dojo.connect($(&#039;my_ok_button&#039;), &#039;onclick&#039;, this, (event) =&amp;gt; {&lt;br /&gt;
                event.preventDefault();&lt;br /&gt;
                this.myDlg.destroy();&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
If necessary, you can remove the default top right corner &#039;close&#039; icon, or replace the function called when it is clicked:&lt;br /&gt;
  // Removes the default close icon&lt;br /&gt;
  this.myDlg.hideCloseIcon();&lt;br /&gt;
&lt;br /&gt;
  // Replace the function call when it&#039;s clicked&lt;br /&gt;
  this.myDlg.replaceCloseCallback((event) =&amp;gt; { ... });&lt;br /&gt;
&lt;br /&gt;
=== Scoring dialogs ===&lt;br /&gt;
&lt;br /&gt;
Sometimes at the end of a round you want to display a big table that details the points wins in each section of the game.&lt;br /&gt;
&lt;br /&gt;
Example: in Hearts game, we display at the end of each round the number of &amp;quot;heart&amp;quot; cards collected by each player, the player who collected the Queen of Spades, and the total number of points loose by each player.&lt;br /&gt;
&lt;br /&gt;
Scoring dialogs are managed entirely on &#039;&#039;&#039;PHP side&#039;&#039;&#039;, but they are described here as their effects are visible only on client side.&lt;br /&gt;
&lt;br /&gt;
Displaying a scoring dialog is quite simple and is using a special notification type: &amp;quot;tableWindow&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // on PHP side:&lt;br /&gt;
  $this-&amp;gt;notify-&amp;gt;all( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table&lt;br /&gt;
        )); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;table&amp;quot; argument is a 2 dimensional PHP array that describes the table you want to display, line by line and column by column.&lt;br /&gt;
&lt;br /&gt;
Example: display an 3x3 array of strings&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = [&lt;br /&gt;
      [ &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, &amp;quot;three&amp;quot; ],    // This is my first line&lt;br /&gt;
      [ &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ],    // This is my second line&lt;br /&gt;
      [ &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; ]    // This is my third line&lt;br /&gt;
   ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see above, in each &amp;quot;cell&amp;quot; of your array you can display a simple string value. But you can also display a complex value with a template and associated arguments like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = [&lt;br /&gt;
      [ &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, [ &amp;quot;str&amp;quot; =&amp;gt; clienttranslate(&amp;quot;a string with an ${argument}&amp;quot;), &amp;quot;args&amp;quot; =&amp;gt; [ &#039;argument&#039; =&amp;gt; &#039;argument_value&#039; ] ] ],&lt;br /&gt;
      [ &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ], &lt;br /&gt;
      [ &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; ]&lt;br /&gt;
   ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is especially useful when you want to display player names with colors. Example from &amp;quot;Hearts&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $firstRow = [ &#039;&#039; ];&lt;br /&gt;
        foreach( $players as $player_id =&amp;gt; $player )    {&lt;br /&gt;
            $cell = [ &#039;str&#039; =&amp;gt; &#039;${player_name}&#039;,&lt;br /&gt;
                      &#039;args&#039; =&amp;gt; [ &#039;player_name&#039; =&amp;gt; $player[&#039;player_name&#039;] ],&lt;br /&gt;
                      &#039;type&#039; =&amp;gt; &#039;header&#039;&lt;br /&gt;
                    ];&lt;br /&gt;
            $firstRow[] = $cell;&lt;br /&gt;
        }&lt;br /&gt;
        $table[] = $firstRow;&lt;br /&gt;
        ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use three extra attributes in the parameter array for the notification:&lt;br /&gt;
* &#039;&#039;&#039;header&#039;&#039;&#039;: the content for this parameter displays before the table (also, the html will be parsed and player names will be colored according to the current game colors). &lt;br /&gt;
* &#039;&#039;&#039;footer&#039;&#039;&#039;: the content for this parameter displays after the table (no parsing for coloring the player names)&lt;br /&gt;
* &#039;&#039;&#039;closing&#039;&#039;&#039;: if this parameter is used, a button will be displayed with this label at the bottom of the popup and will allow players to close it (more easily than by clicking the top right &#039;cross&#039; icon).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $this-&amp;gt;notify-&amp;gt;all( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, [&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table,&lt;br /&gt;
            &amp;quot;header&amp;quot; =&amp;gt; [&#039;str&#039; =&amp;gt; clienttranslate(&#039;Table header with parameter ${number}&#039;),&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; [ &#039;number&#039; =&amp;gt; 3 ],&lt;br /&gt;
                               ],&lt;br /&gt;
            &amp;quot;footer&amp;quot; =&amp;gt; &#039;&amp;lt;div class=&amp;quot;myfoot&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;,&lt;br /&gt;
            &amp;quot;closing&amp;quot; =&amp;gt; clienttranslate( &amp;quot;Closing button label&amp;quot; )&lt;br /&gt;
        ] ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: currently id is not used - so you cannot access resulting div by id on js side &lt;br /&gt;
&lt;br /&gt;
Note: any translatable string have to be wrapped by clienttranslate() on top level OR it has to be recursive template. &lt;br /&gt;
&lt;br /&gt;
DO NOT DO THIS: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   &amp;quot;footer&amp;quot; =&amp;gt; &#039;&amp;lt;div&amp;gt;&#039;.clienttranslate( &amp;quot;The end&amp;quot; ).&#039;&amp;lt;/div&amp;gt;&#039;, // this will not work for translations!!!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Scoring animated display ===&lt;br /&gt;
&lt;br /&gt;
Sometimes, you may want to display a score value over an element to make the scoring easier to follow for the players (Terra Mystica final scoring for example).&lt;br /&gt;
You can do it with:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.displayScoring(anchor_id: string, color: string, score: number | string, duration?: number, offset_x?: number, offset_y?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;anchor_id&#039;&#039;&#039;: ID of the html element to place the animated score onto (without the &#039;#&#039;) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;color&#039;&#039;&#039;: hexadecimal RGB representation of the color (should be the color of the scoring player), but without a leading &#039;#&#039;.  For instance, &#039;ff0000&#039; for red.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;score&#039;&#039;&#039;: numeric score to display, prefixed by a &#039;+&#039; or &#039;-&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;duration&#039;&#039;&#039;: animation duration in milliseconds (optional, default is 1000)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;offset_x&#039;&#039;&#039; and &#039;&#039;&#039;offset_y&#039;&#039;&#039;: if both offset_x and offset_y are defined and not null, apply the following offset (in pixels) to the scoring animation. &lt;br /&gt;
Note that the score is centered in the anchor, so the offsets might have to be negative if you calculate the position.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: if you want to display successively each score, you can use &#039;&#039;this.bga.gameui.notifqueue.setSynchronous()&#039;&#039; function.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setupNotifications: function()   {&lt;br /&gt;
           dojo.subscribe( &#039;displayScoring&#039;, this, &amp;quot;notif_displayScoring&amp;quot; );&lt;br /&gt;
           ...&lt;br /&gt;
    }&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
    notif_displayScoring: function(notif) {&lt;br /&gt;
            const duration = notif.args.duration?notif.args.duration:1000;&lt;br /&gt;
            this.bga.gameui.notifqueue.setSynchronous(&#039;displayScoring&#039;, duration );&lt;br /&gt;
	    this.bga.gameui.displayScoring( notif.args.target, notif.args.color, notif.args.score, duration);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Speech bubble ===&lt;br /&gt;
&lt;br /&gt;
For better interactivity in some games (Love Letter for example), you may use comic book style speech bubbles to express the players voices.&lt;br /&gt;
This is done with showBubble:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.showBubble(anchor_id: string, text: string, delay?: number, duration?: number, custom_class?: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* anchor_id - where to attach the bubble&lt;br /&gt;
* text - what to put in bubble, can be html&lt;br /&gt;
* delay - delay in milliseconds (optional, default 0)&lt;br /&gt;
* duration -  duration of animation in milliseconds (optional, default 3000)&lt;br /&gt;
* custom_class - extra class to add to bubble (optional), if you need to override the default bubble style&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.showBubble(&#039;meeple_2&#039;, _(&#039;Hello&#039;), 0, 1000, &#039;pink_bubble&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  notif_speechBubble(notif) {&lt;br /&gt;
    var html = this.bga.gameui.format_string_recursive(notif.args.text, notif.args.args);&lt;br /&gt;
    this.bga.gameui.showBubble(notif.args.target, html, notif.args.delay ?? 0, notif.args.duration ?? 1000);&lt;br /&gt;
  },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: if your bubble could overlap other active elements of the interface (buttons in particular), as it stays in place even after disappearing, you should use a custom class to give it the style &amp;quot;pointer-events: none;&amp;quot; in order to intercept click events.&lt;br /&gt;
&lt;br /&gt;
Note: If you want this visually, but want to take complete control over this bubble and its animation (for example to make it permanent) you can just use div with &#039;discussion_bubble&#039; class on it, and content of div is what will be shown.&lt;br /&gt;
&lt;br /&gt;
== Translations ==&lt;br /&gt;
&lt;br /&gt;
See [[Translations]]&lt;br /&gt;
&lt;br /&gt;
== Players panels ==&lt;br /&gt;
&lt;br /&gt;
=== Adding stuff to player&#039;s panel ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.playerPanels.getElement(player_id: number): HTMLElement&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns the div in the player panel you can put your counters &amp;amp; other indicators in.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
Add this piece of code in your JS file to add this template to each player panel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Setting up player boards&lt;br /&gt;
            for( var player_id in gamedatas.players )&lt;br /&gt;
            {&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                         &lt;br /&gt;
                // Setting up players boards if needed&lt;br /&gt;
                const html = `&amp;lt;div class=&amp;quot;cp_board&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;stoneicon_p${player.id}&amp;quot; class=&amp;quot;gmk_stoneicon gmk_stoneicon_${player.color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;span id=&amp;quot;stonecount_p${player.id}&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;`;&lt;br /&gt;
                this.bga.playerPanels.getElement(player_id).insertAdjacentHTML(&#039;beforeend&#039;, html);&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Note: the code above is of course from your &amp;quot;setup&amp;quot; function in your Javascript).&lt;br /&gt;
&lt;br /&gt;
Very often, you have to distinguish current player and others players. In this case, you just have to change the content of the &amp;lt;code&amp;gt;html&amp;lt;/code&amp;gt; variable when &amp;quot;player_id&amp;quot; is different than &amp;quot;this.bga.players.getCurrentPlayerId()&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Adding a player panel for an automata ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.playerPanels.addAutomataPlayerPanel(id: number, name: string, params: Object): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The id is the automata id, used to setup the player panel score counter and getPlayerPanelElement. 0 or negative value is recommended, to avoid conflict with real player ids.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
*id: the automata id, used to setup the player panel score counter and getPlayerPanelElement. 0 or negative value is recommended, to avoid conflict with real player ids.&lt;br /&gt;
*name: the name of the automata&lt;br /&gt;
*params: object optionally containing one or more of the following:&lt;br /&gt;
**color: string - the automata player color (default black)&lt;br /&gt;
**iconClass: string - the class, or list of classes separated by spaces, to apply to the player picture.&lt;br /&gt;
**score: number - the automata score (default undefined, will display &#039;-&#039;)&lt;br /&gt;
&lt;br /&gt;
Example from Glow, with the automata Tom when playing solo :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.playerPanels.addAutomataPlayerPanel(0, &#039;Tom&#039;, {&lt;br /&gt;
    iconClass: &#039;tom-avatar&#039;,&lt;br /&gt;
    score: gamedatas.tom.score,&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s panel disabling/enabling ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.disablePlayerPanel(player_id: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disable given player panel (the panel background become gray).&lt;br /&gt;
&lt;br /&gt;
Usually, this is used to signal that this played passes, or will be inactive during a while.&lt;br /&gt;
&lt;br /&gt;
Note that the only effect of this is visual. There are no consequences on the behaviour of the panel itself.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.enablePlayerPanel(player_id:number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable a player panel that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.enableAllPlayerPanels(): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable all player panels that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
=== Player order ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.updatePlayerOrdering(): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function makes sure that player order in player&#039;s panel matches this.gamedatas.playerorder and its normally called by framework.&lt;br /&gt;
You can call it yoursel if you change this.gamedatas.playerorder from notification.&lt;br /&gt;
Also you can override this function to change defaults  OR insert a non-player panel [[BGA_Studio_Cookbook#Inserting_non-player_panel]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Counters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.playerPanels.getScoreCounter(player_id: number): Counter&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns the score counter on the player panel.&lt;br /&gt;
&lt;br /&gt;
To create other counters on the player panel, please use the &amp;quot;ebg/counter&amp;quot; library, documented at [[Counter]].&lt;br /&gt;
&lt;br /&gt;
== BGA GUI components ==&lt;br /&gt;
&lt;br /&gt;
BGA framework provides some useful ready-to-use components for the game interface:&lt;br /&gt;
&lt;br /&gt;
[[Studio#BGA_Studio_game_components_reference]]&lt;br /&gt;
&lt;br /&gt;
Note that each time you are using an additional component, you must declare it at the top of your Javascript file in the list of modules used.&lt;br /&gt;
&lt;br /&gt;
Example with the Game.js file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const BgaAnimations = await importEsmLib(&#039;bga-animations&#039;, &#039;1.x&#039;);&lt;br /&gt;
const [Counter, Stock] = await importDojoLibs([&amp;quot;ebg/counter&amp;quot;, &amp;quot;ebg/stock&amp;quot;]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example with the legacy way if you are using &amp;quot;ebg.stock&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;  /// &amp;lt;=== we are using ebg.stock module&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA Buttons ==&lt;br /&gt;
&lt;br /&gt;
=== Basic Button ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addActionButton(id: string, label: string, method: string | eventhandler, destination?: string, blinking?: boolean, color?: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Deprecated, use [https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Title_bar this.bga.statusBar.addActionButton] instead&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use this method to add an action button in the main action status bar (or other places).&lt;br /&gt;
&lt;br /&gt;
Arguments:&lt;br /&gt;
*id: an element ID that should be unique in your HTML DOM document.&lt;br /&gt;
*label: the text of the button. Should be translatable (use _() function). Note: this can also be any html, such as &amp;quot;&amp;lt;div class=&amp;quot;brick&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, see example below on how to make image action buttons.&lt;br /&gt;
*method: the name of your method that must be triggered when the player clicks on this button (can be name of the method on game class or handler).&lt;br /&gt;
*destination (optional): id of parent on where to add button, ONLY use in rare cases if location is not action bar. Use &#039;&#039;&#039;null&#039;&#039;&#039; as value if you need to specify other arguments.&lt;br /&gt;
*blinking (optional): if set to &#039;&#039;&#039;true&#039;&#039;&#039;, the button is going blink to catch player&#039;s attention. Please DO NOT abuse blinking button. If you need button to blink after some time passed add class &#039;blinking&#039; to the button later.&lt;br /&gt;
*color: could be &#039;&#039;&#039;blue&#039;&#039;&#039; (default), &#039;&#039;&#039;red&#039;&#039;&#039;,&#039;&#039;&#039;gray&#039;&#039;&#039; or &#039;&#039;&#039;none&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You should only use this method in your &amp;quot;onUpdateActionButtons&amp;quot; method. Usually, you use it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onUpdateActionButtons( stateName, args ) {                      &lt;br /&gt;
            if (this.players.isCurrentPlayerActive()) {            &lt;br /&gt;
                switch( stateName ) {&lt;br /&gt;
                case &#039;giveCards&#039;:&lt;br /&gt;
                    this.bga.statusBar.addActionButton(_(&#039;Give selected cards&#039;), () =&amp;gt; this.onGiveCards() ); &lt;br /&gt;
                    this.bga.statusBar.addActionButton(_(&#039;Pass&#039;), () =&amp;gt; this.actions.performAction(&#039;actPass&#039;) ); &lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are adding a &amp;quot;Give selected cards&amp;quot; button in the case we are on game state &amp;quot;giveCards&amp;quot;. When player clicks on this button, it triggers our &amp;quot;onGiveCards&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
===Image Button===&lt;br /&gt;
&lt;br /&gt;
You can use the same method, but add extra class to a button to disable the padding and style it, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.addActionButton( &#039;button_brick&#039;, &#039;&amp;lt;div class=&amp;quot;brick&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, ()=&amp;gt;{... on brick ...}, null, null, &#039;gray&#039;); &lt;br /&gt;
dojo.addClass(&#039;button_brick&#039;,&#039;bgaimagebutton&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.bgaimagebutton {&lt;br /&gt;
  padding: 0px 12px;&lt;br /&gt;
  min-height: 28px;&lt;br /&gt;
  border: none;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use this a lot, you can define a helper function, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This method can be used instead of addActionButton, to add a button which is an image (i.e. resource). Can be useful when player&lt;br /&gt;
 * need to make a choice of resources or tokens.&lt;br /&gt;
 */&lt;br /&gt;
addImageActionButton(id, div, handler, bcolor, tooltip) {&lt;br /&gt;
	if (typeof bcolor == &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
		bcolor = &amp;quot;gray&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
	// this will actually make a transparent button id color = gray&lt;br /&gt;
	this.bga.gameui.addActionButton(id, div, handler, null, false, bcolor);&lt;br /&gt;
	// remove border, for images it better without&lt;br /&gt;
	dojo.style(id, &amp;quot;border&amp;quot;, &amp;quot;none&amp;quot;);&lt;br /&gt;
	// but add shadow style (box-shadow, see css)&lt;br /&gt;
	dojo.addClass(id, &amp;quot;shadow bgaimagebutton&amp;quot;);&lt;br /&gt;
	// you can also add additional styles, such as background&lt;br /&gt;
	if (tooltip) {&lt;br /&gt;
		dojo.attr(id, &amp;quot;title&amp;quot;, tooltip);&lt;br /&gt;
	}&lt;br /&gt;
	return $(id);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Disabling Button===&lt;br /&gt;
&lt;br /&gt;
You can disable the &#039;&#039;&#039;bgabutton&#039;&#039;&#039; by adding the css class &#039;&#039;&#039;disabled&#039;&#039;&#039; in you js. The disabled button is still visible but is grey and not clickable.&lt;br /&gt;
For example in the &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039; : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.addActionButton(&#039;play_button_id&#039;, _(&#039;Play 1 to 3 cards&#039;), () =&amp;gt; this.playFunctionButton()); &lt;br /&gt;
if (condition) {&lt;br /&gt;
  dojo.addClass(&#039;play_button_id&#039;, &#039;disabled&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Custom Buttons===&lt;br /&gt;
&lt;br /&gt;
You can create a custom button, but the BGA framework provides a standard button that requires only .css classes: &#039;&#039;&#039;bgabutton&#039;&#039;&#039; and &#039;&#039;&#039;bgabutton_${color}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_blue&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My blue button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_red bgabutton_big&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My big red button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: To see it in action, check out &#039;&#039;Coloretto&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Button outside of action bar===&lt;br /&gt;
&lt;br /&gt;
Use addActionButton() method with destination argument set&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.addActionButton( &#039;commit_button&#039;, _(&#039;Confirm&#039;), () =&amp;gt; this.onConfirm(), &#039;player_board&#039;, true, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in example above the button will be place on object with id &#039;player_board&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Image loading ==&lt;br /&gt;
&lt;br /&gt;
See also [[Game_art:_img_directory]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Be careful&#039;&#039;&#039;: by default, ALL images at the root of your img directory are loaded on a player&#039;s browser when he loads the game. For this reason, don&#039;t let in your img directory images that are not useful, otherwise it&#039;s going to slowdown the game load. Images in a subfolder of img are NOT preloaded by default.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.images.dontPreloadImage(image_file_name: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.images.dontPreloadImages(image_file_names: string[])&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using dontPreloadImage, you tell the interface to not preload a specific image in your img directory. dontPreloadImages is the same for multiple images at once.&lt;br /&gt;
&lt;br /&gt;
Examples of use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// don&#039;t preload a particular image&lt;br /&gt;
this.bga.images.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
&lt;br /&gt;
// don&#039;t preload a list of unused images (gamedatas.clans contains the number of the clans used in this game).&lt;br /&gt;
this.bga.images.dontPreloadImages([1,2,3,4,5,6].filter(clan =&amp;gt; !gamedatas.clans.include(clan)).map(clan =&amp;gt; `clan${clan}.png`));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.images.preloadImage(image_file_name: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.images.preloadImages(image_file_names: string[])&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Opposite of dontPreloadImage, useful only for images that are not in the root img folder&lt;br /&gt;
Example of use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// preload a particular image&lt;br /&gt;
if (gamedatas.expansionActive) {&lt;br /&gt;
  this.bga.images.preloadImages([&#039;expansion/board.jpg&#039;, &#039;expansion/new-cards.jpg&#039;]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sounds ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.sounds.load(id: string, label: string, fileName: string = undefined): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Load a sound and register its id. Filename is without the extension. If fileName is unset, it will use the same as the id.&lt;br /&gt;
&lt;br /&gt;
In any case, the sound should be placed on your img folder and exist bothe with the mp3 and ogg format/extension.&lt;br /&gt;
&lt;br /&gt;
Examples :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.sounds.load(&#039;play&#039;); // will load play.ogg / play.mp3 in the img dir, and will be playable with id `play`&lt;br /&gt;
this.bga.sounds.load(&#039;claw&#039;, &#039;smash&#039;); // will load smash.ogg / smash.mp3 in the img dir, and will be playable with id `claw`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.sounds.play(id: string): void&#039;&#039;&#039;&lt;br /&gt;
Play a sound by its id, loaded in the setup with &#039;&#039;this.sounds.load&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Examples :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.sounds.play(&#039;play&#039;); &lt;br /&gt;
this.bga.sounds.play(&#039;claw&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.disableNextMoveSound(): void&#039;&#039;&#039;&lt;br /&gt;
Disable the standard &amp;quot;move&amp;quot; sound for this move (to replace it with your custom sound):&lt;br /&gt;
&lt;br /&gt;
Add this to your notification handler:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.disableNextMoveSound();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: it only disable the sound for the next move.&lt;br /&gt;
&lt;br /&gt;
== Status bar ==&lt;br /&gt;
&lt;br /&gt;
=== Status bar text ===&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;this.bga.statusBar.setTitle(title: string, args?: object)&#039;&#039;&#039;&lt;br /&gt;
Update the page title (aka status bar prompt). Can handle ${you} and ${actplayer} and any other var you would pass as args.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (args.mandatory_card_name) {&lt;br /&gt;
    const mandatoryCardTitle = this.bga.players.isCurrentPlayerActive() ? _(&#039;${you} must take ${mandatory_card_name}&#039;) : _(&#039;${actplayer} must take ${mandatory_card_name}&#039;);&lt;br /&gt;
    this.bga.statusBar.setTitle(mandatoryCardTitle, args);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
As opposed to &amp;lt;code&amp;gt;updatePageTitle&amp;lt;/code&amp;gt;, it doesn&#039;t trigger the call &amp;lt;code&amp;gt;onUpdateActionButtons&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;this.bga.gameui.updatePageTitle()&#039;&#039;&#039;&lt;br /&gt;
:This function allows to update the current page title and turn description according to the game state arguments. If the current game state description this.gamedatas.gamestate.descriptionmyturn is modified before calling this function it allows to update the turn description without changing state. This will handle arguments substitutions properly.&lt;br /&gt;
&lt;br /&gt;
Note: this functional also will calls this.onUpdateActionButtons, if you want different buttons then state defaults, use method in example to replace them, if it becomes too clumsy use client states (see above)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DEPRECATED:&amp;lt;/b&amp;gt; use this.bga.statusBar.setTitle instead.&lt;br /&gt;
&lt;br /&gt;
=== Status bar buttons ===&lt;br /&gt;
;&#039;&#039;&#039;this.bga.statusBar.addActionButton(label: string, callback: Function, params?: object): HTMLButtonElement&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
*label: the label to be shown, can be html. If label if used pass traslated string, i.e. _(&#039;Yes&#039;)&lt;br /&gt;
*callback: function to call on click, cannot be method name it has to be function&lt;br /&gt;
*params: object optionally containing one of more of the following:&lt;br /&gt;
**color: string - can be &amp;lt;code&amp;gt;primary&amp;lt;/code&amp;gt; (default) (blue), &amp;lt;code&amp;gt;secondary&amp;lt;/code&amp;gt; (gray), &amp;lt;code&amp;gt;alert&amp;lt;/code&amp;gt; (red)&lt;br /&gt;
**id: string - is the dom element id to set. If null/undefined, the button will not have an id, but you can still manipulate it by storing the reference to the DOM Element returned by the function&lt;br /&gt;
**classes: string|string[] - i.e &amp;lt;code&amp;gt;&#039;disabled blinking&#039;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;[&#039;disabled&#039;, &#039;blinking&#039;]&amp;lt;/code&amp;gt;.&lt;br /&gt;
**destination: ElementOrId - the DOM Element to add the button to. If not specified, will add it to the status bar.&lt;br /&gt;
**title: string - plain text description of the label. Should be set when the button label is an icon, for accessibility.&lt;br /&gt;
**disabled: boolean - makes the button disabled. Will prevent the callback to be executed&lt;br /&gt;
**tooltip: string - the tooltip of the button&lt;br /&gt;
**confirm: string | Function - the confirm message to display before triggering the callback, if set (or function handler, see example below).&lt;br /&gt;
**autoclick: boolean if the button should be auto clicked after a small delay (for Confirmation buttons).&lt;br /&gt;
&lt;br /&gt;
Example of a standard call without params:&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Pass&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actPass&#039;, {}));&lt;br /&gt;
&lt;br /&gt;
Example of a standard call with params:&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Pass&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actPass&#039;, {}), {&lt;br /&gt;
    id: &#039;my_button&#039;,&lt;br /&gt;
    color: &#039;secondary&#039;,&lt;br /&gt;
    classes: &#039;my-outline-class&#039;&lt;br /&gt;
    disabled: true,&lt;br /&gt;
    tooltip: _(&#039;You cannot pass&#039;),&lt;br /&gt;
    confirm: _(&#039;Are you sure to pass?&#039;),&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
Note: the confirm parameter can be a string or a function that returns a string or null&lt;br /&gt;
&lt;br /&gt;
Example of a standard call with params:&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Discard Selected Cards&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actDiscard&#039;, { cardIds: this.getSelectedCardIds().join(&#039;,&#039;) }), {&lt;br /&gt;
    confirm: () =&amp;gt; {&lt;br /&gt;
      if (this.getSelectedCardIds().length === 0) { // no card is selected, show the warning&lt;br /&gt;
        return _(&#039;Are you sure you don&#039;t want to discard any cards?&#039;);&lt;br /&gt;
      } else { // cards are selected, do not show the warning&lt;br /&gt;
        return null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
Example of confirm button with autoclick animation:&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Confirm&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actConfirm&#039;, {}), {&lt;br /&gt;
    autoclick: true&lt;br /&gt;
  });&lt;br /&gt;
  // if you have a user preference to auto-confirm&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Confirm&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actConfirm&#039;, {}), {&lt;br /&gt;
    autoclick: this.bga.userPreferences.get(100) == 1, // adapt to your user preference id and values&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;this.bga.statusBar.removeActionButtons()&#039;&#039;&#039;&lt;br /&gt;
Removes all buttons from title bar&lt;br /&gt;
&lt;br /&gt;
==User preferences ==&lt;br /&gt;
&#039;&#039;&#039;this.bga.userPreferences.get(pref_id)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return the value of a user preference. It will return the value currently selected in the select combo box, in the top-right menu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.userPreferences.set(pref_id, value)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Programmatically change a user preference. It will have the same effect as if the player changed the value in the select combo box, in the top-right menu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.userPreferences.onChange&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A callback you can define if you want to be notified when a user changes a user preference.&lt;br /&gt;
&lt;br /&gt;
Example:&amp;lt;pre&amp;gt;&lt;br /&gt;
// in your Game constructor&lt;br /&gt;
this.bga.userPreferences.onChange = (pref_id, pref_value) =&amp;gt; this.myGamePreferenceChanged(pref_id, pref_value);&lt;br /&gt;
&lt;br /&gt;
myGamePreferenceChanged: function(pref_id, pref_value) {&lt;br /&gt;
  switch (pref_id) {&lt;br /&gt;
    case 201: &lt;br /&gt;
      document.getElementsByTagName(&#039;html&#039;)[0].classList.toggle(&#039;dark-background&#039;, pref_value == 2);&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.userPreferences.toggleVisibility(pref_id, visible)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hide or show a user preference.&lt;br /&gt;
&lt;br /&gt;
Example:&amp;lt;pre&amp;gt;&lt;br /&gt;
myGamePreferenceChanged: function(pref_id, pref_value) {&lt;br /&gt;
  switch (pref_id) {&lt;br /&gt;
    case 101: &lt;br /&gt;
      // if pref 101 is &amp;quot;Confirm moves&amp;quot; and 102 is &amp;quot;Countdown timer on confirm&amp;quot;, we hide the countdown user preference when confirm moves is disabled.&lt;br /&gt;
      this.bga.userPreferences.toggleVisibility(102, prefValue != 2);&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Including classes from external files ==&lt;br /&gt;
You can declare multiple classes in the Game.js file, as long as you export a Game class in the end.&lt;br /&gt;
&lt;br /&gt;
If you want to split your code into multiple js files, export the classes of the file using &amp;lt;code&amp;gt;export class PlayerManager {...}&amp;lt;/code&amp;gt;. You can export multiple classes from the same file file that way.&lt;br /&gt;
&lt;br /&gt;
Then you can import the class in the Game.js file using &amp;lt;code&amp;gt;import { PlayerManager, PlayerTable } from &amp;quot;./PlayerManager.js&amp;quot;;&amp;lt;/code&amp;gt; at the top of the file.&lt;br /&gt;
&lt;br /&gt;
==Other useful stuff ==&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;this.bga.gameui.onScreenWidthChange()&#039;&#039;&#039;&lt;br /&gt;
:This function can be overridden in your game to manage some resizing on the client side when the browser window is resized. This function is also triggered at load time, so it can be used to adapt to the :viewport size at the start of the game too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;this.bga.gameui.bRealtime&lt;br /&gt;
:Return true if the game is in realtime. Note that having a distinct behavior in realtime and turn-based should be exceptional.&lt;br /&gt;
&lt;br /&gt;
;globalThis.g_replayFrom&lt;br /&gt;
:Global contains replay number in live game, it is set to undefined (i.e. not set) when it is not a replay mode, so consequentially the good check is &#039;&#039;&#039;typeof g_replayFrom != &#039;undefined&#039;&#039;&#039;&#039; which returns true if the game is in replay mode &amp;lt;i&amp;gt;during the game&amp;lt;/i&amp;gt; (the game is ongoing but the user clicked &amp;quot;replay from this move&amp;quot; in the log)&lt;br /&gt;
&lt;br /&gt;
;globalThis.g_archive_mode&lt;br /&gt;
:Returns true if the game is in archive mode &amp;lt;i&amp;gt;after the game&amp;lt;/i&amp;gt; (the game has ended)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;this.bga.gameui.instantaneousMode&lt;br /&gt;
:Returns true during replay/archive mode if animations should be skipped. Only needed if you are doing custom animations. (The BGA-provided animation functions like the bga-animations, bga-cards, bga-dice libs and &amp;lt;i&amp;gt;this.bga.gameui.slideToObject()&amp;lt;/i&amp;gt; and similar automatically handle instantaneous mode.)&lt;br /&gt;
:Technically, when you click &amp;quot;replay from move #20&amp;quot;, the system replays the game from the very beginning with moves 0 - 19 happening in instantaneous mode and moves 20+ happening in normal mode.&lt;br /&gt;
&lt;br /&gt;
;globalThis.g_tutorialwritten&lt;br /&gt;
:Returns an object like the below if the game is in tutorial mode, or undefined otherwise. Tutorial mode is a special case of archive mode where comments have been added to a previous game to teach new players the rules.&lt;br /&gt;
    {&lt;br /&gt;
        author: &amp;quot;91577332&amp;quot;,&lt;br /&gt;
        id: &amp;quot;576&amp;quot;,&lt;br /&gt;
        mode: &amp;quot;view&amp;quot;&lt;br /&gt;
        status: &amp;quot;alpha&amp;quot;&lt;br /&gt;
        version_override: null&lt;br /&gt;
        viewer_id: &amp;quot;84554161&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=28144</id>
		<title>Game interface logic: Game.js</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=28144"/>
		<updated>2026-01-20T13:24:45Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: addActionButton examples include args object to bgaPerformAction to help delineate the settings object to addActionButton.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
This is the main file for your game interface. Here you will define:&lt;br /&gt;
&lt;br /&gt;
* Which actions on the page will generate calls to the server.&lt;br /&gt;
* What happens when you get a notification for a change from the server and how it will show in the browser. &lt;br /&gt;
* Setup user interface&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; this file is now named Game.js, located in the modules/js directory. If you see it named yourgamename.js in the root dir, it&#039;s the legacy usage. In the legacy usage, the declaration is a bit different, as it uses define and declare to instanciate a JS object, while the new way exports a class (using ES Modules).&lt;br /&gt;
The new class doesn&#039;t extends gameui, so if you need to access some things from gameui that don&#039;t exist in the sub-components described above, you must use this.gameui.xx.&lt;br /&gt;
&lt;br /&gt;
== Framework sub-components ==&lt;br /&gt;
The framework is now split into multiple sub-components to group the related functions : statusBar, sounds, gameArea, playerPanels, images, userPreferences, players, actions, notifications, dialogs. All are available in the bga object sent to the constructor (or in this.bga for the legacy way).&lt;br /&gt;
&lt;br /&gt;
To make it accessible on the Game class, make it a property like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        constructor(bga){&lt;br /&gt;
            this.bga = bga;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In &amp;lt;mygamename&amp;gt;.js (the obsolete filename), this.bga is already set.&lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
&lt;br /&gt;
The details of how the file is structured are described below with comments in the code skeleton provided to you.&lt;br /&gt;
&lt;br /&gt;
Here is the basic structure:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;constructor&#039;&#039;&#039;: here you can define global variables for your whole interface.&lt;br /&gt;
* &#039;&#039;&#039;setup&#039;&#039;&#039;: this method is called when the page is refreshed, and sets up the game interface.&lt;br /&gt;
* &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;: this method is called when entering a new game state. You can use it to customize the view for each game state. &amp;lt;i&amp;gt;The function is optional, and not needed if you use JS State classes.&amp;lt;/i&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;onLeavingState&#039;&#039;&#039;: this method is called when leaving a game state. &amp;lt;i&amp;gt;The function is optional, and not needed if you use JS State classes.&amp;lt;/i&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039;: called on state changes, in order to add action buttons to the status bar. Note: in a MULTIPLE_ACTIVE_PLAYER state, it will be called when another player has become inactive. &amp;lt;i&amp;gt;The function is optional, and not needed if you use JS State classes.&amp;lt;/i&amp;gt;&lt;br /&gt;
* &#039;&#039;(utility methods)&#039;&#039;: this is where you can define your utility methods.&lt;br /&gt;
* &#039;&#039;(player&#039;s actions)&#039;&#039;: this is where you can write your handlers for player actions on the interface (example: click on an item).&lt;br /&gt;
* &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;: this method associates notifications with notification handlers. For each game notification, you can trigger a javascript method to handle it and update the game interface.&lt;br /&gt;
* &#039;&#039;(notification handlers)&#039;&#039;: this is where you define the notifications handlers associated with notifications in &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;, above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
More details:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setup(gamedatas: object)            &#039;&#039;&#039;&lt;br /&gt;
This method must set up the game user interface according to current game situation specified in parameters.&lt;br /&gt;
The method is called each time the game interface is displayed to a player, ie:&lt;br /&gt;
&lt;br /&gt;
* when the game starts&lt;br /&gt;
* when a player opens a game in the browser later &lt;br /&gt;
* when a player refreshes the game page (F5)&lt;br /&gt;
* when player does a server side Undo&lt;br /&gt;
&lt;br /&gt;
&amp;quot;gamedatas&amp;quot; argument contains all data retrieved by your &amp;quot;getAllDatas&amp;quot; PHP method and some more.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onEnteringState(stateName: string, args: { args: any } | null): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is called each time we enter a new game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
To access state arguments passed via calling php arg* method use args?.args.&lt;br /&gt;
Typically you would do something only for active player, using this.players.isCurrentPlayerActive() check.&lt;br /&gt;
It is also called (for the current game state only) when doing a browser refresh (after the setup method is called).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: for MULTIPLE_ACTIVE_PLAYER states:&lt;br /&gt;
the active players are NOT active yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/inactive status.&lt;br /&gt;
If you are doing initialization of some structures which do not depend on the active player, you can just replace (this.players.isCurrentPlayerActive()) with (!this.players.isCurrentPlayerSpectator()) &lt;br /&gt;
for the main switch in that method.&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Difference_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onLeavingState(stateName: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is called each time we leave a game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this point (i.e. cleanup).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onUpdateActionButtons(stateName: string, args: object | null): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this method you can manage &amp;quot;action buttons&amp;quot; that are displayed in the action status bar and highlight active UI elements.&lt;br /&gt;
To access state arguments passed via calling php arg* method use &#039;&#039;&#039;args&#039;&#039;&#039; parameter. Note: args can be null! For &#039;&#039;&#039;game&#039;&#039;&#039; states and when you don&#039;t supply state args function - it is null.&lt;br /&gt;
This method is called when the active or multiactive player changes. In a classic ACTIVE_PLAYER state this method is called before the onEnteringState state.&lt;br /&gt;
In MULTIPLE_ACTIVE_PLAYER state it is a mess. The sequencing of calls depends on whether you get into that state from transitions OR from reloading the whole game (i.e. F5).&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Difference_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
== States ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== JS State classes ===&lt;br /&gt;
To split the code of the Game class, you can create dedicated classes for each state you handle on the front side (some states like NextPlayer don&#039;t need to be handled on the JS side).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.register(stateIdOrName: string|number, stateClass: Object): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method links a state class to a state name. It should be used in the Game constructor like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Declare the State classes&lt;br /&gt;
        this.bga.states.register(&#039;PlayerTurn&#039;, new PlayerTurn(this, this.bga));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a state class is declared like this, the framework will call its onEnteringState... functions automatically. Example of JS State class:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
class PlayerTurn {&lt;br /&gt;
    constructor(game, bga) {&lt;br /&gt;
        this.game = game;&lt;br /&gt;
        this.bga = bga;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This method is called each time we are entering the game state. You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
     */&lt;br /&gt;
    onEnteringState(args, isCurrentPlayerActive) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This method is called each time we are leaving the game state. You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
     */&lt;br /&gt;
    onLeavingState(args, isCurrentPlayerActive) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * This method is called each time the current player becomes active or inactive in a MULTIPLE_ACTIVE_PLAYER state. You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
     * on MULTIPLE_ACTIVE_PLAYER states, you may want to call this function in onEnteringState using `this.onPlayerActivationChange(args, isCurrentPlayerActive)` at the end of onEnteringState.&lt;br /&gt;
     * If your state is not a MULTIPLE_ACTIVE_PLAYER one, you can delete this function.&lt;br /&gt;
     */&lt;br /&gt;
    onPlayerActivationChange(args, isCurrentPlayerActive) {&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // put custom functions only use on this state here&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getCurrentMainStateName(): string;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the current main state name (ignoring private states)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getCurrentPlayerStateName(): string;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the current player state name (private state name if there is one)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.logger: Function&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can write &amp;lt;code&amp;gt;this.bga.states.logger = console.log&amp;lt;/code&amp;gt; to show debug information about state changes in the console. Remove before going to production!&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getStateClass(stateName: string): Object&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get a state class (instance) by state name.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getCurrentMainStateClass(): Object;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the current main state class (instance) (ignoring private states)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getCurrentPlayerStateClass(): Object;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get the current player state class (instance) (private state if there is one)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.getStateClasses(): Object[];&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns the registered state classes (instances)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Client states===&lt;br /&gt;
&lt;br /&gt;
Client states is a way to simulate the state transition but without actually going to server. It is useful when you need to ask user multiple questions before you send things to server.&lt;br /&gt;
&lt;br /&gt;
Client states don&#039;t have a matching PHP class. They can be used with JS State classes, as long as the stateName declared in setClientState matches the registered JS State class.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.setClientState(stateName: string, args: Object): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
     this.bga.states.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                               descriptionmyturn : _(&amp;quot;${you} must select location&amp;quot;),&lt;br /&gt;
                           });&lt;br /&gt;
&lt;br /&gt;
For more information see [[BGA_Studio_Cookbook#Multi_Step_Interactions:_Select_Worker.2FPlace_Worker_-_Using_Client_States]]&lt;br /&gt;
&lt;br /&gt;
To add custom string interpolation for the state title, you can add them by using the args object like so:&lt;br /&gt;
     this.bga.states.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                              descriptionmyturn : _(&amp;quot;${you} must select location for card {$card_number}&amp;quot;),&lt;br /&gt;
                              args: { card_number: 5 },&lt;br /&gt;
                          });&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.restoreServerGameState(): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you are in client state it will restore the current server state (cheap undo)&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.states.isOnClientState(): boolean;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns if the current state is a client state&lt;br /&gt;
&lt;br /&gt;
== Dojo framework ==&lt;br /&gt;
&lt;br /&gt;
BGA uses the [http://dojotoolkit.org/ Dojo Javascript framework] internally.&lt;br /&gt;
&lt;br /&gt;
To implement a game, you don&#039;t need to use the outdated Dojo framework, as vanilla JS is now able to do the same things. Some example of Dojo will stay on this page to help you read old games code.&lt;br /&gt;
&lt;br /&gt;
== Javascript minimization (after July 2020) ==&lt;br /&gt;
&lt;br /&gt;
For performance reasons, when deploying a game the javascript code is minimized using &#039;&#039;&#039;terser&#039;&#039;&#039; (https://github.com/terser/terser). This minifier works with modern javascript syntax. From your project &amp;quot;Manage game&amp;quot; page, you can now test a minified version of your javascript on the studio (and revert to the original).&lt;br /&gt;
&lt;br /&gt;
NB: it has been reported that there is an issue with this minifier and percentage values for opacity.&lt;br /&gt;
&lt;br /&gt;
== Accessing Players Information ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getCurrentPlayerId(): number&#039;&#039;&#039;&lt;br /&gt;
id of the player who is looking at the game. The player may not be part of the game (i.e. spectator)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.isCurrentPlayerSpectator(): boolean&#039;&#039;&#039;&lt;br /&gt;
Flag set to true if the user at the table is a spectator (not a player).&lt;br /&gt;
&lt;br /&gt;
Note: If you want to hide an element from spectators, you should use [[Game_interface_stylesheet:_yourgamename.css#spectatorMode|CSS &#039;spectatorMode&#039; class]].&lt;br /&gt;
&lt;br /&gt;
You may consider making a function like this, to detect if the game is in a read-only state (i.e. non-interactive):&lt;br /&gt;
  // Returns true for spectators, instant replay (during game), archive mode (after game end)&lt;br /&gt;
  isReadOnly: function () {&lt;br /&gt;
    return this.bga.players.isCurrentPlayerSpectator() || typeof g_replayFrom != &#039;undefined&#039; || g_archive_mode;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.isCurrentPlayerActive(): boolean&#039;&#039;&#039;&lt;br /&gt;
Returns true if the player on whose browser the code is running is currently active (it&#039;s his turn to play). Note: see remarks above about usage of this function inside onEnteringState method.&lt;br /&gt;
  if (this.bga.players.isCurrentPlayerActive()) ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getActivePlayerId(): number&#039;&#039;&#039;&lt;br /&gt;
Return the ID of the active player, or null if we are not in an ACTIVE_PLAYER type state.&lt;br /&gt;
  if (args.player_id == this.bga.players.getActivePlayerId()) ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getActivePlayerIds(): number[]&#039;&#039;&#039;&lt;br /&gt;
Return an array with the IDs of players who are currently active (or an empty array if there are none).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getFormattedPlayerName(playerId): string&#039;&#039;&#039;&lt;br /&gt;
Get the HTML code to display the player name, in bold, with color (and color_back if needed)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.gamedatas: object&#039;&#039;&#039;&lt;br /&gt;
Contains the initial set of data to init the game, created at game start or by game refresh (F5).&lt;br /&gt;
You can update it as needed to keep an up-to-date reference of the game on the client side if you need it, however most of the time this is unnecessary.&lt;br /&gt;
&lt;br /&gt;
Note: In hotseat mode, the framework does not keep this.gamedatas of hotseat players and shares the same set as the main player to store data.&lt;br /&gt;
&lt;br /&gt;
Note: be careful when you update this data structurally, many framework functions expect data to be certain way and they will break if they see something else.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getPlayer(playerId): object&#039;&#039;&#039;&lt;br /&gt;
Return the player data stored in gamedatas.players. Can be undefined, if the player isn&#039;t at this table (spectator).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getActivePlayer(): object&#039;&#039;&#039;&lt;br /&gt;
Same as getPlayer for the active player.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.players.getCurrentPlayer(): object&#039;&#039;&#039;&lt;br /&gt;
Same as getPlayer for the current player.&lt;br /&gt;
&lt;br /&gt;
== Accessing and manipulating the DOM ==&lt;br /&gt;
&lt;br /&gt;
=== Main game area ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameAre.getElement(): HTMLElement&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns the div of the game area to put the game template into.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
Add this piece of code in your JS file, at the beginning of the setup function, to set the template :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                const html = `&amp;lt;div&amp;gt;&lt;br /&gt;
                    &amp;lt;div class=&amp;quot;round-counter&amp;quot;&amp;gt;${_(&#039;Round&#039;)} ${gamedatas.currentRound}/${gamedatas.totalRound}&amp;lt;/div&amp;gt;&lt;br /&gt;
                    &amp;lt;div&amp;gt;...anything else in your game template...&amp;lt;/div&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;`;&lt;br /&gt;
                this.bga.gameAre.getElement().insertAdjacentHTML(&#039;beforeend&#039;, html);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Element by Id ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$(elementId: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The $ function is used to get an HTML element using its &amp;quot;id&amp;quot; attribute.&lt;br /&gt;
&lt;br /&gt;
Example: modify the content of a &amp;quot;span&amp;quot; element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In your HTML code:&lt;br /&gt;
   &amp;lt;span id=&amp;quot;a_value_in_the_game_interface&amp;quot;&amp;gt;1234&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In your Javascript code:&lt;br /&gt;
   $(&#039;a_value_in_the_game_interface&#039;).innerHTML = &amp;quot;9999&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: It is safe to use if you don&#039;t know if variable is string (id of element) or element itself, i.e. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  foo: function(card) {&lt;br /&gt;
       card = $(card); // now its node, no need to write if (typeof card === &#039;string&#039;) ...&lt;br /&gt;
       // but its good idea to check for null here&lt;br /&gt;
       ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getElementById(elementId: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note: $() is the standard method to access some HTML element with the BGA Framework. You can use &#039;&#039;&#039;getElementById&#039;&#039;&#039; but it is longer to type and less handy as it does not do some checks.&lt;br /&gt;
&lt;br /&gt;
=== Style ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.style(node: ElementOrId, styleName: string, styleValue: any): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.style you can modify the CSS property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Make an element disappear&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Give an element a 2px border&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;borderWidth&#039;, &#039;2px&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Change the background position of an element&lt;br /&gt;
     // (very practical when you are using CSS sprites to transform an element to another)&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;backgroundPosition&#039;, &#039;-20px -50px&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you have to modify several CSS properties of an element, or if you have a complex CSS transformation to do, you should consider using dojo.addClass/dojo.removeClass (see below).&lt;br /&gt;
&lt;br /&gt;
You can also use object to set multiple values&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dojo.setStyle(&amp;quot;thinger&amp;quot;, {&lt;br /&gt;
  &amp;quot;opacity&amp;quot;: 0.5,&lt;br /&gt;
  &amp;quot;border&amp;quot;: &amp;quot;3px solid black&amp;quot;,&lt;br /&gt;
  &amp;quot;height&amp;quot;: &amp;quot;300px&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addStyleToClass(cssClassName: string, styleName: string, styleValue: any):&#039;&#039;&#039; &#039;&#039;&#039;void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as dojo.style(), but for all the nodes set with the specified cssClassName&lt;br /&gt;
Equivalent of &lt;br /&gt;
  &lt;br /&gt;
  dojo.query(`.${aclass}`).style(styleName, styleValue)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dojo.query(&amp;quot;#baz &amp;gt; div&amp;quot;).style({&lt;br /&gt;
  opacity:0.75,&lt;br /&gt;
  fontSize:&amp;quot;13pt&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanilla JS style&#039;&#039;&#039;&lt;br /&gt;
  $(&#039;my_element&#039;).style.display=&#039;none&#039;; // set&lt;br /&gt;
  var display = $(&#039;my_element&#039;).style.display; // get&lt;br /&gt;
  $(&#039;my_element&#039;).style.removeProperty(&#039;display&#039;); // remove&lt;br /&gt;
&lt;br /&gt;
=== Classes ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.addClass(node: ElementOrId, classes: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.removeClass(node: ElementOrId, classes: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.hasClass(node: ElementOrId, aclass: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.toggleClass(node: ElementOrId, aclass: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In many situations, many small CSS property updates can be replaced by a CSS class change (i.e., you add a CSS class to your element instead of applying all modifications manually).&lt;br /&gt;
&lt;br /&gt;
Advantages are:&lt;br /&gt;
* All your CSS stuff remains in your CSS file.&lt;br /&gt;
* You can add/remove a list of CSS modifications with a simple function and without error.&lt;br /&gt;
* You can test whether you applied the CSS to an element with the &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Example from &#039;&#039;Reversi&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // We add &amp;quot;possibleMove&amp;quot; to an element&lt;br /&gt;
    dojo.addClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
    // In our CSS file, the class is defined as:&lt;br /&gt;
    .possibleMove {&lt;br /&gt;
      background-color: white;&lt;br /&gt;
      opacity: 0.2;&lt;br /&gt;
      filter:alpha(opacity=20); /* For IE8 and earlier */  &lt;br /&gt;
      cursor: pointer;  &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     // So we&#039;ve applied 4 CSS property changes in one line of code.&lt;br /&gt;
&lt;br /&gt;
     // ... and when we need to check if a square is a possible move on the client side:&lt;br /&gt;
     if( dojo.hasClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; ) )&lt;br /&gt;
     { ... }&lt;br /&gt;
&lt;br /&gt;
     // ... and if we want to remove all possible moves in one line of code (see &amp;quot;dojo.query&amp;quot; method):&lt;br /&gt;
     dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanilla JS classList&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is the only exception where dojo versions are better&lt;br /&gt;
  // add class&lt;br /&gt;
  $(token_id).classList.addClass(&#039;possibleMove&#039;);&lt;br /&gt;
  // remove class&lt;br /&gt;
  $(token_id).classList.removeClass(&#039;possibleMove&#039;);&lt;br /&gt;
  // add 2 classes&lt;br /&gt;
  const myclasses = [&#039;a&#039;,&#039;b&#039;];&lt;br /&gt;
  $(token_id).classList.addClass(...myclasses);&lt;br /&gt;
  // add classes to query result&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.hand .card&amp;quot;).forEach((node)=&amp;gt;node.classList.addClass(&#039;possibleMove&#039;));&lt;br /&gt;
&lt;br /&gt;
=== Attributes ===&lt;br /&gt;
&lt;br /&gt;
;dojo.attr&lt;br /&gt;
&lt;br /&gt;
With dojo.attr you can access or change the value of an attribute or property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Get the title of a node&lt;br /&gt;
     var title = dojo.attr( id, &#039;title&#039; );&lt;br /&gt;
     // Change the height of a node&lt;br /&gt;
     dojo.attr( &#039;img_growing_tree&#039;, &#039;height&#039;, 100 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanilla JS attr&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
   $(token).id=new_id; // set attr for &amp;quot;id&amp;quot;&lt;br /&gt;
   var id = $(token).id; // get&lt;br /&gt;
&lt;br /&gt;
=== Queries ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.query(cssSelector: string): Element[]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.query, you can query a bunch of HTML elements with a single function, with a &amp;quot;CSS selector&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // All elements with class &amp;quot;possibleMove&amp;quot;:&lt;br /&gt;
     var elements = dojo.query( &#039;.possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Count number of tokens (i.e., elements of class &amp;quot;token&amp;quot;) on the board (i.e., the element with id &amp;quot;board&amp;quot;):&lt;br /&gt;
     dojo.query( &#039;#board .token&#039; ).length;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But what is really cool with dojo.query is that you can combine it with almost all methods above.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Trigger a method when the mouse enter in any element with class &amp;quot;meeple&amp;quot;:&lt;br /&gt;
     dojo.query( &#039;.meeple&#039; ).connect( &#039;onmouseenter&#039;, this, &#039;myMethodToTrigger&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Hide all meeples who are on the board&lt;br /&gt;
     dojo.query( &#039;#board .meeple&#039; ).style( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanilla JS query&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  var cards=document.querySelectorAll(&amp;quot;.hand .card&amp;quot;);// all cards in all hands&lt;br /&gt;
  var cards=$(&#039;hand&#039;).querySelectorAll(&amp;quot;.card&amp;quot;);// all cards in specific hand&lt;br /&gt;
  var card=document.querySelector(&amp;quot;.hand .card&amp;quot;);// first card or null if none (super handy)&lt;br /&gt;
&lt;br /&gt;
=== Creating and Destroying elements ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.empty(node: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove all children of the node element&lt;br /&gt;
   dojo.empty(&#039;my_hand&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.destroy(node: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove the element&lt;br /&gt;
   dojo.destroy(&#039;my_token&#039;);&lt;br /&gt;
&lt;br /&gt;
   dojo.query(&amp;quot;.green&amp;quot;, mynode).forEach(dojo.destroy); // this remove all subnode of class green from mynode&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.create(tag: string, attributes?: obj, parent?: ElementOrId): Element&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create element&lt;br /&gt;
&lt;br /&gt;
    dojo.create(&amp;quot;div&amp;quot;, { class: &amp;quot;yellow_arrow&amp;quot; }, parent); // this creates div with class yellow_array and places it in &amp;quot;parent&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.format_block(name: string, args: object): string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This bga function that takes global var from template file and substitute variables, typical use would be&lt;br /&gt;
&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                var div = this.bga.gameui.format_block(&#039;jstpl_player_board&#039;, player ); // var jstpl_player_board = ... is defined in .tpl file &lt;br /&gt;
Note: result is trimmed&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.format_string(name: string, args: object): string&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This bga function just substitute variables in a string, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     var div = this.bga.gameui.format_string(&#039;&amp;lt;div color=&amp;quot;${player_color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, {player_color: &#039;#ff0000&#039;} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: result is trimmed&lt;br /&gt;
&lt;br /&gt;
Note: this can be replaced by using backquoted string now: &lt;br /&gt;
     const player_color =  &#039;#ff0000&#039;;&lt;br /&gt;
&lt;br /&gt;
    const div = ``;&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.format_string_recursive&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This bga function is similar to this.gameui.bga.format_string but is capable of processing recursive argument structures and translations. It is used to format server notifications.&lt;br /&gt;
&lt;br /&gt;
TODO: find better place for these function docs&lt;br /&gt;
&lt;br /&gt;
=== Moving elements ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.place(node: string | Element, refNode: ElementOrId, pos?: string | number): Element&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
dojo.place is the best function to insert HTML code somewhere in your game interface without breaking something. It is much better to use than the &#039;&#039;&#039;innerHTML=&#039;&#039;&#039; method if you must insert HTML tags and not only values.&lt;br /&gt;
&lt;br /&gt;
node: can be a string or a DOM node. If it is a string starting with “&amp;lt;”, it is assumed to be an HTML fragment, which will be created. Otherwise it is assumed to be an id of a DOM node. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Insert your HTML code as a child of a container element&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;div class=&#039;foo&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
pos: optional argument. Can be a number or one of the following strings: “before”, “after”, “replace”, “only”, “first”, or “last”. If omitted, “last” is assumed.&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;replace&amp;quot;: replace the container element with my_node element&lt;br /&gt;
* &amp;quot;first&amp;quot;: places the node as a child of the reference node. The node is placed as the first child.&lt;br /&gt;
* &amp;quot;last&amp;quot; (default): places the node as a child of the reference node. The node is placed as the last child.&lt;br /&gt;
* &amp;quot;before&amp;quot;: places the node right before the reference node.&lt;br /&gt;
* &amp;quot;after&amp;quot;: places the node right after the reference node.&lt;br /&gt;
* &amp;quot;only&amp;quot;: replaces all children of the reference node with the node.&lt;br /&gt;
&lt;br /&gt;
this parameter can be a positive integer. In this case, the node will be placed as a child of the reference node with this number (counting from 0). If the number is more than number of children, the node will be appended to the reference node making it the last child. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Replace all children of container with my_node &lt;br /&gt;
     dojo.place( $(&#039;my_node&#039;), &amp;quot;your_container_element_id&amp;quot;, &amp;quot;only&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also full doc on dojo.place: [https://dojotoolkit.org/reference-guide/1.7/dojo/place.html]&lt;br /&gt;
&lt;br /&gt;
Usually, when you want to insert some piece of HTML in your game interface, you should use &amp;quot;[[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
But you can also relocate elements like that. Note: it won&#039;t animate if you do that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.placeOnObject(mobile_obj: ElementOrId, target_obj: ElementOrId): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
places mobile_obj on target_obj, set the absolute positions and centers the mobile_obj on target_obj,&lt;br /&gt;
effect is immediate&lt;br /&gt;
&lt;br /&gt;
This is not really an animation, but placeOnObject is frequently used before starting an animation.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // (We just created an object &amp;quot;my_new_token&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  // Place the new token on current player board&lt;br /&gt;
  this.bga.gameui.placeOnObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;overall_player_board_&amp;quot;+this.bga.players.getCurrentPlayerId() );&lt;br /&gt;
  &lt;br /&gt;
  // Then slide it to its position on the board&lt;br /&gt;
  this.bga.gameui.slideToObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;a_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.placeOnObjectPos(mobile_obj: ElementOrId, target_obj: ElementOrId, target_x: number, target_y: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method works exactly like placeOnObject, except than you can specify some (x,y) coordinates (in px). This way, the center of &amp;quot;mobile_obj&amp;quot; will be placed to the specified x,y position relatively to the center of &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: the placement works differently from this.bga.gameui.slideToObjectPos&#039;&#039;, since coordinates are calculated based on the center of objects.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.attachToNewParent(mobile_obj: ElementOrId, target_obj: ElementOrId): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With this method, you change the HTML parent of &amp;quot;mobile_obj&amp;quot; element without moving it. &lt;br /&gt;
&amp;quot;target_obj&amp;quot; is the new parent of this element. The beauty of &lt;br /&gt;
attachToNewParent is that the mobile_obj element DOES NOT MOVE during this process.&lt;br /&gt;
&lt;br /&gt;
What happens is that the method calculate a relative position of mobile_obj to make sure it does not move after the HTML parent changes.&lt;br /&gt;
&lt;br /&gt;
Why using this method?&lt;br /&gt;
&lt;br /&gt;
Changing the HTML parent of an element can be useful for the following reasons:&lt;br /&gt;
* When the HTML parent moves, all its child are moving with them. If some game elements is no more linked with a parent HTML object, you may want to attach it to another place.&lt;br /&gt;
* The z_order (vertical order of display) depends on the position in the DOM, so you may need to change the parent of some game elements when they are moving in your game area.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CAREFUL&#039;&#039;&#039;: this function destroys original object and places a clone onto a new parent, this will break all references to this HTML element (ex: dojo.connect).&lt;br /&gt;
If you need version that does not destroy the object but the same otherwise see [[BGA_Studio_Cookbook#Attach_to_new_parent_without_destroying_the_object]]&lt;br /&gt;
&lt;br /&gt;
== Animations ==&lt;br /&gt;
&amp;lt;big&amp;gt;A new lib for animations has been added to the framework: &#039;&#039;&#039;[[BgaAnimations]]&#039;&#039;&#039;. &#039;&#039;We recommend to use it instead of the animations listed above.&#039;&#039;&amp;lt;/big&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.bgaAnimationsActive()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Function to know if animations should be played. Animations should not be played in instantaneousMode (fast-replay mode), or if the tab is not displayed in the browser.&lt;br /&gt;
Returns a boolean saying if animations should be played.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  if (this.bga.gameui.bgaAnimationsActive()) {&lt;br /&gt;
    // play an animation&lt;br /&gt;
  } else {&lt;br /&gt;
    // just apply the end situation of the animation&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you use framework animation functions listed above, they already handle this check so you don&#039;t need it. It&#039;s useful if you write custom animations.&lt;br /&gt;
&lt;br /&gt;
===Dojo Animations===&lt;br /&gt;
&lt;br /&gt;
BGA animations is based on Dojo Animation ([http://dojotoolkit.org/documentation/tutorials/1.8/animation/ see tutorial here]).&lt;br /&gt;
&lt;br /&gt;
However, most of the time, you can just use methods below, which are built on top of Dojo Animation.&lt;br /&gt;
&lt;br /&gt;
Note: one interesting method from Dojo that could be useful from time to time is &amp;quot;Dojo.Animation&amp;quot;. It allows you to make any CSS property &amp;quot;slide&amp;quot; from one value to another.&lt;br /&gt;
&lt;br /&gt;
Note 2: the slideTo methods are not compatible with CSS transform (scale, zoom, rotate...). If possible, avoid using CSS transform on nodes that are being slided. Eventually, the only possible solution to make these 2 compatible is to disable all CSS transform properties, use slideToObjectPos/placeOnObjectPos, and then apply them again.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sliding===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.slideToObject(mobile_obj: ElementOrId, target_obj: ElementOrId, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use slideToObject to &amp;quot;slide&amp;quot; an element to a target position.&lt;br /&gt;
&lt;br /&gt;
Sliding element on the game area is the recommended and the most used way to animate your game interface. Using slides allow players to figure out what is happening on the game, as if they were playing with the real boardgame.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* mobile_obj: the ID of the object to move. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned.&lt;br /&gt;
* target_obj: the ID of the target object. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned. Note that it is not mandatory that mobile_obj and target_obj have the same size. If their size are different, the system slides the center of mobile_obj to the center of target_obj.&lt;br /&gt;
* duration: (optional) defines the duration in millisecond of the slide. The default is 500 milliseconds.&lt;br /&gt;
* delay: (optional). If you defines a delay, the slide will start only after this delay. This is particularly useful when you want to slide several object from the same position to the same position: you can give a 0ms delay to the first object, a 100ms delay to the second one, a 200ms delay to the third one, ... this way they won&#039;t be superposed during the slide.&lt;br /&gt;
&lt;br /&gt;
BE CAREFUL: The method returns an dojo.fx animation, so you can combine it with other animation if you want to. It means that you have to call the &amp;quot;play()&amp;quot; method, otherwise the animation WON&#039;T START.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.slideToObject( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.slideToObjectPos(mobile_obj: ElementOrId, target_obj: ElementOrId, target_x: number, target_y: number, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method does exactly the same as &amp;quot;slideToObject&amp;quot;, except than you can specify some (x,y) coordinates. This way, &amp;quot;mobile_obj&amp;quot; will slide to the specified x,y position relatively to &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example: slide a token to some place on the board, 10 pixels from the top:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.slideToObjectPos( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 0, 10 ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.slideTemporaryObject(mobile_obj_html: string, parent: ElementOrId, from: ElementOrId, to: ElementOrId, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is useful when you want to slide a temporary HTML object from one place to another. As this object does not exists before the animation and won&#039;t remain after, it could be complex to create this object (with dojo.place), to place it at its origin (with placeOnObject) to slide it (with slideToObject) and to make it disappear at the end.&lt;br /&gt;
&lt;br /&gt;
slideTemporaryObject does all of this for you:&lt;br /&gt;
* mobile_obj_html is a piece of HTML code that represent the object to slide.&lt;br /&gt;
* parent is the ID of an HTML element of your interface that will be the parent of this temporary HTML object.&lt;br /&gt;
* from is the ID of the origin of the slide.&lt;br /&gt;
* to is the ID of the target of the slide.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.slideTemporaryObject( &#039;&amp;lt;div class=&amp;quot;token_icon&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, &#039;tokens&#039;, &#039;my_origin_div&#039;, &#039;my_target_div&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: slideTemporaryObject triggers the animation, you don&#039;t have to call &amp;lt;code&amp;gt;.play()&amp;lt;/code&amp;gt; on it. It returns an Dojo animation with an extra `promise` field, allowing you to do &amp;lt;code&amp;gt;await this.bga.gameui.slideTemporaryObject(...).promise&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Destroy===&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.slideToObjectAndDestroy(mobile_obj: ElementOrId, target_obj: ElementOrId, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is a handy shortcut to slide an existing HTML object to some place then destroy it upon arrival. It can be used for example to move a victory token or a card from the board to the player panel to show that the player earns it, then destroy it when we don&#039;t need to keep it visible on the player panel.&lt;br /&gt;
&lt;br /&gt;
It works the same as this.bga.gameui.slideToObject and takes the same arguments, but it starts the animation. &lt;br /&gt;
&lt;br /&gt;
CAREFUL: Make sure nothing is creating the same object at the same time the animation is running, because this will cause some random disappearing effects&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.slideToObjectAndDestroy( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 1000, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: slideToObjectAndDestroy triggers the animation, you don&#039;t have to call &amp;lt;code&amp;gt;.play()&amp;lt;/code&amp;gt; on it. It returns an Dojo animation with an extra `promise` field, allowing you to do &amp;lt;code&amp;gt;await this.bga.gameui.slideToObjectAndDestroy(...).promise&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.fadeOutAndDestroy( node: string | Element, duration?: number, delay?: number):&#039;&#039;&#039; &#039;&#039;&#039;Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function fade out the target node, then destroy it. Its starts the animation.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.fadeOutAndDestroy( &amp;quot;a_card_that_must_disappear&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the HTML node still exists until during few milliseconds, until the fadeOut has been completed.&lt;br /&gt;
Make sure nothing is creating same object at the same time as animation is running, because you will be some random dissapearing effects&lt;br /&gt;
&lt;br /&gt;
Note: fadeOutAndDestroy triggers the animation, you don&#039;t have to call &amp;lt;code&amp;gt;.play()&amp;lt;/code&amp;gt; on it. It returns an Dojo animation with an extra `promise` field, allowing you to do &amp;lt;code&amp;gt;await this.bga.gameui.fadeOutAndDestroy(...).promise&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Rotating elements===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This example combines &amp;quot;Dojo.Animation&amp;quot; method and a CSS property transform that allow you to rotate the element.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// node is Element we rotating&lt;br /&gt;
		    var animation = new dojo.Animation({&lt;br /&gt;
			    curve: [fromDegree, toDegree],&lt;br /&gt;
			    onAnimate: (v) =&amp;gt; {&lt;br /&gt;
				    node.style.transform = &#039;rotate(&#039; + v + &#039;deg)&#039;;&lt;br /&gt;
			    } &lt;br /&gt;
		    });&lt;br /&gt;
		    &lt;br /&gt;
		    animation.play();  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BGA has its own interface to rotate&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.rotateTo(node: string | Element, degree: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It starts the animation, and stored the rotation degree in the class, so next time you rotate object - it is additive.&lt;br /&gt;
There is no animation hooks in this one, if you need to change any parameters use dojo animation above.&lt;br /&gt;
&lt;br /&gt;
There is also &#039;&#039;&#039;this.bga.gameui.rotateInstantTo&#039;&#039;&#039; with same signature which does not animate&lt;br /&gt;
&lt;br /&gt;
Note: rotateTo triggers the animation, you don&#039;t have to call &amp;lt;code&amp;gt;.play()&amp;lt;/code&amp;gt; on it. It returns an Dojo animation with an extra `promise` field, allowing you to do &amp;lt;code&amp;gt;await this.bga.gameui.rotateTo(...).promise&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Animation Callbacks===&lt;br /&gt;
&lt;br /&gt;
If you wish to run some code only after an animation has completed you can do this by linking a callback method to &#039;onEnd&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var animation_id = this.bga.gameui.slideToObject( mobile_obj, target_obj, 500 );&lt;br /&gt;
dojo.connect(animation_id, &#039;onEnd&#039;, () =&amp;gt; {&lt;br /&gt;
   // do something here&lt;br /&gt;
});&lt;br /&gt;
animation_id.play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you wish to call a second animation after the first (rather than general code) then you can use a dojo animation chain (see tutorial referenced above).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.bgaPlayDojoAnimation(anim)&#039;&#039;&#039;&lt;br /&gt;
* anim - the dojo animation&lt;br /&gt;
Play a dojo animation and returns a promise resolved when it ends.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  const anim = this.bga.gameui.slideToObject(`disc_${x}${y}`, `square${x}_${y}`);&lt;br /&gt;
  await this.bga.gameui.bgaPlayDojoAnimation(anim);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  const anim = dojo.fx.chain([&lt;br /&gt;
    dojo.fadeOut( { node: discDiv } ),&lt;br /&gt;
    dojo.fadeIn( { node: discDiv } ),&lt;br /&gt;
  ]);&lt;br /&gt;
  await this.bga.gameui.bgaPlayDojoAnimation(anim);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Players input ==&lt;br /&gt;
&lt;br /&gt;
=== Connecting ===&lt;br /&gt;
&#039;&#039;&#039;dojo.connect(element: Element, event: string, context: object, method: eventHandler): any&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.connect(element: Element, event: string, handler: eventHandler): any&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
Example: associate a click on an element (&amp;quot;my_element&amp;quot;) with one of our methods (&amp;quot;onClickOnMyElement&amp;quot;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      dojo.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, this, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same idea but based on query (i.e. all element of &#039;pet&#039; class)&lt;br /&gt;
      dojo.query(&amp;quot;.pet&amp;quot;).connect(&#039;onclick&#039;, this, &#039;onPet&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: if you need to disconnect the handler you have to store handler returned from this method, i.e.&lt;br /&gt;
   &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var handler = dojo.connect(...);&lt;br /&gt;
    ...&lt;br /&gt;
    dojo.disconnect(handler);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t store the handler - you have to destroy the object to disconnect it&lt;br /&gt;
&lt;br /&gt;
Typical function that implements the input handler will look like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onPet: function(event) {&lt;br /&gt;
    var id = event.currentTarget.id;&lt;br /&gt;
    console.log(&#039;onPet &#039; + id);&lt;br /&gt;
    dojo.stopEvent(event);&lt;br /&gt;
    if (this.gamedatas.gamestate.name == &#039;playerTurnPet&#039;) {&lt;br /&gt;
          this.bga.actions.performAction(&#039;actPlayPet&#039;, {card: id});&lt;br /&gt;
    } else {&lt;br /&gt;
          this.bga.dialogs.showMoveUnauthorized();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.connect(element: ElementOrId, event: string, method: eventHandler): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
      this.bga.gameui.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&lt;br /&gt;
Or you can use an in-place handler&lt;br /&gt;
&lt;br /&gt;
      this.bga.gameui.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, (e) =&amp;gt; { console.log(&#039;boo&#039;); } );&lt;br /&gt;
&lt;br /&gt;
Note that this function stores the connection handler. That is the only real difference between &#039;&#039;&#039;this.bga.gameui.connect&#039;&#039;&#039; and &#039;&#039;&#039;dojo.connect&#039;&#039;&#039;. If you plan to destroy the element you connected, you &#039;&#039;&#039;must&#039;&#039;&#039; call this.bga.gameui.disconnect() to prevent memory leaks.&lt;br /&gt;
This function is mainly for permanent objects - if you just want to connect the temp object you should probably not use this method but use dojo.connect which won&#039;t require any clean-up.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.connectClass(cssClassName: string, event: string, method: eventHandler): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as connect(), but for all the nodes set with the specified cssClassName.&lt;br /&gt;
 this.bga.gameui.connectClass(&#039;pet&#039;, &#039;onclick&#039;, &#039;onPet&#039;);&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.disconnect(element: ElementOrId, event: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disconnect event handler (previously registered with this.bga.gameui.connect or this.bga.gameui.connectClass).&lt;br /&gt;
&lt;br /&gt;
   this.bga.gameui.disconnect( $(&#039;my_element&#039;), &#039;onclick&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: dynamic connect/disconnect is for advanced cases ONLY, you should always connect elements statically if possible, i.e. in setup() method.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.disconnectAll(): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disconnect all previously registed event handlers (registered via this.bga.gameui.connect or this.bga.gameui.connectClass)&lt;br /&gt;
&lt;br /&gt;
  this.bga.gameui.disconnectAll();&lt;br /&gt;
&lt;br /&gt;
=== Actions ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.actions.performAction(action: string, args?: object, options: { lock: boolean, checkAction: boolean, checkPossibleActions?: boolean, ignoreDefaultErrorHandler?: boolean }): Promise&amp;lt;void&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Triggers an asynchronous action call in the php backend. Check more of what actions and arguments are possible in [[Main_game_logic:_Game.php#Actions_(autowired)]] docs.&lt;br /&gt;
&lt;br /&gt;
This method must be used to send a player&#039;s input to the game server. &#039;&#039;&#039;It should not be triggered programmatically&#039;&#039;&#039;, especially not in loops, in callbacks, in notifications, or in onEnteringState/onUpdateActionButtons/onLeavingState, in order not to create race conditions or break replay game and tutorial features. It should be used only in reaction to a user action in the interface.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
&lt;br /&gt;
* action: name of the action, as it is written in &amp;quot;possibleactions&amp;quot; of the current state.&lt;br /&gt;
* args: an object containing the call parameters to send to the action, can be undefined/omitted if action has no parameters. Note: the following arg names are forbidden : &amp;lt;code&amp;gt;$args / $activePlayerId/ $active_player_id / $currentPlayerId / $current_player_id&amp;lt;/code&amp;gt; to not mess with [https://en.doc.boardgamearena.com/State_classes:_State_directory#Functions_act* magic params].&lt;br /&gt;
* options: options to tweak the call with some defaults. Default is &amp;lt;code&amp;gt;{ lock: true, checkAction: true }&amp;lt;/code&amp;gt;.&lt;br /&gt;
** lock: (true by default) locks the user interface before any other action can be executed, that prevents user clicking on more buttons while this action is in progress. Set to false if you want to handle locking by yourself.&lt;br /&gt;
** checkAction: (true by default) check that action specified by &amp;quot;action&amp;quot; parameter in list of possible actions and user is active, only set to false in rare cases when some special out of turn actions are allowed.&lt;br /&gt;
&lt;br /&gt;
Important: this is asynchronous action, this means you should not be doing anything after this line of code except returning; If you want to do something after the call is resolved, use promise handlers - catch and then, see examples below.&lt;br /&gt;
&lt;br /&gt;
Example of a standard call without args:&lt;br /&gt;
  this.bga.actions.performAction(&#039;pass&#039;);&lt;br /&gt;
&lt;br /&gt;
Example of a standard call with action args:&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlayCard&#039;, { id: this.selectedCardId });&lt;br /&gt;
&lt;br /&gt;
Example of a call without checking action (because player is inactive in a multiactive state):&lt;br /&gt;
  this.bga.actions.performAction(&#039;actChangeMind&#039;, {}, { checkAction: false, checkPossibleActions: true });&lt;br /&gt;
&lt;br /&gt;
Example of a call without lock (because of a special action not directly related to the game flow):&lt;br /&gt;
  this.bga.actions.performAction(&#039;actSetAutoBid&#039;, { alwaysBidUntil: 500 }, { lock: false, checkAction: false });&lt;br /&gt;
&lt;br /&gt;
Example of call with an array of ids (to be used with #[IntArrayParam]) :&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlayCards&#039;, { ids: this.selectedCardIds });&lt;br /&gt;
&lt;br /&gt;
Example of call with aJSON object  (to be used with #[JsonParam], note the &amp;quot;stringify&amp;quot;) :&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlanComplexStuff&#039;, { answer: JSON.stringify(this.theJsonObject) });&lt;br /&gt;
&lt;br /&gt;
Example of call with reaction to exception:&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlayCard&#039;, { id: this.selectedCardId }).catch(()=&amp;gt;{ this.selectedCardId = undefined; });&lt;br /&gt;
&lt;br /&gt;
Example of call with reaction to success:&lt;br /&gt;
  this.bga.actions.performAction(&#039;actPlayCard&#039;, { id: this.selectedCardId }).then(()=&amp;gt;{ this.unselectAll(); });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Technical note:&lt;br /&gt;
* This is a combination of checkAction and ajaxcall, returning a Promise which resolves when ajaxcall ends.&lt;br /&gt;
* The function return void promise - the php callback cannot return any result, any results must be handled via the notification mechanism if needed&lt;br /&gt;
* In case there is an error - error message itself handled by framework, you can use error in catch({ message, args }) but you should not be showing it - this is done already, except if you&#039;ve set ignoreDefaultErrorHandler: true&lt;br /&gt;
* If you migrate from this.bgaPerformAction and are using catch on the promise, the result will now be { message, args } instead of args, allowing you to get the args you sent in the exception.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.actions.ajaxcall(url, parameters, obj_callback, callback, callback_anycase?, ajax_method?: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: this.bga.actions.performAction is a simpler way to use ajax calls, ajaxcall stays in the doc for legacy reasons only and should not be used in new projects.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same warning as &#039;&#039;&#039;this.bga.actions.performAction&#039;&#039;&#039; about using on user action only.&lt;br /&gt;
&lt;br /&gt;
* url: the url of the action to perform. For a game, it must be: &amp;quot;/&amp;lt;mygame&amp;gt;/&amp;lt;mygame&amp;gt;/myAction.html&amp;quot;&lt;br /&gt;
* parameters: an array of parameter to send to the game server. &lt;br /&gt;
** Note that &amp;quot;lock: true&amp;quot; must always be specified in this list of parameters in order the interface can be locked during the server call. Cannot use lock: false - to not lock it has to be undefined.&lt;br /&gt;
** Note: Restricted parameter names (please don&#039;t use them):&lt;br /&gt;
*** &amp;quot;action&amp;quot;&lt;br /&gt;
*** &amp;quot;module&amp;quot;&lt;br /&gt;
*** &amp;quot;class&amp;quot;&lt;br /&gt;
* obj_callback: must be set to &amp;quot;this&amp;quot;.&lt;br /&gt;
* callback (non-optional but rarely used): a function to trigger when the server returns result and everything went fine (not used, as all data handling is done via notifications).&lt;br /&gt;
* callback_anycase: (optional) a function to trigger when the server returns ok OR error.  If no error this function is called with parameter value false. If an error occurred, the first parameter will be set to true, the second will contain the error message sent by the PHP back-end, and the third will contain an error code.&lt;br /&gt;
* ajax_method: (optional and rarely used) if you need to send large amounts of data (over 2048 bytes), you can set this parameter to &#039;post&#039; (all lower-case) to send a POST request as opposed to the default GET. This works, but was not officially documented, so only use if you really need to.&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.actions.ajaxcall( &#039;/mygame/mygame/actMyAction.html&#039;, { lock: true, &lt;br /&gt;
   arg1: myarg1, &lt;br /&gt;
   arg2: myarg2&lt;br /&gt;
}, this, (result)=&amp;gt;{} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.actions.checkAction(action: string, nomessage?: boolean): boolean &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* if interface is locked it will return false and show message &amp;quot;An action is already in progress&amp;quot;, unless nomessage set to true &lt;br /&gt;
* if player is not active it will return false and show message &amp;quot;This is not your turn&amp;quot;, unless nomessage set to true &lt;br /&gt;
* if action is not in list of possible actions (defined by &amp;quot;possibleaction&amp;quot; in current game state) it will return false and show &amp;quot;This move is not authorized now&amp;quot; error (unconditionally).&lt;br /&gt;
* otherwise returns true&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  function onClickOnGameElement( evt )  {&lt;br /&gt;
     if( this.bga.actions.checkAction( &amp;quot;actMyAction&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.actions.checkPossibleActions(action: string): boolean&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* this is independent of the player being active, so can be used instead of this.bga.actions.checkAction(). This is particularly useful for multiplayer states when the player is not active in a &#039;player may like to change their mind&#039; scenario. Unlike this.bga.actions.checkAction, this function does NOT take interface locking into account &lt;br /&gt;
&lt;br /&gt;
* if action is not in list of possible actions (defined by &amp;quot;possibleaction&amp;quot; in current game state) it will return false and show &amp;quot;This move is not authorized now&amp;quot; error (unconditionally).&lt;br /&gt;
* otherwise returns true&lt;br /&gt;
&lt;br /&gt;
  function onChangeMyMind( evt )  {&lt;br /&gt;
     if( this.bga.actions.checkPossibleActions( &amp;quot;actMyAction&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.checkLock(nomessage?: boolean): boolean&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When using &amp;quot;lock: true&amp;quot; in ajax call you can use this function to check if the interface is in lock state (it will be locked during server call and notification processing).&lt;br /&gt;
This check can be used to block some other interactions which do not result in ajaxcall or if you want to suppress errors. Note: normally you only need to use this.bga.actions.checkAction(...), this is for advanced cases.&lt;br /&gt;
&lt;br /&gt;
It will also show error unless nomessage is set to true&lt;br /&gt;
&lt;br /&gt;
  function onChangeMyMind( evt )  {&lt;br /&gt;
     if( this.bga.gameui.checkLock() ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
== Notifications ==&lt;br /&gt;
&lt;br /&gt;
When something happens on the server side, your game interface Javascript logic received a notification.&lt;br /&gt;
If you have not done so yet check what notification are in [[Main_game_logic:_yourgamename.game.php#Notifications]]&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can handle these notifications on the client side.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.notifications.setupPromiseNotifications(params = undefined)&#039;&#039;&#039;&lt;br /&gt;
* params - the call parameters, by default { prefix: &#039;notif_&#039;, minDuration: 500, minDurationNoText: 1, logger: null, ignoreNotifications: [], onStart: undefined, onEnd: undefined, }.&lt;br /&gt;
Auto-detect all notifications declared on the game object (functions starting with `notif_`)  and register them with dojo.subscribe.&lt;br /&gt;
&lt;br /&gt;
Registered notifications will be synchronous and will have a minimum duration (if animations are active, by default 500ms with text and 1ms without).&lt;br /&gt;
&lt;br /&gt;
If the notification function returns a Promise, the notification will end when the promise AND the minimum durations are over.&lt;br /&gt;
If the notification function does not return a promise, it is considered as already resolved as soon as the minimum durations are over.&lt;br /&gt;
&lt;br /&gt;
In case of a notification function returning a Promise, the dev is responsible to make it resolve instantaneously if animations are not active.&lt;br /&gt;
&lt;br /&gt;
See `bgaAnimationsActive` to know if animations are active : https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Animations&lt;br /&gt;
&lt;br /&gt;
See `bgaPlayDojoAnimation` to handle dojo animations with promises : https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Animation_Callbacks&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  setupNotifications: function() {&lt;br /&gt;
    this.bga.notifications.setupPromiseNotifications();&lt;br /&gt;
  },    &lt;br /&gt;
  notif_playedCard: async function(args) {&lt;br /&gt;
    await this.getPlayerTable(args.playerId).playCard(args.card);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of setting custom values for all params :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  setupNotifications: function() {&lt;br /&gt;
    this.bga.notifications.setupPromiseNotifications({ &lt;br /&gt;
      prefix: &#039;notif_&#039;, // default is &#039;notif_&#039;&lt;br /&gt;
      minDuration: 1200, // for longer animations (500 by default)&lt;br /&gt;
      minDurationNoText: 1,&lt;br /&gt;
      handlers: [this.notificationsManager], // if you write your notif function in a subclass instead of this (default this)&lt;br /&gt;
      logger: console.log, // show notif debug informations on console. Could be console.warn or any custom debug function (default null = no logs)&lt;br /&gt;
      ignoreNotifications: [&#039;updateAutoPlay&#039;], // the notif_updateAutoPlay function will be ignored by bgaSetupPromiseNotifications. You&#039;ll need to subscribe to it manually&lt;br /&gt;
      onStart: (notifName, msg, args) =&amp;gt; $(&#039;pagemaintitletext&#039;).innerHTML = `${_(&#039;Animation for:&#039;)} ${msg}`, &lt;br /&gt;
      onEnd: (notifName, msg, args) =&amp;gt; $(&#039;pagemaintitletext&#039;).innerHTML = &#039;&#039;,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.wait(delay)&#039;&#039;&#039;&lt;br /&gt;
* delay - the time to wait, in milliseconds&lt;br /&gt;
Return a Promise that resolves at the end of a given number of ms. If animations are not active, resolve instantaneously.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  await this.bga.gameui.wait(500); // wait 500ms before continuing in an async function&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Subscribe to notifications manually ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.subscribe(notif_type: string, callback_obj: Object, handler: string|handler)&#039;&#039;&#039;&lt;br /&gt;
* notif_type - notification type/name send by php server&lt;br /&gt;
* callback_obj - usually this&lt;br /&gt;
* handler - if string method of callback_obj with name name is called, when notification is called, with notification object as parameter (see below)&lt;br /&gt;
&lt;br /&gt;
Your Javascript &amp;quot;setupNotifications&amp;quot; method is the place where you can subscribe to notifications from your PHP code.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you associate one of your Javascript method to a notification &amp;quot;playDisc&amp;quot; (from Reversi example):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   setupNotifications: function() {&lt;br /&gt;
      ...&lt;br /&gt;
      dojo.subscribe(&#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot;);&lt;br /&gt;
   },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the &amp;quot;playDisc&amp;quot; corresponds to the name of the notification you define it in your PHP code, in your &amp;quot;notify-&amp;gt;all&amp;quot; or &amp;quot;notify-&amp;gt;player&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Then, you have to define your &amp;quot;notif_playDisc&amp;quot; method:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   notif_playDisc: function(notif) {&lt;br /&gt;
     // Remove current possible moves (makes the board more clear)&lt;br /&gt;
     dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );          &lt;br /&gt;
     this.addDiscOnBoard( notif.args.x, notif.args.y, notif.args.player_id );&lt;br /&gt;
   },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In a notification handler like our &amp;quot;notif_playDisc&amp;quot; method, you can access all notifications arguments with &amp;quot;notif.args&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
PHP&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notify-&amp;gt;all( &amp;quot;apples&amp;quot;, clienttranslate(&#039;player takes ${count} apples&#039;), [ &amp;quot;count&amp;quot; =&amp;gt; 3 ] );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
JavaScript&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setupNotifications: function() {&lt;br /&gt;
       dojo.subscribe( &#039;apples&#039;, this, &#039;notif_apples&#039; );&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    notif_apples: function(notif) {&lt;br /&gt;
      //You can access the &amp;quot;count&amp;quot; like this:&lt;br /&gt;
       alert(&amp;quot;count = &amp;quot; + notif.args.count);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The notification Object received by client ===&lt;br /&gt;
&lt;br /&gt;
When sending a notification on your PHP, the client side will receive an Object with the following attributes:&lt;br /&gt;
&lt;br /&gt;
* type - type of the notification (as passed by php function)&lt;br /&gt;
* log - the log string passed from php notification&lt;br /&gt;
* args - This is the arguments that you passed on your notification method on php&lt;br /&gt;
* bIsTableMsg - is true when you use [[Main_game_logic:_yourgamename.game.php#NotifyAllPlayers|Notify-&amp;gt;all]] method (false otherwise)&lt;br /&gt;
* channelorig - information about table ID (formatted as : &amp;quot;/table/t[TABLE_NUMBER]&amp;quot;)&lt;br /&gt;
* gamenameorig - name of the game&lt;br /&gt;
* move_id - ID of the move associated with the notification&lt;br /&gt;
* table_id - ID of the table (comes as string)&lt;br /&gt;
* time - UNIX GMT timestamp&lt;br /&gt;
* uid - unique identifier of the notification&lt;br /&gt;
* h - unknown&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; Note that those information were inferred from observation on console log. If an Admin can confirm/correct (and remove this line), you&#039;re welcome :)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ignoring notifications ===&lt;br /&gt;
&lt;br /&gt;
NOTE: With the new &amp;lt;code&amp;gt;_private&amp;lt;/code&amp;gt; arg in $this-&amp;gt;notify-&amp;gt;all, you should not need to ignore notifications anymore. See https://en.doc.boardgamearena.com/Main_game_logic:_Game.php#Sending_private_data_to_some_players for the new way of handling private data in notifications.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setIgnoreNotificationCheck(notif_type: string, predicate: ((notif: Notif)=&amp;gt;boolean))&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;If you need this function and you are in the Dev Discord, please read [https://discord.com/channels/753304735615811584/1448596273081876530/1448596273081876530 This thread] that might avoid the usage of &#039;&#039;&#039;setIgnoreNotificationCheck.&#039;&#039;&#039;&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This method will set a check whether any of notifications of specific type should be ignored.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* notif_type: type of the notification &lt;br /&gt;
* predicate (notif =&amp;gt; boolean): a function that will receive notif object and will return true if this specific notification should be ignored&lt;br /&gt;
&lt;br /&gt;
Before dispatching any notification of this type, the framework will call predicate to check whether notification should be ignored, if it return true - the notification will be dispatched, i.e. logged or handled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.bga.gameui.notifqueue.setIgnoreNotificationCheck( &#039;dealCard&#039;, (notif) =&amp;gt; notif.args.player_id == this.bga.players.getCurrentPlayerId() );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: Remember that this notification is ignored on the client side, but was still received by the client. Therefore it shouldn&#039;t contain any private information as cheaters can get it. In other words this is not a way to hide information.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: When a game is reloaded with F5 or when opening a turn based game, old notifications are replayed as history notification. They are used just to update the game log and are stripped of all arguments except player_id, i18n and any argument present in message. If you use and other argument in your predicate you should &#039;&#039;&#039;preserve&#039;&#039;&#039; it as explained [[Main_game_logic:_yourgamename.game.php#Notify_players|here]].&lt;br /&gt;
&lt;br /&gt;
=== Handle manually synchronous notifications ===&lt;br /&gt;
&lt;br /&gt;
When several notifications are received by your game interface, these notifications are processed immediately, one after the other, in the same exact order they have been generated in your PHP game logic.&lt;br /&gt;
&lt;br /&gt;
However, sometimes, you need to give some time to the players to figure out what happened on the game before jumping to the next notification. Indeed, in many games, there are a lot of automatic actions, and the computer is going to resolve all these actions very fast if you don&#039;t tell it not to do so.&lt;br /&gt;
&lt;br /&gt;
As an example, for Reversi, when someone is playing a disc, we want to wait 500 milliseconds before doing anything else in order the opponent player can figure out what move has been played.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we do this, right after our subscription:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
    this.bga.gameui.notifqueue.setSynchronous( &#039;playDisc&#039;, 500 );   // Wait 500 milliseconds after executing the playDisc handler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
It is also possible to control the delay timing dynamically (e.g., using notification args). As an example, maybe your notification &#039;cardPlayed&#039; should pause for a different amount of time depending on the number or type of cards played.&lt;br /&gt;
&lt;br /&gt;
For this case, use &#039;&#039;&#039;setSynchronous&#039;&#039;&#039; without specifying the duration and use &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039; within the notification callback.&lt;br /&gt;
&lt;br /&gt;
* NOTE: If you forget to invoke &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039;, the game will remain paused forever!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupNotifications: function () {&lt;br /&gt;
    dojo.subscribe( &#039;cardPlayed&#039;, this, &#039;notif_cardPlayed&#039; );&lt;br /&gt;
    this.bga.gameui.notifqueue.setSynchronous( &#039;cardPlayed&#039; ); // wait time is dynamic&lt;br /&gt;
    ...&lt;br /&gt;
},&lt;br /&gt;
&lt;br /&gt;
notif_cardPlayed: function (notif) {&lt;br /&gt;
    // MUST call setSynchronousDuration&lt;br /&gt;
&lt;br /&gt;
    // Example 1: From notification args (PHP)&lt;br /&gt;
    this.bga.gameui.notifqueue.setSynchronousDuration(notif.args.duration);&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Or, example 2: Match the duration to a Dojo animation&lt;br /&gt;
    var anim = dojo.fx.combine([&lt;br /&gt;
        ...&lt;br /&gt;
    ]);&lt;br /&gt;
    anim.play();&lt;br /&gt;
    this.bga.gameui.notifqueue.setSynchronousDuration(anim.duration);&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also manually call this.bga.gameui.notifqueue.setSynchronousDuration(0) once client operations are finished, but be careful that even fast replay still has a path to call it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING: combining synchronous and ignored notifications&#039;&#039;&#039;&lt;br /&gt;
You must be careful when combining dynamic synchronous durations (as described above) with ignored notifications. If you have a conditionally ignored notification like this (see below section):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.bga.gameui.notifqueue.setIgnoreNotificationCheck( &#039;myNotif&#039;, (notif) =&amp;gt; (notif.args.player_id == this.bga.players.getCurrentPlayerId()) /* or any other condition */ )&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then you CANNOT do&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.bga.gameui.notifqueue.setSynchronous(&#039;myNotif&#039;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
as, when the ignored check passes, the notification handler, in which `this.bga.gameui.notifqueue.setSychronousDuration` is called, is never called and so the duration is never set and interface locking results.&lt;br /&gt;
&lt;br /&gt;
The workaround is to set a &amp;quot;dummy&amp;quot; time:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;this.bga.gameui.notifqueue.setSynchronous(&#039;myNotif&#039;, 5000);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whose value is irrelevant but must be large enough to cover the time before the notification handler is called. The large value never actually comes into play because the notification is either ignored, or the synchronous duration is reset to a sensible value inside the handler.&lt;br /&gt;
&lt;br /&gt;
=== Pre-defined notification types ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tableWindow&#039;&#039;&#039; - This defines notification to display [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialogs]], see below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;message&#039;&#039;&#039; - This defines notification that shows on players log and have no other effect (technically any unhandled notification will do the same but its recommended to use this keyword for consistency)&lt;br /&gt;
&lt;br /&gt;
   // You can call this on php side without doing anything on client side&lt;br /&gt;
    $this-&amp;gt;notify-&amp;gt;all( &#039;message&#039;, clienttranslate(&#039;hello&#039;), [] );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;simplePause&#039;&#039;&#039; - This notification will just delay other notifications, maybe useful if you know you need some extra time for animation or something. Requires a time parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notify-&amp;gt;all( &#039;simplePause&#039;, &#039;&#039;, [ &#039;time&#039; =&amp;gt; 500] ); // time is in milliseconds&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: the following types are RESERVED by framework, do not use:&lt;br /&gt;
&lt;br /&gt;
gameStateChange gameStateChangePrivateArg gameStateMultipleActiveUpdate newActivePlayer playerstatus yourturnack clockalert tableInfosChanged playerEliminated tableDecision  archivewaitingdelay end_archivewaitingdelay replaywaitingdelay end_replaywaitingdelay replayinitialwaitingdelay end_replayinitialwaitingdelay aiPlayerWaitingDelay replay_has_ended updateSpectatorList  wouldlikethink updateReflexionTime undoRestorePoint resetInterfaceWithAllDatas zombieModeFail zombieModeFailWarning aiError skipTurnOfPlayer zombieBack allPlayersAreZombie gameResultNeutralized playerConcedeGame showTutorial showCursor showCursorClick skipTurnOfPlayerWarning  banFromTable resultsAvailable switchToTurnbased newPrivateState infomsg&lt;br /&gt;
&lt;br /&gt;
== Tooltips ==&lt;br /&gt;
&lt;br /&gt;
=== Adding static tooltips ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addTooltip(nodeId: string, helpStringTranslated: string, actionStringTranslated: string, delay?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to the DOM node.&lt;br /&gt;
&lt;br /&gt;
Specify &#039;helpStringTranslated&#039; to display some information about &amp;quot;what is this game element?&amp;quot;.&lt;br /&gt;
Specify &#039;actionStringTranslated&#039; to display some information about &amp;quot;what happens when I click on this element?&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
You must specify both of the strings. You can only use one and specify an empty string (&#039;&#039;) for the other one.&lt;br /&gt;
&lt;br /&gt;
When you pass text directly function _() must be used for the text to be marked for translation! Except for empty string.&lt;br /&gt;
&lt;br /&gt;
Parameter &amp;quot;delay&amp;quot; is optional. It is primarily used to specify a zero delay for some game element when the tooltip gives really important information for the game - but remember: no essential information must be placed in tooltips as they won&#039;t be displayed in some browsers (see [[BGA_Studio_Guidelines|Guidelines]]).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.addTooltip( &#039;cardcount&#039;, _(&#039;Number of cards in hand&#039;), &#039;&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this generates static tooltip and attaches to existing dom element, if you need to generate tooltip more dynamically you have to call that method every time information about object is updated or use completely different tehnique, see dynamic tooltips below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addTooltipHtml(nodeId: string, html: string, delay?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to the DOM node (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addTooltipToClass(cssClass: string, helpStringTranslated: string, actionStringTranslated: string, delay?: number ): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add a simple text tooltip to all the DOM nodes set with this cssClass. See more details above for this.bga.gameui.addTooltip.&lt;br /&gt;
     this.bga.gameui.addTooltipToClass( &#039;meeple&#039;, _(&#039;This is A Meeple&#039;), _(&#039;Click to tickle&#039;) );&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must exist and have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addTooltipHtmlToClass(cssClass: string, html: string, delay?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Add an HTML tooltip to to all the DOM nodes set with this cssClass (for more elaborate content such as presenting a bigger version of a card).&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: all concerned nodes must exist and have IDs to get tooltips.&lt;br /&gt;
&lt;br /&gt;
=== Removing static tooltips ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.removeTooltip(nodeId: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove a tooltip from the DOM node with given id.&lt;br /&gt;
&lt;br /&gt;
=== Advanced tooltips ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;force tooltip to open&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If you want to force tooltip to open in reaction to some other action, i.e. click you can do this&lt;br /&gt;
&lt;br /&gt;
   this.bga.gameui.tooltips[id].open(id)&lt;br /&gt;
&lt;br /&gt;
where id is the id of the tooltip node where tooltip was installed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dynamic tooltips&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
See [[BGA_Studio_Cookbook#Dynamic_tooltips]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;tooltips on mobile&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Tooltips is very unreliable on mobile, it is recommended to implement some other method to obtaining same information,&lt;br /&gt;
such as simple click handler in dedicated &amp;quot;Help&amp;quot; mode or provide dedicated clickable areas such as corner of card.&lt;br /&gt;
&lt;br /&gt;
== Banners ==&lt;br /&gt;
&lt;br /&gt;
The framework comes with predefined banners.&lt;br /&gt;
&lt;br /&gt;
=== Last turn banner ===&lt;br /&gt;
When someone fulfills one of the end of the game conditions, so this is the last turn.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameArea.addLastTurnBanner(message?: string, args?: any): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If message is unset, default is &amp;quot;This is the last turn!&amp;quot;. For args example, see the addWinConditionBanner example that works the same way.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.bga.gameArea.addLastTurnBanner(&lt;br /&gt;
        _(&#039;This is the last turn! (deck is empty)&#039;)&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[File:Last turn banner example.png|center]]&lt;br /&gt;
&lt;br /&gt;
If the action triggering the last turn banner is cancelled, you can remove the banner by using&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameArea.removeLastTurnBanner(): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Win condition banner ===&lt;br /&gt;
When the game has multiple win conditions, use this function to display a message detailing which win condition was reached.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameArea.addWinConditionBanner(message?: string, args?: any): void;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    const winConditionText = _(&#039;${player_name} reached the Victory space of the Fame track and wins the game by being the most celebrated Monster!&#039;);&lt;br /&gt;
    this.bga.gameArea.addWinConditionBanner(&lt;br /&gt;
        winConditionText,&lt;br /&gt;
        { &#039;player_name&#039;: this.bga.players.getFormattedPlayerName(winnerId) }&lt;br /&gt;
    );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[File:Win condition banner example.png|center]]&lt;br /&gt;
&lt;br /&gt;
== Warning messages ==&lt;br /&gt;
&lt;br /&gt;
Sometimes, there is something important that is happening in the game and you have to make sure the player get the message. For example, explain why the player cannot do an action he can usually do when he clicks an element, if you don&#039;t need the PHP to validate the possibility.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.dialogs.showMessage(msg: string, type: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
showMessage shows a message in a big rectangular area on the top of the screen of the current player, and it disappears after few seconds (also it will be in the log in some cases).&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;msg&amp;quot; is the string to display. It should be translated.&lt;br /&gt;
* &amp;quot;type&amp;quot; can be set to &amp;quot;info&amp;quot;, &amp;quot;error&amp;quot;, &amp;quot;only_to_log&amp;quot; or custom string. If set to &amp;quot;info&amp;quot;, the message will be an informative message on a white background. If set to &amp;quot;error&amp;quot;, the message will be an error message on a red background and it will be added to log. If set to &amp;quot;only_to_log&amp;quot;, the message will be added to the game log but will not popup at the top of the screen.&lt;br /&gt;
If set to custom string, it will be transparent, to use custom type define &amp;quot;head_xxx&amp;quot; in css, where xxx is the type. For example if you want yellow warning, use &amp;quot;warning&amp;quot; as type and add this to css:&lt;br /&gt;
 .head_warning {&lt;br /&gt;
    background-color: #e6c66e;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Important: the normal way to inform players about the progression of the game is the game log. The &amp;quot;showMessage&amp;quot; is intrusive and should not be used often.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    notif_messageinfo: function(notif) {&lt;br /&gt;
	if (!g_archive_mode) {&lt;br /&gt;
        	var message = this.bga.gameui.format_string_recursive(notif.log, notif.args);&lt;br /&gt;
		this.bga.dialogs.showMessage(_(&#039;Announcement:&#039;) + &amp;quot; &amp;quot; + message, &#039;info&#039;);		&lt;br /&gt;
         }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Show message could be used on the client side to prevent user wrong moves before it is send to server.&lt;br /&gt;
Example from &#039;battleship&#039;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onGrid: function(event) {&lt;br /&gt;
     if (checkIfPlayerTriesToFireOnThemselves(event)) {&lt;br /&gt;
        this.bga.dialogs.showMessage(_(&#039;This is your own board silly!&#039;), &#039;error&#039;);&lt;br /&gt;
        return;&lt;br /&gt;
     }&lt;br /&gt;
     ...&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.dialogs.showMoveUnauthorized(): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Shows predefined user error that move is unauthorized now&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onPet: function(event) {&lt;br /&gt;
     if (checkPet(event)==false) {&lt;br /&gt;
        this.bga.dialogs.showMoveUnauthorized();&lt;br /&gt;
        return;&lt;br /&gt;
     }&lt;br /&gt;
     ...&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dialogs ==&lt;br /&gt;
&lt;br /&gt;
=== Confirmation dialog ===&lt;br /&gt;
&lt;br /&gt;
When an important action with a lot of consequences is triggered by the player, you may want to propose a confirmation dialog.&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the general guideline of BGA is to AVOID the use of confirmation dialogs. Confirmation dialogs slow down the game and bother players. The players know that they have to pay attention to each move when they are playing online.&lt;br /&gt;
&lt;br /&gt;
The situations where you should use a confirmation dialog are the following:&lt;br /&gt;
* It must not happen very often during a game.&lt;br /&gt;
* It must be linked to an action that can really &amp;quot;kill a game&amp;quot; if the player does not pay attention.&lt;br /&gt;
* It must be something that can be done by mistake (ex: a link on the action status bar).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.dialogs.confirmation(message: string): Promise&amp;lt;boolean&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* message - message will be shown to user, use _() to translate&lt;br /&gt;
NOTE: this is an async function, you must handle the consequence in the result of the promise&lt;br /&gt;
&lt;br /&gt;
How to display a confirmation dialog:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.bga.dialogs.confirmation(_(&amp;quot;Are you sure you want to bake a pie?&amp;quot;)).then(result =&amp;gt; {&lt;br /&gt;
      if (result) { &lt;br /&gt;
        this.bakeThePie();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
    return; // nothing should be called or done after calling this, all action must be done in the handler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you&#039;re migrating from this.confirmationDialog,  you&#039;ll need to move the callback function into the &amp;lt;code&amp;gt;then&amp;lt;/code&amp;gt; as it&#039;s now Promise-based&lt;br /&gt;
&lt;br /&gt;
=== Multiple choice dialog ===&lt;br /&gt;
&lt;br /&gt;
You can use this dialog to give user a choice with small amount of options&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.dialogs.multipleChoice(message: string, choices: string[]): Promise&amp;lt;string | null&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
* message - message will be shown to user, use _() to translate&lt;br /&gt;
* choices - array of choices&lt;br /&gt;
&lt;br /&gt;
NOTE: this is an async function, you must handle the consequence in the result of the promise. If the user cancels, it returns null.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    const keys = [&amp;quot;0&amp;quot;, &amp;quot;1&amp;quot;, &amp;quot;5&amp;quot;, &amp;quot;10&amp;quot;];&lt;br /&gt;
    this.bga.dialogs.multipleChoice(_(&amp;quot;How many bugs to fix?&amp;quot;), keys).then(choice =&amp;gt; {&lt;br /&gt;
      if (choice === null) { return; } // cancel operation, do not call server action&lt;br /&gt;
      const bugchoice = keys[choice]; // choice will be 0,1,2,3 here&lt;br /&gt;
      this.bga.actions.performAction(&amp;quot;fixBugs&amp;quot;, { number: bugchoice });&lt;br /&gt;
    });&lt;br /&gt;
    return; // must return here&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you&#039;re migrating from this.multipleChoiceDialog, you&#039;ll need to move the callback function into the &amp;lt;code&amp;gt;then&amp;lt;/code&amp;gt; as it&#039;s now Promise-based&lt;br /&gt;
&lt;br /&gt;
=== Generic Dialogs ===&lt;br /&gt;
&lt;br /&gt;
As a general rule, you shouldn&#039;t use dialogs windows.&lt;br /&gt;
&lt;br /&gt;
BGA guidelines specify that all game elements should be displayed on the main screen. Players can eventually scroll down to see game elements they don&#039;t need to see anytime, and you may eventually create anchors to move between game area section. Of course dialogs windows are very practical, but the thing is: all players know how to scroll down, and not all players know how to show up your dialog window. In addition, when the dialog shows up, players can&#039;t access the other game components.&lt;br /&gt;
&lt;br /&gt;
Sometimes although, you need to display a dialog window. Here is how you do this:&lt;br /&gt;
&lt;br /&gt;
  // Create the new dialog over the play zone. You should store the handler in a member variable to access it later&lt;br /&gt;
  this.myDlg = new ebg.popindialog();&lt;br /&gt;
  this.myDlg.create( &#039;myDialogUniqueId&#039; );&lt;br /&gt;
  this.myDlg.setTitle( _(&amp;quot;my dialog title to translate&amp;quot;) );&lt;br /&gt;
  this.myDlg.setMaxWidth( 500 ); // Optional&lt;br /&gt;
  &lt;br /&gt;
  // Create the HTML of my dialog. &lt;br /&gt;
  // The best practice here is to use [[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&lt;br /&gt;
  var html = this.gameui.format_block( &#039;jstpl_myDialogTemplate&#039;, { &lt;br /&gt;
                arg1: myArg1,&lt;br /&gt;
                arg2: myArg2,&lt;br /&gt;
                ...&lt;br /&gt;
            } );  &lt;br /&gt;
  &lt;br /&gt;
  // Show the dialog&lt;br /&gt;
  this.myDlg.setContent( html ); // Must be set before calling show() so that the size of the content is defined before positioning the dialog&lt;br /&gt;
  this.myDlg.show();&lt;br /&gt;
  &lt;br /&gt;
  // Now that the dialog has been displayed, you can connect your method to some dialog elements&lt;br /&gt;
  // Example, if you have an &amp;quot;OK&amp;quot; button in the HTML of your dialog:&lt;br /&gt;
  dojo.connect($(&#039;my_ok_button&#039;), &#039;onclick&#039;, this, (event) =&amp;gt; {&lt;br /&gt;
                event.preventDefault();&lt;br /&gt;
                this.myDlg.destroy();&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
If necessary, you can remove the default top right corner &#039;close&#039; icon, or replace the function called when it is clicked:&lt;br /&gt;
  // Removes the default close icon&lt;br /&gt;
  this.myDlg.hideCloseIcon();&lt;br /&gt;
&lt;br /&gt;
  // Replace the function call when it&#039;s clicked&lt;br /&gt;
  this.myDlg.replaceCloseCallback((event) =&amp;gt; { ... });&lt;br /&gt;
&lt;br /&gt;
=== Scoring dialogs ===&lt;br /&gt;
&lt;br /&gt;
Sometimes at the end of a round you want to display a big table that details the points wins in each section of the game.&lt;br /&gt;
&lt;br /&gt;
Example: in Hearts game, we display at the end of each round the number of &amp;quot;heart&amp;quot; cards collected by each player, the player who collected the Queen of Spades, and the total number of points loose by each player.&lt;br /&gt;
&lt;br /&gt;
Scoring dialogs are managed entirely on &#039;&#039;&#039;PHP side&#039;&#039;&#039;, but they are described here as their effects are visible only on client side.&lt;br /&gt;
&lt;br /&gt;
Displaying a scoring dialog is quite simple and is using a special notification type: &amp;quot;tableWindow&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // on PHP side:&lt;br /&gt;
  $this-&amp;gt;notify-&amp;gt;all( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, array(&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table&lt;br /&gt;
        )); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;table&amp;quot; argument is a 2 dimensional PHP array that describes the table you want to display, line by line and column by column.&lt;br /&gt;
&lt;br /&gt;
Example: display an 3x3 array of strings&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = [&lt;br /&gt;
      [ &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, &amp;quot;three&amp;quot; ],    // This is my first line&lt;br /&gt;
      [ &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ],    // This is my second line&lt;br /&gt;
      [ &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; ]    // This is my third line&lt;br /&gt;
   ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see above, in each &amp;quot;cell&amp;quot; of your array you can display a simple string value. But you can also display a complex value with a template and associated arguments like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $table = [&lt;br /&gt;
      [ &amp;quot;one&amp;quot;, &amp;quot;two&amp;quot;, [ &amp;quot;str&amp;quot; =&amp;gt; clienttranslate(&amp;quot;a string with an ${argument}&amp;quot;), &amp;quot;args&amp;quot; =&amp;gt; [ &#039;argument&#039; =&amp;gt; &#039;argument_value&#039; ] ] ],&lt;br /&gt;
      [ &amp;quot;four&amp;quot;, &amp;quot;five&amp;quot;, &amp;quot;six&amp;quot; ], &lt;br /&gt;
      [ &amp;quot;seven&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;nine&amp;quot; ]&lt;br /&gt;
   ];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is especially useful when you want to display player names with colors. Example from &amp;quot;Hearts&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $firstRow = [ &#039;&#039; ];&lt;br /&gt;
        foreach( $players as $player_id =&amp;gt; $player )    {&lt;br /&gt;
            $cell = [ &#039;str&#039; =&amp;gt; &#039;${player_name}&#039;,&lt;br /&gt;
                      &#039;args&#039; =&amp;gt; [ &#039;player_name&#039; =&amp;gt; $player[&#039;player_name&#039;] ],&lt;br /&gt;
                      &#039;type&#039; =&amp;gt; &#039;header&#039;&lt;br /&gt;
                    ];&lt;br /&gt;
            $firstRow[] = $cell;&lt;br /&gt;
        }&lt;br /&gt;
        $table[] = $firstRow;&lt;br /&gt;
        ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use three extra attributes in the parameter array for the notification:&lt;br /&gt;
* &#039;&#039;&#039;header&#039;&#039;&#039;: the content for this parameter displays before the table (also, the html will be parsed and player names will be colored according to the current game colors). &lt;br /&gt;
* &#039;&#039;&#039;footer&#039;&#039;&#039;: the content for this parameter displays after the table (no parsing for coloring the player names)&lt;br /&gt;
* &#039;&#039;&#039;closing&#039;&#039;&#039;: if this parameter is used, a button will be displayed with this label at the bottom of the popup and will allow players to close it (more easily than by clicking the top right &#039;cross&#039; icon).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   $this-&amp;gt;notify-&amp;gt;all( &amp;quot;tableWindow&amp;quot;, &#039;&#039;, [&lt;br /&gt;
            &amp;quot;id&amp;quot; =&amp;gt; &#039;finalScoring&#039;,&lt;br /&gt;
            &amp;quot;title&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Title of the scoring dialog&amp;quot;),&lt;br /&gt;
            &amp;quot;table&amp;quot; =&amp;gt; $table,&lt;br /&gt;
            &amp;quot;header&amp;quot; =&amp;gt; [&#039;str&#039; =&amp;gt; clienttranslate(&#039;Table header with parameter ${number}&#039;),&lt;br /&gt;
                                 &#039;args&#039; =&amp;gt; [ &#039;number&#039; =&amp;gt; 3 ],&lt;br /&gt;
                               ],&lt;br /&gt;
            &amp;quot;footer&amp;quot; =&amp;gt; &#039;&amp;lt;div class=&amp;quot;myfoot&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;,&lt;br /&gt;
            &amp;quot;closing&amp;quot; =&amp;gt; clienttranslate( &amp;quot;Closing button label&amp;quot; )&lt;br /&gt;
        ] ); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: currently id is not used - so you cannot access resulting div by id on js side &lt;br /&gt;
&lt;br /&gt;
Note: any translatable string have to be wrapped by clienttranslate() on top level OR it has to be recursive template. &lt;br /&gt;
&lt;br /&gt;
DO NOT DO THIS: &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   &amp;quot;footer&amp;quot; =&amp;gt; &#039;&amp;lt;div&amp;gt;&#039;.clienttranslate( &amp;quot;The end&amp;quot; ).&#039;&amp;lt;/div&amp;gt;&#039;, // this will not work for translations!!!&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Scoring animated display ===&lt;br /&gt;
&lt;br /&gt;
Sometimes, you may want to display a score value over an element to make the scoring easier to follow for the players (Terra Mystica final scoring for example).&lt;br /&gt;
You can do it with:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.displayScoring(anchor_id: string, color: string, score: number | string, duration?: number, offset_x?: number, offset_y?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;anchor_id&#039;&#039;&#039;: ID of the html element to place the animated score onto (without the &#039;#&#039;) &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;color&#039;&#039;&#039;: hexadecimal RGB representation of the color (should be the color of the scoring player), but without a leading &#039;#&#039;.  For instance, &#039;ff0000&#039; for red.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;score&#039;&#039;&#039;: numeric score to display, prefixed by a &#039;+&#039; or &#039;-&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;duration&#039;&#039;&#039;: animation duration in milliseconds (optional, default is 1000)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;offset_x&#039;&#039;&#039; and &#039;&#039;&#039;offset_y&#039;&#039;&#039;: if both offset_x and offset_y are defined and not null, apply the following offset (in pixels) to the scoring animation. &lt;br /&gt;
Note that the score is centered in the anchor, so the offsets might have to be negative if you calculate the position.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: if you want to display successively each score, you can use &#039;&#039;this.bga.gameui.notifqueue.setSynchronous()&#039;&#039; function.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setupNotifications: function()   {&lt;br /&gt;
           dojo.subscribe( &#039;displayScoring&#039;, this, &amp;quot;notif_displayScoring&amp;quot; );&lt;br /&gt;
           ...&lt;br /&gt;
    }&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
    notif_displayScoring: function(notif) {&lt;br /&gt;
            const duration = notif.args.duration?notif.args.duration:1000;&lt;br /&gt;
            this.bga.gameui.notifqueue.setSynchronous(&#039;displayScoring&#039;, duration );&lt;br /&gt;
	    this.bga.gameui.displayScoring( notif.args.target, notif.args.color, notif.args.score, duration);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Speech bubble ===&lt;br /&gt;
&lt;br /&gt;
For better interactivity in some games (Love Letter for example), you may use comic book style speech bubbles to express the players voices.&lt;br /&gt;
This is done with showBubble:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.showBubble(anchor_id: string, text: string, delay?: number, duration?: number, custom_class?: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* anchor_id - where to attach the bubble&lt;br /&gt;
* text - what to put in bubble, can be html&lt;br /&gt;
* delay - delay in milliseconds (optional, default 0)&lt;br /&gt;
* duration -  duration of animation in milliseconds (optional, default 3000)&lt;br /&gt;
* custom_class - extra class to add to bubble (optional), if you need to override the default bubble style&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.bga.gameui.showBubble(&#039;meeple_2&#039;, _(&#039;Hello&#039;), 0, 1000, &#039;pink_bubble&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  notif_speechBubble(notif) {&lt;br /&gt;
    var html = this.bga.gameui.format_string_recursive(notif.args.text, notif.args.args);&lt;br /&gt;
    this.bga.gameui.showBubble(notif.args.target, html, notif.args.delay ?? 0, notif.args.duration ?? 1000);&lt;br /&gt;
  },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: if your bubble could overlap other active elements of the interface (buttons in particular), as it stays in place even after disappearing, you should use a custom class to give it the style &amp;quot;pointer-events: none;&amp;quot; in order to intercept click events.&lt;br /&gt;
&lt;br /&gt;
Note: If you want this visually, but want to take complete control over this bubble and its animation (for example to make it permanent) you can just use div with &#039;discussion_bubble&#039; class on it, and content of div is what will be shown.&lt;br /&gt;
&lt;br /&gt;
== Translations ==&lt;br /&gt;
&lt;br /&gt;
See [[Translations]]&lt;br /&gt;
&lt;br /&gt;
== Players panels ==&lt;br /&gt;
&lt;br /&gt;
=== Adding stuff to player&#039;s panel ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.playerPanels.getElement(player_id: number): HTMLElement&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns the div in the player panel you can put your counters &amp;amp; other indicators in.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example&#039;&#039;&#039;&lt;br /&gt;
Add this piece of code in your JS file to add this template to each player panel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Setting up player boards&lt;br /&gt;
            for( var player_id in gamedatas.players )&lt;br /&gt;
            {&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                         &lt;br /&gt;
                // Setting up players boards if needed&lt;br /&gt;
                const html = `&amp;lt;div class=&amp;quot;cp_board&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;div id=&amp;quot;stoneicon_p${player.id}&amp;quot; class=&amp;quot;gmk_stoneicon gmk_stoneicon_${player.color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;span id=&amp;quot;stonecount_p${player.id}&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;`;&lt;br /&gt;
                this.bga.playerPanels.getElement(player_id).insertAdjacentHTML(&#039;beforeend&#039;, html);&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Note: the code above is of course from your &amp;quot;setup&amp;quot; function in your Javascript).&lt;br /&gt;
&lt;br /&gt;
Very often, you have to distinguish current player and others players. In this case, you just have to change the content of the &amp;lt;code&amp;gt;html&amp;lt;/code&amp;gt; variable when &amp;quot;player_id&amp;quot; is different than &amp;quot;this.bga.players.getCurrentPlayerId()&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Adding a player panel for an automata ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.playerPanels.addAutomataPlayerPanel(id: number, name: string, params: Object): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The id is the automata id, used to setup the player panel score counter and getPlayerPanelElement. 0 or negative value is recommended, to avoid conflict with real player ids.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
*id: the automata id, used to setup the player panel score counter and getPlayerPanelElement. 0 or negative value is recommended, to avoid conflict with real player ids.&lt;br /&gt;
*name: the name of the automata&lt;br /&gt;
*params: object optionally containing one or more of the following:&lt;br /&gt;
**color: string - the automata player color (default black)&lt;br /&gt;
**iconClass: string - the class, or list of classes separated by spaces, to apply to the player picture.&lt;br /&gt;
**score: number - the automata score (default undefined, will display &#039;-&#039;)&lt;br /&gt;
&lt;br /&gt;
Example from Glow, with the automata Tom when playing solo :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.playerPanels.addAutomataPlayerPanel(0, &#039;Tom&#039;, {&lt;br /&gt;
    iconClass: &#039;tom-avatar&#039;,&lt;br /&gt;
    score: gamedatas.tom.score,&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s panel disabling/enabling ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.disablePlayerPanel(player_id: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disable given player panel (the panel background become gray).&lt;br /&gt;
&lt;br /&gt;
Usually, this is used to signal that this played passes, or will be inactive during a while.&lt;br /&gt;
&lt;br /&gt;
Note that the only effect of this is visual. There are no consequences on the behaviour of the panel itself.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.enablePlayerPanel(player_id:number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable a player panel that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.enableAllPlayerPanels(): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Enable all player panels that has been disabled before.&lt;br /&gt;
&lt;br /&gt;
=== Player order ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.updatePlayerOrdering(): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function makes sure that player order in player&#039;s panel matches this.gamedatas.playerorder and its normally called by framework.&lt;br /&gt;
You can call it yoursel if you change this.gamedatas.playerorder from notification.&lt;br /&gt;
Also you can override this function to change defaults  OR insert a non-player panel [[BGA_Studio_Cookbook#Inserting_non-player_panel]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Counters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.playerPanels.getScoreCounter(player_id: number): Counter&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Returns the score counter on the player panel.&lt;br /&gt;
&lt;br /&gt;
To create other counters on the player panel, please use the &amp;quot;ebg/counter&amp;quot; library, documented at [[Counter]].&lt;br /&gt;
&lt;br /&gt;
== BGA GUI components ==&lt;br /&gt;
&lt;br /&gt;
BGA framework provides some useful ready-to-use components for the game interface:&lt;br /&gt;
&lt;br /&gt;
[[Studio#BGA_Studio_game_components_reference]]&lt;br /&gt;
&lt;br /&gt;
Note that each time you are using an additional component, you must declare it at the top of your Javascript file in the list of modules used.&lt;br /&gt;
&lt;br /&gt;
Example with the Game.js file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const BgaAnimations = await importEsmLib(&#039;bga-animations&#039;, &#039;1.x&#039;);&lt;br /&gt;
const [Counter, Stock] = await importDojoLibs([&amp;quot;ebg/counter&amp;quot;, &amp;quot;ebg/stock&amp;quot;]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example with the legacy way if you are using &amp;quot;ebg.stock&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;  /// &amp;lt;=== we are using ebg.stock module&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA Buttons ==&lt;br /&gt;
&lt;br /&gt;
=== Basic Button ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.addActionButton(id: string, label: string, method: string | eventhandler, destination?: string, blinking?: boolean, color?: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;Deprecated, use [https://en.doc.boardgamearena.com/Game_interface_logic:_yourgamename.js#Title_bar this.bga.statusBar.addActionButton] instead&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use this method to add an action button in the main action status bar (or other places).&lt;br /&gt;
&lt;br /&gt;
Arguments:&lt;br /&gt;
*id: an element ID that should be unique in your HTML DOM document.&lt;br /&gt;
*label: the text of the button. Should be translatable (use _() function). Note: this can also be any html, such as &amp;quot;&amp;lt;div class=&amp;quot;brick&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, see example below on how to make image action buttons.&lt;br /&gt;
*method: the name of your method that must be triggered when the player clicks on this button (can be name of the method on game class or handler).&lt;br /&gt;
*destination (optional): id of parent on where to add button, ONLY use in rare cases if location is not action bar. Use &#039;&#039;&#039;null&#039;&#039;&#039; as value if you need to specify other arguments.&lt;br /&gt;
*blinking (optional): if set to &#039;&#039;&#039;true&#039;&#039;&#039;, the button is going blink to catch player&#039;s attention. Please DO NOT abuse blinking button. If you need button to blink after some time passed add class &#039;blinking&#039; to the button later.&lt;br /&gt;
*color: could be &#039;&#039;&#039;blue&#039;&#039;&#039; (default), &#039;&#039;&#039;red&#039;&#039;&#039;,&#039;&#039;&#039;gray&#039;&#039;&#039; or &#039;&#039;&#039;none&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You should only use this method in your &amp;quot;onUpdateActionButtons&amp;quot; method. Usually, you use it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onUpdateActionButtons( stateName, args ) {                      &lt;br /&gt;
            if (this.players.isCurrentPlayerActive()) {            &lt;br /&gt;
                switch( stateName ) {&lt;br /&gt;
                case &#039;giveCards&#039;:&lt;br /&gt;
                    this.bga.statusBar.addActionButton(_(&#039;Give selected cards&#039;), () =&amp;gt; this.onGiveCards() ); &lt;br /&gt;
                    this.bga.statusBar.addActionButton(_(&#039;Pass&#039;), () =&amp;gt; this.actions.performAction(&#039;actPass&#039;) ); &lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are adding a &amp;quot;Give selected cards&amp;quot; button in the case we are on game state &amp;quot;giveCards&amp;quot;. When player clicks on this button, it triggers our &amp;quot;onGiveCards&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
===Image Button===&lt;br /&gt;
&lt;br /&gt;
You can use the same method, but add extra class to a button to disable the padding and style it, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.addActionButton( &#039;button_brick&#039;, &#039;&amp;lt;div class=&amp;quot;brick&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, ()=&amp;gt;{... on brick ...}, null, null, &#039;gray&#039;); &lt;br /&gt;
dojo.addClass(&#039;button_brick&#039;,&#039;bgaimagebutton&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.bgaimagebutton {&lt;br /&gt;
  padding: 0px 12px;&lt;br /&gt;
  min-height: 28px;&lt;br /&gt;
  border: none;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use this a lot, you can define a helper function, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This method can be used instead of addActionButton, to add a button which is an image (i.e. resource). Can be useful when player&lt;br /&gt;
 * need to make a choice of resources or tokens.&lt;br /&gt;
 */&lt;br /&gt;
addImageActionButton(id, div, handler, bcolor, tooltip) {&lt;br /&gt;
	if (typeof bcolor == &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
		bcolor = &amp;quot;gray&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
	// this will actually make a transparent button id color = gray&lt;br /&gt;
	this.bga.gameui.addActionButton(id, div, handler, null, false, bcolor);&lt;br /&gt;
	// remove border, for images it better without&lt;br /&gt;
	dojo.style(id, &amp;quot;border&amp;quot;, &amp;quot;none&amp;quot;);&lt;br /&gt;
	// but add shadow style (box-shadow, see css)&lt;br /&gt;
	dojo.addClass(id, &amp;quot;shadow bgaimagebutton&amp;quot;);&lt;br /&gt;
	// you can also add additional styles, such as background&lt;br /&gt;
	if (tooltip) {&lt;br /&gt;
		dojo.attr(id, &amp;quot;title&amp;quot;, tooltip);&lt;br /&gt;
	}&lt;br /&gt;
	return $(id);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Disabling Button===&lt;br /&gt;
&lt;br /&gt;
You can disable the &#039;&#039;&#039;bgabutton&#039;&#039;&#039; by adding the css class &#039;&#039;&#039;disabled&#039;&#039;&#039; in you js. The disabled button is still visible but is grey and not clickable.&lt;br /&gt;
For example in the &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039; : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.addActionButton(&#039;play_button_id&#039;, _(&#039;Play 1 to 3 cards&#039;), () =&amp;gt; this.playFunctionButton()); &lt;br /&gt;
if (condition) {&lt;br /&gt;
  dojo.addClass(&#039;play_button_id&#039;, &#039;disabled&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Custom Buttons===&lt;br /&gt;
&lt;br /&gt;
You can create a custom button, but the BGA framework provides a standard button that requires only .css classes: &#039;&#039;&#039;bgabutton&#039;&#039;&#039; and &#039;&#039;&#039;bgabutton_${color}&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Examples:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_blue&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My blue button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;a href=&amp;quot;#&amp;quot; id=&amp;quot;my_button_id&amp;quot; class=&amp;quot;bgabutton bgabutton_red bgabutton_big&amp;quot;&amp;gt;&amp;lt;span&amp;gt;My big red button&amp;lt;/span&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: To see it in action, check out &#039;&#039;Coloretto&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Button outside of action bar===&lt;br /&gt;
&lt;br /&gt;
Use addActionButton() method with destination argument set&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.addActionButton( &#039;commit_button&#039;, _(&#039;Confirm&#039;), () =&amp;gt; this.onConfirm(), &#039;player_board&#039;, true, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in example above the button will be place on object with id &#039;player_board&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Image loading ==&lt;br /&gt;
&lt;br /&gt;
See also [[Game_art:_img_directory]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Be careful&#039;&#039;&#039;: by default, ALL images at the root of your img directory are loaded on a player&#039;s browser when he loads the game. For this reason, don&#039;t let in your img directory images that are not useful, otherwise it&#039;s going to slowdown the game load. Images in a subfolder of img are NOT preloaded by default.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.images.dontPreloadImage(image_file_name: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.images.dontPreloadImages(image_file_names: string[])&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using dontPreloadImage, you tell the interface to not preload a specific image in your img directory. dontPreloadImages is the same for multiple images at once.&lt;br /&gt;
&lt;br /&gt;
Examples of use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// don&#039;t preload a particular image&lt;br /&gt;
this.bga.images.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
&lt;br /&gt;
// don&#039;t preload a list of unused images (gamedatas.clans contains the number of the clans used in this game).&lt;br /&gt;
this.bga.images.dontPreloadImages([1,2,3,4,5,6].filter(clan =&amp;gt; !gamedatas.clans.include(clan)).map(clan =&amp;gt; `clan${clan}.png`));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.images.preloadImage(image_file_name: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.images.preloadImages(image_file_names: string[])&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Opposite of dontPreloadImage, useful only for images that are not in the root img folder&lt;br /&gt;
Example of use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// preload a particular image&lt;br /&gt;
if (gamedatas.expansionActive) {&lt;br /&gt;
  this.bga.images.preloadImages([&#039;expansion/board.jpg&#039;, &#039;expansion/new-cards.jpg&#039;]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Sounds ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.sounds.load(id: string, label: string, fileName: string = undefined): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Load a sound and register its id. Filename is without the extension. If fileName is unset, it will use the same as the id.&lt;br /&gt;
&lt;br /&gt;
In any case, the sound should be placed on your img folder and exist bothe with the mp3 and ogg format/extension.&lt;br /&gt;
&lt;br /&gt;
Examples :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.sounds.load(&#039;play&#039;); // will load play.ogg / play.mp3 in the img dir, and will be playable with id `play`&lt;br /&gt;
this.bga.sounds.load(&#039;claw&#039;, &#039;smash&#039;); // will load smash.ogg / smash.mp3 in the img dir, and will be playable with id `claw`&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.sounds.play(id: string): void&#039;&#039;&#039;&lt;br /&gt;
Play a sound by its id, loaded in the setup with &#039;&#039;this.sounds.load&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Examples :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.sounds.play(&#039;play&#039;); &lt;br /&gt;
this.bga.sounds.play(&#039;claw&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.gameui.disableNextMoveSound(): void&#039;&#039;&#039;&lt;br /&gt;
Disable the standard &amp;quot;move&amp;quot; sound for this move (to replace it with your custom sound):&lt;br /&gt;
&lt;br /&gt;
Add this to your notification handler:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.bga.gameui.disableNextMoveSound();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: it only disable the sound for the next move.&lt;br /&gt;
&lt;br /&gt;
== Status bar ==&lt;br /&gt;
&lt;br /&gt;
=== Status bar text ===&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;this.bga.statusBar.setTitle(title: string, args?: object)&#039;&#039;&#039;&lt;br /&gt;
Update the page title (aka status bar prompt). Can handle ${you} and ${actplayer} and any other var you would pass as args.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (args.mandatory_card_name) {&lt;br /&gt;
    const mandatoryCardTitle = this.bga.players.isCurrentPlayerActive() ? _(&#039;${you} must take ${mandatory_card_name}&#039;) : _(&#039;${actplayer} must take ${mandatory_card_name}&#039;);&lt;br /&gt;
    this.bga.statusBar.setTitle(mandatoryCardTitle, args);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
As opposed to &amp;lt;code&amp;gt;updatePageTitle&amp;lt;/code&amp;gt;, it doesn&#039;t trigger the call &amp;lt;code&amp;gt;onUpdateActionButtons&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;this.bga.gameui.updatePageTitle()&#039;&#039;&#039;&lt;br /&gt;
:This function allows to update the current page title and turn description according to the game state arguments. If the current game state description this.gamedatas.gamestate.descriptionmyturn is modified before calling this function it allows to update the turn description without changing state. This will handle arguments substitutions properly.&lt;br /&gt;
&lt;br /&gt;
Note: this functional also will calls this.onUpdateActionButtons, if you want different buttons then state defaults, use method in example to replace them, if it becomes too clumsy use client states (see above)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;DEPRECATED:&amp;lt;/b&amp;gt; use this.bga.statusBar.setTitle instead.&lt;br /&gt;
&lt;br /&gt;
=== Status bar buttons ===&lt;br /&gt;
;&#039;&#039;&#039;this.bga.statusBar.addActionButton(label: string, callback: Function, params?: object): HTMLButtonElement&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
*label: the label to be shown, can be html. If label if used pass traslated string, i.e. _(&#039;Yes&#039;)&lt;br /&gt;
*callback: function to call on click, cannot be method name it has to be function&lt;br /&gt;
*params: object optionally containing one of more of the following:&lt;br /&gt;
**color: string - can be &amp;lt;code&amp;gt;primary&amp;lt;/code&amp;gt; (default) (blue), &amp;lt;code&amp;gt;secondary&amp;lt;/code&amp;gt; (gray), &amp;lt;code&amp;gt;alert&amp;lt;/code&amp;gt; (red)&lt;br /&gt;
**id: string - is the dom element id to set. If null/undefined, the button will not have an id, but you can still manipulate it by storing the reference to the DOM Element returned by the function&lt;br /&gt;
**classes: string|string[] - i.e &amp;lt;code&amp;gt;&#039;disabled blinking&#039;&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;[&#039;disabled&#039;, &#039;blinking&#039;]&amp;lt;/code&amp;gt;.&lt;br /&gt;
**destination: ElementOrId - the DOM Element to add the button to. If not specified, will add it to the status bar.&lt;br /&gt;
**title: string - plain text description of the label. Should be set when the button label is an icon, for accessibility.&lt;br /&gt;
**disabled: boolean - makes the button disabled. Will prevent the callback to be executed&lt;br /&gt;
**tooltip: string - the tooltip of the button&lt;br /&gt;
**confirm: string | Function - the confirm message to display before triggering the callback, if set (or function handler, see example below).&lt;br /&gt;
**autoclick: boolean if the button should be auto clicked after a small delay (for Confirmation buttons).&lt;br /&gt;
&lt;br /&gt;
Example of a standard call without params:&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Pass&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actPass&#039;, {}));&lt;br /&gt;
&lt;br /&gt;
Example of a standard call with params:&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Pass&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actPass&#039;, {}), {&lt;br /&gt;
    id: &#039;my_button&#039;,&lt;br /&gt;
    color: &#039;secondary&#039;,&lt;br /&gt;
    classes: &#039;my-outline-class&#039;&lt;br /&gt;
    disabled: true,&lt;br /&gt;
    tooltip: _(&#039;You cannot pass&#039;),&lt;br /&gt;
    confirm: _(&#039;Are you sure to pass?&#039;),&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
Note: the confirm parameter can be a string or a function that returns a string or null&lt;br /&gt;
&lt;br /&gt;
Example of a standard call with params:&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Discard Selected Cards&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actDiscard&#039;, { cardIds: this.getSelectedCardIds().join(&#039;,&#039;) }), {&lt;br /&gt;
    confirm: () =&amp;gt; {&lt;br /&gt;
      if (this.getSelectedCardIds().length === 0) { // no card is selected, show the warning&lt;br /&gt;
        return _(&#039;Are you sure you don&#039;t want to discard any cards?&#039;);&lt;br /&gt;
      } else { // cards are selected, do not show the warning&lt;br /&gt;
        return null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
Example of confirm button with autoclick animation:&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Confirm&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actConfirm&#039;, {}), {&lt;br /&gt;
    autoclick: true&lt;br /&gt;
  });&lt;br /&gt;
  // if you have a user preference to auto-confirm&lt;br /&gt;
  this.bga.statusBar.addActionButton(_(&#039;Confirm&#039;), () =&amp;gt; this.bga.actions.performAction(&#039;actConfirm&#039;, {}), {&lt;br /&gt;
    autoclick: this.userPreferences.get(100) == 1, // adapt to your user preference id and values&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;this.bga.statusBar.removeActionButtons()&#039;&#039;&#039;&lt;br /&gt;
Removes all buttons from title bar&lt;br /&gt;
&lt;br /&gt;
==User preferences ==&lt;br /&gt;
&#039;&#039;&#039;this.bga.userPreferences.get(pref_id)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return the value of a user preference. It will return the value currently selected in the select combo box, in the top-right menu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.userPreferences.set(pref_id, value)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Programmatically change a user preference. It will have the same effect as if the player changed the value in the select combo box, in the top-right menu.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.userPreferences.onChange&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
A callback you can define if you want to be notified when a user changes a user preference.&lt;br /&gt;
&lt;br /&gt;
Example:&amp;lt;pre&amp;gt;&lt;br /&gt;
// in your Game constructor&lt;br /&gt;
this.bga.userPreferences.onChange = (pref_id, pref_value) =&amp;gt; this.myGamePreferenceChanged(pref_id, pref_value);&lt;br /&gt;
&lt;br /&gt;
myGamePreferenceChanged: function(pref_id, pref_value) {&lt;br /&gt;
  switch (pref_id) {&lt;br /&gt;
    case 201: &lt;br /&gt;
      document.getElementsByTagName(&#039;html&#039;)[0].classList.toggle(&#039;dark-background&#039;, pref_value == 2);&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.bga.userPreferences.toggleVisibility(pref_id, visible)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Hide or show a user preference.&lt;br /&gt;
&lt;br /&gt;
Example:&amp;lt;pre&amp;gt;&lt;br /&gt;
myGamePreferenceChanged: function(pref_id, pref_value) {&lt;br /&gt;
  switch (pref_id) {&lt;br /&gt;
    case 101: &lt;br /&gt;
      // if pref 101 is &amp;quot;Confirm moves&amp;quot; and 102 is &amp;quot;Countdown timer on confirm&amp;quot;, we hide the countdown user preference when confirm moves is disabled.&lt;br /&gt;
      this.bga.userPreferences.toggleVisibility(102, prefValue != 2);&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Including classes from external files ==&lt;br /&gt;
You can declare multiple classes in the Game.js file, as long as you export a Game class in the end.&lt;br /&gt;
&lt;br /&gt;
If you want to split your code into multiple js files, export the classes of the file using &amp;lt;code&amp;gt;export class PlayerManager {...}&amp;lt;/code&amp;gt;. You can export multiple classes from the same file file that way.&lt;br /&gt;
&lt;br /&gt;
Then you can import the class in the Game.js file using &amp;lt;code&amp;gt;import { PlayerManager, PlayerTable } from &amp;quot;./PlayerManager.js&amp;quot;;&amp;lt;/code&amp;gt; at the top of the file.&lt;br /&gt;
&lt;br /&gt;
==Other useful stuff ==&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;this.bga.gameui.onScreenWidthChange()&#039;&#039;&#039;&lt;br /&gt;
:This function can be overridden in your game to manage some resizing on the client side when the browser window is resized. This function is also triggered at load time, so it can be used to adapt to the :viewport size at the start of the game too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;this.bga.gameui.bRealtime&lt;br /&gt;
:Return true if the game is in realtime. Note that having a distinct behavior in realtime and turn-based should be exceptional.&lt;br /&gt;
&lt;br /&gt;
;globalThis.g_replayFrom&lt;br /&gt;
:Global contains replay number in live game, it is set to undefined (i.e. not set) when it is not a replay mode, so consequentially the good check is &#039;&#039;&#039;typeof g_replayFrom != &#039;undefined&#039;&#039;&#039;&#039; which returns true if the game is in replay mode &amp;lt;i&amp;gt;during the game&amp;lt;/i&amp;gt; (the game is ongoing but the user clicked &amp;quot;replay from this move&amp;quot; in the log)&lt;br /&gt;
&lt;br /&gt;
;globalThis.g_archive_mode&lt;br /&gt;
:Returns true if the game is in archive mode &amp;lt;i&amp;gt;after the game&amp;lt;/i&amp;gt; (the game has ended)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;this.bga.gameui.instantaneousMode&lt;br /&gt;
:Returns true during replay/archive mode if animations should be skipped. Only needed if you are doing custom animations. (The BGA-provided animation functions like the bga-animations, bga-cards, bga-dice libs and &amp;lt;i&amp;gt;this.bga.gameui.slideToObject()&amp;lt;/i&amp;gt; and similar automatically handle instantaneous mode.)&lt;br /&gt;
:Technically, when you click &amp;quot;replay from move #20&amp;quot;, the system replays the game from the very beginning with moves 0 - 19 happening in instantaneous mode and moves 20+ happening in normal mode.&lt;br /&gt;
&lt;br /&gt;
;globalThis.g_tutorialwritten&lt;br /&gt;
:Returns an object like the below if the game is in tutorial mode, or undefined otherwise. Tutorial mode is a special case of archive mode where comments have been added to a previous game to teach new players the rules.&lt;br /&gt;
    {&lt;br /&gt;
        author: &amp;quot;91577332&amp;quot;,&lt;br /&gt;
        id: &amp;quot;576&amp;quot;,&lt;br /&gt;
        mode: &amp;quot;view&amp;quot;&lt;br /&gt;
        status: &amp;quot;alpha&amp;quot;&lt;br /&gt;
        version_override: null&lt;br /&gt;
        viewer_id: &amp;quot;84554161&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Migration_Guide&amp;diff=27979</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=27979"/>
		<updated>2026-01-07T13:58:47Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: Add dojo.stopEvent()&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;
*...&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;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;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;
=== 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;_() - can also be replaced with clienttranslate when use for non parameterized exceptions strings like &lt;br /&gt;
&lt;br /&gt;
  throw new \BgaUserException(clienttranslate(&#039;You must choose 3 cards&#039;));&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 scoreCtrl 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;
===Access to DOM elements ===&lt;br /&gt;
New functions getPlayerPanelElement(player_id) and this.getGameAreaElement()&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.getGameAreaElement().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;
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 bgaSetupPromiseNotifications is used. 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;
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.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.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;
&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>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Migration_Guide&amp;diff=27962</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=27962"/>
		<updated>2026-01-06T14:49:24Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: Add caution to Dojo usage section about dojo.style returning lengths as raw pixel numbers, not the set CSS style.&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;
*...&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;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;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;
=== 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;_() - can also be replaced with clienttranslate when use for non parameterized exceptions strings like &lt;br /&gt;
&lt;br /&gt;
  throw new \BgaUserException(clienttranslate(&#039;You must choose 3 cards&#039;));&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 scoreCtrl 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;
===Access to DOM elements ===&lt;br /&gt;
New functions getPlayerPanelElement(player_id) and this.getGameAreaElement()&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.getGameAreaElement().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;
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 bgaSetupPromiseNotifications is used. 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;
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.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.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.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;
&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>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Migration_Guide&amp;diff=27933</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=27933"/>
		<updated>2026-01-03T15:31:38Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: /* Dojo usage */&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;
*...&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;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;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;
=== 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;_() - can also be replaced with clienttranslate when use for non parameterized exceptions strings like &lt;br /&gt;
&lt;br /&gt;
  throw new \BgaUserException(clienttranslate(&#039;You must choose 3 cards&#039;));&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 scoreCtrl 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;
===Access to DOM elements ===&lt;br /&gt;
New functions getPlayerPanelElement(player_id) and this.getGameAreaElement()&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.getGameAreaElement().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;
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 bgaSetupPromiseNotifications is used. 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;
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.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.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;
! colspan=&amp;quot;undefined&amp;quot; |Dojo API &lt;br /&gt;
! colspan=&amp;quot;undefined&amp;quot; |Category&lt;br /&gt;
! colspan=&amp;quot;undefined&amp;quot; |Description&lt;br /&gt;
! colspan=&amp;quot;undefined&amp;quot; |Vanilla JS Replacement&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.byId(&amp;quot;id&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |DOM Selection&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Selects a single DOM element by its ID.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;document.getElementById(&amp;quot;id&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.query(&amp;quot;selector&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |DOM Selection&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Selects a collection of DOM elements using CSS selectors.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&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;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.connect(node, &amp;quot;onclick&amp;quot;, fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Event Handling&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Connects an event handler to a DOM element.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;node.addEventListener(&amp;quot;click&amp;quot;, fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.disconnect(handle)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Event Handling&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Removes an event handler created with &amp;lt;code&amp;gt;dojo.connect&amp;lt;/code&amp;gt;.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&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;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.place(node, parent, &amp;quot;last&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |DOM Manipulation&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Places a DOM node inside a parent node at a specific position.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;parent.appendChild(node)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.create(&amp;quot;tag&amp;quot;, props, parent)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |DOM Manipulation&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Creates a new DOM element with optional properties.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&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;
| colspan=&amp;quot;undefined&amp;quot; |&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;
| colspan=&amp;quot;undefined&amp;quot; |Styling&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Sets an inline CSS property on a DOM node.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;node.style.color = &amp;quot;red&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.hasClass(node, &amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Styling&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Checks if a DOM node has a specific CSS class.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;node.classList.contains(&amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.addClass(node, &amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Styling&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Adds a CSS class to a DOM node.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;node.classList.add(&amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.removeClass(node, &amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Styling&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Removes a CSS class from a DOM node.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;node.classList.remove(&amp;quot;className&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.forEach(array, fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Array Utilities&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Iterates over an array.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;array.forEach(fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.map(array, fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Array Utilities&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Transforms an array by applying a function to each element.&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;array.map(fn)&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.fadeOut, dojo.fadeIn&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Animations&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Various animations&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Use https://en.doc.boardgamearena.com/BgaAnimations or CSS animations&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;dojo.hitch(this, &amp;quot;functionName&amp;quot;)&amp;lt;/code&amp;gt;&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Variable scoping&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |Binds &amp;lt;code&amp;gt;this&amp;lt;/code&amp;gt; (or other variable) in a callback&lt;br /&gt;
| colspan=&amp;quot;undefined&amp;quot; |&amp;lt;code&amp;gt;functionName.bind(this)&amp;lt;/code&amp;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>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BgaAnimations&amp;diff=27503</id>
		<title>BgaAnimations</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BgaAnimations&amp;diff=27503"/>
		<updated>2025-12-06T13:32:11Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: Add a developer note about CSS&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;[https://x.boardgamearena.net/data/game-libs/bga-animations/1.x/demo/index.html Demo]&amp;lt;/big&amp;gt;&#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;big&amp;gt;[https://x.boardgamearena.net/data/game-libs/bga-animations/1.x/docs/index.html Doc]&amp;lt;/big&amp;gt;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&#039;&#039;&#039;bga-animations&#039;&#039;&#039; is a javascript component to handle different type of animations.&lt;br /&gt;
&lt;br /&gt;
The lib can handle the scale &amp;amp; rotation of the containers when doing the animation (the Dojo animations in the &amp;quot;this&amp;quot; cannot).&lt;br /&gt;
It is also Promise-based, so easy to plug-in with the async notification functions.&lt;br /&gt;
The lib relies on the Element.animate function.&lt;br /&gt;
&lt;br /&gt;
The game Reversi is an example of usage.&lt;br /&gt;
&lt;br /&gt;
== Usage ==&lt;br /&gt;
Load the lib:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    getLibUrl(&#039;bga-animations&#039;, &#039;1.x&#039;),&lt;br /&gt;
],&lt;br /&gt;
function (dojo, declare, gamegui, counter, BgaAnimations) { // note that the index of `BgaAnimations` must match the index of the define array&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In your game setup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // create the animation manager, and bind it to the `game.bgaAnimationsActive()` function&lt;br /&gt;
        this.animationManager = new BgaAnimations.Manager({&lt;br /&gt;
            animationsActive: () =&amp;gt; this.bgaAnimationsActive(),&lt;br /&gt;
        });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
notif_moveMeeple: async function(args) {&lt;br /&gt;
    const meepleDiv = document.getElementById(`player-meeple-${args.playerId}`);&lt;br /&gt;
    const destinationDiv = document.getElementById(`table-slot-${args.slot}`);&lt;br /&gt;
    await this.animationManager.slideAndAttach(meepleDiv, destinationDiv);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
notif_scoreMeeple: async function(args) {&lt;br /&gt;
    const meepleDiv = document.getElementById(`player-meeple-${args.playerId}`);&lt;br /&gt;
    await this.animationManager.displayScoring(meepleDiv, args.sscore, this.gamedatas.players[args.playerId].color);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Look at the demo page and the demo source code for a list of all possibilities!&lt;br /&gt;
&lt;br /&gt;
== Versioning ==&lt;br /&gt;
The lib is using semver, so you can require 1.x to be sure to have the last fixes without risking a breaking change. Any breaking change will be noted on the Changelog section.&lt;br /&gt;
&lt;br /&gt;
== Using with TypeScript ==&lt;br /&gt;
If you use TypeScript and this lib, you can download the &#039;&#039;&#039;[https://x.boardgamearena.net/data/game-libs/bga-animations/1.x/dist/bga-animations.d.ts d.ts]&#039;&#039;&#039; file to put in on your game folder to benefit from auto-completion. Depending on the way you build, you might need to remove the last line (the export instruction) to be able to use it.&lt;br /&gt;
&lt;br /&gt;
If your game class is not declared on the define callback, you will need to modify it with this trick (to avoid a &amp;quot;ReferenceError: BgaAnimations is not defined&amp;quot; error) :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
        &amp;quot;dojo&amp;quot;,&lt;br /&gt;
        &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
        &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
        &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
        &amp;quot;ebg/stock&amp;quot;,&lt;br /&gt;
        getLibUrl(&#039;bga-animations&#039;, &#039;1.x&#039;),&lt;br /&gt;
    ],&lt;br /&gt;
function (dojo, declare, gamegui, counter, stock, BgaAnimations) {&lt;br /&gt;
    (window as any).BgaAnimations = BgaAnimations; //trick&lt;br /&gt;
    return declare(&amp;quot;bgagame.reforest&amp;quot;, ebg.core.gamegui, new Reforest());&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Developer notes ==&lt;br /&gt;
&lt;br /&gt;
For all elements which will be animated, it is recommended to use CSS class selectors to style them (not, e.g., ID or parent-based selectors). This is because the animations typically clone the element to animate (giving it a new ID), and the DOM parentage may change as well. Symptoms that this address are things like &amp;lt;code&amp;gt;slideOutAndDestroy&amp;lt;/code&amp;gt; simply causing the element to disappear, or &amp;lt;code&amp;gt;slideAndAttach&amp;lt;/code&amp;gt; causing the element to &amp;quot;jump&amp;quot; to the destination.&lt;br /&gt;
&lt;br /&gt;
== Changelog ==&lt;br /&gt;
&#039;&#039;&#039;1.0.2&#039;&#039;&#039;: fix error when a parallelAnimation is null&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.0.1&#039;&#039;&#039;: Fix documentation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.0.0&#039;&#039;&#039;: Initial version&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=26946</id>
		<title>BGA Studio Cookbook</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=BGA_Studio_Cookbook&amp;diff=26946"/>
		<updated>2025-10-23T17:41:21Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: For tooltips in logs, add how to accomplish addToLog using promise-based notifications.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
This page is a cookbook of design and implementation recipes for BGA Studio framework.&lt;br /&gt;
For tooling and usage recipes see [[Tools and tips of BGA Studio]].&lt;br /&gt;
If you have your own recipes feel free to edit this page.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Visual Effects, Layout and Animation ==&lt;br /&gt;
&lt;br /&gt;
=== DOM manipulatons ===&lt;br /&gt;
&lt;br /&gt;
==== Create pieces dynamically (using template) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
Note: this method is recommended by BGA guildlines&lt;br /&gt;
&lt;br /&gt;
Declared js template with variables in .tpl file, like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    // Javascript HTML templates&lt;br /&gt;
    var jstpl_ipiece = &#039;&amp;lt;div class=&amp;quot;${type} ${type}_${color} inlineblock&amp;quot; aria-label=&amp;quot;${name}&amp;quot; title=&amp;quot;${name}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Use it like this in .js file&lt;br /&gt;
  div = this.format_block(&#039;jstpl_ipiece&#039;, {&lt;br /&gt;
                                type : &#039;meeple&#039;,&lt;br /&gt;
                                color : &#039;ff0000&#039;,&lt;br /&gt;
                                name : &#039;Bob&#039;,&lt;br /&gt;
                            });&lt;br /&gt;
  &lt;br /&gt;
Then you do whatever you need to do with that div, this one specifically design to go to log entries, because it has embedded title (otherwise its a picture only) and no id.&lt;br /&gt;
&lt;br /&gt;
Note: you could have place this variable in js itself, but keeping it in .tpl allows you to have your js code be free of HTML. Normally it never happens but&lt;br /&gt;
it is good to strive for it.&lt;br /&gt;
Note: you can also use string concatenation, its less readable. You can also use dojo dom object creation api&#039;s but its brutally verbose and its more unreadable.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Create pieces dynamically (using string concatenation) ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  div = &amp;quot;&amp;lt;div class=&#039;meeple_&amp;quot;+color+&amp;quot;&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or modern way&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  div = `&amp;lt;div class=&#039;meeple_${color}&#039;&amp;gt;&amp;lt;/div&amp;gt;`;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Create all pieces statically ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.css, ggg.view.php (optional) &lt;br /&gt;
&lt;br /&gt;
* Create ALL game pieces in html template (.tpl)&lt;br /&gt;
* ALL pieces should have unique id, and it should be meaningful, i.e. meeple_red_1&lt;br /&gt;
* Do not use inline styling&lt;br /&gt;
* Id of player&#039;s specific pieces should use some sort of &#039;color&#039; identification, since player id cannot be used in static layout, you can use english color name, hex 6 char value, or color &amp;quot;number&amp;quot; (1,2,3...)&lt;br /&gt;
* Pieces should have separated class for its color, type, etc, so it can be easily styled in groups. In example below you now can style all meeples, all red meeples or all red tokens, or all &amp;quot;first&amp;quot; meeples&lt;br /&gt;
&lt;br /&gt;
ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
  &amp;lt;div id=&amp;quot;home_red&amp;quot; class=&amp;quot;home_red home&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_1&amp;quot; class=&amp;quot;meeple red n1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
     &amp;lt;div id=&amp;quot;meeple_red_2&amp;quot; class=&amp;quot;meeple red n2&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.css:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.meeple {&lt;br /&gt;
	width: 32px;&lt;br /&gt;
	height: 39px;&lt;br /&gt;
	background-image: url(img/78_64_stand_meeples.png);&lt;br /&gt;
	background-size: 352px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.meeple.red {&lt;br /&gt;
	background-position: 30% 0%;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* There should be straight forward mapping between server id and js id (or 1:1)&lt;br /&gt;
* You place objects in different zones of the layout, and setup css to take care of layout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.home .meeple{&lt;br /&gt;
   display: inline-block;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you need to have a temporary object that look like original you can use dojo.clone (and change id to some temp id)&lt;br /&gt;
* If there is lots of repetition or zone grid you can use template generator, but inject style declaration in css instead of inline style for flexibility&lt;br /&gt;
&lt;br /&gt;
Note:&lt;br /&gt;
* If you use this model you cannot use premade js components such as Stock and Zone&lt;br /&gt;
* You have to use alternative methods of animation (slightly altered) since default method will leave object with inline style attributes which you don&#039;t need&lt;br /&gt;
&lt;br /&gt;
==== Use player color in template ====&lt;br /&gt;
&lt;br /&gt;
NOTE: view.php is deprecated, its best to generate html from .js&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.view.php&lt;br /&gt;
&lt;br /&gt;
.view.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function build_page($viewArgs) {&lt;br /&gt;
        // Get players &amp;amp; players number&lt;br /&gt;
        $players = $this-&amp;gt;game-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        $players_nbr = count($players);&lt;br /&gt;
        /**&lt;br /&gt;
         * ********* Place your code below: ***********&lt;br /&gt;
         */&lt;br /&gt;
        &lt;br /&gt;
        // Set PCOLOR to the current player color hex&lt;br /&gt;
        $cplayer = $this-&amp;gt;getCurrentPlayerId();&lt;br /&gt;
        if (array_key_exists($cplayer, $players)) { // may be not set if spectator&lt;br /&gt;
            $player_color = $players [$cplayer] [&#039;player_color&#039;];&lt;br /&gt;
        } else {&lt;br /&gt;
            $player_color = &#039;ffffff&#039;; // spectator&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;tpl [&#039;PCOLOR&#039;] = $player_color;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Status bar ===&lt;br /&gt;
&lt;br /&gt;
==== Changing state prompt ====&lt;br /&gt;
&lt;br /&gt;
State prompt is message displayed for player which usually comes from state description.&lt;br /&gt;
Sometimes you want to change it without changing state (one way is change state but locally, see client states above).&lt;br /&gt;
&lt;br /&gt;
Simple way just change the html&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setMainTitle: function(text) {&lt;br /&gt;
            $(&#039;pagemaintitletext&#039;).innerHTML = text;&lt;br /&gt;
        },&lt;br /&gt;
         // usage&lt;br /&gt;
        onMeeple: function(event) {&lt;br /&gt;
              //... &lt;br /&gt;
              this.setMainTitle(_(&#039;You must select where meeple is going&#039;));&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This however will not work with parameters and will not draw You in color, if you want this its more sophisticated:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setDescriptionOnMyTurn : function(text) {&lt;br /&gt;
            this.gamedatas.gamestate.descriptionmyturn = text;&lt;br /&gt;
            var tpl = dojo.clone(this.gamedatas.gamestate.args);&lt;br /&gt;
            if (tpl === null) {&lt;br /&gt;
                tpl = {};&lt;br /&gt;
            }&lt;br /&gt;
            var title = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.isCurrentPlayerActive() &amp;amp;&amp;amp; text !== null) {&lt;br /&gt;
                tpl.you = this.divYou(); &lt;br /&gt;
            }&lt;br /&gt;
            title = this.format_string_recursive(text, tpl);&lt;br /&gt;
&lt;br /&gt;
            if (!title) {&lt;br /&gt;
                this.setMainTitle(&amp;quot;&amp;amp;nbsp;&amp;quot;);&lt;br /&gt;
            } else {&lt;br /&gt;
                this.setMainTitle(title);&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this method uses &#039;&#039;&#039;setMainTitle&#039;&#039;&#039; defined above and &#039;&#039;&#039;divYou&#039;&#039;&#039; defined in another section of this wiki.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Animation ===&lt;br /&gt;
&lt;br /&gt;
==== Attach to new parent without destroying the object ====&lt;br /&gt;
&lt;br /&gt;
BGA function attachToNewParent for some reason destroys the original, if you want similar function that does not you can use this&lt;br /&gt;
ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        /**&lt;br /&gt;
         * This method will attach mobile to a new_parent without destroying, unlike original attachToNewParent which destroys mobile and&lt;br /&gt;
         * all its connectors (onClick, etc)&lt;br /&gt;
         */&lt;br /&gt;
        attachToNewParentNoDestroy: function (mobile_in, new_parent_in, relation, place_position) {&lt;br /&gt;
&lt;br /&gt;
            const mobile = $(mobile_in);&lt;br /&gt;
            const new_parent = $(new_parent_in);&lt;br /&gt;
&lt;br /&gt;
            var src = dojo.position(mobile);&lt;br /&gt;
            if (place_position)&lt;br /&gt;
                mobile.style.position = place_position;&lt;br /&gt;
            dojo.place(mobile, new_parent, relation);&lt;br /&gt;
            mobile.offsetTop;//force re-flow&lt;br /&gt;
            var tgt = dojo.position(mobile);&lt;br /&gt;
            var box = dojo.marginBox(mobile);&lt;br /&gt;
            var cbox = dojo.contentBox(mobile);&lt;br /&gt;
            var left = box.l + src.x - tgt.x;&lt;br /&gt;
            var top = box.t + src.y - tgt.y;&lt;br /&gt;
&lt;br /&gt;
            mobile.style.position = &amp;quot;absolute&amp;quot;;&lt;br /&gt;
            mobile.style.left = left + &amp;quot;px&amp;quot;;&lt;br /&gt;
            mobile.style.top = top + &amp;quot;px&amp;quot;;&lt;br /&gt;
            box.l += box.w - cbox.w;&lt;br /&gt;
            box.t += box.h - cbox.h;&lt;br /&gt;
            mobile.offsetTop;//force re-flow&lt;br /&gt;
            return box;&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Animation on oversurface ====&lt;br /&gt;
If you use non-absolute position for your game elements (i.e you use layouts) - you cannot really use BGA animation functions. After years of fidding with different options I use&lt;br /&gt;
techique which I call animation on oversurface that works when parents use different zoom, rotation, etc&lt;br /&gt;
&lt;br /&gt;
* You need another layer on top of everything - oversurface&lt;br /&gt;
* We create copy of the object on oversurface - to move&lt;br /&gt;
* We move the real object on final position - but make it invisible for now&lt;br /&gt;
* We move the phantom to final position applying required zoom and rotation (using css animation), then destroy it&lt;br /&gt;
* When animation is done we make original object visible in new position&lt;br /&gt;
&lt;br /&gt;
The code is bit complex it can be found here&lt;br /&gt;
&lt;br /&gt;
https://codepen.io/VictoriaLa/pen/gORvdJo&lt;br /&gt;
&lt;br /&gt;
Game using it: century, ultimaterailroads&lt;br /&gt;
&lt;br /&gt;
==== Scroll element into view ====&lt;br /&gt;
Ingredients: game.js&lt;br /&gt;
&lt;br /&gt;
This function will scroll given node (div) into view and respect replays and archive mode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    scrollIntoViewAfter: function (node, delay) {&lt;br /&gt;
      if (this.instantaneousMode || this.inSetup) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      if (typeof g_replayFrom != &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
        $(node).scrollIntoView();&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      if (!delay) delay = 0;&lt;br /&gt;
      setTimeout(() =&amp;gt; {&lt;br /&gt;
        $(node).scrollIntoView({ behavior: &amp;quot;smooth&amp;quot;, block: &amp;quot;center&amp;quot; });&lt;br /&gt;
      }, delay);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Set Auto-click timer for buttons (setAutoClick) ====&lt;br /&gt;
&lt;br /&gt;
Sets up auto-click for a button after a timeout, with the new progress-bar animation. Works in both JS and TS. You can pass the optional parameters (see code comments) or simply call as:&lt;br /&gt;
&amp;lt;pre&amp;gt;this.setAutoClick(document.getElementById(&#039;someID&#039;);&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: use it only if this.statusBar.addActionButton(..., { autoclick: true }) doesn&#039;t fit your needs! Don&#039;t hesitate to tell BGA why it doesn&#039;t fit your needs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;JavaScript&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
* Sets up auto-click functionality for a button after a timeout period&lt;br /&gt;
* @param button - The button HTML element to auto-click&lt;br /&gt;
* @param timeoutDuration - Optional base duration in ms before auto-click occurs (default: 5000)&lt;br /&gt;
* @param randomIncrement - Optional random additional ms to add to timeout (default: 2000)&lt;br /&gt;
* @param autoClickID - Optional ID for the auto-click events, multiple buttons can therefore point to the same autoClick event&lt;br /&gt;
* @param onAnimationEnd - Optional callback that returns boolean to control if click should occur (default: true)&lt;br /&gt;
*/&lt;br /&gt;
setAutoClick: function(button, timeoutDuration = 5000, randomIncrement = 2000, autoClickID = null, onAnimationEnd = () =&amp;gt; true) {&lt;br /&gt;
    const totalDuration = timeoutDuration + Math.random() * randomIncrement;&lt;br /&gt;
    this.setAutoClick.timeouts = this.setAutoClick.timeouts || {};&lt;br /&gt;
            &lt;br /&gt;
    if(!autoClickID){&lt;br /&gt;
        this.setAutoClick.autoClickIncrement = this.setAutoClick.autoClickIncrement || 1;&lt;br /&gt;
        autoClickID = &#039;auto-click-&#039; + this.setAutoClick.autoClickIncrement++;&lt;br /&gt;
    }&lt;br /&gt;
    this.setAutoClick.timeouts[autoClickID] = this.setAutoClick.timeouts[autoClickID] || [];&lt;br /&gt;
&lt;br /&gt;
    button.style.setProperty(&#039;--bga-autoclick-timeout-duration&#039;, `${totalDuration}ms`);&lt;br /&gt;
    button.classList.add(&#039;bga-autoclick-button&#039;);&lt;br /&gt;
&lt;br /&gt;
    const stopDoubleTrigger = () =&amp;gt; {&lt;br /&gt;
        if(!this.setAutoClick.timeouts[autoClickID]) return;&lt;br /&gt;
        this.setAutoClick.timeouts[autoClickID].forEach(timeout =&amp;gt; clearTimeout(timeout));&lt;br /&gt;
        delete this.setAutoClick.timeouts[autoClickID];&lt;br /&gt;
    }&lt;br /&gt;
    button.addEventListener(&#039;click&#039;, stopDoubleTrigger, true);&lt;br /&gt;
               &lt;br /&gt;
    this.setAutoClick.timeouts[autoClickID].push(&lt;br /&gt;
        setTimeout(() =&amp;gt; {&lt;br /&gt;
            stopDoubleTrigger();&lt;br /&gt;
            if (!document.body.contains(button)) return;&lt;br /&gt;
            const customEventResult = onAnimationEnd();&lt;br /&gt;
            if (customEventResult) button.click();&lt;br /&gt;
        }, totalDuration)&lt;br /&gt;
    );&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;TypeScript&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
* Sets up auto-click functionality for a button after a timeout period&lt;br /&gt;
* @param button - The button HTML element to auto-click&lt;br /&gt;
* @param timeoutDuration - Optional base duration in ms before auto-click occurs (default: 5000)&lt;br /&gt;
* @param randomIncrement - Optional random additional ms to add to timeout (default: 2000)&lt;br /&gt;
* @param autoClickID - Optional ID for the auto-click events, multiple buttons can therefore point to the same autoClick event&lt;br /&gt;
* @param onAnimationEnd - Optional callback that returns boolean to control if click should occur (default: true)&lt;br /&gt;
*/&lt;br /&gt;
public setAutoClick(button: HTMLDivElement, timeoutDuration: number = 5000, randomIncrement: number = 2000, autoClickID: string = null, onAnimationEnd: () =&amp;gt; boolean = () =&amp;gt; true){&lt;br /&gt;
    const fn = this.setAutoClick as typeof this.setAutoClick &amp;amp; {&lt;br /&gt;
        timeouts?: Record&amp;lt;string, number[]&amp;gt;;&lt;br /&gt;
        autoClickIncrement?: number;&lt;br /&gt;
    };&lt;br /&gt;
    fn.timeouts = fn.timeouts || {};&lt;br /&gt;
        &lt;br /&gt;
    const totalDuration = timeoutDuration + Math.random() * randomIncrement;&lt;br /&gt;
&lt;br /&gt;
    if(!autoClickID){&lt;br /&gt;
        fn.autoClickIncrement = fn.autoClickIncrement || 1;&lt;br /&gt;
        autoClickID = &#039;auto-click-&#039; + fn.autoClickIncrement++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    fn.timeouts[autoClickID] = fn.timeouts[autoClickID] || [];&lt;br /&gt;
&lt;br /&gt;
    button.style.setProperty(&#039;--bga-autoclick-timeout-duration&#039;, `${totalDuration}ms`);&lt;br /&gt;
    button.classList.add(&#039;bga-autoclick-button&#039;);&lt;br /&gt;
&lt;br /&gt;
    const stopDoubleTrigger = () =&amp;gt; {&lt;br /&gt;
        if(!fn.timeouts[autoClickID]) return;&lt;br /&gt;
        fn.timeouts[autoClickID].forEach(timeout =&amp;gt; clearTimeout(timeout));&lt;br /&gt;
        delete fn.timeouts[autoClickID];&lt;br /&gt;
    }&lt;br /&gt;
    button.addEventListener(&#039;click&#039;, stopDoubleTrigger, true);&lt;br /&gt;
            &lt;br /&gt;
    fn.timeouts[autoClickID].push(&lt;br /&gt;
        setTimeout(() =&amp;gt; {&lt;br /&gt;
            stopDoubleTrigger();&lt;br /&gt;
            if (!document.body.contains(button)) return;&lt;br /&gt;
            const customEventResult = onAnimationEnd();&lt;br /&gt;
            if (customEventResult) button.click();&lt;br /&gt;
        }, totalDuration)&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Logs ===&lt;br /&gt;
&lt;br /&gt;
==== Inject icon images in the log ====&lt;br /&gt;
&lt;br /&gt;
Here is an example of what was done for Terra Mystica which is simple and straightforward:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//Define the proper message&lt;br /&gt;
		$message = clienttranslate(&#039;${player_name} gets ${power_income} via Structures&#039;);&lt;br /&gt;
		if ($price &amp;gt; 0) {&lt;br /&gt;
			$this-&amp;gt;playerScore-&amp;gt;inc($player_id, -$price);&lt;br /&gt;
			$message = clienttranslate(&#039;${player_name} pays ${vp_price} and gets ${power_income} via Structures&#039;);&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
// Notify&lt;br /&gt;
		$this-&amp;gt;notify-&amp;gt;all( &amp;quot;powerViaStructures&amp;quot;, $message, array(&lt;br /&gt;
			&#039;i18n&#039; =&amp;gt; array( ),&lt;br /&gt;
			&#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
			&#039;player_name&#039; =&amp;gt; $this-&amp;gt;getPlayerNameById($player_id),&lt;br /&gt;
			&#039;power_tokens&#039; =&amp;gt; $power_tokens,&lt;br /&gt;
			&#039;vp_price&#039; =&amp;gt; $this-&amp;gt;getLogsVPAmount($price),&lt;br /&gt;
			&#039;power_income&#039; =&amp;gt; $this-&amp;gt;getLogsPowerAmount($power_income),&lt;br /&gt;
			&#039;newScore&#039; =&amp;gt; $this-&amp;gt;playerScore-&amp;gt;get($player_id),&lt;br /&gt;
			&#039;counters&#039; =&amp;gt; $this-&amp;gt;getGameCounters(null),&lt;br /&gt;
		) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With some functions to have the needed html added inside the substitution variable, such as:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function getLogsPowerAmount( $amount ) {&lt;br /&gt;
		return &amp;quot;&amp;lt;div class=&#039;tmlogs_icon&#039; title=&#039;Power&#039;&amp;gt;&amp;lt;div class=&#039;power_amount&#039;&amp;gt;$amount&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: injecting html from php is not ideal but easy, if you want more clean solution, use method below but it is a lot more sophisticated.&lt;br /&gt;
&lt;br /&gt;
==== Inject images and styled html in the log ====&lt;br /&gt;
&lt;br /&gt;
{{InfoBox|title=Warning — Translation|maxWidth=500|color=#c00|body=&#039;&#039;&#039;In order to prevent interference with the translation process, keep in mind that you must only apply modifications to the args object, and not try to substitute the keys (the &amp;lt;code&amp;gt;${player_name}&amp;lt;/code&amp;gt; parts of your string) in the log string.&#039;&#039;&#039;}}&lt;br /&gt;
&lt;br /&gt;
So you want nice pictures in the game log. What do you do? The first idea that comes to mind is to send html from php in notifications (see method above). &lt;br /&gt;
&lt;br /&gt;
This is a bad idea for many reasons:&lt;br /&gt;
&lt;br /&gt;
* It&#039;s bad architecture. ui elements leak into the server, and now you have to manage the ui in multiple places.&lt;br /&gt;
* If you decided to change something in the ui in future version, replay logs for old games and tutorials may not work, since they use stored notifications.&lt;br /&gt;
* Log previews for old games become unreadable. (This is the log state before you enter the game replay, which is useful for troubleshooting and game analysis.)&lt;br /&gt;
* It&#039;s more data to transfer and store in the db.&lt;br /&gt;
* It&#039;s a nightmare for translators.&lt;br /&gt;
&lt;br /&gt;
So what else can you do? You can use client side log injection to intercept log arguments (which come from the server) and replace them with html on the client side. Here are three different method you can use to achieve this.&lt;br /&gt;
&lt;br /&gt;
===== Define &amp;lt;code&amp;gt;this.bgaFormatText()&amp;lt;/code&amp;gt; method =====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php&lt;br /&gt;
&lt;br /&gt;
I use this recipe for &#039;&#039;&#039;client side log injection&#039;&#039;&#039; to intercept log arguments (which come from the server) and replace them with html on the client side.&lt;br /&gt;
&lt;br /&gt;
[[File:clientloginjection.png|left]] &lt;br /&gt;
&lt;br /&gt;
ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
        /** Declare this function to inject html into log items. */&lt;br /&gt;
&lt;br /&gt;
        bgaFormatText : function(log, args) {&lt;br /&gt;
            try {&lt;br /&gt;
                if (log &amp;amp;&amp;amp; args &amp;amp;&amp;amp; !args.processed) {&lt;br /&gt;
                    args.processed = true;&lt;br /&gt;
                    &lt;br /&gt;
&lt;br /&gt;
                    // list of special keys we want to replace with images&lt;br /&gt;
                    const keys = [&#039;place_name&#039;,&#039;token_name&#039;];&lt;br /&gt;
                    &lt;br /&gt;
                  &lt;br /&gt;
                    for (let i in keys) {&lt;br /&gt;
                        const key = keys[i];&lt;br /&gt;
                        if (args[key]) args[key] = this.getTokenDiv(key, args);                            &lt;br /&gt;
&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                console.error(log,args,&amp;quot;Exception thrown&amp;quot;, e.stack);&lt;br /&gt;
            }&lt;br /&gt;
            return { log, args };&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; In the &#039;&#039;bgaFormatText&#039;&#039; method, the &#039;args&#039; parameter will only contain arguments passed to it from the notify method in Game.php (see below).&lt;br /&gt;
&lt;br /&gt;
The &#039;log&#039; parameter is the actual string that is inserted into the logs. You can perform additional js string manipulation on it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        getTokenDiv : function(key, args) {&lt;br /&gt;
            // ... implement whatever html you want here, example from sharedcode.js&lt;br /&gt;
            var token_id = args[key];&lt;br /&gt;
            var item_type = getPart(token_id,0);&lt;br /&gt;
            var logid = &amp;quot;log&amp;quot; + (this.globalid++) + &amp;quot;_&amp;quot; + token_id;&lt;br /&gt;
            switch (item_type) {&lt;br /&gt;
                case &#039;wcube&#039;:&lt;br /&gt;
                    var tokenDiv = this.format_block(&#039;jstpl_resource_log&#039;, {&lt;br /&gt;
                        &amp;quot;id&amp;quot; : logid,&lt;br /&gt;
                        &amp;quot;type&amp;quot; : &amp;quot;wcube&amp;quot;,&lt;br /&gt;
                        &amp;quot;color&amp;quot; : getPart(token_id,1),&lt;br /&gt;
                    });&lt;br /&gt;
                    return tokenDiv;&lt;br /&gt;
             &lt;br /&gt;
                case &#039;meeple&#039;:&lt;br /&gt;
                    if ($(token_id)) {&lt;br /&gt;
                        var clone = dojo.clone($(token_id));&lt;br /&gt;
    &lt;br /&gt;
                        dojo.attr(clone, &amp;quot;id&amp;quot;, logid);&lt;br /&gt;
                        this.stripPosition(clone);&lt;br /&gt;
                        dojo.addClass(clone, &amp;quot;logitem&amp;quot;);&lt;br /&gt;
                        return clone.outerHTML;&lt;br /&gt;
                    }&lt;br /&gt;
                    break;&lt;br /&gt;
     &lt;br /&gt;
                default:&lt;br /&gt;
                    break;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return &amp;quot;&#039;&amp;quot; + this.clienttranslate_string(this.getTokenName(token_id)) + &amp;quot;&#039;&amp;quot;;&lt;br /&gt;
       },&lt;br /&gt;
       getTokenName : function(key) {&lt;br /&gt;
           return this.gamedatas.token_types[key].name; // get name for the key, from static table for example&lt;br /&gt;
       },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in this case the server simply injects token_id as a name, and the client substitutes it for the translated name or the picture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Game.php:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notify-&amp;gt;all(&#039;playerLog&#039;, clienttranslate(&#039;Game moves ${token_name}&#039;), [&#039;token_name&#039;=&amp;gt;$token_id]);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; As noted above, only arguments actually passed by this method are available to the args parameter received in the client-side &#039;&#039;bgaFormatText&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Sometimes it is the case that you want to pass arguments that are not actually included in the output message. For example, suppose we have a method like this:&lt;br /&gt;
&lt;br /&gt;
           $this-&amp;gt;notify-&amp;gt;all(&#039;tokenPlaced&#039;, clienttranslate(&#039;Player placed ${token_name}&#039;), array(&lt;br /&gt;
              &#039;token_name&#039; =&amp;gt; $token_id,&lt;br /&gt;
              &#039;zone_played&#039; =&amp;gt; $zone);&lt;br /&gt;
&lt;br /&gt;
This will output &amp;quot;Player placed ${token_name}&amp;quot; in the log, and if we subscribe to a notification method activated by the &amp;quot;tokenPlaced&amp;quot; event in the client-side code, that method can make use of the &#039;zone_played&#039; argument. &lt;br /&gt;
&lt;br /&gt;
Now if you want to make some really cool things with game log, most probably you would need more arguments than are included in log message. The problem with that,&lt;br /&gt;
it will work at first, but if you reload game using F5 or when the game loads in turn based mode, you will loose your additional parameters, why? Because when game reloads it does not actually send same notifications, it sends special &amp;quot;hitstorical_log&amp;quot; notification where all  parameters not listed in the message are removed. In example above, field zone_played would be removed from historical log as it is not included in message of the notification. You can till preserve specific arguments in historical log by adding special field preserve to notification arguments like this:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
           $this-&amp;gt;notify-&amp;gt;all(&#039;tokenPlaced&#039;, clienttranslate(&#039;Player placed ${token_name}&#039;), array(&lt;br /&gt;
              &#039;token_name&#039; =&amp;gt; $token_id,&lt;br /&gt;
              &#039;zone_played&#039; =&amp;gt; $zone,&lt;br /&gt;
              &#039;preserve&#039; =&amp;gt; [ &#039;zone_played&#039; ]&lt;br /&gt;
           );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now you can use zone_played in bgaFormatText even in historical logs.&lt;br /&gt;
&lt;br /&gt;
===== Use &amp;lt;code&amp;gt;:formatFunction&amp;lt;/code&amp;gt; option provided by &amp;lt;code&amp;gt;dojo.string.substitute&amp;lt;/code&amp;gt; =====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg_ggg.tpl, ggg.css&lt;br /&gt;
&lt;br /&gt;
The above method will work in most of the cases, but if you use dotted keys such as &amp;lt;code&amp;gt;${card.name}&amp;lt;/code&amp;gt; (which is supported by the framework, for private state args), the key won&#039;t be substituted because the &amp;lt;code&amp;gt;key in arg&amp;lt;/code&amp;gt; test will fail. If so you need to rely either on this way, or the one after.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; using this method on an already advanced project will require you to go through all your notifications to change keys !&lt;br /&gt;
&lt;br /&gt;
Under the hood, the &#039;&#039;&#039;this.format_string_recursive()&#039;&#039;&#039; function calls the &#039;&#039;&#039;dojo.string.substitute&#039;&#039;&#039; method which substitutes &amp;lt;code&amp;gt;${keys}&amp;lt;/code&amp;gt; with the value provided. If you take a look at the [https://dojotoolkit.org/reference-guide/1.7/dojo/string.html#substitute documentation] and [https://github.com/dojo/dojo/blob/c3ceb017cfa25b703f5662dc83d1c8aae9bc5d81/string.js#L163 source code] you can notice that the key can be suffixed with a colon (&amp;lt;code&amp;gt;:&amp;lt;/code&amp;gt;) followed by a function name. This will allow you to specify directly in the substitution string which keys need HTML injection.&lt;br /&gt;
&lt;br /&gt;
First of all, you need to define your formatting function in the ggg.js file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[[ggg.js]]&lt;br /&gt;
        getTokenDiv : function(value, key) {&lt;br /&gt;
            //This is only an example implementation, you need to write your own.&lt;br /&gt;
            //The method should return HTML code&lt;br /&gt;
            switch (key) {&lt;br /&gt;
                case &#039;html_injected_argument1&#039;:&lt;br /&gt;
                    return this.format_block(&#039;jstpl_HTMLLogElement1&#039;,{value: value});&lt;br /&gt;
                case &#039;html_injected_argument2&#039;:&lt;br /&gt;
                    return this.format_block(&#039;jstpl_HTMLLogElement2&#039;,{value: value});&lt;br /&gt;
                ...&lt;br /&gt;
            }&lt;br /&gt;
       }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Obviously you need to define the appropriate templates in the ggg_ggg.tpl file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[[ggg_ggg.tpl]]&lt;br /&gt;
let jstpl_HTMLLogElement1 = &#039;&amp;lt;div class=&amp;quot;log-element log-element-1-${value}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
let jstpl_HTMLLogElement2 = &#039;&amp;lt;div class=&amp;quot;log-element log-element-2-${value}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
And the appropriate classes in ggg.css.&lt;br /&gt;
&lt;br /&gt;
Then you need to add the &amp;lt;code&amp;gt;dojo/aspect&amp;lt;/code&amp;gt; module at the top of the ggg.js file:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 define([&lt;br /&gt;
     &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
     &#039;&#039;&#039;&amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;&amp;quot;dojo/aspect&amp;quot;,&amp;lt;/span&amp;gt;                 //MUST BE IN THIRD POSITION&#039;&#039;&#039; (see [[#Including your own JavaScript module (II)|below]])&lt;br /&gt;
     &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
     &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
 ], function (dojo, declare, &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;&#039;&#039;&#039;aspect&#039;&#039;&#039;&amp;lt;/span&amp;gt;) {&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
And you also need to add the following code in your &amp;lt;code&amp;gt;contructor&amp;lt;/code&amp;gt; method in the ggg.js:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
         constructor: function(){&lt;br /&gt;
&lt;br /&gt;
             // ... skipped code ...&lt;br /&gt;
             let gameObject = this;            //Needed as the this object in aspect.before will not refer to the game object in which the formatting function resides&lt;br /&gt;
             aspect.before(dojo.string, &amp;quot;substitute&amp;quot;, function(template, map, transform) {      //This allows you to modify the arguments of the dojo.string.substitute method before they&#039;re actually passed to it&lt;br /&gt;
                 return [template, map, transform, gameObject];&lt;br /&gt;
             });&lt;br /&gt;
&lt;br /&gt;
Now you&#039;re all set to inject HTML in your logs. To actually achieve this, you must specify the function name with the key like so:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.game.php]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 $this-&amp;gt;notify-&amp;gt;all(&amp;quot;notificationName&amp;quot;, clienttranslate(&amp;quot;This log message contains ${plainTextArgument} and the following will receive HTML injection: ${html_injected_argument1:getTokenDiv}&amp;quot;), [&lt;br /&gt;
     &amp;quot;plainTextArgument&amp;quot; =&amp;gt; &amp;quot;some plain text here&amp;quot;,&lt;br /&gt;
     &amp;quot;html_injected_argument1&amp;quot; =&amp;gt; &amp;quot;some value used by getTokenDiv&amp;quot;,&lt;br /&gt;
 ]);&lt;br /&gt;
&lt;br /&gt;
You&#039;re not limited writing only one function, you can write as many functions as you like, and have them each inject a specific type of HTML. You just need to specify the relevant function name after the column in the substitution key.&lt;br /&gt;
&lt;br /&gt;
===== Use &amp;lt;code&amp;gt;transform&amp;lt;/code&amp;gt; argument of &amp;lt;code&amp;gt;dojo.string.substitute&amp;lt;/code&amp;gt; =====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg_ggg.tpl, ggg.css&lt;br /&gt;
&lt;br /&gt;
This method is also relying on the use of &amp;lt;code&amp;gt;dojo.string.substitute&amp;lt;/code&amp;gt; by the framework, and will use the &amp;lt;code&amp;gt;transform&amp;lt;/code&amp;gt; argument, which, accordting to [https://github.com/dojo/dojo/blob/c3ceb017cfa25b703f5662dc83d1c8aae9bc5d81/string.js#L163 source code] and [https://dojotoolkit.org/reference-guide/1.7/dojo/string.html#substitute documentation] will be run on all the messages going through dojo.string.substitute.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING:&#039;&#039;&#039; This method will be applied to all strings that go through dojo.string.substitute. As such you must take extra care not to substitute keys that may be used by the framework (i.e. ${id}). In order to do so, a good practise would be to prefix all keys that need substitution with a trigram of the game name.&lt;br /&gt;
&lt;br /&gt;
Since all the keys will be fed to the tranform function, by default, it must return the value, substituted or not per your needs. You can define the function like this in the ggg.js file:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
         getTokenDiv : function(value, key) {&lt;br /&gt;
             //This is only an example implementation, you need to write your own.&lt;br /&gt;
             //The method should return HTML code&lt;br /&gt;
             switch (key) {&lt;br /&gt;
                 case &#039;html_injected_argument1&#039;:&lt;br /&gt;
                     return this.format_block(&#039;jstpl_HTMLLogElement1&#039;,{value: value});&lt;br /&gt;
                 case &#039;html_injected_argument2&#039;:&lt;br /&gt;
                     return this.format_block(&#039;jstpl_HTMLLogElement2&#039;,{value: value});&lt;br /&gt;
                 ...&lt;br /&gt;
                 default:&lt;br /&gt;
                     return value; //Needed otherwise regular strings won&#039;t appear since since the value isn&#039;t returned by the function&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
The templates must be defined in the ggg_ggg.tpl file and the corresponding CSS classes in the ggg.css file.&lt;br /&gt;
&lt;br /&gt;
You need to add the following code at the beginning of the ggg.js file:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 define([&lt;br /&gt;
     &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
     &#039;&#039;&#039;&amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;&amp;quot;dojo/aspect&amp;quot;,&amp;lt;/span&amp;gt;                 //MUST BE IN THIRD POSITION&#039;&#039;&#039; (see [[#Including your own JavaScript module (II)|below]])&lt;br /&gt;
     &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
     &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
 ], function (dojo, declare, &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;&#039;&#039;&#039;aspect&#039;&#039;&#039;&amp;lt;/span&amp;gt;) {&lt;br /&gt;
 ...&lt;br /&gt;
And the following code to the &amp;lt;code&amp;gt;constructor&amp;lt;/code&amp;gt; method in ggg.js:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[ggg.js]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
         constructor: function(){&lt;br /&gt;
             // ... skipped code ...&lt;br /&gt;
             let transformFunction = dojo.hitch(this, &amp;quot;getTokenDiv&amp;quot;);          //Needed as the this object in aspect.before will not refer to the game object in which the formatting function resides&lt;br /&gt;
             aspect.before(dojo.string, &amp;quot;substitute&amp;quot;, function(template, map, transform) {&lt;br /&gt;
                 if (undefined === transform) {    //Check for a transform function presence, just in case&lt;br /&gt;
                     return [template, map, transformFunction];&lt;br /&gt;
                 }&lt;br /&gt;
             });&lt;br /&gt;
Then you&#039;re all set for log injection, no need to change anything on the PHP side.&lt;br /&gt;
&lt;br /&gt;
==== Processing logs on re-loading ====&lt;br /&gt;
&lt;br /&gt;
You rarely need to process logs when reloading, but if you want to do something fancy you may have to do it after logs are loaded. &lt;br /&gt;
Logs are loaded asyncronously so you have to listen for logs to be fully loaded.&lt;br /&gt;
Unfortunately there is no direct way of doing it so this is the hack.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hack alert&#039;&#039;&#039; - this extends undocumented function and may be broken when framework is updated&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
			/*&lt;br /&gt;
  			* [Undocumented] Override BGA framework functions to call onLoadingLogsComplete when loading is done&lt;br /&gt;
                        @Override&lt;br /&gt;
   			*/&lt;br /&gt;
			setLoader: function(image_progress, logs_progress) {&lt;br /&gt;
				this.inherited(arguments); // required, this is &amp;quot;super()&amp;quot; call, do not remove&lt;br /&gt;
				//console.log(&amp;quot;loader&amp;quot;, image_progress, logs_progress)&lt;br /&gt;
				if (!this.isLoadingLogsComplete &amp;amp;&amp;amp; logs_progress &amp;gt;= 100) {&lt;br /&gt;
					this.isLoadingLogsComplete = true; // this is to prevent from calling this more then once&lt;br /&gt;
					this.onLoadingLogsComplete();&lt;br /&gt;
				}&lt;br /&gt;
			},&lt;br /&gt;
&lt;br /&gt;
			onLoadingLogsComplete: function() {&lt;br /&gt;
				console.log(&#039;Loading logs complete&#039;);&lt;br /&gt;
				// do something here&lt;br /&gt;
			},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Overriding format_string_recursive to inject HTML into log, including adding tooltips to log====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
I&#039;m using cards as an example but this will work with any type of resource or game element. The first step is to override format_string_recursive. You can find info about this in this [https://bga-devs.github.io/blog/posts/translations-summary/ excellent guide]. We will replace the return line from the guide with this:&lt;br /&gt;
 return this.logInject(text);&lt;br /&gt;
The purpose of logInject() is to catch pre-coded text from your notifications, siphon out the meaningful info so that you can manipulate it on the front end, and then replace that pre-coded text in the log with whatever html you desire, as well as adding a tooltip to the element you&#039;re injecting. Here is a simplified version of logInject():&lt;br /&gt;
 logInject: function (log_entry) {&lt;br /&gt;
     const card_regex = /\[\w+-*\w* *\w*\(\d+\)\]/g;    // this will catch a card name in the log formatted like so: [card_name(card_type_arg)] -You may need to adjust the regex to catch your card names&lt;br /&gt;
     const cards_to_replace = log_entry.matchAll(card_regex);&lt;br /&gt;
     for (let card of cards_to_replace) {&lt;br /&gt;
         const match = card[0];&lt;br /&gt;
         const left_parenthesis = match.indexOf(&#039;(&#039;);&lt;br /&gt;
         const card_type_arg = match.slice(left_parenthesis+1, match.length-2);&lt;br /&gt;
         const card_span = this.getHTMLForLog(card_type_arg, &#039;card&#039;);&lt;br /&gt;
         log_entry = log_entry.replace(match, card_span);&lt;br /&gt;
     }&lt;br /&gt;
     return log_entry;&lt;br /&gt;
 }&lt;br /&gt;
getHTMLForLog() takes the card_type_arg and uses it to create the &amp;lt;nowiki&amp;gt;&amp;lt;span&amp;gt; to be injected into the log that you can then attach a tooltip to:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 getHTMLForLog: function (item, type) {   // in this example, item refers to the card_type_arg&lt;br /&gt;
     switch(type) {&lt;br /&gt;
         case &#039;card&#039;:&lt;br /&gt;
             this.log_span_num++; // adds a unique num to the span id so that duplicate card names in the log have unique ids&lt;br /&gt;
             const card_name = this.gamedatas[&#039;cards&#039;][item][&#039;description&#039;];  // or wherever you store your translated card name&lt;br /&gt;
             const item_type = &#039;card_tt&#039;;&lt;br /&gt;
             return `&amp;lt;nowiki&amp;gt;&amp;lt;span id=&amp;quot;${this.log_span_num}_item_${item}&amp;quot; class=&amp;quot;${item_type} item_tooltip&amp;quot;&amp;gt;${card_name}&amp;lt;/span&amp;gt;&amp;lt;/nowiki&amp;gt;`;&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
If you only want to add some HTML to your log and don&#039;t care about the tooltips, you can remove the item_tooltip class from the above and stop here. If you want tooltips, you&#039;ll need a function to add them:&lt;br /&gt;
 addTooltipsToLog: function() {&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;   const item_elements = dojo.query(&#039;.item_tooltip:not(.tt_processed)&#039;);&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;   Array.from(item_elements).forEach(ele =&amp;gt; {&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;       const ele_id = ele.id;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;       ele.classList.add(&#039;tt_processed&#039;);  // prevents tooltips being re-added to previous log entries&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;       if (ele.classList.contains(&#039;card_tt&#039;)) {&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;           const card_type_arg = ele_id.slice(-3).replace(/^\D+/g, &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;);  // extracts the card_type_arg from the span id&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;           this.cardTooltip(ele_id, card_type_arg)&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;       }&lt;br /&gt;
 &amp;lt;nowiki&amp;gt; &amp;lt;/nowiki&amp;gt;   });&lt;br /&gt;
 }&lt;br /&gt;
cardTooltip() is just however you want to create and add your tooltip. Mine is below:&lt;br /&gt;
 cardTooltip: function (ele, card_type_arg) {&lt;br /&gt;
     const card = this.gamedatas.cards[card_type_arg];&lt;br /&gt;
     const bg_pos = card[&#039;x_y&#039;];&lt;br /&gt;
     const skill = dojo.string.substitute(&amp;quot;${skill}&amp;quot;, { skill: card[&#039;skill&#039;] });&lt;br /&gt;
     const description = dojo.string.substitute(&amp;quot;${description}&amp;quot;, { description: card[&#039;description&#039;] });&lt;br /&gt;
     const html = `&amp;lt;nowiki&amp;gt;&amp;lt;div style=&amp;quot;margin-bottom: 5px; display: inline;&amp;quot;&amp;gt;&amp;lt;strong&amp;gt;${description}&amp;lt;/strong&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
                   &amp;lt;nowiki&amp;gt;&amp;lt;span style=&amp;quot;font-size: 10px; margin-left: 5px;&amp;quot;&amp;gt;${skill}&amp;lt;/span&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
                   &amp;lt;nowiki&amp;gt;&amp;lt;div class=&amp;quot;asset asset_tt&amp;quot; style=&amp;quot;background-position: -${bg_pos[0]}% -${bg_pos[1]}%; margin-bottom: 5px;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/nowiki&amp;gt;`;&lt;br /&gt;
     this.addTooltipHTML(ele, html, 1000);&lt;br /&gt;
 }&lt;br /&gt;
And finally, you need to connect addTooltipsToLog. Using the new promise-based notifications you can supply the `onEnd` param like&lt;br /&gt;
 this.bgaSetupPromiseNotifications({ onEnd: this.addTooltipsToLog.bind(this) });&lt;br /&gt;
Or, if you&#039;re not using them, you can attach to the notifqueue so it is called whenever the log is updated like&lt;br /&gt;
 dojo.connect(this.notifqueue, &#039;addToLog&#039;, () =&amp;gt; {&lt;br /&gt;
     this.addTooltipsToLog();&lt;br /&gt;
 });&lt;br /&gt;
You can expand this to cover multiple types of tooltips. For example, I have it set up for cards: formatted in log as [card_name(card_type_arg)], hexes: formatted as {pitch_name(pitch_type_arg)}, objectives: formatted as ==objective_name(objective_type_arg)==, etc.&lt;br /&gt;
&lt;br /&gt;
===Player Panel===&lt;br /&gt;
&lt;br /&gt;
====Inserting non-player panel====&lt;br /&gt;
&#039;&#039;&#039;This should be avoided. The new guideline is to avoid it in new games and remove it from old games.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg_ggg.tpl&lt;br /&gt;
&lt;br /&gt;
If you want to insert non-player panel on the right side (for example to hold extra preferences, zooming controls, etc)&lt;br /&gt;
&lt;br /&gt;
this can go pretty much anywhere in template it will be moved later&lt;br /&gt;
&lt;br /&gt;
ggg_ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	&amp;lt;div class=&#039;player_board_config&#039; id=&amp;quot;player_board_config&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;!-- here is whatever you want, buttons just example --&amp;gt;&lt;br /&gt;
		&amp;lt;button id=&amp;quot;zoom-out&amp;quot; class=&amp;quot; fa fa-search-minus fa-2x config-control&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;br /&gt;
		&amp;lt;button id=&amp;quot;zoom-in&amp;quot; class=&amp;quot; fa fa-search-plus fa-2x config-control&amp;quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;br /&gt;
		&amp;lt;button id=&amp;quot;show-settings&amp;quot; class=&amp;quot;fa fa-cog fa-2x config-control &amp;quot;&amp;gt;&amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
some hackery required in js&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* @Override */&lt;br /&gt;
	updatePlayerOrdering() {&lt;br /&gt;
		this.inherited(arguments);&lt;br /&gt;
		dojo.place(&#039;player_board_config&#039;, &#039;player_boards&#039;, &#039;first&#039;);&lt;br /&gt;
	},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Images and Icons ===&lt;br /&gt;
&lt;br /&gt;
==== Accessing images from js ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt; &lt;br /&gt;
     // your game resources&lt;br /&gt;
     &lt;br /&gt;
     var my_img = &#039;&amp;lt;img src=&amp;quot;&#039;+g_gamethemeurl+&#039;img/cards.jpg&amp;quot;/&amp;gt;&#039;;&lt;br /&gt;
     &lt;br /&gt;
     // shared resources&lt;br /&gt;
     var my_help_img = &amp;quot;&amp;lt;img class=&#039;imgtext&#039; src=&#039;&amp;quot; + g_themeurl + &amp;quot;img/layout/help_click.png&#039; alt=&#039;action&#039; /&amp;gt; &amp;lt;span class=&#039;tooltiptext&#039;&amp;gt;&amp;quot; +&lt;br /&gt;
                    text + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====High-Definition Graphics====&lt;br /&gt;
&lt;br /&gt;
Some users will have screens which can display text and images at a greater resolution than the usual 72 dpi, e.g. the &amp;quot;Retina&amp;quot; screens on the 5k iMac, all iPads, and high-DPI screens on laptops from many manufacturers. If you can get art assets at this size, they will make your game look extra beautiful. You &#039;&#039;could&#039;&#039; just use large graphics and scale them down, but that would increase the download time and bandwidth for users who can&#039;t display them. Instead, a good way is to prepare a separate graphics file at exactly twice the size you would use otherwise, and add &amp;quot;@2x&amp;quot; at the end of the filename, e.g. if pieces.png is 240x320, then pieces@2x.png is 480x640.&lt;br /&gt;
&lt;br /&gt;
There are two changes required in order to use the separate graphics files. First in your css, where you use a file, add a media query which overrides the original definition and uses the bigger version on devices which can display them. Ensuring that the &amp;quot;background-size&amp;quot; attribute is set means that the size of the displayed object doesn&#039;t change, but only is drawn at the improved dot pitch.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.piece {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    background-image: url(&#039;img/pieces.png&#039;);&lt;br /&gt;
    background-size:240px 320px;&lt;br /&gt;
    z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
@media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&lt;br /&gt;
{&lt;br /&gt;
    .piece {&lt;br /&gt;
        background-image: url(&#039;img/pieces@2x.png&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Secondly, in your setup function in javascript, you must ensure than only the appropriate one version of the file gets pre-loaded (otherwise you more than waste the bandwidth saved by maintaining the standard-resolution file). Note that the media query is the same in both cases:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            var isRetina = &amp;quot;(-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2), (min-resolution: 192dpi)&amp;quot;;&lt;br /&gt;
            if (window.matchMedia(isRetina).matches)&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                this.dontPreloadImage( &#039;pieces@2x.png&#039; );&lt;br /&gt;
                this.dontPreloadImage( &#039;board@2x.jpg&#039; );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Using CSS to create different colors of game pieces if you have only white piece====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
background-color: #${color}; &lt;br /&gt;
background-blend-mode: multiply;&lt;br /&gt;
background-image: url( &#039;img/mypiece.png&#039;);&lt;br /&gt;
mask: url(&#039;img/mypiece.png&#039;);&lt;br /&gt;
-webkit-mask: url(&#039;img/mypiece.png&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where ${color} - is color you want&lt;br /&gt;
&lt;br /&gt;
Note: piece has to be white (shades of gray). Sprite can be used too, just add add background-position as usual.&lt;br /&gt;
&lt;br /&gt;
==== Accessing player avatar URLs ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      getPlayerAvatar(playerId) {&lt;br /&gt;
         let avatarURL = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
         if (null != $(&#039;avatar_&#039; + playerId)) {&lt;br /&gt;
            let smallAvatarURL = dojo.attr(&#039;avatar_&#039; + playerId, &#039;src&#039;);&lt;br /&gt;
            avatarURL = smallAvatarURL.replace(&#039;_32.&#039;, &#039;_184.&#039;);&lt;br /&gt;
         }&lt;br /&gt;
         else {&lt;br /&gt;
            avatarURL = &#039;https://x.boardgamearena.net/data/data/avatar/default_184.jpg&#039;;&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
         return avatarURL;&lt;br /&gt;
      },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note:  This gets avatar URLs at 184x184 resolution.  You can also use 92, 50, and 32 depending on which resolution you want.&lt;br /&gt;
&lt;br /&gt;
====Adding Image buttons====&lt;br /&gt;
&lt;br /&gt;
Its pretty trivial but just in case you need a working function:&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                addImageActionButton: function (id, div_html, handler) { // div_html is string not node&lt;br /&gt;
                    this.addActionButton(id, div_html, handler, &#039;&#039;, false, &#039;gray&#039;); &lt;br /&gt;
                    dojo.style(id, &amp;quot;border&amp;quot;, &amp;quot;none&amp;quot;); // remove ugly border&lt;br /&gt;
                    dojo.addClass(id, &amp;quot;bgaimagebutton&amp;quot;); // add css class to do more styling&lt;br /&gt;
                    return $(id); // return node for chaining&lt;br /&gt;
                },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Example of usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.addImageActionButton(&#039;button_coin&#039;,&amp;quot;&amp;lt;div class=&#039;coin&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, ()=&amp;gt;{ alert(&#039;Ha!&#039;); });&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Other Fluff===&lt;br /&gt;
&lt;br /&gt;
====Use thematic fonts====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.css&lt;br /&gt;
&lt;br /&gt;
Sometime game elements use specific fonts of text, if you want to match it up you can load some specific font (IMPORTANT: from some &#039;&#039;&#039;free font&#039;&#039;&#039; source. See notes below).&lt;br /&gt;
&lt;br /&gt;
[[File:Dragonline_font.png]]&lt;br /&gt;
&lt;br /&gt;
.css&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/* latin-ext */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: 400;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/2Dy1Unur1HJoklbsg4iPJ_Y6323mHUZFJMgTvxaG2iE.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;&lt;br /&gt;
}&lt;br /&gt;
/* latin */&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(https://fonts.gstatic.com/s/qwigley/v6/gThgNuQB0o5ITpgpLi4Zpw.woff2) format(&#039;woff2&#039;);&lt;br /&gt;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;&lt;br /&gt;
}&lt;br /&gt;
@font-face {&lt;br /&gt;
  font-family: &#039;Qwigley&#039;;&lt;br /&gt;
  font-style: normal;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  src: local(&#039;Qwigley&#039;), local(&#039;Qwigley-Regular&#039;), url(http://ff.static.1001fonts.net/q/w/qwigley.regular.ttf) format(&#039;ttf&#039;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.zone_title {&lt;br /&gt;
	display: inline-block;&lt;br /&gt;
	position: absolute;&lt;br /&gt;
	font: italic 32px/32px &amp;quot;Qwigley&amp;quot;, cursive;	   &lt;br /&gt;
	height: 32px;&lt;br /&gt;
	width: auto;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NB:&#039;&#039;&#039; if you need to include a font that&#039;s not available online, an extra action will be needed from an admin. Please include the font file(s) in your img directory, and mention it to admins when requesting your game to be moved to alpha. &#039;&#039;&#039;Please remember that the font has to be free, and include a .txt with all appropriate license information about the font.&#039;&#039;&#039;&lt;br /&gt;
You can look for free fonts (for example) on https://fonts.google.com or https://www.fontsquirrel.com/)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Content Security Policy&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
BGA runs a Content Security Policy which will limit the origins from which you can load external fonts, in order to prevent license abuse.&lt;br /&gt;
&lt;br /&gt;
The CSP is a whitelist of allowed origins. To see the list, view the response headers of any page on Studio, and look for the &amp;quot;Content-Security-Policy&amp;quot; header.&lt;br /&gt;
&lt;br /&gt;
You will specifically want to check for the font-src token within these headers, and limit any external fonts to these sources.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This list is subject to change&#039;&#039;&#039; but as of the time of writing, the only acceptabled external sites are use.typekit.net and fonts.gstatic.com.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Scale to fit for big boards===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg_ggg.tpl, ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Lets say you have huge game board, and lets say you want it to be 1400px wide. Besides the board there will be side bar which is 240 and trim. &lt;br /&gt;
My display is 1920 wide so it fits, but there is big chance other people won&#039;t have that width. What do you do?&lt;br /&gt;
&lt;br /&gt;
You have to decide:&lt;br /&gt;
* If board does not fit you want scale whole thing down, the best way is probably use viewport (see https://en.doc.boardgamearena.com/Your_game_mobile_version)&lt;br /&gt;
*You can leave the board as is and make sure it is scrollable horizonatally&lt;br /&gt;
*You add custom scale just for the board (can add user controls  - and hook to transform: scale())&lt;br /&gt;
&lt;br /&gt;
I tried to auto-scale but this just does work, too many variables - browser zoom, 3d mode, viewport, custom bga scaling, devicePixelRatio - all create some impossible coctail of zooming...&lt;br /&gt;
Here is scaling functing for custom user scaling&lt;br /&gt;
&lt;br /&gt;
ggg_ggg.tpl:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   &amp;lt;div id=&amp;quot;thething&amp;quot; class=&amp;quot;thething&amp;quot;&amp;gt;&lt;br /&gt;
            ... everything else you declare ...&lt;br /&gt;
   &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
ggg.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    onZoomPlus: function() {&lt;br /&gt;
       this.setZoom(this.zoom + 0.1);&lt;br /&gt;
    },&lt;br /&gt;
    onZoomMinus: function() {&lt;br /&gt;
       this.setZoom(this.zoom - 0.1);&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    setZoom: function (zoom) {&lt;br /&gt;
      zoom = parseInt(zoom) || 0;&lt;br /&gt;
      if (zoom === 0 || zoom &amp;lt; 0.1 || zoom &amp;gt; 10) {&lt;br /&gt;
        zoom = 1;&lt;br /&gt;
      }&lt;br /&gt;
      this.zoom = zoom;&lt;br /&gt;
      var inner = document.getElementById(&amp;quot;thething&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (zoom == 1) {&lt;br /&gt;
        inner.style.removeProperty(&amp;quot;transform&amp;quot;);&lt;br /&gt;
        inner.style.removeProperty(&amp;quot;width&amp;quot;);&lt;br /&gt;
      } else {&lt;br /&gt;
        inner.style.transform = &amp;quot;scale(&amp;quot; + zoom + &amp;quot;)&amp;quot;;&lt;br /&gt;
        inner.style.transformOrigin = &amp;quot;0 0&amp;quot;;&lt;br /&gt;
        inner.style.width = 100 / zoom + &amp;quot;%&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
      localStorage.setItem(`${this.game_name}_zoom`, &amp;quot;&amp;quot; + this.zoom);&lt;br /&gt;
      this.onScreenWidthChange();&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Dynamic tooltips===&lt;br /&gt;
&lt;br /&gt;
If you really need a dynamic tooltip you can use this technique. (Only use it if the static tooltips provided by the BGA framework are not sufficient.)&lt;br /&gt;
&lt;br /&gt;
            new dijit.Tooltip({&lt;br /&gt;
                connectId: [&amp;quot;divItemId&amp;quot;],&lt;br /&gt;
                getContent: function(matchedNode){&lt;br /&gt;
                    return &amp;quot;... calculated ...&amp;quot;; &lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This is an out-of-the-box djit.Tooltip. It has a &#039;&#039;getContent&#039;&#039; method which is called dynamically.&lt;br /&gt;
&lt;br /&gt;
The string returned by getContent() becomes the innerHTML of the tooltip, so it can be anything. In this example matchedNode is a dojo node representing dom object with id of &amp;quot;divItemId&amp;quot; but there are more parameters which I am not posting here which allows more sophisticated subnode queries (i.e. you can attach tooltip to all nodes with class or whatever).&lt;br /&gt;
&lt;br /&gt;
[https://dojotoolkit.org/reference-guide/1.10/dijit/Tooltip.html dijit.Tooltip]&lt;br /&gt;
&lt;br /&gt;
It&#039;s not part of the BGA API so use at your own risk.&lt;br /&gt;
&lt;br /&gt;
===Rendering text with players color and proper background===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        /* Implementation of proper colored You with background in case of white or light colors  */&lt;br /&gt;
 &lt;br /&gt;
        divYou: function() {&lt;br /&gt;
            var color = this.gamedatas.players[this.player_id].color;&lt;br /&gt;
            var color_bg = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.gamedatas.players[this.player_id] &amp;amp;&amp;amp; this.gamedatas.players[this.player_id].color_back) {&lt;br /&gt;
                color_bg = &amp;quot;background-color:#&amp;quot; + this.gamedatas.players[this.player_id].color_back + &amp;quot;;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            var you = &amp;quot;&amp;lt;span style=\&amp;quot;font-weight:bold;color:#&amp;quot; + color + &amp;quot;;&amp;quot; + color_bg + &amp;quot;\&amp;quot;&amp;gt;&amp;quot; + __(&amp;quot;lang_mainsite&amp;quot;, &amp;quot;You&amp;quot;) + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
            return you;&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        /* Implementation of proper colored player name with background in case of white or light colors  */&lt;br /&gt;
&lt;br /&gt;
        divColoredPlayer: function(player_id) {&lt;br /&gt;
            var color = this.gamedatas.players[player_id].color;&lt;br /&gt;
            var color_bg = &amp;quot;&amp;quot;;&lt;br /&gt;
            if (this.gamedatas.players[player_id] &amp;amp;&amp;amp; this.gamedatas.players[player_id].color_back) {&lt;br /&gt;
                color_bg = &amp;quot;background-color:#&amp;quot; + this.gamedatas.players[player_id].color_back + &amp;quot;;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            var div = &amp;quot;&amp;lt;span style=\&amp;quot;color:#&amp;quot; + color + &amp;quot;;&amp;quot; + color_bg + &amp;quot;\&amp;quot;&amp;gt;&amp;quot; + this.gamedatas.players[player_id].name + &amp;quot;&amp;lt;/span&amp;gt;&amp;quot;;&lt;br /&gt;
            return div;&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Cool realistic shadow effect with CSS===&lt;br /&gt;
&lt;br /&gt;
====Rectangles and circles====&lt;br /&gt;
&lt;br /&gt;
It is often nice to have a drop shadow around tiles and tokens, to separate them from the table visually. It is very easy to add a shadow to rectangular elements, just add this to your css:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.xxx-tile {&lt;br /&gt;
    box-shadow: 3px 3px 3px #000000a0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
box-shadow obeys &#039;&#039;&#039;border-radius&#039;&#039;&#039; of the element, so it will look good for rounded rectangles, and hence also circles (if border-radius is set appropriately).&lt;br /&gt;
&lt;br /&gt;
box-shadow also supports various other parameters and can be used to achieve effects such as glowing, borders, inner shadows etc. If you need to animate a box-shadow, you may be able to get better performance (avoiding redraws) if you attach the shadow to another element (possibly an ::after pseudo-element) and change only the &#039;&#039;&#039;opacity&#039;&#039;&#039; of that element.&lt;br /&gt;
&lt;br /&gt;
==== Irregular Shapes ====&lt;br /&gt;
&lt;br /&gt;
If you wish to make a shadow effect for game pieces that are not a rectangle, but your game pieces are drawn from rectangles in a PNG image, you can apply the shadow to the piece using any art package and save it inside the image. This usually will yield the best performance. Remember to account for the size of the shadow when you lay out images in the sprite sheet.&lt;br /&gt;
&lt;br /&gt;
However that sometimes will not be an option, for example if the image needs to be rotated while the shadow remains offset in the same direction. In this case, one option is to not use box-shadow but use filter, which is supported by recent major browsers.  This way, you can use the alpha channel of your element to drop a shadow.  This even work for transparent backgrounds, so that if you are using the &amp;quot;CSS-sprite&amp;quot; method, it will work!&lt;br /&gt;
&lt;br /&gt;
For instance:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.xxx-token {&lt;br /&gt;
    filter: drop-shadow(0px 0px 1px #000000);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beware that some browsers still do not always draw drop-shadow correctly. In particular, Safari frequently leaves bits of shadow behind when objects move around the screen. In Chrome, shadows sometimes flicker badly if another element is animating close by. Some of these correctness issues can be solved by adding &#039;&#039;&#039;isolation: isolate; will-change: filter;&#039;&#039;&#039; to affected elements, but this significantly affects redraw performance.&lt;br /&gt;
&lt;br /&gt;
Beware of performance issues - particularly on Safari (MacOS, iPhone and iPad). Keep in mind that drop-shadow are very GPU intensive. This becomes noticeable once you have about 40 components with drop-shadow filter. If that is your case, you can quite easily implement a user preference to disable shadows for users on slower machines:&lt;br /&gt;
&lt;br /&gt;
gameoptions.inc.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
100 =&amp;gt; array(&lt;br /&gt;
			&#039;name&#039; =&amp;gt; totranslate(&#039;Shadows&#039;),&lt;br /&gt;
			&#039;needReload&#039; =&amp;gt; true, // after user changes this preference game interface would auto-reload&lt;br /&gt;
			&#039;values&#039; =&amp;gt; array(&lt;br /&gt;
					1 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate( &#039;Enabled&#039; ), &#039;cssPref&#039; =&amp;gt; &#039;&#039; ),&lt;br /&gt;
					2 =&amp;gt; array( &#039;name&#039; =&amp;gt; totranslate( &#039;Disabled&#039; ), &#039;cssPref&#039; =&amp;gt; &#039;no-shadow&#039; )&lt;br /&gt;
			)&lt;br /&gt;
	),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[game].css&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.no-shadow * {&lt;br /&gt;
	filter: none !important; &lt;br /&gt;
} &lt;br /&gt;
&amp;lt;/pre&amp;gt;For Safari, it is usually better to simply disable drop-shadow completely: [[Game interface stylesheet: yourgamename.css#Warning: using drop-shadow]].&lt;br /&gt;
&lt;br /&gt;
====Shadows with clip-path====&lt;br /&gt;
&lt;br /&gt;
For some reason, a shadow will not work together with clip-path on one element. To use both clip-path (when for example using .svg to cut out cardboard components from your .jpg spritesheet) and drop-shadow, you need to wrap the element into another one, and apply drop-shadow to the outer one, and clip-path to the inner one.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div class=&#039;my-token-wrap&#039;&amp;gt;&lt;br /&gt;
  &amp;lt;div class=&#039;my-token&#039;&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.my-token-wrap {&lt;br /&gt;
    filter: drop-shadow(0px 0px 1px #000000);&lt;br /&gt;
}&lt;br /&gt;
.my-token-wrap .my-token {&lt;br /&gt;
    clip-path: url(#my-token-path);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Using the CSS classes from the state machine ===&lt;br /&gt;
&lt;br /&gt;
If you need to hide or show stuff depending on the state of your game, you can of course use javascript, but CSS is hand enough for that.  The #overall-content element does change class depending on the game state.  For instance, if you are in state &#039;&#039;playerTurn&#039;&#039;, it will have the class &#039;&#039;gamestate_playerTurn&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
So now, if you want to show the discard pile only during player turns, you may use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#discard_pile { display: none }&lt;br /&gt;
.gamestate_playerTurn #discard_pile { display: block }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This can be used if you want to change sizing of elements, position, layout or visual appearance.&lt;br /&gt;
&lt;br /&gt;
==Game Model and Database design ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Database for The euro game ===&lt;br /&gt;
Lets say we have a game with workers, dice, tokens, board, resources, money and vp. Workers and dice can be placed in various zones on the board, and you can get resources, money, tokens and vp in your home zone. Also tokens can be flipped or not flipped.&lt;br /&gt;
&lt;br /&gt;
[[File:Madeira board.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now lets try to map it, we have&lt;br /&gt;
*(meeple,zone)&lt;br /&gt;
*(die, zone, sideup)&lt;br /&gt;
*(resource cube/money token/vp token,player home zone)&lt;br /&gt;
*(token, player home zone, flip state)&lt;br /&gt;
We can notice that resource and money are uncountable, and don&#039;t need to be track individually so we can replace our mapping to&lt;br /&gt;
*(resource type/money,player home zone, count)&lt;br /&gt;
And vp stored already for us in player table, so we can remove it from that list.&lt;br /&gt;
&lt;br /&gt;
Now when we get to encode it we can see that everything can be encoded as (object,zone,state) form, where object and zone is string and state is integer. The resource mapping is slightly different semantically so you can go with two table, or counting using same table with state been used as count for resources.&lt;br /&gt;
&lt;br /&gt;
So the piece mapping for non-grid based games can be in most case represented by (string: token_key, string: token_location, int: token_state), example of such database schema can be found here: [https://github.com/elaskavaia/bga-sharedcode/blob/master/dbmodel.sql dbmodel.sql] and class implementing access to it here [https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php table.game.php].&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
!token_key&lt;br /&gt;
!token_location&lt;br /&gt;
!token_state&lt;br /&gt;
|-&lt;br /&gt;
|meeple_red_1&lt;br /&gt;
|home_red&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|dice_black_2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|dice_green_1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|bread&lt;br /&gt;
|home_red &lt;br /&gt;
| 5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Now how we represent resource counters such as bread?&lt;br /&gt;
Using same table from we simply add special counter token for bread and use state to indicate the count. Note to keep first column unique we have to add player identification for that counter, i.e. ff0000 is red player.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
!token_key&lt;br /&gt;
!token_location&lt;br /&gt;
!token_state&lt;br /&gt;
|-&lt;br /&gt;
|bread_ff0000&lt;br /&gt;
|tableau_ff0000&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
See php module for this table here https://github.com/elaskavaia/bga-sharedcode/blob/master/modules/tokens.php&lt;br /&gt;
&lt;br /&gt;
Variant 2: Additional resource table, resource count for each player id&lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `resource` (&lt;br /&gt;
  `player_id` int(10) unsigned NOT NULL,&lt;br /&gt;
  `resource_key` varchar(32) NOT NULL,&lt;br /&gt;
  `resource_count` int(10) signed NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`player_id`,`resource_key`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
 ALTER TABLE resource ADD CONSTRAINT fk_player_id FOREIGN KEY (player_id) REFERENCES player(player_id);&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+resource&lt;br /&gt;
!player_id&lt;br /&gt;
!resource_key&lt;br /&gt;
!resource_count&lt;br /&gt;
|-&lt;br /&gt;
| 123456&lt;br /&gt;
|bread&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 3: More normalised&lt;br /&gt;
&lt;br /&gt;
This version is similar to &amp;quot;card&amp;quot; table from hearts tutorial, you can also use exact cards database schema and Deck implementation for most purposes (even you not dealing with cards). &lt;br /&gt;
&lt;br /&gt;
 CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `token_type` varchar(16) NOT NULL,&lt;br /&gt;
  `token_arg` int(11) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_id`)&lt;br /&gt;
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
!token_id&lt;br /&gt;
!token_type&lt;br /&gt;
!token_arg&lt;br /&gt;
!token_location&lt;br /&gt;
!token_state&lt;br /&gt;
|-&lt;br /&gt;
|22&lt;br /&gt;
|meeple&lt;br /&gt;
|123456&lt;br /&gt;
|home_123456&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|23&lt;br /&gt;
|dice&lt;br /&gt;
|2&lt;br /&gt;
|board_guard&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|26 &lt;br /&gt;
|dice&lt;br /&gt;
|1&lt;br /&gt;
|board_action_mayor&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|49&lt;br /&gt;
|bread&lt;br /&gt;
|0&lt;br /&gt;
|home_123456&lt;br /&gt;
|5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Advantages of this would be is a bit more straightforward to do some queries in db, disadvantage its hard to read (as you can compare with previous example, you&lt;br /&gt;
cannot just look at say, ah I know what it means). Another questionable advantage is it allows you to do id randomisation, so it hard to do crafted queries to &lt;br /&gt;
cheat, the down side of that you cannot understand it either, and handcraft db states for debugging or testing.&lt;br /&gt;
&lt;br /&gt;
=== Database for The card game===&lt;br /&gt;
&lt;br /&gt;
Lets say you have a standard card game, player have hidden cards in hand, you can draw card from draw deck, play card on tableau and discard to discard pile.&lt;br /&gt;
We have to design database for such game.&lt;br /&gt;
&lt;br /&gt;
In real word to &amp;quot;save&amp;quot; the game we take a picture a play area, save cards from it, then put away draw deck, discard and hand of each player separately and mark it, also we will record current scoring (if any) and who&#039;s turn was it.&lt;br /&gt;
&lt;br /&gt;
*Framework handles state machine transition, so you don&#039;t have to worry about database design for that (i.e. who&#039;s turn it is, what phase of the game we are at, you still have to design it but part of state machine step)&lt;br /&gt;
*Also framework supports basic player information, color, order around the table, basic scoring, etc, so you don&#039;t have to worry about it either&lt;br /&gt;
*The only thing you need in our database is state of the &amp;quot;board&amp;quot;, which is &amp;quot;where each pieces is, and in what state&amp;quot;, or (position,rotation) pair.&lt;br /&gt;
&lt;br /&gt;
Lets see what we have for that: &lt;br /&gt;
*The card state is very simple, its usually &amp;quot;face up/face down&amp;quot;, &amp;quot;tapped/untapped&amp;quot;, &amp;quot;right side up/up side down&amp;quot;&lt;br /&gt;
*As position go we never need real coordinates x,y,z. We need to know what &amp;quot;zone&amp;quot; card was, and depending on the zone it may sometimes need an extra &amp;quot;z&amp;quot; or &amp;quot;x&amp;quot; as card order. The zone position usually static or irrelevant.&lt;br /&gt;
*So our model is: we have cards, which have some attributes, at any given point in time they belong to a &amp;quot;zone&amp;quot;, and can also have order and state&lt;br /&gt;
* Now for mapping we should consider what information changes and what information is static, later is always candidate for material file&lt;br /&gt;
*For dynamic information we should try to reduce amount of fields we need&lt;br /&gt;
**we need at least a field for card, so its one&lt;br /&gt;
**we need to know what zone cards belong to, its 2&lt;br /&gt;
**and we have possibly few other fields, if you look closely at you game you may find out that most of the zone only need one attribute at a time, i.e. draw pile always have cards face down, hand always face up, also for hand and discard order does not matter at all (but for draw it does matter). So in majority of cases we can get away with one single extra integer field representing state or order&lt;br /&gt;
*In real database both card and zone will be integers as primary keys referring to additional tables, but in our case its total overkill, so they can be strings as easily&lt;br /&gt;
&lt;br /&gt;
Variant 1: Minimalistic&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_key` varchar(32) unsigned NOT NULL,&lt;br /&gt;
  `card_location` varchar(32) NOT NULL,&lt;br /&gt;
  `card_state` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Variant 2: More normalised&lt;br /&gt;
&lt;br /&gt;
This version supported by Deck php class, so unless you want to rewrite db access layer go with this one&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you using this schema, some zones/locations have special semantic. The &#039;hand&#039; location is actually multiple locations - one per player, but player id is encoded as card_location_arg. If &#039;hand&#039; in your game is ordered, visible or can have some other card states, you cannot use hand location (replacement is hand_&amp;lt;player_id&amp;gt; or hand_&amp;lt;color_id&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
==Game Elements==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Resource===&lt;br /&gt;
&lt;br /&gt;
A game resource, such as &amp;quot;wood,&amp;quot; is usually infinite and represented by a count allocated to a specific player or supply.&lt;br /&gt;
&lt;br /&gt;
If a resource can be placed on location, use the &amp;quot;Meeple&amp;quot; model described below.&lt;br /&gt;
&lt;br /&gt;
For a working example, you can check out: [https://codepen.io/VictoriaLa/pen/emYgLzR CodePen Example] (ui only).&lt;br /&gt;
&lt;br /&gt;
====Representation in Database====&lt;br /&gt;
In a minimalistic &amp;quot;tokens&amp;quot; database, it would look like this (e.g., the red player has 3 wood):&lt;br /&gt;
  &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
!token_key&lt;br /&gt;
!token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|wood_ff0000&lt;br /&gt;
|&lt;br /&gt;
|3&lt;br /&gt;
|-&lt;br /&gt;
|wood_supply&lt;br /&gt;
|&lt;br /&gt;
|40&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The second row you need to store the resource in the supply (if it&#039;s counted).&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t like this solution can use bga_globals table for this or create your own resource table.&lt;br /&gt;
&lt;br /&gt;
Its not recommened to extend player table to store this information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Representation in Material File (material.inc.php)====&lt;br /&gt;
In the material file, you can define some information about resources. For instance, you can specify that it&#039;s of type &amp;quot;resource&amp;quot; and call it &amp;quot;Wood&amp;quot; in English, along with a tooltip:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;token_types = [&lt;br /&gt;
  ...&lt;br /&gt;
  &#039;wood&#039; =&amp;gt; [&lt;br /&gt;
     &#039;name&#039; =&amp;gt; clienttranslate(&#039;Wood&#039;),&lt;br /&gt;
     &#039;tooltip&#039; =&amp;gt; clienttranslate(&#039;Game resource used for building houses&#039;),&lt;br /&gt;
     &#039;type&#039; =&amp;gt; &#039;resource&#039;,&lt;br /&gt;
     &#039;max&#039; =&amp;gt; 40&lt;br /&gt;
  ]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====HTML Representation====&lt;br /&gt;
In HTML, this would look something like this within the player panel. Using the data attribute instead of a CDATA value is much more flexible:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;wood_ff0000&amp;quot; class=&amp;quot;resource wood&amp;quot; data-value=&amp;quot;3&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== JavaScript Handling ====&lt;br /&gt;
When you get the object from the server, one of the tokens will be sent in the array like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
token = {&lt;br /&gt;
  key: &#039;wood_ff0000&#039;,&lt;br /&gt;
  location: &#039;-&#039;,&lt;br /&gt;
  state: &#039;3&#039;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can create a corresponding `&amp;lt;div&amp;gt;` in the `setup()` method of `game.js` as follows:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const playerColor = token.key.split(&#039;_&#039;)[1];&lt;br /&gt;
const resType = token.key.split(&#039;_&#039;)[0];&lt;br /&gt;
const tokenInfo = this.gamedatas.token_types[resType]; // token_types is the structure from the material file sent to the client&lt;br /&gt;
const div = `&amp;lt;div id=&amp;quot;${token.key}&amp;quot; class=&amp;quot;${resType} ${tokenInfo.type} ${token.key}&amp;quot; data-value=&amp;quot;${token.state}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;`;&lt;br /&gt;
&lt;br /&gt;
if (playerColor != &#039;supply&#039;) {&lt;br /&gt;
    document.querySelector(`#player_board_${this.getPlayerIdByColor(playerColor)} &amp;gt; .player-board-game-specific-content`).insertAdjacentHTML(&#039;beforeend&#039;,div);&lt;br /&gt;
    this.addTooltip(token.key, _(tokenInfo.name) + &amp;quot; &amp;quot; + _(tokenInfo.tooltip), &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you receive an update notification (assuming you get the same &amp;quot;token&amp;quot; object), you can simply update the `data-value`:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
document.querySelector(`#${token.key}`).dataset.value = token.state;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To display the resource in the game log, you can format it like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Player gains &amp;lt;div class=&amp;quot;resource wood&amp;quot; data-value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For more on injecting icon images in the log, see: [[BGA_Studio_Cookbook#Inject_icon_images_in_the_log]]&lt;br /&gt;
&lt;br /&gt;
====Graphic Representation (.css)====&lt;br /&gt;
To properly display the resource image, it is preferable to use an image sprite that includes all resources, &lt;br /&gt;
usually it will be .png as these objects have shape. &lt;br /&gt;
This how will .css look like with horizontal sprite image:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.resource {&lt;br /&gt;
  background-image: url(https://en.doc.boardgamearena.com/images/d/d3/Cubes.png);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  background-size: cover; /* auto-scale */&lt;br /&gt;
  aspect-ratio: 1/1; /* that will keep heigh in sync */&lt;br /&gt;
  width: 32px; /* default size, specific location should override */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.wood {&lt;br /&gt;
  /* Since the sprite is a horizontal row of 11 cubes and 9 is the brown cube position */&lt;br /&gt;
  background-position: calc(100% / (11 - 1) * 9) 0%;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To show a text overlay with the resource value, you can use the following CSS:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.resource[data-value]:after {&lt;br /&gt;
  content: attr(data-value);&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  font-size: xx-large;&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  text-shadow: 2px 0 2px #fff, 0 -2px 2px #fff, 0 2px 2px #fff, -2px 0 2px #fff;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This solution is fully scalable — you only need to specify the size where you want it displayed. &lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.player_board_content &amp;gt; .resource {&lt;br /&gt;
  width: 40px;&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you have that board that tracks the resource on resource tracker - you can show this IN ADDITION of showing resource on player panel.&lt;br /&gt;
&lt;br /&gt;
====Selection and Actions====&lt;br /&gt;
It is best to put buttons with resource images on the status bar, rather than having the player click on the player panel.&lt;br /&gt;
&lt;br /&gt;
For animation:&lt;br /&gt;
*Can use move animation to animate resourced gained or played from the board location to the player panel&lt;br /&gt;
*Can use &amp;quot;vapor&amp;quot; animation to show resource gained from the board&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Meeple===&lt;br /&gt;
&lt;br /&gt;
A meeple is a game piece, typically representing a &amp;quot;worker,&amp;quot; depicted as a human-shaped figure in a specific color assigned to a player.&lt;br /&gt;
&lt;br /&gt;
The key distinction between meeples and traditional resources is that meeples are placed on locations and can exist &lt;br /&gt;
in at least two states — standing or lying down. &lt;br /&gt;
&lt;br /&gt;
This concept also applies to similar pieces like &amp;quot;houses,&amp;quot; &amp;quot;animeeples,&amp;quot; &amp;quot;ships,&amp;quot; and others.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Representation in Database====&lt;br /&gt;
In a simplified &amp;quot;tokens&amp;quot; database, it might be represented like this &lt;br /&gt;
(e.g., the red player&#039;s first meeple is on action spot 1, while the white meeple remains in supply):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
!token_key&lt;br /&gt;
!token_location&lt;br /&gt;
! token_state&lt;br /&gt;
|-&lt;br /&gt;
|meeple_ff0000_1&lt;br /&gt;
|actionspot_1&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|meeple_ffffff_1&lt;br /&gt;
| supply&lt;br /&gt;
|0&lt;br /&gt;
|}  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Representation in Material File (material.inc.php)====&lt;br /&gt;
&lt;br /&gt;
Here we define some properties, for example name can be used in notification and as tooltip, type can be used to create the div by &lt;br /&gt;
javascript, &#039;create&#039; - can be used by server to create 8 meeples of this type in database and set location to &#039;supply_ff0000&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;token_types = [&lt;br /&gt;
  ...&lt;br /&gt;
  &#039;meeple_ff0000&#039; =&amp;gt; [&lt;br /&gt;
     &#039;name&#039; =&amp;gt; clienttranslate(&#039;Red Worker&#039;),&lt;br /&gt;
     &#039;type&#039; =&amp;gt; &#039;meeple meeple_ff0000&#039;,&lt;br /&gt;
     &#039;create&#039; =&amp;gt; 8,&lt;br /&gt;
     &#039;location&#039; =&amp;gt; &#039;supply_ff0000&#039;&lt;br /&gt;
  ]&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====HTML Representation ====&lt;br /&gt;
In HTML, this would look something like this. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;meeple_ff0000_1&amp;quot; class=&amp;quot;meeple meeple_ff0000&amp;quot; data-state=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====JavaScript Handling ====&lt;br /&gt;
When you get the object from the server, each meeple object will be similar to this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
meeple = {&lt;br /&gt;
  key: &#039;meeple_ff0000_1&#039;,&lt;br /&gt;
  location: &#039;actionslot_1&#039;,&lt;br /&gt;
  state: &#039;1&#039;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can create a corresponding `&amp;lt;div&amp;gt;` in the `setup()` method of `game.js` as follows:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
const playerColor = token.key.split(&#039;_&#039;)[1];&lt;br /&gt;
const resType = token.key.split(&#039;_&#039;)[0];&lt;br /&gt;
const tokenInfo = this.gamedatas.token_types[resType]; // token_types is the structure from the material file sent to the client&lt;br /&gt;
const div = `&amp;lt;div id=&amp;quot;${token.key}&amp;quot; class=&amp;quot;${tokenInfo.type} ${token.key}&amp;quot; data-state=&amp;quot;${token.state}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;`;&lt;br /&gt;
&lt;br /&gt;
$(token.location).insertAdjacentHTML(&#039;beforeend&#039;,div);&lt;br /&gt;
this.addTooltip(token.key, _(tokenInfo.name) + &amp;quot; &amp;quot; + _(tokenInfo.tooltip), &amp;quot;&amp;quot;);&lt;br /&gt;
$(token.key).addEventListener(&#039;onclick&#039;,(ev)=&amp;gt;this.onMeepleClick(ev));&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
When you receive an update notification (assuming you get the same &amp;quot;token&amp;quot; object), you either create it if not exists or animate:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if ($(token.key)) {&lt;br /&gt;
  // exists&lt;br /&gt;
  $(token.key).dataset.state = token.state; // update state&lt;br /&gt;
  this.moveToken(token.key, token.location); // animate to new location (custom functon), see [[BGA_Studio_Cookbook#Animation]]&lt;br /&gt;
  } else {&lt;br /&gt;
  // crate meeple using code in previous section&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Graphic Representation (.css)====&lt;br /&gt;
&lt;br /&gt;
Use same sprite technique from Resource section above.&lt;br /&gt;
&lt;br /&gt;
When placed on the board it will look good with shadow, but its not recommended on mobile&lt;br /&gt;
&lt;br /&gt;
  filter: drop-shadow(black 5px 5px 5px);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
To represent &amp;quot;laying down&amp;quot; meeple, you have to use a different sprite image, which you will apply based on data attribute&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.meeple[data-state=&amp;quot;1&amp;quot;] {&lt;br /&gt;
   background-image: url(...);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also rotate you div, but it will look lame.&lt;br /&gt;
Other options include changing its shading, adding overlay (i.e. sad face) and so on. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Selection and Actions====&lt;br /&gt;
To show user that meeple is active it best to use drop-shadow as image as non-square, however this may be very slow.&lt;br /&gt;
For simplier case use box shadow.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.active_slot {&lt;br /&gt;
  filter: drop-shadow(0px 0px 10px blue);&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* draw a circle around game element for selection */&lt;br /&gt;
.active_slot_simple:after {&lt;br /&gt;
  content: &amp;quot; &amp;quot;;&lt;br /&gt;
  width: 110%;&lt;br /&gt;
  top: -5%;&lt;br /&gt;
  left: -5%;&lt;br /&gt;
  aspect-ratio: 1/1;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  border-radius: 50%;&lt;br /&gt;
  box-shadow: 0px 0px 4px 3px #64b4ff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See code example at https://codepen.io/VictoriaLa/pen/emYgLzR&lt;br /&gt;
&lt;br /&gt;
When a meeple is gained from the supply, you can display a meeple icon on the status bar button &lt;br /&gt;
instead of showing the supply on the board.&lt;br /&gt;
&lt;br /&gt;
===Dice ===&lt;br /&gt;
The 2D dice can use similar handing as meeple but it has 6 states instead of 2.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: Never roll dice using javascript. All dice rolling must be done using bga_rand() function in php.&lt;br /&gt;
&lt;br /&gt;
====Representation in Database====&lt;br /&gt;
In a simplified &amp;quot;tokens&amp;quot; database, it might be represented like this &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
!token_key&lt;br /&gt;
!token_location&lt;br /&gt;
!token_state&lt;br /&gt;
|-&lt;br /&gt;
|die_black&lt;br /&gt;
|actionspot_1&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|die_red&lt;br /&gt;
|supply &lt;br /&gt;
|6&lt;br /&gt;
|}&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
====Representation in Material File (material.inc.php)====&lt;br /&gt;
&lt;br /&gt;
Similar to resource and meeple above&lt;br /&gt;
&lt;br /&gt;
====HTML Representation====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;die_black&amp;quot; class=&amp;quot;die&amp;quot; data-state=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====JavaScript Handling (.js)====&lt;br /&gt;
See meeple section&lt;br /&gt;
&lt;br /&gt;
====Graphic Representation (.css)====&lt;br /&gt;
For dice we would usually use N x 6 sprite, and since the sides are square - the .jpg format is better (it is smaller then png)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.die {  &lt;br /&gt;
  background-image: url(https://en.doc.boardgamearena.com/images/c/c5/64_64_dice.jpg);&lt;br /&gt;
  background-size: 600%;&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  aspect-ratio: 1/1;&lt;br /&gt;
  width: 64px;&lt;br /&gt;
  border-radius: 5%; /* looks better with rounded corders */&lt;br /&gt;
}&lt;br /&gt;
.die[data-state=&amp;quot;3&amp;quot;] {&lt;br /&gt;
  background-position: calc(100% / 5 * 2) 0%;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The 3D dice a bit tricker to create but its feasible, see https://codepen.io/VictoriaLa/pen/QWBBbwz for an example.&lt;br /&gt;
&lt;br /&gt;
Also multiple examples on N-sided dice can be found on [[BGA_Code_Sharing]]&lt;br /&gt;
&lt;br /&gt;
====Selection and Actions====&lt;br /&gt;
Since it is a square its a lot easier to make a square selection highlight&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.die.active_slot  {&lt;br /&gt;
  box-shadow: 0px 0px 4px 4px blue;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Card===&lt;br /&gt;
&lt;br /&gt;
Cards are the most complex game resource, they can be located in various zones, stacked, tapped, put face down and can have arbitrary complete abilities.&lt;br /&gt;
If you have square tiles - it can be treated the same as cards.&lt;br /&gt;
&lt;br /&gt;
====Representation in Database====&lt;br /&gt;
&lt;br /&gt;
In a simplified &amp;quot;tokens&amp;quot; database, it might be represented like this &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
!token_key&lt;br /&gt;
!token_location&lt;br /&gt;
!token_state&lt;br /&gt;
|-&lt;br /&gt;
|card_project_123&lt;br /&gt;
|tableau_ff0000&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|card_corp_p1&lt;br /&gt;
| deck_corp&lt;br /&gt;
|6&lt;br /&gt;
|}&lt;br /&gt;
  &lt;br /&gt;
Means project card is player red tableau and state 1 means it has been used for example,&lt;br /&gt;
and second card of corproration file in in deck at position 6 from the top.&lt;br /&gt;
&lt;br /&gt;
When duplcates are in play you need to add extra unique disambigator in the key.&lt;br /&gt;
&lt;br /&gt;
Usually cards will have numeric id associated with type, but it this number is per expansition, so leave the space for expansion identifier in there also.&lt;br /&gt;
&lt;br /&gt;
Another option use [[Deck]] component.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Representation in Material====&lt;br /&gt;
&lt;br /&gt;
All the card properties which do not change during the game can be put in material file (or its alternative)&lt;br /&gt;
&lt;br /&gt;
This is example from terraforming mars&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &#039;card_main_81&#039; =&amp;gt; [  //&lt;br /&gt;
  &#039;location&#039; =&amp;gt; &#039;deck_main&#039;,&lt;br /&gt;
  &#039;create&#039; =&amp;gt; &#039;single&#039;,&lt;br /&gt;
  &#039;num&#039; =&amp;gt; 81,&lt;br /&gt;
  &#039;name&#039; =&amp;gt; clienttranslate(&#039;Ganymede Colony&#039;),&lt;br /&gt;
  &#039;t&#039; =&amp;gt; 1,&lt;br /&gt;
  &#039;r&#039; =&amp;gt; &amp;quot;city(&#039;Ganymede Colony&#039;)&amp;quot;,&lt;br /&gt;
  &#039;cost&#039; =&amp;gt; 20,&lt;br /&gt;
  &#039;tags&#039; =&amp;gt; &#039;Space City Jovian&#039;,&lt;br /&gt;
  &#039;vp&#039; =&amp;gt; &#039;tagJovian&#039;,&lt;br /&gt;
  &#039;deck&#039; =&amp;gt; &#039;Basic&#039;,&lt;br /&gt;
  &#039;text&#039; =&amp;gt; clienttranslate(&#039;Place a city tile ON THE RESERVED AREA [for Ganymede Colony].&#039;),&lt;br /&gt;
  &#039;text_vp&#039; =&amp;gt; clienttranslate(&#039;1 VP per Jovian tag you have.&#039;),&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====HTML Representation====&lt;br /&gt;
&lt;br /&gt;
There is 2 main options:&lt;br /&gt;
* Use exact cards images in english&lt;br /&gt;
*Use cards images WITHOUT text&lt;br /&gt;
&lt;br /&gt;
The 3d option is completely redo the graphic layout that game designed did already, but I won&#039;t go there&lt;br /&gt;
&lt;br /&gt;
The first option is very simple and similar to other resources and meeple&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;card_project_123&amp;quot; class=&amp;quot;card card_project card_project_123&amp;quot; data-state=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The second option means you can add translated text instead&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;card_project_123&amp;quot; class=&amp;quot;card card_project card_project_123&amp;quot; data-state=&amp;quot;1&amp;quot; data-cost=&amp;quot;22&amp;quot;&amp;gt;&lt;br /&gt;
   &amp;lt;div class=&amp;quot;card_name&amp;quot;&amp;gt;Ganymede Colony&amp;lt;/div&amp;gt;&lt;br /&gt;
   &amp;lt;div class=&amp;quot;card_text&amp;quot;&amp;gt;Place a city tile ON THE RESERVED AREA [for Ganymede Colony].&amp;lt;/div&amp;gt;&lt;br /&gt;
   &amp;lt;div class=&amp;quot;card_cost&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above card_cost is also rendered as this can change during the game (even printed value is the same),&lt;br /&gt;
it would be rendered using data-cost attribute.&lt;br /&gt;
&lt;br /&gt;
Instead of using class you can also use state even if it is static&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_H_10&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&amp;quot;H&amp;quot; data-rank=&amp;quot;10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: to make flip animation you effectively need to make a &amp;quot;3d&amp;quot; card and provide both faces with separate graphics,&lt;br /&gt;
which makes more complex div. See examples at [[BgaCards]].&lt;br /&gt;
&lt;br /&gt;
Note: you can also use [[Stock]] component that handles html, js, css, layout and selection at the same time. If do that skip sections below.&lt;br /&gt;
&lt;br /&gt;
====JavaScript Handling (.js)====&lt;br /&gt;
You will get the server data which looks like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
card = {&lt;br /&gt;
  key: &#039;card_project_123&#039;,&lt;br /&gt;
  location: &#039;tableau_ff0000&#039;,&lt;br /&gt;
  state: &#039;1&#039;&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;
  createCard(token: Token) {&lt;br /&gt;
    // token_types is the structure from the material file sent to the client&lt;br /&gt;
    const tokenInfo = this.gamedatas.token_types[token.key]; &lt;br /&gt;
    const div = `&lt;br /&gt;
    &amp;lt;div id=&amp;quot;${token.key}&amp;quot; class=&amp;quot;${tokenInfo.type} ${token.key}&amp;quot; data-state=&amp;quot;${token.state}&amp;quot;&amp;gt;&lt;br /&gt;
       &amp;lt;div class=&amp;quot;card_name&amp;quot;&amp;gt;${_(tokenInfo.name)}&amp;lt;/div&amp;gt;&lt;br /&gt;
       &amp;lt;div class=&amp;quot;card_text&amp;quot;&amp;gt;${_(tokenInfo.text)}&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;`;&lt;br /&gt;
&lt;br /&gt;
    $(token.location).insertAdjacentHTML(&#039;beforeend&#039;,div);&lt;br /&gt;
    this.addTooltipHtml(token.key, this.getTooptipHtmlForToken(token));&lt;br /&gt;
    $(token.key).addEventListener(&amp;quot;onclick&amp;quot;, (ev) =&amp;gt; this.onCardClick(ev));&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you receive an update notification (assuming you get the same &amp;quot;token&amp;quot; object), you either create it if not exists or animate:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if ($(token.key)) {&lt;br /&gt;
  // exists&lt;br /&gt;
  $(token.key).dataset.state = token.state; // update state&lt;br /&gt;
  $(token.key).dataset.cost = token.cost; // update cost (discounted cost)&lt;br /&gt;
  this.moveCard(token.key, token.location); // animate to new location (custom functon), see [[BGA_Studio_Cookbook#Animation]]&lt;br /&gt;
} else {&lt;br /&gt;
  this.createCard(token);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====Graphic Representation (.css)====&lt;br /&gt;
&lt;br /&gt;
For this html&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;game&amp;quot; class=&amp;quot;classic_deck&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;hand&amp;quot; class=&amp;quot;hand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_H_10&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;H&#039; data-rank=&amp;quot;10&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;card_C_K&amp;quot; class=&amp;quot;card&amp;quot; data-suit=&#039;C&#039; data-rank=&amp;quot;K&amp;quot;&amp;gt; &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is example css using sprite image of playing cards&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.card {&lt;br /&gt;
   background-image: url(&#039;https://x.boardgamearena.net/data/others/cards/FULLREZ_CARDS_ORIGINAL_NORMAL.jpg&#039;);   /* don&#039;t do full url in your game, copy this file inside img folder */&lt;br /&gt;
  &lt;br /&gt;
   background-size: 1500% auto;  /* this mean size of background is 15 times bigger than size of card, because its sprite */&lt;br /&gt;
   border-radius: 5%;&lt;br /&gt;
   width: 10em;&lt;br /&gt;
   height: 13.5em;&lt;br /&gt;
   box-shadow: 0.1em 0.1em 0.2em 0.1em #555;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
.card[data-rank=&amp;quot;10&amp;quot;] { /* 10 is column number 10 - 2 because we start from 0 and first card is sprite is 2. The multiplier is (15 - 1) is because we have 15 columns. -1 is because % in CSS is weird like that. */&lt;br /&gt;
   background-position-x: calc(100% / (15 - 1) * (10 - 2));&lt;br /&gt;
}&lt;br /&gt;
.card[data-rank=&amp;quot;K&amp;quot;] { /* King will be number 13 in rank */&lt;br /&gt;
   background-position-x: calc(100% / (15 - 1) * (13 - 2));&lt;br /&gt;
}&lt;br /&gt;
.card[data-suit=&amp;quot;H&amp;quot;] { /* Hears row position is 1 (because we count from 0). Multiplier (4 - 1) is because we have 4 rows and -1 is because % in CSS is weird like that. */&lt;br /&gt;
   background-position-y: calc(100% / (4 - 1) * (1));&lt;br /&gt;
}&lt;br /&gt;
.card[data-suit=&amp;quot;C&amp;quot;] { /* Clubs row position is 2 */&lt;br /&gt;
   background-position-y: calc(100% / (4 - 1) * (2));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
See code at https://codepen.io/VictoriaLa/pen/mdMzRxa&lt;br /&gt;
&lt;br /&gt;
====Selection and Actions====&lt;br /&gt;
&lt;br /&gt;
Since it is a square its a lot easier to make a square selection highlight&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.card.active_slot  {&lt;br /&gt;
  box-shadow: 0px 0px 4px 4px blue;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Card Layouts====&lt;br /&gt;
There are two options - you use [[Stock]] component or don&#039;t, see [[Anti-Stock]] for details on how to do your own layouts.&lt;br /&gt;
&lt;br /&gt;
This is comprehensive example of various card layouts and animations&lt;br /&gt;
https://thoun.github.io/bga-cards/demo/index.html&lt;br /&gt;
&lt;br /&gt;
===Hex Tiles===&lt;br /&gt;
From data perspective hex tiles exactly the same as cards.&lt;br /&gt;
From visualization there is a small trick.&lt;br /&gt;
&lt;br /&gt;
CSS:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.hex {&lt;br /&gt;
  width: var(--hex-width);&lt;br /&gt;
  aspect-ratio: 1 / 1.1193;&lt;br /&gt;
  border-radius: 30%;&lt;br /&gt;
  background-color: yellow; /* this is just for demo, use proper .png file for this */&lt;br /&gt;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.hex.active_slot_simple {&lt;br /&gt;
  background-color: rgba(86, 207, 110, 0.4);&lt;br /&gt;
}&lt;br /&gt;
.hex.active_slot {&lt;br /&gt;
  filter: drop-shadow(0px 0px 10px blue);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Tetris Tiles===&lt;br /&gt;
You can use clip-path for actual shape and svg path for outline&lt;br /&gt;
See example at https://codepen.io/VictoriaLa/pen/OJmoZGw&lt;br /&gt;
&lt;br /&gt;
===Track===&lt;br /&gt;
&lt;br /&gt;
Tracker can be represented as &amp;quot;resource&amp;quot; in database - in this case its just number, or similar to &amp;quot;meeple&amp;quot; in which case&lt;br /&gt;
the location will have the &amp;quot;number&amp;quot; associated with position on track&lt;br /&gt;
&lt;br /&gt;
In a simplified &amp;quot;tokens&amp;quot; database, it might be represented like this &lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+token&lt;br /&gt;
!token_key&lt;br /&gt;
!token_location&lt;br /&gt;
!token_state&lt;br /&gt;
|-&lt;br /&gt;
|tracker_o&lt;br /&gt;
| scale_o_1&lt;br /&gt;
|0&lt;br /&gt;
|-&lt;br /&gt;
|tracker_t &lt;br /&gt;
| scale_t_10 &lt;br /&gt;
|0&lt;br /&gt;
|}&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
The tracker location in this case may have some properties in material file, for example to trigger game effect when we land on this spot&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &#039;scale_t&#039; =&amp;gt; [&lt;br /&gt;
    &#039;index_start&#039; =&amp;gt; 0,&lt;br /&gt;
    &#039;max&#039; =&amp;gt; 20,&lt;br /&gt;
    &#039;value_start&#039; =&amp;gt; -30,&lt;br /&gt;
    &#039;value_step&#039; =&amp;gt; 2,&lt;br /&gt;
    &#039;slot_type&#039; =&amp;gt; &#039;slot slot_t&#039;&lt;br /&gt;
  ],&lt;br /&gt;
  &#039;scale_t_10&#039; =&amp;gt; [&lt;br /&gt;
    &#039;r&#039; =&amp;gt; &#039;ocean&#039;,&lt;br /&gt;
    &#039;param&#039; =&amp;gt; &#039;t&#039;,&lt;br /&gt;
    &#039;tooltp&#039; =&amp;gt; clienttranslate(&#039;Place an ocean&#039;),&lt;br /&gt;
    &#039;value&#039; =&amp;gt; 0&lt;br /&gt;
  ],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The track in this case can be generated as series of slots (create in js)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    for(let i=trackInfo.index_start,value = trackInfo.value_start;i&amp;lt;trackInfo.index_start+trackInfo.max;i++,value+=trackInfo.value_step) {&lt;br /&gt;
      $(trackInfo.key).insertAdjacentHTML(&#039;beforeend&#039;,`&amp;lt;div id=&amp;quot;${trackInfo.key}_${i}&amp;quot; class=&amp;quot;${trackInfo.slot_type} data-value=${value}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;`);&lt;br /&gt;
      this.addTooltip(`${trackInfo.key}_${i}`, _(tokenInfo.tooltip), &amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then use regular move animation to move tracker into position on track.&lt;br /&gt;
&lt;br /&gt;
==Code Organization==&lt;br /&gt;
&lt;br /&gt;
===Including your own JavaScript module===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, modules/ggg_other.js&lt;br /&gt;
&lt;br /&gt;
*Create ggg_other.js in modules/ folder and sync&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;&lt;br /&gt;
], function( dojo, declare )&lt;br /&gt;
{&lt;br /&gt;
return declare(&amp;quot;bgagame.other&amp;quot;, null, { // null here if we don&#039;t want to inherit from anything&lt;br /&gt;
        constructor: function(){},&lt;br /&gt;
        mystuff: function(){},&lt;br /&gt;
    });&lt;br /&gt;
        &lt;br /&gt;
});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
*Modify ggg.js to include it&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  define([ &amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;, &amp;quot;ebg/core/gamegui&amp;quot;, &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    g_gamethemeurl + &amp;quot;modules/ggg_other.js&amp;quot;     // load my own module!!!&lt;br /&gt;
  ], function(dojo,&lt;br /&gt;
        declare) {&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
use it&lt;br /&gt;
&lt;br /&gt;
  foo = new bgagame.other();&lt;br /&gt;
&lt;br /&gt;
===Including your own JavaScript module (II) ===&lt;br /&gt;
&lt;br /&gt;
*Create ggg_other.js in modules/ folder and sync&lt;br /&gt;
&lt;br /&gt;
  define([], function () {&lt;br /&gt;
    return &amp;quot;value&amp;quot;;&lt;br /&gt;
  }); &lt;br /&gt;
&lt;br /&gt;
* Modify ggg.js to include it&lt;br /&gt;
&lt;br /&gt;
  define([ &lt;br /&gt;
    &amp;quot;dojo&amp;quot;, &lt;br /&gt;
    &amp;quot;dojo/_base/declare&amp;quot;, &lt;br /&gt;
    &amp;quot;bgagame/modules/ggg_other&amp;quot;, &lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;, &lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;&lt;br /&gt;
  ], function(dojo, declare, other) {&lt;br /&gt;
  &lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
This is maybe a little bit more the idea of the AMD Loader than the first option, although the first option should work as well.&lt;br /&gt;
&lt;br /&gt;
A little explanation to this:&lt;br /&gt;
The define function loads all the modules listed in the array and calls the following function with these loaded modules as parameters.&lt;br /&gt;
By putting your module at the third position in the array it is passed as the third parameter to the function. Be aware that the modules are resolved by position only, not by name. So you can load the module &#039;&#039;&#039;ggg_other&#039;&#039;&#039; and pass it as a parameter with the name &#039;&#039;&#039;other&#039;&#039;&#039;. &#039;&#039;&#039;gamegui&#039;&#039;&#039; and &#039;&#039;&#039;counter&#039;&#039;&#039; are passed in as well, but when the parameters are not defined they are just skipped. Because these modules put their content into the global scope it does not matter and you can use them from there.&lt;br /&gt;
&lt;br /&gt;
In the example above the string &amp;quot;value&amp;quot; is passed for the parameter &#039;&#039;&#039;other&#039;&#039;&#039;, but the function in your module can return whatever you want. It can be an object, an array, something you declared with dojo.declare, you can return even functions. &lt;br /&gt;
Your module can load other modules. Just put them in the array at the beginning and pass them as parameters to your function.&lt;br /&gt;
The advantage of passing the values as parameter is that you do not need to put these values in the global scope, so they can&#039;t be collisions with values defined in other scripts or the BGA Framework.&lt;br /&gt;
&lt;br /&gt;
The dojo toolkit provides good documentation to all of its components, the complete documentation for the AMD-Loader is here:&lt;br /&gt;
https://dojotoolkit.org/documentation/tutorials/1.10/modules/index.html It should be still correct, even as it seems to be only for version 1.10&lt;br /&gt;
&lt;br /&gt;
===Including your own PHP module===&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, modules/ggg_other.php&lt;br /&gt;
&lt;br /&gt;
*Create ggg_other.php in modules/ folder and sync&lt;br /&gt;
*Modify ggg.game.php to include it&lt;br /&gt;
&lt;br /&gt;
 require_once (&#039;modules/ggg_other.php&#039;);&lt;br /&gt;
&lt;br /&gt;
===Creating a test class to run PHP locally ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.game.php, stubs&lt;br /&gt;
For this you need stubs of other method you can use this for example&lt;br /&gt;
https://github.com/elaskavaia/bga-sharedcode/raw/master/misc/module/table/table.game.php&lt;br /&gt;
&lt;br /&gt;
Create another php files, i.e ggg_test.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
define(&amp;quot;APP_GAMEMODULE_PATH&amp;quot;, &amp;quot;misc/&amp;quot;); // include path to stubs, which defines &amp;quot;table.game.php&amp;quot; and other classes&lt;br /&gt;
require_once (&#039;eminentdomaine.game.php&#039;);&lt;br /&gt;
&lt;br /&gt;
class MyGameTest1 extends MyGame { // this is your game class defined in ggg.game.php&lt;br /&gt;
    function __construct() {&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        include &#039;../material.inc.php&#039;;// this is how this normally included, from constructor&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // override/stub methods here that access db and stuff&lt;br /&gt;
    function getGameStateValue($var) {&lt;br /&gt;
        if ($var == &#039;round&#039;)&lt;br /&gt;
            return 3;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
$x = new MyGameTest1(); // instantiate your class&lt;br /&gt;
$p = $x-&amp;gt;getGameProgression(); // call one of the methods to test&lt;br /&gt;
if ($p != 50)&lt;br /&gt;
    echo &amp;quot;Test1: FAILED&amp;quot;;&lt;br /&gt;
else&lt;br /&gt;
    echo &amp;quot;Test1: PASSED&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Run from command line like&lt;br /&gt;
 php8.4 ggg_test.php&lt;br /&gt;
&lt;br /&gt;
If you do it this way - you can also use local php debugger (i.e. integrated with IDE or command line).&lt;br /&gt;
&lt;br /&gt;
===Avoiding code in dojo declare style===&lt;br /&gt;
Dojo class declarations are rather bizzare and do not work with most IDEs.&lt;br /&gt;
If you want to write in plain JS with classes, you can stub all the dojo define/declare stuff&lt;br /&gt;
and hook your class into that, so the classes are outside of this mess.&lt;br /&gt;
&lt;br /&gt;
NOTE: this technique is for experienced developers, do not try it if you do not understand&lt;br /&gt;
the consequences.&lt;br /&gt;
&lt;br /&gt;
This is complete example of game .js class&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // Testla is game name is has to be changed&lt;br /&gt;
class Testla {&lt;br /&gt;
	constructor(game) {&lt;br /&gt;
		console.log(&#039;game constructor&#039;);&lt;br /&gt;
		this.game = game;&lt;br /&gt;
		this.varfoo = new MyFoo(); // this example of class from custom module&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	setup(gamedatas) {&lt;br /&gt;
		console.log(&amp;quot;Starting game setup&amp;quot;, this.varfoo);&lt;br /&gt;
		this.gamedatas = gamedatas;&lt;br /&gt;
		this.dojo.create(&amp;quot;div&amp;quot;, { class: &#039;whiteblock&#039;, innerHTML: _(&amp;quot;hello&amp;quot;) }, &#039;thething&#039;);&lt;br /&gt;
		console.log(&amp;quot;Ending game setup&amp;quot;);&lt;br /&gt;
	};&lt;br /&gt;
	onEnteringState(stateName, args) {&lt;br /&gt;
		console.log(&#039;onEnteringState : &#039; + stateName, args);&lt;br /&gt;
		this.game.addActionButton(&#039;b1&#039;,_(&#039;Click Me&#039;), (e)=&amp;gt;this.onButtonClick(e));&lt;br /&gt;
	};&lt;br /&gt;
	onLeavingState(stateName) {&lt;br /&gt;
		console.log(&#039;onLeavingState : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onUpdateActionButtons(stateName, args) {&lt;br /&gt;
		console.log(&#039;onUpdateActionButtons : &#039; + stateName, args);&lt;br /&gt;
	};&lt;br /&gt;
	onButtonClick(event) {&lt;br /&gt;
		console.log(&#039;onButtonClick&#039;,event);&lt;br /&gt;
	};&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
define([&lt;br /&gt;
	&amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
	&amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
	g_gamethemeurl + &#039;/modules/foo.js&#039; // custom module if needed&lt;br /&gt;
],&lt;br /&gt;
	function(dojo, declare) {&lt;br /&gt;
                // testla is game name is has to be changed&lt;br /&gt;
		return declare(&amp;quot;bgagame.testla&amp;quot;, ebg.core.gamegui, {&lt;br /&gt;
			constructor: function() {&lt;br /&gt;
				this.xapp = new Testla(this);&lt;br /&gt;
				this.xapp.dojo = dojo;&lt;br /&gt;
			},&lt;br /&gt;
			setup: function(gamedatas) {&lt;br /&gt;
				this.xapp.setup(gamedatas);&lt;br /&gt;
			},&lt;br /&gt;
			onEnteringState: function(stateName, args) {&lt;br /&gt;
				this.xapp.onEnteringState(stateName, args?.args);&lt;br /&gt;
			},&lt;br /&gt;
			onLeavingState: function(stateName) {&lt;br /&gt;
				this.xapp.onLeavingState(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
			onUpdateActionButtons: function(stateName, args) {&lt;br /&gt;
				this.xapp.onUpdateActionButtons(stateName, args);&lt;br /&gt;
			},&lt;br /&gt;
		});&lt;br /&gt;
	});&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===More readable JS: onEnteringState===&lt;br /&gt;
&lt;br /&gt;
If you have a lot of states in onEnteringState or onUpdateActionButtons and friends - it becomes rather wild, you can do this trick to call some methods dynamically.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
     onEnteringState: function(stateName, args) {&lt;br /&gt;
       console.log(&#039;Entering state: &#039; + stateName, args);&lt;br /&gt;
&lt;br /&gt;
       // Call appropriate method&lt;br /&gt;
       var methodName = &amp;quot;onEnteringState_&amp;quot; + stateName;&lt;br /&gt;
       if (this[methodName] !== undefined) {             &lt;br /&gt;
          console.log(&#039;Calling &#039; + methodName, args.args);&lt;br /&gt;
          this[methodName](args.args);&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerTurn: function(args) { // this is args directly, not args.args &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
     onEnteringState_playerSomethingElse: function(args) { &lt;br /&gt;
         // process&lt;br /&gt;
     },&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: since its ignores the undefined functions you don&#039;t have define function for each state, but on the other hand you cannot make typos.&lt;br /&gt;
Same applies to onUpdateActionButtons except you pass &#039;args&#039; to method, not args.args, and for onLeavingState where you don&#039;t pass anything.&lt;br /&gt;
&lt;br /&gt;
=== Frameworks and Preprocessors=== &lt;br /&gt;
&lt;br /&gt;
*[[BGA Type Safe Template]] - Setting up a fully typed project using typescript and more!&lt;br /&gt;
*[[Using Vue]] - work-in-progress guide on using the modern framework Vue.js to create a game&lt;br /&gt;
* [[Using Typescript and Scss]] - How to auto-build Typescript and SCSS files to make your code cleaner&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===PHP Migration===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; */php, modules/*.php&lt;br /&gt;
&lt;br /&gt;
BGA recently migrated to from 7.4 to 8.2 then 8.4.&lt;br /&gt;
New php has new rules and deprecations.&lt;br /&gt;
&lt;br /&gt;
There is a tool that can help you do the migration automation, which is php module called rector https://getrector.com/.&lt;br /&gt;
Below is the recipe that converts variables in strings like ${var} (which is deprecated) to {$var}.&lt;br /&gt;
&lt;br /&gt;
1. Install the module&lt;br /&gt;
 composer global require --dev rector/rector&lt;br /&gt;
2. Go to your project directory, commit your code first before this!&lt;br /&gt;
&lt;br /&gt;
3. Create a rector.php file on top level with the following content:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
use Rector\Config\RectorConfig;&lt;br /&gt;
use Rector\Php82\Rector\Encapsed\VariableInStringInterpolationFixerRector;&lt;br /&gt;
&lt;br /&gt;
return RectorConfig::configure()&lt;br /&gt;
    -&amp;gt;withPaths([&lt;br /&gt;
        __DIR__ &lt;br /&gt;
    ])&lt;br /&gt;
    // A. whole set&lt;br /&gt;
    //-&amp;gt;withPreparedSets(typeDeclarations: true)&lt;br /&gt;
    // B. or few rules&lt;br /&gt;
    -&amp;gt;withRules([&lt;br /&gt;
        VariableInStringInterpolationFixerRector::class&lt;br /&gt;
    ]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
4. Dry run (mine is on linux, not sure where global install on windows)&lt;br /&gt;
  ~/.config/composer/vendor/bin/rector process --dry-run&lt;br /&gt;
&lt;br /&gt;
5. If happy re-run without --dry-run&lt;br /&gt;
&lt;br /&gt;
6. Can remove rector.php now (or can do different rules)&lt;br /&gt;
&lt;br /&gt;
==Backend==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Assigning Player Order===&lt;br /&gt;
Normally when game starts there is &amp;quot;natural&amp;quot; player order assigned randomly.&lt;br /&gt;
&lt;br /&gt;
If you want to deliberatly assign player order at the start of the game (for example, in a game with teams options), you can do so by retrieving the initialization-only player attribute &#039;&#039;&#039;player_table_order&#039;&#039;&#039; and using it to assign values to &#039;&#039;&#039;player_no&#039;&#039;&#039; (which is normally assigned at the start of a game in the order in which players come to the table). (See [https://en.doc.boardgamearena.com/Game_database_model:_dbmodel.sql#The_player_table Game database model] for more details.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&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; To prevent unfair advantage (e.g. collusion), the random order must be the default option and &amp;lt;b&amp;gt;non-random options should be limited to friendly mode.&amp;lt;/b&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                // Retrieve inital player order ([0=&amp;gt;playerId1, 1=&amp;gt;playerId2, ...])&lt;br /&gt;
		$playerInitialOrder = [];&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$playerInitialOrder[$player[&#039;player_table_order&#039;]] = $playerId;&lt;br /&gt;
		}&lt;br /&gt;
		ksort($playerInitialOrder);&lt;br /&gt;
		$playerInitialOrder = array_flip(array_values($playerInitialOrder));&lt;br /&gt;
&lt;br /&gt;
		// Player order based on &#039;playerTeams&#039; option&lt;br /&gt;
		$playerOrder = [0, 1, 2, 3];&lt;br /&gt;
		switch ($this-&amp;gt;getGameStateValue(&#039;playerTeams&#039;)) {&lt;br /&gt;
			case $this-&amp;gt;TEAM_1_2:&lt;br /&gt;
				$playerOrder = [0, 2, 1, 3];&lt;br /&gt;
				break;&lt;br /&gt;
			case $this-&amp;gt;TEAM_1_4:&lt;br /&gt;
				$playerOrder = [0, 1, 3, 2];&lt;br /&gt;
				break;&lt;br /&gt;
			case $this-&amp;gt;TEAM_RANDOM:&lt;br /&gt;
				shuffle($playerOrder);&lt;br /&gt;
				break;&lt;br /&gt;
			default:&lt;br /&gt;
			case $this-&amp;gt;TEAM_1_3:&lt;br /&gt;
				// Default order&lt;br /&gt;
				break;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
                // Create players&lt;br /&gt;
		// Note: if you added some extra field on &amp;quot;player&amp;quot; table in the database (dbmodel.sql), you can initialize it there.&lt;br /&gt;
		$sql =&lt;br /&gt;
			&#039;INSERT INTO player (player_id, player_color, player_canal, player_name, player_avatar, player_no) VALUES &#039;;&lt;br /&gt;
		$values = [];&lt;br /&gt;
&lt;br /&gt;
		foreach ($players as $playerId =&amp;gt; $player) {&lt;br /&gt;
			$color = array_shift($default_colors);&lt;br /&gt;
			$values[] =&lt;br /&gt;
				&amp;quot;(&#039;&amp;quot; .&lt;br /&gt;
				$playerId .&lt;br /&gt;
				&amp;quot;&#039;,&#039;$color&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$player[&#039;player_canal&#039;] .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_name&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				addslashes($player[&#039;player_avatar&#039;]) .&lt;br /&gt;
				&amp;quot;&#039;,&#039;&amp;quot; .&lt;br /&gt;
				$playerOrder[$playerInitialOrder[$playerId]] .&lt;br /&gt;
				&amp;quot;&#039;)&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
		$sql .= implode(&#039;,&#039;, $values);&lt;br /&gt;
		$this-&amp;gt;DbQuery($sql);&lt;br /&gt;
		$this-&amp;gt;reattributeColorsBasedOnPreferences(&lt;br /&gt;
			$players,&lt;br /&gt;
			$gameinfos[&#039;player_colors&#039;]&lt;br /&gt;
		);&lt;br /&gt;
		$this-&amp;gt;reloadPlayersBasicInfos();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send different notifications to active player vs everybody else===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Hack alert. This is a hack. We were hoping for proper solution by bga framework.&lt;br /&gt;
&lt;br /&gt;
This will allow you to send notification with two message one for specific player and one for everybody else including spectators.&lt;br /&gt;
Note that this does not split the data - all data must be shared.&lt;br /&gt;
&lt;br /&gt;
Add this to .js file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
bgaFormatText: function(log, args) {&lt;br /&gt;
   if (typeof args.log_others != &#039;undefined&#039; &amp;amp;&amp;amp; typeof args.player_id != &#039;undefined&#039; &amp;amp;&amp;amp; this.player_id != args.player_id) {&lt;br /&gt;
      log = args.log_others;&lt;br /&gt;
   }&lt;br /&gt;
   return { log, args }; // you must return this so the framework can handle the default formatting&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example of usage (from eminentdomain)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    $this-&amp;gt;notify-&amp;gt;all(&#039;tokenMoved&#039;, &lt;br /&gt;
             clienttranslate(&#039;${player_name} adds +2 Colonies to ${place_name}&#039;), // notification with show for player with player_id&lt;br /&gt;
             [&#039;player_id&#039;=&amp;gt;$player_id, // this is mandatory&lt;br /&gt;
             &#039;log_others&#039;=&amp;gt;clienttranslate(&#039;${player_name} adds +2 Colonies to an unknown planet&#039;), // notification will show for others&lt;br /&gt;
              ...&lt;br /&gt;
             ]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Send transient notifications without incrementing move ID===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.php&lt;br /&gt;
&lt;br /&gt;
Hack alert. This is a hack.&lt;br /&gt;
&lt;br /&gt;
Use this if you need to send some transient notification that should not create a new move ID. The notification should be idempotent -- it should have no practical effect on the game state and would be &#039;&#039;&#039;safe to drop&#039;&#039;&#039; (e.g., it would not matter if a player never received this notification). For example, in a co-op game you want all players to see a real-time preview of some action, before the active player commits their turn.&lt;br /&gt;
&lt;br /&gt;
Doing this mainly affects the instant replay &amp;amp; archive modes. During replay, the BGA framework automatically inserts a 1.5-second pause between each &amp;quot;move&amp;quot;. With this hack, your transient notifications are not considered to be a &amp;quot;move&amp;quot;, so no pause gets added.&lt;br /&gt;
&lt;br /&gt;
;In ggg.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;not_a_move_notification = true; // note: do not increase the move counter&lt;br /&gt;
$this-&amp;gt;notify-&amp;gt;all(&#039;cardsPreview&#039;, &#039;&#039;, $args);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: you cannot have code that send notification or even changes state after this, and you cannot reset this variable back either because it only takes effect when you exit action handling function&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Assorted Stuff==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Out-of-turn actions: Un-pass===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js, ggg.game.php, ggg.action.php, states.inc.php&lt;br /&gt;
&lt;br /&gt;
In multiplayer game sometimes players passes but than they think more and want to un-Pass and redo their choice. &lt;br /&gt;
To re-active a player who passes some trickery required.&lt;br /&gt;
&lt;br /&gt;
Define a special action that does that and hook it up.&lt;br /&gt;
&lt;br /&gt;
In states.inc.php add an action to MULTIPLE_ACTIVE_PLAYER state to &amp;quot;unpass&amp;quot;, lets call it &amp;quot;actionCancel&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In ggg.action.php add action hook&lt;br /&gt;
    public function actionCancel() {&lt;br /&gt;
        $this-&amp;gt;setAjaxMode();&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;actionCancel();&lt;br /&gt;
        $this-&amp;gt;ajaxResponse();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
In ggg.game.php add action handler&lt;br /&gt;
    function actionCancel() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction(&#039;actionCancel&#039;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive(array ($this-&amp;gt;getCurrentPlayerId() ), &#039;error&#039;, false);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Finally to call this in client ggg.js you would do something like:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 onUpdateActionButtons:  function(stateName, args) {&lt;br /&gt;
   if (this.isCurrentPlayerActive()) { &lt;br /&gt;
     // ...&lt;br /&gt;
   } else if (!this.isSpectator) { // player is NOT active but not spectator&lt;br /&gt;
       switch (stateName) {&lt;br /&gt;
          case &#039;playerTurnMultiPlayerState&#039;:&lt;br /&gt;
		this.addActionButton(&#039;button_unpass&#039;, _(&#039;Oh no!&#039;), &#039;onUnpass&#039;);&lt;br /&gt;
		break;&lt;br /&gt;
	}&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
				&lt;br /&gt;
 onUnpass: function(e) {&lt;br /&gt;
    this.bgaPerformAction(&amp;quot;actionCancel&amp;quot;, null, { checkAction: false }); // no checkAction!&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Although be careful that if the turn comes back to the player while he is about to click cancel, the action buttons will be updated and the player will misclick which can be quite frustrating. To avoid this, move the cancel button to another position, like to the left of pagemaintitletext:&lt;br /&gt;
  dojo.place(&#039;button_unpass&#039;, &#039;pagemaintitletext&#039;, &#039;before&#039;);&lt;br /&gt;
Being out of the generalactions div, it won&#039;t be automatically destroyed like normal buttons, so you&#039;ll have to handle that yourself in onLeavingState. You might also want to change the button color to red (blue buttons for active player only, red buttons also for inactive players?)&lt;br /&gt;
&lt;br /&gt;
Note: same technique can be used to do other out-of-turn actions, such as re-arranging cards in hand, exchanging resources, etc (i.e. if permitted by rules, such as &amp;quot;at any time player can...&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
===Multi Step Interactions: Select Worker/Place Worker - Using Selection ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
Simple way to implement something like that without extra states is to use &amp;quot;selection&amp;quot; mechanism. When user click on worker add some sort of class into that element i.e. &#039;selected&#039; (which also have to have some indication by css i.e. outline).&lt;br /&gt;
&lt;br /&gt;
Than user can click on placement zone, you can use dojo.query for &amp;quot;selected&amp;quot; element and use it along with zone id to send data to server. If proper worker is not selected yet can give a error message using this.showMessage(...) function.&lt;br /&gt;
&lt;br /&gt;
Extra code required to properly cleanup selection between states.&lt;br /&gt;
Also when you do that sometimes you want to change the state prompt, see below &#039;Change state prompt&#039;&lt;br /&gt;
&lt;br /&gt;
===Multi Step Interactions: Select Worker/Place Worker - Using Client States ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ingredients:&#039;&#039;&#039; ggg.js&lt;br /&gt;
&lt;br /&gt;
I don&#039;t think its documented feature but there is a way to do client-only states, which is absolutely wonderful for few reasons&lt;br /&gt;
*When player interaction is two step process, such as select worker, place worker, or place worker, pick one of two resources of your choice&lt;br /&gt;
* When multi-step process can result of impossible situation and has to be undone (by rules)&lt;br /&gt;
*When multi-step process is triggered from multiple states (such as you can do same thing as activated card action, pass action or main action)&lt;br /&gt;
&lt;br /&gt;
So lets do Select Worker/Place Worker&lt;br /&gt;
&lt;br /&gt;
Define your server state as usual, i.e. playerMainTurn -&amp;gt; &amp;quot;You must pick up a worker&amp;quot;.&lt;br /&gt;
Now define a client state, we only need &amp;quot;name&amp;quot; and &amp;quot;descriptionmyturn&amp;quot;, lets say &amp;quot;client_playerPicksLocation&amp;quot;. Always prefix names of client state with &amp;quot;client_&amp;quot; to avoid confusion. Now we have to do the following:&lt;br /&gt;
*Have a handler for onUpdateActionButtons for playerMainTurn to activate all possible workers he can pick&lt;br /&gt;
*When player clicks workers, remember the worker in one of the members of the main class, I usually use one called this.clientStateArgs.&lt;br /&gt;
*Transition to new client state&lt;br /&gt;
  onWorker: function(e) {&lt;br /&gt;
      var id = event.currentTarget.id;&lt;br /&gt;
      dojo.stopEvent(event);&lt;br /&gt;
      ... // do validity checks&lt;br /&gt;
      this.clientStateArgs.worker_id = id;&lt;br /&gt;
      this.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                                descriptionmyturn : _(&amp;quot;${you} must select location&amp;quot;),&lt;br /&gt;
                            });&lt;br /&gt;
   }&lt;br /&gt;
* Have a handler for onUpdateActionButtons for client_playerPicksLocation to activate all possible locations this worker can go AND add Cancel button (see below)&lt;br /&gt;
*Have a location handler which will eventually send a server request, using stored this.clientStateArgs.worker_id as worker id&lt;br /&gt;
*The cancel button should call a method to restore server state, also if you doing it for more than one state you can add this universally using this.on_client_state check&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        if (this.isCurrentPlayerActive()) {&lt;br /&gt;
          if (this.on_client_state &amp;amp;&amp;amp; !$(&#039;button_cancel&#039;)) {&lt;br /&gt;
               this.addActionButton(&#039;button_cancel&#039;, _(&#039;Cancel&#039;), dojo.hitch(this, function() {&lt;br /&gt;
                                             this.restoreServerGameState();&lt;br /&gt;
               }));&lt;br /&gt;
          }&lt;br /&gt;
        } &lt;br /&gt;
Note: usually I call my own function call this.cancelLocalStateEffects() which will do more stuff first then call restoreServerGameState(), same function is usually needs to be called when server request has failed (i.e. invalid move)&lt;br /&gt;
&lt;br /&gt;
Note: If you need more than 2 steps, you may have to do client side animation to reflect the new state, which gets trickier because you have to undo that also on cancellation.&lt;br /&gt;
&lt;br /&gt;
Code is available here [https://github.com/elaskavaia/bga-sharedcode/blob/master/sharedcode.js sharedcode.js] (its using playerTurnPlayCubes and client_selectCubeLocation).&lt;br /&gt;
&lt;br /&gt;
===Action Stack - Using Client States===&lt;br /&gt;
&lt;br /&gt;
Action stack required where game is very complex and use triggered effects that can &amp;quot;stack&amp;quot;. It not always actual stack, it can be queue or random access.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
*Magic the Gathering - classic card game where effects go on Stack, that allows to counter spell and counter spell of counter spell (not on bga - it just example of mechanics)&lt;br /&gt;
*Ultimate Railroads - action taking game where effects can be executed in any order&lt;br /&gt;
*Lewis and Clark - card game where actions executed as queue&lt;br /&gt;
&lt;br /&gt;
There is two ways of implementing it - on the server or the client.&lt;br /&gt;
For the server see article below.&lt;br /&gt;
The requirement for client side stack implementation is - all action can be undone, which means&lt;br /&gt;
* No dice rolls&lt;br /&gt;
* No card drawn&lt;br /&gt;
* No other players interaction&lt;br /&gt;
&lt;br /&gt;
No snippets are here, as this will be too complex but basically flow is:&lt;br /&gt;
*You have a action/effect stack (queue/list) as js object attached to &amp;quot;this&amp;quot;, i.e. this.unprocessed_actions&lt;br /&gt;
*When player plays a card, worker, etc, you read the effect of that card from the material file (client copy), and place into stack&lt;br /&gt;
*Then we call dispatch method which pulls the next action from the stack and change client state accordinly, i.e. this.setClientState(&amp;quot;client_playerGainsCubes&amp;quot;)&lt;br /&gt;
* When players acts on it - the action is removed from the stack and added to &amp;quot;server action arguments&amp;quot; list, this is another object which be used to send ajax call, i.e. this.clientStateArgs&lt;br /&gt;
*If nothing left in stack we can submit the ajax call assembling parameters from collected arguments (that can include action name)&lt;br /&gt;
*This method allows cheap undo - by restoring server state you will wipe out all user actions (but if you need intermediate aninmation you have to handle it yourself)&lt;br /&gt;
&lt;br /&gt;
Code can be found in Ultimate Railroads game (but it is random access list - so it a bit complex) and Lewis and Clark (complexity - user can always deny part of any effect)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Action Stack - Using Server States===&lt;br /&gt;
&lt;br /&gt;
See definition of Action Stack above.&lt;br /&gt;
&lt;br /&gt;
To implement you usually need another db table that has the following fields: index of effect - which is used for sorted access, type - which is essense of the effect (i.e. collect resource), some extra arguments (i.e. resource type and resource count), and usually owner of the effect (i.e. player id)&lt;br /&gt;
The flow is:&lt;br /&gt;
* There is some initial player state, where player can play card for example&lt;br /&gt;
*Player main action - pushes the card effect on stack, which also can cause triggered effects which also go on stack&lt;br /&gt;
*After action processing is finished switch to game state which is &amp;quot;dispatcher&amp;quot;&lt;br /&gt;
*Dispatcher pulls the top effect (whatever definition of the top is), changes the active player and changes the state to appropriate player state to collect response. The &amp;quot;top&amp;quot; can be choice of multiple actions, in this case player has to chose one before resolving the effect.&lt;br /&gt;
*Player state knows about the stack and pulls arguments (argX) from the effect arguments of the db&lt;br /&gt;
*Player action should clear up the top effect, and can possibly add more effects, then switch to &amp;quot;dispatcher&amp;quot; state again&lt;br /&gt;
*If stack is empty, dispatcher can either pick next player itself or use another game state which responsible for picking next player&lt;br /&gt;
&lt;br /&gt;
Code can be found in Tapestry and Terraforming Mars.&lt;br /&gt;
===Custom error/exception handling in JavaScript === &lt;br /&gt;
&lt;br /&gt;
;In ggg.php&lt;br /&gt;
Throw \BgaUserException with some easy-to-identify prefix such as &amp;quot;!!!&amp;quot; and a custom error code. DO NOT TRANSLATE this message text. The exception will rollback database transaction and cancel all changes (including any notifications).&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function foo(bool $didConfirm = false): void&lt;br /&gt;
    {&lt;br /&gt;
        // do processing for the user&#039;s move&lt;br /&gt;
        // afterwards, you determine this move will end the game&lt;br /&gt;
        // so you want to rollback the transaction and require the user to confirm the move first&lt;br /&gt;
&lt;br /&gt;
        if ($gameIsEnding &amp;amp;&amp;amp; !$didConfirm) {&lt;br /&gt;
            throw new \BgaUserException(&#039;!!!endGameConfirm&#039;, 9001);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;In ggg.js&lt;br /&gt;
Override framework function showMessage to suppress the red banner message and gamelog message when you detect the &amp;quot;!!!&amp;quot; prefix&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    /* @Override */&lt;br /&gt;
    showMessage: function (msg, type) {&lt;br /&gt;
      if (type == &amp;quot;error&amp;quot; &amp;amp;&amp;amp; msg &amp;amp;&amp;amp; msg.startsWith(&amp;quot;!!!&amp;quot;)) {&lt;br /&gt;
        return; // suppress red banner and gamelog message&lt;br /&gt;
      }&lt;br /&gt;
      this.inherited(arguments);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Deal with the error in your callback:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    fooAction: function (didConfirm) {&lt;br /&gt;
      var data = {&lt;br /&gt;
        foo: &amp;quot;bar&amp;quot;,&lt;br /&gt;
        didConfirm: !!didConfirm,&lt;br /&gt;
      };&lt;br /&gt;
      this.bgaPerformAction(&amp;quot;fooAction&amp;quot;, data).catch((error, errorMsg) =&amp;gt; {&lt;br /&gt;
        if (error &amp;amp;&amp;amp; errorMsg == &amp;quot;!!!endGameConfirm&amp;quot;) {&lt;br /&gt;
          // your custom error handling goes here&lt;br /&gt;
          // for example, show a confirmation dialog and repeat the action with additional param&lt;br /&gt;
          this.confirmationDialog(&lt;br /&gt;
            _(&amp;quot;Doing the foo action now will end the game&amp;quot;),&lt;br /&gt;
            () =&amp;gt; this.fooAction(true)&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For custom global error handling, you could modify ajaxcallwrapper:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ajaxcallwrapper: function (action, args, handler) {&lt;br /&gt;
    if (!args) args = {};&lt;br /&gt;
    args.lock = true;&lt;br /&gt;
    args.version = this.gamedatas.version;&lt;br /&gt;
    if (this.checkAction(action)) {&lt;br /&gt;
      this.bgaPerformAction(&lt;br /&gt;
        action,&lt;br /&gt;
        args&lt;br /&gt;
      ).catch((error, errorMsg, errorCode) =&amp;gt; {&lt;br /&gt;
          if (error &amp;amp;&amp;amp; errorMsg == &amp;quot;!!!checkVersion&amp;quot;) {&lt;br /&gt;
            this.infoDialog(&lt;br /&gt;
              _(&amp;quot;A new version of this game is now available&amp;quot;),&lt;br /&gt;
              _(&amp;quot;Reload Required&amp;quot;),&lt;br /&gt;
              () =&amp;gt; {&lt;br /&gt;
                window.location.reload();&lt;br /&gt;
              },&lt;br /&gt;
              true&lt;br /&gt;
            );&lt;br /&gt;
          } else {&lt;br /&gt;
            if (handler) handler(error, errorMsg, errorCode);&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;
===Force players to refresh after new deploy===&lt;br /&gt;
&lt;br /&gt;
When you deploy a new version of your game, the PHP backend code is immediately updated but the JavaScript/HTML/CSS frontend code *does not update* for active players until they manually refresh the page (F5) in their browser. Obviously this is not ideal. In the best case, real-time tables don&#039;t see your shiny new enhancements. In the worst case, your old JS code isn&#039;t compatible with your new PHP code and the game breaks in strange ways (any bug reports filed will be false positives and unable to reproduce). To avoid any problems, you should force all players to immediately reload the page following a new deploy.&lt;br /&gt;
&lt;br /&gt;
By throwing a &amp;quot;visible&amp;quot; exception (simplest solution), you&#039;ll get something like this which instructs the user to reload:&lt;br /&gt;
&lt;br /&gt;
[[File:Force-refresh.png|950x950px]]&lt;br /&gt;
&lt;br /&gt;
Or, if you combine this technique with the above custom error handling technique, you could do something a bit nicer. You could show a dialog box and automatically refresh the page when the user clicks &amp;quot;OK&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Reload-required.png|500x500px]]&lt;br /&gt;
; In ggg.php&lt;br /&gt;
Transmit the server version number in &amp;lt;code&amp;gt;getAllDatas()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    protected function getAllDatas(): array&lt;br /&gt;
    {&lt;br /&gt;
        $players = $this-&amp;gt;getCollectionFromDb(&amp;quot;SELECT player_id id, player_score score FROM player&amp;quot;);&lt;br /&gt;
        return [&lt;br /&gt;
            &#039;players&#039; =&amp;gt; $players,&lt;br /&gt;
            &#039;version&#039; =&amp;gt; intval($this-&amp;gt;gamestate-&amp;gt;table_globals[300]), // &amp;lt;-- ADD HERE&lt;br /&gt;
            ...&lt;br /&gt;
        ];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Create a helper function to fail if the client and server versions mismatch. Note the version check uses &amp;lt;code&amp;gt;!=&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;&amp;amp;lt;&amp;lt;/code&amp;gt; so it can support rollback to a previous deploy as well. ;-)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function checkVersion(int $clientVersion): void&lt;br /&gt;
    {&lt;br /&gt;
        if ($clientVersion != intval($this-&amp;gt;gamestate-&amp;gt;table_globals[300])) {&lt;br /&gt;
            // Simplest way is to throw a &amp;quot;visible&amp;quot; exception&lt;br /&gt;
            // It&#039;s ugly but comes with a &amp;quot;click here&amp;quot; link to refresh&lt;br /&gt;
            throw new BgaVisibleSystemException($this-&amp;gt;_(&amp;quot;A new version of this game is now available. Please reload the page (F5).&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
            // For something prettier, throw a &amp;quot;user&amp;quot; exception and handle in JS&lt;br /&gt;
            // (see BGA cookbook section above on custom error handling)&lt;br /&gt;
            throw new \BgaUserException(&#039;!!!checkVersion&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Every action requires a parameter &amp;lt;code&amp;gt;int $version&amp;lt;/code&amp;gt; and a call to &amp;lt;code&amp;gt;$this-&amp;gt;checkVersion()&amp;lt;/code&amp;gt; as the first line. The version check should happen before anything else, even before checking if the action is allowed (since possible actions could change between versions). If you are using auto-wired &amp;quot;act&amp;quot; action functions, modify each to start like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    #[CheckAction(false)]&lt;br /&gt;
    public function actXxx(int $version, ...) {&lt;br /&gt;
        $this-&amp;gt;checkVersion($version);&lt;br /&gt;
        $this-&amp;gt;checkAction(&#039;actXxx&#039;); // or $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction(&#039;actXxx&#039;);&lt;br /&gt;
        ...&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;In ggg.js&lt;br /&gt;
Transmit the version (from gamedatas) as a parameter with every ajax call. For example, if you&#039;re already using a wrapper function for every ajax call, add it like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  ajaxcallwrapper: function (action, args) {&lt;br /&gt;
    if (!args) args = {};&lt;br /&gt;
    args.version = this.gamedatas.version; // &amp;lt;-- ADD HERE&lt;br /&gt;
    this.bgaPerformAction(action, args);&lt;br /&gt;
  },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Disable / lock table creation for new deploy===&lt;br /&gt;
&lt;br /&gt;
If you are deploying a major new game version, especially if it involves upgrading production game databases, you may have a lot of angry players if you break their tables.  Depending on your changes, you may be able to restore the previous version and fix the tables easily.&lt;br /&gt;
&lt;br /&gt;
However, if a new deploy turns out bad and players created turn-based tables while it was live, it may be quite difficult to fix those tables, since they were created from a bad deploy.&lt;br /&gt;
&lt;br /&gt;
The solution?  You can announce in your game group that you are locking table creation, and then in your new version, add an impossible startcondition to an existing option.  &lt;br /&gt;
Note: This only makes sense if you have a few games running in real time mode in the time of deployment, otherwise it won&#039;t achieve much, unless you wait at least a day for other turn based games to break (or not)&lt;br /&gt;
&lt;br /&gt;
Here is an example of an option with only 2 values (if you don&#039;t have options at all you have to create a fake option to use this method, if you have more values - you have to list them all): &lt;br /&gt;
&lt;br /&gt;
;In gameoptions.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        &amp;quot;startcondition&amp;quot;: {&lt;br /&gt;
            &amp;quot;0&amp;quot;: [ { &amp;quot;type&amp;quot;: &amp;quot;minplayers&amp;quot;, &amp;quot;value&amp;quot;: 32, &amp;quot;message&amp;quot;: &amp;quot;Maintenance in progress.  Table creation is disabled.&amp;quot; } ],&lt;br /&gt;
            &amp;quot;1&amp;quot;: [ { &amp;quot;type&amp;quot;: &amp;quot;minplayers&amp;quot;, &amp;quot;value&amp;quot;: 32, &amp;quot;message&amp;quot;: &amp;quot;Maintenance in progress.  Table creation is disabled.&amp;quot; } ]&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
;In gameoptions.inc.php (older method if you have it in php)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// TODO NEXT remove after testing deploy to upgrade, here 0 and 1 - replace with values of your option!&lt;br /&gt;
&#039;startcondition&#039; =&amp;gt; [&lt;br /&gt;
   0 =&amp;gt; [ [ &#039;type&#039; =&amp;gt; &#039;minplayers&#039;, &#039;value&#039; =&amp;gt; 32, &#039;message&#039; =&amp;gt; totranslate(&#039;Maintenance in progress.  Table creation is disabled.&#039;) ] ],&lt;br /&gt;
   1 =&amp;gt; [ [ &#039;type&#039; =&amp;gt; &#039;minplayers&#039;, &#039;value&#039; =&amp;gt; 32, &#039;message&#039; =&amp;gt; totranslate(&#039;Maintenance in progress.  Table creation is disabled.&#039;) ] ],&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Be sure to click &amp;quot;Reload game options configuration&amp;quot; after making this change, then test in studio (test that you cannot create any table)&lt;br /&gt;
* Deploy to production&lt;br /&gt;
*Now, when a player attempts to create a new table, they will see a red error bar with your &amp;quot;Maintenance in progress&amp;quot; message.&lt;br /&gt;
*Wait for screaming (if you have real times games in progress waiting 15 min probably ok, if you have only turn based games, probably a day)&lt;br /&gt;
*Once you confirm the new deploy looks good, you can revert the change in gameoptions.inc.php and do another deploy.&lt;br /&gt;
&lt;br /&gt;
===Local Storage===&lt;br /&gt;
&lt;br /&gt;
There is not much you can store in localStorage (https://developer.mozilla.org/docs/Web/API/Window/localStorage), since most stuff should be stored either in game db or in user prefrences,&lt;br /&gt;
but some stuff makes sense to store there, for example &amp;quot;zoom&amp;quot; level (if you use custom zooming). This setting really affect this specific host and specific browser, setting it localStorage makes most sense.&lt;br /&gt;
&lt;br /&gt;
game.js&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   setup: function (gamedatas) {&lt;br /&gt;
        let zoom = localStorage.getItem(`${this.game_name}_zoom`);&lt;br /&gt;
        this.setZoom(zoom);&lt;br /&gt;
...&lt;br /&gt;
   },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In this case setZoom is custom function to actually set it.&lt;br /&gt;
When zoom changed, for example when some buttons pressed, store current value (but sanitize it so it never so bad that game cannot be viewed&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    setZoom: function (zoom) {&lt;br /&gt;
      zoom = parseInt(zoom) || 0;&lt;br /&gt;
      if (zoom === 0 || zoom &amp;lt; 0.1 || zoom &amp;gt; 10) {&lt;br /&gt;
        zoom = 1;&lt;br /&gt;
      }&lt;br /&gt;
      this.zoom = zoom;&lt;br /&gt;
      localStorage.setItem(`${this.game_name}_zoom`, &amp;quot;&amp;quot; + this.zoom);&lt;br /&gt;
... do actual zooming stuff&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Capture client JavaScript errors in the &amp;quot;unexpected error&amp;quot; log===&lt;br /&gt;
&lt;br /&gt;
PHP (backend) errors are recorded in the &amp;quot;unexpected error&amp;quot; log, but JavaScript (frontend) errors are only available in the browser itself. This means you have no visibility about things that go wrong in the client... unless you make clients report their errors to the server.&lt;br /&gt;
&lt;br /&gt;
;In actions.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  public function jsError()&lt;br /&gt;
  {&lt;br /&gt;
    $this-&amp;gt;setAjaxMode(false);&lt;br /&gt;
    $this-&amp;gt;game-&amp;gt;jsError($_POST[&#039;userAgent&#039;], $_POST[&#039;msg&#039;]);&lt;br /&gt;
    $this-&amp;gt;ajaxResponse();&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt; &lt;br /&gt;
&lt;br /&gt;
; In game.php:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function jsError($userAgent, $msg): void&lt;br /&gt;
    {&lt;br /&gt;
        $this-&amp;gt;error(&amp;quot;JavaScript error from User-Agent: $userAgent\n$msg // &amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;In game.js:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&amp;quot;dojo&amp;quot;, &amp;quot;dojo/_base/declare&amp;quot;, &amp;quot;ebg/core/gamegui&amp;quot;, &amp;quot;ebg/counter&amp;quot;], function (dojo, declare) {&lt;br /&gt;
  const uniqJsError = {};&lt;br /&gt;
  ...&lt;br /&gt;
&lt;br /&gt;
  return declare(&amp;quot;bgagame.nowboarding&amp;quot;, ebg.core.gamegui, {&lt;br /&gt;
    ...&lt;br /&gt;
    /* @Override */&lt;br /&gt;
    onScriptError(msg) {&lt;br /&gt;
      if (!uniqJsError[msg]) {&lt;br /&gt;
        uniqJsError[msg] = true;&lt;br /&gt;
        console.error(&amp;quot;⛔ Reporting JavaScript error&amp;quot;, msg);&lt;br /&gt;
        this.ajaxcall(&lt;br /&gt;
          &amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + this.game_name + &amp;quot;/jsError.html&amp;quot;,&lt;br /&gt;
          {&lt;br /&gt;
            msg,&lt;br /&gt;
            userAgent: navigator.userAgent,&lt;br /&gt;
          },&lt;br /&gt;
          this,&lt;br /&gt;
          () =&amp;gt; {},&lt;br /&gt;
          () =&amp;gt; {},&lt;br /&gt;
          &amp;quot;post&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
      this.inherited(arguments);&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Algorithms ==&lt;br /&gt;
&lt;br /&gt;
===Generate permutations in lexicographic order===&lt;br /&gt;
&lt;br /&gt;
Use this when you have an array like [1, 2, 3, 4] and need to loop over some/all 24 permutations of possible ordering. This type of [https://www.php.net/manual/en/language.generators.syntax.php generator function] computes each possibility one at a time, making it vastly more efficient than either a normal iteration or recursive function that produce all possibilities up front.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function generatePermutations(array $array): Generator&lt;br /&gt;
{&lt;br /&gt;
    // https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order&lt;br /&gt;
    // Sort the array and this is the first permutation&lt;br /&gt;
    sort($array);&lt;br /&gt;
    yield $array;&lt;br /&gt;
&lt;br /&gt;
    $count = count($array);&lt;br /&gt;
    do {&lt;br /&gt;
        // Find the largest index k where a[k] &amp;lt; a[k + 1]&lt;br /&gt;
        // End when no such index exists&lt;br /&gt;
        $found = false;&lt;br /&gt;
        for ($k = $count - 2; $k &amp;gt;= 0; $k--) {&lt;br /&gt;
            $kvalue = $array[$k];&lt;br /&gt;
            $knext = $array[$k + 1];&lt;br /&gt;
            if ($kvalue &amp;lt; $knext) {&lt;br /&gt;
                // Find the largest index l greater than k where a[k] &amp;lt; a[l]&lt;br /&gt;
                for ($l = $count - 1; $l &amp;gt; $k; $l--) {&lt;br /&gt;
                    $lvalue = $array[$l];&lt;br /&gt;
                    if ($kvalue &amp;lt; $lvalue) {&lt;br /&gt;
                        // Swap a[k] and a[l]&lt;br /&gt;
                        [$array[$k], $array[$l]] = [$array[$l], $array[$k]];&lt;br /&gt;
&lt;br /&gt;
                        // Reverse the sequence from a[k + 1] up to and including the final element&lt;br /&gt;
                        $reverse = array_reverse(array_slice($array, $k + 1));&lt;br /&gt;
                        array_splice($array, $k + 1, $count, $reverse);&lt;br /&gt;
                        yield $array;&lt;br /&gt;
&lt;br /&gt;
                        // Restart with the new array to find the next permutation&lt;br /&gt;
                        $found = true;&lt;br /&gt;
                        break 2;&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    } while ($found);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$cash = [4, 1, 2, 3, 4];&lt;br /&gt;
foreach ($this-&amp;gt;generatePermutations($cash) as $p) {&lt;br /&gt;
    // your code here to evaluate permutation $p&lt;br /&gt;
    // first iteration: $p = [1, 2, 3, 4, 4]&lt;br /&gt;
    // last (60th) iteration: $p = [4, 4, 3, 2, 1]&lt;br /&gt;
    // break from loop once you achieve your goal&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=26616</id>
		<title>Game database model: dbmodel.sql</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_database_model:_dbmodel.sql&amp;diff=26616"/>
		<updated>2025-09-27T13:04:38Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: Added a section on AUTO_INCREMENT behavior.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
In this file, you specify the database schema of your game.&lt;br /&gt;
&lt;br /&gt;
This file contains SQL queries that will be executed during the creation of your game table.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; you can&#039;t change the database schema during the game.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Create your schema ==&lt;br /&gt;
&lt;br /&gt;
To build this file, we recommend you build the tables you need with the PhpMyAdmin tool (see the BGA user guide), and then export them and copy/paste the content to this file.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; the name of a column must not be the same as the name of the table, as the framework replay function relies on regexp substitution to save/restore the previous state in a clone table with another name.&lt;br /&gt;
&lt;br /&gt;
Example: Deck component, see [[Deck]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example: Euro Game. See details on database design for euro game at [[BGA_Studio_Cookbook#Database_for_The_euro_game]]&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `token` (&lt;br /&gt;
  `token_key` varchar(32) NOT NULL,&lt;br /&gt;
  `token_location` varchar(32) NOT NULL,&lt;br /&gt;
  `token_state` int(10),&lt;br /&gt;
  PRIMARY KEY (`token_key`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rules you should follow:&lt;br /&gt;
&lt;br /&gt;
* Do not overcomplicate, you are dealing with games with 50-500 pieces!&lt;br /&gt;
** If you have 5 tables for a card game with 30 cards - it is overkill&lt;br /&gt;
* The database should only be storing dynamic data, all static data should be stored in material.php.inc&lt;br /&gt;
** Example: if you have cards that have power, color, and special abilities. In the database, you only need to store the card type, all the other properties should not be there. The only exception is if it changes during the game.&lt;br /&gt;
* Columns should be permanent, independent of the game data, i.e. location, type, position, row, etc.&lt;br /&gt;
** Example: do not create columns such as Country1, Country2, Country3, etc.&lt;br /&gt;
* Do not store translatable strings in the database, use an integer number of &amp;quot;ident&amp;quot; to access properties&lt;br /&gt;
** i.e. card type should be &amp;quot;22&amp;quot; or &amp;quot;bob_cat&amp;quot;, instead of &amp;quot;Bob&#039;s cat&amp;quot;&lt;br /&gt;
* Create a separate module in PHP to handle all database queries, do a lot of type checking to prevent SQL injections&lt;br /&gt;
&lt;br /&gt;
Example of method to handle a database query:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // Set token state&lt;br /&gt;
    function setTokenState($token_key, $state) {&lt;br /&gt;
        self::checkState($state); // ensure state is number&lt;br /&gt;
        self::checkKey($token_key); // ensure key is alphanum&lt;br /&gt;
        $sql = &amp;quot;UPDATE `{$this-&amp;gt;table}`&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; SET `token_state` = &#039;$state&#039;&amp;quot;;&lt;br /&gt;
        $sql .= &amp;quot; WHERE `token_key` = &#039;$token_key&#039;&amp;quot;; // don&#039;t need to escape anymore since we checked key before&lt;br /&gt;
        self::DbQuery($sql);&lt;br /&gt;
        return $state;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Default tables ==&lt;br /&gt;
&lt;br /&gt;
By default, BGA creates four tables for your game: &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, &#039;&#039;&#039;gamelog&#039;&#039;&#039;, and &#039;&#039;&#039;player&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You &#039;&#039;&#039;MUST NOT MODIFY&#039;&#039;&#039; the schemas of the &#039;&#039;&#039;global&#039;&#039;&#039;, &#039;&#039;&#039;stats&#039;&#039;&#039;, or &#039;&#039;&#039;gamelog&#039;&#039;&#039; tables (and you must not access them directly with SQL queries in your PHP code).&lt;br /&gt;
&lt;br /&gt;
=== The &#039;&#039;&#039;player&#039;&#039;&#039; table ===&lt;br /&gt;
&lt;br /&gt;
You may add columns to the &#039;&#039;&#039;player&#039;&#039;&#039; table. It is very practical to add simple values associated with players. &#039;&#039;&#039;NB:&#039;&#039;&#039; you must not alter existing columns created by the framework.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ALTER TABLE `player` ADD `player_reserve_size` SMALLINT UNSIGNED NOT NULL DEFAULT &#039;7&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The commonly used columns of the default &amp;quot;player&amp;quot; table are:&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_no&amp;lt;/strong&amp;gt;: the index of a player in natural playing order (starting with 1)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_id&amp;lt;/strong&amp;gt; (int)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_name&amp;lt;/strong&amp;gt;: (note: it is better to access this data with the getActivePlayerName() or loadPlayersBasicInfos() methods)&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score&amp;lt;/strong&amp;gt;: the current score of a player (displayed in the player panel). You must update this field to update a player&#039;s score.&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_score_aux&amp;lt;/strong&amp;gt;: the secondary score, used as a tie breaker. You must update this field according to tie breaking rules of the game (see also: [[Main_game_logic:_yourgamename.game.php#Manage_player_scores_and_Tie_breaker|Manage_player_scores_and_Tie_breaker]])&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;strong&amp;gt;player_table_order&amp;lt;/strong&amp;gt;: gives an indication of the rank of the player by order of arrival in the lobby (starting with 1). It is not the same as player_no (which is the player order &amp;lt;u&amp;gt;within&amp;lt;/u&amp;gt; the game). player_table_order is useful for setting custom teams if desired in a game option (for instance, 1st-2nd vs 3rd-4th).&amp;lt;br/&amp;gt;&amp;lt;strong&amp;gt;Note:&amp;lt;/strong&amp;gt; player_table_order &#039;&#039;only exists during game initialization&#039;&#039; (in the &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; function). It is not added as a column in the &#039;&#039;&#039;players&#039;&#039;&#039; Db table.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strong&amp;gt;&amp;lt;u&amp;gt;CAUTION:&amp;lt;/u&amp;gt;&amp;lt;/strong&amp;gt; &#039;&#039;&#039;player_table_order&#039;&#039;&#039; is not guaranteed to be equal to the rank of the player in the table. For example, in a four-player game, if the table was full but the third player leaves before the game starts, the fourth player becomes the third on this table &amp;lt;u&amp;gt;but&amp;lt;/u&amp;gt; their player_table_no is still equal to four! If another player then joins, their player_table_no will then be 5.&amp;lt;br /&amp;gt;Thus, it is essential to normalize these values first in the game setup if you wish to use them to prevent bugs at game launch. For example, if the set of player_table_order are &amp;lt;player A&amp;gt;: 3, &amp;lt;player B&amp;gt;: 2, &amp;lt;player C&amp;gt;: 5, &amp;lt;player D&amp;gt;: 7, you see that you can&#039;t read those values as ranks directly, but you can still deduce that &amp;lt;player B&amp;gt; was first on the table, then &amp;lt;player A&amp;gt;, then &amp;lt;player C&amp;gt;, and then &amp;lt;player D&amp;gt;&amp;amp;nbsp;&amp;amp;#128521;&lt;br /&gt;
&lt;br /&gt;
See [https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Assigning_Player_Order Assigning Player Order] in the &#039;&#039;&#039;BGA Studio Cookbook&#039;&#039;&#039; for an example.&lt;br /&gt;
&lt;br /&gt;
== CREATE TABLES ==&lt;br /&gt;
You can create tables, using engine InnoDB.&lt;br /&gt;
See examples above on how to create tables.&lt;br /&gt;
Pay attention to the following:&lt;br /&gt;
* Always add IF NOT EXISTS&lt;br /&gt;
* Always set ENGINE=InnoDB DEFAULT CHARSET=utf8&lt;br /&gt;
* Define primary keys&lt;br /&gt;
* If you create NOT NULL fields after the game has gone into production, make sure you took care of the database migration&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: if you use comments, then you must not do it in the same line as the code.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
`activated` BOOL NOT NULL DEFAULT 1, --  activated or not&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
will also comment out the whole column `activated` BOOL, and that code will not be executed.&lt;br /&gt;
&lt;br /&gt;
== PHP ==&lt;br /&gt;
Database initialization should be in the function setupNewGame() in &#039;gamename.game.php&#039;.&lt;br /&gt;
&lt;br /&gt;
Database schema migration should be in the function upgradeTableDb(), see below.&lt;br /&gt;
&lt;br /&gt;
Warning: all CREATE/ALTER tables and views should be in dbmodel.sql. Do not call these queries from PHP to avoid implicit commits https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html&lt;br /&gt;
which will cause issues. The only time you can do such queries from PHP is in the upgradeTableDb() method.&lt;br /&gt;
&lt;br /&gt;
== Errors Log ==&lt;br /&gt;
To trace Database creation, check the logs that you can access in /admin/studio.&lt;br /&gt;
&lt;br /&gt;
== Post-release database modification ==&lt;br /&gt;
If you want to modify your database schema after the first release of your game to production, then you should implement the upgradeTableDb() method, see [[Post-release phase#Updating the database schema|Updating the database schema after release]]&lt;br /&gt;
&lt;br /&gt;
== Uses and misuses of AUTO_INCREMENT ==&lt;br /&gt;
&lt;br /&gt;
AUTO_INCREMENT is not particularly well-named; it&#039;s best to think of it as simply guaranteeing uniqueness of a column value. Try to design your schema and model so you don&#039;t require strictly-increasing-by-one identifiers; do not assume that the next row inserted will have a value one larger than the current maximum.&lt;br /&gt;
&lt;br /&gt;
While it does generally produce consecutive values, it does not guarantee contiguous generation (i.e. you can end up with &amp;quot;skipped&amp;quot; numbers). Technically you can even end up with later-number rows being inserted earlier (you&#039;d likely only notice or care about that if you also had a &amp;quot;creation_timestamp&amp;quot; column, though, and wanted it to be &amp;quot;in sync&amp;quot; with the auto_incremented column).&lt;br /&gt;
More details can be found [https://dev.mysql.com/doc/refman/8.4/en/innodb-auto-increment-handling.html#innodb-auto-increment-configurable here]&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Counter&amp;diff=23107</id>
		<title>Counter</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Counter&amp;diff=23107"/>
		<updated>2024-10-27T16:37:16Z</updated>

		<summary type="html">&lt;p&gt;Vagabond: Update example to avoid use of format_block(), and actually works; use getPlayerPanelElement() instead of using the overall playerboard div.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This is very simple control that allow to set/get numeric value from inner html of div/span, and provides animation on from/to value.  It is used for the built-in scoreboard element scoreCtrl.&lt;br /&gt;
&lt;br /&gt;
== Dependency ==&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to add &#039;&#039;&#039;ebg/counter&#039;&#039;&#039; as a dependency (this should be standard in the new game template):&lt;br /&gt;
&lt;br /&gt;
    // in your game js&lt;br /&gt;
    define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;    /// &amp;lt;==== HERE],&lt;br /&gt;
&lt;br /&gt;
== Setup a counter ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var counter = new ebg.counter();&lt;br /&gt;
counter.create(targetId);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &#039;&#039;&#039;targetId&#039;&#039;&#039; either string or dom element, which already exists in the template, which will be used to display the counter value.&lt;br /&gt;
For example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;span id=&amp;quot;my_counter&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In reality you will have a counter per player, so probably want to create a counter per player, in this case target Id can be &#039;hand_size_player_&#039; + player_id and you create it in the loop for all players and store as class member. See example below on how to inject per-player sections.&lt;br /&gt;
&lt;br /&gt;
== API ==&lt;br /&gt;
;create(target)&lt;br /&gt;
:associate counter with existing target DOM element&lt;br /&gt;
&lt;br /&gt;
;getValue()&lt;br /&gt;
:return current value&lt;br /&gt;
&lt;br /&gt;
;incValue(by);&lt;br /&gt;
:increment value by &amp;quot;by&amp;quot; and animate from previous value&lt;br /&gt;
&lt;br /&gt;
;setValue(value);&lt;br /&gt;
:set value, no animation&lt;br /&gt;
&lt;br /&gt;
;toValue(value);&lt;br /&gt;
:set value with animation&lt;br /&gt;
&lt;br /&gt;
;disable()&lt;br /&gt;
:Sets the value to &amp;quot;-&amp;quot;. Note it just changes display value once, it does not actually disable it, i.e. if you set it again, it will be shown again&lt;br /&gt;
&lt;br /&gt;
;speed&lt;br /&gt;
:Duration of the animation, default is 100&lt;br /&gt;
const x = new ebg.counter()&lt;br /&gt;
x.speed = 300; // to make it slower&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Typescript declaration (if you need it for ide)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
declare class Counter {&lt;br /&gt;
  speed: number; // duration of the animation, default is 100ms&lt;br /&gt;
&lt;br /&gt;
  create(target: string): void; //  associate counter with existing target DOM element&lt;br /&gt;
  getValue(): number; //  return current value&lt;br /&gt;
  incValue(by: number): number; //  increment value by &amp;quot;by&amp;quot; and animate from previous value&lt;br /&gt;
  setValue(value: number): void; //  set value, no animation&lt;br /&gt;
  toValue(value: number): void; // set value with animation&lt;br /&gt;
  disable(): void; // Sets value to &amp;quot;-&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Players panels ==&lt;br /&gt;
&lt;br /&gt;
=== Adding stuff to player&#039;s panel ===&lt;br /&gt;
&lt;br /&gt;
First, create a new JS template string function and variables to hold your counter(s) in your template (tpl) file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    stone_counters: {},&lt;br /&gt;
    jstpl_player_board: function(player) {&lt;br /&gt;
      return &lt;br /&gt;
      `&amp;lt;div class=&amp;quot;cp_board&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;div id=&amp;quot;stoneicon_p${player.player_id}&amp;quot; class=&amp;quot;gmk_stoneicon gmk_stoneicon_${player.player_color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
         &amp;lt;span id=&amp;quot;stonecount_p${player.player_id}&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;&lt;br /&gt;
       &amp;lt;/div&amp;gt;`;&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, add this piece of code in the &#039;&#039;&#039;setup&#039;&#039;&#039; function of your JS file to add this template to each player panel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            for( var player_id in gamedatas.players )   {&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                         &lt;br /&gt;
                // Setting up players boards if needed&lt;br /&gt;
                var player_board_div = this.getPlayerPanelElement(player_id);&lt;br /&gt;
                dojo.place( jstpl_player_board( player ), player_board_div );&lt;br /&gt;
&lt;br /&gt;
                // create counter per player&lt;br /&gt;
                this.stone_counters[player_id] = new ebg.counter();&lt;br /&gt;
                this.stone_counters[player_id].create( &#039;stonecount_p&#039;+player_id );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Often, you have to distinguish between the current player and other players. In this case, create another JS template (ex: jstpl_otherplayer_board) and use it where &amp;quot;player_id&amp;quot; is different than &amp;quot;this.player_id&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Vagabond</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=23106</id>
		<title>Game interface logic: Game.js</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=23106"/>
		<updated>2024-10-27T16:28:46Z</updated>

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

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