<?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=Fletcheese</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=Fletcheese"/>
	<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/Special:Contributions/Fletcheese"/>
	<updated>2026-10-23T22:09:09Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.11</generator>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Practical_debugging&amp;diff=23413</id>
		<title>Practical debugging</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Practical_debugging&amp;diff=23413"/>
		<updated>2024-12-07T17:24:56Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: /* Customizing the player id replacement */ loadBugReportSQL override not working&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page gives you practical tips to debug your game during development. Don&#039;t hesitate to share your difficulties with us so that we can improve this section.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
&lt;br /&gt;
To work on BGA Studio, we recommend that you use [http://www.google.com/chrome Google Chrome] as it&#039;s currently the fastest browser for the BGA platform, and it&#039;s available for all OSes.&lt;br /&gt;
&lt;br /&gt;
Another reason to use Chrome is that it embeds all the tools you need to work on BGA Studio. You can see them by pressing &amp;quot;F12&amp;quot; or from the menu (&amp;quot;Tools &amp;gt; Development tools&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
A good practice is to use a second browser to develop the game, in order to verify that your game is working fine on this browser too.&lt;br /&gt;
&lt;br /&gt;
To debug with Firefox browser, we advise you to use these 2 extensions:&lt;br /&gt;
* [https://addons.mozilla.org/firefox/addon/firebug/ Firebug]&lt;br /&gt;
* [https://addons.mozilla.org/firefox/addon/web-developer/ Web developer]&lt;br /&gt;
&lt;br /&gt;
To debug with other browsers (IE, Edge, Opera), we advise you to use one of the most recent versions. Latest versions of the browser will likely have better development tools than the previous ones...&lt;br /&gt;
&lt;br /&gt;
== General tip for debugging ==&lt;br /&gt;
&lt;br /&gt;
=== Save &amp;amp; Restore ===&lt;br /&gt;
&lt;br /&gt;
In general for debugging, think of using the &#039;[[Tools_and_tips_of_BGA_Studio#Save_.26_restore_state|save &amp;amp; restore]] state&#039; functionality. It enables you to save the state of your game just before the issue you are investigating, then come back to that point with one click as many times as needed to understand what is going wrong.&lt;br /&gt;
&lt;br /&gt;
You can save up to 3 different states.&lt;br /&gt;
&lt;br /&gt;
=== Refresh ===&lt;br /&gt;
&lt;br /&gt;
If something does not seems to work properly even you &amp;quot;fixed it&amp;quot;, it may be refresh issue. Not all files born equal. Some require a lot more steps to get into the game.&lt;br /&gt;
&lt;br /&gt;
See https://en.doc.boardgamearena.com/Studio_file_reference for information on how to &amp;quot;refresh&amp;quot; each files.&lt;br /&gt;
&lt;br /&gt;
== Debugging my game when it cannot start ==&lt;br /&gt;
&lt;br /&gt;
If your game won&#039;t start because of an error, you are probably in one of these situations:&lt;br /&gt;
* There is a SQL error in your dbmodel.sql file.&lt;br /&gt;
* You have a syntax error in your PHP file.&lt;br /&gt;
* Your PHP &amp;quot;setupNewGame&amp;quot; generates exception&lt;br /&gt;
* You transition to new game state from the initial state which generates exception (or state is misconfigured)&lt;br /&gt;
* You transition to player state from the initial state which has excpetion in arg* or action* method (or state is misconfigured)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If the error is not explicitly displayed when you click on &amp;quot;Express start&amp;quot;, you should check the &amp;quot;Gameserver error log&amp;quot; as per [[Studio logs]].&lt;br /&gt;
However errors and logs generated by setupNewGame not always (almost never) there, so see Debug setupNewGame session.&lt;br /&gt;
More cases of why game can&#039;t start are described on the [[Troubleshooting]] page.&lt;br /&gt;
&lt;br /&gt;
== Debugging an issue with the waiting screen ==&lt;br /&gt;
&lt;br /&gt;
BGA displays a waiting screen during a few seconds inviting free players to become premium when they are playing a lot.&lt;br /&gt;
&lt;br /&gt;
This waiting screen should not in principle impact your game, but in some cases it might.&lt;br /&gt;
&lt;br /&gt;
To test the waiting screen on the studio, you can set the desired duration by adding the get parameter studioLockingDuration with the number of seconds for the lock screen to be displayed. For example to have a 10 seconds waiting screen when you launch a game on the studio:&lt;br /&gt;
https://studio.boardgamearena.com?studioLockingDuration=10&lt;br /&gt;
&lt;br /&gt;
Then you can just set it back to zero in the same way with https://studio.boardgamearena.com?studioLockingDuration=0 (or restart your browser to clear the session value).&lt;br /&gt;
&lt;br /&gt;
== Debugging my PHP game logic (or my view) ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Add traces to your code ===&lt;br /&gt;
&lt;br /&gt;
You can use the following functions in your game to add server side logging:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$this-&amp;gt;dump( &#039;name_of_variable&#039;, $variable );&#039;&#039;&#039;  // dump variable, like var_dump but in the log debug level logging, goes to [[Studio_logs|BGA request&amp;amp;SQL logs]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$this-&amp;gt;debug( $message );&#039;&#039;&#039;  // debug level logging, goes to [[Studio_logs|BGA request&amp;amp;SQL logs]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$this-&amp;gt;trace( $message );&#039;&#039;&#039;  // info level logging, goes to [[Studio_logs|BGA request&amp;amp;SQL logs]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$this-&amp;gt;warn( $message );&#039;&#039;&#039;   // warning level logging, goes to [[Studio_logs#BGA_unexpected_exceptions_logs|BGA unexpected exceptions log]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$this-&amp;gt;error( $message );&#039;&#039;&#039;  // error level logging, goes to [[Studio_logs#BGA_unexpected_exceptions_logs|BGA unexpected exceptions log]]&lt;br /&gt;
&lt;br /&gt;
Check [[Studio logs]] for more details on how to access your logs.&lt;br /&gt;
&lt;br /&gt;
This can be useful when you need to follow the flow of your code and not just stop it to see how it goes at some point.&lt;br /&gt;
&lt;br /&gt;
Only the error log level will appear in production. This level should be used only for critical problems. &lt;br /&gt;
Other levels will show only in the development environment and can be used as you see fit.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING&#039;&#039;&#039;: tracing does not work in constructor, setupNewGame and game states immediately following starting state (not sure why). Use other method described below in this case (seciton &amp;quot;Debugging setupNewGame&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
To access logs on production, use button &amp;quot;Display recent errors from production (unexpected errors)&amp;quot; on control panel of your game&lt;br /&gt;
&lt;br /&gt;
=== Call php functions from chat ===&lt;br /&gt;
&lt;br /&gt;
This is best feature ever, you can call individual function in your game.php from chat window, see details&lt;br /&gt;
at https://en.doc.boardgamearena.com/Tools_and_tips_of_BGA_Studio#Run_PHP_functions_from_the_chat&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Dump data and die ===&lt;br /&gt;
First, make sure you can reproduce the needed game situation with one click.  Use Save (&amp;quot;[[Tools_and_tips_of_BGA_Studio#Save_.26_restore_state|save &amp;amp; restore]]&amp;quot;) function before doing some &amp;quot;test actions&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If you want to see what data looks like on some path you can simply throw this in exception, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$value = var_export($my_var, true);&lt;br /&gt;
throw new BgaUserException(&#039;I am here: &#039;.$value);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternately use json instead of php formaing:&lt;br /&gt;
    $value = json_encode($my_var, JSON_PRETTY_PRINT);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Another possibility for this is to place a &#039;&#039;&#039;die(&#039;ok&#039;)&#039;&#039;&#039; and &#039;&#039;&#039;var_dump(...)&#039;&#039;&#039; functions&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 echo &amp;quot;&amp;lt;pre&amp;gt;&amp;quot;;&lt;br /&gt;
 var_dump( $my_variable );&lt;br /&gt;
 echo &amp;quot;&amp;amp;lt;/pre&amp;gt;&amp;quot;;&lt;br /&gt;
 die(&#039;ok&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: since this text will be returned back to client it will usually choke on this, but you can actually see it better if you wrap it some html (hence the &amp;amp;lt;pre&amp;gt; tag)&lt;br /&gt;
&lt;br /&gt;
=== Debug at home ===&lt;br /&gt;
&lt;br /&gt;
If you develop some complex logic it is better sometimes to stub all external calls and debug it locally using command line or IDE debugger for php.&lt;br /&gt;
You can get some basic stubs here https://github.com/elaskavaia/bga-sharedcode/raw/master/misc/module/table/table.game.php&lt;br /&gt;
&lt;br /&gt;
To run php locally you need to wrap it into test or something, see example https://en.doc.boardgamearena.com/BGA_Studio_Cookbook#Creating_a_test_class_to_run_PHP_locally&lt;br /&gt;
&lt;br /&gt;
=== Debugging setupNewGame ===&lt;br /&gt;
&lt;br /&gt;
This is separate section because tracing method do not work in this function.&lt;br /&gt;
Recommended way to debug it &lt;br /&gt;
* leave  setupNewGame exactly as in template (inlcuding setting up player table and activating first player), and add a single call at the end&lt;br /&gt;
  $this-&amp;gt;initMyTables();&lt;br /&gt;
This will be your own function which you will be changing, so you don&#039;t touch setupNewGame anymore.&lt;br /&gt;
&lt;br /&gt;
Remember that this function cannot send notification or query active or current player. If you need to get player data use $this-&amp;gt;loadPlayersBasicInfos().&lt;br /&gt;
&lt;br /&gt;
    function initMyTables() {&lt;br /&gt;
        try {&lt;br /&gt;
           $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
          // ... code the function&lt;br /&gt;
        } catch ( Exception $e ) {&lt;br /&gt;
            // logging does not actually work in game init :(&lt;br /&gt;
            // but if you calling from php chat it will work&lt;br /&gt;
            $this-&amp;gt;error(&amp;quot;Fatal error while creating game&amp;quot;);&lt;br /&gt;
            $this-&amp;gt;dump(&#039;err&#039;, $e);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
Create a code for this function, and if it does not work run it from the chat window of the just created game (i.e. &#039;initMyTables()&#039; without quotes). That way you can see debug output!&lt;br /&gt;
The only trick is you have to clear all your tables in the begging so when you run it multiple times your db does not puke.&lt;br /&gt;
If your game does not start at all - do not even call it from setupNewGame, comment it out and only call from chat window until it works.&lt;br /&gt;
Don&#039;t forget you can also look at tables in db using php-admin tool (link at the bottom of the game table in studio).&lt;br /&gt;
&lt;br /&gt;
The same problem exists if you game state immediately follow starting state (problem of debugging it without the logs), in this case create a dummy player state in which player just press OK that will transition&lt;br /&gt;
to you game state, after you done debugging it remove the state and shortcut the transition to your game state.&lt;br /&gt;
&lt;br /&gt;
Instead of calling initMyTables directly you can call helper function instead from chat window which will also reset the client, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function debug_initMyTables() {&lt;br /&gt;
        $this-&amp;gt;deleteAllTables(); // this suppose to delete/reset all data - you have to implement this function&lt;br /&gt;
        $this-&amp;gt;initMyTables();&lt;br /&gt;
        $newGameDatas = $this-&amp;gt;getAllTableDatas(); // this is framework function&lt;br /&gt;
        $this-&amp;gt;notifyPlayer($this-&amp;gt;getActivePlayerId(), &#039;resetInterfaceWithAllDatas&#039;, &#039;&#039;, $newGameDatas); // this is notification to reset all data &lt;br /&gt;
        $this-&amp;gt;notifyAllPlayers(&amp;quot;message&amp;quot;,&#039;setup called&#039;,[]);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;HINT: This is a great suggestion. If you make any simple mistake in any code in setupNewGame, you may see &amp;quot;BGA Service Exception&amp;quot; instead of anything very useful, since setupNewGame failed. For example, even sending a bad SQL string to $this-&amp;gt;dbQuery() will generate this error. Very hard to debug!&lt;br /&gt;
&lt;br /&gt;
=== Debugging endOfGame ===&lt;br /&gt;
&lt;br /&gt;
Debugging end of game is hard if game ends! Make sure it does not end, then you can restore to previous state using saved states.&lt;br /&gt;
In php file:&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;processEndOfGame();&lt;br /&gt;
    if ($this-&amp;gt;getBgaEnvironment() == &#039;studio&#039;)&lt;br /&gt;
       $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;debuglast&#039;); // debug end&lt;br /&gt;
    else&lt;br /&gt;
       $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;last&#039;); // real end&lt;br /&gt;
&lt;br /&gt;
You have to add a special user state in states.inc.php file (note: this snippet uses php constants instead of state numbers)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        STATE_GAME_TURN_NEXT_PLAYER =&amp;gt; array( // normal state&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; &#039;&#039;,&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
                &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;st_gameTurnNextPlayer&amp;quot;,&lt;br /&gt;
                &amp;quot;updateGameProgression&amp;quot; =&amp;gt; true,&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; array(&lt;br /&gt;
                        &amp;quot;next&amp;quot; =&amp;gt; STATE_PLAYER_TURN_ACTION,&lt;br /&gt;
                        &amp;quot;loopback&amp;quot; =&amp;gt;  STATE_GAME_TURN_NEXT_PLAYER,&lt;br /&gt;
                        &amp;quot;last&amp;quot; =&amp;gt; STATE_END_GAME,&lt;br /&gt;
                        &amp;quot;debuglast&amp;quot; =&amp;gt; STATE_PLAYER_GAME_END // for debugging on studio&lt;br /&gt;
                        ), &lt;br /&gt;
        ),&lt;br /&gt;
        // for debugging end of game&lt;br /&gt;
        STATE_PLAYER_GAME_END =&amp;gt; array(&lt;br /&gt;
                &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerGameEnd&amp;quot;,&lt;br /&gt;
                &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Game Over&#039;),&lt;br /&gt;
                &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;Game Over&#039;),&lt;br /&gt;
                &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
                &amp;quot;args&amp;quot;=&amp;gt;&amp;quot;arg_playerTurnAction&amp;quot;,&lt;br /&gt;
                &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;end&amp;quot;),&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt;&lt;br /&gt;
                array(&lt;br /&gt;
                        &amp;quot;next&amp;quot; =&amp;gt; STATE_END_GAME,&lt;br /&gt;
                        &amp;quot;loopback&amp;quot;=&amp;gt; STATE_PLAYER_GAME_END)&lt;br /&gt;
        ),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Writing custom debug functions ===&lt;br /&gt;
Sometimes you want to set up a situation to debug a special case, and you need tu update the game situation to fit your test. To do this quickly without needing to play a full game and hope to get the card you want to test, you can write custom debug functions.&lt;br /&gt;
&lt;br /&gt;
For example, if I need to change the type of a card to your need, you can write a function like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function debug_setCardType(int $id, int $type, int $typeArg = 0) {&lt;br /&gt;
      $this-&amp;gt;DbQuery(&amp;quot;UPDATE card SET card_type = $type, card_type_arg = $typeArg WHERE card_id = $id&amp;quot; );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;Then you can call this function by writing in the chat (on studio only) :&amp;lt;pre&amp;gt;&lt;br /&gt;
debug_setCardType(46,2,3)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you want this debug function to be quickly accessible, you need to prefix it with &#039;&#039;&#039;debug_&#039;&#039;&#039; to make it show in the debug menu of the Studio :&lt;br /&gt;
[[File:Custom-debug-function-example.png]]&lt;br /&gt;
&lt;br /&gt;
BGA will detect methods with this prefix and the associated parameters.&lt;br /&gt;
&lt;br /&gt;
Functions with parameters will show with &amp;quot;...&amp;quot; in the debug menu and will show a popin to set the parameters. Functions without parameters will be called directly. The result in the end is the same as calling the function from the chat.&lt;br /&gt;
&lt;br /&gt;
== Debugging my HTML/CSS layout ==&lt;br /&gt;
&lt;br /&gt;
Example situations&lt;br /&gt;
&lt;br /&gt;
* Why doesn&#039;t my game element show up in the interface?&lt;br /&gt;
* Why hasn&#039;t my CSS property been applied to this element?&lt;br /&gt;
* Why is this game element displayed at this position?&lt;br /&gt;
&lt;br /&gt;
A useful tip when an element does not show up in the interface is to give it a red background:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#my_element {&lt;br /&gt;
  ... some CSS definitions ...&lt;br /&gt;
  background-color: red;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This way, you know if the element is not visible because of some CSS property or because of something else.&lt;br /&gt;
&lt;br /&gt;
Another tip: sometimes, changing a CSS property has no visible effect on your interface. In that case, add a &amp;quot;display:none&amp;quot; property. If your element does not disappear, the bug probably comes from your CSS selector and not from your CSS property.&lt;br /&gt;
&lt;br /&gt;
Using Chrome &amp;quot;Elements&amp;quot; tab (the first one), you can:&lt;br /&gt;
* See the CURRENT HTML of your page. Remember that the classical &amp;quot;show page source&amp;quot; is inefficient with BGA as you are modifying the page source with your Javascript code.&lt;br /&gt;
* Using the &amp;quot;magnifying glass&amp;quot;, you can click on any part of your game interface and check its HTML code and associated CSS styles.&lt;br /&gt;
* You can even modify directly some CSS properties and see how it looks immediately in the game interface.&lt;br /&gt;
&lt;br /&gt;
When changing css you have to force reload (Ctrl+R). But it also reloads all images which is long, if you want it faster you can click the Reload CSS button.&lt;br /&gt;
=== Debugging Toolips CSS/Layout ===&lt;br /&gt;
&lt;br /&gt;
To inspect tooltip you need to pin it so it does not disappear.&lt;br /&gt;
* Chrome tools:&lt;br /&gt;
** Open dev tools and switch to Source tab to engage with debugger&lt;br /&gt;
** Hover over you element until tooltip showing&lt;br /&gt;
** Press F8 - that stops the JS, so tooltip should freeze&lt;br /&gt;
** Now you can go to Elements tab and find your tooltip at the botton in dijitTooltip div&lt;br /&gt;
** Don&#039;t forget to resume it again to continue (F8 again or resume button)&lt;br /&gt;
* Other method: Open the console (dev tools) large enough window, hover to make the tooltip appear and alt + tab to focus the console that will cover the tooltip. That way the onmouseout will never be triggered.&lt;br /&gt;
&lt;br /&gt;
=== Debugging my Javascript game interface logic ===&lt;br /&gt;
&lt;br /&gt;
To debug javascript you just use embedded browser debugger, usually found in Source tab of dev tools (F12)&lt;br /&gt;
&lt;br /&gt;
Modern browsers also allow you to put breakpoints in your js code. It is in source tab, but its a bit difficult to find (your code that is), see picture below on how to insert breakpoints.&lt;br /&gt;
&lt;br /&gt;
You can do this by pressing Ctrl + B when your cursor is on the line where you want to set the breakpoint, or by clicking just to the left of the line number. One thing to be aware of is that refreshing via F5 removes set breakpoints, due to some cache busting values added to the URL. This can be remedied by adding this line to the end of your javascript source file, which enables the proper source mapping:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;//# sourceURL=myjsfile.js&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Bga-debug.jpg]]&lt;br /&gt;
&lt;br /&gt;
The easier method is to add breakpoint directly into your code and reload.&lt;br /&gt;
&lt;br /&gt;
In Chrome, to add a breakpoint: add a line to your .js file&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;debugger; &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Refresh the page F5, and make sure you have the Developer tools window open, press F12. &lt;br /&gt;
When the break-point is hit you can then step through your code and visualise variables, etc.&lt;br /&gt;
&lt;br /&gt;
=== Do complex things on the PHP side ===&lt;br /&gt;
&lt;br /&gt;
The most frequent case is the following: you want to compute possible moves in a game situation. Doing it in Javascript is a nightmare. Do it in PHP, and transfer the results to your client interface using the &amp;quot;args&amp;quot; game state property.&lt;br /&gt;
&lt;br /&gt;
Note: See the Reversi tutorial for an example.&lt;br /&gt;
&lt;br /&gt;
=== Add traces in your code ===&lt;br /&gt;
&lt;br /&gt;
You can use the following:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;console.log( variable_to_inspect )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It will give you the object structure of the variable in the Javascript console, without blocking the execution.&lt;br /&gt;
&lt;br /&gt;
It&#039;s often a good idea to precede this call with a console.log( &#039;### HERE ###&#039; ); to find more easily the appropriate line in the console log.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;alert( variable_to_inspect )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It will popup what you wish and pause the execution until you click ok.&lt;br /&gt;
&lt;br /&gt;
This won&#039;t be useful for complex structures; only native types will be plainly displayed. But this is sometimes useful just with messages to make sure which way the execution goes.&lt;br /&gt;
&lt;br /&gt;
== Online format checkers ==&lt;br /&gt;
Copy and paste code for a quick code sanity check like the right number of brackets.&lt;br /&gt;
&lt;br /&gt;
PHP: [https://phpcodechecker.com/ https://phpcodechecker.com/]&lt;br /&gt;
&lt;br /&gt;
JS:  [http://esprima.org/demo/validate.html http://esprima.org/demo/validate.html]&lt;br /&gt;
&lt;br /&gt;
Checks for proper attributes values and browser&#039;s compatibility&lt;br /&gt;
&lt;br /&gt;
CSS: http://jigsaw.w3.org/css-validator/&lt;br /&gt;
&lt;br /&gt;
== Some frequent errors ==&lt;br /&gt;
&lt;br /&gt;
See [[Troubleshooting]].&lt;br /&gt;
&lt;br /&gt;
== Get the database matching a bug report ==&lt;br /&gt;
&lt;br /&gt;
When a player creates a bug report in production, a snapshot of the game database is taken. You can get access to this snapshot from the studio by following the steps below:&lt;br /&gt;
* Create a table in the studio with the same game and number of players as the table for which the report has been written. Launch this table.&lt;br /&gt;
* Load the bug dump by entering the bug report ID this debug section&lt;br /&gt;
[[File:LoadBugReportInput.png]]&lt;br /&gt;
&lt;br /&gt;
=== Customizing the player id replacement ===&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;&#039;&#039;Note&#039;&#039;&#039;: as of 7 Dec 2024, this method may not actually work.  In most cases the above ootb loading should handle player_id replacement correctly. For edge cases (e.g. php serialize), DB can be fixed during getAllDatas&#039;&#039;&amp;lt;/blockquote&amp;gt;By default, the tool will replace any production player ids in the dump by the studio player ids of the created table.&lt;br /&gt;
&lt;br /&gt;
In case you want more control, setup a `loadBugReportSQL` method in your game php file (in the DebugTrait if you have one).&lt;br /&gt;
If a function with this name is detected on your game, the framework will not replace the ids, and it&#039;s up to you to change them.&lt;br /&gt;
&lt;br /&gt;
Example of `loadBugReportSQL` function:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function loadBugReportSQL(int $reportId, array $studioPlayers): void&lt;br /&gt;
    {&lt;br /&gt;
        $prodPlayers = $this-&amp;gt;getObjectListFromDb(&amp;quot;SELECT `player_id` FROM `player`&amp;quot;, true);&lt;br /&gt;
        $prodCount = count($prodPlayers);&lt;br /&gt;
        $studioCount = count($studioPlayers);&lt;br /&gt;
        if ($prodCount != $studioCount) {&lt;br /&gt;
            throw new BgaVisibleSystemException(&amp;quot;Incorrect player count (bug report has $prodCount players, studio table has $studioCount players)&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // SQL specific to your game&lt;br /&gt;
        // For example, reset the current state if it&#039;s already game over&lt;br /&gt;
        $sql = [&lt;br /&gt;
            &amp;quot;UPDATE `global` SET `global_value` = 10 WHERE `global_id` = 1 AND `global_value` = 99&amp;quot;&lt;br /&gt;
        ];&lt;br /&gt;
        foreach ($prodPlayers as $index =&amp;gt; $prodId) {&lt;br /&gt;
            $studioId = $studioPlayers[$index];&lt;br /&gt;
            // SQL common to all games&lt;br /&gt;
            $sql[] = &amp;quot;UPDATE `player` SET `player_id` = $studioId WHERE `player_id` = $prodId&amp;quot;;&lt;br /&gt;
            $sql[] = &amp;quot;UPDATE `global` SET `global_value` = $studioId WHERE `global_value` = $prodId&amp;quot;;&lt;br /&gt;
            $sql[] = &amp;quot;UPDATE `stats` SET `stats_player_id` = $studioId WHERE `stats_player_id` = $prodId&amp;quot;;&lt;br /&gt;
            $sql[] = &amp;quot;UPDATE `bga_globals` set `name` = REPLACE(`name`, &#039;$prodId&#039;, &#039;$studioId&#039;), `value` = REPLACE(`value`, &#039;$prodId&#039;, &#039;$studioId&#039;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            // SQL specific to your game&lt;br /&gt;
            $sql[] = &amp;quot;UPDATE `card` SET `card_location_arg` = $studioId WHERE `card_location_arg` = $prodId&amp;quot;;&lt;br /&gt;
            $sql[] = &amp;quot;UPDATE `my_table` SET `my_column` = REPLACE(`my_column`, &#039;$prodId&#039;, &#039;$studioId&#039;)&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        foreach ($sql as $q) {&lt;br /&gt;
            $this-&amp;gt;DbQuery($q);&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;reloadPlayersBasicInfos();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you used quietmint&#039;s `loadBugSQL` function, there are slight changes: the method name changed, and the studio players ids are plassed as method&#039;s second param, instead of computing them. &lt;br /&gt;
All other parts added in PHP/JS files for loadBug method can be removed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: If you get a &amp;quot;Not logged&amp;quot; error showing, you probably left a getCurrentPlayerId call in the `loadBugReportSQL` method.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Studio environment ==&lt;br /&gt;
&lt;br /&gt;
Some developers have requested a method allowing to know which environment the module is running on. While in general, your code should be the same on all environments so that the validation process makes sense, this may allow for example to display some helpers for testing during development while being sure that they&#039;ll never show up outside of the studio.&lt;br /&gt;
&lt;br /&gt;
From your &amp;lt;gamename&amp;gt;.game.php file you can use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if ($this-&amp;gt;getBgaEnvironment() == &#039;studio&#039;) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Or if needed from your &amp;lt;gamename&amp;gt;.view.php file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;if ($this-&amp;gt;game-&amp;gt;getBgaEnvironment() == &#039;studio&#039;) { ... }&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelplivingforest&amp;diff=22744</id>
		<title>Gamehelplivingforest</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelplivingforest&amp;diff=22744"/>
		<updated>2024-09-26T17:13:34Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Added details on what Fire Varans do&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Summary==&lt;br /&gt;
&#039;&#039;&#039;Draw phase&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Draw Guardian Animals. If you draw 3 solitary symbols [[File:Solitary1.PNG]] (top-left of the Guardian Animals cards) you cannot draw anymore (unless you&#039;ve drawn gregarious symbols). You only get to use 1 standard Action (there are ways in the next phase to get bonus Actions). If you stop at a point where you have less then 3 solitary symbols, you get to use 2 standard different Actions. Solitary symbols can be canceled by gregarious symbols [[File:Gregarious.png]]. So 3 solitary symbols - 1 gregarious symbol = 2 solitary symbols = 2 different standard Actions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Action phase&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Choose one or more of the following Actions:&lt;br /&gt;
* &#039;&#039;Take a Fragment tile&#039;&#039;: Take a Fragment tile. It can be played in a future Guardian Animal Phase to destroy a Fire Varan (fire card) or place a Guardian Animal card that you have just drawn back to your personal discard stack, regardless of its type.&lt;br /&gt;
* &#039;&#039;Attract one or more Guardian Animals&#039;&#039;: Add up the amount of suns [[File:Sun.PNG]] you have to take one or more Guardian Animal cards visible in the reserve of Guardian Animals, for a total cost equal to or lower than your number of suns. The cost of a Guardian Animal is visible in the right-bottom corner of the card.&lt;br /&gt;
* &#039;&#039;Extinguish the Fire&#039;&#039;: Add up the amount of water [[File:Water.PNG]] you have and pick one or more Fire tiles from the Circle of Spirits for a total cost equal to or lower than your number of water.&lt;br /&gt;
* &#039;&#039;Move forward on the Circle of Spirits&#039;&#039;: Add up the number of spirals [[File:Spiral.PNG]] and move your Spirit of Nature standee clockwise on the Circle of Spirits by a number of rocks equal to or lower than your number of spirals. Gain the bonus of the rock you land on (may give specific extra Action), take a Victory tile of every player you jump over.&lt;br /&gt;
* &#039;&#039;Plant one and only one Protective Tree&#039;&#039;: Add up the amount of leaves [[File:Leaf.PNG]] and take one, and only one, Protective Tree for a total cost equal to or lower than your number of leaves. By placing a Protective Tree on specific corners you gain a specific extra Action.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;End of Game turn&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It&#039;s fully automated, so you don&#039;t have to do a thing. Next turn starts after this.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Goal of the game ==&lt;br /&gt;
The winner is the player that fulfills at least one of these 3 objectives:&lt;br /&gt;
* Plant 12 &#039;&#039;&#039;different&#039;&#039;&#039; Protective Trees&lt;br /&gt;
* Collect 12 Sacred Flowers&lt;br /&gt;
* Extinguish 12 Fires&lt;br /&gt;
&lt;br /&gt;
The game stops at the end of a complete Action phase when one of the players has managed to complete one of these. If several players complete one of the three victory conditions at the end of a turn, then they add up the values of all three victory conditions. The player with the highest total wins.&lt;br /&gt;
&lt;br /&gt;
== Game turn ==&lt;br /&gt;
Each Game turn includes 3 phases:&lt;br /&gt;
&lt;br /&gt;
1. Guardian Animals (draw phase)&lt;br /&gt;
&lt;br /&gt;
2. Action(s)&lt;br /&gt;
&lt;br /&gt;
3. End of Game turn (&#039;&#039;automated in BGA&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
=== 1. Guardian Animals ===&lt;br /&gt;
During this phase, all the Spirits of Nature (= players) play at the same time.&lt;br /&gt;
&lt;br /&gt;
You draw and turn face up the Guardian Animals cards from your personal draw stack. This way you form your &#039;&#039;&#039;Guardian Animal Help Line&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
If you want to draw a new Guardian Animal card to place in your Help Line , but your draw stack runs empty, then your discard stack gets shuffled to make a new draw stack. It is when you want to draw, and not when your draw stack turns empty, that you can make a new one.&lt;br /&gt;
&lt;br /&gt;
You &#039;&#039;&#039;can&#039;&#039;&#039; stop drawing cards whenever you want. However, if you reveal a card showing a third solitary symbol [[File:Solitary1.PNG]], then you &#039;&#039;&#039;must&#039;&#039;&#039; stop drawing cards. This card closes your Help Line.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important!&#039;&#039;&#039; A gregarious symbol [[File:Gregarious.png]] cancels a solitary symbol. It will therefore be possible to play more than 3 solitary Guardian Animals in the same turn, provided that you have already revealed one or more gregarious Guardian Animals. Note that only the symbol of the solitary Guardian Animal is canceled, the Elements will be taken into account in the Action phase.&lt;br /&gt;
&lt;br /&gt;
You can find both the solitary and gregarious symbol in the top left corner of a Guardian Animals card.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Fragment tiles&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[File:Fragment.PNG]]&lt;br /&gt;
&lt;br /&gt;
Whenever you want during this phase, you can discard a Fragment tile in order to, at choice:&lt;br /&gt;
* Destroy a Fire Varan card that you have just drawn. It is put back in the Fire Varan stack.&lt;br /&gt;
* Place a Guardian Animal card that you have just drawn back to your personal discard stack, regardless of its type.&lt;br /&gt;
&lt;br /&gt;
After playing a Fragment, you can either stop or continue to draw.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Once all players have finished drawing their cards, the guardian Animals phase ends and you can move on to the Action phase.&lt;br /&gt;
&lt;br /&gt;
===2. Action Phase===&lt;br /&gt;
During this phase, the players play &#039;&#039;&#039;in turn&#039;&#039;&#039;, starting with the player possessing the Sacred Tree. At the start of the game the Sacred Tree is given to a random player. After every Game turn it is given to the next player clockwise.&lt;br /&gt;
&lt;br /&gt;
If your Help Line shows &#039;&#039;&#039;less than 3 solitary symbols&#039;&#039;&#039; (not counting the ones canceled by gregarious symbols), you can then perform &#039;&#039;&#039;2 different Actions&#039;&#039;&#039;. For example, in your Help Line are 3 solitary symbols and 1 gregarious symbol, then only 2 solitary symbols count and you get 2 Actions.&lt;br /&gt;
&lt;br /&gt;
If your Help Line shows &#039;&#039;&#039;3 solitary symbols&#039;&#039;&#039; (not canceled by gregarious symbols), you can then perform &#039;&#039;&#039;only 1 Action&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The different Actions:&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;Take a Fragment tile&#039;&#039;: Take a Fragment tile. It can be played in a future Guardian Animal Phase.&lt;br /&gt;
* &#039;&#039;Attract one or more Guardian Animals&#039;&#039;: Add up the amount of suns [[File:Sun.PNG]] you have to take one or more Guardian Animal cards visible in the reserve of Guardian Animals, for a total cost equal to or lower than your number of suns. Place the card(s) &#039;&#039;&#039;on top&#039;&#039;&#039; of your personal draw stack. The cost of a Guardian Animal is visible in the right-bottom corner of the card.&lt;br /&gt;
* &#039;&#039;Extinguish the Fire&#039;&#039;: Add up the amount of water [[File:Water.PNG]] you have and pick one or more Fire tiles from the Circle of Spirits for a total cost equal to or lower than your number of water. Reminder: having 12 Fire tiles (tiles, not the number on the Fire tile) is a way to win the game.&lt;br /&gt;
* &#039;&#039;Move forward on the Circle of Spirits&#039;&#039;: Add up the number of spirals [[File:Spiral.PNG]] and move your Spirit of Nature standee clockwise on the Circle of Spirits by a number of rocks equal to or lower than your number of spirals. &lt;br /&gt;
If one or more Spirits of Nature are on a rock ahead of you, jump over them without counting their rocks and take one of their Victory tiles of your choice, whether it originally belongs to them or was taken from another player.&lt;br /&gt;
&lt;br /&gt;
The rock you land on triggers a bonus. This an additional Action, it is added and may be different from or identical to the other Actions you take in your turn.&lt;br /&gt;
* &#039;&#039;Plant one and only one Protective Tree&#039;&#039;: Add up the amount of leaves [[File:Leaf.PNG]] and take one, and only one, Protective Tree for a total cost equal to or lower than your number of leaves. Place it in your Forest, on a space adjacent to a Protective Tree already planted. Diagonal spaces do not count. Reminder: having 12 different Protective Trees is a way to win the game.&lt;br /&gt;
By completing specific rows or columns you gain extra permanent bonuses on top of the permanent bonuses provided by the Protective Trees. You can take it into account for your second Action and in following Game turns.&lt;br /&gt;
&lt;br /&gt;
Planting a Protective Tree in a corner triggers an immediate bonus Action. This can only be used once per corner.&lt;br /&gt;
&lt;br /&gt;
===3. End of Game turn===&lt;br /&gt;
&#039;&#039;This phase is fully automated in BGA.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Stage 1: Onibi attacks!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If some Fire tiles remain at the center of the Circle of Spirits, add up their values. Then, each player adds up their value in water [[File:Water.PNG]]. If this value in water is strictly lower than the strength of the Fire, add as many Fire Varan cards to your discard stack as there are Fire tiles at the center of the Circle of Spirits.  Fire Varan cards count as solitary animals when drawn with no benefit - you do not want these.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Stage 2: Onibi is attacking the Sacred Tree&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
For each Guardian Animals card taken this turn, a Fire of a corresponding value is added to the Circle of Spirits:&lt;br /&gt;
&lt;br /&gt;
*Level 1: Fire of value 2&lt;br /&gt;
*Level 2: Fire of value 3&lt;br /&gt;
*Level 3: Fire of value 4&lt;br /&gt;
&lt;br /&gt;
There can never be more than 7 Fires in the center of the Circle of Spirits. If there are no more Fire tiles in the Circle of Spirits after stage 1, a Fire tile of value 2 is added, even if no Guardian Animals have been taken.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Stage 3: The arrival of new Guardian Animals&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The Guardian Animals reserve is refilled by revealing as many new cards per level as there were cards taken this turn.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Stage 4: The Return of Guardian Animals&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
All Guardian Animals cards from your Help Line are moved to your personal discard stack.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Stage 5: Giving the Sacred Tree&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The Sacred Tree (the starting token) is given to the next player clockwise.&lt;br /&gt;
&lt;br /&gt;
The next Game turn begins.&lt;br /&gt;
&lt;br /&gt;
== Kodama Expansion ==&lt;br /&gt;
The Kodama expansion adds a Kodama market and symbols, new trees, new guardian spirits, the Onibi standee, and new element tiles. Mainly, this expansion gives a new use for the pink flower symbol aside from the win condition. Additionally, the new win condition is set to 13, and not 12.&lt;br /&gt;
&lt;br /&gt;
=== Kodama Symbols ===&lt;br /&gt;
Each player starts with 1 card with a solitary Kodama symbol in their deck. They can get more Kodama symbol cards from the market or one of the new trees available in the expansion. During a player&#039;s Guardian Animal draw phase, the receive bonuses when they reveal a certain number of Kodama symbols.&lt;br /&gt;
&lt;br /&gt;
* 2 Kodama symbols can net you a (x) Fragment tile.&lt;br /&gt;
* 3 Kodama symbols can net you a (2Water/2Sun/2Tree) or (1Wind/1Flower) tile. Each of these tiles can only count as one of the listed element bonuses.&lt;br /&gt;
* 4 Kodama symbols can net you an additional action. This additional action cannot be the same as your other actions unless a new lvl 2 Guardian Animal Card or the 11 tree is in your play area.&lt;br /&gt;
&lt;br /&gt;
=== New Kodama Trees ===&lt;br /&gt;
Except for the tree that says +1 Kodama, the other trees are bonuses multiplied by the Kodama symbols in your Guardian Animal run. e.g. the (Kodama) Water tree counts as 3 water if you pull 3 Kodama symbols in your Guardian Animal Run.&lt;br /&gt;
&lt;br /&gt;
=== New Guardian Animals ===&lt;br /&gt;
There are 5 new lvl 2 and lvl 3 Guardian Animals in the market. The new lvl 2 animals allow you to take the action listed twice in the same turn (like the 11 tree, but temporary and specifically for one listed action.) The new lvl 3 Guardian Animals allow you to take an additional action of the listed type.&lt;br /&gt;
&lt;br /&gt;
=== Kodama Market ===&lt;br /&gt;
The Kodama market is where you can add Kodama cards to your deck, using pink flower symbols as currency. Much like buying with sun, the new Kodama card is added face down to the top of your deck. You cannot buy more than 1 Kodama card even if you have a lot of flower symbols. When a Kodama card is purchased, the new Onibi standee will go around the wind board, jumping over any players tokens. Whenever Onibi jumps a player&#039;s token, a fire 2 is added to the center. Onibi will move:&lt;br /&gt;
&lt;br /&gt;
* 3 wind spaces for a 2 player game;&lt;br /&gt;
* 2 wind spaces for a 3 player game; or&lt;br /&gt;
* 1 wind space for a 4 player game.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=21849</id>
		<title>Main game logic: Game.php</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Main_game_logic:_Game.php&amp;diff=21849"/>
		<updated>2024-07-13T18:23:25Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: /* Using player names */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
This is the main file for your game logic. Here you initialize the game, persist data, implement the rules and notify the client interface of changes.&lt;br /&gt;
&lt;br /&gt;
This is the main  class that implements the &amp;quot;server&amp;quot; callbacks. As it is a server it cannot initiate any data communicate with the game client (running in browser) and only can respond to client using notifications.&lt;br /&gt;
&lt;br /&gt;
Your php class instance won&#039;t be in memory between two callbacks, every time client send a request a new class will be created, constructor will be called and eventually your callback function.&lt;br /&gt;
&lt;br /&gt;
== File Structure ==&lt;br /&gt;
&lt;br /&gt;
The details of how the file is structured are described directly with comments in the code skeleton provided to you.&lt;br /&gt;
 &lt;br /&gt;
Here is the basic structure:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;__construct&#039;&#039;&#039;: the game constructor, where you define global variables and initiaze class members.&lt;br /&gt;
* &#039;&#039;&#039;setupNewGame&#039;&#039;&#039;: initial setup of the game. Takes an array of players, indexed by player_id. Structure of each player includes player_name, player_canal, player_avatar, and flags indicating admin/ai/premium/order/language/beginner.&lt;br /&gt;
* &#039;&#039;&#039;getAllDatas&#039;&#039;&#039;: where you retrieve all game data during a complete reload of the game. Return value must be associative array. Value of &#039;players&#039; is reserved for returning players data from players table, if you set it it must follow certain rules &lt;br /&gt;
        $result [&#039;players&#039;] = $this-&amp;gt;getCollectionFromDb(&amp;quot;SELECT player_id id, player_score score, player_no no, player_color color FROM player&amp;quot;);&lt;br /&gt;
        // Returned value must include [&#039;players&#039;][$player_id]][&#039;score&#039;] for scores to populate when F5 is pressed.&lt;br /&gt;
* &#039;&#039;&#039;getGameProgression&#039;&#039;&#039;: where you compute the game progression indicator. Returns a number indicating percent of progression (0-100). Used to calculate ELO changes of remaining players when a player quits, or as a conceding requirement (in non-tournament 2 player games, a player may concede if the progression is at least 50%).&lt;br /&gt;
* Utility functions: your utility functions.&lt;br /&gt;
* Player actions: the entry points for players actions ([https://en.doc.boardgamearena.com/Players_actions:_yourgamename.action.php more info here]). &lt;br /&gt;
* Game state arguments: methods to return additional data on specific game states ([http://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php#args more info here]).&lt;br /&gt;
* Game state actions: the logic to run when entering a new game state ([http://en.doc.boardgamearena.com/Your_game_state_machine:_states.inc.php#action more info here]).&lt;br /&gt;
* &#039;&#039;&#039;initTable&#039;&#039;&#039;: (not part of template) - this function is called for every php callback by the framework and it can be implement by the game (empty by default). You can use it in rare cases where you need to read database and manipulate some data before any ANY php entry functions are called (such as getAllDatas,action*,st*, etc). Note: it is not called before arg* methods &lt;br /&gt;
* &#039;&#039;&#039;zombieTurn&#039;&#039;&#039;: what to do it&#039;s the turn of a zombie player.&lt;br /&gt;
* &#039;&#039;&#039;upgradeTableDb&#039;&#039;&#039;: function to migrate database if you change it after release on production.&lt;br /&gt;
* &#039;&#039;&#039;getGameName&#039;&#039;&#039;: returns the game name. This will be setup when you create the project. If you are copying files in from another project, make sure you keep this function intact. It must return the right game name, or lots of things will be broken.&lt;br /&gt;
&lt;br /&gt;
== Accessing player information ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: In the following methods, be mindful of the difference between the &amp;quot;active&amp;quot; player and the &amp;quot;current&amp;quot; player. The &#039;&#039;&#039;active&#039;&#039;&#039; player is the player whose turn it is - not necessarily the player who sent a request! The &#039;&#039;&#039;current&#039;&#039;&#039; player is the player who sent the request and will see the results returned by your methods: not necessarily the player whose turn it is!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; getPlayersNumber()&lt;br /&gt;
: Returns the number of players playing at the table&lt;br /&gt;
: Note: doesn&#039;t work in the beggining of setupNewGame (use count($players) instead). It will work after initialization of player table.&lt;br /&gt;
&lt;br /&gt;
; getActivePlayerId()&lt;br /&gt;
: Get the &amp;quot;active_player&amp;quot;, whatever what is the current state type.&lt;br /&gt;
: Note: it does NOT mean that this player is active right now, because state type could be &amp;quot;game&amp;quot; or &amp;quot;multiplayer&amp;quot;&lt;br /&gt;
: Note: avoid using this method in a &amp;quot;multiplayer&amp;quot; state because it does not mean anything.&lt;br /&gt;
&lt;br /&gt;
; getActivePlayerName()&lt;br /&gt;
: Get the &amp;quot;active_player&amp;quot; name&lt;br /&gt;
: Note: avoid using this method in a &amp;quot;multiplayer&amp;quot; state because it does not mean anything.&lt;br /&gt;
&lt;br /&gt;
; getPlayerNameById($player_id)&lt;br /&gt;
: Get the name by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerColorById($player_id)&lt;br /&gt;
: Get the color by id&lt;br /&gt;
&lt;br /&gt;
; getPlayerNoById($player_id)&lt;br /&gt;
: Get &#039;player_no&#039; (number) by id&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; loadPlayersBasicInfos()&lt;br /&gt;
: Get an associative array with generic data about players (ie: not game specific data).&lt;br /&gt;
: The key of the associative array is the player id. The returned table is cached, so ok to call multiple times without performance concerns.&lt;br /&gt;
: The content of each value is:&lt;br /&gt;
: * player_name - the name of the player&lt;br /&gt;
: * player_color (ex: ff0000) - the color code of the player (as string)&lt;br /&gt;
: * player_no - the position of the player at the start of the game in natural table order, i.e. 1,2,3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
                foreach ($players as $player_id =&amp;gt; $info) {&lt;br /&gt;
                    $player_color = $info[&#039;player_color&#039;];&lt;br /&gt;
                    ...&lt;br /&gt;
                }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: if you want array of player ids only you can do this:&lt;br /&gt;
    $player_ids =  array_keys($this-&amp;gt;loadPlayersBasicInfos());  &lt;br /&gt;
&lt;br /&gt;
; getCurrentPlayerId(bool $bReturnNullIfNotLogged = false) int&lt;br /&gt;
: Get the &amp;quot;current_player&amp;quot;. The current player is the one from which the action originated (the one who sent the request).&lt;br /&gt;
: &#039;&#039;&#039;Be careful&#039;&#039;&#039;: This is not necessarily the active player!&lt;br /&gt;
: In general, you shouldn&#039;t use this method, unless you are in &amp;quot;multiplayer&amp;quot; state.&lt;br /&gt;
: &#039;&#039;&#039;Very important&#039;&#039;&#039;: in your setupNewGame and zombieTurn function, you must never use getCurrentPlayerId() or getCurrentPlayerName(), &lt;br /&gt;
: otherwise it will fail with a &amp;quot;Not logged&amp;quot; error message (these actions are triggered from the main site and propagated to the gameserver from a server, not from a browser. As a consequence, there is no current player associated to these actions).&lt;br /&gt;
&lt;br /&gt;
; getCurrentPlayerName(bool $bReturnEmptyIfNotLogged = false) string&lt;br /&gt;
: Get the &amp;quot;current_player&amp;quot; name. &lt;br /&gt;
: Note: this will throw an exception if current player is not at the table, i.e. spectator&lt;br /&gt;
: Be careful using this method (see above).&lt;br /&gt;
&lt;br /&gt;
; getCurrentPlayerColor()&lt;br /&gt;
: Get the &amp;quot;current_player&amp;quot; color. &lt;br /&gt;
: Note: this will throw an exception if current player is not at the table, i.e. spectator&lt;br /&gt;
: Be careful using this method (see above).&lt;br /&gt;
&lt;br /&gt;
; isCurrentPlayerZombie()&lt;br /&gt;
: Check the &amp;quot;current_player&amp;quot; zombie status. If true, player is zombie, i.e. left or was kicked out of the game.&lt;br /&gt;
: Note: this will throw an exception if current player is not at the table, i.e. spectator&lt;br /&gt;
&lt;br /&gt;
; isSpectator()&lt;br /&gt;
: Check the &amp;quot;current_player&amp;quot; spectator status. If true, the user accessing the game is a spectator (not part of the game). For this user, the interface should display all public information, and no private information (like a friend sitting at the same table as players and just spectating the game).&lt;br /&gt;
&lt;br /&gt;
; getActivePlayerColor()&lt;br /&gt;
: This function does not seems to exist in API, if you need it here is implementation&lt;br /&gt;
      function getActivePlayerColor() {&lt;br /&gt;
        $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
        $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        if (isset($players[$player_id]))&lt;br /&gt;
            return $players[$player_id][&#039;player_color&#039;];&lt;br /&gt;
        else&lt;br /&gt;
            return null;&lt;br /&gt;
    }&lt;br /&gt;
; isPlayerZombie($player_id)&lt;br /&gt;
: This method does not exists, but if you need it it looks like this&lt;br /&gt;
    protected function isPlayerZombie($player_id) {&lt;br /&gt;
        $players = $this-&amp;gt;loadPlayersBasicInfos();&lt;br /&gt;
        if (! isset($players[$player_id]))&lt;br /&gt;
            throw new BgaSystemException(&amp;quot;Player $player_id is not playing here&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        return ($players[$player_id][&#039;player_zombie&#039;] == 1);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Accessing the database ==&lt;br /&gt;
&lt;br /&gt;
The main game logic should be the only point from which you should access the game database. You access your database using SQL queries with the methods below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
BGA uses [http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html database transactions]. This means that your database changes WON&#039;T BE APPLIED to the database until your request ends normally (web request, not database request). Using transactions is in fact very useful for you; at any time, if your game logic detects that something is wrong (example: a disallowed move), you just have to throw an exception and all changes to the game situation will be removed. This also means that you need not (and in fact cannot) use your own transactions for multiple related database operations.&lt;br /&gt;
&lt;br /&gt;
However there are sets of database operation that will do implicit commit (most common mistake is to use &amp;quot;TRUNCATE&amp;quot;), you cannot use these operations during the game, it breaks the unrolling of transactions and will lead to nasty issues&lt;br /&gt;
(https://mariadb.com/kb/en/sql-statements-that-cause-an-implicit-commit).&lt;br /&gt;
&lt;br /&gt;
All methods below are part of game class (and view class) and can be accessed using $this-&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; DbQuery( string $sql )&lt;br /&gt;
: This is the generic method to access the database.&lt;br /&gt;
: It can execute any type of SELECT/UPDATE/DELETE/REPLACE/INSERT query on the database. Returns result of the query.&lt;br /&gt;
: For SELECT queries, the specialized methods below are much better.&lt;br /&gt;
: Do not use method for TRUNCATE, DROP and other table altering operations. See disclamer above about implicit commits. If you really need TRUNCATE use DELETE FROM xxx instead.&lt;br /&gt;
&lt;br /&gt;
; getUniqueValueFromDB( string $sql )&lt;br /&gt;
: Returns a unique value from DB or null if no value is found.&lt;br /&gt;
: $sql must be a SELECT query.&lt;br /&gt;
: Raise an exception if more than 1 row is returned.&lt;br /&gt;
&lt;br /&gt;
; getCollectionFromDB( string $sql, bool $bSingleValue=false ) array&lt;br /&gt;
: Returns an associative array of rows for a sql SELECT query.&lt;br /&gt;
: The key of the resulting associative array is the first field specified in the SELECT query.&lt;br /&gt;
: The value of the resulting associative array is an associative array with all the field specified in the SELECT query and associated values.&lt;br /&gt;
: First column must be a primary or alternate key (semantically, it does not actually have to declared in sql as such).&lt;br /&gt;
: The resulting collection can be empty (it won&#039;t be null).&lt;br /&gt;
: If you specified $bSingleValue=true and if your SQL query requests 2 fields A and B, the method returns an associative array &amp;quot;A=&amp;gt;B&amp;quot;, otherwise its A=&amp;gt;[A,B]&lt;br /&gt;
: Note: The name a bit misleading, it really return associative array, i.e. map and NOT a collection. You cannot use it to get list of values which may have duplicates (hence primary key requirement on first column). If you need simple array use getObjectListFromDB() method.&lt;br /&gt;
&lt;br /&gt;
Example 1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$result = $this-&amp;gt;getCollectionFromDB( &amp;quot;SELECT player_id id, player_name name, player_score score FROM player&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
[&lt;br /&gt;
 1234 =&amp;gt; [ &#039;id&#039;=&amp;gt;1234, &#039;name&#039;=&amp;gt;&#039;myuser0&#039;, &#039;score&#039;=&amp;gt;1 ],&lt;br /&gt;
 1235 =&amp;gt; [ &#039;id&#039;=&amp;gt;1235, &#039;name&#039;=&amp;gt;&#039;myuser1&#039;, &#039;score&#039;=&amp;gt;0 ]&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example 2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$result = $this-&amp;gt;getCollectionFromDB( &amp;quot;SELECT player_id id, player_name name FROM player&amp;quot;, true );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
[&lt;br /&gt;
 1234 =&amp;gt; &#039;myuser0&#039;,&lt;br /&gt;
 1235 =&amp;gt; &#039;myuser1&#039;&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; getNonEmptyCollectionFromDB(string $sql) array&lt;br /&gt;
: Same as getCollectionFromDB($sdl), but raise an exception if the collection is empty. Note: this function does NOT have 2nd argument as previous one does.&lt;br /&gt;
&lt;br /&gt;
; getObjectFromDB(string $sql) array&lt;br /&gt;
: Returns one row for the sql SELECT query as an associative array or null if there is no result (where fields are keys mapped to values)&lt;br /&gt;
: Raise an exception if the query return more than one row (you can use LIMIT 1 in the query to avoid the exception)&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$result = $this-&amp;gt;getObjectFromDB( &amp;quot;SELECT player_id id, player_name name, player_score score FROM player WHERE player_id=&#039;$player_id&#039;&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
[&lt;br /&gt;
  &#039;id&#039;=&amp;gt;1234, &#039;name&#039;=&amp;gt;&#039;myuser0&#039;, &#039;score&#039;=&amp;gt;1 &lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; getNonEmptyObjectFromDB(string $sql) array&lt;br /&gt;
: Similar to previous one, but raise an exception if no row is found&lt;br /&gt;
&lt;br /&gt;
; getObjectListFromDB(string $sql, bool $bUniqueValue=false) array&lt;br /&gt;
: Return an array of rows for a sql SELECT query.&lt;br /&gt;
: The result is the same as &amp;quot;getCollectionFromDB&amp;quot; except that the result is a simple array (and not an associative array).&lt;br /&gt;
: The result can be empty.&lt;br /&gt;
: If you specified $bUniqueValue=true and if your SQL query request 1 field, the method returns directly an array of values.&lt;br /&gt;
&lt;br /&gt;
Example 1:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$result = $this-&amp;gt;getObjectListFromDB( &amp;quot;SELECT player_id id, player_name name, player_score score FROM player&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
[&lt;br /&gt;
 [ &#039;id&#039;=&amp;gt;1234, &#039;name&#039;=&amp;gt;&#039;myuser0&#039;, &#039;score&#039;=&amp;gt;1 ],&lt;br /&gt;
 [ &#039;id&#039;=&amp;gt;1235, &#039;name&#039;=&amp;gt;&#039;myuser1&#039;, &#039;score&#039;=&amp;gt;0 ]&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example 2:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$result = $this-&amp;gt;getObjectListFromDB( &amp;quot;SELECT player_name name FROM player&amp;quot;, true );&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
[&lt;br /&gt;
 &#039;myuser0&#039;,&lt;br /&gt;
 &#039;myuser1&#039;&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; getDoubleKeyCollectionFromDB(string $sql, bool $bSingleValue=false) array&lt;br /&gt;
: Return an associative array of associative array, from a SQL SELECT query.&lt;br /&gt;
: First array level correspond to first column specified in SQL query.&lt;br /&gt;
: Second array level correspond to second column specified in SQL query.&lt;br /&gt;
: If $bSingleValue = true, keep only third column on result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; DbGetLastId()&lt;br /&gt;
: Return the PRIMARY key of the last inserted row (see PHP mysql_insert_id function).&lt;br /&gt;
&lt;br /&gt;
; DbAffectedRow() int&lt;br /&gt;
: Return the number of row affected by the last operation&lt;br /&gt;
&lt;br /&gt;
; escapeStringForDB(string $string) string&lt;br /&gt;
: You must use this function on every string type data in your database that contains unsafe data.&lt;br /&gt;
: (unsafe = can be modified by a player).&lt;br /&gt;
: This method makes sure that no SQL injection will be done through the string used.&lt;br /&gt;
: Note: if you using standard types in ajax actions, like AT_alphanum it is sanitized before arrival,&lt;br /&gt;
: this is only needed if you manage to get unchecked string, like in the games where user has to enter text as a response.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: see Editing [[Game database model: dbmodel.sql]] to know how to define your database model.&lt;br /&gt;
&lt;br /&gt;
== Use globals ==&lt;br /&gt;
&lt;br /&gt;
Sometimes, you want a single global integer value for your game, and you don&#039;t want to create a DB table specifically for it.&lt;br /&gt;
&lt;br /&gt;
You can do this with the BGA framework &amp;quot;global&amp;quot;. Your value will be stored in the &amp;quot;global&amp;quot; table in the database, and you can access it with simple methods.&lt;br /&gt;
&lt;br /&gt;
All methods below are members of the game class and should be accessed via $this-&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;initGameStateLabels(array $labelsMap): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method should be located at the beginning of constructor of &#039;&#039;yourgamename.game.php&#039;&#039;. This is where you define the globals used in your game logic, by assigning them IDs.&lt;br /&gt;
&lt;br /&gt;
You can define up to 80 globals, with IDs from 10 to 89 (inclusive, there can be gaps). &lt;br /&gt;
Also you must use this method to access value of game options [[Game_options_and_preferences:_gameoptions.inc.php]], in that case, IDs need to be between 100 and 199.&lt;br /&gt;
You must &#039;&#039;&#039;not&#039;&#039;&#039; use globals outside the range defined above, as those values are used by other components of the framework.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   function __construct() {&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        $this-&amp;gt;initGameStateLabels([ &lt;br /&gt;
                &amp;quot;my_first_global_variable&amp;quot; =&amp;gt; 10,&lt;br /&gt;
                &amp;quot;my_second_global_variable&amp;quot; =&amp;gt; 11,&lt;br /&gt;
                &amp;quot;my_game_variant&amp;quot; =&amp;gt; 100&lt;br /&gt;
        ]);&lt;br /&gt;
         // other code ...&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
NOTE: The methods below WILL throw an exception if label is not defined using the call above.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setGameStateInitialValue( string $label, int $value ): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Initialize global value. This is not required if you ok with default value if 0. This should be called from setupNewGame function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getGameStateValue( string $label, int $default = 0): int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Retrieve the value of a global. Returns $default if global is not been initialized (by setGameStateInitialValue).&lt;br /&gt;
&lt;br /&gt;
NOTE: this method use globals &amp;quot;cache&amp;quot; if you directly manipulated globals table OR call this function after undoRestorePoint() - it won&#039;t work as expected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $value = $this-&amp;gt;getGameStateValue(&#039;my_first_global_variable&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For debugging purposes, you can have labels and value pairs send to client side by inserting that code in your &amp;quot;getAllDatas&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$labels = array_keys($this-&amp;gt;mygamestatelabels);&lt;br /&gt;
$result[&#039;myglobals&#039;] = array_combine($labels, array_map([$this,&#039;getGameStateValue&#039;],$labels));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That assumes you stored your label mapping in $this-&amp;gt;mygamestatelabels in constructor&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;mygamestatelabels=[&amp;quot;my_first_global_variable&amp;quot; =&amp;gt; 10, ...];&lt;br /&gt;
  $this-&amp;gt;initGameStateLabels($this-&amp;gt;mygamestatelabels);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setGameStateValue( string $label, int $value ): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Set the current value of a global. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $this-&amp;gt;setGameStateValue(&#039;my_first_global_variable&#039;, 42);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;incGameStateValue( string $label, int $increment ): int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Increment the current value of a global. If increment is negative, decrement the value of the global.&lt;br /&gt;
&lt;br /&gt;
Return the final value of the global. If global was not initialized it will initialize it as 0.&lt;br /&gt;
&lt;br /&gt;
NOTE: this method use globals &amp;quot;cache&amp;quot; if you directly manipulated globals table OR call this function after undoRestorePoint() - it won&#039;t work as expected.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  $value = $this-&amp;gt;incGameStateValue(&#039;my_first_global_variable&#039;, 1);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== BGA predefined globals ===&lt;br /&gt;
&lt;br /&gt;
BGA already defines some globals in the &#039;&#039;global&#039;&#039; database table. You should not change them directly but it can be useful to know what they mean when debugging:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! global_id !! label !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || || Current state &lt;br /&gt;
|-&lt;br /&gt;
| 2 || || Active player id&lt;br /&gt;
|-&lt;br /&gt;
| 3 || next_move_id || Next move number&lt;br /&gt;
|-&lt;br /&gt;
| 4 ||  || Game id&lt;br /&gt;
|-&lt;br /&gt;
| 5 ||  || Table creator id&lt;br /&gt;
|-&lt;br /&gt;
| 6 || playerturn_nbr || Player turn number&lt;br /&gt;
|-&lt;br /&gt;
| 7 || gameprogression || Game progression&lt;br /&gt;
|-&lt;br /&gt;
| 8 || initial_reflexion_time || Initial reflection time&lt;br /&gt;
|-&lt;br /&gt;
| 9 || additional_reflexion_time || Additional reflection time&lt;br /&gt;
|-&lt;br /&gt;
| 200 || reflexion_time_profile || Reflexion time profile&lt;br /&gt;
|-&lt;br /&gt;
| 201 || bgaranking_mode ||  BGA ranking mode&lt;br /&gt;
|-&lt;br /&gt;
| 207 || game_language ||GAMESTATE_GAME_LANG&lt;br /&gt;
|-&lt;br /&gt;
| 300 || game_db_version ||GAMESTATE_GAMEVERSION: Current version of the game (when in production)&lt;br /&gt;
|-&lt;br /&gt;
| 301 || game_result_neutralized ||GAMESTATE_GAME_RESULT_NEUTRALIZED&lt;br /&gt;
|-&lt;br /&gt;
| 302 || neutralized_player_id ||GAMESTATE_NEUTRALIZED_PLAYER_ID&lt;br /&gt;
|-&lt;br /&gt;
| 304 || undo_moves_stored ||GAMESTATE_UNDO_MOVES_STORED&lt;br /&gt;
|-&lt;br /&gt;
| 305 || undo_moves_player ||GAMESTATE_UNDO_MOVES_PLAYER&lt;br /&gt;
|-&lt;br /&gt;
| 306 || lock_screen_timestamp ||GAMESTATE_LOCK_TIMESTAMP&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Game states and active players ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Activate player handling ===&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;activeNextPlayer()&lt;br /&gt;
: Make the next player active in the natural player order.&lt;br /&gt;
: Note: you CANNOT use this method in a &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot; state. You must use a &amp;quot;game&amp;quot; type game state for this.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;activePrevPlayer()&lt;br /&gt;
: Make the previous player active (in the natural player order).&lt;br /&gt;
: Note: you CANNOT use this method in a &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot; state. You must use a &amp;quot;game&amp;quot; type game state for this.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer( $player_id )&lt;br /&gt;
: You can call this method to make any player active.&lt;br /&gt;
: Note: you CANNOT use this method in a &amp;quot;activeplayer&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot; state. You must use a &amp;quot;game&amp;quot; type game state for this.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;getActivePlayerId()&lt;br /&gt;
: Return the &amp;quot;active_player&amp;quot; id&lt;br /&gt;
: Note: it does NOT mean that this player is active right now, because state type could be &amp;quot;game&amp;quot; or &amp;quot;multipleactiveplayer&amp;quot;&lt;br /&gt;
: Note: avoid using this method in a &amp;quot;multipleactiveplayer&amp;quot; state because it does not mean anything.&lt;br /&gt;
&lt;br /&gt;
=== Multiple activate player handling ===&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive()&lt;br /&gt;
: All playing players are made active. Update notification is sent to all players (this will trigger &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039;).&lt;br /&gt;
: Usually, you use this method at the beginning of a game state (e.g., &amp;quot;stGameState&amp;quot;) which transitions to a &#039;&#039;multipleactiveplayer&#039;&#039; state in which multiple players have to perform some action. Do not use this method if you going to make some more changes in the active player list. (I.e., if you want to take away multipleactiveplayer status immediately afterwards, use setPlayersMultiactive instead.)&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_MultiPlayerInit() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;stMakeEveryoneActive()&lt;br /&gt;
:this method can be used in state machine to make everybody active as &amp;quot;st&amp;quot; method of multiplayeractive state, it just calls $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive()&lt;br /&gt;
&lt;br /&gt;
This is to be used in state declaration:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
    		&amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurnPlace&amp;quot;,&lt;br /&gt;
    		&amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Other player must place ships&#039;),&lt;br /&gt;
    		&amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must place ships (click on YOUR SHIPS board to place)&#039;),&lt;br /&gt;
    		&amp;quot;type&amp;quot; =&amp;gt; &amp;quot;multipleactiveplayer&amp;quot;,&lt;br /&gt;
                &#039;action&#039; =&amp;gt; &#039;stMakeEveryoneActive&#039;,&lt;br /&gt;
                &#039;args&#039; =&amp;gt; &#039;arg_playerTurnPlace&#039;,&lt;br /&gt;
    	     	&amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;actionBla&amp;quot; ),&lt;br /&gt;
                &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;next&amp;quot; =&amp;gt; 4, &amp;quot;last&amp;quot; =&amp;gt; 99)&lt;br /&gt;
    ),&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setAllPlayersNonMultiactive( $next_state )&lt;br /&gt;
: All playing players are made inactive. Transition to next state&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive( $players, $next_state, $bExclusive = false )&lt;br /&gt;
: Make a specific list of players active during a multiactive gamestate. Update notification is sent to all players whose state changed.&lt;br /&gt;
: &amp;quot;players&amp;quot; is the array of player id that should be made active. If &amp;quot;players&amp;quot; is not empty the value of &amp;quot;next_state&amp;quot; will be ignored (you can put whatever you want)&lt;br /&gt;
: If &amp;quot;bExclusive&amp;quot; parameter is not set or false it doesn&#039;t deactivate other previously active players. If its set to true, the players who will be multiactive at the end are only these in &amp;quot;$players&amp;quot; array&lt;br /&gt;
&lt;br /&gt;
: In case &amp;quot;players&amp;quot; is empty, the method trigger the &amp;quot;next_state&amp;quot; transition to go to the next game state.&lt;br /&gt;
: returns true if state transition happened, false otherwise&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive( $player_id, $next_state )&lt;br /&gt;
: During a multiactive game state, make the specified player inactive.&lt;br /&gt;
: Usually, you call this method during a multiactive game state after a player did his action. It is also possible to call it directly from multiplayer action handler.&lt;br /&gt;
: If this player was the last active player, the method trigger the &amp;quot;next_state&amp;quot; transition to go to the next game state.&lt;br /&gt;
: returns true if state transition happened, false otherwise&lt;br /&gt;
Example of usage (see state declaration of playerTurnPlace above):&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function actionBla($args) {&lt;br /&gt;
        $this-&amp;gt;checkAction(&#039;actionBla&#039;);&lt;br /&gt;
        // handle the action using $this-&amp;gt;getCurrentPlayerId()&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive( $this-&amp;gt;getCurrentPlayerId(), &#039;next&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;getActivePlayerList()&lt;br /&gt;
: With this method you can retrieve the list of the active player at any time.&lt;br /&gt;
: During a &amp;quot;game&amp;quot; type gamestate, it will return a void array.&lt;br /&gt;
: During a &amp;quot;activeplayer&amp;quot; type gamestate, it will return an array with one value (the active player id).&lt;br /&gt;
: During a &amp;quot;multipleactiveplayer&amp;quot; type gamestate, it will return an array of the active players id.&lt;br /&gt;
: Note: you should only use this method in the latter case.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;  $this-&amp;gt;gamestate-&amp;gt;updateMultiactiveOrNextState( $next_state_if_none )&lt;br /&gt;
: Sends update notification about multiplayer changes. All multiactive set* functions above do that, however if you want to change state manually using db queries for complex calculations, you have to call this yourself after. Do not call this if you calling one of the other setters above.&lt;br /&gt;
Example: you have player teams and you want to activate all players in one team&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $sql = &amp;quot;UPDATE player SET player_is_multiactive=&#039;0&#039;&amp;quot;;&lt;br /&gt;
        $this-&amp;gt;DbQuery( $sql );&lt;br /&gt;
        $sql = &amp;quot;UPDATE player SET player_is_multiactive=&#039;1&#039; WHERE player_id=&#039;$player_id&#039; AND player_team=&#039;$team_no&#039;&amp;quot;;&lt;br /&gt;
        $this-&amp;gt;DbQuery( $sql );&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;updateMultiactiveOrNextState( &#039;error&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; updating database manually&lt;br /&gt;
: Use this helper function to change multiactive state without sending notification&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Changes values of multiactivity in db, does not sent notifications.&lt;br /&gt;
     * To send notifications after use updateMultiactiveOrNextState&lt;br /&gt;
     * @param number $player_id, player id &amp;lt;=0 or null - means ALL&lt;br /&gt;
     * @param number $value - 1 multiactive, 0 non multiactive&lt;br /&gt;
     */&lt;br /&gt;
    function dbSetPlayerMultiactive($player_id = -1, $value = 1) {&lt;br /&gt;
        if (! $value)&lt;br /&gt;
            $value = 0;&lt;br /&gt;
        else&lt;br /&gt;
            $value = 1;&lt;br /&gt;
        $sql = &amp;quot;UPDATE player SET player_is_multiactive = &#039;$value&#039; WHERE player_zombie = 0 and player_eliminated = 0&amp;quot;;&lt;br /&gt;
        if ($player_id &amp;gt; 0) {&lt;br /&gt;
            $sql .= &amp;quot; AND player_id = $player_id&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
        $this-&amp;gt;DbQuery($sql);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;$this-&amp;gt;gamestate-&amp;gt;isPlayerActive($player_id)&lt;br /&gt;
:Return true if specified player is active right now.&lt;br /&gt;
:This method take into account game state type, ie nobody is active if game state is &amp;quot;game&amp;quot; and several players can be active if game state is &amp;quot;multiplayer&amp;quot;&lt;br /&gt;
&lt;br /&gt;
;$this-&amp;gt;bIndependantMultiactiveTable&lt;br /&gt;
:This flag can be set to true in constructor of game.php to force creation of second table to handle multiplayer states (normally these are in player table), this is very advanced feature.&lt;br /&gt;
:ONLY use it after you deploy you game to production if you receive unusual amount of bug report with dead lock symptoms DURING multiactiveplayer states&lt;br /&gt;
    function __construct() {&lt;br /&gt;
      ...&lt;br /&gt;
      $this-&amp;gt;bIndependantMultiactiveTable=true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
=== States functions ===&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextState( $transition )&lt;br /&gt;
: Change current state to a new state. Important: the $transition parameter is the name of the transition, and NOT the name of the target game state, see [[Your game state machine: states.inc.php]] for more information about states.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$this-&amp;gt;gamestate-&amp;gt;jumpToState($stateNum)&#039;&#039;&#039;&lt;br /&gt;
: Change current state to a new state. Important: the $stateNum parameter is the key of the state. See [[Your game state machine: states.inc.php]] for more information about states.&lt;br /&gt;
: Note: this is very advanced method, it should not be used in normal cases. Specific advanced cases include - jumping to specific state from &amp;quot;do_anytime&amp;quot; actions, jumping to dispatcher state or jumping to recovery state from zombie player function&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;checkAction( $actionName, $bThrowException=true )&lt;br /&gt;
: Check if the current player can perform a specific action in the current game state, and optionally throw an exception if they can&#039;t.&lt;br /&gt;
: The action is valid if it is listed in the &amp;quot;possibleactions&amp;quot; array for the current game state (see game state description).&lt;br /&gt;
: This method MUST be the first one called in ALL your PHP methods that handle player actions, in order to make sure a player doesn&#039;t perform an action not allowed by the rules at the point in the game.  It should not be called from methods where the current player is not necessarily the active player, otherwise it may fail with an &amp;quot;It is not your turn&amp;quot; exception.&lt;br /&gt;
: If &amp;quot;bThrowException&amp;quot; is set to &amp;quot;false&amp;quot;, the function returns &#039;&#039;&#039;false&#039;&#039;&#039; in case of failure instead of throwing an exception. This is useful when several actions are possible, in order to test each of them without throwing exceptions.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction( $action )&lt;br /&gt;
: (rarely used)&lt;br /&gt;
: This works exactly like &amp;quot;checkAction&amp;quot; (above), except that it does NOT check if the current player is active.&lt;br /&gt;
: &#039;&#039;&#039;Note: This does NOT check either spectator or eliminated status, so those checks must be done manually.&#039;&#039;&#039;&lt;br /&gt;
: This is used specifically in certain game states when you want to authorize additional actions for players that are not active at the moment.&lt;br /&gt;
: Example: in &#039;&#039;Libertalia&#039;&#039;, you want to authorize players to change their mind about the card played. They are of course not active at the time they change their mind, so you cannot use &amp;quot;checkAction&amp;quot;; use &amp;quot;checkPossibleAction&amp;quot; instead.&lt;br /&gt;
&lt;br /&gt;
This is how PHP action looks that returns player to active state (only for multiplayeractive states). To be able to execute this on client do not call checkAction on js side for this specific action.&lt;br /&gt;
&lt;br /&gt;
   function actionUnpass() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;checkPossibleAction(&#039;actUnpass&#039;); // player changed mind about passing while others were thinking&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive(array ($this-&amp;gt;getCurrentPlayerId() ), &#039;error&#039;, false);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;state()&lt;br /&gt;
: Get an associative array of current game state attributes, see [[Your game state machine: states.inc.php]] for state attributes.&lt;br /&gt;
&lt;br /&gt;
  $state=$this-&amp;gt;gamestate-&amp;gt;state(); if( $state[&#039;name&#039;] == &#039;myGameState&#039; ) {...}&lt;br /&gt;
&lt;br /&gt;
I suggest to define and use this function in your php class to access state name:&lt;br /&gt;
&lt;br /&gt;
    public function getStateName() {&lt;br /&gt;
        $state = $this-&amp;gt;gamestate-&amp;gt;state();&lt;br /&gt;
        return $state[&#039;name&#039;];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;state_id()&lt;br /&gt;
: Get the id of the current game state (rarely useful, its best to use name, unless you use constants for state ids)&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;isMutiactiveState()&lt;br /&gt;
: Return true if we are in multipleactiveplayer state, false otherwise&lt;br /&gt;
&lt;br /&gt;
=== Private parallel states ===&lt;br /&gt;
&lt;br /&gt;
See the overview of private parallel states [[Your_game_state_machine:_states.inc.php#Private_parallel_states|here]].&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers()&lt;br /&gt;
: All active players in a multiactive state are entering a first private state defined in the master state&#039;s initialprivate parameter.&lt;br /&gt;
: Every time you need to start a private parallel states you need to call this or similar methods below.&lt;br /&gt;
: Note: at least one player needs to be active (see [[#Multiple_activate_player_handling|above]]) and current game state must be a multiactive state with initialprivate parameter defined&lt;br /&gt;
: Note: initialprivate parameter of master state should be set to the id of the first private state. This private state needs to be defined in states.php with the type set to &#039;private&#039;.&lt;br /&gt;
: Note: this method is usually preceded with activating some or all players&lt;br /&gt;
: Note: initializing private state can run action or args methods of the initial private state&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function stStartPlayerTurn() {&lt;br /&gt;
        // This is usually done in master state action method&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers();&lt;br /&gt;
&lt;br /&gt;
        // in some cases you can move immediately some or all players to different private states&lt;br /&gt;
        if ($someCondition) {&lt;br /&gt;
            //move all players to different state &lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers(&amp;quot;some_transition&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($other condition) {&lt;br /&gt;
            //move single player to different state&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($specificPlayerId, &amp;quot;some_transition&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForPlayers($playerIds)&lt;br /&gt;
: Players with specified ids are entering a first private state defined in the master state initialprivate parameter.&lt;br /&gt;
: Same considerations apply as for the method above.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;initializePrivateState($playerId)&lt;br /&gt;
: Player with the specified id is entering a first private state defined in the master state initialprivate parameter.&lt;br /&gt;
: Everytime you need to start a private parallel states you need to call this or similar methods above&lt;br /&gt;
: Note: player needs to be active (see [[#Multiple_activate_player_handling|above]]) and current game state must be a multiactive state with initialprivate parameter defined&lt;br /&gt;
: Note: initialprivate parameter of master state should be set to the id of the first private state. This private state needs to be defined in states.php with the type set to &#039;private&#039;.&lt;br /&gt;
: Note: this method is usually preceded with activating that player&lt;br /&gt;
: Note: initializing private state can run action or args methods of the initial private state&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function st_ChangeMind() {&lt;br /&gt;
        // This player finished his move before, but now decides change something while other players are still active&lt;br /&gt;
        // We activate the player and initialize his private state&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayersMultiactive([$this-&amp;gt;getCurrentPlayerId()], &amp;quot;&amp;quot;);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateState(this-&amp;gt;getCurrentPlayerId());&lt;br /&gt;
&lt;br /&gt;
        // It is also possible to move the player to some other specific state immediately&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;some_transition&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers($transition)&lt;br /&gt;
: All active players will transition to next private state by specified transition&lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: transition should lead to another private state (i.e. a state with type defined as &#039;private&#039;&lt;br /&gt;
: Note: transition should be defined in private state in which the players currently are. &lt;br /&gt;
: Note: this method can run action or args methods of the target state&lt;br /&gt;
: Note: this is usually used after initializing the private state to move players to specific private state according to the game logic&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function stStartPlayerTurn() {&lt;br /&gt;
        // This is usually done in master state action method&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setAllPlayersMultiactive();&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;initializePrivateStateForAllActivePlayers();&lt;br /&gt;
&lt;br /&gt;
        if ($specificOption) {&lt;br /&gt;
            //move all players to different state &lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForAllActivePlayers(&amp;quot;some_transition&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextPrivateStateForPlayers($playerIds, $transition)&lt;br /&gt;
: Players with specified ids will transition to next private state specified by provided transition.&lt;br /&gt;
: Same considerations apply as for the method above.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($playerId, $transition)&lt;br /&gt;
: Player with specified id will transition to next private state specified by provided transition&lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: transition should lead to another private state (i.e. a state with type defined as &#039;private&#039;&lt;br /&gt;
: Note: transition should be defined in private state in which the players currently are. &lt;br /&gt;
: Note: this method can run action or args methods of the target state for specified player&lt;br /&gt;
: Note: this is usually used after some player actions to move to next private state&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function actSomeAction() {&lt;br /&gt;
        $this-&amp;gt;checkAction(&amp;quot;actSomeAction&amp;quot;); //needs to be defined in the current state&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;some_transition&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;unsetPrivateStateForAllPlayers()&lt;br /&gt;
: All players private state will be reset to null, which means they will get out of private parallel states and be in a master state like the private states are not used &lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: this is usually used to clean up after leaving a master state in which private states were used, but can be used in other cases when we want to exit private parallel states and use a regular multiactive state for all players&lt;br /&gt;
: Note: After unseting private state only actions on master state are possible&lt;br /&gt;
: Note: Usually it is not necessary to unset private states as they will be initialized to first private state when private states are needed again. Nevertheless it is generally better to clean private state after exiting private parallel states to avoid bugs. &lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function stNextRound() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;unsetPrivateStateForAllPlayers();&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;unsetPrivateStateForPlayers($playerIds, $transition)&lt;br /&gt;
: For players with specified ids private state will be reset to null, which means they will get out of private parallel states and be in a master state like the private states are not used.&lt;br /&gt;
: Same considerations apply as for the method above.&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;unsetPrivateState($playerId)&lt;br /&gt;
: For player with specified id private state will be reset to null, which means they will get out of private parallel states and be in a master state like the private states are not used &lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: this is usually used when deactivating player to clean up their parallel state&lt;br /&gt;
: Note: After unseting private state only actions on master state are possible&lt;br /&gt;
: Note: Usually it is not necessary to unset private state as it will be initialized to first private state when private states are needed again. Nevertheless it is generally better to clean private state when not needed to avoid bugs. &lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function done() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;setPlayerNonMultiactive( $this-&amp;gt;getCurrentPlayerId(), &amp;quot;newTurn&amp;quot; );&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;unsetPrivateState($this-&amp;gt;getCurrentPlayerId());&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;setPrivateState($playerId, $newStateId)&lt;br /&gt;
: For player with specified id a new private state would be set&lt;br /&gt;
: Note: game needs to be in a master state which allows private parallel states&lt;br /&gt;
: Note: this should be rarely used as it doesn&#039;t check if the transition is allowed (it doesn&#039;t even specifies transition). This can be useful in very complex cases when standard state machine is not adequate (i.e. specific cards can lead to some micro action in various states where defining transitions back and forth can become very tedious.) &lt;br /&gt;
: Note: this method can run action or args methods of the target state for specified player&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function actSomeAction() {&lt;br /&gt;
        $this-&amp;gt;checkAction(&amp;quot;actSomeAction&amp;quot;); //needs to be defined in the current state&lt;br /&gt;
&lt;br /&gt;
        if ($playerHaveSpecificCard)&lt;br /&gt;
            return $this-&amp;gt;gamestate-&amp;gt;setPrivateState($this-&amp;gt;getCurrentPlayerId(), 35);&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextPrivateState($this-&amp;gt;getCurrentPlayerId(), &amp;quot;some_transition&amp;quot;);        &lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; $this-&amp;gt;gamestate-&amp;gt;getPrivateState($playerId) &lt;br /&gt;
: This return the private state or null if not initialized or not in private state&lt;br /&gt;
&lt;br /&gt;
==== State Arguments in Private parallel states ====&lt;br /&gt;
&lt;br /&gt;
The args method called for private states will have the player_id passed to it, allowing you to customise the arguments returned for that player.&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
    &amp;lt;pre&amp;gt;&lt;br /&gt;
    function argMyPrivateState($player_id) {&lt;br /&gt;
        return array(&lt;br /&gt;
          &#039;my_data&#039; =&amp;gt; $this-&amp;gt;getPlayerSpecificData($player_id)&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
    &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Inactive Players ====&lt;br /&gt;
&lt;br /&gt;
During Private Parallel State, active players will be managed by the private state that is current assigned to them.&lt;br /&gt;
&lt;br /&gt;
Inactive players will be managed by the master multipleactiveplayer state, so your client should respond to that state in order to display any status message advising players that they are waiting for others to have their turn, or to add any buttons that allow players to potentially &amp;quot;break in&amp;quot; and become active.&lt;br /&gt;
&lt;br /&gt;
== Players turn order ==&lt;br /&gt;
&lt;br /&gt;
When table is created the &amp;quot;natural&amp;quot; player order is assigned to player at random, and stored in &amp;quot;read-only&amp;quot; field &amp;quot;player_no&amp;quot;.&lt;br /&gt;
If you need to create a custom order you should never change natural order but have a separate data structure. &lt;br /&gt;
For example you can alter the players table to add another &amp;quot;custom_order&amp;quot; field, you can use state globals or you can use your natural board database, &lt;br /&gt;
to store meeple_color/position_location pair.&lt;br /&gt;
BGA currently does not provide any API to create/store custom player order.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getNextPlayerTable()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return an associative array which associate each player with the next player around the table.&lt;br /&gt;
&lt;br /&gt;
In addition, key 0 is associated to the first player to play.&lt;br /&gt;
&lt;br /&gt;
Example: if three player with ID 1000, 2000 and 3000 are around the table, in this order, the method returns:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   array( &lt;br /&gt;
    1000 =&amp;gt; 2000, &lt;br /&gt;
    2000 =&amp;gt; 3000, &lt;br /&gt;
    3000 =&amp;gt; 1000, &lt;br /&gt;
    0 =&amp;gt; 1000 &lt;br /&gt;
   );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getPrevPlayerTable()&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as above, but the associative array associate the previous player around the table. However there no 0 index here.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getPlayerAfter( $player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get player playing after given player in natural playing order.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getPlayerBefore( $player_id )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Get player playing before given player in natural playing order.&lt;br /&gt;
&lt;br /&gt;
Note: There is no API to modify this order, if you have custom player order you have to maintain it in your database&lt;br /&gt;
and have custom function to access it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;createNextPlayerTable( $players, $bLoop=true )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using $players array creates a map of current =&amp;gt; next as in example from getNextPlayerTable(), however you can use custom order here. &lt;br /&gt;
If parmeter $bLoop is set to true then last player will points to first (creaing a loop), false otherwise.&lt;br /&gt;
In any case index 0 points to first player (first element of $players array). $players is array of player ids in desired order.&lt;br /&gt;
&lt;br /&gt;
Note: This function &#039;&#039;&#039;DOES NOT&#039;&#039;&#039; change the order in database, it only creates a map using key/values as descibed.&lt;br /&gt;
&lt;br /&gt;
Example of usage:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function getNextPlayerTableCustom() {&lt;br /&gt;
        $starting = $this-&amp;gt;getStartingPlayer(); // custom function to get starting player&lt;br /&gt;
        $player_ids = $this-&amp;gt;getPlayerIdsInOrder($starting); // custom function to create players array starting from starting player&lt;br /&gt;
        return $this-&amp;gt;createNextPlayerTable($player_ids, false); // create next player table in custom order&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$table = $this-&amp;gt;createNextPlayerTable([3000,2000,1000], false);&lt;br /&gt;
&lt;br /&gt;
will return:&lt;br /&gt;
   [ &lt;br /&gt;
    3000 =&amp;gt; 2000, &lt;br /&gt;
    2000 =&amp;gt; 1000, &lt;br /&gt;
    1000 =&amp;gt; null,&lt;br /&gt;
    0 =&amp;gt; 3000 &lt;br /&gt;
   ]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Notifications ==&lt;br /&gt;
&lt;br /&gt;
To understand notifications, please read [http://www.slideshare.net/boardgamearena/the-bga-framework-at-a-glance The BGA Framework at a glance] first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Notifications are crutial part of BGA framework. Everything players see, all changes which happen on frontend (including setup) are done via notfications.&lt;br /&gt;
Some of the are framework notifications and some of them are custom (game specific).&lt;br /&gt;
Generally you should not send or handle stanard notifications, except exposed APIs.&lt;br /&gt;
Example of standard notifications:&lt;br /&gt;
* game setup (first time client connects to game)&lt;br /&gt;
* game state change&lt;br /&gt;
* active player change&lt;br /&gt;
Example of custom notification&lt;br /&gt;
* game piece moved&lt;br /&gt;
* player scored points&lt;br /&gt;
&lt;br /&gt;
Notifications are queued, i.e. sent at the very end of the action, when it ends normally. It means that if you throw an exception for any reason (i.e: move is not allowed), no notifications will be sent to players.&lt;br /&gt;
&lt;br /&gt;
Notification can be sent from the following  functions (and transive calls obviosly):&lt;br /&gt;
&lt;br /&gt;
* action handler (action* in game.php). It is a MUST actually. At least one notificaton must be sent (but it includes state transition which sends it)&lt;br /&gt;
* game state transition (st* in game.php)&lt;br /&gt;
* setupNewGame (after player tables setup is finished)&lt;br /&gt;
&lt;br /&gt;
Notification cannot be sent from the following:&lt;br /&gt;
* .view.php&lt;br /&gt;
* .action.php&lt;br /&gt;
* material.inc.php&lt;br /&gt;
* constructor of .game.php&lt;br /&gt;
* arg* methods of .game.php&lt;br /&gt;
&lt;br /&gt;
There are conceptually two types of notification:&lt;br /&gt;
* public - sent to all client who are listening - that includes all players in the table and spectators&lt;br /&gt;
* private - that can only be sent to a player &lt;br /&gt;
&lt;br /&gt;
The bundle of notifications is sent at the end action considered a single &amp;quot;move&amp;quot; and move counter increases.&lt;br /&gt;
If you ONLY sending private notifications during action handling - they will not have associate move_id (to avoid it add simple public notification with empty message). &lt;br /&gt;
In rare case if you want to change this behavior, you can apply some hackery described in [[BGA_Studio_Cookbook]]&lt;br /&gt;
&lt;br /&gt;
Note: total notification size is now limited to 128K. It seems a lot, but don&#039;t forget that notification are bundled and only send at the end of action which also INCLUDES all game state transitions that follow.&lt;br /&gt;
&lt;br /&gt;
The notifications are handled on JS side by subscribing to notifications (only do it for custom notifications!). See [Game_interface_logic:_yourgamename.js#Notifications]&lt;br /&gt;
&lt;br /&gt;
=== NotifyAllPlayers ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;notifyAllPlayers(string $notification_type,string $message,array $notification_args )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Send a notification to all players of the game and spectators (public).&lt;br /&gt;
&lt;br /&gt;
* notification_type: A string that defines the type of your notification.&lt;br /&gt;
&lt;br /&gt;
Your game interface Javascript logic will use this to know what is the type of the received notification (and to trigger the corresponding method).&lt;br /&gt;
&lt;br /&gt;
* message: A string that defines what is to be displayed in the game log.&lt;br /&gt;
&lt;br /&gt;
You can use an empty string here (&#039;&#039;). In this case, nothing is displayed in the game log.&lt;br /&gt;
&lt;br /&gt;
Unless its empty, use &amp;quot;clienttranslate&amp;quot; method to make sure string is translated.&lt;br /&gt;
&lt;br /&gt;
You can use arguments in your $notification_log string, that refers to values defines in the &amp;quot;$notification_args&amp;quot; argument (see below). &lt;br /&gt;
Note: Make sure you only use single quotes (&#039;), otherwise PHP will try to interpolate the variable and will ignore the values in the args array.&lt;br /&gt;
&lt;br /&gt;
* notification_args: The arguments of your notifications, as an associative array.&lt;br /&gt;
&lt;br /&gt;
This array will be transmitted to the game interface logic, in order the game interface can be updated.&lt;br /&gt;
&lt;br /&gt;
Complete notifyAllPlayers example (from &amp;quot;Reversi&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;notifyAllPlayers( &amp;quot;playDisc&amp;quot;, clienttranslate( &#039;${player_name} plays a disc and turns over ${returned_nbr} disc(s)&#039; ),&lt;br /&gt;
 array(&lt;br /&gt;
        &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
        &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
        &#039;returned_nbr&#039; =&amp;gt; count( $turnedOverDiscs ),&lt;br /&gt;
        &#039;x&#039; =&amp;gt; $x,&lt;br /&gt;
        &#039;y&#039; =&amp;gt; $y&lt;br /&gt;
     ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see in the example above the use of the &amp;quot;clienttranslate&amp;quot; method, and the use of 2 arguments &amp;quot;player_name&amp;quot; and &amp;quot;returned_nbr&amp;quot; in the notification log.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: NO private data must be sent with this method, as a cheater could see it even if it is not used explicitly by the game interface logic. If you want to send private information to a player, please use notifyPlayer below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: this array is serialized to be sent to the browsers, and will be saved with the notification to be able to replay the game later. If it is too big, it can make notifications slower / less reliable, and replay archives very big (to the point of failing). So as a general rule, you should send only the minimum of information necessary to update the client interface with no overhead in order to keep the notifications as light as possible.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: When the game page is reloaded (i.e. F5 or when loading turn based game) all previous notifications are replayed as history notifications. These notifications do not trigger notification handlers and are used basically to build the game log. Because of that most of the notification arguments (except i18n, player_id and all arguments referenced in the message), are removed from these history notifications. If you need additional arguments in history notifications you can add special field &amp;lt;b&amp;gt;preserve&amp;lt;/b&amp;gt; to notification arguments, like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;notifyAllPlayers( &amp;quot;playDisc&amp;quot;, clienttranslate( &#039;${player_name} plays a disc and turns over ${returned_nbr} disc(s)&#039; ),&lt;br /&gt;
 array(&lt;br /&gt;
        &#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
        &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&lt;br /&gt;
        &#039;returned_nbr&#039; =&amp;gt; count( $turnedOverDiscs ),&lt;br /&gt;
        &#039;x&#039; =&amp;gt; $x,&lt;br /&gt;
        &#039;y&#039; =&amp;gt; $y,&lt;br /&gt;
        &#039;preserve&#039; =&amp;gt; [ &#039;x&#039;, &#039;y&#039; ]&lt;br /&gt;
     ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
In this example, fields x and y will be preserved when replaying history notification at the game load.&lt;br /&gt;
&lt;br /&gt;
NOTE: The ONLY reason &#039;preserve&#039; is useful if you have custom method to render notifications in game log which changes some text arguments into html (i.e. to insert the images instead of plain text). Do not use preserve &amp;quot;just in case&amp;quot; - it will only bloat the logs and make game load VERY slow.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: If both public and private notifications are sent to the same player in the same action (AJAX call), they will initially appear in the log in the order in which they were called, but they are placed into the game log in the following order: All private notifications first, then all public notifications. This means that when the page is refreshed, or when a player loads an asynchronous game, if you have called any public notifications &#039;&#039;before&#039;&#039; the last private notification, they will appear out of order in the log.&lt;br /&gt;
&lt;br /&gt;
==== HTML in Notifications ====&lt;br /&gt;
&lt;br /&gt;
You CAN use some HTML inside your notification log, however it not recommended for many reasons:&lt;br /&gt;
* Its bad architecture, ui elements leak into server now you have to manage ui in many places&lt;br /&gt;
* If you decided to change something in ui in a future version, old games replay and tutorials may not work, since they use stored notifications (for example if the change occured during the game and later this game is used for tutorial)&lt;br /&gt;
* When you read log preview for old games its unreadable (this is log before you enter the game replay, useful for troubleshooting or game analysis)&lt;br /&gt;
* Its more data to transfer and store in db&lt;br /&gt;
* Its nightmare for translators, at least don&#039;t put HTML tags inside the &amp;quot;clienttranslate&amp;quot; method. You can use a notification argument instead, and provide your HTML through this argument.&lt;br /&gt;
&lt;br /&gt;
If you still want to have pretty pictures in the log check this [[BGA_Studio_Cookbook#Inject_images_and_styled_html_in_the_log]].&lt;br /&gt;
&lt;br /&gt;
==== Recursive Notifications ====&lt;br /&gt;
&lt;br /&gt;
If your notification contains some phrases that build programmatically you may need to use recursive notifications. In this case the argument can be not only the string but&lt;br /&gt;
an array itself, which contains &#039;log&#039; and &#039;args&#039;, i.e.&lt;br /&gt;
&lt;br /&gt;
  $this-&amp;gt;notifyAllPlayers(&#039;message&#039;,clienttranslate(&#039;Game moves ${token_name_rec}&#039;),&lt;br /&gt;
                   [&#039;token_name_rec&#039;=&amp;gt;[&#039;log&#039;=&amp;gt;&#039;${token_name} #${token_number}&#039;,&lt;br /&gt;
                                       &#039;args&#039;=&amp;gt; [&#039;token_name&#039;=&amp;gt;clienttranslate(&#039;Boo&#039;), &#039;token_number&#039;=&amp;gt;$number, &#039;i18n&#039;=&amp;gt;[&#039;token_name&#039;] ]&lt;br /&gt;
                                      ]&lt;br /&gt;
                   ]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Excluding some players ====&lt;br /&gt;
&lt;br /&gt;
Sometimes you want to notify all players of a message but not have it appear in the log of specific players (for example, have every player see &amp;quot;Player X draws a card&amp;quot; but have Player X  will get a private notification &amp;quot;You draw the Ace of Spades&amp;quot;, so you want them not to see the public one).&lt;br /&gt;
&lt;br /&gt;
To send a notification to all players but have some clients ignore it, send it as normal from the server, but implement &#039;&#039;&#039;setIgnoreNotificationCheck&#039;&#039;&#039; on the client to ignore the message under given conditions. See the [[Game_interface_logic:_yourgamename.js#Ignoring_notifications]] documentation for more details. Note: do not sent private info with such notification, hiding something on client side is not a hacker safe.&lt;br /&gt;
&lt;br /&gt;
==== Using player names  ====&lt;br /&gt;
&lt;br /&gt;
The variable for player name must be ${player_name} in order to be highlighted with the player color in the game log, it has to have matching &#039;player_id&#039; argument in $notification_args. If you want a second player name in the log, name the variable ${player_name2} and $player_id2, etc.  For the multiple player case, usage of player_id and player_name is not mandatory i.e. skipping to player_id1 and player_name1 is fine.&lt;br /&gt;
&lt;br /&gt;
Special handling of arguments:&lt;br /&gt;
* ${player_name}  - this will be wrapped in html and text shown using color of the corresponding player, some colors also have reserved background. This will apply recursively as well.&lt;br /&gt;
* ${player_name1}, ${player_name2}, ${player_name3}, etc. work the same as above&lt;br /&gt;
In order for this to work you must pass corresponding player_idX AND player_nameX in args i.e.&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;notifyAllPlayers(&lt;br /&gt;
      &#039;buyAndPassCard&#039;,&lt;br /&gt;
      clienttranslate(&#039;${player_name} buys ${card_name} and passes it to ${player_name2}&#039;),&lt;br /&gt;
      [&lt;br /&gt;
        &#039;player_id&#039; =&amp;gt; $player1[&#039;id&#039;],&lt;br /&gt;
        &#039;player_name&#039; =&amp;gt; $player1[&#039;name&#039;],&lt;br /&gt;
        &#039;player_id2&#039; =&amp;gt; $player2[&#039;id&#039;],&lt;br /&gt;
        &#039;player_name2&#039; =&amp;gt; $player2[&#039;name&#039;],&lt;br /&gt;
        ...&lt;br /&gt;
      ]&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
Note: player_name is not translatable, never add it to i18n array&lt;br /&gt;
&lt;br /&gt;
=== NotifyPlayer ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;notifyPlayer(int $player_id, string $notification_type, string $message, $notification_args )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as above, except that the notification is sent to one player only. The player must be the player at the game table.&lt;br /&gt;
&lt;br /&gt;
This method must be used each time some private information must be transmitted to a player.&lt;br /&gt;
&lt;br /&gt;
Important: the variable for player name must be ${player_name} in order to be highlighted with the player color in the game log. Since its a private notification it may be more appropriate to use &amp;quot;you&amp;quot; insted&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  $this-&amp;gt;notifyPlayer($player_id,&#039;message&#039;,clienttranslate(&#039;You draw ${card_name}&#039;), [ ... ]);&lt;br /&gt;
or&lt;br /&gt;
  $this-&amp;gt;notifyPlayer($player_id,&#039;message&#039;,clienttranslate(&#039;${player_name} draws ${card_name}&#039;), [ &#039;player_name&#039; =&amp;gt; $this-&amp;gt;getPlayerNameById($player_id), ... ]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: Spectators cannot be notified using this method, because their player ID is not available via loadPlayersBasicInfos() or otherwise. You must use notifyAllPlayers() for any notification that spectators should get.&lt;br /&gt;
&lt;br /&gt;
== Randomization ==&lt;br /&gt;
&lt;br /&gt;
A large number of board games rely on random, most often based on dice, cards shuffling, picking some item in a bag, and so on. This is very important to ensure a high level of randomness for each of these situations.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s are a list of techniques you should use in these situations, from the best to the worst.&lt;br /&gt;
&lt;br /&gt;
=== Dice and bga_rand ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;bga_rand( min, max )&#039;&#039;&#039; &lt;br /&gt;
This is a BGA framework function that provides you a random number between &amp;quot;min&amp;quot; and &amp;quot;max&amp;quot; (inclusive), using the best available random method available on the system.&lt;br /&gt;
&lt;br /&gt;
This is the preferred function you should use, because we are updating it when a better method is introduced.&lt;br /&gt;
&lt;br /&gt;
As of now, bga_rand is based on the PHP function &amp;quot;random_int&amp;quot;, which ensures a cryptographic level of randomness.&lt;br /&gt;
&lt;br /&gt;
In particular, it is &#039;&#039;&#039;mandatory&#039;&#039;&#039; to use it for all &#039;&#039;&#039;dice throw&#039;&#039;&#039; (ie: games using other methods for dice throwing will be rejected by BGA during review).&lt;br /&gt;
&lt;br /&gt;
Note: rand() and mt_rand() are deprecated on BGA and should not be used anymore, as their randomness is not as good as &amp;quot;bga_rand&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Arrays ===&lt;br /&gt;
&lt;br /&gt;
Although PHP&#039;s &amp;quot;shuffle()&amp;quot; is generally considered good enough (see below, BGA&#039;s own Deck component uses this), the following PHP code based on &amp;quot;random_int&amp;quot; provides a cryptographically-secure method to choose a random key, value, or slice of an array. (the slice preserves keys)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    private function getRandomKey(array &amp;amp;$array)&lt;br /&gt;
    {&lt;br /&gt;
        $size = count($array);&lt;br /&gt;
        if ($size == 0) {&lt;br /&gt;
            trigger_error(&amp;quot;getRandomKey(): Array is empty&amp;quot;, E_USER_WARNING);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
        $rand = random_int(0, $size - 1);&lt;br /&gt;
        $slice = array_slice($array, $rand, 1, true);&lt;br /&gt;
        foreach ($slice as $key =&amp;gt; $value) {&lt;br /&gt;
            return $key;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private function getRandomValue(array &amp;amp;$array)&lt;br /&gt;
    {&lt;br /&gt;
        $size = count($array);&lt;br /&gt;
        if ($size == 0) {&lt;br /&gt;
            trigger_error(&amp;quot;getRandomValue(): Array is empty&amp;quot;, E_USER_WARNING);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
        $rand = random_int(0, $size - 1);&lt;br /&gt;
        $slice = array_slice($array, $rand, 1, true);&lt;br /&gt;
        foreach ($slice as $key =&amp;gt; $value) {&lt;br /&gt;
            return $value;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    private function getRandomSlice(array &amp;amp;$array, int $count)&lt;br /&gt;
    {&lt;br /&gt;
        $size = count($array);&lt;br /&gt;
        if ($size == 0) {&lt;br /&gt;
            trigger_error(&amp;quot;getRandomSlice(): Array is empty&amp;quot;, E_USER_WARNING);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
        if ($count &amp;lt; 1 || $count &amp;gt; $size) {&lt;br /&gt;
            trigger_error(&amp;quot;getRandomSlice(): Invalid count $count for array with size $size&amp;quot;, E_USER_WARNING);&lt;br /&gt;
            return null;&lt;br /&gt;
        }&lt;br /&gt;
        $slice = [];&lt;br /&gt;
        $randUnique = [];&lt;br /&gt;
        while (count($randUnique) &amp;lt; $count) {&lt;br /&gt;
            $rand = random_int(0, $size - 1);&lt;br /&gt;
            if (array_key_exists($rand, $randUnique)) {&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
            $randUnique[$rand] = true;&lt;br /&gt;
            $slice += array_slice($array, $rand, 1, true);&lt;br /&gt;
        }&lt;br /&gt;
        return $slice;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== shuffle and cards shuffling ===&lt;br /&gt;
&lt;br /&gt;
To shuffle items, like a pile of cards, the best way is to use the BGA PHP [[Deck]] component and to use &amp;quot;shuffle&amp;quot; method. This ensures that the best available shuffling method is used, and that if in the future we improve it your game will be up to date.&lt;br /&gt;
&lt;br /&gt;
As of now, the Deck component shuffle method is based on PHP &amp;quot;shuffle&amp;quot; method, which has quite good randomness (even if not as good as bga_rand). In consequence, we accept other shuffling methods during reviews, as long as they are based on PHP &amp;quot;shuffle&amp;quot; function (or similar, like &amp;quot;array_rand&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
=== Other methods ===&lt;br /&gt;
&lt;br /&gt;
Mysql &amp;quot;RAND()&amp;quot; function has not enough randomness to be a valid method to get a random element on BGA. This function has been used in some existing games and has given acceptable results, but now it should be avoided and you should use other methods instead.&lt;br /&gt;
&lt;br /&gt;
== Game statistics ==&lt;br /&gt;
&lt;br /&gt;
There are 2 types of statistics:&lt;br /&gt;
* a &amp;quot;player&amp;quot; statistic is a statistic associated to a player&lt;br /&gt;
* a &amp;quot;table&amp;quot; statistic is a statistic not associated to a player (global statistic for this game).&lt;br /&gt;
&lt;br /&gt;
See [[Game statistics: stats.inc.php]] to see how you define statistics for your game.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;initStat( $table_or_player, $name, $value, $player_id = null )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create a statistic entry with a default value.&lt;br /&gt;
&lt;br /&gt;
This method must be called for each statistic of your game, in your setupNewGame method.&lt;br /&gt;
If you neglect to call this for a statistic, and also do not update the value during the course of a certain game using setStat or incStat, the value of the stat will be undefined rather than 0. This will result in it being ignored at the end of the game, as if it didn&#039;t apply to that particular game, and excluded from cumulative statistics. As a consequence - if do not want statistic to be applied, do not init it, or call set or inc on it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;$table_or_player&#039; must be set to &amp;quot;table&amp;quot; if this is a table statistic, or &amp;quot;player&amp;quot; if this is a player statistic.&lt;br /&gt;
&lt;br /&gt;
&#039;$name&#039; is the name of your statistic, as it has been defined in your stats.inc.php file.&lt;br /&gt;
&lt;br /&gt;
&#039;$value&#039; is the initial value of the statistic. If this is a player statistic and if the player is not specified by &amp;quot;$player_id&amp;quot; argument, the value is set for ALL players.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setStat( $value, $name, $player_id = null )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Set a statistic $name to $value.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;$player_id&amp;quot; is not specified, setStat consider it is a TABLE statistic.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;$player_id&amp;quot; is specified, setStat consider it is a PLAYER statistic.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;incStat( $delta, $name, $player_id = null )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Increment (or decrement) specified statistic value by $delta value. Same behavior as setStat function.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getStat( $name, $player_id = null )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return the value of statistic specified by $name. Useful when creating derivative statistics such as average.&lt;br /&gt;
&lt;br /&gt;
== Translations ==&lt;br /&gt;
&lt;br /&gt;
See [[Translations]]&lt;br /&gt;
&lt;br /&gt;
== Manage player scores and Tie breaker ==&lt;br /&gt;
&lt;br /&gt;
=== Normal scoring ===&lt;br /&gt;
&lt;br /&gt;
At the end of the game, players automatically get a rank depending on their score: the player with the biggest score is #1, the player with the second biggest score is #2, and so on...&lt;br /&gt;
&lt;br /&gt;
During the game, you update player&#039;s score directly by updating &amp;quot;player_score&amp;quot; field of &amp;quot;player&amp;quot; table in database.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  // +2 points to active player&lt;br /&gt;
  $this-&amp;gt;DbQuery( &amp;quot;UPDATE player SET player_score=player_score+2 WHERE player_id=&#039;&amp;quot;.self::getActivePlayerId().&amp;quot;&#039;&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
  // Set score of active player to 5&lt;br /&gt;
  $this-&amp;gt;DbQuery( &amp;quot;UPDATE player SET player_score=5 WHERE player_id=&#039;&amp;quot;.self::getActivePlayerId().&amp;quot;&#039;&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: don&#039;t forget to notify the client side in order the score control can be updated accordingly.&lt;br /&gt;
&lt;br /&gt;
=== Tie breaker ===&lt;br /&gt;
&lt;br /&gt;
Tie breaker is used when two players get the same score at the end of a game.&lt;br /&gt;
&lt;br /&gt;
Tie breaker is using &amp;quot;player_score_aux&amp;quot; field of &amp;quot;player&amp;quot; table. It is updated exactly like the &amp;quot;player_score&amp;quot; field.&lt;br /&gt;
&lt;br /&gt;
Tie breaker score is displayed only for players who are tied at the end of the game. Most of the time, it is not supposed to be displayed explicitly during the game.&lt;br /&gt;
&lt;br /&gt;
When you are using &amp;quot;player_score_aux&amp;quot; functionality, you must describe the formula to use in your gameinfos.inc.php file like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
         &#039;tie_breaker_description&#039; =&amp;gt; totranslate(&amp;quot;Describe here your tie breaker formula&amp;quot;),&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This description will be used as a tooltip to explain to players how this auxiliary score has been calculated.&lt;br /&gt;
&lt;br /&gt;
See also [https://en.doc.boardgamearena.com/Game_meta-information:_gameinfos.inc.php#Multiple_tie_breaker_management Multiple Tie Breaker Management].&lt;br /&gt;
&lt;br /&gt;
=== Co-operative game ===&lt;br /&gt;
&lt;br /&gt;
To make everyone win/lose together in a full-coop game:&lt;br /&gt;
&lt;br /&gt;
Add the following in gameinfos.inc.php :&lt;br /&gt;
&#039;is_coop&#039; =&amp;gt; 1, // full cooperative&lt;br /&gt;
&lt;br /&gt;
Assign a score of zero to everyone if it&#039;s a loss.&lt;br /&gt;
Assign the same score &amp;gt; 0 to everyone if it&#039;s a win.&lt;br /&gt;
&lt;br /&gt;
=== Semi-coop ===&lt;br /&gt;
&lt;br /&gt;
If the game is not full-coop, then everyone loses = everyone is tied. I.e. set score to 0 to everybody.&lt;br /&gt;
&lt;br /&gt;
=== Only &amp;quot;winners&amp;quot; and &amp;quot;losers&amp;quot; ===&lt;br /&gt;
&lt;br /&gt;
For some games, there is only a group (or a single) &amp;quot;winner&amp;quot;, and everyone else is a &amp;quot;loser&amp;quot;, with no &amp;quot;end of game rank&amp;quot; (1st, 2nd, 3rd...).&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
* Coup&lt;br /&gt;
* Not Alone&lt;br /&gt;
* Werewolves&lt;br /&gt;
* Quantum&lt;br /&gt;
&lt;br /&gt;
In this case:&lt;br /&gt;
* Set the scores so that the winner has the best score, and the other players have the same (lower) score.&lt;br /&gt;
* Add the following lines to gameinfos.inc.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// If in the game, all losers are equal (no score to rank them or explicit in the rules that losers are not ranked between them), set this to true &lt;br /&gt;
// The game end result will display &amp;quot;Winner&amp;quot; for the 1st player and &amp;quot;Loser&amp;quot; for all other players&lt;br /&gt;
&#039;losers_not_ranked&#039; =&amp;gt; true,&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Werewolves and Coup are implemented like this, as you can see here:&lt;br /&gt;
* https://boardgamearena.com/#!gamepanel?game=werewolves&amp;amp;section=lastresults&lt;br /&gt;
* https://boardgamearena.com/#!gamepanel?game=coupcitystate&amp;amp;section=lastresults&lt;br /&gt;
&lt;br /&gt;
Adding this has the following effects:&lt;br /&gt;
* On game results for this game, &amp;quot;Winner&amp;quot; or &amp;quot;Loser&amp;quot; is going to appear instead of the usual &amp;quot;1st, 2nd, 3rd, ...&amp;quot;.&lt;br /&gt;
* When a game is over, the result of the game will be &amp;quot;End of game: Victory&amp;quot; or &amp;quot;End of game: Defeat&amp;quot; depending on the result of the CURRENT player (instead of the usual &amp;quot;Victory of XXX&amp;quot;).&lt;br /&gt;
* When calculating ELO points, if there is at least one &amp;quot;Loser&amp;quot;, no &amp;quot;victorious&amp;quot; player can lose ELO points, and no &amp;quot;losing&amp;quot; player can win ELO point. Usually it may happened because being tie with many players with a low rank is considered as a tie and may cost you points. If losers_not_ranked is set, we prevent this behavior and make sure you only gain/loss ELO when you get the corresponding results.&lt;br /&gt;
&lt;br /&gt;
Important: this SHOULD NOT be used for cooperative games (see is_coop parameter), or for 2 players games (it makes no sense in this case).&lt;br /&gt;
&lt;br /&gt;
=== Solo ===&lt;br /&gt;
&lt;br /&gt;
If game supports solo variant, a negative or zero score means defeat, a positive score means victory.&lt;br /&gt;
&lt;br /&gt;
=== Player elimination ===&lt;br /&gt;
&lt;br /&gt;
In some games, this is useful to eliminate a player from the game in order he/she can start another game without waiting for the current game end.&lt;br /&gt;
&lt;br /&gt;
This case should be rare. Please don&#039;t use player elimination feature if some player just has to wait the last 10% of the game for game end. This feature should be used only in games where players are eliminated all along the game (typical examples: &amp;quot;Perudo&amp;quot; or &amp;quot;The Werewolves of Miller&#039;s Hollow&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
&lt;br /&gt;
* Player to eliminate should NOT be active anymore (preferably use the feature in a &amp;quot;game&amp;quot; type game state).&lt;br /&gt;
* In your PHP code:&lt;br /&gt;
  $this-&amp;gt;eliminatePlayer( &amp;lt;player_to_eliminate_id&amp;gt; );&lt;br /&gt;
* the player is informed in a dialog box that he no longer have to play and can start another game if he/she wants too (with buttons &amp;quot;stay at this table&amp;quot; &amp;quot;quit table and back to main site&amp;quot;). In any case, the player is free to start &amp;amp; join another table from now.&lt;br /&gt;
* When your game is over, all players who have been eliminated before receive a &amp;quot;notification&amp;quot; (the small &amp;quot;!&amp;quot; icon on the top right of the BGA interface) that indicate them that &amp;quot;the game has ended&amp;quot; and invite them to review the game results.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; this should not be used on a player who has already left the game (&amp;quot;zombie&amp;quot;) as leaving/being kicked of the game (outside of the scope of the rules) is not the same as being eliminated from the game (according to the rules), except if in the course of the game, the zombie player is eliminated according to the rules.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important:&#039;&#039;&#039; When all surviving players are eliminated at the same time BGA framework causes the game to be abandoned automatically.&lt;br /&gt;
To circumvent this, the game should leave 1 player not eliminated but change final scores accordingly and end the game.&lt;br /&gt;
&lt;br /&gt;
=== Scoring Helper functions ===&lt;br /&gt;
&lt;br /&gt;
These functions should have been API but they are not, just add them to your php game and use for every game.&lt;br /&gt;
&lt;br /&gt;
    // get score&lt;br /&gt;
    function dbGetScore($player_id) {&lt;br /&gt;
        return $this-&amp;gt;getUniqueValueFromDB(&amp;quot;SELECT player_score FROM player WHERE player_id=&#039;$player_id&#039;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // set score&lt;br /&gt;
    function dbSetScore($player_id, $count) {&lt;br /&gt;
        $this-&amp;gt;DbQuery(&amp;quot;UPDATE player SET player_score=&#039;$count&#039; WHERE player_id=&#039;$player_id&#039;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // set aux score (tie breaker)&lt;br /&gt;
    function dbSetAuxScore($player_id, $score) {&lt;br /&gt;
        $this-&amp;gt;DbQuery(&amp;quot;UPDATE player SET player_score_aux=$score WHERE player_id=&#039;$player_id&#039;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // increment score (can be negative too)&lt;br /&gt;
    function dbIncScore($player_id, $inc) {&lt;br /&gt;
        $count = $this-&amp;gt;dbGetScore($player_id);&lt;br /&gt;
        if ($inc != 0) {&lt;br /&gt;
            $count += $inc;&lt;br /&gt;
            $this-&amp;gt;dbSetScore($player_id, $count);&lt;br /&gt;
        }&lt;br /&gt;
        return $count;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
== Reflexion time ==&lt;br /&gt;
&lt;br /&gt;
; function giveExtraTime( $player_id, $specific_time=null )&lt;br /&gt;
: Give standard extra time to this player.&lt;br /&gt;
: Standard extra time depends on the speed of the game (small with &amp;quot;slow&amp;quot; game option, bigger with other options).&lt;br /&gt;
: You can also specify an exact time to add, in seconds, with the &amp;quot;specified_time&amp;quot; argument (rarely used).&lt;br /&gt;
&lt;br /&gt;
; function isAsync()&lt;br /&gt;
: Returns true if game is turn based, false if it is realtime&lt;br /&gt;
&lt;br /&gt;
== Undo moves ==&lt;br /&gt;
&lt;br /&gt;
Please read our [[BGA Undo policy]] before.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important&#039;&#039;&#039;: Before using these methods, you must also add the following to your &amp;quot;gameinfos.inc.php&amp;quot; file, otherwise these methods are ineffective:&lt;br /&gt;
  &#039;db_undo_support&#039; =&amp;gt; true&lt;br /&gt;
&lt;br /&gt;
Note: if you deploy undo support after game is in production this will take into effect for new games only, old games will give user an error if user choses Undo action, but otherwise it should not affect them.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; function undoSavepoint( )&lt;br /&gt;
: Save the whole game situation inside an &amp;quot;Undo save point&amp;quot;.&lt;br /&gt;
: There is only ONE undo save point available (see [[BGA Undo policy]]). Cannot use in multiactivate state or in game state where next state is multiactive.&lt;br /&gt;
: Note: this function does not actually do anything when it is called, it only raises the flag to store the database AFTER transaction is over. So the actual state will be saved when you exit the function  calling it (technically before first queued notification is sent, which matters if you transition to game state not to user state after), this may affect what you end up saving.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; function undoRestorePoint()&lt;br /&gt;
: Restore the situation previously saved as an &amp;quot;Undo save point&amp;quot;.&lt;br /&gt;
: You must make sure that the active player is the same after and before the undoRestorePoint (ie: this is your responsibility to ensure that the player that is active when this method is called is exactly the same than the player that was active when the undoSavePoint method has been called).&lt;br /&gt;
&lt;br /&gt;
    function actionUndo() {&lt;br /&gt;
        $this-&amp;gt;checkAction(&#039;actionUndo&#039;);&lt;br /&gt;
        $this-&amp;gt;undoRestorePoint();&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;next&#039;); // transition to single player state (i.e. beginning of player actions for this turn)&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important note&#039;&#039;&#039;: if you are reading game state variable right after restore (without changing state first) it won&#039;t work properly as the global table cache is not automatically refreshed after undoRestorePoint(). So you should either change state immediately to refresh game state values, or use $this-&amp;gt;gamestate-&amp;gt;reloadState() to refresh the state. If you choose to do the latest, be aware that this will bring the state machine back to the state during which the save point snapshot has been taken using undoSavepoint() (which means your transition you do after has to declared in the state which was saved, not in the state which was active for your actionUndo())&lt;br /&gt;
&lt;br /&gt;
== Managing errors and exceptions ==&lt;br /&gt;
&lt;br /&gt;
Note: when you throw an exception, all database changes and all notifications are cancelled immediately. This way, the game situation that existed before the request is completely restored.&lt;br /&gt;
&lt;br /&gt;
; throw new BgaUserException ( $error_message)&lt;br /&gt;
: Base class to notify a user error&lt;br /&gt;
: You must throw this exception when a player wants to do something that they are not allowed to do.&lt;br /&gt;
: The error message will be shown to the player as a &amp;quot;red message&amp;quot;.&lt;br /&gt;
: The error message must be translated, make sure you use self::_() or $this-&amp;gt;_() here and NOT clientranslate()&lt;br /&gt;
: Throwing such an exception is NOT considered a bug, so it is not traced in BGA error logs.&lt;br /&gt;
&lt;br /&gt;
Example from Gomoku:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     throw new BgaUserException( $this-&amp;gt;_(&amp;quot;There is already a stone on this intersection, you can&#039;t play there&amp;quot;) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; throw new BgaVisibleSystemException ( $error_message)&lt;br /&gt;
: You must throw this exception when you detect something that is not supposed to happened in your code.&lt;br /&gt;
: The error message is shown to the user as an &amp;quot;Unexpected error&amp;quot;, in order that he can report it in the forum.&lt;br /&gt;
: The error message is logged in BGA error logs. If it happens regularly, we will report it to you.&lt;br /&gt;
&lt;br /&gt;
; throw new BgaSystemException ( $error_message)&lt;br /&gt;
: Base class to notify a system exception. The message will be hidden from the user, but show in the logs. Use this if the message contains technical information.&lt;br /&gt;
: You shouldn&#039;t use this type of exception except if you think the information shown could be critical. Indeed: a generic error message will be shown to the user, so it&#039;s going to be difficult for you to see what happened.&lt;br /&gt;
&lt;br /&gt;
== Zombie mode ==&lt;br /&gt;
&lt;br /&gt;
When a player leaves a game for any reason (expelled, quit), he becomes a &amp;quot;zombie player&amp;quot;. In this case, the results of the game won&#039;t count for statistics, but this is cool if the other players can finish the game anyway. That&#039;s why zombie mode exists: allow the other player to finish the game, even if the situation is not ideal.&lt;br /&gt;
&lt;br /&gt;
While developing your zombie mode, keep in mind that:&lt;br /&gt;
* Do not refer to the rules, because this situation is not planned by the rules.&lt;br /&gt;
* Try to figure that you are playing with your friends and one of them has to leave: how can we finish the game without killing the spirit of the game?&lt;br /&gt;
* The idea is NOT to develop an artificial intelligence for the game.&lt;br /&gt;
* Do not try to end the game early, even in a two-player game. The zombie is there to allow the game to continue, not to end it. Trying to end the game is not supported by the framework and will likely cause unexpected errors.&lt;br /&gt;
&lt;br /&gt;
Most of the time, the best thing to do when it is zombie player turn is to jump immediately to a state where he is not active anymore. For example, if he is in a game state where he has a choice between playing A and playing B, the best thing to do is NOT to choose A or B, but to pass. So, even if there&#039;s no &amp;quot;pass&amp;quot; action in the rules, add a &amp;quot;zombiepass&amp;quot; transitition in your game state and use it.&lt;br /&gt;
&lt;br /&gt;
Each time a zombie player must play, your &amp;quot;zombieTurn&amp;quot; method is called.&lt;br /&gt;
&lt;br /&gt;
Parameters:&lt;br /&gt;
* $state: the name of the current game state.&lt;br /&gt;
* $active_player: the id of the active player.&lt;br /&gt;
&lt;br /&gt;
Most of the time, your zombieTurn method looks like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function zombieTurn( $state, $active_player )&lt;br /&gt;
    {&lt;br /&gt;
    	$statename = $state[&#039;name&#039;];&lt;br /&gt;
&lt;br /&gt;
        if( $statename == &#039;myFirstGameState&#039;&lt;br /&gt;
             ||  $statename == &#039;my2ndGameState&#039;&lt;br /&gt;
             ||  $statename == &#039;my3rdGameState&#039;&lt;br /&gt;
               ....&lt;br /&gt;
           )&lt;br /&gt;
        {&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextState( &amp;quot;zombiePass&amp;quot; );&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
            throw new BgaVisibleSystemException( &amp;quot;Zombie mode not supported at this game state: &amp;quot;.$statename );&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in the example above, all corresponding game state should implement &amp;quot;zombiePass&amp;quot; as a transition.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Very important&#039;&#039;&#039;: your zombie code will be called when the player leaves the game. This action is triggered from the main site and propagated to the gameserver from a server, not from a browser. As a consequence, there is no current player associated to this action. In your zombieTurn function, you must &#039;&#039;&#039;never&#039;&#039;&#039; use getCurrentPlayerId() or getCurrentPlayerName(), otherwise it will fail with a &amp;quot;Not logged&amp;quot; error message.&lt;br /&gt;
&lt;br /&gt;
== User preferences ==&lt;br /&gt;
&#039;&#039;&#039;getGameUserPreference(int $playerId, int $prefId): ?int&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Return the value of a user preference for a player. It will return the value currently selected in the select combo box, in the top-right menu.&lt;br /&gt;
&lt;br /&gt;
== Player color preferences ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
BGA premium users may choose their preferred color for playing. For example, if they are used to play green for every board game, they can select &amp;quot;green&amp;quot; in their BGA preferences page.&lt;br /&gt;
&lt;br /&gt;
Making your game compatible with colors preferences is very easy and requires only 1 line of configuration change:&lt;br /&gt;
&lt;br /&gt;
On your gameinfos.inc.php file, add the following lines :&lt;br /&gt;
&lt;br /&gt;
  // Favorite colors support: if set to &amp;quot;true&amp;quot;, support attribution of favorite colors based on player&#039;s preferences (see reattributeColorsBasedOnPreferences PHP method)&lt;br /&gt;
  // NB: this parameter is used only to flag games supporting this feature; you must use (or not use) reattributeColorsBasedOnPreferences PHP method to actually enable or disable the feature.&lt;br /&gt;
  &#039;favorite_colors_support&#039; =&amp;gt; true,&lt;br /&gt;
&lt;br /&gt;
Then, on your main &amp;lt;your_game&amp;gt;.game.php file check the code of &amp;quot;setupNewGame&amp;quot;. New template already have correct code, but if you editing very old game and it may be absent.&lt;br /&gt;
&lt;br /&gt;
        $gameinfos = $this-&amp;gt;getGameinfos();&lt;br /&gt;
        ...&lt;br /&gt;
        if ($gameinfos[&#039;favorite_colors_support&#039;])&lt;br /&gt;
            $this-&amp;gt;reattributeColorsBasedOnPreferences($players, $gameinfos[&#039;player_colors&#039;]); // this should be above reloadPlayersBasicInfos()&lt;br /&gt;
        $this-&amp;gt;reloadPlayersBasicInfos();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;reattributeColorsBasedOnPreferences&amp;quot; method reattributes all colors, taking into account players color preferences and available colors.&lt;br /&gt;
&lt;br /&gt;
Note that you must update the colors to indicate the colors available for your game.&lt;br /&gt;
&lt;br /&gt;
Some important remarks:&lt;br /&gt;
* for some games (i.e. Chess), the color has an influence on a mechanism of the game, most of the time by giving a special advantage to a player (i.e. Starting the game). Color preference mechanism must NOT be used in such a case.&lt;br /&gt;
* your logic should NEVER consider that the first player has the color X, that the second player has the color Y, and so on. If this is the case, your game will NOT be compatible with reattributeColorsBasedOnPreferences as this method attribute colors to players based on their preferences and not based as their order at the table.&lt;br /&gt;
&lt;br /&gt;
=== Custom color assignments ===&lt;br /&gt;
Some colors don&#039;t play nicely with BGA&#039;s color difference algorithm. If you receive feedback that colors are not well chosen, you can bypass the BGA algorithm by specifying a map from user preference colors to game colors.&lt;br /&gt;
&lt;br /&gt;
For example, you may wish to assign BGA&#039;s blue to your game&#039;s baby blue: &amp;lt;code&amp;gt;&amp;quot;0000ff&amp;quot; /* Blue */ =&amp;gt; &amp;quot;89CFF0&amp;quot;,&amp;lt;/code&amp;gt; whereas otherwise, a deep purple might be chosen instead. Just be sure that the assigned colors are also present in the &amp;lt;code&amp;gt;player_colors&amp;lt;/code&amp;gt; array passed to &amp;lt;code&amp;gt;reattributeColorsBasedOnPreferences&amp;lt;/code&amp;gt;, otherwise the assignment will be ignored.&lt;br /&gt;
&lt;br /&gt;
To do this, implement this method in your &amp;lt;code&amp;gt;X.game.php&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
Note: the user preference colors (the keys in the returned array) should not be modified, or the code may not work as expected. These are the colors players can choose between in their profile.&lt;br /&gt;
     /**&lt;br /&gt;
      * Returns an array of user preference colors to game colors.&lt;br /&gt;
      * Game colors must be among those which are passed to reattributeColorsBasedOnPreferences()&lt;br /&gt;
      * Each game color can be an array of suitable colors, or a single color:&lt;br /&gt;
      * [&lt;br /&gt;
      *    // The first available color chosen:&lt;br /&gt;
      *    &#039;ff0000&#039; =&amp;gt; [&#039;990000&#039;, &#039;aa1122&#039;],&lt;br /&gt;
      *    // This color is chosen, if available&lt;br /&gt;
      *    &#039;0000ff&#039; =&amp;gt; &#039;000099&#039;,&lt;br /&gt;
      * ]&lt;br /&gt;
      * If no color can be matched from this array, then the default implementation is used.&lt;br /&gt;
      */&lt;br /&gt;
     function getSpecificColorPairings(): array {&lt;br /&gt;
         return array(&lt;br /&gt;
             &amp;quot;ff0000&amp;quot; /* Red */         =&amp;gt; null,&lt;br /&gt;
             &amp;quot;008000&amp;quot; /* Green */       =&amp;gt; null,&lt;br /&gt;
             &amp;quot;0000ff&amp;quot; /* Blue */        =&amp;gt; null,&lt;br /&gt;
             &amp;quot;ffa500&amp;quot; /* Yellow */      =&amp;gt; null,&lt;br /&gt;
             &amp;quot;000000&amp;quot; /* Black */       =&amp;gt; null,&lt;br /&gt;
             &amp;quot;ffffff&amp;quot; /* White */       =&amp;gt; null,&lt;br /&gt;
             &amp;quot;e94190&amp;quot; /* Pink */        =&amp;gt; null,&lt;br /&gt;
             &amp;quot;982fff&amp;quot; /* Purple */      =&amp;gt; null,&lt;br /&gt;
             &amp;quot;72c3b1&amp;quot; /* Cyan */        =&amp;gt; null,&lt;br /&gt;
             &amp;quot;f07f16&amp;quot; /* Orange */      =&amp;gt; null,&lt;br /&gt;
             &amp;quot;bdd002&amp;quot; /* Khaki green */ =&amp;gt; null,&lt;br /&gt;
             &amp;quot;7b7b7b&amp;quot; /* Gray */        =&amp;gt; null,&lt;br /&gt;
         );&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
== Legacy games API ==&lt;br /&gt;
&lt;br /&gt;
For some very specific games (&amp;quot;legacy&amp;quot;, &amp;quot;campaign&amp;quot;), you need to keep some informations from a game to another.&lt;br /&gt;
&lt;br /&gt;
This should be an exceptional situation: the legacy API is costing resources on Board Game Arena databases, and is slowing down the game setup process + game end of game process. Please do not use it for things like:&lt;br /&gt;
* keeping a player preference/settings (=&amp;gt; player preferences and game options should be used instead)&lt;br /&gt;
* keeping a statistics, a score, or a ranking, while it is not planned in the physical board game, or while there is no added value compared to BGA statistics / rankings.&lt;br /&gt;
&lt;br /&gt;
You should use it for:&lt;br /&gt;
* legacy games: when some components of the game has been altered in a previous game and should be kept as it is.&lt;br /&gt;
* &amp;quot;campaign style&amp;quot; games: when a player is getting a &amp;quot;reward&amp;quot; at the end of a game, and should be able to use it in further games.&lt;br /&gt;
&lt;br /&gt;
Important: you cannot store more than 64k of data (serialized as JSON) per player per game. If you go over 64k, storeLegacyData function is going to FAIL, and there is a risk to create a major bug (= players blocked) in your game. You MUST make sure that no more than 64k of data is used for each player for your game. For example, if you are implementing a &amp;quot;campaign style&amp;quot; game and if you allow a player to start multiple campaign, you must LIMIT the number of different campaign so that the total data size to not go over the limit. We strongly recommend you to use this:&lt;br /&gt;
&lt;br /&gt;
  try &lt;br /&gt;
  {&lt;br /&gt;
  	$this-&amp;gt;storeLegacyTeamData( $my_data );&lt;br /&gt;
  }&lt;br /&gt;
  catch( feException $e ) // feException is a base class of BgaSystemException and others...&lt;br /&gt;
  {&lt;br /&gt;
  	if( $e-&amp;gt;getCode() == FEX_legacy_size_exceeded )&lt;br /&gt;
  	{&lt;br /&gt;
  		// Do something here to free some space in Legacy data (ex: by removing some variables)&lt;br /&gt;
  	}&lt;br /&gt;
  	else&lt;br /&gt;
  		throw $e;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
The keys may only contain letters and numbers, underscore seems not to be allowed.&lt;br /&gt;
&lt;br /&gt;
; function storeLegacyData( $player_id, $key, $data, $ttl = 365 )&lt;br /&gt;
: Store some data associated with $key for the given user / current game&lt;br /&gt;
: In the opposite of all other game data, this data will PERSIST after the end of this table, and can be re-used&lt;br /&gt;
: in a future table with the same game.&lt;br /&gt;
: IMPORTANT: The only possible place where you can use this method is when the game is over at your table (last game action). Otherwise, there is a risk of conflicts between ongoing games.    &lt;br /&gt;
: TTL is a time-to-live: the maximum, and default, is 365 days.&lt;br /&gt;
: In any way, the total data (= all keys) you can store for a given user+game is 64k (note: data is store serialized as JSON data)&lt;br /&gt;
: NOTICE: You can store some persistant data across all tables from your game using the specific player_id 0 which is unused. In such case, it&#039;s even more important to manage correctly the size of your data to avoid any exception or issue while storing updated data (ie. you can use this for some kind of leaderbord for solo game or contest)&lt;br /&gt;
: Note: This function cannot be called during game setup (will throw an error).&lt;br /&gt;
&lt;br /&gt;
; function retrieveLegacyData( $player_id, $key )&lt;br /&gt;
: Get data associated with $key for the current game&lt;br /&gt;
: This data is common to ALL tables from the same game for this player, and persist from one table to another.&lt;br /&gt;
: Note: calling this function has an important cost =&amp;gt; please call it few times (possibly: only ONCE) for each player for 1 game if possible&lt;br /&gt;
: Note: you can use &#039;%&#039; in $key to retrieve all keys matching the given patterns&lt;br /&gt;
&lt;br /&gt;
; function removeLegacyData( $player_id, $key )&lt;br /&gt;
: Remove some legacy data with the given key&lt;br /&gt;
: (useful to free some data to avoid going over 64k)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; function storeLegacyTeamData( $data, $ttl = 365 )&lt;br /&gt;
: Same as storeLegacyData, except that it stores some data for the whole team within the current table and does not use a key&lt;br /&gt;
: Ie: if players A, B and C are at a table, the legacy data will be saved for future table with (exactly) A, B and C on the table.&lt;br /&gt;
: This is useful for games which are intended to be played several time by the same team.&lt;br /&gt;
: Note: the data total size is still limited, so you must implement catch the FEX_legacy_size_exceeded exception if it happens&lt;br /&gt;
&lt;br /&gt;
; function retrieveLegacyTeamData()&lt;br /&gt;
: Same as retrieveLegacyData, except that it retrieves some data for the whole team within the current table (set by storeLegacyTeamData)&lt;br /&gt;
&lt;br /&gt;
; function removeLegacyTeamData()&lt;br /&gt;
: Same as removeLegacyData, except that it retrieves some data for the whole team within the current table (set by storeLegacyTeamData)&lt;br /&gt;
&lt;br /&gt;
== Players text input and moderation ==&lt;br /&gt;
This section concerns only games where the players have to write some words to play: games based on words, like &amp;quot;Just one&amp;quot; or &amp;quot;Codenames&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Some players will use your game to write insults or profanities. As this is part of the game and not in the game chat, these words cannot be reported by players and moderated.&lt;br /&gt;
&lt;br /&gt;
If you met the following situation:&lt;br /&gt;
&lt;br /&gt;
* You are asking a player to type a text (word(s) or sentence)&lt;br /&gt;
* The player can enter any text (this is not a pre-selection or anything you can control)&lt;br /&gt;
* This text is visible by at least one other player&lt;br /&gt;
&lt;br /&gt;
Then, you must use the following method:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;function logTextForModeration( $player_id, $text )&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
player_id = player who write the text&lt;br /&gt;
&lt;br /&gt;
text = text that has been written&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This function will have no visible consequence for your game, but will allow players to report the text to moderators if something happens.&lt;br /&gt;
&lt;br /&gt;
== Language dependent games API ==&lt;br /&gt;
&lt;br /&gt;
This API is used for games that are heavily language dependent. Two most common use cases are:&lt;br /&gt;
* Games that have a language dependent component that are not necessarily translatable, typically a list of words. (Think of games like Codenames, Decrypto, Just One...)&lt;br /&gt;
* Games with massive communication where players would like to ensure that all participants speak the same language. (Think of games like Werewolf, The Resistance, maybe even dixit...)&lt;br /&gt;
&lt;br /&gt;
If this option is used, the table created will be limited only to users that have specific language in their profile. Player starting the game would be able to chose one of the languages they speak.&lt;br /&gt;
&lt;br /&gt;
There is a new property language_dependency in gameinfos.inc.php which can be set like this:&lt;br /&gt;
  &#039;language_dependency&#039; =&amp;gt; false,  //or if the property is missing, the game is not language dependent&lt;br /&gt;
  &#039;language_dependency&#039; =&amp;gt; true, //all players at the table must speak the same language&lt;br /&gt;
  &#039;language_dependency&#039; =&amp;gt; array( 1 =&amp;gt; &#039;en&#039;, 2 =&amp;gt; &#039;fr&#039;, 3 =&amp;gt; &#039;it&#039; ), //1-based list of supported languages&lt;br /&gt;
&lt;br /&gt;
In the gamename.game.php file, you can get the id of selected language with the method &#039;&#039;&#039;getGameLanguage&#039;&#039;&#039;.&lt;br /&gt;
; function getGameLanguage()&lt;br /&gt;
: Returns an index of the selected language as defined in gameinfos.inc.php.&lt;br /&gt;
&lt;br /&gt;
Languages currently available on BGA are:&lt;br /&gt;
  &#039;ar&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;العربية&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ar_AE&#039; ),             // Arabic&lt;br /&gt;
  &#039;be&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;беларуская мова&amp;quot;, &#039;code&#039; =&amp;gt; &#039;be_BY&#039; ),     // Belarusian&lt;br /&gt;
  &#039;bn&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;বাংলা&amp;quot;, &#039;code&#039; =&amp;gt; &#039;bn_BD&#039; ),                // Bengali&lt;br /&gt;
  &#039;bg&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;български език&amp;quot;, &#039;code&#039; =&amp;gt; &#039;bg_BG&#039; ),      // Bulgarian&lt;br /&gt;
  &#039;ca&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;català&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ca_ES&#039; ),              // Catalan&lt;br /&gt;
  &#039;cs&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;čeština&amp;quot;, &#039;code&#039; =&amp;gt; &#039;cs_CZ&#039; ),             // Czech&lt;br /&gt;
  &#039;da&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;dansk&amp;quot;, &#039;code&#039; =&amp;gt; &#039;da_DK&#039; ),               // Danish&lt;br /&gt;
  &#039;de&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;deutsch&amp;quot;, &#039;code&#039; =&amp;gt; &#039;de_DE&#039; ),             // German&lt;br /&gt;
  &#039;el&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Ελληνικά&amp;quot;, &#039;code&#039; =&amp;gt; &#039;el_GR&#039; ),            // Greek&lt;br /&gt;
  &#039;en&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;English&amp;quot;, &#039;code&#039; =&amp;gt; &#039;en_US&#039; ),             // English&lt;br /&gt;
  &#039;es&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;español&amp;quot;, &#039;code&#039; =&amp;gt; &#039;es_ES&#039; ),             // Spanish&lt;br /&gt;
  &#039;et&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;eesti keel&amp;quot;, &#039;code&#039; =&amp;gt; &#039;et_EE&#039; ),          // Estonian       &lt;br /&gt;
  &#039;fi&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;suomi&amp;quot;, &#039;code&#039; =&amp;gt; &#039;fi_FI&#039; ),               // Finnish&lt;br /&gt;
  &#039;fr&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;français&amp;quot;, &#039;code&#039; =&amp;gt; &#039;fr_FR&#039; ),            // French&lt;br /&gt;
  &#039;he&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;עברית&amp;quot;, &#039;code&#039; =&amp;gt; &#039;he_IL&#039; ),               // Hebrew       &lt;br /&gt;
  &#039;hi&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;हिन्दी&amp;quot;, &#039;code&#039; =&amp;gt; &#039;hi_IN&#039; ),                 // Hindi&lt;br /&gt;
  &#039;hr&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Hrvatski&amp;quot;, &#039;code&#039; =&amp;gt; &#039;hr_HR&#039; ),            // Croatian&lt;br /&gt;
  &#039;hu&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;magyar&amp;quot;, &#039;code&#039; =&amp;gt; &#039;hu_HU&#039; ),              // Hungarian&lt;br /&gt;
  &#039;id&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Bahasa Indonesia&amp;quot;, &#039;code&#039; =&amp;gt; &#039;id_ID&#039; ),    // Indonesian&lt;br /&gt;
  &#039;ms&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Bahasa Malaysia&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ms_MY&#039; ),     // Malaysian&lt;br /&gt;
  &#039;it&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;italiano&amp;quot;, &#039;code&#039; =&amp;gt; &#039;it_IT&#039; ),            // Italian&lt;br /&gt;
  &#039;ja&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;日本語&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ja_JP&#039; ),               // Japanese&lt;br /&gt;
  &#039;jv&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Basa Jawa&amp;quot;, &#039;code&#039; =&amp;gt; &#039;jv_JV&#039; ),           // Javanese                       &lt;br /&gt;
  &#039;ko&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;한국어&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ko_KR&#039; ),               // Korean&lt;br /&gt;
  &#039;lt&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;lietuvių&amp;quot;, &#039;code&#039; =&amp;gt; &#039;lt_LT&#039; ),            // Lithuanian&lt;br /&gt;
  &#039;lv&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;latviešu&amp;quot;, &#039;code&#039; =&amp;gt; &#039;lv_LV&#039; ),            // Latvian&lt;br /&gt;
  &#039;nl&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;nederlands&amp;quot;, &#039;code&#039; =&amp;gt; &#039;nl_NL&#039; ),          // Dutch&lt;br /&gt;
  &#039;no&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;norsk&amp;quot;, &#039;code&#039; =&amp;gt; &#039;nb_NO&#039; ),               // Norwegian&lt;br /&gt;
  &#039;oc&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;occitan&amp;quot;, &#039;code&#039; =&amp;gt; &#039;oc_FR&#039; ),             // Occitan&lt;br /&gt;
  &#039;pl&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;polski&amp;quot;, &#039;code&#039; =&amp;gt; &#039;pl_PL&#039; ),              // Polish&lt;br /&gt;
  &#039;pt&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;português&amp;quot;,  &#039;code&#039; =&amp;gt; &#039;pt_PT&#039; ),          // Portuguese&lt;br /&gt;
  &#039;ro&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;română&amp;quot;,  &#039;code&#039; =&amp;gt; &#039;ro_RO&#039;  ),            // Romanian&lt;br /&gt;
  &#039;ru&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Русский язык&amp;quot;, &#039;code&#039; =&amp;gt; &#039;ru_RU&#039; ),        // Russian&lt;br /&gt;
  &#039;sk&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;slovenčina&amp;quot;, &#039;code&#039; =&amp;gt; &#039;sk_SK&#039; ),          // Slovak&lt;br /&gt;
  &#039;sl&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;slovenščina&amp;quot;, &#039;code&#039; =&amp;gt; &#039;sl_SI&#039; ),         // Slovenian       &lt;br /&gt;
  &#039;sr&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Српски&amp;quot;, &#039;code&#039; =&amp;gt; &#039;sr_RS&#039; ),              // Serbian       &lt;br /&gt;
  &#039;sv&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;svenska&amp;quot;, &#039;code&#039; =&amp;gt; &#039;sv_SE&#039; ),             // Swedish&lt;br /&gt;
  &#039;tr&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Türkçe&amp;quot;, &#039;code&#039; =&amp;gt; &#039;tr_TR&#039; ),              // Turkish       &lt;br /&gt;
  &#039;uk&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;Українська мова&amp;quot;, &#039;code&#039; =&amp;gt; &#039;uk_UA&#039; ),     // Ukrainian&lt;br /&gt;
  &#039;zh&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;中文 (漢)&amp;quot;,  &#039;code&#039; =&amp;gt; &#039;zh_TW&#039; ),           // Traditional Chinese (Hong Kong, Macau, Taiwan)&lt;br /&gt;
  &#039;zh-cn&#039; =&amp;gt; array( &#039;name&#039; =&amp;gt; &amp;quot;中文 (汉)&amp;quot;, &#039;code&#039; =&amp;gt; &#039;zh_CN&#039; ),         // Simplified Chinese (Mainland China, Singapore)&lt;br /&gt;
&lt;br /&gt;
== Debugging and Tracing ==&lt;br /&gt;
&lt;br /&gt;
To debug php code you can use some tracing functions available from the parent class such as debug, trace, error, warn, dump.&lt;br /&gt;
  &lt;br /&gt;
  $this-&amp;gt;debug(&amp;quot;Ahh!&amp;quot;);&lt;br /&gt;
  $this-&amp;gt;dump(&#039;my_var&#039;,$my_var);&lt;br /&gt;
&lt;br /&gt;
See [[Practical_debugging]] section for complete information about debugging interfaces and where to find logs.&lt;br /&gt;
&lt;br /&gt;
== PHP 8 upgrade ==&lt;br /&gt;
&lt;br /&gt;
See [[PHP 8 upgrade]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_earth&amp;diff=20793</id>
		<title>Tips earth</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_earth&amp;diff=20793"/>
		<updated>2024-04-15T00:06:53Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: /* Ecosystem / Terrain */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
Earth is an engine building resource management with min-max/optimization at its core.  There are numerous factors to consider for every decision.  This is overwhelming at first, but as you play more you start recognizing more and more factors and begin to understand how to weigh them against each other.  Some decisions come down to card knowledge.  E.g. where do I place this card now to account for a maximum number of future drawn cards that consider position?  The most weight should be placed on factors that exist now, but the best players will eek out edges by considering potential future factors too.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Note that this advice is largely geared toward 2-player games because this is the competitive format.&lt;br /&gt;
&lt;br /&gt;
== Which action to pick? ==&lt;br /&gt;
&lt;br /&gt;
=== Planting ===&lt;br /&gt;
&lt;br /&gt;
The highest interaction point of Earth is on planting.  Whoever completes their board first not only gets 7 bonus points (you should think of this as a 14-point swing in 2-player games because zero-sum), but also is setting the pace for the game.  This principle rules in most if not all games where the end criteria is determined by some form of board completion - the player who is ahead on completion status is controlling the pace of the game and *much* more likely to win.  If you have two things that you can Plant and a fairly high likelihood of being able to follow your opponent&#039;s Plant action (consider that you get to choose 1 of 4 which is fairly likely to yield a cheap option) then you should do it.  At its core, there is a race happening in this game and the player who picks Plant more frequently is winning it.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
This leads us into the next question: what should I plant and where?  Early in the game, the answer is usually &amp;quot;whatever you have&amp;quot;.  But later in the game as you get more cards, the answer becomes more nuanced.&lt;br /&gt;
&lt;br /&gt;
==== Engine ====&lt;br /&gt;
&lt;br /&gt;
• Green cards are very good.  Plant is the most picked action so anything extra you can do in response to Planting is guaranteed money in the bank.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• After Green, the best actions are those that let you do more Planting.  Some consideration should be given to &amp;quot;what color does my opponent have a lot of and is thus more likely to pick?&amp;quot;  If you Plant actions of that color, then you can get more &amp;quot;follow&amp;quot; bonuses.  But as we&#039;ve already said, they should be picking Plant as often as possible so this is less important than: &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• &amp;quot;What do I want to do if I can&#039;t plant?&amp;quot;  The answer is either get more cards or get more soil.  Ideally both.  So the best thing you can do is add card draw to your Red/Blue action OR add Soil gain to your Yellow action.  Then when you can&#039;t Plant, use the action that lets you double-dip on Soil and card draw.  &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Don&#039;t forget that Sprouts are just inefficient soil (3-&amp;gt;2) so the Blue action actually yields *6* Soil, 1 MORE than Red at the cost of 2 Compost (assuming you have the prerequisite number of open Sprout places, but you can always convert them to Soil beforehand).  Until the late game, you should be using your sprouts for soil whenever you need it to do more Planting.  In the late game you have to weigh the points lost in Sprouts against the extra points gained from planting a &amp;quot;better&amp;quot; card.&lt;br /&gt;
&lt;br /&gt;
==== Fauna ====&lt;br /&gt;
&lt;br /&gt;
This is the second highest interaction element of Earth after Planting.  The player who first achieves each goal is getting +4 points (8-point swing for 2-player).  While less important than Plant-maxing, this is still a considerable difference.  And you know about all Fauna from the start of the game so it should immediately begin impacting all of your decisions adding a little bit of weight to Plant each card that matches some Fauna conditions especially for those that match multiple.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Even if you lose the race to a Fauna, it&#039;s still 11 points which weighs pretty heavily.  It can still be correct to give up or forgo Fauna, just depends on the options being weighed.&lt;br /&gt;
&lt;br /&gt;
==== Ecosystem / Terrain ====&lt;br /&gt;
&lt;br /&gt;
These are being lumped together because they&#039;re effectively the same thing.  There is no race with the opponent so they amount to solo goals.  Ecosystems are known from the start so you can immediately start factoring them into what you play whereas Terrain can be drawn at any point in the game.  This is why card knowledge is important.  You cannot *rely* on getting a specific Terrain, but if you&#039;ve accounted for it with your board positioning, then you&#039;ve set yourself up for additional beneficial scenarios if you get lucky.  Success is when preparation meets opportunity :)&lt;br /&gt;
&lt;br /&gt;
==== Where? ====&lt;br /&gt;
&lt;br /&gt;
Considerations for where to Plant each card are fairly limited, but this is a potential area for gaining an edge in close games:&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Stay open as long as reasonably possible.  Once you have a row or column of length 4, your board is &amp;quot;locked&amp;quot;.  Until then you have the freedom to plant in more positions.  Maintaining this freedom can net you better opportunities later in the game.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Most important is Ecosystems and Terrain that have already been played or you have in hand and plan to play over the course of the game.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• After that is logical order of resolution.  You want to draw cards before you have to Compost from your hand via some other action.  Secondary to that are things like gaining Growth/Sprouts to later spend in your turn for costs, but you will almost always already have this so you can simply replace it later in the turn.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Then the last consideration is what position-based Terrain cards could I draw into later in the game that I want to be able to play?  I still don&#039;t know all the cards, but ones that come to mind are the Habitat-based &amp;quot;path&amp;quot; cards (draw a line of cards that share a habitat) and the plant-type directionals (in this row, in this column, orthogonally adjacent, etc).  It is impossible to account for every Terrain, but accounting for as many as possible will help you win more games&lt;br /&gt;
&lt;br /&gt;
=== Not Planting (anything else) ===&lt;br /&gt;
&lt;br /&gt;
See the Engine section above.  None of the actions are bad, but what to pick just depends on what you and the opponent have already played.  Always look at your opponent&#039;s board - don&#039;t pick actions that help your opponent more than they help you.  You&#039;re typically only even considering this if you can&#039;t pick Plant or if you&#039;re in a late game situation where you can dominate your opponent on points per action.&lt;br /&gt;
&lt;br /&gt;
== End Game ==&lt;br /&gt;
&lt;br /&gt;
As the end of the game approaches (one player has 3 empty spaces on the board), there are new important considerations.  &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Double check who went first.  If the second/last player completes their board, then the game ends after their turn.  Otherwise everyone after that player gets another turn.  Make sure you factor this into your plans for what you want to Plant before the game ends. &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Tally up your Terrain and Ecosystem goals.  Many of these give points based on sets/pairs/trios.  If you&#039;re close to one of these thresholds (e.g. odd number for a pair-based bonus), add some priority to getting that last item.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• There is a lot of nuance around picking Plant later in the game depending on who is winning the race and how many empty spaces each player has left.  The ideal scenario is one in which you have 1 empty space and your opponent has at least 3 empty spaces.  The key to manufacturing this game state is to Plant early and often which is why this is emphasized so heavily&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Example 1: you have 3 empty board spaces and your opponent has 4.  If you pick Plant then the result is you have 1 and opponent has 3.  This is good because if your opponent picks Plant, you get the 7-point bonus and the game will end.  A similar scenario occurs even if it is your opponent&#039;s turn.  They Plant down to 2 empty spaces as do you.  You can pick your final Plant, get the 7 points, and the opponent only has 1 empty spot at which point the game ends if you&#039;re second or they can do one last &amp;quot;inefficient&amp;quot; Plant action for the last space.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Example 2: you have 2 empty and your opponent has 3 and it&#039;s your turn.  If you went second then picking Plant ends the game - great.  But if you went first, then your opponent is effectively given a &amp;quot;free&amp;quot; Plant where you cannot follow.  You plant to 0 empty, opponent is at 2, then they can Plant again while you can&#039;t.  A notably exception to this is if you have some Terrain that lets you replace it with a Plant from your hand.  Choosing not to plant is just as bad because you now have to pick an &amp;quot;inefficient&amp;quot; last Plant of 1 or forgo the 7-point bonus entirely.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Example 3: you both have 3 empty board spaces.  This is a standoff position.  Neither player wants to Plant because the result is that the opponent will win the 7-point bonus (tie for completion on the same turn goes to turn-player).  Whoever has the bigger engine is favored here.  By that we mean some combination of Sprout/Growth room and the resulting points per action noting that Compost and some specific Terrain bonuses do not have limits (e.g. 1 point per card in hand).&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
&lt;br /&gt;
Hope this is helpful to some people.  I have still not played many Earth games, but it clearly has high strategic depth.  You may or may not find that depth to be interesting as the highest levels of play emphasize deep knowledge of all the cards, but there&#039;s a lot of room for interesting decisions leading up to that level.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=20506</id>
		<title>Troubleshooting</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Troubleshooting&amp;diff=20506"/>
		<updated>2024-03-17T21:32:07Z</updated>

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

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

		<summary type="html">&lt;p&gt;Fletcheese: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
Earth is an engine building resource management with min-max/optimization at its core.  There are numerous factors to consider for every decision.  This is overwhelming at first, but as you play more you start recognizing more and more factors and begin to understand how to weigh them against each other.  Some decisions come down to card knowledge.  E.g. where do I place this card now to account for a maximum number of future drawn cards that consider position?  The most weight should be placed on factors that exist now, but the best players will eek out edges by considering potential future factors too.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Note that this advice is largely geared toward 2-player games because this is the competitive format.&lt;br /&gt;
&lt;br /&gt;
== Which action to pick? ==&lt;br /&gt;
&lt;br /&gt;
=== Planting ===&lt;br /&gt;
&lt;br /&gt;
The highest interaction point of Earth is on planting.  Whoever completes their board first not only gets 7 bonus points (you should think of this as a 14-point swing in 2-player games because zero-sum), but also is setting the pace for the game.  This principle rules in most if not all games where the end criteria is determined by some form of board completion - the player who is ahead on completion status is controlling the pace of the game and *much* more likely to win.  If you have two things that you can Plant and a fairly high likelihood of being able to follow your opponent&#039;s Plant action (consider that you get to choose 1 of 4 which is fairly likely to yield a cheap option) then you should do it.  At its core, there is a race happening in this game and the player who picks Plant more frequently is winning it.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
This leads us into the next question: what should I plant and where?  Early in the game, the answer is usually &amp;quot;whatever you have&amp;quot;.  But later in the game as you get more cards, the answer becomes more nuanced.&lt;br /&gt;
&lt;br /&gt;
==== Engine ====&lt;br /&gt;
&lt;br /&gt;
• Green cards are very good.  Plant is the most picked action so anything extra you can do in response to Planting is guaranteed money in the bank.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• After Green, the best actions are those that let you do more Planting.  Some consideration should be given to &amp;quot;what color does my opponent have a lot of and is thus more likely to pick?&amp;quot;  If you Plant actions of that color, then you can get more &amp;quot;follow&amp;quot; bonuses.  But as we&#039;ve already said, they should be picking Plant as often as possible so this is less important than: &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• &amp;quot;What do I want to do if I can&#039;t plant?&amp;quot;  The answer is either get more cards or get more soil.  Ideally both.  So the best thing you can do is add card draw to your Red/Blue action OR add Soil gain to your Yellow action.  Then when you can&#039;t Plant, use the action that lets you double-dip on Soil and card draw.  &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Don&#039;t forget that Sprouts are just inefficient soil (3-&amp;gt;2) so the Blue action actually yields *6* Soil, 1 MORE than Red at the cost of 2 Compost (assuming you have the prerequisite number of open Sprout places, but you can always convert them to Soil beforehand).  Until the late game, you should be using your sprouts for soil whenever you need it to do more Planting.  In the late game you have to weigh the points lost in Sprouts against the extra points gained from planting a &amp;quot;better&amp;quot; card.&lt;br /&gt;
&lt;br /&gt;
==== Fauna ====&lt;br /&gt;
&lt;br /&gt;
This is the second highest interaction element of Earth after Planting.  The player who first achieves each goal is getting +4 points (8-point swing for 2-player).  While less important than Plant-maxing, this is still a considerable difference.  And you know about all Fauna from the start of the game so it should immediately begin impacting all of your decisions adding a little bit of weight to Plant each card that matches some Fauna conditions especially for those that match multiple.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Even if you lose the race to a Fauna, it&#039;s still 11 points which weighs pretty heavily.  It can still be correct to give up or forgo Fauna, just depends on the options being weighed.&lt;br /&gt;
&lt;br /&gt;
==== Ecosystem / Terrain ====&lt;br /&gt;
&lt;br /&gt;
These are being lumped together because they&#039;re effectively the same thing.  There is no race with the opponent so they amount to solo goals.  Ecosystems are known from the start so you can immediately start factoring them into what you play whereas Terrain can be drawn at any point in the game.  This is why card knowledge is important.  You cannot *rely* on getting a specific Terrain, but if you&#039;ve accounted for it with your board positioning, then you&#039;ve set yourself up for additional beneficial scenarios if you get lucky.  Success is when luck meets opportunity :)&lt;br /&gt;
&lt;br /&gt;
==== Where? ====&lt;br /&gt;
&lt;br /&gt;
Considerations for where to Plant each card are fairly limited, but this is a potential area for gaining an edge in close games:&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Stay open as long as reasonably possible.  Once you have a row or column of length 4, your board is &amp;quot;locked&amp;quot;.  Until then you have the freedom to plant in more positions.  Maintaining this freedom can net you better opportunities later in the game.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Most important is Ecosystems and Terrain that have already been played or you have in hand and plan to play over the course of the game.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• After that is logical order of resolution.  You want to draw cards before you have to Compost from your hand via some other action.  Secondary to that are things like gaining Growth/Sprouts to later spend in your turn for costs, but you will almost always already have this so you can simply replace it later in the turn.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Then the last consideration is what position-based Terrain cards could I draw into later in the game that I want to be able to play?  I still don&#039;t know all the cards, but ones that come to mind are the Habitat-based &amp;quot;path&amp;quot; cards (draw a line of cards that share a habitat) and the plant-type directionals (in this row, in this column, orthogonally adjacent, etc).  It is impossible to account for every Terrain, but accounting for as many as possible will help you win more games&lt;br /&gt;
&lt;br /&gt;
=== Not Planting (anything else) ===&lt;br /&gt;
&lt;br /&gt;
See the Engine section above.  None of the actions are bad, but what to pick just depends on what you and the opponent have already played.  Always look at your opponent&#039;s board - don&#039;t pick actions that help your opponent more than they help you.  You&#039;re typically only even considering this if you can&#039;t pick Plant or if you&#039;re in a late game situation where you can dominate your opponent on points per action.&lt;br /&gt;
&lt;br /&gt;
== End Game ==&lt;br /&gt;
&lt;br /&gt;
As the end of the game approaches (one player has 3 empty spaces on the board), there are new important considerations.  &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Double check who went first.  If the second/last player completes their board, then the game ends after their turn.  Otherwise everyone after that player gets another turn.  Make sure you factor this into your plans for what you want to Plant before the game ends. &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Tally up your Terrain and Ecosystem goals.  Many of these give points based on sets/pairs/trios.  If you&#039;re close to one of these thresholds (e.g. odd number for a pair-based bonus), add some priority to getting that last item.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• There is a lot of nuance around picking Plant later in the game depending on who is winning the race and how many empty spaces each player has left.  The ideal scenario is one in which you have 1 empty space and your opponent has at least 3 empty spaces.  The key to manufacturing this game state is to Plant early and often which is why this is emphasized so heavily&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Example 1: you have 3 empty board spaces and your opponent has 4.  If you pick Plant then the result is you have 1 and opponent has 3.  This is good because if your opponent picks Plant, you get the 7-point bonus and the game will end.  A similar scenario occurs even if it is your opponent&#039;s turn.  They Plant down to 2 empty spaces as do you.  You can pick your final Plant, get the 7 points, and the opponent only has 1 empty spot at which point the game ends if you&#039;re second or they can do one last &amp;quot;inefficient&amp;quot; Plant action for the last space.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Example 2: you have 2 empty and your opponent has 3 and it&#039;s your turn.  If you went second then picking Plant ends the game - great.  But if you went first, then your opponent is effectively given a &amp;quot;free&amp;quot; Plant where you cannot follow.  You plant to 0 empty, opponent is at 2, then they can Plant again while you can&#039;t.  A notably exception to this is if you have some Terrain that lets you replace it with a Plant from your hand.  Choosing not to plant is just as bad because you now have to pick an &amp;quot;inefficient&amp;quot; last Plant of 1 or forgo the 7-point bonus entirely.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Example 3: you both have 3 empty board spaces.  This is a standoff position.  Neither player wants to Plant because the result is that the opponent will win the 7-point bonus (tie for completion on the same turn goes to turn-player).  Whoever has the bigger engine is favored here.  By that we mean some combination of Sprout/Growth room and the resulting points per action noting that Compost and some specific Terrain bonuses do not have limits (e.g. 1 point per card in hand).&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
&lt;br /&gt;
Hope this is helpful to some people.  I have still not played many Earth games, but it clearly has high strategic depth.  You may or may not find that depth to be interesting as the highest levels of play emphasize deep knowledge of all the cards, but there&#039;s a lot of room for interesting decisions leading up to that level.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_barenpark&amp;diff=19595</id>
		<title>Tips barenpark</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_barenpark&amp;diff=19595"/>
		<updated>2024-01-17T23:25:01Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bärenpark is mostly about tactics rather than long term strategy. The two key points are: 1) be efficient filling your park, and 2) pay attention to what your opponents are doing.&lt;br /&gt;
&lt;br /&gt;
== Be efficient ==&lt;br /&gt;
&lt;br /&gt;
Being efficient at filling up your park means things that you may have already realised if you&#039;ve been playing Bärenpark for a while such as:&lt;br /&gt;
&lt;br /&gt;
a) Never end your turn without a tile in hand that you can place on your next turn. &lt;br /&gt;
&lt;br /&gt;
b) Minimize the number of 1 square holes you end up.  Typically if you are forced into taking a 1 square piece to fill a gap, then that means you made a mistake.  Review your game and try to play more flexibly&lt;br /&gt;
&lt;br /&gt;
c) Take the best tile you can. While you are allowed to pick up a tile from a lower tier when you cover up an orange excavator or white cement truck, this is always the wrong decision unless the supply has run out. You should plan ahead to ensure that you are able to play maximum value pieces&lt;br /&gt;
&lt;br /&gt;
d) Use the &amp;quot;try mode&amp;quot; to help you work out how you can best fit tiles in your park efficiently. &lt;br /&gt;
&lt;br /&gt;
e) Think carefully about how you place your new park areas. You probably want to cover up either the orange excavator and/or the white cement mixers quickly. Getting early pick of the enclosure tiles means getting more choice of shapes and tiles worth more points. Similarly being able to get more than your share of animal houses can give you a significant advantage over your opponent/s.&lt;br /&gt;
&lt;br /&gt;
f) Try to remain flexible and leave yourself open to multiple options for efficiently filling up your remaining space, when possible. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beginners quite often overvalue completing park areas for the bear statues points. The difference between a bear statue and the one underneath it is only 1 point (or 2 points in 2p which amounts to a 4p swing because zero-sum). You don&#039;t want to ignore this entirely but putting off completing an area for a few turns may allow you to get more points from claiming achievements or getting higher value animal houses (3p diff, 6p swing for 2-player) and enclosures than you would&#039;ve got from getting an earlier bear statue. The real trick is to know when to do this which leads into point 2...&lt;br /&gt;
&lt;br /&gt;
== Pay attention to what your opponents are doing ==&lt;br /&gt;
&lt;br /&gt;
All the ways to score points in Bärenpark are potentially worth more points the earlier you do them (achievements, bear statues, animal houses &amp;amp; enclosures). But it&#039;s just not possible to be quick at all of these at once. Take a quick moment to assess your opponents&#039; boards and the supply. What are your opponents working towards? What tiles in the supply might be gone before your next turn? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No matter what an opponent is focusing on, they will be neglecting something else. Or even better, you may see an opportunity where you can beat them to an achievement they&#039;ve been working towards and then they&#039;ll have to settle for a lower amount of points for it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Generally the best time to claim any achievement (or bear statue) is the exact turn before your opponent is about to get it. If there&#039;s no way your opponents can beat you to the achievement you&#039;ve been working towards before your next turn, it may be worth doing something else with this turn and claiming the achievement next turn instead. But remember to always be efficient at filling up your park too.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_barenpark&amp;diff=19594</id>
		<title>Tips barenpark</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_barenpark&amp;diff=19594"/>
		<updated>2024-01-17T23:23:16Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Clarifying some language&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bärenpark is mostly about tactics rather than long term strategy. The two key points are: 1) be efficient filling your park, and 2) pay attention to what your opponents are doing.&lt;br /&gt;
&lt;br /&gt;
== Be efficient ==&lt;br /&gt;
&lt;br /&gt;
Being efficient at filling up your park means things that you may have already realised if you&#039;ve been playing Bärenpark for a while such as:&lt;br /&gt;
&lt;br /&gt;
a) Never end your turn without a tile in hand that you can place on your next turn. &lt;br /&gt;
&lt;br /&gt;
b) Minimize the number of 1 square holes you end up.  Typically if you are forced into taking a 1 square piece to fill a gap, then that means you made a mistake.  Review your game and try to play more flexibly&lt;br /&gt;
&lt;br /&gt;
c) Take the best tile you can. While you are allowed to pick up a tile from a lower tier when you cover up an orange excavator or white cement truck, this is always the wrong decision unless the supply has run out. You should plan ahead to ensure that you are able to play maximum value pieces&lt;br /&gt;
&lt;br /&gt;
d) Use the &amp;quot;try mode&amp;quot; to help you work out how you can best fit tiles in your park efficiently. &lt;br /&gt;
&lt;br /&gt;
e) Think carefully about how you place your new park areas. You probably want to cover up either the orange excavator and/or the white cement mixers quickly. Getting early pick of the enclosure tiles means getting more choice of shapes and tiles worth more points. Similarly being able to get more than your share of animal houses can give you a significant advantage over your opponent/s.&lt;br /&gt;
&lt;br /&gt;
f) Try to remain flexible and leave yourself open to multiple options for efficiently filling up your remaining space, when possible. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Beginners quite often overvalue completing park areas for the bear statues points. The difference between a bear statue and the one underneath it is only 1 point (or 2 points in 2p). You don&#039;t want to ignore this entirely but putting off completing an area for a few turns may allow you to get more points from claiming achievements or getting higher value animal houses and enclosures than you would&#039;ve got from getting an earlier bear statue. The real trick is to know when to do this which leads into point 2...&lt;br /&gt;
&lt;br /&gt;
== Pay attention to what your opponents are doing ==&lt;br /&gt;
&lt;br /&gt;
All the ways to score points in Bärenpark are potentially worth more points the earlier you do them (achievements, bear statues, animal houses &amp;amp; enclosures). But it&#039;s just not possible to be quick at all of these at once. Take a quick moment to assess your opponents&#039; boards and the supply. What are your opponents working towards? What tiles in the supply might be gone before your next turn? &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
No matter what an opponent is focusing on, they will be neglecting something else. Or even better, you may see an opportunity where you can beat them to an achievement they&#039;ve been working towards and then they&#039;ll have to settle for a lower amount of points for it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Generally the best time to claim any achievement (or bear statue) is the exact turn before your opponent is about to get it. If there&#039;s no way your opponents can beat you to the achievement you&#039;ve been working towards before your next turn, it may be worth doing something else with this turn and claiming the achievement next turn instead. But remember to always be efficient at filling up your park too.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_earth&amp;diff=19511</id>
		<title>Tips earth</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_earth&amp;diff=19511"/>
		<updated>2024-01-10T17:43:21Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Initial creation with general strategy&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
Earth is an engine building resource management with min-max/optimization at its core.  There are numerous factors to consider for every decision.  This is overwhelming at first, but as you play more you start recognizing more and more factors and begin to understand how to weigh them against each other.  Some decisions come down to card knowledge.  E.g. where do I place this card now to account for a maximum number of future drawn cards that consider position?  The most weight should be placed on factors that exist now, but the best players will eek out edges by considering potential future factors too.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Note that this advice is largely geared toward 2-player games because this is the competitive format.&lt;br /&gt;
&lt;br /&gt;
== Which action to pick? ==&lt;br /&gt;
&lt;br /&gt;
=== Planting ===&lt;br /&gt;
&lt;br /&gt;
The highest interaction point of Earth is on planting.  Whoever completes their board first not only gets 7 bonus points (you should think of this as a 14-point swing in 2-player games because zero-sum), but also is setting the pace for the game.  This principle rules in most if not all games where the end criteria is determined by some form of board completion - the player who is ahead on completion status is controlling the pace of the game and *much* more likely to win.  If you have two things that you can Plant and a fairly high likelihood of being able to follow your opponent&#039;s Plant action (consider that you get to choose 1 of 4 which is fairly likely to yield a cheap option) then you should do it.  At its core, there is a race happening in this game and the player who picks Plant more frequently is winning it.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
This leads us into the next question: what should I plant and where?  Early in the game, the answer is usually &amp;quot;whatever you have&amp;quot;.  But later in the game as you get more cards, the answer becomes more nuanced.&lt;br /&gt;
&lt;br /&gt;
==== Engine ====&lt;br /&gt;
&lt;br /&gt;
• Green cards are very good.  Plant is the most picked action so anything extra you can do in response to Planting is guaranteed money in the bank.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• After Green, the best actions are those that let you do more Planting.  Some consideration should be given to &amp;quot;what color does my opponent have a lot of and is thus more likely to pick?&amp;quot;  If you Plant actions of that color, then you can get more &amp;quot;follow&amp;quot; bonuses.  But as we&#039;ve already said, they should be picking Plant as often as possible so this is less important than: &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• &amp;quot;What do I want to do if I can&#039;t plant?&amp;quot;  The answer is either get more cards or get more soil.  Ideally both.  So the best thing you can do is add card draw to your Red/Blue action OR add Soil gain to your Yellow action.  Then when you can&#039;t Plant, use the action that lets you double-dip on Soil and card draw.  &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Don&#039;t forget that Sprouts are just inefficient soil (3-&amp;gt;2) so the Blue action actually yields *6* Soil, 1 MORE than Red at the cost of 2 Compost (assuming you have the prerequisite number of open Sprout places, but you can always convert them to Soil beforehand).  Until the late game, you should be using your sprouts for soil whenever you need it to do more Planting.  In the late game you have to weigh the points lost in Sprouts against the extra points gained from planting a &amp;quot;better&amp;quot; card.&lt;br /&gt;
&lt;br /&gt;
==== Fauna ====&lt;br /&gt;
&lt;br /&gt;
This is the second highest interaction element of Earth after Planting.  The player who first achieves each goal is getting +4 points (8-point swing for 2-player).  While less important than Plant-maxing, this is still a considerable difference.  And you know about all Fauna from the start of the game so it should immediately begin impacting all of your decisions adding a little bit of weight to Plant each card that matches some Fauna conditions especially for those that match multiple.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
Even if you lose the race to a Fauna, it&#039;s still 11 points which weighs pretty heavily.  It can still be correct to give up or forgo Fauna, just depends on the options being weighed.&lt;br /&gt;
&lt;br /&gt;
==== Ecosystem / Terrain ====&lt;br /&gt;
&lt;br /&gt;
These are being lumped together because they&#039;re effectively the same thing.  There is no race with the opponent so they amount to solo goals.  Ecosystems are known from the start so you can immediately start factoring them into what you play whereas Terrain can be drawn at any point in the game.  This is why card knowledge is important.  You cannot *rely* on getting a specific Terrain, but if you&#039;ve accounted for it with your board positioning, then you&#039;ve set yourself up for additional beneficial scenarios if you get lucky.  Success is when luck meets opportunity :)&lt;br /&gt;
&lt;br /&gt;
==== Where? ====&lt;br /&gt;
&lt;br /&gt;
Considerations for where to Plant each card are fairly limited, but this is a potential area for gaining an edge in close games:&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Stay open as long as reasonably possible.  Once you have a row or column of length 4, your board is &amp;quot;locked&amp;quot;.  Until then you have the freedom to plant in more positions.  Maintaining this freedom can net you better opportunities later in the game.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Most important is Ecosystems and Terrain that have already been played or you have in hand and plan to play over the course of the game.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• After that is logical order of resolution.  You want to draw cards before you have to Compost from your hand via some other action.  Secondary to that are things like gaining Growth/Sprouts to later spend in your turn for costs, but you will almost always already have this so you can simply replace it later in the turn.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Then the last consideration is what position-based Terrain cards could I draw into later in the game that I want to be able to play?  I still don&#039;t know all the cards, but ones that come to mind are the Habitat-based &amp;quot;path&amp;quot; cards (draw a line of cards that share a habitat) and the plant-type directionals (in this row, in this column, orthogonally adjacent, etc).  It is impossible to account for every Terrain, but accounting for as many as possible will help you win more games&lt;br /&gt;
&lt;br /&gt;
=== Not Planting (anything else) ===&lt;br /&gt;
&lt;br /&gt;
See the Engine section above.  None of the actions are bad, but what to pick just depends on what you and the opponent have already played.  Always look at your opponent&#039;s board - don&#039;t pick actions that help your opponent more than they help you.  You&#039;re typically only even considering this if you can&#039;t pick Plant.&lt;br /&gt;
&lt;br /&gt;
== End Game ==&lt;br /&gt;
&lt;br /&gt;
As the end of the game approaches (one player has 3 empty spaces on the board), there are new important considerations.  &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Double check who went first.  If the second/last player completes their board, then the game ends after their turn.  Otherwise everyone after that player gets another turn.  Make sure you factor this into your plans for what you want to Plant before the game ends. &lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• Tally up your Terrain and Ecosystem goals.  Many of these give points based on sets/pairs/trios.  If you&#039;re close to one of these thresholds (e.g. odd number for a pair-based bonus), add some priority to getting that last item.&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
• There is a lot of nuance around picking Plant later in the game depending on who is winning the race and how many empty spaces each player has left.  The ideal scenario is one in which you have 1 empty space and your opponent has at least 3 empty spaces.  The key to manufacturing this game state is to Plant early and often which is why this is emphasized so heavily&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Example 1: you have 3 empty board spaces and your opponent has 4.  If you pick Plant then the result is you have 1 and opponent has 3.  This is good because if your opponent picks Plant, you get the 7-point bonus and the game will end.  A similar scenario occurs even if it is your opponent&#039;s turn.  They Plant down to 2 empty spaces as do you.  You can pick your final Plant, get the 7 points, and the opponent only has 1 empty spot at which point the game ends if you&#039;re second or they can do one last &amp;quot;inefficient&amp;quot; Plant action for the last space.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Example 2: you have 2 empty and your opponent has 3 and it&#039;s your turn.  If you went second then picking Plant ends the game - great.  But if you went first, then your opponent is effectively given a &amp;quot;free&amp;quot; Plant where you cannot follow.  You plant to 0 empty, opponent is at 2, then they can Plant again while you can&#039;t.  A notably exception to this is if you have some Terrain that lets you replace it with a Plant from your hand.  Choosing not to plant is just as bad because you now have to pick an &amp;quot;inefficient&amp;quot; last Plant of 1 or forgo the 7-point bonus entirely.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Example 3: you both have 3 empty board spaces.  This is a standoff position.  Neither player wants to Plant because the result is that the opponent will win the 7-point bonus (tie for completion on the same turn goes to turn-player).  Whoever has the bigger engine is favored here.  By that we mean some combination of Sprout/Growth room and the resulting points per action noting that Compost and some specific Terrain bonuses do not have limits (e.g. 1 point per card in hand).&lt;br /&gt;
&lt;br /&gt;
=== Conclusion ===&lt;br /&gt;
&lt;br /&gt;
Hope this is helpful to some people.  I have still not played many Earth games, but it clearly has high strategic depth.  You may or may not find that depth to be interesting as the highest levels of play emphasize deep knowledge of all the cards, but there&#039;s a lot of room for interesting decisions leading up to that level.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_spacebase&amp;diff=18497</id>
		<title>Tips spacebase</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_spacebase&amp;diff=18497"/>
		<updated>2023-10-23T20:18:03Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Added 2 bullets&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Dice Statistics ==&lt;br /&gt;
The lower sectors are more likely to be activated than higher sectors, since players can select either individual die values or their sum:&lt;br /&gt;
* Sectors 1-6 will trigger much more often than 7-12, but rewards for higher sectors are typically better.&lt;br /&gt;
*The probability distribution of outcomes is:&lt;br /&gt;
** 1 &#039;&#039;(11%)&#039;&#039;, 2 &#039;&#039;(12%)&#039;&#039;, 3 &#039;&#039;(13%)&#039;&#039;, 4 &#039;&#039;(14%)&#039;&#039;, 5 &#039;&#039;(15%)&#039;&#039;, 6 &#039;&#039;(16%)&#039;&#039;, 7 &#039;&#039;(6%)&#039;&#039;, 8 &#039;&#039;(5%)&#039;&#039;, 9 &#039;&#039;(4%)&#039;&#039;, 10 &#039;&#039;(3%)&#039;&#039;, 11 &#039;&#039;(2%)&#039;&#039;, 12 &#039;&#039;(1%)&#039;&#039;&lt;br /&gt;
*These values expressed as the likelihood of getting an outcome based rolling two dice is:&lt;br /&gt;
** 1 &#039;&#039;(33%)&#039;&#039;, 2 &#039;&#039;(36%)&#039;&#039;, 3 &#039;&#039;(39%)&#039;&#039;, 4 &#039;&#039;(42%)&#039;&#039;, 5 &#039;&#039;(44%)&#039;&#039;, 6 &#039;&#039;(47%)&#039;&#039;, 7 &#039;&#039;(17%)&#039;&#039;, 8 &#039;&#039;(14%)&#039;&#039;, 9 &#039;&#039;(11%)&#039;&#039;, 10 &#039;&#039;(8%)&#039;&#039;, 11 &#039;&#039;(6%)&#039;&#039;, 12 &#039;&#039;(3%)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== General Strategy ==&lt;br /&gt;
* Purchase cards from a variety of sectors, to maximize the chance of deployed cards triggering on other players&#039; turns.&lt;br /&gt;
* Player Count impacts which rewards are most important: deployed (red) rewards trigger more often in higher-player-count games.&lt;br /&gt;
* Don&#039;t purchase Colony Cards too early, to avoid locking out sectors&lt;br /&gt;
* Use &amp;quot;arrow&amp;quot; rewards/abilities to mitigate the luck of die rolls and have more control over which sectors are triggered.&lt;br /&gt;
* Balance the type of rewards on your board - you can&#039;t win without VPs, but high income and credits are needed to purchase the best cards.&lt;br /&gt;
* Remember it is a race to 40 points, so if one person is getting ahead on VPs then prioritize getting VPs to catch-up (e.g. buy Colony cards)&lt;br /&gt;
* Focus less on the price of cards and more on their sector and effect.  It&#039;s okay to overspend for a card that works better with your strategy&lt;br /&gt;
* A single point is worth 3 credits as clearly demonstrated by the colony cards.  Early in the game prioritizing credits is sometimes okay to get better cards but more often than not, you should just choose points&lt;br /&gt;
&lt;br /&gt;
Try new strategies!&lt;br /&gt;
* Bet heavily on a single sector.  Purchase many cards in one sector and hope for good rolls.  Clever use of &amp;quot;arrow&amp;quot; rewards can help maximize your gains.&lt;br /&gt;
* Race to get a deployed card in every sector.  You&#039;ll be able to trigger rewards on every dice roll, and even have some options on what to choose!&lt;br /&gt;
* Try for the elusive &amp;quot;You Win&amp;quot; card.  It may take incredible luck (or skill), but what a dramatic way to win!  Who needs other sources of VPs if you can instantly win?&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_challengers&amp;diff=17326</id>
		<title>Tips challengers</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_challengers&amp;diff=17326"/>
		<updated>2023-06-27T21:15:34Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: More detailed strategies - less emphasis on luck&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Challengers is a card drafting auto-battler game.  Naturally the cards you are offered and the order in which your deck appears is based on luck, but there are still many important and often difficult decisions to be made which will impact how successful you are.&lt;br /&gt;
&lt;br /&gt;
== General Strategy ==&lt;br /&gt;
&lt;br /&gt;
The goal of the draft is to maximize your deck&#039;s power/size while minimizing the likelihood of &amp;quot;benching out&amp;quot; (7th bench card).  This is an oversimplification but a good first principle to work from.  With that in mind, the following is implied:&lt;br /&gt;
&lt;br /&gt;
• Drafting duplicates is crucial. These will increase your deck size and power while not making you bench out.  Ignoring synergy a pair of 2-power cards is generally as good as 1 4-power card.  The 2-power cards are sometimes better on the attack but worse on defense.  The 4-power is sometimes worse on attack but better on defense&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Synergy is key.  Cards like Vendor, A.I., Stable Boy, Make-up Artist, Band, Blacksmith, etc can be extremely strong if the rest of your deck support them.  Learning what all the cards do and what your &amp;quot;outs&amp;quot; are to improve your deck is crucial&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Winning the later rounds is way more important than the early rounds.  It&#039;s okay to take losses with a bloated deck early to maximize your odds of getting lucky with a later draft.  Winning only rounds 5, 6, and 7 will almost always get you into the final&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Know when to reroll.  This is probably the most skill-testing part of the entire game.  If your deck has a lot of one-ofs, you probably need to reroll when you&#039;re not offered any duplicates&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Know when to cut.  Generally speaking, you want 6 or 7 unique cards.  Until the last few rounds of the game, sticking at 7 or 8 can be okay to have more potential pair opportunities on the next draft.  In the last round or two, you should hopefully have doubled up on enough of your deck that having more than 6 cards is too risky to be worth it.  If your decks overall power is low, you may need to sit at 7 and hope you draw a single as the last card&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Relying on bench cleaners sometimes works but is very risky.  If you roll your bench cleaners before any singletons, then their effect is wasted.  Usually you&#039;re better off cutting the one-of Vacuum Cleaner or Butler.  Only consider playing them in duplicates&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Check which set is removed at the beginning of the game. This can influence your early picks in so far as what to look for and what to avoid&lt;br /&gt;
&lt;br /&gt;
== Sets ==&lt;br /&gt;
Very rough/general breakdown of each set which realistically is not all that useful - keeping in mind individual card effects will be much more helpful:&lt;br /&gt;
&lt;br /&gt;
• City (Light Blue) - Cards in this set tend to depend on cards in other sets to boost them.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Castle (Dark Blue) - Cards in this set tend to boost cards in other sets.&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Film Studio (Green) - Cards in this set tend to focus on the attack. &lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Funfair (Yellow) - Cards in this set tend to focus on rearranging your deck. &lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Haunted House (Orange) - Cards in this set tend to remove cards from your bench (either to your deck or to your exhaust pile). &lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Outer Space (Red) - Cards in this set tend to replace themselves or other cards in your deck. &lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Shipwreck (Purple) - Cards in this set tend to give defensive boosts.&lt;br /&gt;
&lt;br /&gt;
There are cross-over cards in each set, but your early picks tend to reflect these themes.&lt;br /&gt;
&lt;br /&gt;
Good luck!&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_patchwork&amp;diff=17178</id>
		<title>Tips patchwork</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_patchwork&amp;diff=17178"/>
		<updated>2023-06-17T23:42:36Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Added piece evaluation section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For the rules of patchwork, see &amp;lt;b&amp;gt;[[Gamehelppatchwork|GameHelpPatchwork]]&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
&lt;br /&gt;
* Patchwork seems like a simple game of placing Tetris-like pieces into a grid by paying for them with buttons. &lt;br /&gt;
* However, it&#039;s complex in that you have to balance the time vs. the cost to get a piece.&lt;br /&gt;
* Use up too much time you will have an unfinished quilt, costing you -2 points per empty space.&lt;br /&gt;
* Spend too much at the wrong time you could get button poor and be forced to jump when you don&#039;t want to. &lt;br /&gt;
&lt;br /&gt;
=== Some key things to consider ===&lt;br /&gt;
&#039;&#039;&#039;Evaluating Pieces&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Not all pieces are created equal&#039;&#039;.  &lt;br /&gt;
* There are 5 metrics to evaluate a piece on which include: button cost, time cost, button income, number of squares, and ease of fit&lt;br /&gt;
* All of these are easily quantified except ease of fit, but this is a crucial metric because the most efficient pieces (minimum cost, maximum squares/income) are the ones that seem hardest to fit into your quilt&lt;br /&gt;
* Takeaway: pick the most efficient pieces early in the game while you have plenty of time to fit other pieces around them&lt;br /&gt;
&lt;br /&gt;
==== Patches with buttons ====&lt;br /&gt;
&lt;br /&gt;
* Getting patches with buttons early is &#039;&#039;&#039;critical&#039;&#039;&#039;.&lt;br /&gt;
* You get more buttons when you pass one of the 9 buttons spots on the board, so the early you get them the more buttons you will get over the course of the game.&lt;br /&gt;
* &#039;&#039;For example:&#039;&#039; if you get a two-button patch in your first turn it will pay off with 18 buttons!&lt;br /&gt;
** But getting it later will have diminishing returns.&lt;br /&gt;
&lt;br /&gt;
==== Jumping ====&lt;br /&gt;
&lt;br /&gt;
* Jumping over an opponent and losing time to get buttons is &#039;&#039;&#039;sometimes&#039;&#039;&#039; a good thing.&lt;br /&gt;
** Early in the game, it allows you to get more buttons (money) early and buy better pieces (i.e., pieces with more buttons on them) earlier in the game.&lt;br /&gt;
** For why this is good refer to &#039;&#039;&#039;[[#Patches_with_buttons|Patches with buttons]]&#039;&#039;&#039;. &lt;br /&gt;
* If you do jump over an opponent, try to do it between buttons spots on the board, jumping over an opponent between button spots so you can buy the patch with buttons is preferred.&lt;br /&gt;
** Jumping over button spot misses a chance to buy a piece and get the buttons from it. &lt;br /&gt;
&lt;br /&gt;
==== Sides ====&lt;br /&gt;
&lt;br /&gt;
* Don&#039;t be afraid to leave an opening on the sides of the board, you can likely get a patch to fill it later, and you will not likely fill all your board anyway.&lt;br /&gt;
** This helps you avoid placing a piece in a bad spot because you are trying to fill every space - bad placement will then get you into trouble later when the board is tighter. &lt;br /&gt;
&lt;br /&gt;
==== Strategy ====&lt;br /&gt;
&lt;br /&gt;
* Some prefer to start from the bottom up, or a corner up, as they find it easier to fill the board.&lt;br /&gt;
** Others work from the centre out.&lt;br /&gt;
* Figure out what works for you!&lt;br /&gt;
&lt;br /&gt;
==== 7×7 bonus ====&lt;br /&gt;
&lt;br /&gt;
* Getting the 7×7 bonus for 7 points is &#039;&#039;&#039;great&#039;&#039;&#039; - &#039;&#039;&#039;however&#039;&#039;&#039; - going for it at the cost of not filling your board or bad placement which will make it hard to fill your board later will likely result in a loss anyway.&lt;br /&gt;
** Remember, it&#039;s -2 points for empty spaces, so the 7 point bonus only pays for 3.5 empty spaces, so getting the bonus but ending up with 6 openings for -12 points is counterproductive. &lt;br /&gt;
&lt;br /&gt;
 Good luck and have fun, it&#039;s a great game live or virtually!&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_nextstation&amp;diff=16757</id>
		<title>Tips nextstation</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_nextstation&amp;diff=16757"/>
		<updated>2023-04-24T21:32:53Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Detail&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==General Strategy==&lt;br /&gt;
&lt;br /&gt;
1. Try to maximize the chance that any given card being drawn is both playable &#039;&#039;&#039;and&#039;&#039;&#039; contributes to your score&lt;br /&gt;
&amp;lt;br/&amp;gt;2. You will frequently find yourself in the situation where you have to &amp;quot;guess&amp;quot; which of the remaining cards is next to determine which station you should draw toward.  But it&#039;s never truly a 50/50 decision - there are tie breakers to be taken into account.  Which outcome has higher upside?  Does one result include more red card(s) which are guaranteed to be drawn eventually vs blue cards which may or may not be?&lt;br /&gt;
&amp;lt;br/&amp;gt;3. Aim to draw each route such that you have many stations in one district and then &#039;&#039;&#039;at most one&#039;&#039;&#039; station in any other district.  Drawing 2 stations in 2 different districts means you have effectively thrown away a station losing you an opportunity for about 5 or 6 points.  A good route where all blue cards were drawn should score at &#039;&#039;&#039;least&#039;&#039;&#039; 5x6&lt;br /&gt;
&amp;lt;br/&amp;gt;4. In the event that you are forced into taking a bad station (this will happen) try to take the station that has the highest opportunity for future upside - usually an interchange with a later route.  In some cases not drawing the station at all is the best option because it can get in the way&lt;br /&gt;
&amp;lt;br/&amp;gt;5. Every route start point has 8 adjacent stations, 2 of each type.  Keep this in mind while drawing earlier routes.  You should avoid making both stations of any given type inaccessible from a start point&lt;br /&gt;
&amp;lt;br/&amp;gt;6. Consider the trade-offs of drawing a &amp;quot;long&amp;quot; connection between stations.  This will limit your future options, but may let you score more points now.  It&#039;s usually obvious which color route is most effected by drawing one of the long connections.  If you haven&#039;t drawn that route yet, you often should not use that connection&lt;br /&gt;
&lt;br /&gt;
==Objectives==&lt;br /&gt;
&lt;br /&gt;
At the start of the game analyze the objectives.  These can have a significant impact on how you should prioritize drawing each route as missing an objective will usually mean you lose.  Break down of each objective:&lt;br /&gt;
&lt;br /&gt;
1. 6 River crossings - there isn&#039;t much to say on this one.  Usually you should be crossing the river 6 times regardless of how you&#039;re drawing, but do keep it in mind and try to prioritize getting to the river a little more than normal&lt;br /&gt;
&amp;lt;br/&amp;gt;2. 9 Central District Stations - again fairly simple.  This one should not be very hard to achieve assuming you&#039;re pushing 2 of your routes through the center like you should be&lt;br /&gt;
&amp;lt;br/&amp;gt;3. 8 Interchanges - this is a bit more challenging.  Draw 2 of your routes with the central district as their majority which should get you 4-5 interchanges.  Sending a route through one of your future route start points can be good but be careful that you&#039;re not ruining that route&#039;s regular scoring&lt;br /&gt;
&amp;lt;br/&amp;gt;4. 13 Districts - this is the most difficult objective.  Certain card orderings can make the objective impossible or at least not worth pursuing.  Drawing into an outer corner district is inherently sketchy.  We want to keep both segments of our route playable as long as possible.  But if we draw into the corner, there are now no longer any good stations for that segment (results in a 2nd station in the inner corner district which is almost always 0 points).  If you&#039;re playing super hard for this objective, you may almost always achieve it, but if you sacrifice more than 10 points from your regular scoring (~2 &amp;quot;missed&amp;quot; stations) then it wasn&#039;t worth it.&lt;br /&gt;
&amp;lt;br/&amp;gt;5. 5 Tourist Sites - plays interestingly with normal scoring.  Each tourist site except the central one has a natural route for scoring it.  But that forces you into drawing at least 2 routes in its starting district which means you would forgo any central district majority which is bad because the central district majority routes have the highest scoring potential.  So the best way to play this is to try to hit tourist sites in non-start districts on 2 of our routes which also draw their majority through the center&lt;br /&gt;
&lt;br /&gt;
==Pencil Powers==&lt;br /&gt;
&lt;br /&gt;
Each pencil power has a unique impact on your route.  You should always aim to use it, but you also need to be careful not to waste it.&lt;br /&gt;
&lt;br /&gt;
1. Joker - this lets you play a little more &amp;quot;loosey goosey&amp;quot;.  You can take bigger risks knowing there&#039;s a wild card to get you out of it.  Until it&#039;s gone&lt;br /&gt;
&amp;lt;br/&amp;gt;2. Draw a second station of same type - this is probably the hardest power to use effectively.  I usually end up using it more liberally than any of the other powers because you can often find yourself in a position where doubling up any of the remaining stations doesn&#039;t actually score more points&lt;br /&gt;
&amp;lt;br/&amp;gt;3. Railroad Switch - plays somewhat similarly to Joker.  Makes it much easier to play into a dead end knowing you can start up another segment on demand&lt;br /&gt;
&amp;lt;br/&amp;gt;4. 2x Station - the easiest card to play.  Note how the math changes making drawing across additional districts more valuable&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Game_interface_logic:_Game.js&amp;diff=16745</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=16745"/>
		<updated>2023-04-22T22:17:09Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: /* Connecting */ This method does NOT work with string id, must be element $(id)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
This is the main file for your game interface. Here you will define:&lt;br /&gt;
&lt;br /&gt;
* Which actions on the page will generate calls to the server.&lt;br /&gt;
* What happens when you get a notification for a change from the server and how it will show in the browser. &lt;br /&gt;
* Setup user interface&lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
&lt;br /&gt;
The details of how the file is structured are described below with comments in the code skeleton provided to you.&lt;br /&gt;
&lt;br /&gt;
Here is the basic structure:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;constructor&#039;&#039;&#039;: here you can define global variables for your whole interface.&lt;br /&gt;
* &#039;&#039;&#039;setup&#039;&#039;&#039;: this method is called when the page is refreshed, and sets up the game interface.&lt;br /&gt;
* &#039;&#039;&#039;onEnteringState&#039;&#039;&#039;: this method is called when entering a new game state. You can use it to customize the view for each game state.&lt;br /&gt;
* &#039;&#039;&#039;onLeavingState&#039;&#039;&#039;: this method is called when leaving a game state.&lt;br /&gt;
* &#039;&#039;&#039;onUpdateActionButtons&#039;&#039;&#039;: called when entering a new state, in order to add action buttons to the status bar.&lt;br /&gt;
* &#039;&#039;(utility methods)&#039;&#039;: this is where you can define your utility methods.&lt;br /&gt;
* &#039;&#039;(player&#039;s actions)&#039;&#039;: this is where you can write your handlers for player actions on the interface (example: click on an item).&lt;br /&gt;
* &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;: this method associates notifications with notification handlers. For each game notification, you can trigger a javascript method to handle it and update the game interface.&lt;br /&gt;
* &#039;&#039;(notification handlers)&#039;&#039;: this is where you define the notifications handlers associated with notifications in &#039;&#039;&#039;setupNotifications&#039;&#039;&#039;, above.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
More details:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setup(gamedatas: object)            &#039;&#039;&#039;&lt;br /&gt;
This method must set up the game user interface according to current game situation specified in parameters.&lt;br /&gt;
The method is called each time the game interface is displayed to a player, ie:&lt;br /&gt;
&lt;br /&gt;
* when the game starts&lt;br /&gt;
* when a player opens a game in the browser later &lt;br /&gt;
* when a player refreshes the game page (F5)&lt;br /&gt;
* when player does a server side Undo&lt;br /&gt;
&lt;br /&gt;
&amp;quot;gamedatas&amp;quot; argument contains all data retrieved by your &amp;quot;getAllDatas&amp;quot; PHP method and some more.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onEnteringState(stateName: string, args: { args: any } | null): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is called each time we enter a new game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this moment.&lt;br /&gt;
To access state arguments passed via calling php arg* method use args?.args.&lt;br /&gt;
Typically you would do something only for active player, using this.isCurrentPlayerActive() check.&lt;br /&gt;
It is also called (for the current game state only) when doing a browser refresh (after the setup method is called).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039;: for multipleactiveplayer states:&lt;br /&gt;
the active players are NOT active yet so you must use onUpdateActionButtons to perform the client side operation which depends on a player active/inactive status.&lt;br /&gt;
If you are doing initialization of some structures which do not depend on the active player, you can just replace (this.isCurrentPlayerActive()) with (!this.isSpectator) &lt;br /&gt;
for the main switch in that method.&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Difference_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onLeavingState(stateName: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is called each time we leave a game state.&lt;br /&gt;
You can use this method to perform some user interface changes at this point (i.e. cleanup).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;onUpdateActionButtons(stateName: string, args: object | null): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this method you can manage &amp;quot;action buttons&amp;quot; that are displayed in the action status bar and highlight active UI elements.&lt;br /&gt;
To access state arguments passed via calling php arg* method use &#039;&#039;&#039;args&#039;&#039;&#039; parameter. Note: args can be null! For &#039;&#039;&#039;game&#039;&#039;&#039; states and when you don&#039;t supply state args function - it is null.&lt;br /&gt;
This method is called when the active or multiactive player changes. In a classic &amp;quot;activePlayer&amp;quot; state this method is called before the onEnteringState state.&lt;br /&gt;
In multipleactiveplayer state it is a mess. The sequencing of calls depends on whether you get into that state from transitions OR from reloading the whole game (i.e. F5).&lt;br /&gt;
&lt;br /&gt;
See more details in [[Your_game_state_machine:_states.inc.php#Difference_between_Single_active_and_Multi_active_states]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Dojo framework ==&lt;br /&gt;
&lt;br /&gt;
BGA uses the [http://dojotoolkit.org/ Dojo Javascript framework].&lt;br /&gt;
&lt;br /&gt;
The Dojo framework allows us to do complex things more easily. The BGA framework uses Dojo extensively.&lt;br /&gt;
&lt;br /&gt;
To implement a game, you only need to use a few parts of the Dojo framework. All the Dojo methods you need are described on this page.&lt;br /&gt;
&lt;br /&gt;
== Javascript minimization (after July 2020) ==&lt;br /&gt;
&lt;br /&gt;
For performance reasons, when deploying a game the javascript code is minimized using &#039;&#039;&#039;terser&#039;&#039;&#039; (https://github.com/terser/terser). This minifier works with modern javascript syntax. From your project &amp;quot;Manage game&amp;quot; page, you can now test a minified version of your javascript on the studio (and revert to the original).&lt;br /&gt;
&lt;br /&gt;
NB: it has been reported that there is an issue with this minifier and percentage values for opacity.&lt;br /&gt;
&lt;br /&gt;
== Accessing Players Information ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;player_id: number&#039;&#039;&#039;&lt;br /&gt;
id of the player who is looking at the game. The player may not be part of the game (i.e. spectator)&lt;br /&gt;
  if (notif.args.player_id == this.player_id) {&lt;br /&gt;
    ...&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;isSpectator: boolean&#039;&#039;&#039;&lt;br /&gt;
Flag set to true if the user at the table is a spectator (not a player).&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    if (this.isSpectator) {&lt;br /&gt;
        this.player_color = &#039;ffffff&#039;;&lt;br /&gt;
    } else {&lt;br /&gt;
        this.player_color = gamedatas.players[this.player_id].color;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: If you want to hide an element from spectators, you should use [[Game_interface_stylesheet:_yourgamename.css#spectatorMode|CSS &#039;spectatorMode&#039; class]].&lt;br /&gt;
&lt;br /&gt;
You may consider making a function like this, to detect if the game is in a read-only state (i.e. non-interactive):&lt;br /&gt;
  // Returns true for spectators, instant replay (during game), archive mode (after game end)&lt;br /&gt;
  isReadOnly: function () {&lt;br /&gt;
    return this.isSpectator || typeof g_replayFrom != &#039;undefined&#039; || g_archive_mode;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;gamedatas: object&#039;&#039;&#039;&lt;br /&gt;
Contains the initial set of data to init the game, created at game start or by game refresh (F5).&lt;br /&gt;
You can update it as needed to keep an up-to-date reference of the game on the client side if you need it, however most of the time this is unnecessary.&lt;br /&gt;
&lt;br /&gt;
Note: In hotseat mode, the framework does not keep this.gamedatas of hotseat players and shares the same set as the main player to store data.&lt;br /&gt;
&lt;br /&gt;
Note: be careful when you update this data structurally, many framework functions expect data to be certain way and they will break if they see something else.&lt;br /&gt;
&lt;br /&gt;
Typical example of accessing player&#039;s info&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
for (var player_id in this.gamedatas.players) { &lt;br /&gt;
    var playerInfo = this.gamedatas.players [player_id];&lt;br /&gt;
    var c = playerInfo.color;&lt;br /&gt;
    var name = playerInfo.name;&lt;br /&gt;
    // do something &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;isCurrentPlayerActive(): boolean&#039;&#039;&#039;&lt;br /&gt;
Returns true if the player on whose browser the code is running is currently active (it&#039;s his turn to play). Note: see remarks above about usage of this function inside onEnteringState method.&lt;br /&gt;
  if (this.isCurrentPlayerActive()) {&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getActivePlayerId(): number&#039;&#039;&#039;&lt;br /&gt;
Return the ID of the active player, or null if we are not in an &amp;quot;activeplayer&amp;quot; type state.&lt;br /&gt;
  if (this.player_id == this.getActivePlayerId()) ...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getActivePlayers(): number[]&#039;&#039;&#039;&lt;br /&gt;
Return an array with the IDs of players who are currently active (or an empty array if there are none).&lt;br /&gt;
&lt;br /&gt;
== Accessing and manipulating the DOM ==&lt;br /&gt;
&lt;br /&gt;
=== Element by Id ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;$(elementId: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The $ function is used to get an HTML element using its &amp;quot;id&amp;quot; attribute.&lt;br /&gt;
&lt;br /&gt;
Example: modify the content of a &amp;quot;span&amp;quot; element:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
In your HTML code:&lt;br /&gt;
   &amp;lt;span id=&amp;quot;a_value_in_the_game_interface&amp;quot;&amp;gt;1234&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In your Javascript code:&lt;br /&gt;
   $(&#039;a_value_in_the_game_interface&#039;).innerHTML = &amp;quot;9999&amp;quot;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Note: It is safe to use if you don&#039;t know if variable is string (id of element) or element itself, i.e. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  foo: function(card) {&lt;br /&gt;
       card = $(card); // now its node, no need to write if (typeof card === &#039;string&#039;) ...&lt;br /&gt;
       // but its good idea to check for null here&lt;br /&gt;
       ...&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;getElementById(elementId: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Note: $() is the standard method to access some HTML element with the BGA Framework. You can use &#039;&#039;&#039;getElementById&#039;&#039;&#039; but a longer to type and less handy as it does not do some checks.&lt;br /&gt;
&lt;br /&gt;
=== Style ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.style(node: ElementOrId, styleName: string, styleValue: any): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.style you can modify the CSS property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Make an element disappear&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Give an element a 2px border&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;borderWidth&#039;, &#039;2px&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Change the background position of an element&lt;br /&gt;
     // (very practical when you are using CSS sprites to transform an element to another)&lt;br /&gt;
     dojo.style( &#039;my_element&#039;, &#039;backgroundPosition&#039;, &#039;-20px -50px&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: if you have to modify several CSS properties of an element, or if you have a complex CSS transformation to do, you should consider using dojo.addClass/dojo.removeClass (see below).&lt;br /&gt;
&lt;br /&gt;
You can also use object to set multiple values&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dojo.setStyle(&amp;quot;thinger&amp;quot;, {&lt;br /&gt;
  &amp;quot;opacity&amp;quot;: 0.5,&lt;br /&gt;
  &amp;quot;border&amp;quot;: &amp;quot;3px solid black&amp;quot;,&lt;br /&gt;
  &amp;quot;height&amp;quot;: &amp;quot;300px&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;addStyleToClass(cssClassName: string, styleName: string, styleValue: any):void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as dojo.style(), but for all the nodes set with the specified cssClassName&lt;br /&gt;
Equivalent of &lt;br /&gt;
  &lt;br /&gt;
  dojo.query(`.${aclass}`).style(styleName, styleValue)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
dojo.query(&amp;quot;#baz &amp;gt; div&amp;quot;).style({&lt;br /&gt;
  opacity:0.75,&lt;br /&gt;
  fontSize:&amp;quot;13pt&amp;quot;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS style&#039;&#039;&#039;&lt;br /&gt;
  $(&#039;my_element&#039;).style.display=&#039;none&#039;; // set&lt;br /&gt;
  var display = $(&#039;my_element&#039;).style.display; // get&lt;br /&gt;
  $(&#039;my_element&#039;).style.removeProperty(&#039;display&#039;); // remove&lt;br /&gt;
&lt;br /&gt;
=== Classes ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.addClass(node: ElementOrId, classes: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.removeClass(node: ElementOrId, classes: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.hasClass(node: ElementOrId, aclass: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.toggleClass(node: ElementOrId, aclass: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In many situations, many small CSS property updates can be replaced by a CSS class change (i.e., you add a CSS class to your element instead of applying all modifications manually).&lt;br /&gt;
&lt;br /&gt;
Advantages are:&lt;br /&gt;
* All your CSS stuff remains in your CSS file.&lt;br /&gt;
* You can add/remove a list of CSS modifications with a simple function and without error.&lt;br /&gt;
* You can test whether you applied the CSS to an element with the &#039;&#039;&#039;dojo.hasClass&#039;&#039;&#039; method.&lt;br /&gt;
&lt;br /&gt;
Example from &#039;&#039;Reversi&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // We add &amp;quot;possibleMove&amp;quot; to an element&lt;br /&gt;
    dojo.addClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
    // In our CSS file, the class is defined as:&lt;br /&gt;
    .possibleMove {&lt;br /&gt;
      background-color: white;&lt;br /&gt;
      opacity: 0.2;&lt;br /&gt;
      filter:alpha(opacity=20); /* For IE8 and earlier */  &lt;br /&gt;
      cursor: pointer;  &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     // So we&#039;ve applied 4 CSS property changes in one line of code.&lt;br /&gt;
&lt;br /&gt;
     // ... and when we need to check if a square is a possible move on the client side:&lt;br /&gt;
     if( dojo.hasClass( &#039;square_&#039;+x+&#039;_&#039;+y, &#039;possibleMove&#039; ) )&lt;br /&gt;
     { ... }&lt;br /&gt;
&lt;br /&gt;
     // ... and if we want to remove all possible moves in one line of code (see &amp;quot;dojo.query&amp;quot; method):&lt;br /&gt;
     dojo.query( &#039;.possibleMove&#039; ).removeClass( &#039;possibleMove&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS classList&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is the only exception where dojo versions are better&lt;br /&gt;
  // add class&lt;br /&gt;
  $(token_id).classList.addClass(&#039;possibleMove&#039;);&lt;br /&gt;
  // remove class&lt;br /&gt;
  $(token_id).classList.removeClass(&#039;possibleMove&#039;);&lt;br /&gt;
  // add 2 classes&lt;br /&gt;
  const myclasses = [&#039;a&#039;,&#039;b&#039;];&lt;br /&gt;
  $(token_id).classList.addClass(...myclasses);&lt;br /&gt;
  // add classes to query result&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.hand .card&amp;quot;).forEach((node)=&amp;gt;node.classList.addClass(&#039;possibleMove&#039;));&lt;br /&gt;
&lt;br /&gt;
=== Attributes ===&lt;br /&gt;
&lt;br /&gt;
;dojo.attr&lt;br /&gt;
&lt;br /&gt;
With dojo.attr you can access or change the value of an attribute or property of any HTML element in your interface.&lt;br /&gt;
&lt;br /&gt;
Exemple:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Get the title of a node&lt;br /&gt;
     var title = dojo.attr( id, &#039;title&#039; );&lt;br /&gt;
     // Change the height of a node&lt;br /&gt;
     dojo.attr( &#039;img_growing_tree&#039;, &#039;height&#039;, 100 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS attr&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
   $(token).id=new_id; // set attr for &amp;quot;id&amp;quot;&lt;br /&gt;
   var id = $(token).id; // get&lt;br /&gt;
&lt;br /&gt;
=== Queries ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.query(cssSelector: string): Element[]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.query, you can query a bunch of HTML elements with a single function, with a &amp;quot;CSS selector&amp;quot; style.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // All elements with class &amp;quot;possibleMove&amp;quot;:&lt;br /&gt;
     var elements = dojo.query( &#039;.possibleMove&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Count number of tokens (i.e., elements of class &amp;quot;token&amp;quot;) on the board (i.e., the element with id &amp;quot;board&amp;quot;):&lt;br /&gt;
     dojo.query( &#039;#board .token&#039; ).length;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
But what is really cool with dojo.query is that you can combine it with almost all methods above.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Trigger a method when the mouse enter in any element with class &amp;quot;meeple&amp;quot;:&lt;br /&gt;
     dojo.query( &#039;.meeple&#039; ).connect( &#039;onmouseenter&#039;, this, &#039;myMethodToTrigger&#039; );&lt;br /&gt;
&lt;br /&gt;
     // Hide all meeples who are on the board&lt;br /&gt;
     dojo.query( &#039;#board .meeple&#039; ).style( &#039;display&#039;, &#039;none&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Vanila JS query&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
  var cards=document.querySelectorAll(&amp;quot;.hand .card&amp;quot;);// all cards in all hands&lt;br /&gt;
  var cards=$(&#039;hand&#039;).querySelectorAll(&amp;quot;.card&amp;quot;);// all cards in specific hand&lt;br /&gt;
  var card=document.querySelector(&amp;quot;.hand .card&amp;quot;);// first card or null if none (super handy)&lt;br /&gt;
&lt;br /&gt;
=== Creating and Destroying elements ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.empty(node: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove all children of the node element&lt;br /&gt;
   dojo.empty(&#039;my_hand&#039;);&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.destroy(node: ElementOrId)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Remove the element&lt;br /&gt;
   dojo.destroy(&#039;my_token&#039;);&lt;br /&gt;
&lt;br /&gt;
   dojo.query(&amp;quot;.green&amp;quot;, mynode).forEach(dojo.destroy); // this remove all subnode of class green from mynode&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.create(tag: string, attributes?: obj, parent?: ElementOrId): Element&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Create element&lt;br /&gt;
&lt;br /&gt;
    dojo.create(&amp;quot;div&amp;quot;, { class: &amp;quot;yellow_arrow&amp;quot; }, parent); // this creates div with class yellow_array and places it in &amp;quot;parent&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.format_block(name: string, args: object): string&#039;&#039;&#039;&lt;br /&gt;
This bga function that takes global var from template file and substitute variables, typical use would be&lt;br /&gt;
&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                var div = this.format_block(&#039;jstpl_player_board&#039;, player ); // var jstpl_player_board = ... is defined in .tpl file &lt;br /&gt;
Note: result is trimmed&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.format_string(name: string, args: object): string&#039;&#039;&#039;&lt;br /&gt;
This bga function just substitute variables in a string, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     var div = this.format_string(&#039;&amp;lt;div color=&amp;quot;${player_color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, {player_color: &#039;#ff0000&#039;} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: result is trimmed&lt;br /&gt;
&lt;br /&gt;
Note: this can be replaced by using backquoted string now: &lt;br /&gt;
     const player_color =  &#039;#ff0000&#039;;&lt;br /&gt;
     const div = `&amp;lt;div color=&amp;quot;${player_color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;`;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.format_string_recursive&#039;&#039;&#039;&lt;br /&gt;
This bga function is similar to this.format_string but is capable of processing recursive argument structures and translations. It is used to format server notifications.&lt;br /&gt;
&lt;br /&gt;
TODO: find better place for these function docs&lt;br /&gt;
&lt;br /&gt;
=== Moving elements ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.place(node: string | Element, refNode: ElementOrId, pos?: string | number): Element&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
dojo.place is the best function to insert HTML code somewhere in your game interface without breaking something. It is much better to use than the &#039;&#039;&#039;innerHTML=&#039;&#039;&#039; method if you must insert HTML tags and not only values.&lt;br /&gt;
&lt;br /&gt;
node: &lt;br /&gt;
&lt;br /&gt;
Can be a String or a DOM node. If it is a string starting with “&amp;lt;”, it is assumed to be an HTML fragment, which will be created. Otherwise it is assumed to be an id of a DOM node.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Insert your HTML code as a child of a container element&lt;br /&gt;
     dojo.place( &amp;quot;&amp;lt;div class=&#039;foo&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, &amp;quot;your_container_element_id&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
pos:&lt;br /&gt;
&lt;br /&gt;
Optional argument. Can be a number or one of the following strings: “before”, “after”, “replace”, “only”, “first”, or “last”. If omitted, “last” is assumed. &lt;br /&gt;
&lt;br /&gt;
&amp;quot;replace&amp;quot;: Replace the container element with my_node element&lt;br /&gt;
&lt;br /&gt;
&amp;quot;first&amp;quot;: Places the node as a child of the reference node. The node is placed as the first child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;last&amp;quot; (default): Places the node as a child of the reference node. The node is placed as the last child.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;before&amp;quot;: places the node right before the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;after&amp;quot;: places the node right after the reference node.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;only&amp;quot;: replaces all children of the reference node with the node.&lt;br /&gt;
&lt;br /&gt;
positive integer: This parameter can be a positive integer. In this case, the node will be placed as a child of the reference node with this number (counting from 0). If the number is more than number of children, the node will be appended to the reference node making it the last child. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     // Replace all children of container with my_node &lt;br /&gt;
     dojo.place( $(&#039;my_node&#039;), &amp;quot;your_container_element_id&amp;quot;, &amp;quot;only&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
See also full doc on dojo.place: [https://dojotoolkit.org/reference-guide/1.7/dojo/place.html]&lt;br /&gt;
&lt;br /&gt;
Usually, when you want to insert some piece of HTML in your game interface, you should use &amp;quot;[[Game_layout:_view_and_template:_yourgamename.view.php_and_yourgamename_yourgamename.tpl#Javascript_templates|Javascript templates]]&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
But you can also relocate elements like that. Note: it won&#039;t animate if you do that.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;placeOnObject(mobile_obj: ElementOrId, target_obj: ElementOrId): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
places mobile_obj on target_obj, set the absolute positions and centers the mobile_obj on target_obj,&lt;br /&gt;
effect is immediate&lt;br /&gt;
&lt;br /&gt;
This is not really an animation, but placeOnObject is frequently used before starting an animation.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  // (We just created an object &amp;quot;my_new_token&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
  // Place the new token on current player board&lt;br /&gt;
  this.placeOnObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;overall_player_board_&amp;quot;+this.player_id );&lt;br /&gt;
  &lt;br /&gt;
  // Then slide it to its position on the board&lt;br /&gt;
  this.slideToObject( &amp;quot;my_new_token&amp;quot;, &amp;quot;a_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;placeOnObjectPos( mobile_obj: ElementOrId, target_obj: ElementOrId, target_x: number, target_y: number ): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method works exactly like placeOnObject, except than you can specify some (x,y) coordinates (in px). This way, the center of &amp;quot;mobile_obj&amp;quot; will be placed to the specified x,y position relatively to the center of &amp;quot;target_obj&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: the placement works differently from this.slideToObjectPos&#039;&#039;, since coordinates are calculated based on the center of objects.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.attachToNewParent(mobile_obj: ElementOrId, target_obj: ElementOrId): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With this method, you change the HTML parent of &amp;quot;mobile_obj&amp;quot; element without moving it. &lt;br /&gt;
&amp;quot;target_obj&amp;quot; is the new parent of this element. The beauty of &lt;br /&gt;
attachToNewParent is that the mobile_obj element DOES NOT MOVE during this process.&lt;br /&gt;
&lt;br /&gt;
What happens is that the method calculate a relative position of mobile_obj to make sure it does not move after the HTML parent changes.&lt;br /&gt;
&lt;br /&gt;
Why using this method?&lt;br /&gt;
&lt;br /&gt;
Changing the HTML parent of an element can be useful for the following reasons:&lt;br /&gt;
* When the HTML parent moves, all its child are moving with them. If some game elements is no more linked with a parent HTML object, you may want to attach it to another place.&lt;br /&gt;
* The z_order (vertical order of display) depends on the position in the DOM, so you may need to change the parent of some game elements when they are moving in your game area.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;CAREFUL&#039;&#039;&#039;: this function destroys original object and places a clone onto a new parent, this will break all references to this HTML element (ex: dojo.connect).&lt;br /&gt;
If you need version that does not destroy the object but the same otherwise see [[BGA_Studio_Cookbook#Attach_to_new_parent_without_destroying_the_object]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Animations ==&lt;br /&gt;
&lt;br /&gt;
===Dojo Animations===&lt;br /&gt;
&lt;br /&gt;
BGA animations is based on Dojo Animation ([http://dojotoolkit.org/documentation/tutorials/1.8/animation/ see tutorial here]).&lt;br /&gt;
&lt;br /&gt;
However, most of the time, you can just use methods below, which are built on top of Dojo Animation.&lt;br /&gt;
&lt;br /&gt;
Note: one interesting method from Dojo that could be useful from time to time is &amp;quot;Dojo.Animation&amp;quot;. It allows you to make any CSS property &amp;quot;slide&amp;quot; from one value to another.&lt;br /&gt;
&lt;br /&gt;
Note 2: the slideTo methods are not compatible with CSS transform (scale, zoom, rotate...). If possible, avoid using CSS transform on nodes that are being slided. Eventually, the only possible solution to make these 2 compatible is to disable all CSS transform properties, use slideToObjectPos/placeOnObjectPos, and then apply them again.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Sliding===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;slideToObject(mobile_obj: ElementOrId, target_obj: ElementOrId, duration?: number, delay?: number): Animation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can use slideToObject to &amp;quot;slide&amp;quot; an element to a target position.&lt;br /&gt;
&lt;br /&gt;
Sliding element on the game area is the recommended and the most used way to animate your game interface. Using slides allow players to figure out what is happening on the game, as if they were playing with the real boardgame.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* mobile_obj: the ID of the object to move. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned.&lt;br /&gt;
* target_obj: the ID of the target object. This object must be &amp;quot;relative&amp;quot; or &amp;quot;absolute&amp;quot; positioned. Note that it is not mandatory that mobile_obj and target_obj have the same size. If their size are different, the system slides the center of mobile_obj to the center of target_obj.&lt;br /&gt;
* duration: (optional) defines the duration in millisecond of the slide. The default is 500 milliseconds.&lt;br /&gt;
* delay: (optional). If you defines a delay, the slide will start only after this delay. This is particularly useful when you want to slide several object from the same position to the same position: you can give a 0ms delay to the first object, a 100ms delay to the second one, a 200ms delay to the third one, ... this way they won&#039;t be superposed during the slide.&lt;br /&gt;
&lt;br /&gt;
BE CAREFUL: The method returns an dojo.fx animation, so you can combine it with other animation if you want to. It means that you have to call the &amp;quot;play()&amp;quot; method, otherwise the animation WON&#039;T START.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.slideToObject( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot; ).play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;slideToObjectPos(mobile_obj: 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;
&#039;&#039;&#039;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;slideToObjectAndDestroy: function(mobile_obj: string | Element, target_obj: string | Element, duration?: number, delay?: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method is a handy shortcut to slide an existing HTML object to some place then destroy it upon arrival. It can be used for example to move a victory token or a card from the board to the player panel to show that the player earns it, then destroy it when we don&#039;t need to keep it visible on the player panel.&lt;br /&gt;
&lt;br /&gt;
It works the same as this.slideToObject and takes the same arguments, but it starts the animation. &lt;br /&gt;
&lt;br /&gt;
CAREFUL: Make sure nothing is creating the same object at the same time the animation is running, because this will cause some random disappearing effects&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.slideToObjectAndDestroy( &amp;quot;some_token&amp;quot;, &amp;quot;some_place_on_board&amp;quot;, 1000, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;fadeOutAndDestroy( node: string | Element, duration?: number, delay?: number):void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This function fade out the target node, then destroy it. Its starts the animation.&lt;br /&gt;
* duration/delay works exactly like in &amp;quot;slideToObject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.fadeOutAndDestroy( &amp;quot;a_card_that_must_disappear&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
CAREFUL: the HTML node still exists until during few milliseconds, until the fadeOut has been completed.&lt;br /&gt;
Make sure nothing is creating same object at the same time as animation is running, because you will be some random dissapearing effects&lt;br /&gt;
&lt;br /&gt;
===Rotating elements===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This example combines &amp;quot;Dojo.Animation&amp;quot; method and a CSS property transform that allow you to rotate the element.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// node is Element we rotating&lt;br /&gt;
		    var animation = new dojo.Animation({&lt;br /&gt;
			    curve: [fromDegree, toDegree],&lt;br /&gt;
			    onAnimate: (v) =&amp;gt; {&lt;br /&gt;
				    node.style.transform = &#039;rotate(&#039; + v + &#039;deg)&#039;;&lt;br /&gt;
			    } &lt;br /&gt;
		    });&lt;br /&gt;
		    &lt;br /&gt;
		    animation.play();  &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
BGA has its own interface to rotate&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;rotateTo(node: string | Element, degree: number): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
It starts the animation, and stored the rotation degree in the class, so next time you rotate object - it is additive.&lt;br /&gt;
There is no animation hooks in this one, if you need to change any parameters use dojo animation above.&lt;br /&gt;
&lt;br /&gt;
There is also &#039;&#039;&#039;rotateInstantTo&#039;&#039;&#039; with same signature which does not animate&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Animation Callbacks===&lt;br /&gt;
&lt;br /&gt;
If you wish to run some code only after an animation has completed you can do this by linking a callback method to &#039;onEnd&#039;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var animation_id = this.slideToObject( mobile_obj, target_obj, 500 );&lt;br /&gt;
dojo.connect(animation_id, &#039;onEnd&#039;, () =&amp;gt; {&lt;br /&gt;
   // do something here&lt;br /&gt;
});&lt;br /&gt;
animation_id.play();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you wish to call a second animation after the first (rather than general code) then you can use a dojo animation chain (see tutorial referenced above).&lt;br /&gt;
&lt;br /&gt;
== Players input ==&lt;br /&gt;
&lt;br /&gt;
=== Connecting ===&lt;br /&gt;
&#039;&#039;&#039;dojo.connect(element: 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, hander: eventHandler): any&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
Example: associate a click on an element (&amp;quot;my_element&amp;quot;) with one of our methods (&amp;quot;onClickOnMyElement&amp;quot;):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
      dojo.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, this, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same idea but base on query (i.e. all element of &#039;pet&#039; class)&lt;br /&gt;
      dojo.query(&amp;quot;.pet&amp;quot;).connect(&#039;onclick&#039;, this, &#039;onPet&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: if you need to disconnect the handler you have to store handler returned from this method, i.e.&lt;br /&gt;
   &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    var handler = dojo.connect(...);&lt;br /&gt;
    ...&lt;br /&gt;
    dojo.disconnect(handler);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t store the handler - you have to destroy the object to disconnect it&lt;br /&gt;
&lt;br /&gt;
Typical function that implements the input handler will look like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
onPet: function(event) {&lt;br /&gt;
    var id = event.currentTarget.id;&lt;br /&gt;
    console.log(&#039;onPet &#039; + id);&lt;br /&gt;
    dojo.stopEvent(event);&lt;br /&gt;
    if (this.gamedatas.gamestate.name == &#039;playerTurnPet&#039;) {&lt;br /&gt;
          this.ajaxcallwrapper(&#039;playPet&#039;, {card: id});&lt;br /&gt;
    } else {&lt;br /&gt;
          this.showMoveUnauthorized();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;connect(element: ElementOrId, event: string, method: eventHandler): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Used to associate a player event with one of your notification methods.&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, &#039;onClickOnMyElement&#039; );&lt;br /&gt;
&lt;br /&gt;
Or you can use an in-place handler&lt;br /&gt;
&lt;br /&gt;
      this.connect( $(&#039;my_element&#039;), &#039;onclick&#039;, (e) =&amp;gt; { console.log(&#039;boo&#039;); } );&lt;br /&gt;
&lt;br /&gt;
Note that this function stores the connection handler. That is the only real difference between &#039;&#039;&#039;this.connect&#039;&#039;&#039; and &#039;&#039;&#039;dojo.connect&#039;&#039;&#039;. If you plan to destroy the element you connected, you &#039;&#039;&#039;must&#039;&#039;&#039; call this.disconnect() to prevent memory leaks.&lt;br /&gt;
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;
&lt;br /&gt;
&#039;&#039;&#039;connectClass(cssClassName: string, event: string, method: eventHandler): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Same as connect(), but for all the nodes set with the specified cssClassName.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
	this.connectClass(&#039;pet&#039;, &#039;onclick&#039;, &#039;onPet&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;disconnect(element: ElementOrId, event: string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Disconnect event handler (previously registered with this.connect or this.connectClass).&lt;br /&gt;
&lt;br /&gt;
   this.disconnect( $(&#039;my_element&#039;), &#039;onclick&#039;);&lt;br /&gt;
&lt;br /&gt;
Note: dynamic connect/disconnect is for advanced cases ONLY, you should always connect elements statically if possible, i.e. in setup() method.&lt;br /&gt;
&lt;br /&gt;
;disconnectAll() &lt;br /&gt;
&lt;br /&gt;
Disconnect all previously registed event handlers (registered via this.connect or this.connectClass)&lt;br /&gt;
&lt;br /&gt;
  this.disconnectAll();&lt;br /&gt;
&lt;br /&gt;
=== Actions ===&lt;br /&gt;
&#039;&#039;&#039;this.ajaxcall(url, parameters, obj_callback, callback, callback_anycase?, ajax_method?: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This method must be used to send a player input to the game server. &#039;&#039;&#039;It should not be triggered programmatically&#039;&#039;&#039;, especially not in loops, in callbacks, in notifications, or in onEnteringState/onUpdateActionButtons/onLeavingState, in order not to create race conditions or break replay game and tutorial features. It should be used only in reaction to a user action in the interface.&lt;br /&gt;
&lt;br /&gt;
* url: the url of the action to perform. For a game, it must be: &amp;quot;/&amp;lt;mygame&amp;gt;/&amp;lt;mygame&amp;gt;/myAction.html&amp;quot;&lt;br /&gt;
* parameters: an array of parameter to send to the game server. &lt;br /&gt;
** Note that &amp;quot;lock: true&amp;quot; must always be specified in this list of parameters in order the interface can be locked during the server call. Cannot use lock: false - to not lock it has to be undefined.&lt;br /&gt;
** Note: Restricted parameter names (please don&#039;t use them):&lt;br /&gt;
*** &amp;quot;action&amp;quot;&lt;br /&gt;
*** &amp;quot;module&amp;quot;&lt;br /&gt;
*** &amp;quot;class&amp;quot;&lt;br /&gt;
* obj_callback: must be set to &amp;quot;this&amp;quot;.&lt;br /&gt;
* callback (non-optional but rarely used): a function to trigger when the server returns result and everything went fine (not used, as all data handling is done via notifications).&lt;br /&gt;
* callback_anycase: (optional) a function to trigger when the server returns ok OR error.  If no error this function is called with parameter value false. 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/myaction.html&#039;, { lock: true, &lt;br /&gt;
   arg1: myarg1, &lt;br /&gt;
   arg2: myarg2&lt;br /&gt;
}, this, (result)=&amp;gt;{} );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: to reduce the boilerplate code you can define your own wrapper, which will do checking, locking and allow to skip parameters, for example&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ajaxcallwrapper: function(action, args, handler) {&lt;br /&gt;
	if (!args) {&lt;br /&gt;
		args = {};&lt;br /&gt;
	}&lt;br /&gt;
	args.lock = true;&lt;br /&gt;
&lt;br /&gt;
	if (this.checkAction(action)) {&lt;br /&gt;
		this.ajaxcall(&amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + this.game_name + &amp;quot;/&amp;quot; + action + &amp;quot;.html&amp;quot;, args, this, (result) =&amp;gt; { }, handler);&lt;br /&gt;
	}&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This can be called like this which is a lot more compact&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playDraw&#039;);&lt;br /&gt;
   this.ajaxcallwrapper(&#039;playMove&#039;, {card: id})&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;checkAction(action: string, nomessage?: boolean): boolean &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Check if player can do the specified action by taking into account:&lt;br /&gt;
* if interface is locked it will return false and show message &amp;quot;An action is already in progress&amp;quot;,  unless nomessage set to true &lt;br /&gt;
* if player is not active it will return false and show message &amp;quot;This is not your turn&amp;quot;, unless nomessage set to true &lt;br /&gt;
* if action is not in list in possible actions (defined by &amp;quot;possibleaction&amp;quot; in current game state) it will return false and show &amp;quot;This move is not authorized now&amp;quot; error (unconditionally).&lt;br /&gt;
* otherwise returns true&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  function onClickOnGameElement( evt )  {&lt;br /&gt;
     if( this.checkAction( &amp;quot;my_action&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;checkPossibleActions(action: string): boolean&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* this is independent of the player being active, so can be used instead of this.checkAction(). This is particularly useful for multiplayer states when the player is not active in a &#039;player may like to change their mind&#039; scenario. Unlike this.checkAction, this function does NOT take interface locking into account &lt;br /&gt;
&lt;br /&gt;
* if action is not in list in possible actions (defined by &amp;quot;possibleaction&amp;quot; in current game state) it will return false and show &amp;quot;This move is not authorized now&amp;quot; error (unconditionally).&lt;br /&gt;
* otherwise returns true&lt;br /&gt;
&lt;br /&gt;
  function onChangeMyMind( evt )  {&lt;br /&gt;
     if( this.checkPossibleActions( &amp;quot;my_action&amp;quot; ) ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;checkLock(nomessage?: boolean): boolean&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
When using &amp;quot;lock: true&amp;quot; in ajax call you can use this function to check if interface is in lock state (it will be locked during server call and notification processing).&lt;br /&gt;
This check can be used to block some other interactions which do not result in ajaxcall or if you want to suppress errors. Note: normally you only need to use this.checkAction(...), this is for advanced cases.&lt;br /&gt;
&lt;br /&gt;
It will also show error unless nomessage is set to true&lt;br /&gt;
&lt;br /&gt;
  function onChangeMyMind( evt )  {&lt;br /&gt;
     if( this.checkLock() ) {&lt;br /&gt;
        // Do the action&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
== Notifications ==&lt;br /&gt;
&lt;br /&gt;
When something happens on the server side, your game interface Javascript logic received a notification.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how you can handle these notifications on the client side.&lt;br /&gt;
&lt;br /&gt;
=== Subscribe to notifications ===&lt;br /&gt;
&lt;br /&gt;
&#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;
Sometimes you need to ignore some notification on client side. You don&#039;t want them to be shown in game log and you don&#039;t want them to be handled.&lt;br /&gt;
&lt;br /&gt;
The most common use case is when a player gets private information. They will receive a specific notification (such as &amp;quot;You received Ace of Heart&amp;quot;), while other players would receive more generic notification (&amp;quot;Player received a card&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
In X.game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $this-&amp;gt;notifyAllPlayers(&amp;quot;dealCard&amp;quot;, clienttranslate(&#039;${player_name} received a card&#039;), [&lt;br /&gt;
            &#039;player_id&#039; =&amp;gt; $playerId,&lt;br /&gt;
            &#039;player_name&#039; =&amp;gt; $this-&amp;gt;getActivePlayerName()&lt;br /&gt;
        ]);&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;notifyPlayer($playerId, &amp;quot;dealCardPrivate&amp;quot;, clienttranslate(&#039;You received ${cardName}&#039;), [&lt;br /&gt;
            &amp;quot;type&amp;quot; =&amp;gt; $card[&amp;quot;type&amp;quot;],&lt;br /&gt;
            &amp;quot;cardName&amp;quot; =&amp;gt; $this-&amp;gt;getCardName($card[&amp;quot;type&amp;quot;])&lt;br /&gt;
        ]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The problem with this approach is that the active player will receive two notifications:&lt;br /&gt;
* Player1 received a card&lt;br /&gt;
* You received Ace of Hearts&lt;br /&gt;
&lt;br /&gt;
Hence, notification ignoring.&lt;br /&gt;
&lt;br /&gt;
NOTE: You can think that it would be possible to send such notification to all players except active just by using notifyPlayer and it seems to work. The problem however is that table spectators would miss such notification and their user interface (and game log) wouldn&#039;t be updated. Since there is no way to send notification just to spectators, ignoring the notification (or &amp;quot;filtering&amp;quot;) is the only reasonable solution.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setIgnoreNotificationCheck(notif_type: string, predicate: ((notif: Notif)=&amp;gt;boolean))&#039;&#039;&#039;&lt;br /&gt;
This method will set a check whether any of notifications of specific type should be ignored.&lt;br /&gt;
&lt;br /&gt;
The parameters are:&lt;br /&gt;
* notif_type: type of the notification &lt;br /&gt;
* predicate (notif =&amp;gt; boolean): a function that will receive notif object and will return true if this specific notification should be ignored&lt;br /&gt;
&lt;br /&gt;
Before dispatching any notification of this type, the framework will call predicate to check whether notification should be ignored, if it return true - the notification will be dispatched, i.e. logged or handled.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.notifqueue.setIgnoreNotificationCheck( &#039;dealCard&#039;, (notif) =&amp;gt; (notif.args.player_id == this.player_id) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: Remember that this notification is ignored on the client side, but was still received by the client. Therefore it shouldn&#039;t contain any private information as cheaters can get it. In other words this is not a way to hide information.&lt;br /&gt;
&lt;br /&gt;
IMPORTANT: When a game is reloaded with F5 or when opening a turn based game, old notifications are replayed as history notification. They are used just to update the game log and are stripped of all arguments except player_id, i18n and any argument present in message. If you use and other argument in your predicate you should &#039;&#039;&#039;preserve&#039;&#039;&#039; it as explained [[Main_game_logic:_yourgamename.game.php#Notify_players|here]].&lt;br /&gt;
&lt;br /&gt;
=== Synchronous notifications ===&lt;br /&gt;
&lt;br /&gt;
When several notifications are received by your game interface, these notifications are processed immediately, one after the other, in the same exact order they have been generated in your PHP game logic.&lt;br /&gt;
&lt;br /&gt;
However, sometimes, you need to give some time to the players to figure out what happened on the game before jumping to the next notification. Indeed, in many games, there are a lot of automatic actions, and the computer is going to resolve all these actions very fast if you don&#039;t tell it not to do so.&lt;br /&gt;
&lt;br /&gt;
As an example, for Reversi, when someone is playing a disc, we want to wait 500 milliseconds before doing anything else in order the opponent player can figure out what move has been played.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we do this, right after our subscription:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    dojo.subscribe( &#039;playDisc&#039;, this, &amp;quot;notif_playDisc&amp;quot; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;playDisc&#039;, 500 );   // Wait 500 milliseconds after executing the playDisc handler&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
It is also possible to control the delay timing dynamically (e.g., using notification args). As an example, maybe your notification &#039;cardPlayed&#039; should pause for a different amount of time depending on the number or type of cards played.&lt;br /&gt;
&lt;br /&gt;
For this case, use &#039;&#039;&#039;setSynchronous&#039;&#039;&#039; without specifying the duration and use &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039; within the notification callback.&lt;br /&gt;
&lt;br /&gt;
* NOTE: If you forget to invoke &#039;&#039;&#039;setSynchronousDuration&#039;&#039;&#039;, the game will remain paused forever!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
setupNotifications: function () {&lt;br /&gt;
    dojo.subscribe( &#039;cardPlayed&#039;, this, &#039;notif_cardPlayed&#039; );&lt;br /&gt;
    this.notifqueue.setSynchronous( &#039;cardPlayed&#039; ); // wait time is dynamic&lt;br /&gt;
    ...&lt;br /&gt;
},&lt;br /&gt;
&lt;br /&gt;
notif_cardPlayed: function (notif) {&lt;br /&gt;
    // MUST call setSynchronousDuration&lt;br /&gt;
&lt;br /&gt;
    // Example 1: From notification args (PHP)&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(notif.args.duration);&lt;br /&gt;
    ...&lt;br /&gt;
&lt;br /&gt;
    // Or, example 2: Match the duration to a Dojo animation&lt;br /&gt;
    var anim = dojo.fx.combine([&lt;br /&gt;
        ...&lt;br /&gt;
    ]);&lt;br /&gt;
    anim.play();&lt;br /&gt;
    this.notifqueue.setSynchronousDuration(anim.duration);&lt;br /&gt;
},&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
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;
=== Adding static tooltips ===&lt;br /&gt;
&#039;&#039;&#039;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;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;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;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;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;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;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;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 the 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;
&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;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.ajaxcallwrapper(&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;
Note: any traslatable stirng 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;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;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;
At first, create a new &amp;quot;JS template&amp;quot; string in your template (tpl) file:&lt;br /&gt;
&lt;br /&gt;
(from Gomoku example)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var jstpl_player_board = &#039;\&amp;lt;div class=&amp;quot;cp_board&amp;quot;&amp;gt;\&lt;br /&gt;
    &amp;lt;div id=&amp;quot;stoneicon_p${id}&amp;quot; class=&amp;quot;gmk_stoneicon gmk_stoneicon_${color}&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;span id=&amp;quot;stonecount_p${id}&amp;quot;&amp;gt;0&amp;lt;/span&amp;gt;\&lt;br /&gt;
&amp;lt;/div&amp;gt;&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then, you add this piece of code in your JS file to add this template to each player panel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Setting up player boards&lt;br /&gt;
            for( var player_id in gamedatas.players )&lt;br /&gt;
            {&lt;br /&gt;
                var player = gamedatas.players[player_id];&lt;br /&gt;
                         &lt;br /&gt;
                // Setting up players boards if needed&lt;br /&gt;
                var player_board_div = $(&#039;player_board_&#039;+player_id);&lt;br /&gt;
                dojo.place( this.format_block(&#039;jstpl_player_board&#039;, player ), player_board_div );&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Note: the code above is of course from your &amp;quot;setup&amp;quot; function in your Javascript).&lt;br /&gt;
&lt;br /&gt;
Very often, you have to distinguish current player and others players. In this case, you just have to create another JS template (ex: jstpl_otherplayer_board) and use it when &amp;quot;player_id&amp;quot; is different than &amp;quot;this.player_id&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Player&#039;s panel disabling/enabling ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;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;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;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;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;
Note: there is bga component called  &amp;quot;ebg/counter&amp;quot; this API is not using it, these methods&lt;br /&gt;
below declared right in core game. If you need animation for counters use ebg/counter&lt;br /&gt;
&lt;br /&gt;
To use this API just create a counter dom element like this (class does not really matter)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 &amp;lt;div class=&amp;quot;counter&amp;quot; id=&amp;quot;bread&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
 &amp;lt;div class=&amp;quot;counter&amp;quot; id=&amp;quot;coin&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The &amp;quot;bread&amp;quot; will the counter name.&lt;br /&gt;
&lt;br /&gt;
The php code should send all &amp;quot;counters&amp;quot; data from getAllDatas() method like this&lt;br /&gt;
&lt;br /&gt;
game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  protected function getAllDatas() {&lt;br /&gt;
    // (the key must match counter_name)&lt;br /&gt;
    $result[&#039;counters&#039;]=[&lt;br /&gt;
        &#039;bread&#039; =&amp;gt; [ &lt;br /&gt;
         &#039;counter_name&#039; =&amp;gt; &#039;bread&#039;, &lt;br /&gt;
         &#039;counter_value&#039; =&amp;gt; 3&lt;br /&gt;
         ], &lt;br /&gt;
        &#039;coin&#039; =&amp;gt; [&lt;br /&gt;
          &#039;counter_name&#039; =&amp;gt; &#039;coin&#039;, &lt;br /&gt;
          &#039;counter_value&#039; =&amp;gt; 5&lt;br /&gt;
        ]&lt;br /&gt;
   ];&lt;br /&gt;
   return $result;&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setCounter(counter_name:stirng, new_value: string | number): void&lt;br /&gt;
&lt;br /&gt;
updates the global this.gamedatas.counters and value of node $(counter_name)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  notif_counter: function(notif) { &lt;br /&gt;
    this.setCounter(notif.args.counter_name, notif.args.counter_value);&lt;br /&gt;
  },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;incCounter(counter_name:string, delta: number): void&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  notif_counter : function(notif) {&lt;br /&gt;
    this.incCounter(notif.args.counter_name, notif.args.inc);&lt;br /&gt;
  },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;updateCounters(counters: object): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Useful for updating game counters in the player panel (such as resources). &lt;br /&gt;
&#039;counters&#039; arg is map of counters (the key must match counter_name)&lt;br /&gt;
  {&lt;br /&gt;
    &#039;bread&#039;: { &lt;br /&gt;
         &#039;counter_name&#039; : &#039;bread&#039;, &lt;br /&gt;
         &#039;counter_value&#039; =&amp;gt; 3&lt;br /&gt;
    }, &lt;br /&gt;
    &#039;coin&#039;: { &lt;br /&gt;
         &#039;counter_name&#039; : &#039;coin&#039;, &lt;br /&gt;
         &#039;counter_value&#039; =&amp;gt; 5&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
All counters MUST be referenced in this.gamedatas.counters (means they should be send from php) and will be updated.&lt;br /&gt;
DOM objects referenced by &#039;counter_name&#039; will have their innerHTML updated with &#039;counter_value&#039;.&lt;br /&gt;
&lt;br /&gt;
Usually you call this from notification&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                        notif_counter : function(notif) {&lt;br /&gt;
                            this.updateCounters(notif.args.counters);&lt;br /&gt;
                        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA GUI components ==&lt;br /&gt;
&lt;br /&gt;
BGA framework provides some useful ready-to-use components for the game interface:&lt;br /&gt;
&lt;br /&gt;
[[Studio#BGA_Studio_game_components_reference]]&lt;br /&gt;
&lt;br /&gt;
Note that each time you are using an additional component, you must declare it at the top of your Javascript file in the list of modules used.&lt;br /&gt;
&lt;br /&gt;
Example if you are using &amp;quot;ebg.stock&amp;quot;:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;  /// &amp;lt;=== we are using ebg.stock module&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BGA Buttons ==&lt;br /&gt;
&lt;br /&gt;
=== Basic Button ===&lt;br /&gt;
&#039;&#039;&#039;addActionButton( id: string, label: string, method: string | eventhandler, destination?: string, blinking?: boolean, color?:string): void&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can use this method to add an action button in the main action status bar (or other places).&lt;br /&gt;
&lt;br /&gt;
Arguments:&lt;br /&gt;
* id: an element ID that should be unique in your HTML DOM document.&lt;br /&gt;
* label: the text of the button. Should be translatable (use _() function). Note: this can also be any html, such as &amp;quot;&amp;lt;div class=&#039;brick&#039;&amp;gt;&amp;lt;/div&amp;gt;&amp;quot;, see example below on how to make image action buttons.&lt;br /&gt;
* method: the name of your method that must be triggered when the player clicks on this button (can be name of the method on game class or handler).&lt;br /&gt;
* destination (optional): id of parent on where to add button, ONLY use in rare cases if location is not action bar. Use &#039;&#039;&#039;null&#039;&#039;&#039; as value if you need to specify other arguments.&lt;br /&gt;
* blinking (optional): if set to &#039;&#039;&#039;true&#039;&#039;&#039;, the button is going blink to catch player&#039;s attention. Please DO NOT abuse blinking button. If you need button to blink after some time passed add class &#039;blinking&#039; to the button later.&lt;br /&gt;
* color: could be &#039;&#039;&#039;blue&#039;&#039;&#039; (default), &#039;&#039;&#039;red&#039;&#039;&#039;,&#039;&#039;&#039;gray&#039;&#039;&#039; or &#039;&#039;&#039;none&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
You should only use this method in your &amp;quot;onUpdateActionButtons&amp;quot; method. Usually, you use it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onUpdateActionButtons: function( stateName, args ) {                      &lt;br /&gt;
            if (this.isCurrentPlayerActive()) {            &lt;br /&gt;
                switch( stateName ) {&lt;br /&gt;
                case &#039;giveCards&#039;:&lt;br /&gt;
                    this.addActionButton( &#039;giveCards_button&#039;, _(&#039;Give selected cards&#039;), &#039;onGiveCards&#039; ); &lt;br /&gt;
                    this.addActionButton( &#039;pass_button&#039;, _(&#039;Pass&#039;), ()=&amp;gt;this.ajaxcallwrapper(&#039;pass&#039;) ); &lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are adding a &amp;quot;Give selected cards&amp;quot; button in the case we are on game state &amp;quot;giveCards&amp;quot;. When player clicks on this button, it triggers our &amp;quot;onGiveCards&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Example using blinking red button:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    this.addActionButton( &#039;button_confirm&#039;, _(&#039;Confirm?&#039;), &#039;onConfirm&#039;, null, true, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to call the handled with arguments, you can use arrow functions, like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
     this.addActionButton( &#039;commit_button&#039;, _(&#039;Confirm&#039;), () =&amp;gt; this.onConfirm(this.selectedCardId), null, false, &#039;red&#039;); &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Image Button ===&lt;br /&gt;
&lt;br /&gt;
You can use the same method, but add extra class to a button to disable the padding and style it, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.addActionButton( &#039;button_brick&#039;, &#039;&amp;lt;div class=&amp;quot;brick&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&#039;, ()=&amp;gt;{... on brick ...}, null, null, &#039;gray&#039;); &lt;br /&gt;
dojo.addClass(&#039;button_brick&#039;,&#039;bgaimagebutton&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.bgaimagebutton {&lt;br /&gt;
  padding: 0px 12px;&lt;br /&gt;
  min-height: 28px;&lt;br /&gt;
  border: none;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you use this a lot, you can define a helper function, i.e.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * This method can be used instead of addActionButton, to add a button which is an image (i.e. resource). Can be useful when player&lt;br /&gt;
 * need to make a choice of resources or tokens.&lt;br /&gt;
 */&lt;br /&gt;
addImageActionButton: function(id, div, handler, bcolor, tooltip) {&lt;br /&gt;
	if (typeof bcolor == &amp;quot;undefined&amp;quot;) {&lt;br /&gt;
		bcolor = &amp;quot;gray&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
	// this will actually make a transparent button id color = gray&lt;br /&gt;
	this.addActionButton(id, div, handler, null, false, bcolor);&lt;br /&gt;
	// remove 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;dontPreloadImage(image_file_name: string)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Using dontPreloadImage, you tell the interface to not preload a specific image in your img directory.&lt;br /&gt;
&lt;br /&gt;
Example of use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is particularly useful if for example you have 2 different themes for a game. To accelerate the loading of the game, you can specify to not preload images corresponding to the other theme.&lt;br /&gt;
&lt;br /&gt;
Another example of use: in &amp;quot;Gosu&amp;quot; game with Kamakor extension, you play with 5 sets of cards among 10 available. Cards images are organized by sets, and we only preload the images corresponding to the 5 current sets with &#039;&#039;&#039;ensureSpecificGameImageLoading( image_file_names_array )&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// By default, do not preload anything&lt;br /&gt;
this.dontPreloadImage( &#039;cards.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan1.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan2.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan3.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan4.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan5.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan6.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan7.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan8.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan9.png&#039; );&lt;br /&gt;
this.dontPreloadImage( &#039;clan10.png&#039; );&lt;br /&gt;
var to_preload = [];&lt;br /&gt;
for( i in this.gamedatas.clans )&lt;br /&gt;
{&lt;br /&gt;
	var clan_id = this.gamedatas.clans[i];&lt;br /&gt;
	to_preload.push( &#039;clan&#039;+clan_id+&#039;.png&#039; );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
this.ensureSpecificGameImageLoading( to_preload );&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; You don&#039;t need to specify to not preload game box images (game_box.png, game_box75.png...) since they are not preloaded by default.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ensureSpecificGameImageLoading(list: string[])&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is oppostive of dontPreloadImage - its ensure specific images is loaded. Note: only makes sense if preload list is empty, otherwise everything is loaded anyway&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;load specific images&#039;&#039;&#039;&lt;br /&gt;
All images that will be preloaded stored in g_img_preload. If you want to override it directly - there is no API, but you can do this in GAME constructor&lt;br /&gt;
&lt;br /&gt;
          g_img_preload = [&#039;tokens.png&#039;, &#039;trains.png&#039;, &#039;loc_plan.png&#039;, &#039;eng.png&#039;, &#039;eng-back.png&#039;];&lt;br /&gt;
&lt;br /&gt;
You can also set it to empty array and call ensureSpecificGameImageLoading() on specific images&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Sounds ==&lt;br /&gt;
&lt;br /&gt;
Add a custom sound and make it load with your interface:&lt;br /&gt;
&lt;br /&gt;
Add this in your template (.tpl) file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.mp3&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;audio id=&amp;quot;audiosrc_o_&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&amp;quot; src=&amp;quot;{GAMETHEMEURL}img/&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;.ogg&amp;quot; preload=&amp;quot;none&amp;quot; autobuffer&amp;gt;&amp;lt;/audio&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: this is a requirement to provide both a mp3 and a ogg file with the names &amp;lt;code&amp;gt;&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;[.ogg][.mp3]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Play the sound (from your .js file):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
playSound(&#039;&amp;lt;gamename&amp;gt;_&amp;lt;yoursoundname&amp;gt;&#039;);   // do not add &#039;this.&#039; - its a global function&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Disable the standard &amp;quot;move&amp;quot; sound for this move (to replace it with your custom sound):&lt;br /&gt;
&lt;br /&gt;
Add this to your notification handler:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
this.disableNextMoveSound();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: it only disable the sound for the next move.&lt;br /&gt;
&lt;br /&gt;
== Title bar and states ==&lt;br /&gt;
&lt;br /&gt;
=== Client states ===&lt;br /&gt;
&lt;br /&gt;
Client states is a way to simulate the state transition but without actually going&lt;br /&gt;
to server. It is usefull when you need to ask user multiple questions before you&lt;br /&gt;
send things to server&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;setClientState(newState: string, args: object)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
     this.setClientState(&amp;quot;client_playerPicksLocation&amp;quot;, {&lt;br /&gt;
                               descriptionmyturn : _(&amp;quot;${you} must select location&amp;quot;),&lt;br /&gt;
                           });&lt;br /&gt;
&lt;br /&gt;
For more information see [[BGA_Studio_Cookbook#Multi_Step_Interactions:_Select_Worker.2FPlace_Worker_-_Using_Client_States]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;restoreServerGameState()&#039;&#039;&#039;&lt;br /&gt;
If you are in client state it will restore the current server state (cheap undo)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;this.on_client_state&#039;&#039;&#039;&lt;br /&gt;
Boolean indicating that we are in client state&lt;br /&gt;
&lt;br /&gt;
=== Title bar ===&lt;br /&gt;
If you simply want to show something in title bar you can do it directly &lt;br /&gt;
     $(&#039;pagemaintitletext&#039;).innerHTML = text;&lt;br /&gt;
&lt;br /&gt;
This however will not work with parameters and will not draw You in color,&lt;br /&gt;
if you want to do proper args rendering use method below&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;removeActionButtons()&#039;&#039;&#039;&lt;br /&gt;
Removes all buttons from title bar&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;updatePageTitle()&#039;&#039;&#039;&lt;br /&gt;
:This function allows to update the current page title and turn description according to the game state 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;
== Other useful stuff ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;dojo.hitch&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
With dojo.hitch, you can create a callback function that will run with your game object context whatever happen.&lt;br /&gt;
&lt;br /&gt;
Typical example: display a BGA confirmation dialog with a callback function created with dojo.hitch:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), dojo.hitch( this, function() {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, function( result ) {} );&lt;br /&gt;
        } ) );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, using dojo.hitch, we ensure that the &amp;quot;this&amp;quot; object will be set when the callback is called.&lt;br /&gt;
&lt;br /&gt;
NOTE: In modern JS there are lambdas that eliminate need for that, the example above will look like this&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        this.confirmationDialog( _(&#039;Are you sure you want to make this?&#039;), () =&amp;gt; {&lt;br /&gt;
            this.ajaxcall( &#039;/mygame/mygame/makeThis.html&#039;, { lock:true }, this, (result) =&amp;gt; {} );&lt;br /&gt;
        } );   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
;&#039;&#039;&#039;onScreenWidthChange()&#039;&#039;&#039;&lt;br /&gt;
:This function can be overridden in your game to manage some resizing on the client side when the browser window is resized. This function is also triggered at load time, so it can be used to adapt to the :viewport size at the start of the game too.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; this.bRealtime&lt;br /&gt;
: Return true if the game is in realtime. Note that having a distinct behavior in realtime and turn-based should be exceptional.&lt;br /&gt;
&lt;br /&gt;
; g_replayFrom&lt;br /&gt;
: Global contains reply number in live game, it is set to undefined (i.e. not set) when it is not a reply mode, so consequentially the good check is &#039;&#039;&#039;typeof g_replayFrom != &#039;undefined&#039;&#039;&#039;&#039; which returns true if the game is in replay mode &amp;lt;i&amp;gt;during the game&amp;lt;/i&amp;gt; (the game is ongoing but the user clicked &amp;quot;reply from this move&amp;quot; in the log)&lt;br /&gt;
&lt;br /&gt;
; g_archive_mode&lt;br /&gt;
: Returns true if the game is in archive mode &amp;lt;i&amp;gt;after the game&amp;lt;/i&amp;gt; (the game has ended)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; this.instantaneousMode&lt;br /&gt;
: Returns true during replay/archive mode if animations should be skipped. Only needed if you are doing custom animations. (The BGA-provided animation functions like &amp;lt;i&amp;gt;this.slideToObject()&amp;lt;/i&amp;gt; automatically handle instantaneous mode.)&lt;br /&gt;
: Technically, when you click &amp;quot;replay from move #20&amp;quot;, the system replays the game from the very beginning with moves 0 - 19 happening in instantaneous mode and moves 20+ happening in normal mode.&lt;br /&gt;
&lt;br /&gt;
; g_tutorialwritten&lt;br /&gt;
: Returns an object like the below if the game is in tutorial mode, or undefined otherwise. Tutorial mode is a special case of archive mode where comments have been added to a previous game to teach new players the rules.&lt;br /&gt;
    {&lt;br /&gt;
        author: &amp;quot;91577332&amp;quot;,&lt;br /&gt;
        id: &amp;quot;576&amp;quot;,&lt;br /&gt;
        mode: &amp;quot;view&amp;quot;&lt;br /&gt;
        status: &amp;quot;alpha&amp;quot;&lt;br /&gt;
        version_override: null&lt;br /&gt;
        viewer_id: &amp;quot;84554161&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&#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>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_photosynthesis&amp;diff=16561</id>
		<title>Tips photosynthesis</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_photosynthesis&amp;diff=16561"/>
		<updated>2023-04-10T14:48:30Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Overhaul with more detailed strategy&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== General Strategy ===&lt;br /&gt;
The key build pattern is to separate each of your trees by an &amp;quot;L&amp;quot; shape/pseudo-knight&#039;s move (one space away in 2 adjacent directions) such that they will never block each others light.  Naturally everyone will be trying to do this which inevitably leads to contested tree spaces.  &lt;br /&gt;
&lt;br /&gt;
Always think about what your plan is on the next turn.  How much sun will you get?  If you&#039;re playing with heavy shadow, which of your trees will you be able to grow?  To accurately answer both of these questions you need to consider the turn order and make educated guesses about where your opponent(s) will grow.  This is something you build an intuition for over time, but generally imagine you were them.  Where would you want to grow?  Check how much sun they have and what trees they have in stock to determine what they&#039;re capable of.  This has a major impact on where you want to grow so that you are not blocked and/or you can block them.&lt;br /&gt;
&lt;br /&gt;
It&#039;s worth emphasizing how important the turn order is as well.  If you&#039;re going first in a round, you get first pick of spaces to plant seeds and grow your trees without being shadowed by opponents&#039; growth and the opportunity to cast shadows on where they want to grow (heavy shadow).  But going last can be good too.  Imagine you have 2 different trees that you could grow.  Either could be shadowed or in the sun on the next turn depending on which trees your opponents choose to grow.  If you go last, you now have full info to grow the correct tree to gain sun.&amp;lt;blockquote&amp;gt;Note: most of this advice is written with 3-player, 3-round heavy shadow games in mind as that&#039;s currently (April 2023) the competitive format.  In 2-player games the board is much less contested and players are more free to expand.  Without heavy shadow there&#039;s generally much less thinking required.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Early Game ===&lt;br /&gt;
On your first turn, upgrade a small tree to a medium tree. This leads to additional sun income but more importantly lets you plant seeds 2 spaces away (L shape).  It is often better to stake your claim over a spot by planting a seed than it is to upgrade your tree for more sun.  Your additional trees in prime locations will lead to more sun in the long-term.  Don&#039;t get greedy with maxing early sun; take the prime real estate while it&#039;s available.&lt;br /&gt;
&lt;br /&gt;
It may seem like going for the center in 3+ player games is crucial, but there are often situations where you can never grow your seed (assuming heavy shadow) as it&#039;s easy to be surrounded on all sides.&lt;br /&gt;
&lt;br /&gt;
=== Mid Game ===&lt;br /&gt;
Your goal should be to get all your level 2 and 3 trees on the board.  Until you have done this you should &#039;&#039;never&#039;&#039; be scoring your trees.  This is a waste of sun both in that you could have spent it on growing your engine &#039;&#039;and&#039;&#039; you&#039;ve thrown away the 3 income that tree produces.  Once you have spent all your level 3 trees and there&#039;s nowhere left to build 2&#039;s then you have no choice but to start collecting.  Even then you should be checking your sun limit of 20.  If the next turn&#039;s sunlight does not put you over 20, &#039;&#039;do not collect&#039;&#039;.  In some cases even if it puts you 1 or 2 over, waiting to collect may be better.  Think carefully before planting any seeds toward the end of round 2.  If they do not (a) net you 5 sun (the cost to plant a seed and level 1 tree) or (b) have enough time and sun to be grown to level 3 and collected, then you should probably not build it.  In very rare cases planting a seed just to block an opponent&#039;s potential tree &#039;&#039;may&#039;&#039; be beneficial but probably not.&lt;br /&gt;
&lt;br /&gt;
=== Late Game ===&lt;br /&gt;
The last round of the game is all about carefully growing and collecting your remaining trees.  Leave up the trees that block your opponent&#039;s sun and collect the trees that block your own sun ideally on the turn right before this would occur.  In heavy shadow you also need to make sure you can both grow &#039;&#039;and collect&#039;&#039; your trees since both actions are potentially blocked by opponent&#039;s taller trees.  The key threshold each turn is 12 sun.  This is how much you need to collect a tree, re-buy that tree, and plant it (4+5+3).  Aim to do this as many turns as possible in the final round and you should at least be a contender for victory.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_livingforest&amp;diff=16530</id>
		<title>Tips livingforest</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_livingforest&amp;diff=16530"/>
		<updated>2023-04-07T21:34:57Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;WIP&lt;br /&gt;
&lt;br /&gt;
Unlike creature cards, you may only buy one tree per action. You can get two trees in a turn by landing on the &#039;buy a tree&#039; action on the spiral. With careful planning, you can chain together 4 actions in a turn.&lt;br /&gt;
&lt;br /&gt;
Everyone starts with 0 Gregarious (White) and 5 Solitary (Black) Guardian Animals. &lt;br /&gt;
Count the number of symbols in your draw deck and discard pile to know what you will be drawing.&lt;br /&gt;
For example, drawing 3 solitary symbols in your first 3 cards means the rest of your draw pile only contains 2 solitary symbols (for your next turn).  This cheatsheet created by a BGG user is incredibly helpful for tracking your remaining cards and what they do:&lt;br /&gt;
&lt;br /&gt;
https://boardgamegeek.com/filepage/233342/starting-deck-symbols&lt;br /&gt;
&lt;br /&gt;
You should very rarely be drawing after hitting 2 Solitary animals unless you are very far behind or do not have a viable turn without more draws.  If you are starting your turn with a low deck, it&#039;s better to wait Fragments (discards) until after you reshuffle - though notably this is only really possible with 2 or less Solitaries remaining barring a Gregarious.&lt;br /&gt;
&lt;br /&gt;
Pay attention to the turn order (first player token). &lt;br /&gt;
Attracting Guardian Animal allows the first player of the next turn to extinguish the Fire.&lt;br /&gt;
&lt;br /&gt;
Remember that you may buy identical Protective Trees, especially if you are not aiming for Tree victory.&lt;br /&gt;
This can be important for denying your opponents or stacking Sacred Flowers.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t underestimate the value of high movement.  Stealing other players&#039; tokens is a big point swing and it lets you cheat 2 of the same action without getting the big tree.  At the same time, consider holding your space if it&#039;s very valuable to an opponent so that they can&#039;t land on it.  This often applies to tree planting spaces.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_gizmos&amp;diff=15923</id>
		<title>Tips gizmos</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_gizmos&amp;diff=15923"/>
		<updated>2023-02-02T15:14:31Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Added detail&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;At its core Gizmos is a resource management engine building game thus the goal is to maximize your obtainment and value of each resource - chiefly Energy (and indirectly engine power) in the early game and then points in the late game.  So naturally you should be focusing on the Gizmos that help you get more Energy and then more points.&lt;br /&gt;
&lt;br /&gt;
== Early Game ==&lt;br /&gt;
&lt;br /&gt;
You start limited to taking one action per turn (technically two with the starting file trigger).  Your goal is to gain extra actions as quickly as possible.  Buying upgrades is generally a very poor idea at this point.  Buying a converter can be good, but for the most part you should be looking for Build into Pick triggers &amp;gt; Pick into Draw triggers &amp;gt; File into Pick triggers.  Once you have one or more of these you should look for other Gizmos that align with the color.  If you already have a Build Red into Pick Gizmo, buying a Build Red into VP Gizmo is fantastic.  If you already have a Pick Blue into Draw trigger, buying a Blue Converter is a great idea.  That being said, dipping into other colors is not a bad idea if that&#039;s the only option available to you.  It&#039;s good to be flexible so that you&#039;re not only looking for a single color of Gizmo/Energy.&lt;br /&gt;
&lt;br /&gt;
Your first action should almost always be filing a Gizmo.  If there are no Build or Pick Triggers in row I or II, then research Level I to look for one.&lt;br /&gt;
&lt;br /&gt;
=== The File Strategy ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s worth mentioning that some people believe there to be two strategies in Gizmos: one focused on building a lot and another focused on filing a lot.  A well played build strategy will beat a file focused strategy more than 90% of the time because building a lot of Gizmos ends the game so much faster than filing.  Every file action you take is one less build that you could have taken.  The only chance the file strategy has is to build 4 Level III Gizmos but that rarely comes together.  Putting your opponents on a clock is very important.&lt;br /&gt;
&lt;br /&gt;
== Mid Game / General Strategy ==&lt;br /&gt;
&lt;br /&gt;
If you have a good build/pick engine going, the value of buying Upgrades, Build into VP, and Converters goes up.&lt;br /&gt;
&lt;br /&gt;
The most skill-testing part of Gizmos is determining when you should take a risk by Researching versus accepting a potentially suboptimal Gizmo from the row.  This is something you simply have to build an intuition for over time, but it&#039;s worth mentioning a general principle present in all games that involve mitigating randomness: how risky you are playing should be inversely proportional to how much you are winning.  Are you winning?  Don&#039;t take unnecessary risks - just keep winning.  Are you losing?  Take some big risks to get back in the game - you&#039;ll just lose if you don&#039;t.  Obviously you&#039;re usually somewhere in-between but the principle is an important one.&lt;br /&gt;
&lt;br /&gt;
Keep in mind that Level 3 multi-color Gizmos trigger ALL of your Build cards.  Building random VP Gizmos even if they do not align with your usual build colors can be good for this reason.  But also remember that each game includes a random 16 Level III cards out of the total pool of 36.  So it is entirely possible, albeit unlikely, that none of the multi-color Gizmos made it into the Game.  There&#039;s no way to know until you&#039;ve researched the whole deck.&lt;br /&gt;
&lt;br /&gt;
== Late Game ==&lt;br /&gt;
&lt;br /&gt;
Reevaluate where you are at point-wise relative to your opponents.  Do you need to research Level III hoping to find a big finisher?  Or can you just build that face up Level II and coast to a victory?  Most of the time the player that builds the 16th Gizmo is also the winner.  Double check who first player is so you know who will get another turn and who does not.  Try to be the player that sets the pace of the game.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_gizmos&amp;diff=15767</id>
		<title>Tips gizmos</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_gizmos&amp;diff=15767"/>
		<updated>2023-01-20T01:47:57Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Initial creation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Build an engine that lets you repeatedly buy Gizmos while getting multiple new energies on each purchase.&lt;br /&gt;
&lt;br /&gt;
TODO: elaborate&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_raceforthegalaxy&amp;diff=14971</id>
		<title>Tips raceforthegalaxy</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_raceforthegalaxy&amp;diff=14971"/>
		<updated>2022-10-06T18:28:19Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: /* == */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Base Game Only, 2 Player only variant.&lt;br /&gt;
Race for the Galaxy is a resource management game.  The game is won through Victory Points (VP). The 2 possible ways to get VP are: &lt;br /&gt;
1. Playing developments &amp;amp; worlds. &lt;br /&gt;
2. Consuming goods to gain the additional VP chips.&lt;br /&gt;
&lt;br /&gt;
So the following strategies are based around one or both of these methods.&lt;br /&gt;
&lt;br /&gt;
== Gameflow ==&lt;br /&gt;
&lt;br /&gt;
Broadly speaking, most common strategies go though 3 different phases.&lt;br /&gt;
&lt;br /&gt;
=== 0. Starting Cards: ===&lt;br /&gt;
Some starting cards are strictly stronger than others, but you always want to consider synergy with your hand.  If you have a military windfall world in hand, keep the starting card with military.  Improved Explore, discounts, and card draw are ideal.  Barring that a windfall world into $ consume is a very effective start to open up options.  If you have neither, starting with a +1,+6 Explore is often the best first turn to find some gas for your engine.&lt;br /&gt;
&lt;br /&gt;
=== 1. Start of the game: ===&lt;br /&gt;
Money (cards in hand) and resource generation (improved Explore/discounts/card draw) is more important than VP at this stage.&lt;br /&gt;
Gain cards in hand by trading goods, normally from cheap windfall worlds, or exploring.&lt;br /&gt;
You may also see some small trading improvement cards which aid this strategy like &#039;Export Duties&#039; or &#039;Spice World&#039;&lt;br /&gt;
&lt;br /&gt;
=== 2. Middle game: ===&lt;br /&gt;
Develop a card drawing and/or goods producing engine by playing card cost saving and gaining cards. &lt;br /&gt;
Examples include &#039;Drop Ships&#039;, &#039;Replicant Robots&#039;, &#039;Diverse Economy&#039;, &#039;Consumer Markets&#039;.&lt;br /&gt;
Not to be overlooked are lots of cards which aid free stuff in the produce phase.&lt;br /&gt;
&lt;br /&gt;
=== 3. End game: ===&lt;br /&gt;
The game ends after a player reaches 12 developments &amp;amp; worlds or 24 VP chips (in 2-player games, the pool of VP chips is 12 per player) have been gained. These two ways of ending the game also broadly categorize the strategies for winning the game.&lt;br /&gt;
You either aim to out develop/settle your opponent with superior card drawing/discount engine, or aim to build a produce and consumeX2 engine that nets roughly 6 more VP chips per turn than your opponent. Expansion will struggle to keep up with 6 points per turn, but each strategy can diversify into the other to take advantage of the opponent&#039;s phases (see Drafting / Leeching).&lt;br /&gt;
&lt;br /&gt;
Recognize the turn the game will likely end, and build 6? point developments that gain lots of points in the final count. Build other high scoring worlds like alien worlds and military worlds.&lt;br /&gt;
Whatever you decide it should be to maximize your potential of hand and cards on the table, and looking to see how your position best plays against your opponents to secure victory.&lt;br /&gt;
Occasionally you may tell that the only way to victory could be to +5/0 explore to dig for that one final 6 point dev card that will earn you 14 points. Better to go down fighting than to simply concede.&lt;br /&gt;
&lt;br /&gt;
== General Strategy ==&lt;br /&gt;
&lt;br /&gt;
=== Drafting / Leeching / Playing the opponent: ===&lt;br /&gt;
Whatever you want to call it, the strategy of your opponent should be considered at all times. This is not just a multiplayer solitaire game.&lt;br /&gt;
So at the &#039;choose actions&#039; initial part of the round, consider what benefits you the most, but also consider what benefits your opponent the least.&lt;br /&gt;
For example, if your opponent has very few cards in hand, their develop and settle options may be limited - especially if they have no develop/settle engine powers or military.&lt;br /&gt;
Alternatively, if their tableau has no produce powers, you might safely produce without gifting your opponent free goods and VP. It&#039;s even better if you have developments/worlds with production powers in hand, which guarantees that if they settle a production development/world, you get to develop/settle one too and remain ahead.  Conversely anticipate when your opponent will recognize this about your hand and choose Explore to hopefully get you playable options.&lt;br /&gt;
&lt;br /&gt;
Stay flexible. Take and keep cheap, easy to play filler cards to leech develops and settles.&lt;br /&gt;
Occasionally you get the &#039;zugzwang&#039; feeling, where both players would normally choose produce or settle (or any other action type) but neither do because insufficient advantage would be gained from calling it. An example of this would be two players with equal produce/consume engines - neither wishes to call produce when they could use another phase to try to outflank the opponent, so both players pivot to expansion until one player finds advantage in producing again.&lt;br /&gt;
&lt;br /&gt;
So the likelihood and the beauty of the game is that there is no one strategy to beat all others. You must be willing to be flexible at all times to maximize your position&#039;s dominance over your opponent&#039;s.&lt;br /&gt;
&lt;br /&gt;
=== Pacing ===&lt;br /&gt;
Depending on the strategy both you and your opponent are playing, one of you is likely to benefit more from extending the game.  Correctly identifying which player that is can be crucial.  If you have some powerful 6? cards in hand, you may want to take less Develop/Settle actions as this expedites the end game.  If you are off to an earlier start (better discounts / draw engine) you may want to take as many Develop/Settle actions as you possibly can to give your opponent less time to find their engine.  If you can correctly anticipate your opponents action, then you can double up on the other which further speeds up the game.&lt;br /&gt;
&lt;br /&gt;
=== Some small extra tips: ===&lt;br /&gt;
Yes, some games may only last 6 or 7 rounds and you&#039;ve just been beaten by a very rapid cheap blue or brown 2x consume and produce tactic.&lt;br /&gt;
Leaving 0 or few cards in the hand after a round can leave you exposed. If you do this then you need to have a plan, like a alien yellow windfall world ready to be traded or something.&lt;br /&gt;
It&#039;s a race; always question your position and the end of the game, try to finish on a high, 6 point development cards are often played in the final round to steal the win.&lt;br /&gt;
A non military strategy can still deploy a 7 point rebel world with the help of the &#039;Contact Specialist&#039;.&lt;br /&gt;
Don&#039;t blame the card draw, 95% of the time a credible alternative is available. It sucks to lose, play better next time!&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_wingspan&amp;diff=14970</id>
		<title>Tips wingspan</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_wingspan&amp;diff=14970"/>
		<updated>2022-10-06T16:47:36Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: More formatting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
At its core Wingspan is an engine building resource management game.  Your most finite resources is actions as you are limited to 26 (8+7+6+5) of these each game.  So generally speaking you want to get the most out of every action.  Play that bird before you take an action in its row so that you get an extra resource.  There are of course exceptions to this e.g. if you need to move up in the rankings for an end of round goal.&lt;br /&gt;
&lt;br /&gt;
== Early Game ==&lt;br /&gt;
&lt;br /&gt;
When the game starts take the time to analyze each of these goals as they will heavily shape what to go for in this game.  Lots of egg goals?  Investing more into the grasslands may be a good idea.  Lots of bird goals?  Investing more into the Forest may be better.  These are both oversimplifications as generally speaking you will build birds in every habitat and take every action over the course of most games.  There are many other important considerations: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Many nest-specific goals means the wild nest birds are stronger&amp;lt;br/&amp;gt;&lt;br /&gt;
• Consider which nest goals exist and lean more on keeping and playing birds with that nest&amp;lt;br/&amp;gt;&lt;br /&gt;
• Varying location based goals (eggs or birds in one of the 3 habitats) means the flighty birds (when on the right change habitat) are stronger&amp;lt;br/&amp;gt;&lt;br /&gt;
• With all of the above in mind, specific pink birds become stronger too as opponents are forced into taking these actions or forgo end of round goals&amp;lt;br/&amp;gt;&lt;br /&gt;
• Weight the later goals more heavily since these are worth more points - there&#039;s nothing wrong with skipping the first goal or two if it means positioning yourself to win the last one or two&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
You should think of the bonus cards as additional private end of game goals.  Consider whether one of your bonus cards aligns with later end of round goals as that increases its value.  Then move to your birds.  Cross reference the end of round goals and above info with your hand and the available birds.  Ideally you want to plan out your first few turns.  Some general principles:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Brown and pink action birds are ideal in the early game when there is more time to trigger their ability.  More specifically you want powers that generate additional resources - cards &amp;gt; food &amp;gt; eggs.  With that...&amp;lt;br/&amp;gt;&lt;br /&gt;
•• Cards: this is the most important resource.  Having a good card draw/cycle engine lets you find the birds you actually want to play often while scoring tuck points&amp;lt;br/&amp;gt;&lt;br /&gt;
•• Food: you need food to play your cards, but you don&#039;t know what food you need until you find good cards and you can discard cards for food.  Over the course of a game you should be drawing (and pitching) a lot more cards than food.  Caching food is basically always worse than gaining it until the last turn or two depending on what birds and how much food you have&amp;lt;br/&amp;gt;&lt;br /&gt;
•• Eggs: eggs are inherently less valuable than the other resources until the end of the game when eggs score points whereas cards and food do not.  I say inherently because at every step you get 1 more egg than the other resources.  So early in the game, you almost always want to spend an egg to draw (if you can) whereas later you need to think about it a bit more&amp;lt;br/&amp;gt;&lt;br /&gt;
• The best starting birds either draw you food or cards.  If you get both, your early game should run very smoothly&amp;lt;br/&amp;gt;&lt;br /&gt;
•• You should obviously consider the cost of each bird when making this decision.  That 3-cost food producer might be good early, but consider how that will impact your ability to play other birds.&amp;lt;br/&amp;gt;&lt;br /&gt;
• Note if you&#039;re going first as you are guaranteed your pick of the shown birds which may be better to start with than any in your hand - there&#039;s nothing wrong with drawing a powerful bird on your first turn&amp;lt;br/&amp;gt;&lt;br /&gt;
• Generally you should be keeping 1-3 birds.  Keeping 5 should literally never be done and keeping 4 only makes sense if your hand is insane and/or you have a 1-cost forest bird going into 2 food production&amp;lt;br/&amp;gt;&lt;br /&gt;
• Be wary of any actions that benefit opponents equally to you.  These are probably bad in almost all cases&lt;br /&gt;
&lt;br /&gt;
== Mid-Game ==&lt;br /&gt;
&lt;br /&gt;
You should have a small resource engine hopefully consisting of birds that play toward at least one goal.  Here are some principles focused more on the midgame:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
• Routinely check your opponents boards and consider which remaining goals you have a realistic chance at winning.  Compare how hard you have to invest into the goal, how likely you are to win it, and what you could be doing instead which might yield a greater long-term return e.g. maybe a later goal if players are less invested into it&amp;lt;br/&amp;gt;&lt;br /&gt;
•• You should check their resource count and engine power as this factors in to how much they can develop into goals.  If you&#039;re not that far behind then you may see that their resources cannot (or are very unlikely) to outpace you&amp;lt;br/&amp;gt;&lt;br /&gt;
• Also check for pink birds.  In some cases you should actually skip an action (e.g. predator) to prevent an opponent from gaining a more valuable resource (food is generally worth more than one point).  But this is just a consideration - you can&#039;t skip playing birds in a habitat altogether but maybe you can wait to do it on the same turn as another opponent&amp;lt;br/&amp;gt;&lt;br /&gt;
• It is good to play bonus card birds in the mid game.  This will give you time to play toward the goal while having less impact on your early engine&amp;lt;br/&amp;gt;&lt;br /&gt;
• If you have a good card draw engine, prioritize and collect additional play birds.  Planning around big bird chains in the last round can often turn the tide of a game&lt;br /&gt;
&lt;br /&gt;
== End Game ==&lt;br /&gt;
&lt;br /&gt;
As the 3rd round comes to an end and the final round approaches you should be able to plan out the rest of your turns.  Make a final decision on which goals you can reasonably commit to and play accordingly.  It&#039;s okay to not always get the highest tier goal.  Maybe playing out your non-goal birds in hand yields more points.  Keep in mind that every round you spend gathering food to play your birds is a lost opportunity for other ways to gain points so maybe you should be stocking your remaining birds with eggs instead.  You should be able to calculate which route has the highest expected score.  Good luck!&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_wingspan&amp;diff=14968</id>
		<title>Tips wingspan</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_wingspan&amp;diff=14968"/>
		<updated>2022-10-06T02:47:03Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Formatting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
&lt;br /&gt;
At its core Wingspan is an engine building resource management game.  Your most finite resources is actions as you are limited to 26 (8+7+6+5) of these each game.  So generally speaking you want to get the most out of every action.  Play that bird before you take an action in its row so that you get an extra resource.  There are of course exceptions to this e.g. if you need to move up in the rankings for an end of round goal.&lt;br /&gt;
&lt;br /&gt;
== Early Game ==&lt;br /&gt;
&lt;br /&gt;
When the game starts take the time to analyze each of these goals as they will heavily shape what to go for in this game.  Lots of egg goals?  Investing more into the grasslands may be a good idea.  Lots of bird goals?  Investing more into the Forest may be better.  These are both oversimplifications as generally speaking you will build birds in every habitat and take every action over the course of most games.  There are many other important considerations: &lt;br /&gt;
&lt;br /&gt;
* Many nest-specific goals means the wild nest birds are stronger&lt;br /&gt;
* Consider which nest goals exist and lean more on keeping and playing birds with that nest&lt;br /&gt;
* Varying location based goals (eggs or birds in one of the 3 habitats) means the flighty birds (when on the right change habitat) are stronger&lt;br /&gt;
* With all of the above in mind, specific pink birds become stronger too as opponents are forced into taking these actions or forgo end of round goals&lt;br /&gt;
* Weight the later goals more heavily since these are worth more points - there&#039;s nothing wrong with skipping the first goal or two if it means positioning yourself to win the last one or two&lt;br /&gt;
&lt;br /&gt;
You should think of the bonus cards as additional private end of game goals.  Consider whether one of your bonus cards aligns with later end of round goals as that increases its value.  Then move to your birds.  Cross reference the end of round goals and above info with your hand and the available birds.  Ideally you want to plan out your first few turns.  Some general principles:&lt;br /&gt;
&lt;br /&gt;
* Brown and pink action birds are ideal in the early game when there is more time to trigger their ability.  More specifically you want powers that generate additional resources - cards &amp;gt; food &amp;gt; eggs.  With that...&lt;br /&gt;
** Cards: this is the most important resource.  Having a good card draw/cycle engine lets you find the birds you actually want to play often while scoring tuck points&lt;br /&gt;
** Food: you need food to play your cards, but you don&#039;t know what food you need until you find good cards and you can discard cards for food.  Over the course of a game you should be drawing (and pitching) a lot more cards than food.  Caching food is basically always worse than gaining it until the last turn or two depending on what birds and how much food you have&lt;br /&gt;
** Eggs: eggs are inherently less valuable than the other resources until the end of the game when eggs score points whereas cards and food do not.  I say inherently because at every step you get 1 more egg than the other resources.  So early in the game, you almost always want to spend an egg to draw (if you can) whereas later you need to think about it a bit more&lt;br /&gt;
* The best starting birds either draw you food or cards.  If you get both, your early game should run very smoothly&lt;br /&gt;
** You should obviously consider the cost of each bird when making this decision.  That 3-cost food producer might be good early, but consider how that will impact your ability to play other birds.&lt;br /&gt;
* Note if you&#039;re going first as you are guaranteed your pick of the shown birds which may be better to start with than any in your hand - there&#039;s nothing wrong with drawing a powerful bird on your first turn&lt;br /&gt;
* Generally you should be keeping 1-3 birds.  Keeping 5 should literally never be done and keeping 4 only makes sense if your hand is insane and/or you have a 1-cost forest bird going into 2 food production&lt;br /&gt;
* Be wary of any actions that benefit opponents equally to you.  These are probably bad in almost all cases&lt;br /&gt;
&lt;br /&gt;
== Mid-Game ==&lt;br /&gt;
&lt;br /&gt;
You should have a small resource engine hopefully consisting of birds that play toward at least one goal.  Here are some principles focused more on the midgame:&lt;br /&gt;
&lt;br /&gt;
* Routinely check your opponents boards and consider which remaining goals you have a realistic chance at winning.  Compare how hard you have to invest into the goal, how likely you are to win it, and what you could be doing instead which might yield a greater long-term return e.g. maybe a later goal if players are less invested into it&lt;br /&gt;
** You should check their resource count and engine power as this factors in to how much they can develop into goals.  If you&#039;re not that far behind then you may see that their resources cannot (or are very unlikely) to outpace you&lt;br /&gt;
* Also check for pink birds.  In some cases you should actually skip an action (e.g. predator) to prevent an opponent from gaining a more valuable resource (food is generally worth more than one point).  But this is just a consideration - you can&#039;t skip playing birds in a habitat altogether but maybe you can wait to do it on the same turn as another opponent&lt;br /&gt;
* It is good to play bonus card birds in the mid game.  This will give you time to play toward the goal while having less impact on your early engine&lt;br /&gt;
* If you have a good card draw engine, prioritize and collect additional play birds.  Planning around big bird chains in the last round can often turn the tide of a game&lt;br /&gt;
&lt;br /&gt;
== End Game ==&lt;br /&gt;
&lt;br /&gt;
As the 3rd round comes to an end and the final round approaches you should be able to plan out the rest of your turns.  Make a final decision on which goals you can reasonably commit to and play accordingly.  It&#039;s okay to not always get the highest tier goal.  Maybe playing out your non-goal birds in hand yields more points.  Or maybe you should stock your remaining birds with eggs.  You should be able to calculate which route has the highest expected score.  Good luck!&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_wingspan&amp;diff=14967</id>
		<title>Tips wingspan</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_wingspan&amp;diff=14967"/>
		<updated>2022-10-06T02:44:58Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Initial creation with general strategy&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Wingspan Strategy ==&lt;br /&gt;
&lt;br /&gt;
=== Introduction ===&lt;br /&gt;
&lt;br /&gt;
At its core Wingspan is an engine building resource management game.  Your most finite resources is actions as you are limited to 26 (8+7+6+5) of these each game.  So generally speaking you want to get the most out of every action.  Play that bird before you take an action in its row so that you get an extra resource.  There are of course exceptions to this e.g. if you need to move up in the rankings for an end of round goal.&lt;br /&gt;
&lt;br /&gt;
=== Early Game ===&lt;br /&gt;
&lt;br /&gt;
When the game starts take the time to analyze each of these goals as they will heavily shape what to go for in this game.  Lots of egg goals?  Investing more into the grasslands may be a good idea.  Lots of bird goals?  Investing more into the Forest may be better.  These are both oversimplifications as generally speaking you will build birds in every habitat and take every action over the course of most games.  There are many other important considerations: &lt;br /&gt;
&lt;br /&gt;
* Many nest-specific goals means the wild nest birds are stronger&lt;br /&gt;
* Consider which nest goals exist and lean more on keeping and playing birds with that nest&lt;br /&gt;
* Varying location based goals (eggs or birds in one of the 3 habitats) means the flighty birds (when on the right change habitat) are stronger&lt;br /&gt;
* With all of the above in mind, specific pink birds become stronger too as opponents are forced into taking these actions or forgo end of round goals&lt;br /&gt;
* Weight the later goals more heavily since these are worth more points - there&#039;s nothing wrong with skipping the first goal or two if it means positioning yourself to win the last one or two&lt;br /&gt;
&lt;br /&gt;
You should think of the bonus cards as additional private end of game goals.  Consider whether one of your bonus cards aligns with later end of round goals as that increases its value.  Then move to your birds.  Cross reference the end of round goals and above info with your hand and the available birds.  Ideally you want to plan out your first few turns.  Some general principles:&lt;br /&gt;
&lt;br /&gt;
* Brown and pink action birds are ideal in the early game when there is more time to trigger their ability.  More specifically you want powers that generate additional resources - cards &amp;gt; food &amp;gt; eggs.  With that...&lt;br /&gt;
** Cards: this is the most important resource.  Having a good card draw/cycle engine lets you find the birds you actually want to play often while scoring tuck points&lt;br /&gt;
** Food: you need food to play your cards, but you don&#039;t know what food you need until you find good cards and you can discard cards for food.  Over the course of a game you should be drawing (and pitching) a lot more cards than food.  Caching food is basically always worse than gaining it until the last turn or two depending on what birds and how much food you have&lt;br /&gt;
** Eggs: eggs are inherently less valuable than the other resources until the end of the game when eggs score points whereas cards and food do not.  I say inherently because at every step you get 1 more egg than the other resources.  So early in the game, you almost always want to spend an egg to draw (if you can) whereas later you need to think about it a bit more&lt;br /&gt;
* The best starting birds either draw you food or cards.  If you get both, your early game should run very smoothly&lt;br /&gt;
** You should obviously consider the cost of each bird when making this decision.  That 3-cost food producer might be good early, but consider how that will impact your ability to play other birds.&lt;br /&gt;
* Note if you&#039;re going first as you are guaranteed your pick of the shown birds which may be better to start with than any in your hand - there&#039;s nothing wrong with drawing a powerful bird on your first turn&lt;br /&gt;
* Generally you should be keeping 1-3 birds.  Keeping 5 should literally never be done and keeping 4 only makes sense if your hand is insane and/or you have a 1-cost forest bird going into 2 food production&lt;br /&gt;
* Be wary of any actions that benefit opponents equally to you.  These are probably bad in almost all cases&lt;br /&gt;
&lt;br /&gt;
=== Mid-Game ===&lt;br /&gt;
&lt;br /&gt;
You should have a small resource engine hopefully consisting of birds that play toward at least one goal.  Here are some principles focused more on the midgame:&lt;br /&gt;
&lt;br /&gt;
* Routinely check your opponents boards and consider which remaining goals you have a realistic chance at winning.  Compare how hard you have to invest into the goal, how likely you are to win it, and what you could be doing instead which might yield a greater long-term return e.g. maybe a later goal if players are less invested into it&lt;br /&gt;
** You should check their resource count and engine power as this factors in to how much they can develop into goals.  If you&#039;re not that far behind then you may see that their resources cannot (or are very unlikely) to outpace you&lt;br /&gt;
* Also check for pink birds.  In some cases you should actually skip an action (e.g. predator) to prevent an opponent from gaining a more valuable resource (food is generally worth more than one point).  But this is just a consideration - you can&#039;t skip playing birds in a habitat altogether but maybe you can wait to do it on the same turn as another opponent&lt;br /&gt;
* It is good to play bonus card birds in the mid game.  This will give you time to play toward the goal while having less impact on your early engine&lt;br /&gt;
* If you have a good card draw engine, prioritize and collect additional play birds.  Planning around big bird chains in the last round can often turn the tide of a game&lt;br /&gt;
&lt;br /&gt;
=== End Game ===&lt;br /&gt;
&lt;br /&gt;
As the 3rd round comes to an end and the final round approaches you should be able to plan out the rest of your turns.  Make a final decision on which goals you can reasonably commit to and play accordingly.  It&#039;s okay to not always get the highest tier goal.  Maybe playing out your non-goal birds in hand yields more points.  Or maybe you should stock your remaining birds with eggs.  You should be able to calculate which route has the highest expected score.  Good luck!&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelplittlefactory&amp;diff=14850</id>
		<title>Gamehelplittlefactory</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelplittlefactory&amp;diff=14850"/>
		<updated>2022-09-29T20:03:35Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Minor corrections&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Object of the Game ==&lt;br /&gt;
&lt;br /&gt;
Be the first to score ten (10+) or more &#039;&#039;&#039;Influence Points&#039;&#039;&#039; (VPs) by producing buildings and also using your buildings to produce more VPs.&lt;br /&gt;
&lt;br /&gt;
== First Turn ==&lt;br /&gt;
&lt;br /&gt;
On the first turn you may trade up to all of your coins for basic goods (wood,&lt;br /&gt;
grain, clay, stone, and/or cotton) as long as they are available. The first&lt;br /&gt;
player starts with three (3), second four (4), third (5) etc.&lt;br /&gt;
&lt;br /&gt;
== Game-play ==&lt;br /&gt;
&lt;br /&gt;
On your turn you must choose to either &#039;&#039;&#039;Produce&#039;&#039;&#039; or &#039;&#039;&#039;Trade&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;You have a set hand limit of seven (7) goods.&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Produce&#039;&#039;&#039; a single basic good (wood, wheat, clay, stone, or cotton)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Produce&#039;&#039;&#039; a single trade good by revealing or expending one or more other goods (as shown below and in the &#039;&#039;&#039;Conversion Chart&#039;&#039;&#039; in the lower right of the game board)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Trade&#039;&#039;&#039; a number of goods for other goods / buildings of equal (or lesser) cost&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;Additionally, each building you own may perform its action once per turn - before or after you produce or trade &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Expended Basic Goods returned to their columns for immediate reuse.&lt;br /&gt;
&lt;br /&gt;
Expended Trade Goods go into the discard pile to the right of their deck.&lt;br /&gt;
&lt;br /&gt;
When a column of Trade Goods is depleted, replacement cards are drawn until there are again five distinct cards, shuffling the discard pile as needed.&lt;br /&gt;
&lt;br /&gt;
After your turn, it proceeds to the next player.&lt;br /&gt;
&lt;br /&gt;
This repeats until the winning condition are met.  A player has ten (10+) or more victory points.&lt;br /&gt;
&lt;br /&gt;
=== Trading ===&lt;br /&gt;
&lt;br /&gt;
Each good has a value in the upper left, which is its trade value (which is always equal to it purchase price, in the lower center-right).  This value (combined with any other cards) may be used to purchase any other available card(s). Either the number of cards you discard or gain must be 1.&lt;br /&gt;
&lt;br /&gt;
=== Producing ===&lt;br /&gt;
&lt;br /&gt;
A good may be produced if it is in one of the five columns on the left side of the board by revealing or expending the appropriate good(s).&lt;br /&gt;
&lt;br /&gt;
The piles to the right of the decks show cards that have been previously expended.  These cards may be examined at any time, but may not produced.&lt;br /&gt;
&lt;br /&gt;
Note that basic goods do not have a cost, so you may always produce one basic good (among those available on the bottom row).  This is inefficient but sometimes necessary.&lt;br /&gt;
&lt;br /&gt;
If you have multiple choices of what to produce, you can only select one per turn.  However buildings allow you to perform additional conversions.&lt;br /&gt;
&lt;br /&gt;
=== Buildings ===&lt;br /&gt;
&lt;br /&gt;
Buildings are worth 1-3 &#039;&#039;&#039;Influence Points&#039;&#039;&#039; (VPs).  Most buildings have an additional ability (a limited extra trade/consume phase), which is either one of the trades on the &#039;&#039;&#039;Conversion Chart&#039;&#039;&#039; or a trade of one or more specific goods for a given number of additional Influence Points.&lt;br /&gt;
If the conditions on the top of the card are met you will have the option to play the card once during your turn, either before or after you Trade or Produce.&lt;br /&gt;
&lt;br /&gt;
== The Goods ==&lt;br /&gt;
&lt;br /&gt;
=== Basic Goods ===&lt;br /&gt;
First Level (Beige)&lt;br /&gt;
&lt;br /&gt;
All Basic Goods have trade value 1.  The numbers after each good are the quantity available with 4/3/2 players.&lt;br /&gt;
;Wood (5/4/3)&lt;br /&gt;
:Expend two (x2) to produce Paling&lt;br /&gt;
:Expend to produce Coal&lt;br /&gt;
:Expend with Grain to produce Sheep&lt;br /&gt;
:Expend with Clew to produce Fishing Rod&lt;br /&gt;
&lt;br /&gt;
;Wheat (3/3/2)&lt;br /&gt;
:Expend to produce Flour&lt;br /&gt;
:Expend with Wood to produce Sheep&lt;br /&gt;
:Expend with Clay to produce Cow&lt;br /&gt;
&lt;br /&gt;
;Clay (3/3/2)&lt;br /&gt;
:Expend with Grain to produce Cow&lt;br /&gt;
:Expend to produce Clay Brick&lt;br /&gt;
:Expend with Stone Brick to produce Wall&lt;br /&gt;
&lt;br /&gt;
;Stone (3/2/2)&lt;br /&gt;
:Expend to produce Cut Stone&lt;br /&gt;
:Expend to produce Fish&lt;br /&gt;
:Expend with Coal to produce Beam&lt;br /&gt;
&lt;br /&gt;
;Cotton (2/1/1)&lt;br /&gt;
:Expend to produce Clew&lt;br /&gt;
&lt;br /&gt;
=== Second Level Trade Goods (Blue) ===&lt;br /&gt;
&lt;br /&gt;
;Paling (wooden boards) (Value 5, Quantity 2)&lt;br /&gt;
:Expend to produce Barrel&lt;br /&gt;
:Expend to build Fishmonger&lt;br /&gt;
:Expend to build Spinning Mill&lt;br /&gt;
:Expend to build Cloth Mill&lt;br /&gt;
:Expend to build Fish Pond&lt;br /&gt;
:Expend to build Cattle Ranch&lt;br /&gt;
:Expend with Clay Brick and Cut Stone to build Mansion&lt;br /&gt;
:Expend with Beam and Wall to build Castle&lt;br /&gt;
;Coal (Value 3, Quantity 3)&lt;br /&gt;
:Expend with Stone to produce Beam&lt;br /&gt;
:Expend with Flour to produce Bread&lt;br /&gt;
:Expend to build Butcher Shop&lt;br /&gt;
:Expend to build Clay Brick Factory&lt;br /&gt;
:Expend with Clay Brick to build Brewery&lt;br /&gt;
;Flour (Value 3, Quantity 2)&lt;br /&gt;
:Expend with Coal to produce Bread&lt;br /&gt;
:Expend to build Masonry&lt;br /&gt;
;Sheep (Value 5, Quantity 2)&lt;br /&gt;
:Reveal to produce Clew&lt;br /&gt;
:Expend to produce Steak&lt;br /&gt;
;Cow (Value 5, Quantity 2)&lt;br /&gt;
:Reveal to produce Milk&lt;br /&gt;
:Expend to produce Steak&lt;br /&gt;
;Clay Brick (Value 3, Quantity 3)&lt;br /&gt;
:Expend to build Bakery&lt;br /&gt;
:Expend to build Foundry&lt;br /&gt;
:Expend to build Water Mill&lt;br /&gt;
:Expend to build Sheep Ranch&lt;br /&gt;
:Expend to build Milk Shop&lt;br /&gt;
:Expend to build Quarry&lt;br /&gt;
:Expend with Coal to build Brewery&lt;br /&gt;
:Expend with Stone Brick to build Bread Store&lt;br /&gt;
:Expend with Paling and Stone Brick to build Mansion&lt;br /&gt;
;Cut Stone (Value 3, Quantity 2)&lt;br /&gt;
:Expend with Clay to produce Wall&lt;br /&gt;
:Expend to build Sawmill&lt;br /&gt;
:Expend to build Barrel Factory&lt;br /&gt;
:Expend to build Leather Factory&lt;br /&gt;
:Expend to build Charcoal Hut&lt;br /&gt;
:Expend to build Dairy&lt;br /&gt;
:Expend with Clay Brick to build Bread Store&lt;br /&gt;
:Expend with Paling and Clay Brick to build Mansion&lt;br /&gt;
;Fish (Value 5, Quantity 1)&lt;br /&gt;
:Expend to build Specialty Shop&lt;br /&gt;
;Clew (yarn) (Value 3, Quantity 2)&lt;br /&gt;
:Expend with Wood to produce Fishing Rod&lt;br /&gt;
:Expend to produce Cloth&lt;br /&gt;
&lt;br /&gt;
=== Third Level Trade Goods (Purple) ===&lt;br /&gt;
&lt;br /&gt;
All third level trade goods are unique (have quantity 1)&lt;br /&gt;
&lt;br /&gt;
;Barrel (Value 8)&lt;br /&gt;
;Beam (Value 8)&lt;br /&gt;
:Expend with Paling and Wall to build Castle&lt;br /&gt;
:Expend to build Deli&lt;br /&gt;
:Expend to build Shoe Store&lt;br /&gt;
;Bread (Value 11)&lt;br /&gt;
;Steak (Value 8)&lt;br /&gt;
;Leather (sometimes called Fabric) (Value 8)&lt;br /&gt;
;Milk (Value 4)&lt;br /&gt;
;Wall (Value 8)&lt;br /&gt;
:Expend to build Tailor&lt;br /&gt;
:Expend to build Restaurant&lt;br /&gt;
:Expend to build Cheese Store&lt;br /&gt;
:Expend with Paling and Beam to build Castle&lt;br /&gt;
;Fishing Rod (Value 8)&lt;br /&gt;
:Reveal to produce Fish&lt;br /&gt;
;Cloth (Value 6)&lt;br /&gt;
:Expend to build Hardware Store&lt;br /&gt;
&lt;br /&gt;
== The Buildings ==&lt;br /&gt;
Once you have a building a process will be &amp;quot;automated&amp;quot; for you, provided that you have the necessary input good(s) and that the output good is available.&lt;br /&gt;
The building may activated only once during your turn. &lt;br /&gt;
A building can be produced by expending the good(s) listed at the bottom right in lieu of trading for its &amp;quot;cost&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Worth 1VP ===&lt;br /&gt;
&lt;br /&gt;
;Butcher Shop (Expend Coal or trade in 6)&lt;br /&gt;
:Allows you to expend Sheep to produce Steak&lt;br /&gt;
:Allows you to expend Cow to produce Steak&lt;br /&gt;
;Brick Factory (Expend Coal or trade in 6)&lt;br /&gt;
:Allows you to expend Clay to produce Clay Brick&lt;br /&gt;
;Bakery (Expend Clay Brick or trade in 6)&lt;br /&gt;
:Allows you to expend Coal and Flour to produce Bread&lt;br /&gt;
;Foundry (Expend Clay Brick or trade in 6)&lt;br /&gt;
:Allows you to expend Coal and Cut Stone to produce Beam&lt;br /&gt;
;Water Mill (Expend Clay Brick or trade in 6)&lt;br /&gt;
:Allows you to expend Grain to produce Flour&lt;br /&gt;
;Sheep Ranch (Expend Clay Brick or trade in 6)&lt;br /&gt;
:Allows you to expend Wheat and Wood to produce Sheep&lt;br /&gt;
;Barrel Factory (Expend Cut Stone or trade in 6)&lt;br /&gt;
:Allows you to expend Paling to produce Barrel&lt;br /&gt;
;Leather Factory (Expend Cut Stone or trade in 6)&lt;br /&gt;
:Allows you to expend Cow to produce Leather&lt;br /&gt;
;Milk Shop (Expend Clay Brick or trade in 6)&lt;br /&gt;
:Allows you to expend Milk to gain 1VP&lt;br /&gt;
;Charcoal Hut (Expend Cut Stone or trade in 6)&lt;br /&gt;
:Allows you to expend Wood to produce Coal&lt;br /&gt;
;Quarry (Expend Clay Brick or trade in 6)&lt;br /&gt;
:Allows you to expend Stone to produce Cut Stone.&lt;br /&gt;
;Sawmill (Expend Cut Stone or trade in 6)&lt;br /&gt;
:Allows you to expend 2x Wood to produce Paling&lt;br /&gt;
;Dairy (Expend Cut Stone or trade in 6)&lt;br /&gt;
:Allows you to reveal Cow to produce Milk&lt;br /&gt;
;Masonry (Expend Flour or trade in 6)&lt;br /&gt;
:Allows you to expend Cut Stone and Clay to produce Wall&lt;br /&gt;
&lt;br /&gt;
;Fishmonger (Expend Paling or trade in 8)&lt;br /&gt;
:Allows you to expend Fish to gain 1VP&lt;br /&gt;
;Specialty Shop (Expend Fish or trade in 8)&lt;br /&gt;
:Allows you to trade a level 3 good for other goods (&#039;&#039;&#039;not&#039;&#039;&#039; buildings)&lt;br /&gt;
;Spinning Mill (Expend Paling or trade in 8)&lt;br /&gt;
:Allows you to reveal Sheep or expend Cotton to produce Clew&lt;br /&gt;
;Textile Mill (Expend Paling or trade in 8)&lt;br /&gt;
:Allows you to expend Clew to produce Cloth&lt;br /&gt;
;Fish Pond (Expend Paling or trade in 8)&lt;br /&gt;
:Allows you to reveal Fishing Rod or expend Stone to produce Fish&lt;br /&gt;
;Cattle Range (Expend Paling or trade in 8)&lt;br /&gt;
:Allows you to expend Clay and Wheat to produce Cow&lt;br /&gt;
&lt;br /&gt;
;Hardware Store (Expend Cloth or trade in 10)&lt;br /&gt;
:Allows you to expend Leather to gain 2VP&lt;br /&gt;
:Allows you to expend Beam to gain 2VP&lt;br /&gt;
&lt;br /&gt;
=== Worth 2VP ===&lt;br /&gt;
&lt;br /&gt;
;Brewery (Expend Clay Brick and Coal or trade in 11)&lt;br /&gt;
:Allows you to expend Barrel and Wheat to gain 2VP&lt;br /&gt;
;Bread Store (Expend Clay Brick and Cut Stone or trade in 11)&lt;br /&gt;
:Allows you to expend Bread to gain 2VP&lt;br /&gt;
;Deli (Expend Beam or trade in 12)&lt;br /&gt;
:Allows you to expend Steak to gain 2VP&lt;br /&gt;
;Shoe Store (Expend Beam or trade in 12)&lt;br /&gt;
:Allows you to expend Leather and Clew to gain 3VP&lt;br /&gt;
;Tailor (Expend Wall or trade in 12)&lt;br /&gt;
:Allows you to expend Cloth and Clew to gain 2VP&lt;br /&gt;
;Restaurant (Expend Wall or trade in 12)&lt;br /&gt;
:Allows you to expend Steak and Bread to gain 4VP&lt;br /&gt;
;Cheese Store (Expend Wall or trade in 12)&lt;br /&gt;
:Allows you to expend Barrel and Milk to gain 3VP&lt;br /&gt;
&lt;br /&gt;
=== Worth 3VP ===&lt;br /&gt;
&lt;br /&gt;
;Mansion (Expend Paling, Clay Brick, and Cut Stone or trade in 18)&lt;br /&gt;
:Has no effect&lt;br /&gt;
&lt;br /&gt;
=== Worth 5VP ===&lt;br /&gt;
&lt;br /&gt;
;Castle (Expend Paling, Bean, and Wall or trade in 30)&lt;br /&gt;
:Has no effect&lt;br /&gt;
&lt;br /&gt;
== Anatomy of Card == &lt;br /&gt;
* Bottom center - the cost of the card&lt;br /&gt;
** Each board represents one method of obtaining the card&lt;br /&gt;
** If an icon includes the card outline, it is merely revealed, otherwise it is expended&lt;br /&gt;
** If there are two icons, both must be paid&lt;br /&gt;
** The right-most icon is the purchase price, which is paid by expending goods (or gold, on the first turn of the game)&lt;br /&gt;
* Bottom right (small) - total copies of card in the deck&lt;br /&gt;
* Upper left &#039;&#039;(Goods Only)&#039;&#039; -- small icon and trade-in value of card&lt;br /&gt;
* Top &#039;&#039;(Buildings Only)&#039;&#039; - &amp;quot;Automated&amp;quot; Action which may be performed once a turn, if the inputs are owned and the output is available&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Gamehelpgizmos&amp;diff=14843</id>
		<title>Gamehelpgizmos</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Gamehelpgizmos&amp;diff=14843"/>
		<updated>2022-09-29T02:23:09Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Initial population using rules as guidance&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Overview ==&lt;br /&gt;
&lt;br /&gt;
Gizmos is an engine building resource management game.  You will start with simple turns consisting of a single action while building your engine up to the point where you can trigger many actions per turn.&lt;br /&gt;
&lt;br /&gt;
== The Player Turn ==&lt;br /&gt;
&lt;br /&gt;
On your turn, you must perform 1 of the following actions:&lt;br /&gt;
&lt;br /&gt;
* File: File 1 Gizmo from the Display Area.&lt;br /&gt;
* Pick: Pick 1 Energy of your choice from the Energy Row.&lt;br /&gt;
* Build: Build 1 Gizmo from the Display Area or from your Archive.&lt;br /&gt;
* Research: Draw Gizmo cards from 1 of the facedown Level Decks and choose 1 to File or Build&lt;br /&gt;
&lt;br /&gt;
=== File ===&lt;br /&gt;
&lt;br /&gt;
Select 1 faceup Gizmo card from any row and then choose File.  After Filing a Gizmo, it is immediately replaced with the top card of the corresponding deck. After you draw this new Gizmo, your File Action is over.&lt;br /&gt;
&lt;br /&gt;
Your Archive has a limit to how many Gizmos it can hold, as indicated in your Player Dashboard’s Upgrades Area. Each player starts the game with a File Limit of 1, but some Upgrade Gizmos will increase that number. Your Archive can never hold more Gizmos than your File Limit, so if you are at your limit, you cannot take a File Action.&lt;br /&gt;
&lt;br /&gt;
=== Pick ===&lt;br /&gt;
&lt;br /&gt;
Choose 1 Energy from the 6 available in the Energy Row to add it to your Energy Storage Ring.  Your Energy Storage Ring has a limited amount of Energy it can hold, as indicated in your Player Dashboard’s Upgrades Area. Each player starts the game with a Storage Limit of 5, but some Upgrade Gizmos will increase that number.  Your Ring can never hold more Energy than your Energy Storage Limit, so if you are at your limit, you cannot take any more Energy, not even to replace existing ones.&lt;br /&gt;
&lt;br /&gt;
:: &#039;&#039;&#039;IMPORTANT&#039;&#039;&#039;: Some abilities let you &#039;&#039;&#039;Draw&#039;&#039;&#039; a random Energy.  This is &#039;&#039;not&#039;&#039; a Pick Action and thus will not trigger any other actions.&lt;br /&gt;
&lt;br /&gt;
=== Build ===&lt;br /&gt;
&lt;br /&gt;
Choose 1 faceup Gizmo card from the Display Area OR from your Archive.  Spend Energy from your Energy Storage Ring matching the Gizmo’s Energy Type and Cost.  After building a Gizmo from a row it is immediately replaced with a new Gizmo from the top of the corresponding deck.  After replenishing, your Build action is over.&lt;br /&gt;
&lt;br /&gt;
The Gizmo goes below your Player Dashboard in the area corresponding to its Gizmo Type stacked so you can see all of their effects.&lt;br /&gt;
&lt;br /&gt;
==== Converters ==== &lt;br /&gt;
&lt;br /&gt;
When performing a Build Action, you may be able to use your active Converter Gizmos to convert the Energy you have into the Energy you need.  You may do this by selecting your built Converter.  More details on the types of Converters may be found in the linked List of Effects PDF.&lt;br /&gt;
&lt;br /&gt;
=== Research ===&lt;br /&gt;
&lt;br /&gt;
Choose any facedown Level Deck (1, 2, or 3) and draw a number of cards equal to your Research Amount. You may not draw from more than 1 Level Deck at a time. Each player starts the game with a Research Amount of 3, but some Upgrade Gizmos will increase that number.  If there are fewer cards in the chosen Level Deck than your Research Amount, you will draw only the number of cards available.  After you draw the cards, choose 1 of them and either Build it (if you have enough Energy) or File it (if you have space in your Archive). Or you can choose to do neither and Pass.&lt;br /&gt;
&lt;br /&gt;
The remaining cards are then returned to the bottom of the corresponding Level Deck, in the order of your choosing. &lt;br /&gt;
&lt;br /&gt;
:: &#039;&#039;&#039;Note&#039;&#039;&#039;: The File or Build Action you perform during a Research Action also counts to trigger active Gizmos (see Triggering Gizmo Effects below).&lt;br /&gt;
&lt;br /&gt;
=== Triggering Gizmo Effects ===&lt;br /&gt;
&lt;br /&gt;
While taking 1 of the 4 available actions is the basis of the game, the real core of it (and the key to victory) is triggering your Gizmos’ effects in order to accomplish much more on your turn than you would otherwise. Every Gizmo you Build and place below your Player Dashboard has an Effect that is activated by a specific Trigger (learn all about these in the linked PDF of List of Effects). Whenever you perform an action, Gizmos that have triggered will be highlighted.  After the triggering action is complete, you may activate the Effects of any triggered Gizmos, in any order you wish. Just keep in mind that each Gizmo may only be &#039;&#039;&#039;used&#039;&#039;&#039; once per turn even if its trigger conditions are met more than once. &lt;br /&gt;
&lt;br /&gt;
:: &#039;&#039;&#039;Note:&#039;&#039;&#039; you &#039;&#039;&#039;may&#039;&#039;&#039; use the Effect of a Gizmo on the same turn it is built.  However, it cannot be triggered by the same action that Built it.&lt;br /&gt;
&lt;br /&gt;
== Chain Reactions ==&lt;br /&gt;
&lt;br /&gt;
The secret of master inventors is building their Gizmos in a way that will cause chain reactions, with one Gizmo triggering another to generate the most benefits! The Effect of one Gizmo may be a different action than the one originally performed. So, when you then perform that secondary action, it may trigger other Gizmos, and so on. Whenever you perform an action, whether it’s your one action for that turn &lt;br /&gt;
or an action triggered by a Gizmo Effect, always check the Gizmos under that action to see if any of them are triggered.  &lt;br /&gt;
&lt;br /&gt;
There is no limit to the number of Gizmos that may be activated, but always remember that each Gizmo can only be used once per turn. The order in which each Gizmo’s effect is executed is up to the player, regardless of the order in which the actions that triggered those effects occurred. A Gizmo built at the beginning of a chain reaction may end up being activated later in that chain reaction, as long as it’s not triggered by the action that Built it. Sometimes finding the optimal order to execute actions and effects can yield greater results.&lt;br /&gt;
&lt;br /&gt;
== End of the Game ==&lt;br /&gt;
&lt;br /&gt;
The end of the game is triggered when a player builds their 4th Level 3 Gizmo or their 16th Gizmo total (including their Starting Gizmo). Once that happens, play continues until the player to the right of the First Player completes their turn. That is, until all players have had an equal number of turns in the game. If the player who triggered the end of the game is the player to the right of the First Player, then the game ends when they complete their turn. &lt;br /&gt;
&lt;br /&gt;
Naturally the player with the most Victory Points wins!  In case of a tie, the tied player with the most Gizmos in their Active Gizmo Area wins (this does not include Filed Gizmos). If it’s still tied, the tied player with the most Energy left in their Energy Storage Ring wins. If it’s still tied, the tied player furthest from the First Player, going clockwise, wins.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=14110</id>
		<title>Tips littlefactory</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=14110"/>
		<updated>2022-07-20T19:36:06Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Disclaimer ===&lt;br /&gt;
&lt;br /&gt;
Much of the following only applies to 2-player games as this is the competitive format.  With more than 2 players things get a little crazier because only the level 1 resource numbers change, so all the decks cycle much more quickly.  Generally speaking this means that resource production buildings are better and point production buildings are worse as there are more players who can grab and hold those resources.  Kingmaker situations are common.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Early Game ===&lt;br /&gt;
• Securing buildings that give level 2 resource production is crucial, but not at the cost of your entire economy&amp;lt;br/&amp;gt;&lt;br /&gt;
• First player must trade for 3 level 1 resources based on what&#039;s currently shown - trading for a single level 2 makes it too easy for the opponent to block&amp;lt;br/&amp;gt;&lt;br /&gt;
• Second player has the option to trade for and effectively block one of first player&#039;s level 2 build options - this can be a good idea if that resource builds into a powerful building like coal, stone, or brick production&amp;lt;br/&amp;gt;&lt;br /&gt;
• Consider trading for all of one or more level 1 resource types to prevent the opponent from being able to buy certain cards - this is particularly effective for wheat or stone, but is applicable for clay or wood in some cases&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Midgame / General Strategy ===&lt;br /&gt;
• Pay attention to what resources your opponent is grabbing - buying cards out from under your opponent can be pivotal&amp;lt;br/&amp;gt;&lt;br /&gt;
• The game is played in cycles of building up high value cards and then trading them down for buildings or more resources - it&#039;s important to not spend all of your resources on buildings i.e. try to keep at least one 3+ value card to trade your way back into production&amp;lt;br/&amp;gt;&lt;br /&gt;
• If a player is low on resources, it is easier to hamstring them into no options but slow production - always keep this in mind for yourself and your opponent&amp;lt;br/&amp;gt;&lt;br /&gt;
• Watch the discard piles and deck sizes.  If you can, spend the resources you produce via buildings before the deck is reshuffled as rebuilding those resources is free value.  Conversely, try to buy and hold resources your opponent builds freely so they do not get the extra value&amp;lt;br/&amp;gt;&lt;br /&gt;
• When producing a resource always consider what the next card of the deck could be.  In some cases waiting to use your building to produce at the start of your turn is better to give your opponent one less option.  In other cases, producing it now is better because the opponent would otherwise buy it out from under you.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Late Game ===&lt;br /&gt;
• Building up high resource value is great, but never forget that the only way to win is to reach 10 points.  Plan out turns in advance to see if it&#039;s time to flip the switch and just buy buildings or if continuing to increase resource value makes sense&amp;lt;br/&amp;gt;&lt;br /&gt;
• Pay especially close attention to cards that convert resources to points as a player can win in one turn from as low as 6, 5, or even 4 points in very rare cases - with proper planning it should be easy to block these sorts of plays&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=14109</id>
		<title>Tips littlefactory</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=14109"/>
		<updated>2022-07-20T19:35:34Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: /* Early Game */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Disclaimer ===&lt;br /&gt;
&lt;br /&gt;
Much of the following only applies to 2-player games as this is the competitive format.  With more than 2 players things get a little crazier because only the level 1 resource numbers change, so all the decks cycle much more quickly.  Generally speaking this means that resource production buildings are better and point production buildings are worse as there are more players who can grab and hold those resources.  Kingmaker situations are common.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Early Game ===&lt;br /&gt;
• Securing buildings that give level 2 resource production is crucial, but not at the cost of your entire economy&amp;lt;br/&amp;gt;&lt;br /&gt;
• First player must trade for 3 level 1 resources based on what&#039;s currently shown - trading for a single level 2 makes it too easy for the opponent to block&amp;lt;br/&amp;gt;&lt;br /&gt;
• Second player has the option to trade for and effectively block one of first player&#039;s level 2 build options - this can be a good idea if that resource builds into a powerful building like coal, stone, or brick production&amp;lt;br/&amp;gt;&lt;br /&gt;
• Consider trading for all of one or more level 1 resource types to prevent the opponent from being able to buy certain cards - this is particularly effective for wheat or stone, but is applicable for clay or wood in some cases&amp;lt;br/&amp;gt;&lt;br /&gt;
• When producing a resource always consider what the next card of the deck could be.  In some cases waiting to use your building to produce at the start of your turn is better to give your opponent one less option.  In other cases, producing it now is better because the opponent would otherwise buy it out from under you.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Midgame / General Strategy ===&lt;br /&gt;
• Pay attention to what resources your opponent is grabbing - buying cards out from under your opponent can be pivotal&amp;lt;br/&amp;gt;&lt;br /&gt;
• The game is played in cycles of building up high value cards and then trading them down for buildings or more resources - it&#039;s important to not spend all of your resources on buildings i.e. try to keep at least one 3+ value card to trade your way back into production&amp;lt;br/&amp;gt;&lt;br /&gt;
• If a player is low on resources, it is easier to hamstring them into no options but slow production - always keep this in mind for yourself and your opponent&amp;lt;br/&amp;gt;&lt;br /&gt;
• Watch the discard piles and deck sizes.  If you can, spend the resources you produce via buildings before the deck is reshuffled as rebuilding those resources is free value.  Conversely, try to buy and hold resources your opponent builds freely so they do not get the extra value&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Late Game ===&lt;br /&gt;
• Building up high resource value is great, but never forget that the only way to win is to reach 10 points.  Plan out turns in advance to see if it&#039;s time to flip the switch and just buy buildings or if continuing to increase resource value makes sense&amp;lt;br/&amp;gt;&lt;br /&gt;
• Pay especially close attention to cards that convert resources to points as a player can win in one turn from as low as 6, 5, or even 4 points in very rare cases - with proper planning it should be easy to block these sorts of plays&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=14107</id>
		<title>Tips railroadink</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=14107"/>
		<updated>2022-07-20T17:26:14Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: More lake notes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General Strategy / Base Game ==&lt;br /&gt;
&lt;br /&gt;
• Try and pick a starting point, then head in one direction with roads, and in the other direction with railroads, to maximize points for longest highway/railroad. While most of your points will come from connecting exits, having a route or even a bridge/special route run through the center is a good idea for additional points.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Remember you can let roads and railroads end on the side of the board, even when there is no exit. These do not count as a penalty.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Be smart about bridge use - this does not count as a connection between your road and railroad, but it does double dip in terms of points for longest road and railroad if placed well.  When you do not have a good place, try to use it as a straight road/railroad along the edge as this mitigates the point loss to -1 instead of -2.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Don&#039;t forget to use your first special route by the end of the 5th round, as you only get 3 and can only use one per round.  Ideally it should be one of the two railroad, two road junctions and be played early in the game to ensure your longest road and railroad are part of a single network.  The best places for it are one of the center exits, one up from each exit in a corner, or in the actual center.  Special routes should either be planned around explicitly or used in place of 3-way connectors that never come.  Unless desperate in the last couple rounds, you should never throw a converter in the middle of your road/railroad.  Converters should be placed at &amp;quot;in-betweener&amp;quot; exits to ensure your longest road/railroad can continue connecting exits uninterrupted.  Use 3-way pieces in tandem with the converters to maintain one network.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• On the last turn, prioritize using extra rolls to close off penalties rather than lengthen rail/roads or fill center tiles because number of penalties is the first tiebreaker after score&lt;br /&gt;
&lt;br /&gt;
• A well-played game generally scores in the 60s: 36-45 from exits, 20-30 total between longest road and railroad, 3-9 for center, and negative 0-10 for broken ends.  There is a lot of variation based on routes offered.  High scoring rolls can get into the 70s or even low 80s.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Expansions ==&lt;br /&gt;
&lt;br /&gt;
=== River ===&lt;br /&gt;
&lt;br /&gt;
• Careful use of the river bridges is crucial&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• There&#039;s a constant struggle to determine whether it&#039;s worth the risk of hoping to hit the right river pieces to extend or if you should connect the edge now and not take the risk.  Take calculated risks based on what your opponents have done.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lakes ===&lt;br /&gt;
&lt;br /&gt;
• Lakes make it &amp;lt;i&amp;gt;much&amp;lt;/i&amp;gt; easier to connect all exits due to piers.  Keep in mind for every route you build that you will need to find a way to connect it to your lake via a pier, but in ~90% of games you should score all 45 points for exits if you played well&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• It is crucial that you have a single lake at the end of the game as this should amount to 15-20 points. If there are a lot of early pier rolls, focus on building your lake on a corner/half of the board and your longest road/railroad networks on the other side. But make sure you don&#039;t neglect going for a long road/railroad as these should also amount to 15-25 points collectively&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• In a game with less piers, focusing your lake in mostly the center of the board is safer&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Unlike in the base game, building your longest road and railroad as separate networks is okay because they can be connected via piers on your lake.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Auto-filling tiles with water is crucial because (a) it lets you sprawl your lake wider for more connectivity and (b) it&#039;s free points toward lake size.  Aim to fill 5+ tiles with water.  Plan your lake with early positioning of 2 and 3-sided water tiles with other 1-sided waters to &amp;quot;cascade&amp;quot; water-fill in the last few rounds.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• If well-planned, you should not rely on rolling 2/3 sided tiles to connect your lake.  It&#039;s okay to have some penalties placing late piers that can&#039;t connect - this will simply offset one of your auto-filled tiles.  Don&#039;t forget that open water sides do &amp;lt;i&amp;gt;not&amp;lt;/i&amp;gt; count as a penalty.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Keep in mind that your lake does not have to be one solid mass of water - it can have islands.  Placing two 3-side water tiles with their land-side touching surrounded by other water to later cascade auto-fill is a great strategy&lt;br /&gt;
&lt;br /&gt;
=== Meteor ===&lt;br /&gt;
&lt;br /&gt;
• Meteor is the least impactful expansion.  There are a few key differences to keep in mind, but the overall game plan largely matches the base game&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Key point #1: base your route connection (where road meets railroad) as far as possible from the meteor to minimize the possibility of interruptionM&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Key point #2: later in the game build toward the early meteor hits - especially ones in the center.  If two meteor strikes line up diagonally, then putting a 3-sided road/rail, bridge, or even special route adjacent to both of them is worth 4 points&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Key point #3: you should &amp;lt;i&amp;gt;almost never&amp;lt;/i&amp;gt; use a special route to prevent a meteor landing.  Keep in mind that you can always place on top of meteor strikes.  I.e. if a meteor lands on your road/railroad and it&#039;s not a special route, then you can just cover it up with that same piece once it rolls again or worst case use the special route you would have covered up preventing it.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Other than that focus on the usual things.  Maintain continuous road and railroad segments as long as possible.  There are 6 instead of 7 rounds so building through the center is likely a tad worse than in the base game.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lava ===&lt;br /&gt;
&lt;br /&gt;
• Building a volcano in the corner with a road/rail volcano piece on each side is a fantastic option: +5 points for a closed volcano using only 3 pieces while also contributing toward connected routes.  However you should almost always join them with a special route rather than a bridge because hoping to join up your road/railroads later is very risky.&amp;lt;br/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=14092</id>
		<title>Tips littlefactory</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=14092"/>
		<updated>2022-07-19T22:19:45Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Disclaimer ===&lt;br /&gt;
&lt;br /&gt;
Much of the following only applies to 2-player games as this is the competitive format.  With more than 2 players things get a little crazier because only the level 1 resource numbers change, so all the decks cycle much more quickly.  Generally speaking this means that resource production buildings are better and point production buildings are worse as there are more players who can grab and hold those resources.  Kingmaker situations are common.&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Early Game ===&lt;br /&gt;
• Securing buildings that give level 2 resource production is crucial, but not at the cost of your entire economy&amp;lt;br/&amp;gt;&lt;br /&gt;
• First player must trade for 3 level 1 resources based on what&#039;s currently shown - trading for a single level 2 makes it too easy for the opponent to block&amp;lt;br/&amp;gt;&lt;br /&gt;
• Second player has the option to trade for and effectively block one of first player&#039;s level 2 build options - this can be a good idea if that resource builds into a powerful building like coal, stone, or brick production&amp;lt;br/&amp;gt;&lt;br /&gt;
• Consider trading for all of one or more level 1 resource types to prevent the opponent from being able to buy certain cards - this is particularly effective for wheat or stone, but is applicable for clay or wood in some cases&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Midgame / General Strategy ===&lt;br /&gt;
• Pay attention to what resources your opponent is grabbing - buying cards out from under your opponent can be pivotal&amp;lt;br/&amp;gt;&lt;br /&gt;
• The game is played in cycles of building up high value cards and then trading them down for buildings or more resources - it&#039;s important to not spend all of your resources on buildings i.e. try to keep at least one 3+ value card to trade your way back into production&amp;lt;br/&amp;gt;&lt;br /&gt;
• If a player is low on resources, it is easier to hamstring them into no options but slow production - always keep this in mind for yourself and your opponent&amp;lt;br/&amp;gt;&lt;br /&gt;
• Watch the discard piles and deck sizes.  If you can, spend the resources you produce via buildings before the deck is reshuffled as rebuilding those resources is free value.  Conversely, try to buy and hold resources your opponent builds freely so they do not get the extra value&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Late Game ===&lt;br /&gt;
• Building up high resource value is great, but never forget that the only way to win is to reach 10 points.  Plan out turns in advance to see if it&#039;s time to flip the switch and just buy buildings or if continuing to increase resource value makes sense&amp;lt;br/&amp;gt;&lt;br /&gt;
• Pay especially close attention to cards that convert resources to points as a player can win in one turn from as low as 6, 5, or even 4 points in very rare cases - with proper planning it should be easy to block these sorts of plays&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=13958</id>
		<title>Tips railroadink</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=13958"/>
		<updated>2022-07-12T17:37:12Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: /* Expansions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General Strategy / Base Game ==&lt;br /&gt;
&lt;br /&gt;
• Try and pick a starting point, then head in one direction with roads, and in the other direction with railroads, to maximize points for longest highway/railroad. While most of your points will come from connecting exits, having a route or even a bridge/special route run through the center is a good idea for additional points.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Remember you can let roads and railroads end on the side of the board, even when there is no exit. These do not count as a penalty.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Be smart about bridge use - this does not count as a connection between your road and railroad, but it does double dip in terms of points for longest road and railroad if placed well.  When you do not have a good place, try to use it as a straight road/railroad along the edge as this mitigates the point loss to -1 instead of -2.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Don&#039;t forget to use your first special route by the end of the 5th round, as you only get 3 and can only use one per round.  Ideally it should be one of the two railroad, two road junctions and be played early in the game to ensure your longest road and railroad are part of a single network.  The best places for it are one of the center exits, one up from each exit in a corner, or in the actual center.  Special routes should either be planned around explicitly or used in place of 3-way connectors that never come.  Unless desperate in the last couple rounds, you should never throw a converter in the middle of your road/railroad.  Converters should be placed at &amp;quot;in-betweener&amp;quot; exits to ensure your longest road/railroad can continue connecting exits uninterrupted.  Use 3-way pieces in tandem with the converters to maintain one network.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• On the last turn, prioritize using extra rolls to close off penalties rather than lengthen rail/roads or fill center tiles because number of penalties is the first tiebreaker after score&lt;br /&gt;
&lt;br /&gt;
• A well-played game generally scores in the 60s: 36-45 from exits, 20-30 total between longest road and railroad, 3-9 for center, and negative 0-10 for broken ends.  There is a lot of variation based on routes offered.  High scoring rolls can get into the 70s or even low 80s.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Expansions ==&lt;br /&gt;
&lt;br /&gt;
=== River ===&lt;br /&gt;
&lt;br /&gt;
• Careful use of the river bridges is crucial&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• There&#039;s a constant struggle to determine whether it&#039;s worth the risk of hoping to hit the right river pieces to extend or if you should connect the edge now and not take the risk.  Take calculated risks based on what your opponents have done&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lakes ===&lt;br /&gt;
&lt;br /&gt;
• Lakes make it &amp;lt;i&amp;gt;much&amp;lt;/i&amp;gt; easier to connect all exits due to piers.  Keep in mind for every route you build that you will need to find a way to connect it to your lake via a pier, but in ~90% of games you should score all 45 points for exits if you played well&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• It is crucial that you have a single lake at the end of the game as this should amount to 15-20 points. If there are a lot of early pier rolls, focus on building your lake on a corner/half of the board and your longest road/railroad networks on the other side. But make sure you don&#039;t neglect going for a long road/railroad as these should also amount to 15-25 points collectively&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• In a game with less piers, focusing your lake in mostly the center of the board is safer&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Unlike in the base game, building your longest road and railroad as separate networks is okay because they can be connected via piers on your lake.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Auto-filling tiles with water is crucial because (a) it lets you sprawl your lake wider for more connectivity and (b) it&#039;s free points toward lake size.  Aim to fill 5+ tiles with water.  Plan your lake with early positioning of 2 and 3-sided water tiles with other 1-sided waters to &amp;quot;cascade&amp;quot; water-fill in the last few rounds.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• If well-planned, you should not rely on rolling 2/3 sided tiles to connect your lake.  It&#039;s okay to have some penalties placing late piers that can&#039;t connect - this will simply offset one of your auto-filled tiles.  Don&#039;t forget that open water sides do &amp;lt;i&amp;gt;not&amp;lt;/i&amp;gt; count as a penalty&lt;br /&gt;
&lt;br /&gt;
=== Meteor ===&lt;br /&gt;
&lt;br /&gt;
• Meteor is the least impactful expansion.  There are a few key differences to keep in mind, but the overall game plan largely matches the base game&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Key point #1: base your route connection (where road meets railroad) as far as possible from the meteor to minimize the possibility of interruptionM&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Key point #2: later in the game build toward the early meteor hits - especially ones in the center.  If two meteor strikes line up diagonally, then putting a 3-sided road/rail, bridge, or even special route adjacent to both of them is worth 4 points&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Key point #3: you should &amp;lt;i&amp;gt;almost never&amp;lt;/i&amp;gt; use a special route to prevent a meteor landing.  Keep in mind that you can always place on top of meteor strikes.  I.e. if a meteor lands on your road/railroad and it&#039;s not a special route, then you can just cover it up with that same piece once it rolls again or worst case use the special route you would have covered up preventing it.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Other than that focus on the usual things.  Maintain continuous road and railroad segments as long as possible.  There are 6 instead of 7 rounds so building through the center is likely a tad worse than in the base game.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lava ===&lt;br /&gt;
&lt;br /&gt;
• Building a volcano in the corner with a road/rail volcano piece on each side is a fantastic option: +5 points for a closed volcano using only 3 pieces while also contributing toward connected routes.  However you should almost always join them with a special route rather than a bridge because hoping to join up your road/railroads later is very risky&amp;lt;br/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=13830</id>
		<title>Tips railroadink</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=13830"/>
		<updated>2022-06-30T16:24:13Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Formatting and started expansions section with lakes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== General Strategy / Base Game ==&lt;br /&gt;
&lt;br /&gt;
• Try and pick a starting point, then head in one direction with roads, and in the other direction with railroads, to maximize points for longest highway/railroad. While most of your points will come from connecting exits, having a route or even a bridge/special route run through the center is a good idea for additional points.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Remember you can let roads and railroads end on the side of the board, even when there is no exit. These do not count as a penalty.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Be smart about bridge use - this does not count as a connection between your road and railroad, but it does double dip in terms of points for longest road and railroad if placed well.  When you do not have a good place, try to use it as a straight road/railroad along the edge as this mitigates the point loss to -1 instead of -2.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Don&#039;t forget to use your first special route by the end of the 5th round, as you only get 3 and can only use one per round.  Ideally it should be one of the two railroad, two road junctions and be played early in the game to ensure your longest road and railroad are part of a single network.  The best places for it are one of the center exits, one up from each exit in a corner, or in the actual center.  Special routes should either be planned around explicitly or used in place of 3-way connectors that never come.  Unless desperate in the last couple rounds, you should never throw a converter in the middle of your road/railroad.  Converters should be placed at &amp;quot;in-betweener&amp;quot; exits to ensure your longest road/railroad can continue connecting exits uninterrupted.  Use 3-way pieces in tandem with the converters to maintain one network.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• On the last turn, prioritize using extra rolls to close off penalties rather than lengthen rail/roads or fill center tiles because number of penalties is the first tiebreaker after score&lt;br /&gt;
&lt;br /&gt;
• A well-played game generally scores in the 60s: 36-45 from exits, 20-30 total between longest road and railroad, 3-9 for center, and negative 0-10 for broken ends.  There is a lot of variation based on routes offered.  High scoring rolls can get into the 70s or even low 80s.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Expansions ==&lt;br /&gt;
&lt;br /&gt;
=== Lakes ===&lt;br /&gt;
&lt;br /&gt;
• Lakes make it &amp;lt;i&amp;gt;much&amp;lt;/i&amp;gt; easier to connect all exits due to piers.  Keep in mind for every route you build that you will need to find a way to connect it to your lake via a pier, but in ~90% of games you should score all 45 points for exits if you played well&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• It is crucial that you have a single lake at the end of the game as this should amount to 15-20 points. If there are a lot of early pier rolls, focus on building your lake on a corner/half of the board and your longest road/railroad networks on the other side. But make sure you don&#039;t neglect going for a long road/railroad as these should also amount to 15-25 points collectively&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• In a game with less piers, focusing your lake in mostly the center of the board is safer&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Unlike in the base game, building your longest road and railroad as separate networks is okay because they can be connected via piers on your lake.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• Auto-filling tiles with water is crucial because (a) it lets you sprawl your lake wider for more connectivity and (b) it&#039;s free points toward lake size.  Aim to fill 5+ tiles with water.  Plan your lake with early positioning of 2 and 3-sided water tiles with other 1-sided waters to &amp;quot;cascade&amp;quot; water-fill in the last few rounds.&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
• If well-planned, you should not rely on rolling 2/3 sided tiles to connect your lake.  It&#039;s okay to have some penalties placing late piers that can&#039;t connect - this will simply offset one of your auto-filled tiles.  Don&#039;t forget that open water sides do &amp;lt;i&amp;gt;not&amp;lt;/i&amp;gt; count as a penalty&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=13550</id>
		<title>Tips littlefactory</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=13550"/>
		<updated>2022-06-10T17:19:05Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: More detail, better formatting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Disclaimer ===&lt;br /&gt;
&lt;br /&gt;
Much of the following only applies to 2-player games as this is the competitive format.  With more than 2 players things get a little crazier because only the level 1 resource numbers change, so all the decks cycle much more quickly.  Generally speaking this means that resource production buildings are better and point production buildings are worse as there are more players who can grab and hold those resources.  Kingmaker situations are common.&lt;br /&gt;
&lt;br /&gt;
=== Early Game ===&lt;br /&gt;
• Securing buildings that give level 2 resource production is crucial, but not at the cost of your entire economy&amp;lt;br/&amp;gt;&lt;br /&gt;
• First player must trade for 3 level 1 resources based on what&#039;s currently shown - trading for a single level 2 makes it too easy for the opponent to block&amp;lt;br/&amp;gt;&lt;br /&gt;
• Second player has the option to trade for and effectively block one of first player&#039;s level 2 build options - this can be a good idea if that resource builds into a powerful building like coal, stone, or brick production&amp;lt;br/&amp;gt;&lt;br /&gt;
• Consider trading for of one or more level 1 resource types to force your opponent off of certain level 2s - this is particularly effective for wheat or stone, but is applicable for clay or wood in some cases&amp;lt;br/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Midgame / General Strategy ===&lt;br /&gt;
• Pay attention to what resources your opponent is grabbing - buying cards out from under your opponent can be pivotal&amp;lt;br/&amp;gt;&lt;br /&gt;
• The game is played in cycles of building up high value cards and then trading them down for buildings or more resources - it&#039;s important to not spend all of your resources on buildings i.e. try to keep at least one 3+ value card to trade your way back into production&amp;lt;br/&amp;gt;&lt;br /&gt;
• If a player is low on resources, it is easier to hamstring them into no options but slow production - always keep this in mind for yourself and your opponent&amp;lt;br/&amp;gt;&lt;br /&gt;
• Watch the discard piles and deck sizes.  If you can, spend the resources you produce via buildings before the deck is reshuffled as rebuilding those resources is free value.  Conversely, try to buy and hold resources your opponent builds freely so they do not get the extra value&lt;br /&gt;
&lt;br /&gt;
=== Late Game ===&lt;br /&gt;
• Building up high resource value is great, but never forget that the only way to win is to reach 10 points.  Plan out turns in advance to see if it&#039;s time to flip the switch and just buy buildings or if continuing to increase resource value makes sense&amp;lt;br/&amp;gt;&lt;br /&gt;
• Pay especially close attention to cards that convert resources to points as a player can win in one turn from as low as 6, 5, or even 4 points in very rare cases - with proper planning it should be easy to block these sorts of plays&amp;lt;br/&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=13146</id>
		<title>Tips railroadink</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=13146"/>
		<updated>2022-05-10T23:12:15Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Try and pick a starting point, then head in one direction with roads, and in the other direction with railroads, to maximize points for longest highway/railroad. While most of your points will come from connecting exits, having one route run through the center is a good idea for additional points.&lt;br /&gt;
&lt;br /&gt;
Remember you can let roads and railroads end on the side of the board, even when there is no exit. These do not count as a penalty.&lt;br /&gt;
&lt;br /&gt;
Be smart about bridge use - this does not count as a connection between your road and railroad, but it does double dip in terms of points for longest road and railroad if placed well.  When you do not have a good place, try to use it as a straight road/railroad along the edge as this mitigates the point loss to -1 instead of -2.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to use your first special route by the end of the 5th round, as you only get 3 and can only use one per round.  Ideally it should be one of the two railroad, two road junctions and be played early in the game to ensure your longest road and railroad are part of a single network.  The best places for it are one of the center exits, one up from each exit in a corner, or in the actual center.  Special routes should either be planned around explicitly or used in place of 3-way connectors that never come.  Unless desperate in the last couple rounds, you should never throw a converter in the middle of your road/railroad.  Converters should be placed at &amp;quot;in-betweener&amp;quot; exits to ensure your longest road/railroad can continue connecting exits uninterrupted.  Use 3-way pieces in tandem with the converters to maintain one network.&lt;br /&gt;
&lt;br /&gt;
A well-played game generally scores in the 60s: 36-45 from exits, 20-30 total between longest road and railroad, 3-9 for center, and negative 0-10 for broken ends.  There is a lot of variation based on routes offered.  High scoring rolls can get into the 70s or even low 80s.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=13145</id>
		<title>Tips railroadink</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_railroadink&amp;diff=13145"/>
		<updated>2022-05-10T22:59:33Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Try and pick a starting point, then head in one direction with roads, and in the other direction with railroads, to maximize points for longest highway/railroad. While most of your points will come from connecting exits, having one route run through the center is a good idea for additional points.&lt;br /&gt;
&lt;br /&gt;
Remember you can let roads and railroads end on the side of the board, even when there is no exit. These do not count as a penalty.&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to use your first special route by the end of the 5th round, as you only get 3 and can only use one per round.  Ideally it should be one of the two railroad, two road junctions and be played early in the game to ensure your longest road and railroad are part of a single network.  The best places for it are one of the center exits, one up from each exit in a corner, or in the actual center.  Special routes should either be planned around explicitly or used in place of 3-way connectors that never come.  Unless desperate in the last couple rounds, you should never throw a converter in the middle of your road/railroad.  Converters should be placed at &amp;quot;in-betweener&amp;quot; exits to ensure your longest road/railroad can continue connecting exit uninterrupted.&lt;br /&gt;
&lt;br /&gt;
A well-played game generally scores in the 60s: 36-45 from exits, 20-30 total between longest road and railroad, 3-9 for center, and negative 3-7 for broken ends.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=13144</id>
		<title>Tips littlefactory</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_littlefactory&amp;diff=13144"/>
		<updated>2022-05-10T22:49:26Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Little Factory Strategy Tips&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As a general rule of thumb, try to perform the action that increases your current net resource value by as much as possible.  If you cannot increase your current net value, what trades can you make now to enable increasing your net value on coming turns?  Work toward buildings that give you additional actions that you can frequently use.  The buildings that turn wood into coal, clay into bricks, and stone into stone bricks are all hugely important for ramping into more buildings whereas buildings that cost tier 2 resources may only be usable once or twice the whole game.  The scarcity of resources is actually very relevant.  Keep count of what other players have been buying so you know what is likely to appear and so that you know which resources/buildings will still be available come your next turn.&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_abyss&amp;diff=13143</id>
		<title>Tips abyss</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_abyss&amp;diff=13143"/>
		<updated>2022-05-10T19:51:41Z</updated>

		<summary type="html">&lt;p&gt;Fletcheese: Abyss Strategy Tips&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Abyss is a resource management game and success comes down to properly managing these resources which include:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Cards in hand&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;ul&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;More higher numbered cards of different colors = more lords you can buy&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Card color flexibility is especially important when the court refreshes - you want to maximize your chances of taking advantage of the new lord pool&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Explored 4 and 5 cost cards should almost always be purchased while 2 and 1 almost never.  3s are a toss-up depending on how many pearls each player has and how useful it is building toward the current lords in court&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;When spending cards, try to use either all high or all low number cards.  Using one high number card with low numbered cards means a missed opportunity to affiliate extra points&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Saving high numbered cards to auto-affiliate at the end of the game is perfectly viable&amp;lt;/li&amp;gt; &lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Cards in council&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;ul&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;The council is perhaps the most novel aspect of Abyss and by extension the hardest to build intuition on&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;When cards are already in council exploring becomes a worse option as you risk a council stack becoming a more appealing option for your opponent&#039;s next turn&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Choosing to take council cards rather than explore has many important implications:&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
     &amp;lt;li&amp;gt;Your opponent does not have the opportunity to buy a card - you can lock down a lord purchase by getting the final cards from council&amp;lt;/li&amp;gt;&lt;br /&gt;
     &amp;lt;li&amp;gt;Barring lord powers, you can only gain pearls by exploring.  This can lead to a give and take where players alternate who is exploring&amp;lt;/li&amp;gt;&lt;br /&gt;
     &amp;lt;li&amp;gt;Generally speaking it is better to not be the one exploring because it gives the opponent first dibs at every card&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Pearls&lt;br /&gt;
  &amp;lt;ul&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Pearls are not worth any points so as the game goes on they should be used more and more liberally&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;When your opponent has no pearls, exploring becomes &amp;lt;i&amp;gt;much&amp;lt;/i&amp;gt; more appealing&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Do not underestimate the value in spending pearls for buying lords.  Purchasing a mono-color lord with pearls and a 4 or 5 card is very appealing as you can then affiliate that card&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Spending a pearl to add a lord to court is very rarely a good decision but can come up&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
 &amp;lt;/li&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Lords&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;ul&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Active (key) lord powers can drastically warp the progression of a game.  An exhaustive list is outside the scope of this guide&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Some lord powers with others in interesting ways.  Learning all the interactions can only come from playing games&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Do not forget that getting a third key disables all of your keyed lords&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
 &amp;lt;li&amp;gt;Points&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;ul&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Like many similar games, the only resource that matters at the end is points&amp;lt;/li&amp;gt;&lt;br /&gt;
   &amp;lt;li&amp;gt;Points come from:&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
     &amp;lt;li&amp;gt;Lords&lt;br /&gt;
      &amp;lt;ul&amp;gt;&lt;br /&gt;
       &amp;lt;li&amp;gt;Key lords are generally better early, point lords are better late.  Though it&#039;s important to consider that not all lords are created equal&amp;lt;/li&amp;gt;&lt;br /&gt;
      &amp;lt;/ul&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
     &amp;lt;li&amp;gt;Locations&lt;br /&gt;
      &amp;lt;ul&amp;gt;&lt;br /&gt;
       &amp;lt;li&amp;gt;Depending on early key lord hits, it may be beneficial to delay your first location as much as possible.  This has the added benefit of making a location choice working with as much information as possible&amp;lt;/li&amp;gt;&lt;br /&gt;
       &amp;lt;li&amp;gt;Generally speaking if none of the already revealed locations are worth more than about 10 points, you should reveal 4 locations.  The added options for you far outweigh those for your opponent as you&#039;re often looking for the same locations anyway&amp;lt;/li&amp;gt;&lt;br /&gt;
      &amp;lt;/ul&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
     &amp;lt;li&amp;gt;Affiliated Allies&lt;br /&gt;
      &amp;lt;ul&amp;gt;&lt;br /&gt;
       &amp;lt;li&amp;gt;You should be looking to score around 20 points off affiliated allies.  Plan your card and lord purchases well to affiliate high value allies&amp;lt;/li&amp;gt;&lt;br /&gt;
      &amp;lt;/ul&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
     &amp;lt;li&amp;gt;Monster Tokens&lt;br /&gt;
      &amp;lt;ul&amp;gt;&lt;br /&gt;
       &amp;lt;li&amp;gt;Do not underestimate Monster Tokens.  In general whenever the monster track is at 2, you should fight it and take 2 tokens.  Expected point value 6 is &amp;lt;i&amp;gt;much&amp;lt;/i&amp;gt; better than a card&amp;lt;/li&amp;gt;&lt;br /&gt;
      &amp;lt;/ul&amp;gt;&lt;br /&gt;
     &amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
   &amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fletcheese</name></author>
	</entry>
</feed>