<?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=Xmakina</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=Xmakina"/>
	<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/Special:Contributions/Xmakina"/>
	<updated>2026-09-18T11:15:08Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.0</generator>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tools_and_tips_of_BGA_Studio&amp;diff=18928</id>
		<title>Tools and tips of BGA Studio</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tools_and_tips_of_BGA_Studio&amp;diff=18928"/>
		<updated>2023-11-19T09:10:57Z</updated>

		<summary type="html">&lt;p&gt;Xmakina: /* State machine diagram generation tool */ Add link for new State Machine generator&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
== Server Tools and Tips ==&lt;br /&gt;
=== Starting a game in one click ===&lt;br /&gt;
&lt;br /&gt;
To start a game:&lt;br /&gt;
* Go to Play now and configure game type: Simple game -&amp;gt; Turn-based -&amp;gt; Manual&lt;br /&gt;
* Select your game and click on &amp;quot;Create&amp;quot;.&lt;br /&gt;
* If you want to play a game with 3 players, specify that you want a maximum of 3 players at this table.&lt;br /&gt;
* Click on &amp;quot;Express Start&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Stopping a game in one click ===&lt;br /&gt;
&lt;br /&gt;
* Click on the &amp;quot;menú&amp;quot; icon on the top right of the screen.&lt;br /&gt;
* Click on &amp;quot;Express Stop&amp;quot; (&amp;quot;Quit this game&amp;quot; if playing a solo game).&lt;br /&gt;
&lt;br /&gt;
=== Switching between users ===&lt;br /&gt;
&lt;br /&gt;
When running a game on Studio, you can use the little red arrow near each player&#039;s name to open a new tab with this player&#039;s perspective.&lt;br /&gt;
You can also modify the URL to view the table as any user you want (changing &amp;amp;testuser=myid in the URL), allowing to easily test as a spectator.&lt;br /&gt;
&lt;br /&gt;
=== Access to game database and Logs ===&lt;br /&gt;
&lt;br /&gt;
At the bottom of the game area, there is section without a title containing 3 useful links:&lt;br /&gt;
&lt;br /&gt;
  Go to game database • BGA request&amp;amp;SQL logs • BGA unexpected exceptions logs&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Go to game database&amp;quot; link is an immediate access to the PhpMyAdmin tool to view/edit the tables of the current game&lt;br /&gt;
* BGA request&amp;amp;SQL logs - link to your studio PHP log - all tables, all severities. Anything you print using debugging and tracing functions from PHP and some framework logs&lt;br /&gt;
* BGA unexpected exceptions logs - same log as above but only severity warning and higher&lt;br /&gt;
&lt;br /&gt;
See [[Practical debugging]] for more info about it.&lt;br /&gt;
&lt;br /&gt;
=== Save &amp;amp; restore state ===&lt;br /&gt;
&lt;br /&gt;
Using links of this section, you can save the complete current (database) state of your game, then restore it later.&lt;br /&gt;
&lt;br /&gt;
This is particularly useful when you want to develop a part of the game that is difficult to reproduce: you just have to save the situation just before, and then restore it until this part works fine.&lt;br /&gt;
&lt;br /&gt;
We provide you 3 &amp;quot;slots&amp;quot;: 1, 2 and 3. This way, you can save 3 different game situations.&lt;br /&gt;
&lt;br /&gt;
Limits:&lt;br /&gt;
* the &amp;quot;restore&amp;quot; function does not work anymore when the game is over.&lt;br /&gt;
* a saved situation from a given table cannot be restored in another table.&lt;br /&gt;
* when you &amp;quot;restore&amp;quot; a situation, the current browser page is refreshed to reflect the updated game situation, but you have to refresh you other tabs/pages manually.&lt;br /&gt;
&lt;br /&gt;
=== Input/Output debugging section ===&lt;br /&gt;
&lt;br /&gt;
This section shows you:&lt;br /&gt;
* The AJAX calls made by your game interface to the game server. AJAX calls (outputs) begins with &amp;quot;&amp;gt;&amp;quot;&lt;br /&gt;
* The notifications received by your game interface. Notifications (inputs) begins with &amp;quot;&amp;lt;&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Note: if you click on some notification title, you can resend it immediately to the user interface.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Run PHP functions from the chat ===&lt;br /&gt;
&lt;br /&gt;
On BGA Studio, you can directly run a PHP method from the table chat. The production environment does not allow PHP methods to be called from the table chat.&lt;br /&gt;
&lt;br /&gt;
For example, if on your PHP you have this method:&lt;br /&gt;
   &lt;br /&gt;
   function giveMoneyToPlayer($player_id, $amount) { ... }&lt;br /&gt;
&lt;br /&gt;
You can call this method directly from the chat like this: &lt;br /&gt;
&lt;br /&gt;
  giveMoneyToPlayer(2564,2)&lt;br /&gt;
&lt;br /&gt;
Note: this is not a real php statement, you cannot use self::, you cannot use &amp;quot;;&amp;quot; at the end and you cannot use quotes,&lt;br /&gt;
if you need to pass a string skip the quotes, like this&lt;br /&gt;
  &lt;br /&gt;
  giveToActivePlayer(money,2)&lt;br /&gt;
&lt;br /&gt;
What if you want something more complex like passing an array? Or calling other function? Just create another function in php for that and use it. I suggest to use prefix debug for all such functions.&lt;br /&gt;
  function debug_q($x) {&lt;br /&gt;
       $player_id = $this-&amp;gt;getActivePlayerId();&lt;br /&gt;
       $this-&amp;gt; giveMoneyToPlayer($player_id, $x);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
=== Zombify a player ===&lt;br /&gt;
&lt;br /&gt;
Call this from chat (studio only) to zombify current player (who is &amp;quot;thinking&amp;quot;)&lt;br /&gt;
  timeout()&lt;br /&gt;
&lt;br /&gt;
Never call from game code.&lt;br /&gt;
&lt;br /&gt;
=== Stopping Hanging Game ===&lt;br /&gt;
&lt;br /&gt;
If game is hanging and you cannot enter it to stop you can type this URL (replace 12345 with your table number),&lt;br /&gt;
which should bring you to a place where you can stop it without entering:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;https://studio.boardgamearena.com/#!table?table=12345&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Desktop and Web Tools ==&lt;br /&gt;
=== Code Editors and IDEs ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Visual Studio Code ====&lt;br /&gt;
Microsoft Visual Studio Code is light weight IDE/Editor. All desktops.&lt;br /&gt;
https://code.visualstudio.com&lt;br /&gt;
&lt;br /&gt;
See [[Setting up BGA Development environment using VSCode]]&lt;br /&gt;
&lt;br /&gt;
==== Eclipse For PHP Developers ====&lt;br /&gt;
&lt;br /&gt;
Eclipse PHP package can be starting point for development you need. You may also want to &lt;br /&gt;
install Tern JS plugins to understand dojo style JS. All desktops.&lt;br /&gt;
https://projects.eclipse.org/projects/tools.pdt&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Gedit (Ubuntu) ====&lt;br /&gt;
&#039;&#039;&#039;Edit TPL&#039;&#039;&#039;&lt;br /&gt;
To edit TPL with HTML code highlightings in Gedit under Ubuntu:&lt;br /&gt;
&lt;br /&gt;
find gtksourceview directory in /usr/share, depending on your version (2.0, 3.0,...).&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Here it&#039;s 3.0, then type in a terminal window:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    sudo gedit /usr/share/gtksourceview-3.0/language-specs/html.lang&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
then find &#039;globs&#039; section, and change:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &amp;lt;property name=&amp;quot;globs&amp;quot;&amp;gt;*.html;*.htm;*.tpl&amp;lt;/property&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== File Sync ===&lt;br /&gt;
&lt;br /&gt;
NOTE: If you use VS Code you don&#039;t need to use methods below, use one of the sync methods provided by VS Code extensios. See [[Setting up BGA Development environment using VSCode]]&lt;br /&gt;
&lt;br /&gt;
==== File Sync on Windows ====&lt;br /&gt;
&lt;br /&gt;
Install [http://winscp.net/ WinSCP]. Map a remote directory to a local one and enable continuous sync (one way). You need SFTP password you get when you registered dev account.&lt;br /&gt;
&lt;br /&gt;
==== File Sync on Linux ====&lt;br /&gt;
&lt;br /&gt;
===== Option 1 - Nautilus (file manager) =====&lt;br /&gt;
You can just use Nautilus &amp;quot;connect to a server&amp;quot; function with URL sftp://1.studio.boardgamearena.com&lt;br /&gt;
Then you&#039;ll get a mounted local folder mapping your studio folder and you can use any editor you like without further need for sync. Downside - if connection goes down you cannot work on source code, no local copy.&lt;br /&gt;
&lt;br /&gt;
===== Option 2 - sftp and rsync =====&lt;br /&gt;
This setup will sync in the background (continious sync) when file is saved, after you set it up and start just save your files and they be on server before you can hit refresh.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
BASEDIR=`dirname $0`&lt;br /&gt;
REMOTE=$BASEDIR/remote&lt;br /&gt;
LOCAL=$BASEDIR/workspace&lt;br /&gt;
GAME=mygamenamehere&lt;br /&gt;
&lt;br /&gt;
#mount remote&lt;br /&gt;
fusermount -u $REMOTE #this unmounts dir&lt;br /&gt;
#this asssumes your default ssh key is uploaded to studio&lt;br /&gt;
sshfs  myusernamehere@1.studio.boardgamearena.com: $REMOTE&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#this starts auto-sync from local to remote mount&lt;br /&gt;
killall lsyncd&lt;br /&gt;
lsyncd -delay 1 -rsync $LOCAL/$GAME/ $REMOTE/$GAME&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This can be able run on startup, so you don&#039;t have to do anything manually. However sshfs is not very stable you&lt;br /&gt;
have to kill and restart it sometimes. And remote goes away sometimes due to connection issues with studio. &lt;br /&gt;
In this case its handy to have a local copy, which is what lsyncd for.&lt;br /&gt;
&lt;br /&gt;
You can also sync on demand (from a build script or editor command) using&lt;br /&gt;
 rsync -vlrt $LOCAL/$GAME/ $REMOTE/$GAME&lt;br /&gt;
&lt;br /&gt;
Note: is insecure way of running sshfs&lt;br /&gt;
echo LongDevPassword | sshfs -o password_stdin ...&lt;br /&gt;
&lt;br /&gt;
===== Option 3 - lftp =====&lt;br /&gt;
&lt;br /&gt;
[https://lftp.yar.ru/ lftp] is a fast command-line file transfer program. It supports parallel threads, transferring multiple files at a time.&lt;br /&gt;
&lt;br /&gt;
* Linux: Install using your package manager, for example: &#039;&#039;&#039;sudo apt-get install lftp&#039;&#039;&#039;&lt;br /&gt;
* Mac: Install [https://brew.sh/ Homebrew], then install lftp using &#039;&#039;&#039;brew install lftp&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
To upload your project to BGA studio, use the &amp;quot;mirror&amp;quot; command like this:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;lftp sftp://&amp;lt;span style=&amp;quot;color:blue&amp;quot;&amp;gt;myuser&amp;lt;/span&amp;gt;:&amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;mypassword&amp;lt;/span&amp;gt;@1.studio.boardgamearena.com/ -e &amp;quot;mirror --reverse --parallel=10 --delete &amp;lt;span style=&amp;quot;color:orange&amp;quot;&amp;gt;/local/path/to/myproject&amp;lt;/span&amp;gt;/ &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;myproject&amp;lt;/span&amp;gt;/; exit&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Be sure to include the trailing &#039;&#039;&#039;/&#039;&#039;&#039; after both directory names.&lt;br /&gt;
&lt;br /&gt;
By default, if a file already exists on BGA Studio with the same time + size it assumed to be the same and won&#039;t be transferred. This makes the transfer process much quicker after the first time. If you&#039;re working with multiple developers on the same project and you find that it is transfers all files every time, you may want to add the option &#039;&#039;&#039;--ignore-time&#039;&#039;&#039; (if a file already exist on BGA Studio with the same size it is assumed to be the same and won&#039;t be transferred). Read [https://lftp.yar.ru/lftp-man.html the manual] for more details.&lt;br /&gt;
&lt;br /&gt;
This is one time sync (unless I am missing something this does not do continious sync?)&lt;br /&gt;
&lt;br /&gt;
=== Debuggers ===&lt;br /&gt;
&lt;br /&gt;
Browser is the best tool for JS/HTML5 debugging, see [[Practical debugging]] for details.&lt;br /&gt;
&lt;br /&gt;
=== Version Control ===&lt;br /&gt;
Studio provides svn for you code on server, there are some limited abilities there to see history and restore. I recommend to also keep your code in another repository, which allows keeping more fine-grained history and can simplify collaboration.&lt;br /&gt;
&lt;br /&gt;
A quick option is to use a local repo, which you can sync to cloud or backup.&lt;br /&gt;
&lt;br /&gt;
Other option is to host source code on github. If you do, the convention is to use github.com/&amp;lt;yourname&amp;gt;/bga-&amp;lt;yourgame&amp;gt;. It is recommended to add the [https://github.com/topics/boardgamearena boardgamearena] tag and add your repo to the list on the [[BGA_Code_Sharing]] page.&lt;br /&gt;
&lt;br /&gt;
If you publish the source somewhere externally, make sure you &#039;&#039;&#039;don&#039;t post high-res publisher graphics&#039;&#039;&#039;, only web resources, and post a separate license for graphics files. Also, &#039;&#039;&#039;don&#039;t include a file with your sftp password&#039;&#039;&#039; (github is automatically crawled for passwords by hackers; a hacking attempt occurred on BGA studio for this reason in June 2020).&lt;br /&gt;
&lt;br /&gt;
You can also configure github to automatically deploy to BGA whenever you push to a branch. See [https://forum.boardgamearena.com/viewtopic.php?f=12&amp;amp;t=13370&amp;amp;start=10#p59537 this forum post] for instructions.&lt;br /&gt;
&lt;br /&gt;
=== PHP CLI ===&lt;br /&gt;
Its handy to have php cli (command line) tools install to run php locally, so you can test some stuff without deployment cycle, or create some scripts that generate code or markup.&lt;br /&gt;
&lt;br /&gt;
=== Image Manipulation ===&lt;br /&gt;
==== ImageMagick ====&lt;br /&gt;
Handy set of image manipulation &#039;&#039;&#039;command line&#039;&#039;&#039; tools, useful to for example to stitch together bunch of images and re-size, to use as sprite (in Stock component for example). I.e. you got a graphics file from publisher where every tile is 600x600 PNG file in separate file. You want .jpg instead of .png to make it not like 20Mb, and combine all images in one column and re-size to 128x128:&lt;br /&gt;
&lt;br /&gt;
(Linux example)&lt;br /&gt;
 /usr/bin/montage  `ls Tiles*.png` -tile 1 -geometry 128x128+0+0 out/tiles128.jpg&lt;br /&gt;
&lt;br /&gt;
The order of the images will match the &#039;ls&#039; order. If needed change the filenames if you need a specific order.&lt;br /&gt;
&lt;br /&gt;
https://www.imagemagick.org/script/download.php&lt;br /&gt;
&lt;br /&gt;
==== Gimp ====&lt;br /&gt;
&lt;br /&gt;
GUI tool, very complex but will do ALL what you possibly need to do with game graphics&lt;br /&gt;
&lt;br /&gt;
https://www.gimp.org/&lt;br /&gt;
&lt;br /&gt;
==== Shrinking ====&lt;br /&gt;
&lt;br /&gt;
Shrink images without loss of quality https://tinypng.com/ or http://www.iloveimg.com/ &lt;br /&gt;
&lt;br /&gt;
==== PDF Scrapper ====&lt;br /&gt;
extract images from PDF file (i.e. game rulebook) :&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
https://www.ilovepdf.com/&lt;br /&gt;
&lt;br /&gt;
http://www.extractpdf.com/&lt;br /&gt;
&lt;br /&gt;
On linux tool that does it in command line &amp;quot;pdfimages&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Rename/Copy project ====&lt;br /&gt;
&lt;br /&gt;
You can now override your project with any other project using Studio Control Panel.&lt;br /&gt;
&lt;br /&gt;
Alternatively there is a script available in sharedcode project to do the renaming which can be called in command line if you have php command line installed.&lt;br /&gt;
You need to have php clt (command line interface) installed, then you can download script and run it.&lt;br /&gt;
&lt;br /&gt;
https://github.com/elaskavaia/bga-sharedcode/blob/master/misc/bgaprojectrename.php&lt;br /&gt;
&lt;br /&gt;
Usage:&lt;br /&gt;
 php bgaprojectrename.php &amp;lt;originalProjectPath&amp;gt; &amp;lt;copyOfProjectRenamedPath&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Example on how to call it in command line  if you project name is &amp;quot;heartsmyproject&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 php7.0 git/bga-sharedcode/tools/bgaprojectrename.php remote/hearts/ remote/heartsmyproject/&lt;br /&gt;
&lt;br /&gt;
==== BGA Workbench ====&lt;br /&gt;
&lt;br /&gt;
PHP library providing tools to help manage BGA Studio projects including deployment and test utilities. https://github.com/danielholmes/bga-workbench&lt;br /&gt;
&lt;br /&gt;
=== Testing and validation tools ===&lt;br /&gt;
&lt;br /&gt;
* Run static analysis on your project to detect common problem and translation issues - project check - available from control panel - manage games - &amp;lt;your project&amp;gt; - Check project (blue button left middle)&lt;br /&gt;
* Check if web feature is supported https://caniuse.com/&lt;br /&gt;
* PHP: https://phpcodechecker.com/&lt;br /&gt;
* JS: http://esprima.org/demo/validate.html&lt;br /&gt;
* CSS: http://jigsaw.w3.org/css-validator/&lt;br /&gt;
&lt;br /&gt;
=== State machine diagram generation tool ===&lt;br /&gt;
&lt;br /&gt;
You can easily generate a state machine diagram from your states.inc.php using the dot language (https://graphviz.org/) via a PHP script.&lt;br /&gt;
&lt;br /&gt;
To do so:&lt;br /&gt;
* download the php script from the bga-sharedcode git repo located here https://github.com/elaskavaia/bga-sharedcode/blob/master/misc/generate_state_diagram.php and place it into your project root (on the same level as states.inc.php)&lt;br /&gt;
* run the script locally: &amp;quot;php.exe generate_state_diagram.php &amp;gt; graph.dot&amp;quot;&lt;br /&gt;
* open the generated dot file for visualization in visual studio code using the &amp;quot;Graphviz Interactive Preview&amp;quot; extension&lt;br /&gt;
* alternatively install graphiz (https://graphviz.org/download/) and generate an image file by running the following command &amp;quot;dot -Tpng -o graph.png graph.dot&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Here is an example of running the generation script on the hearts game from the tutorial:&lt;br /&gt;
&lt;br /&gt;
[[File:State_machine_diagram_dot.png]]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Legend:&#039;&#039;&#039;&lt;br /&gt;
* states of type game appear in yellow&lt;br /&gt;
* states of type activeplayer appear in blue&lt;br /&gt;
* states of type multipleactiveplayer appear in green&lt;br /&gt;
Once you have this state machine, you can use it to generate boilerplate code using the [https://github.com/xmakina/bga-statemachinegenerator BGA State Machine Generator]&lt;br /&gt;
&lt;br /&gt;
== Other useful tools ==&lt;br /&gt;
&lt;br /&gt;
* Website with bunch of textures and sounds http://www.grsites.com/archive/textures/&lt;br /&gt;
* Shrink images without loss of quality https://tinypng.com/ or http://www.iloveimg.com/ (recommended by Gregory Isabelli)&lt;br /&gt;
* CSS shapes https://css-tricks.com/examples/ShapesOfCSS/&lt;br /&gt;
* PDF Scraper - extract images - http://www.extractpdf.com/&lt;br /&gt;
* Hexagonal Grids (from Red Blob Games) - https://www.redblobgames.com/grids/hexagons/&lt;br /&gt;
* CSS tools (shades, shapes, textures) - https://dev.to/lissy93/super-useful-css-resources-1ba3&lt;br /&gt;
* Color blind pallette https://jfly.uni-koeln.de/color/&lt;br /&gt;
* CSS stroked text https://blog.logrocket.com/create-beautiful-stroked-text-css/&lt;br /&gt;
* CSS box model and SVG images https://www.freecodecamp.org/news/how-to-use-css-box-model-and-style-svg-images/&lt;br /&gt;
&lt;br /&gt;
== Client Tips ==&lt;br /&gt;
&lt;br /&gt;
=== Speed up game re-loading by disabling Input/Output debug section ===&lt;br /&gt;
&lt;br /&gt;
Development UI have few sections for debugging only, such as &#039;Input/Output debugging section&#039;. Loading this data will significantly slow down&lt;br /&gt;
your reload. I did some profiling and my reloading (i.e. F5) took 14 seconds, 12 of which it was dealing with loading this section. &lt;br /&gt;
If you not using it you can disable it. In your JavaScript code, in the begging of &#039;setup&#039; method add this code&lt;br /&gt;
&lt;br /&gt;
         dojo.destroy(&#039;debug_output&#039;);&lt;br /&gt;
&lt;br /&gt;
That should get rid of this section and overhead associated with loading it (it may have some other side-effects, I have not explored all of them)&lt;br /&gt;
&lt;br /&gt;
=== Speed up CSS development and layout ===&lt;br /&gt;
&lt;br /&gt;
Syncing files to server and refreshing is relative fast but still can take up to 20 seconds which is annoying.&lt;br /&gt;
If you working&lt;br /&gt;
a lot on css/images/layout you can speed it up by copying html in some state of the game to your local folder.&lt;br /&gt;
I.e. in your  project folder create directory misc/ and save your html as misc/test.html and changing path to css to load from local disk (and it will load your images to from local disk as well). &lt;br /&gt;
I.e. find something like&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;http://1.studio.boardgamearena.com:8081/data/themereleases/151226-1240/games/mygame/999999-9999/mygame.css&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and replace with&lt;br /&gt;
   &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;../mygame.css&amp;quot;/&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
You project structure will look like this&lt;br /&gt;
&lt;br /&gt;
 mygame&lt;br /&gt;
   img/ &amp;lt;-- your images&lt;br /&gt;
   mygame.css  &amp;lt;-- your original css&lt;br /&gt;
   ...&lt;br /&gt;
   misc/&lt;br /&gt;
     test.html &amp;lt;-- your test html&lt;br /&gt;
&lt;br /&gt;
It is a bit tricky to save html exact state, if you do save as it also pulls all resources sometimes.&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Xmakina</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=18825</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=18825"/>
		<updated>2023-11-10T09:21:51Z</updated>

		<summary type="html">&lt;p&gt;Xmakina: /* Layout and Graphics */ update tutorial image to reflect what is actually shown&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Using this tutorial, you can build a complete working game on the BGA environment: Hearts.&lt;br /&gt;
&lt;br /&gt;
Before you read this tutorial, you must:&lt;br /&gt;
* Read the overall presentations of the BGA Framework ([[Studio|see here]]).&lt;br /&gt;
* Know the rules for Hearts&lt;br /&gt;
* Some-what know the languages used on BGA: PHP, SQL, HTML, CSS, Javascript&lt;br /&gt;
* Set up your development environment [http://en.doc.boardgamearena.com/First_steps_with_BGA_Studio First Steps with BGA Studio]&lt;br /&gt;
* As part of setup you have to have access to your ftp home folder in studio, which would have the full &#039;hearts&#039; game source code. We will be using some resources of this game in this tutorial, so copy it over to local disk if you have not done so.&lt;br /&gt;
&lt;br /&gt;
If you are stuck or have question about this tutorial, post on [https://forum.boardgamearena.com/viewforum.php?f=12 BGA Developers forum]&lt;br /&gt;
&lt;br /&gt;
== Create your first game ==&lt;br /&gt;
&lt;br /&gt;
If you have not already, you have to create a project in BGA Studio. For this tutorial you can create a project heartsYOURNAME where&lt;br /&gt;
YOURNAME is your developer login name. You can also re-use the project you have created for the &amp;quot;First Steps&amp;quot; tutorial above.&lt;br /&gt;
With the initial skeleton of code provided, you can already start a game from the BGA Studio. &lt;br /&gt;
&lt;br /&gt;
1. Find and express start the game in turn-based mode with 4 players. Make sure it works. If you want to see the game as 2nd player press red arrow button on the player panel to switch to that player. More details can be found in [[First_steps_with_BGA_Studio]]&lt;br /&gt;
&lt;br /&gt;
2. Modify the text in heartsYOURNAME_heartsYOURNAME.tpl, reload the page in the browser and make sure your ftp sync works as expected.&lt;br /&gt;
Note: if you have not setup auto-sync do it now, manually copying files is a no-starter.&lt;br /&gt;
&lt;br /&gt;
3. Express stop from settings menu (the gear icon).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Note: please do &#039;&#039;&#039;not&#039;&#039;&#039; use the hearts project code as a base. This tutorial assumes you started with a TEMPLATE project with no prior modifications. Using the hearts project as a base will be very confusing and you won&#039;t be able to follow all the steps.&lt;br /&gt;
&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Attention!!!&amp;lt;/b&amp;gt; Very important note about reloading, if you don&#039;t remember this you may spent hours debugging. Browser caches .css files and images. If you change any of these files you have to do &amp;quot;full reload&amp;quot; which is usually Ctrl+F5 (or Ctrl+reload button on browser) not just a regular reload.&lt;br /&gt;
&lt;br /&gt;
== Hook version control system ==&lt;br /&gt;
&lt;br /&gt;
For a real game, or even for this tutorial, we recommend committing the code to version control right from the start. You are going to find yourself in a situation where the game doesn&#039;t even start anymore and no way of debugging it, unless you have a way to revert. That is where version control becomes very handy. If you are not familiar with version control (e.g. [https://git-scm.com/docs/gittutorial git]) then at least back up your files after each major change. Start now.&lt;br /&gt;
&lt;br /&gt;
Code for this tutorial available is on github: https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
&lt;br /&gt;
Different revisions represent different steps along the process, starting from original template to a PARTIAL game. The full game can be found in your FTP home folder.&lt;br /&gt;
&lt;br /&gt;
== Update game infos and box graphics ==&lt;br /&gt;
&lt;br /&gt;
Even it does nothing yet, always start by making sure the game looks decent in the game selector, meaning it has nice box graphics and its information is correct. For that we need to edit [[Game_meta-information: gameinfos.inc.php|gameinfos.inc.php]].&lt;br /&gt;
&lt;br /&gt;
For a real game, you would go to [http://boardgamegeek.com BoardGameGeek], find the game, and use the information from BGG to fill in the gameinfos.&lt;br /&gt;
&lt;br /&gt;
So let&#039;s do that. Find &amp;quot;hearts&amp;quot; on BoardGameGeek. (Hint: Original release 1850 :))&lt;br /&gt;
&lt;br /&gt;
You can fill in the year of publishing and bgg id, put &#039;&#039;Public Domain&#039;&#039; under publisher (for a real game, leave an empty string so it won&#039;t be displayed), and a publisher id of 171 for public domain. And as designer and author you can just put your own name just for fun. Set number of players to 4.&lt;br /&gt;
&lt;br /&gt;
  // Players configuration that can be played (ex: 2 to 4 players)&lt;br /&gt;
  &#039;players&#039; =&amp;gt; array( 4 ),  &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important step&#039;&#039;&#039;: you have to refresh the information in the Studio website through the control panel. So go to Control Panel -&amp;gt; Manage Games -&amp;gt; heartsYOURNAME&lt;br /&gt;
and press Reload for &#039;Reload game informations&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The next step would be to replace &#039;&#039;&#039;game_box.png&#039;&#039;&#039; with nicer images. This can be done from the [[Game metadata manager]]. &lt;br /&gt;
&lt;br /&gt;
Now try to start the game again. If you somehow introduced a syntax error in the gameinfos file it may not work (the game won&#039;t start).&lt;br /&gt;
Always use the &amp;quot;Express Start&amp;quot; button to start the game. You should see a standard state prompt from the template. You should see 4 players on the right: testdude0 .. testdude3.&lt;br /&gt;
To switch between them press the red arrow button near their names, it will open another tab. This way you don&#039;t need to login and logout from multiple accounts!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Note: if you had run the game before with less than 4 players there is a bug that will prevent you from running it with 4 only (if you did not run it before or run it with 4 players as instructed stop reading this note), to workaround revert back to original players array (i.e. 1,2,3,4), reload game options, then create a table with 4 players, exit that game table, then change gameoptions to 4 only as above, reload game options, create table again.&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Code Rev [https://github.com/elaskavaia/bga-heartsla/tree/4b3a73eeb5acae961ade18473af119e8ce8d1a8f]&lt;br /&gt;
&lt;br /&gt;
== Layout and Graphics ==&lt;br /&gt;
&lt;br /&gt;
In this section we will do graphics of the game, and main layout of the game.&lt;br /&gt;
&lt;br /&gt;
First copy a sprite with cards image from [https://github.com/elaskavaia/bga-heartsla/blob/4b3a73eeb5acae961ade18473af119e8ce8d1a8f/img/cards.jpg hearts img/cards.jpg]  into img/ folder of your project. Project hearts is mounted to your home directory on bga server.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;There are better quality deck of cards image at https://en.doc.boardgamearena.com/Common_board_game_elements_image_resources&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Details about images can be found here: [[Game art: img directory]].&lt;br /&gt;
&lt;br /&gt;
Edit .tpl to add some divs to represent player table and hand area&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;myhand_wrap&amp;quot; class=&amp;quot;whiteblock&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3&amp;gt;My Hand&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-tpl2.png]]&lt;br /&gt;
&lt;br /&gt;
Now lets add a card into the hand, just so you can feel it. Edit .tpl and a playertablecard div inside a hand div&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
       &amp;lt;div class=&amp;quot;playertablecard&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit .css file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.playertablecard {&lt;br /&gt;
    display: inline-block;&lt;br /&gt;
    position: relative;&lt;br /&gt;
    margin-top: 5px;&lt;br /&gt;
    width: 72px;&lt;br /&gt;
    height: 96px;&lt;br /&gt;
    background-image: url(&#039;img/cards.jpg&#039;); /* temp hack to see it */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you edit CSS remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&lt;br /&gt;
&amp;lt;i&amp;gt;Same when you change existing graphics files&amp;lt;/i&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You should see this:&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-tpl3.png]]&lt;br /&gt;
&lt;br /&gt;
Awesome! Now lets do the rest of layout.&lt;br /&gt;
&lt;br /&gt;
There are few ways of how html could have been generated, you could have start with nothing and generate&lt;br /&gt;
all by java script. Or you could have started with complete game markup in html and make java script just hide and move pieces around. BGA framework provides also a third way which is mix of both plus template engine to generate HTML using php. So lets do that.&lt;br /&gt;
&lt;br /&gt;
Change .tpl file to have this inside&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;playertables&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- BEGIN player --&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_{DIR}&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; style=&amp;quot;color:#{PLAYER_COLOR}&amp;quot;&amp;gt;&lt;br /&gt;
            {PLAYER_NAME}&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablecard&amp;quot; id=&amp;quot;playertablecard_{PLAYER_ID}&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;!-- END player --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;myhand_wrap&amp;quot; class=&amp;quot;whiteblock&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3&amp;gt;{MY_HAND}&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What we did is we added &amp;quot;block&amp;quot; player, it is marked up using html comments. {VAR} notation is used&lt;br /&gt;
to inject variables and &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;!-- BEGIN xxx --&amp;gt; &lt;br /&gt;
   inside &lt;br /&gt;
  &amp;lt;!-- END xxx --&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
effectively allows us to do template loops.&lt;br /&gt;
&lt;br /&gt;
In .view.php insert this code after &#039;Place your code below&#039; comment&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $template = self::getGameName() . &amp;quot;_&amp;quot; . self::getGameName();&lt;br /&gt;
        &lt;br /&gt;
        $directions = array( &#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039; );&lt;br /&gt;
        &lt;br /&gt;
        // this will inflate our player block with actual players data&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;begin_block($template, &amp;quot;player&amp;quot;);&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $info ) {&lt;br /&gt;
            $dir = array_shift($directions);&lt;br /&gt;
            $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player&amp;quot;, array (&amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id,&lt;br /&gt;
                    &amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $players [$player_id] [&#039;player_name&#039;],&lt;br /&gt;
                    &amp;quot;PLAYER_COLOR&amp;quot; =&amp;gt; $players [$player_id] [&#039;player_color&#039;],&lt;br /&gt;
                    &amp;quot;DIR&amp;quot; =&amp;gt; $dir ));&lt;br /&gt;
        }&lt;br /&gt;
        // this will make our My Hand text translatable&lt;br /&gt;
        $this-&amp;gt;tpl[&#039;MY_HAND&#039;] = self::_(&amp;quot;My hand&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What it does is for each player we have it will replicate the html between &amp;lt;!-- BEGIN player --&amp;gt; and &amp;lt;!-- END player --&amp;gt; tags, substituting the variable denoted by {XXX}&lt;br /&gt;
with the values you provide. The DIR variable in this case we pulling from directions array (where array_shift will take first element and remove it from the array).&lt;br /&gt;
&lt;br /&gt;
Reload. If everything went well you should see this:&lt;br /&gt;
&lt;br /&gt;
[[File:Hearts all rows.png|alt=Display a list of all players, with a dummy card in each position]]&lt;br /&gt;
&lt;br /&gt;
These are &amp;quot;tableau&amp;quot; areas for 4 players plus My hand visible only to one player. They are not exactly how we wanted them to be because we did not edit .css yet.&lt;br /&gt;
&lt;br /&gt;
Now edit .css, add these lines after import before our previous definition&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** Table layout **/&lt;br /&gt;
&lt;br /&gt;
#playertables {&lt;br /&gt;
    position: relative;&lt;br /&gt;
    width: 710px;&lt;br /&gt;
    height: 340px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.playertablename {&lt;br /&gt;
    font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.playertable {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    text-align: center;&lt;br /&gt;
    width: 180px;&lt;br /&gt;
    height: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.playertable_N {&lt;br /&gt;
    left: 50%;&lt;br /&gt;
    top: 0px;&lt;br /&gt;
    margin-left: -90px; /* half of 180 */&lt;br /&gt;
}&lt;br /&gt;
.playertable_S {&lt;br /&gt;
    left: 50%;&lt;br /&gt;
    bottom: 0px;&lt;br /&gt;
    margin-left: -90px; /* half of 180 */&lt;br /&gt;
}&lt;br /&gt;
.playertable_W {&lt;br /&gt;
    left: 0px;&lt;br /&gt;
    top: 50%;&lt;br /&gt;
    margin-top: -55px; /* half of 130 */&lt;br /&gt;
}&lt;br /&gt;
.playertable_E {&lt;br /&gt;
    right: 0px;&lt;br /&gt;
    top: 50%;&lt;br /&gt;
    margin-top: -55px; /* half of 130 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now you force Reload and you should see this:&lt;br /&gt;
[[File:Heartsla-tpl5.png]]&lt;br /&gt;
&lt;br /&gt;
This is almost all we need for graphics and layout, there are few tweaks left there but lets do some more heavy lifting now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Note: if you did not see changes you may have not force reloaded, force means you use Ctrl+F5 or Cltr+Shift-R, if you don&#039;t &amp;quot;force&amp;quot; browser will use cached version of .css and images! Which is not what you just changed&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Another Note: In general if you have auto-sync you don&#039;t need to reload if you change game.php file, you need normal reload if you change js, and force reload for css and images. If you changed state machine or database you likely need to restart the game.&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Game Interface JS Stock ==&lt;br /&gt;
&lt;br /&gt;
The BGA framework provides a few out of the box classes to deal with cards. The client side&lt;br /&gt;
contains a class called [[Stock]] and it can be used for any dynamic html &amp;quot;pieces&amp;quot; management that uses&lt;br /&gt;
common sprite images. On the server side we will use the [[Deck]] class which we discuss later.&lt;br /&gt;
&lt;br /&gt;
If you open cards.jpg in an image viewer you will see that it is a &amp;quot;sprite&amp;quot; image - a 13x4 grid of images stitched together,&lt;br /&gt;
which is a very efficient way to transport images. So we will use the Stock class to mark up these images and create&lt;br /&gt;
&amp;quot;card&amp;quot; divs for us.&lt;br /&gt;
&lt;br /&gt;
First, we need to add &#039;&#039;&#039;ebg/stock&#039;&#039;&#039; as a dependency in the hearts.js file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;     /// &amp;lt;==== HERE&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then add this to the Javascript constructor, this will define size of our cards&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            console.log(&#039;hearts constructor&#039;);&lt;br /&gt;
            this.cardwidth = 72;&lt;br /&gt;
            this.cardheight = 96;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The stock is initialized in the Javascript &amp;quot;setup&amp;quot; method like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // TODO: Set up your game interface here, according to &amp;quot;gamedatas&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    // Player hand&lt;br /&gt;
    this.playerHand = new ebg.stock(); // new stock object for hand&lt;br /&gt;
    this.playerHand.create( this, $(&#039;myhand&#039;), this.cardwidth, this.cardheight );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As parameters of the &amp;quot;create&amp;quot; method, we provided the width/height of an item (a card), and the container div &amp;quot;myhand&amp;quot; - which is an id of &amp;quot;div&amp;quot; element from our .tpl file representing a player hand.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then, we must tell the stock what items it is going to display during its life: the 52 cards of a standard card game from a CSS sprite image named &amp;quot;cards.jpg&amp;quot; with all the cards arranged in 4 rows and 13 columns.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we tell stock what item types to display:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            this.playerHand.image_items_per_row = 13; // 13 images per row&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
            // Create cards types:&lt;br /&gt;
            for (var color = 1; color &amp;lt;= 4; color++) {&lt;br /&gt;
                for (var value = 2; value &amp;lt;= 14; value++) {&lt;br /&gt;
                    // Build card type id&lt;br /&gt;
                    var card_type_id = this.getCardUniqueId(color, value);&lt;br /&gt;
                    this.playerHand.addItemType(card_type_id, card_type_id, g_gamethemeurl + &#039;img/cards.jpg&#039;, card_type_id);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And add this function to the utilities section&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Get card unique identifier based on its color and value&lt;br /&gt;
        getCardUniqueId : function(color, value) {&lt;br /&gt;
            return (color - 1) * 13 + (value - 2);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanations:&lt;br /&gt;
* At first, we tell the stock component that our CSS sprite contains 13 items per row. This way, it can find the correct image for each card type id.&lt;br /&gt;
* Then for the 4x13 cards, we call the &#039;&#039;&#039;addItemType&#039;&#039;&#039; method that creates the type. The arguments are the type id, the weight of the card (for sorting purpose), the URL of our CSS sprite, and the position of our card image in the CSS sprite. It happens to be the same number in our case.&lt;br /&gt;
&lt;br /&gt;
Note: we need to generate a unique ID for each type of card based on its color and value.  For that we create a function &#039;&#039;&#039;getCardUniqueId&#039;&#039;&#039;. The type is the unique identifier of the TYPE of the card, e.g., the queen of spades encoded as an integer. If our deck had 2 standard card decks we would have had 2 queens of spades; they would share the same type and the same image but would have different ids. NOTE: It&#039;s unfortunate that they named this &#039;&#039;&#039;getCardUniqueId&#039;&#039;&#039;; it should have been &#039;&#039;&#039;getCardUniqueType&#039;&#039;&#039;, because it really isn&#039;t an id, but a TYPE of card. The type of the item should either be a reversible function of its properties (i.e., kind of suite * 13 + value) or just an enumerator described in material.inc.php. In this specific case it&#039;s a synthetic type id, which also the same as the number of the card in the sprite image (i.e., if you enumerate each image in sprite going left to right, then top to bottom).&lt;br /&gt;
&lt;br /&gt;
Now let&#039;s add the 5 of Hearts to the player&#039;s hand just for fun (this code will go in setup method after types initialization):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// 2 = hearts, 5 is 5, and 42 is the card id, which normally would come from db&lt;br /&gt;
this.playerHand.addToStockWithId( this.getCardUniqueId( 2, 5 ), 42 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will add the card with id 42 and type 16 ( (2-1)*13+(5-2)=16 ). &lt;br /&gt;
&lt;br /&gt;
Note that number 16 would not be something you can see in database, Deck database will have separate field for type and type_arg where type is suite and type_arg is number, so its not the same thing, but you can use same formula to convert. Number 42 on the other hand would be id field in database. But we get to database in the later section.&lt;br /&gt;
&lt;br /&gt;
If you reload now you should see the 5 of hearts in &amp;quot;your hand&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Stock control can handle clicking on items and forms the selection. You can immediately react to selection&lt;br /&gt;
or you can query it later; for example when user presses some other button.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s hook it up. Add this in the setup method in .js file, after this.playerHand is initialised:&lt;br /&gt;
&lt;br /&gt;
     dojo.connect( this.playerHand, &#039;onChangeSelection&#039;, this, &#039;onPlayerHandSelectionChanged&#039; );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then find the Player&#039;s action comment section in .js file and add a handler after the comment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onPlayerHandSelectionChanged: function() {&lt;br /&gt;
            var items = this.playerHand.getSelectedItems();&lt;br /&gt;
&lt;br /&gt;
            if (items.length &amp;gt; 0) {&lt;br /&gt;
                if (this.checkAction(&#039;playCard&#039;, true)) {&lt;br /&gt;
                    // Can play a card&lt;br /&gt;
&lt;br /&gt;
                    var card_id = items[0].id;&lt;br /&gt;
                    console.log(&amp;quot;on playCard &amp;quot;+card_id);&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;giveCards&#039;)) {&lt;br /&gt;
                    // Can give cards =&amp;gt; let the player select some cards&lt;br /&gt;
                } else {&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The function name of the handler is 4th parameter of the dojo.connect function. Make sure you spell it correctly or there will be unpredictable effects.&lt;br /&gt;
&lt;br /&gt;
Now if you reload, open the Javascript Console (F12), and then click on the card in My Hand, you should see:&lt;br /&gt;
  on playCard 42&lt;br /&gt;
printed on the console&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note : You need to be the active player to have rights to play a card and so log your message in the console&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Game Database and Game Initialisation ==&lt;br /&gt;
&lt;br /&gt;
Next step, you want to design a game database and setup a new game (on the server side).&lt;br /&gt;
For that we need to a) modify the database schema to add our cards data b) add some global variables into&lt;br /&gt;
the existing globals table.&lt;br /&gt;
&lt;br /&gt;
To modify the schema, first exit your existing game(s). Open &#039;&#039;&#039;dbmodel.sql&#039;&#039;&#039; file and uncomment the card table creation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the &amp;quot;card&amp;quot; table which will be managed by the Deck php class.&lt;br /&gt;
&lt;br /&gt;
In addition we want a little piece of information in the players table:&lt;br /&gt;
&lt;br /&gt;
  -- add info about first player&lt;br /&gt;
  ALTER TABLE `player` ADD `player_first` BOOLEAN NOT NULL DEFAULT &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
Not sure why they put this into the player table, as we could use a global db variable to hold first player as easily.&lt;br /&gt;
But I am just following the existing code more-or-less.&lt;br /&gt;
&lt;br /&gt;
Next we finally get into .game.php class, where the main logic and db interaction would be. Find php constructor which should be &lt;br /&gt;
  function __construct( )&lt;br /&gt;
This is first function in a file. Add this code to constructor.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        self::initGameStateLabels( array( &lt;br /&gt;
                         &amp;quot;currentHandType&amp;quot; =&amp;gt; 10, &lt;br /&gt;
                         &amp;quot;trickColor&amp;quot; =&amp;gt; 11, &lt;br /&gt;
                         &amp;quot;alreadyPlayedHearts&amp;quot; =&amp;gt; 12,&lt;br /&gt;
                          ) );&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;cards = self::getNew( &amp;quot;module.common.deck&amp;quot; );&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;init( &amp;quot;card&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we are initializing three &amp;quot;Game State Variables&amp;quot; which are variables stored in the database. They are integers.&lt;br /&gt;
It must start with values higher or equal to 10 since values lower than 10 are reserved. These values are stored by numeric ids&lt;br /&gt;
in the database, but in the php we associate them with string labels for convenience of access. The variables are &amp;quot;trickColor&amp;quot;: numbers from 1 to 4 that map to card suit (not sure why it&#039;s called color; maybe it&#039;s a translation from French); &amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick; &amp;quot;currentHandType&amp;quot;: stores the value to indicate who to give cards to during exchange.&lt;br /&gt;
&lt;br /&gt;
The next 2 lines are creating $this-&amp;gt;cards object and associating it with &amp;quot;card&amp;quot; table in the the database.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;If we called db table &#039;foo&#039; instead of &#039;card&#039; the last statement would have been  $this-&amp;gt;cards-&amp;gt;init( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point I would start a new game and make sure it starts, then exit. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;&lt;br /&gt;
If you made a mistake&lt;br /&gt;
in the .sql or php constructor the game won&#039;t start, and good luck debugging it. (That is why it&#039;s important to check&lt;br /&gt;
once in a while to make sure it still starts while you remember what you have changed.)&lt;br /&gt;
&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Code Rev [https://github.com/elaskavaia/bga-heartsla/tree/e3a049257b592ff6167688d4d344f8a83d349b08]&lt;br /&gt;
&lt;br /&gt;
Now we can go to game initialization &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; in game.php. This method is called only once when the game is created.&lt;br /&gt;
&lt;br /&gt;
In your template project you should have code that deals with player table, just leave it as is. Start inserting the&lt;br /&gt;
other code after &amp;quot;Start the game initialization&amp;quot; comment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Init global values with their initial values&lt;br /&gt;
&lt;br /&gt;
        // Note: hand types: 0 = give 3 cards to player on the left&lt;br /&gt;
        //                   1 = give 3 cards to player on the right&lt;br /&gt;
        //                   2 = give 3 cards to player opposite&lt;br /&gt;
        //                   3 = keep cards&lt;br /&gt;
        self::setGameStateInitialValue( &#039;currentHandType&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Set current trick color to zero (= no trick color)&lt;br /&gt;
        self::setGameStateInitialValue( &#039;trickColor&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Mark if we already played hearts during this hand&lt;br /&gt;
        self::setGameStateInitialValue( &#039;alreadyPlayedHearts&#039;, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we initialize all the globals to 0.&lt;br /&gt;
&lt;br /&gt;
Next is to create our cards in the database. We have one deck of cards so it&#039;s pretty simple.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Create cards&lt;br /&gt;
        $cards = array ();&lt;br /&gt;
        foreach ( $this-&amp;gt;colors as $color_id =&amp;gt; $color ) {&lt;br /&gt;
            // spade, heart, diamond, club&lt;br /&gt;
            for ($value = 2; $value &amp;lt;= 14; $value ++) {&lt;br /&gt;
                //  2, 3, 4, ... K, A&lt;br /&gt;
                $cards [] = array (&#039;type&#039; =&amp;gt; $color_id,&#039;type_arg&#039; =&amp;gt; $value,&#039;nbr&#039; =&amp;gt; 1 );&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;createCards( $cards, &#039;deck&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code that will create one of each card. But don&#039;t run it yet, because we missing $this-&amp;gt;colors.&lt;br /&gt;
So we have state of the game in the database, but there is some static game information which never changes.&lt;br /&gt;
This information should be stored in material.inc.php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
We will edit this file now by adding these lines&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;colors = array(&lt;br /&gt;
    1 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;spade&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;spade&#039;) ),&lt;br /&gt;
    2 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;heart&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;heart&#039;) ),&lt;br /&gt;
    3 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;club&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;club&#039;) ),&lt;br /&gt;
    4 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;diamond&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;diamond&#039;) )&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
$this-&amp;gt;values_label = array(&lt;br /&gt;
    2 =&amp;gt;&#039;2&#039;,&lt;br /&gt;
    3 =&amp;gt; &#039;3&#039;,&lt;br /&gt;
    4 =&amp;gt; &#039;4&#039;,&lt;br /&gt;
    5 =&amp;gt; &#039;5&#039;,&lt;br /&gt;
    6 =&amp;gt; &#039;6&#039;,&lt;br /&gt;
    7 =&amp;gt; &#039;7&#039;,&lt;br /&gt;
    8 =&amp;gt; &#039;8&#039;,&lt;br /&gt;
    9 =&amp;gt; &#039;9&#039;,&lt;br /&gt;
    10 =&amp;gt; &#039;10&#039;,&lt;br /&gt;
    11 =&amp;gt; clienttranslate(&#039;J&#039;),&lt;br /&gt;
    12 =&amp;gt; clienttranslate(&#039;Q&#039;),&lt;br /&gt;
    13 =&amp;gt; clienttranslate(&#039;K&#039;),&lt;br /&gt;
    14 =&amp;gt; clienttranslate(&#039;A&#039;)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where $this-&amp;gt;colors will define Suit labels and $this-&amp;gt;values_label will define value labels.&lt;br /&gt;
If you noticed, we have two of each label for suits. This is because sometimes we need translated values on the php&lt;br /&gt;
side and sometimes we don&#039;t. In this case &#039;&#039;&#039;nametr&#039;&#039;&#039; will return a translated value in php, which is only useful when you throw exceptions to show the right strings. If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. &#039;clienttranslate&#039; marks the value for translation but does not actually change it for php. For more about this wonderful translation stuff see [[Translations]].&lt;br /&gt;
&lt;br /&gt;
== Full game model synchronisation ==&lt;br /&gt;
&lt;br /&gt;
Now at any point in the game we need to make sure that database information can be reflected back in the UI, so we must fix the &#039;&#039;&#039;getAllDatas&#039;&#039;&#039; function&lt;br /&gt;
to return all possible data we need to reconstruct the game. This is in the game.php file. The template for getAllDatas() already takes care of player info. Let&#039;s just&lt;br /&gt;
add hand and tableau data before we return a result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Cards in player hand&lt;br /&gt;
        $result[&#039;hand&#039;] = $this-&amp;gt;cards-&amp;gt;getCardsInLocation( &#039;hand&#039;, $current_player_id );&lt;br /&gt;
        &lt;br /&gt;
        // Cards played on the table&lt;br /&gt;
        $result[&#039;cardsontable&#039;] = $this-&amp;gt;cards-&amp;gt;getCardsInLocation( &#039;cardsontable&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now on the client side we should display this data, so in your .js file in the setup function (which is the receiver of getAllDatas) replace our hack of putting 5 of Hearts directly into the hand with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Cards in player&#039;s hand&lt;br /&gt;
            for ( var i in this.gamedatas.hand) {&lt;br /&gt;
                var card = this.gamedatas.hand[i];&lt;br /&gt;
                var color = card.type;&lt;br /&gt;
                var value = card.type_arg;&lt;br /&gt;
                this.playerHand.addToStockWithId(this.getCardUniqueId(color, value), card.id);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Cards played on table&lt;br /&gt;
            for (i in this.gamedatas.cardsontable) {&lt;br /&gt;
                var card = this.gamedatas.cardsontable[i];&lt;br /&gt;
                var color = card.type;&lt;br /&gt;
                var value = card.type_arg;&lt;br /&gt;
                var player_id = card.location_arg;&lt;br /&gt;
                this.playCardOnTable(player_id, color, value, card.id);&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This should show hand and tableau cards now, except we are missing the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function. So find the &#039;&#039;&#039;getCardUniqueId&#039;&#039;&#039; function which&lt;br /&gt;
should be in the utilities section and add this after it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        playCardOnTable : function(player_id, color, value, card_id) {&lt;br /&gt;
            // player_id =&amp;gt; direction&lt;br /&gt;
            dojo.place(this.format_block(&#039;jstpl_cardontable&#039;, {&lt;br /&gt;
                x : this.cardwidth * (value - 2),&lt;br /&gt;
                y : this.cardheight * (color - 1),&lt;br /&gt;
                player_id : player_id&lt;br /&gt;
            }), &#039;playertablecard_&#039; + player_id);&lt;br /&gt;
&lt;br /&gt;
            if (player_id != this.player_id) {&lt;br /&gt;
                // Some opponent played a card&lt;br /&gt;
                // Move card from player panel&lt;br /&gt;
                this.placeOnObject(&#039;cardontable_&#039; + player_id, &#039;overall_player_board_&#039; + player_id);&lt;br /&gt;
            } else {&lt;br /&gt;
                // You played a card. If it exists in your hand, move card from there and remove&lt;br /&gt;
                // corresponding item&lt;br /&gt;
&lt;br /&gt;
                if ($(&#039;myhand_item_&#039; + card_id)) {&lt;br /&gt;
                    this.placeOnObject(&#039;cardontable_&#039; + player_id, &#039;myhand_item_&#039; + card_id);&lt;br /&gt;
                    this.playerHand.removeFromStockById(card_id);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // In any case: move it to its final destination&lt;br /&gt;
            this.slideToObject(&#039;cardontable_&#039; + player_id, &#039;playertablecard_&#039; + player_id).play();&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work we also need to add a card template in the .tpl file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Javascript HTML templates&lt;br /&gt;
&lt;br /&gt;
var jstpl_cardontable = &#039;&amp;lt;div class=&amp;quot;cardontable&amp;quot; id=&amp;quot;cardontable_${player_id}&amp;quot; style=&amp;quot;background-position:-${x}px -${y}px&amp;quot;&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;
&lt;br /&gt;
What this does is basically create another card object, because if it is not our card it&#039;s not in our hand (Stock) so&lt;br /&gt;
we have to create it out of thin air. The technique to do that is to implement a Javascript template object defined in the .tpl file with some&lt;br /&gt;
parameters, which will basically create a &amp;quot;div&amp;quot; string (yes you could have used string concatenation but it would not be fancy).&lt;br /&gt;
Now dojo.place places it (the div) on top of a placeholder. Now we have an object with an id of &#039;cardontable_&#039; + player_id. Depending&lt;br /&gt;
on who is playing it we either place it on the player miniboard or in hand (and remove it from hand stock). Then we animate the card move.&lt;br /&gt;
&lt;br /&gt;
We also should fix our .css file now to add style for cardontable and REMOVE background for playertablecard which really is a placeholder div and not a card. (Don&#039;t miss the remove step; it will be all screwy if you do!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.playertablecard {&lt;br /&gt;
    display: inline-block;&lt;br /&gt;
    position: relative;&lt;br /&gt;
    margin-top: 5px;&lt;br /&gt;
    width: 72px;&lt;br /&gt;
    height: 96px;&lt;br /&gt;
    /* we remove background-image here */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*** cards on table ***/&lt;br /&gt;
&lt;br /&gt;
.cardontable {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    width: 72px;&lt;br /&gt;
    height: 96px;&lt;br /&gt;
    background-image: url(&#039;img/cards.jpg&#039;); &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now to test that it actually works let&#039;s deal cards to players during game initialization:&lt;br /&gt;
&lt;br /&gt;
Add this after createCards in setupNewGame function in the game.php file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Shuffle deck&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;shuffle(&#039;deck&#039;);&lt;br /&gt;
        // Deal 13 cards to each players&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player ) {&lt;br /&gt;
            $cards = $this-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
        } &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now when you start the game you should see 13 cards in your hand!&lt;br /&gt;
&lt;br /&gt;
We just need to hook-up clicking on card and test if our playCardOnTable works.&lt;br /&gt;
&lt;br /&gt;
Find onPlayerHandSelectionChanged function in the JS file, we should have logging there like  console.log(&amp;quot;on playCard &amp;quot;+card_id);&lt;br /&gt;
So after that insert this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                    console.log(&amp;quot;on playCard &amp;quot;+card_id);&lt;br /&gt;
                    // type is (color - 1) * 13 + (value - 2)&lt;br /&gt;
                    var type = items[0].type;&lt;br /&gt;
                    var color = Math.floor(type / 13) + 1;&lt;br /&gt;
                    var value = type % 13 + 2;&lt;br /&gt;
                    &lt;br /&gt;
                    this.playCardOnTable(this.player_id,color,value,card_id);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: this code is for testing we will replace it with server interaction after we test it.&lt;br /&gt;
&lt;br /&gt;
Now if you force reload (because we changed .css before) you should be able to click on card from your hand and see it moving,&lt;br /&gt;
you can click on few cards this way. When you done enjoying the animation, press F5 to get your hand back.&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-sync.png]]&lt;br /&gt;
&lt;br /&gt;
Code Rev [https://github.com/elaskavaia/bga-heartsla/tree/01d4e2f595fd14c2adcc97a957d21bb2766f78a8]&lt;br /&gt;
&lt;br /&gt;
== State Machine ==&lt;br /&gt;
&lt;br /&gt;
Now we need to create a game state machine. So the states are:&lt;br /&gt;
&lt;br /&gt;
* Cards are dealt to all players (lets call it &amp;quot;newHand&amp;quot;)&lt;br /&gt;
* Player is selected who will start a new trick (&amp;quot;newTrick&amp;quot;)&lt;br /&gt;
* Player start or respond to played card (&amp;quot;playerTurn&amp;quot;)&lt;br /&gt;
* Game control is passed to next player or trick is ended (&amp;quot;nextPlayer&amp;quot;)&lt;br /&gt;
* End of hand processing (scoring and check for end of game) (&amp;quot;nextHand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
In addition players can exchange cards so we need two more states for that but we will skip it for now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The state handling spread across 4 files, so you have to make sure all pieces are connected together.&lt;br /&gt;
The state machine states.php defines all the states, and function handlers on php side in a form of string,&lt;br /&gt;
and if any of these functions are not implemented it would be very hard to debug because it will break in random places.&lt;br /&gt;
&lt;br /&gt;
So .states.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
    // The initial state. Please do not modify.&lt;br /&gt;
    1 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Game setup&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    /// New hand&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;newHand&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stNewHand&amp;quot;,&lt;br /&gt;
        &amp;quot;updateGameProgression&amp;quot; =&amp;gt; true,   &lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 30 )&lt;br /&gt;
    ),    &lt;br /&gt;
&lt;br /&gt;
    21 =&amp;gt; array(       &lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;giveCards&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Some players must choose 3 cards to give to ${direction}&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must choose 3 cards to give to ${direction}&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;multipleactiveplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGiveCards&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argGiveCards&amp;quot;,&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;giveCards&amp;quot; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;giveCards&amp;quot; =&amp;gt; 22, &amp;quot;skip&amp;quot; =&amp;gt; 22 )        &lt;br /&gt;
    ), &lt;br /&gt;
    &lt;br /&gt;
    22 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;takeCards&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stTakeCards&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;startHand&amp;quot; =&amp;gt; 30, &amp;quot;skip&amp;quot; =&amp;gt; 30  )&lt;br /&gt;
    ),        &lt;br /&gt;
      &lt;br /&gt;
    &lt;br /&gt;
    // Trick&lt;br /&gt;
    &lt;br /&gt;
    30 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;newTrick&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stNewTrick&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 31 )&lt;br /&gt;
    ),       &lt;br /&gt;
    31 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a card&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; =&amp;gt; 32 )&lt;br /&gt;
    ), &lt;br /&gt;
    32 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;nextPlayer&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stNextPlayer&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextPlayer&amp;quot; =&amp;gt; 31, &amp;quot;nextTrick&amp;quot; =&amp;gt; 30, &amp;quot;endHand&amp;quot; =&amp;gt; 40 )&lt;br /&gt;
    ), &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    // End of the hand (scoring, etc...)&lt;br /&gt;
    40 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;endHand&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stEndHand&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextHand&amp;quot; =&amp;gt; 2, &amp;quot;endGame&amp;quot; =&amp;gt; 99 )&lt;br /&gt;
    ),     &lt;br /&gt;
   &lt;br /&gt;
    // Final state.&lt;br /&gt;
    // Please do not modify.&lt;br /&gt;
    99 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameEnd&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;End of game&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameEnd&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argGameEnd&amp;quot;&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The full details on these fields are in [[Your_game_state_machine:_states.inc.php]].&lt;br /&gt;
&lt;br /&gt;
But basically we have Player states, in which a human player has to perform an &amp;quot;action&amp;quot; by pressing some button in the UI or selecting some game item, which will trigger js handler, which will do an ajax call to the server into API defined&lt;br /&gt;
by .action.php file. All functions in this file are API between client and server and have very simple&lt;br /&gt;
and repetitive structures. In this case there are only two actions player can do - play a card or pass cards to other player. So these 2 functions go into .action.php file, we will only define one now since we have not implemented card passing states yet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function playCard() {&lt;br /&gt;
        self::setAjaxMode();&lt;br /&gt;
        $card_id = self::getArg(&amp;quot;id&amp;quot;, AT_posint, true);&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;playCard($card_id);&lt;br /&gt;
        self::ajaxResponse();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make it run we have to define all the handler functions that we referenced in states, which are - one function for state arguments argGiveCards, 4 functions for robot states (where the game performs some action)&lt;br /&gt;
and 1 function for player actions handling.&lt;br /&gt;
In .game.php, find &#039;Game state arguments&#039; section and paste this in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argGiveCards() {&lt;br /&gt;
        return array ();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This normally passes some parameters to states, but we don&#039;t need anything yet. It&#039;s good to have a placeholder there anyway, so we can fix it later.&lt;br /&gt;
Important: even when it&#039;s a stub, this function must return an array not a scalar.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s do stubs for other functions, find the game state actions section in .game.php file and insert these&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stNewHand() {&lt;br /&gt;
        // Take back all cards (from any location =&amp;gt; null) to deck&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(null, &amp;quot;deck&amp;quot;);&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;shuffle(&#039;deck&#039;);&lt;br /&gt;
        // Deal 13 cards to each players&lt;br /&gt;
        // Create deck, shuffle it and give 13 initial cards&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player ) {&lt;br /&gt;
            $cards = $this-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
            // Notify player about his cards&lt;br /&gt;
            self::notifyPlayer($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        self::setGameStateValue(&#039;alreadyPlayedHearts&#039;, 0);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function stNewTrick() {&lt;br /&gt;
        // New trick: active the player who wins the last trick, or the player who own the club-2 card&lt;br /&gt;
        // Reset trick color to 0 (= no color)&lt;br /&gt;
        self::setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function stNextPlayer() {&lt;br /&gt;
        // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
        if ($this-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;cardsontable&#039;) == 4) {&lt;br /&gt;
            // This is the end of the trick&lt;br /&gt;
            // Move all cards to &amp;quot;cardswon&amp;quot; of the given player&lt;br /&gt;
            $best_value_player_id = self::activeNextPlayer(); // TODO figure out winner of trick&lt;br /&gt;
            $this-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
        &lt;br /&gt;
            if ($this-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;hand&#039;) == 0) {&lt;br /&gt;
                // End of the hand&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;endHand&amp;quot;);&lt;br /&gt;
            } else {&lt;br /&gt;
                // End of the trick&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;nextTrick&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            // Standard case (not the end of the trick)&lt;br /&gt;
            // =&amp;gt; just active the next player&lt;br /&gt;
            $player_id = self::activeNextPlayer();&lt;br /&gt;
            self::giveExtraTime($player_id);&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;nextPlayer&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function stEndHand() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;nextHand&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Important: All state actions game or player must end with state transition (or thrown exception). Also make sure it&#039;s ONLY one state transition,&lt;br /&gt;
if you accidentally fall through after state transition and do another one it will be a real mess and head scratching for long time.&lt;br /&gt;
&lt;br /&gt;
Now find &#039;player actions&#039; section and paste this code there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function playCard($card_id) {&lt;br /&gt;
        self::checkAction(&amp;quot;playCard&amp;quot;);&lt;br /&gt;
        $player_id = self::getActivePlayerId();&lt;br /&gt;
        throw new BgaUserException(self::_(&amp;quot;Not implemented: &amp;quot;) . &amp;quot;$player_id plays $card_id&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We won&#039;t implement it yet but throw an exception which we will see if interaction is working properly&lt;br /&gt;
&lt;br /&gt;
Now the game should start but it would not be any different than before because we have to implement actual interactions.&lt;br /&gt;
It&#039;s good to check if it&#039;s still working though (and if it was running before you have to exit because we changed state machine and normally it will break stuff)&lt;br /&gt;
&lt;br /&gt;
== Client - Server interactions ==&lt;br /&gt;
&lt;br /&gt;
Now to implement things for real we have hook UI actions to ajax calls, and process notifications sent by the server.&lt;br /&gt;
So previously we hooked playCardOnTable right into js handler which caused client animation, in real game its a two&lt;br /&gt;
step operation. When user clicks on game element js client sends an ajax call to server, server processes it and updates database, server sends&lt;br /&gt;
notification in response, client hooks animations to server notification.&lt;br /&gt;
&lt;br /&gt;
So in .js code replace onPlayerHandSelectionChanged with&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onPlayerHandSelectionChanged : function() {&lt;br /&gt;
            var items = this.playerHand.getSelectedItems();&lt;br /&gt;
&lt;br /&gt;
            if (items.length &amp;gt; 0) {&lt;br /&gt;
                var action = &#039;playCard&#039;;&lt;br /&gt;
                if (this.checkAction(action, true)) {&lt;br /&gt;
                    // Can play a card&lt;br /&gt;
                    var card_id = items[0].id;                    &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;, {&lt;br /&gt;
                        id : card_id,&lt;br /&gt;
                        lock : true&lt;br /&gt;
                    }, this, function(result) {&lt;br /&gt;
                    }, function(is_error) {&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;giveCards&#039;)) {&lt;br /&gt;
                    // Can give cards =&amp;gt; let the player select some cards&lt;br /&gt;
                } else {&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now when you click on card you should get a server response: Not implemented...&lt;br /&gt;
&lt;br /&gt;
Lets implement it, in .game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function playCard($card_id) {&lt;br /&gt;
        self::checkAction(&amp;quot;playCard&amp;quot;);&lt;br /&gt;
        $player_id = self::getActivePlayerId();&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;moveCard($card_id, &#039;cardsontable&#039;, $player_id);&lt;br /&gt;
        // XXX check rules here&lt;br /&gt;
        $currentCard = $this-&amp;gt;cards-&amp;gt;getCard($card_id);&lt;br /&gt;
        // And notify&lt;br /&gt;
        self::notifyAllPlayers(&#039;playCard&#039;, clienttranslate(&#039;${player_name} plays ${value_displayed} ${color_displayed}&#039;), array (&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array (&#039;color_displayed&#039;,&#039;value_displayed&#039; ),&#039;card_id&#039; =&amp;gt; $card_id,&#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; $this-&amp;gt;values_label [$currentCard [&#039;type_arg&#039;]],&#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; $this-&amp;gt;colors [$currentCard [&#039;type&#039;]] [&#039;name&#039;] ));&lt;br /&gt;
        // Next player&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;playCard&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We get the card from client, we move it to the table (moveCard is hooked to database directly, its part of deck class),&lt;br /&gt;
we notify all players and we change state. What we are missing here is bunch of checks (rule enforcements), we will add it later.&lt;br /&gt;
&lt;br /&gt;
Interesting part about this notify is that we use i18n array for strings that needs to be translated by client, so&lt;br /&gt;
they are sent as English text in notification, then client has to know which parameters needs translating.&lt;br /&gt;
&lt;br /&gt;
On the client side .js we have to implement a notification handler to do the animation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setupNotifications : function() {&lt;br /&gt;
            console.log(&#039;notifications subscriptions setup&#039;);&lt;br /&gt;
&lt;br /&gt;
            dojo.subscribe(&#039;newHand&#039;, this, &amp;quot;notif_newHand&amp;quot;);&lt;br /&gt;
            dojo.subscribe(&#039;playCard&#039;, this, &amp;quot;notif_playCard&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        notif_newHand : function(notif) {&lt;br /&gt;
            // We received a new full hand of 13 cards.&lt;br /&gt;
            this.playerHand.removeAll();&lt;br /&gt;
&lt;br /&gt;
            for ( var i in notif.args.cards) {&lt;br /&gt;
                var card = notif.args.cards[i];&lt;br /&gt;
                var color = card.type;&lt;br /&gt;
                var value = card.type_arg;&lt;br /&gt;
                this.playerHand.addToStockWithId(this.getCardUniqueId(color, value), card.id);&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        notif_playCard : function(notif) {&lt;br /&gt;
            // Play a card on the table&lt;br /&gt;
            this.playCardOnTable(notif.args.player_id, notif.args.color, notif.args.value, notif.args.card_id);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now it actually works through the server when you click on card - the move is recorded. If you test it now you will notice&lt;br /&gt;
after trick is done all cards remains on the table, but if you press F5 they would disappear, this is because&lt;br /&gt;
we updated database to pick-up the cards but did not send notification about it, so we need to send notification about it&lt;br /&gt;
and have a handler for it&lt;br /&gt;
&lt;br /&gt;
So in .game.php file add notification in stNextPlayer function after moveAllCardsInLocation call:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Notify&lt;br /&gt;
            // Note: we use 2 notifications here in order we can pause the display during the first notification&lt;br /&gt;
            //  before we move all cards to the winner (during the second)&lt;br /&gt;
            $players = self::loadPlayersBasicInfos();&lt;br /&gt;
            self::notifyAllPlayers( &#039;trickWin&#039;, clienttranslate(&#039;${player_name} wins the trick&#039;), array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $best_value_player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; $players[ $best_value_player_id ][&#039;player_name&#039;]&lt;br /&gt;
            ) );            &lt;br /&gt;
            self::notifyAllPlayers( &#039;giveAllCardsToPlayer&#039;,&#039;&#039;, array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $best_value_player_id&lt;br /&gt;
            ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And in .js file add 2 more notification handlers.&lt;br /&gt;
&lt;br /&gt;
This is to subscribe in setupNotifications function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            dojo.subscribe( &#039;trickWin&#039;, this, &amp;quot;notif_trickWin&amp;quot; );&lt;br /&gt;
            this.notifqueue.setSynchronous( &#039;trickWin&#039;, 1000 );&lt;br /&gt;
            dojo.subscribe( &#039;giveAllCardsToPlayer&#039;, this, &amp;quot;notif_giveAllCardsToPlayer&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And these are handlers&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        notif_trickWin : function(notif) {&lt;br /&gt;
            // We do nothing here (just wait in order players can view the 4 cards played before they&#039;re gone.&lt;br /&gt;
        },&lt;br /&gt;
        notif_giveAllCardsToPlayer : function(notif) {&lt;br /&gt;
            // Move all cards on table to given table, then destroy them&lt;br /&gt;
            var winner_id = notif.args.player_id;&lt;br /&gt;
            for ( var player_id in this.gamedatas.players) {&lt;br /&gt;
                var anim = this.slideToObject(&#039;cardontable_&#039; + player_id, &#039;overall_player_board_&#039; + winner_id);&lt;br /&gt;
                dojo.connect(anim, &#039;onEnd&#039;, function(node) {&lt;br /&gt;
                    dojo.destroy(node);&lt;br /&gt;
                });&lt;br /&gt;
                anim.play();&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So &#039;trickWin&#039; notification does not do much except it will delay the processing of next notification by 1 second (1000 ms)&lt;br /&gt;
and it will log the message (that happens independently of what handler does).&lt;br /&gt;
&amp;lt;i&amp;gt;Note: if on the other hand you don&#039;t want to log but want to do something else, send an empty message&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now after the trick you see all cards move towards the &amp;quot;player&#039;s stash&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Scoring and End of game handling ==&lt;br /&gt;
&lt;br /&gt;
Now we should calculate scoring and for that we need to actually track who wins the trick.&lt;br /&gt;
Trick is won by the player with highest card (no trump). We just need to remember what is trick suite.&lt;br /&gt;
For which we will use state variable &#039;trickColor&#039; which we already conveniently created.&lt;br /&gt;
&lt;br /&gt;
In .game.php file find playCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = self::getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            self::setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember first suit being played, now to use it modify stNextPlayer function to fix our TODO comment&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stNextPlayer() {&lt;br /&gt;
        // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
        if ($this-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;cardsontable&#039;) == 4) {&lt;br /&gt;
            // This is the end of the trick&lt;br /&gt;
            $cards_on_table = $this-&amp;gt;cards-&amp;gt;getCardsInLocation(&#039;cardsontable&#039;);&lt;br /&gt;
            $best_value = 0;&lt;br /&gt;
            $best_value_player_id = null;&lt;br /&gt;
            $currentTrickColor = self::getGameStateValue(&#039;trickColor&#039;);&lt;br /&gt;
            foreach ( $cards_on_table as $card ) {&lt;br /&gt;
                // Note: type = card color&lt;br /&gt;
                if ($card [&#039;type&#039;] == $currentTrickColor) {&lt;br /&gt;
                    if ($best_value_player_id === null || $card [&#039;type_arg&#039;] &amp;gt; $best_value) {&lt;br /&gt;
                        $best_value_player_id = $card [&#039;location_arg&#039;]; // Note: location_arg = player who played this card on table&lt;br /&gt;
                        $best_value = $card [&#039;type_arg&#039;]; // Note: type_arg = value of the card&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            // Active this player =&amp;gt; he&#039;s the one who starts the next trick&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer( $best_value_player_id );&lt;br /&gt;
            &lt;br /&gt;
            // Move all cards to &amp;quot;cardswon&amp;quot; of the given player&lt;br /&gt;
            $this-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
        &lt;br /&gt;
            // Notify&lt;br /&gt;
            // ... same code here as before&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The scoring rule in the studio example code is huge multi-page function, for this tutorial we will make simplier.&lt;br /&gt;
Lets score -1 point per heart and call it a day. And game will end when somebody goes -100 or below.&lt;br /&gt;
&lt;br /&gt;
As UI goes for scoring, the main thing to update is the scoring on the mini boards represented by stars, also&lt;br /&gt;
we want to show that in the log. &lt;br /&gt;
In addition scoring can be shown in [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialog]] using tableWindow notification, but it is a tutorial on its own and you can do it as homework (it is part of original heart game).&lt;br /&gt;
&lt;br /&gt;
In .js file we need to add one more subscription and notification handler:&lt;br /&gt;
            dojo.subscribe( &#039;newScores&#039;, this, &amp;quot;notif_newScores&amp;quot; );&lt;br /&gt;
in setupNotifications&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
        notif_newScores : function(notif) {&lt;br /&gt;
            // Update players&#039; scores&lt;br /&gt;
            for ( var player_id in notif.args.newScores) {&lt;br /&gt;
                this.scoreCtrl[player_id].toValue(notif.args.newScores[player_id]);&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
somewhere after. this.scoreCtrl is pre-existing object that shows the scoring and this function will update score values per player from notification argument&lt;br /&gt;
&lt;br /&gt;
so in .game.php our stEndHand function will look like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stEndHand() {&lt;br /&gt;
            // Count and score points, then end the game or go to the next hand.&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        // Gets all &amp;quot;hearts&amp;quot; + queen of spades&lt;br /&gt;
&lt;br /&gt;
        $player_to_points = array ();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player ) {&lt;br /&gt;
            $player_to_points [$player_id] = 0;&lt;br /&gt;
        }&lt;br /&gt;
        $cards = $this-&amp;gt;cards-&amp;gt;getCardsInLocation(&amp;quot;cardswon&amp;quot;);&lt;br /&gt;
        foreach ( $cards as $card ) {&lt;br /&gt;
            $player_id = $card [&#039;location_arg&#039;];&lt;br /&gt;
            // Note: 2 = heart&lt;br /&gt;
            if ($card [&#039;type&#039;] == 2) {&lt;br /&gt;
                $player_to_points [$player_id] ++;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        // Apply scores to player&lt;br /&gt;
        foreach ( $player_to_points as $player_id =&amp;gt; $points ) {&lt;br /&gt;
            if ($points != 0) {&lt;br /&gt;
                $sql = &amp;quot;UPDATE player SET player_score=player_score-$points  WHERE player_id=&#039;$player_id&#039;&amp;quot;;&lt;br /&gt;
                self::DbQuery($sql);&lt;br /&gt;
                $heart_number = $player_to_points [$player_id];&lt;br /&gt;
                self::notifyAllPlayers(&amp;quot;points&amp;quot;, clienttranslate(&#039;${player_name} gets ${nbr} hearts and looses ${nbr} points&#039;), array (&lt;br /&gt;
                        &#039;player_id&#039; =&amp;gt; $player_id,&#039;player_name&#039; =&amp;gt; $players [$player_id] [&#039;player_name&#039;],&lt;br /&gt;
                        &#039;nbr&#039; =&amp;gt; $heart_number ));&lt;br /&gt;
            } else {&lt;br /&gt;
                // No point lost (just notify)&lt;br /&gt;
                self::notifyAllPlayers(&amp;quot;points&amp;quot;, clienttranslate(&#039;${player_name} did not get any hearts&#039;), array (&lt;br /&gt;
                        &#039;player_id&#039; =&amp;gt; $player_id,&#039;player_name&#039; =&amp;gt; $players [$player_id] [&#039;player_name&#039;] ));&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        $newScores = self::getCollectionFromDb(&amp;quot;SELECT player_id, player_score FROM player&amp;quot;, true );&lt;br /&gt;
        self::notifyAllPlayers( &amp;quot;newScores&amp;quot;, &#039;&#039;, array( &#039;newScores&#039; =&amp;gt; $newScores ) );&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        foreach ( $newScores as $player_id =&amp;gt; $score ) {&lt;br /&gt;
            if ($score &amp;lt;= -100) {&lt;br /&gt;
                // Trigger the end of the game !&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;endGame&amp;quot;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;nextHand&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So it should more less work now, including end of game condition. Try to play it!&lt;br /&gt;
&lt;br /&gt;
== Additional stuff ==&lt;br /&gt;
&lt;br /&gt;
The following things were not implemented and can add them yourself by looking at the code of original hearts game:&lt;br /&gt;
&lt;br /&gt;
* Remove debug code from setupNewGame to deal cards, cards are now dealt in stNewHand state handler&lt;br /&gt;
* Rule checking and rule enforcements in playCard function&lt;br /&gt;
* Start scoring with 100 points each and end when &amp;lt;= 0&lt;br /&gt;
* Fix scoring rules with Q of spades and 26 point reverse scoring&lt;br /&gt;
* First player one with 2 club&lt;br /&gt;
* Add progress handling&lt;br /&gt;
* Add statistics&lt;br /&gt;
* Add card exchange states&lt;br /&gt;
* Add game option to start with 75 points instead of 100&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Xmakina</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Hearts_all_rows.png&amp;diff=18824</id>
		<title>File:Hearts all rows.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Hearts_all_rows.png&amp;diff=18824"/>
		<updated>2023-11-10T09:20:55Z</updated>

		<summary type="html">&lt;p&gt;Xmakina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Display a list of all players, with a dummy card in each position&lt;/div&gt;</summary>
		<author><name>Xmakina</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=File:Hearts_Tutorial_showing_all_players.png&amp;diff=18823</id>
		<title>File:Hearts Tutorial showing all players.png</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=File:Hearts_Tutorial_showing_all_players.png&amp;diff=18823"/>
		<updated>2023-11-10T09:19:03Z</updated>

		<summary type="html">&lt;p&gt;Xmakina: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Display a list of all players, with a dummy card in each position&lt;/div&gt;</summary>
		<author><name>Xmakina</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=18822</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=18822"/>
		<updated>2023-11-10T09:06:46Z</updated>

		<summary type="html">&lt;p&gt;Xmakina: /* Layout and Graphics */ Add hack removal&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Using this tutorial, you can build a complete working game on the BGA environment: Hearts.&lt;br /&gt;
&lt;br /&gt;
Before you read this tutorial, you must:&lt;br /&gt;
* Read the overall presentations of the BGA Framework ([[Studio|see here]]).&lt;br /&gt;
* Know the rules for Hearts&lt;br /&gt;
* Some-what know the languages used on BGA: PHP, SQL, HTML, CSS, Javascript&lt;br /&gt;
* Set up your development environment [http://en.doc.boardgamearena.com/First_steps_with_BGA_Studio First Steps with BGA Studio]&lt;br /&gt;
* As part of setup you have to have access to your ftp home folder in studio, which would have the full &#039;hearts&#039; game source code. We will be using some resources of this game in this tutorial, so copy it over to local disk if you have not done so.&lt;br /&gt;
&lt;br /&gt;
If you are stuck or have question about this tutorial, post on [https://forum.boardgamearena.com/viewforum.php?f=12 BGA Developers forum]&lt;br /&gt;
&lt;br /&gt;
== Create your first game ==&lt;br /&gt;
&lt;br /&gt;
If you have not already, you have to create a project in BGA Studio. For this tutorial you can create a project heartsYOURNAME where&lt;br /&gt;
YOURNAME is your developer login name. You can also re-use the project you have created for the &amp;quot;First Steps&amp;quot; tutorial above.&lt;br /&gt;
With the initial skeleton of code provided, you can already start a game from the BGA Studio. &lt;br /&gt;
&lt;br /&gt;
1. Find and express start the game in turn-based mode with 4 players. Make sure it works. If you want to see the game as 2nd player press red arrow button on the player panel to switch to that player. More details can be found in [[First_steps_with_BGA_Studio]]&lt;br /&gt;
&lt;br /&gt;
2. Modify the text in heartsYOURNAME_heartsYOURNAME.tpl, reload the page in the browser and make sure your ftp sync works as expected.&lt;br /&gt;
Note: if you have not setup auto-sync do it now, manually copying files is a no-starter.&lt;br /&gt;
&lt;br /&gt;
3. Express stop from settings menu (the gear icon).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Note: please do &#039;&#039;&#039;not&#039;&#039;&#039; use the hearts project code as a base. This tutorial assumes you started with a TEMPLATE project with no prior modifications. Using the hearts project as a base will be very confusing and you won&#039;t be able to follow all the steps.&lt;br /&gt;
&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Attention!!!&amp;lt;/b&amp;gt; Very important note about reloading, if you don&#039;t remember this you may spent hours debugging. Browser caches .css files and images. If you change any of these files you have to do &amp;quot;full reload&amp;quot; which is usually Ctrl+F5 (or Ctrl+reload button on browser) not just a regular reload.&lt;br /&gt;
&lt;br /&gt;
== Hook version control system ==&lt;br /&gt;
&lt;br /&gt;
For a real game, or even for this tutorial, we recommend committing the code to version control right from the start. You are going to find yourself in a situation where the game doesn&#039;t even start anymore and no way of debugging it, unless you have a way to revert. That is where version control becomes very handy. If you are not familiar with version control (e.g. [https://git-scm.com/docs/gittutorial git]) then at least back up your files after each major change. Start now.&lt;br /&gt;
&lt;br /&gt;
Code for this tutorial available is on github: https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
&lt;br /&gt;
Different revisions represent different steps along the process, starting from original template to a PARTIAL game. The full game can be found in your FTP home folder.&lt;br /&gt;
&lt;br /&gt;
== Update game infos and box graphics ==&lt;br /&gt;
&lt;br /&gt;
Even it does nothing yet, always start by making sure the game looks decent in the game selector, meaning it has nice box graphics and its information is correct. For that we need to edit [[Game_meta-information: gameinfos.inc.php|gameinfos.inc.php]].&lt;br /&gt;
&lt;br /&gt;
For a real game, you would go to [http://boardgamegeek.com BoardGameGeek], find the game, and use the information from BGG to fill in the gameinfos.&lt;br /&gt;
&lt;br /&gt;
So let&#039;s do that. Find &amp;quot;hearts&amp;quot; on BoardGameGeek. (Hint: Original release 1850 :))&lt;br /&gt;
&lt;br /&gt;
You can fill in the year of publishing and bgg id, put &#039;&#039;Public Domain&#039;&#039; under publisher (for a real game, leave an empty string so it won&#039;t be displayed), and a publisher id of 171 for public domain. And as designer and author you can just put your own name just for fun. Set number of players to 4.&lt;br /&gt;
&lt;br /&gt;
  // Players configuration that can be played (ex: 2 to 4 players)&lt;br /&gt;
  &#039;players&#039; =&amp;gt; array( 4 ),  &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important step&#039;&#039;&#039;: you have to refresh the information in the Studio website through the control panel. So go to Control Panel -&amp;gt; Manage Games -&amp;gt; heartsYOURNAME&lt;br /&gt;
and press Reload for &#039;Reload game informations&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The next step would be to replace &#039;&#039;&#039;game_box.png&#039;&#039;&#039; with nicer images. This can be done from the [[Game metadata manager]]. &lt;br /&gt;
&lt;br /&gt;
Now try to start the game again. If you somehow introduced a syntax error in the gameinfos file it may not work (the game won&#039;t start).&lt;br /&gt;
Always use the &amp;quot;Express Start&amp;quot; button to start the game. You should see a standard state prompt from the template. You should see 4 players on the right: testdude0 .. testdude3.&lt;br /&gt;
To switch between them press the red arrow button near their names, it will open another tab. This way you don&#039;t need to login and logout from multiple accounts!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Note: if you had run the game before with less than 4 players there is a bug that will prevent you from running it with 4 only (if you did not run it before or run it with 4 players as instructed stop reading this note), to workaround revert back to original players array (i.e. 1,2,3,4), reload game options, then create a table with 4 players, exit that game table, then change gameoptions to 4 only as above, reload game options, create table again.&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Code Rev [https://github.com/elaskavaia/bga-heartsla/tree/4b3a73eeb5acae961ade18473af119e8ce8d1a8f]&lt;br /&gt;
&lt;br /&gt;
== Layout and Graphics ==&lt;br /&gt;
&lt;br /&gt;
In this section we will do graphics of the game, and main layout of the game.&lt;br /&gt;
&lt;br /&gt;
First copy a sprite with cards image from [https://github.com/elaskavaia/bga-heartsla/blob/4b3a73eeb5acae961ade18473af119e8ce8d1a8f/img/cards.jpg hearts img/cards.jpg]  into img/ folder of your project. Project hearts is mounted to your home directory on bga server.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;There are better quality deck of cards image at https://en.doc.boardgamearena.com/Common_board_game_elements_image_resources&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Details about images can be found here: [[Game art: img directory]].&lt;br /&gt;
&lt;br /&gt;
Edit .tpl to add some divs to represent player table and hand area&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;myhand_wrap&amp;quot; class=&amp;quot;whiteblock&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3&amp;gt;My Hand&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-tpl2.png]]&lt;br /&gt;
&lt;br /&gt;
Now lets add a card into the hand, just so you can feel it. Edit .tpl and a playertablecard div inside a hand div&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
       &amp;lt;div class=&amp;quot;playertablecard&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit .css file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.playertablecard {&lt;br /&gt;
    display: inline-block;&lt;br /&gt;
    position: relative;&lt;br /&gt;
    margin-top: 5px;&lt;br /&gt;
    width: 72px;&lt;br /&gt;
    height: 96px;&lt;br /&gt;
    background-image: url(&#039;img/cards.jpg&#039;); /* temp hack to see it */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you edit CSS remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&lt;br /&gt;
&amp;lt;i&amp;gt;Same when you change existing graphics files&amp;lt;/i&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You should see this:&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-tpl3.png]]&lt;br /&gt;
&lt;br /&gt;
Awesome! Now lets do the rest of layout.&lt;br /&gt;
&lt;br /&gt;
First, remove &amp;lt;code&amp;gt;background-image&amp;lt;/code&amp;gt; from &amp;lt;code&amp;gt;.playertablecard&amp;lt;/code&amp;gt;. That was a temporary fix that we don&#039;t need any more.&lt;br /&gt;
&lt;br /&gt;
There are few ways of how html could have been generated, you could have start with nothing and generate&lt;br /&gt;
all by java script. Or you could have started with complete game markup in html and make java script just hide and move pieces around. BGA framework provides also a third way which is mix of both plus template engine to generate HTML using php. So lets do that.&lt;br /&gt;
&lt;br /&gt;
Change .tpl file to have this inside&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;playertables&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- BEGIN player --&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_{DIR}&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; style=&amp;quot;color:#{PLAYER_COLOR}&amp;quot;&amp;gt;&lt;br /&gt;
            {PLAYER_NAME}&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablecard&amp;quot; id=&amp;quot;playertablecard_{PLAYER_ID}&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;!-- END player --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;myhand_wrap&amp;quot; class=&amp;quot;whiteblock&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3&amp;gt;{MY_HAND}&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What we did is we added &amp;quot;block&amp;quot; player, it is marked up using html comments. {VAR} notation is used&lt;br /&gt;
to inject variables and &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;!-- BEGIN xxx --&amp;gt; &lt;br /&gt;
   inside &lt;br /&gt;
  &amp;lt;!-- END xxx --&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
effectively allows us to do template loops.&lt;br /&gt;
&lt;br /&gt;
In .view.php insert this code after &#039;Place your code below&#039; comment&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $template = self::getGameName() . &amp;quot;_&amp;quot; . self::getGameName();&lt;br /&gt;
        &lt;br /&gt;
        $directions = array( &#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039; );&lt;br /&gt;
        &lt;br /&gt;
        // this will inflate our player block with actual players data&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;begin_block($template, &amp;quot;player&amp;quot;);&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $info ) {&lt;br /&gt;
            $dir = array_shift($directions);&lt;br /&gt;
            $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player&amp;quot;, array (&amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id,&lt;br /&gt;
                    &amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $players [$player_id] [&#039;player_name&#039;],&lt;br /&gt;
                    &amp;quot;PLAYER_COLOR&amp;quot; =&amp;gt; $players [$player_id] [&#039;player_color&#039;],&lt;br /&gt;
                    &amp;quot;DIR&amp;quot; =&amp;gt; $dir ));&lt;br /&gt;
        }&lt;br /&gt;
        // this will make our My Hand text translatable&lt;br /&gt;
        $this-&amp;gt;tpl[&#039;MY_HAND&#039;] = self::_(&amp;quot;My hand&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What it does is for each player we have it will replicate the html between &amp;lt;!-- BEGIN player --&amp;gt; and &amp;lt;!-- END player --&amp;gt; tags, substituting the variable denoted by {XXX}&lt;br /&gt;
with the values you provide. The DIR variable in this case we pulling from directions array (where array_shift will take first element and remove it from the array).&lt;br /&gt;
&lt;br /&gt;
Reload. If everything went well you should see this:&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-tpl4.png]]&lt;br /&gt;
&lt;br /&gt;
These are &amp;quot;tableau&amp;quot; areas for 4 players plus My hand visible only to one player.&lt;br /&gt;
They are not exactly how we wanted them to be because we did not edit .css yet.&lt;br /&gt;
&lt;br /&gt;
Now edit .css, add these lines after import before our previous definition&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** Table layout **/&lt;br /&gt;
&lt;br /&gt;
#playertables {&lt;br /&gt;
    position: relative;&lt;br /&gt;
    width: 710px;&lt;br /&gt;
    height: 340px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.playertablename {&lt;br /&gt;
    font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.playertable {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    text-align: center;&lt;br /&gt;
    width: 180px;&lt;br /&gt;
    height: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.playertable_N {&lt;br /&gt;
    left: 50%;&lt;br /&gt;
    top: 0px;&lt;br /&gt;
    margin-left: -90px; /* half of 180 */&lt;br /&gt;
}&lt;br /&gt;
.playertable_S {&lt;br /&gt;
    left: 50%;&lt;br /&gt;
    bottom: 0px;&lt;br /&gt;
    margin-left: -90px; /* half of 180 */&lt;br /&gt;
}&lt;br /&gt;
.playertable_W {&lt;br /&gt;
    left: 0px;&lt;br /&gt;
    top: 50%;&lt;br /&gt;
    margin-top: -55px; /* half of 130 */&lt;br /&gt;
}&lt;br /&gt;
.playertable_E {&lt;br /&gt;
    right: 0px;&lt;br /&gt;
    top: 50%;&lt;br /&gt;
    margin-top: -55px; /* half of 130 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now you force Reload and you should see this:&lt;br /&gt;
[[File:Heartsla-tpl5.png]]&lt;br /&gt;
&lt;br /&gt;
This is almost all we need for graphics and layout, there are few tweaks left there but lets do some more heavy lifting now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Note: if you did not see changes you may have not force reloaded, force means you use Ctrl+F5 or Cltr+Shift-R, if you don&#039;t &amp;quot;force&amp;quot; browser will use cached version of .css and images! Which is not what you just changed&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Another Note: In general if you have auto-sync you don&#039;t need to reload if you change game.php file, you need normal reload if you change js, and force reload for css and images. If you changed state machine or database you likely need to restart the game.&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Game Interface JS Stock ==&lt;br /&gt;
&lt;br /&gt;
The BGA framework provides a few out of the box classes to deal with cards. The client side&lt;br /&gt;
contains a class called [[Stock]] and it can be used for any dynamic html &amp;quot;pieces&amp;quot; management that uses&lt;br /&gt;
common sprite images. On the server side we will use the [[Deck]] class which we discuss later.&lt;br /&gt;
&lt;br /&gt;
If you open cards.jpg in an image viewer you will see that it is a &amp;quot;sprite&amp;quot; image - a 13x4 grid of images stitched together,&lt;br /&gt;
which is a very efficient way to transport images. So we will use the Stock class to mark up these images and create&lt;br /&gt;
&amp;quot;card&amp;quot; divs for us.&lt;br /&gt;
&lt;br /&gt;
First, we need to add &#039;&#039;&#039;ebg/stock&#039;&#039;&#039; as a dependency in the hearts.js file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;     /// &amp;lt;==== HERE&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then add this to the Javascript constructor, this will define size of our cards&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            console.log(&#039;hearts constructor&#039;);&lt;br /&gt;
            this.cardwidth = 72;&lt;br /&gt;
            this.cardheight = 96;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The stock is initialized in the Javascript &amp;quot;setup&amp;quot; method like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // TODO: Set up your game interface here, according to &amp;quot;gamedatas&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    // Player hand&lt;br /&gt;
    this.playerHand = new ebg.stock(); // new stock object for hand&lt;br /&gt;
    this.playerHand.create( this, $(&#039;myhand&#039;), this.cardwidth, this.cardheight );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As parameters of the &amp;quot;create&amp;quot; method, we provided the width/height of an item (a card), and the container div &amp;quot;myhand&amp;quot; - which is an id of &amp;quot;div&amp;quot; element from our .tpl file representing a player hand.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then, we must tell the stock what items it is going to display during its life: the 52 cards of a standard card game from a CSS sprite image named &amp;quot;cards.jpg&amp;quot; with all the cards arranged in 4 rows and 13 columns.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we tell stock what item types to display:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            this.playerHand.image_items_per_row = 13; // 13 images per row&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
            // Create cards types:&lt;br /&gt;
            for (var color = 1; color &amp;lt;= 4; color++) {&lt;br /&gt;
                for (var value = 2; value &amp;lt;= 14; value++) {&lt;br /&gt;
                    // Build card type id&lt;br /&gt;
                    var card_type_id = this.getCardUniqueId(color, value);&lt;br /&gt;
                    this.playerHand.addItemType(card_type_id, card_type_id, g_gamethemeurl + &#039;img/cards.jpg&#039;, card_type_id);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And add this function to the utilities section&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Get card unique identifier based on its color and value&lt;br /&gt;
        getCardUniqueId : function(color, value) {&lt;br /&gt;
            return (color - 1) * 13 + (value - 2);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanations:&lt;br /&gt;
* At first, we tell the stock component that our CSS sprite contains 13 items per row. This way, it can find the correct image for each card type id.&lt;br /&gt;
* Then for the 4x13 cards, we call the &#039;&#039;&#039;addItemType&#039;&#039;&#039; method that creates the type. The arguments are the type id, the weight of the card (for sorting purpose), the URL of our CSS sprite, and the position of our card image in the CSS sprite. It happens to be the same number in our case.&lt;br /&gt;
&lt;br /&gt;
Note: we need to generate a unique ID for each type of card based on its color and value.  For that we create a function &#039;&#039;&#039;getCardUniqueId&#039;&#039;&#039;. The type is the unique identifier of the TYPE of the card, e.g., the queen of spades encoded as an integer. If our deck had 2 standard card decks we would have had 2 queens of spades; they would share the same type and the same image but would have different ids. NOTE: It&#039;s unfortunate that they named this &#039;&#039;&#039;getCardUniqueId&#039;&#039;&#039;; it should have been &#039;&#039;&#039;getCardUniqueType&#039;&#039;&#039;, because it really isn&#039;t an id, but a TYPE of card. The type of the item should either be a reversible function of its properties (i.e., kind of suite * 13 + value) or just an enumerator described in material.inc.php. In this specific case it&#039;s a synthetic type id, which also the same as the number of the card in the sprite image (i.e., if you enumerate each image in sprite going left to right, then top to bottom).&lt;br /&gt;
&lt;br /&gt;
Now let&#039;s add the 5 of Hearts to the player&#039;s hand just for fun (this code will go in setup method after types initialization):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// 2 = hearts, 5 is 5, and 42 is the card id, which normally would come from db&lt;br /&gt;
this.playerHand.addToStockWithId( this.getCardUniqueId( 2, 5 ), 42 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will add the card with id 42 and type 16 ( (2-1)*13+(5-2)=16 ). &lt;br /&gt;
&lt;br /&gt;
Note that number 16 would not be something you can see in database, Deck database will have separate field for type and type_arg where type is suite and type_arg is number, so its not the same thing, but you can use same formula to convert. Number 42 on the other hand would be id field in database. But we get to database in the later section.&lt;br /&gt;
&lt;br /&gt;
If you reload now you should see the 5 of hearts in &amp;quot;your hand&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Stock control can handle clicking on items and forms the selection. You can immediately react to selection&lt;br /&gt;
or you can query it later; for example when user presses some other button.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s hook it up. Add this in the setup method in .js file, after this.playerHand is initialised:&lt;br /&gt;
&lt;br /&gt;
     dojo.connect( this.playerHand, &#039;onChangeSelection&#039;, this, &#039;onPlayerHandSelectionChanged&#039; );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then find the Player&#039;s action comment section in .js file and add a handler after the comment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onPlayerHandSelectionChanged: function() {&lt;br /&gt;
            var items = this.playerHand.getSelectedItems();&lt;br /&gt;
&lt;br /&gt;
            if (items.length &amp;gt; 0) {&lt;br /&gt;
                if (this.checkAction(&#039;playCard&#039;, true)) {&lt;br /&gt;
                    // Can play a card&lt;br /&gt;
&lt;br /&gt;
                    var card_id = items[0].id;&lt;br /&gt;
                    console.log(&amp;quot;on playCard &amp;quot;+card_id);&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;giveCards&#039;)) {&lt;br /&gt;
                    // Can give cards =&amp;gt; let the player select some cards&lt;br /&gt;
                } else {&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The function name of the handler is 4th parameter of the dojo.connect function. Make sure you spell it correctly or there will be unpredictable effects.&lt;br /&gt;
&lt;br /&gt;
Now if you reload, open the Javascript Console (F12), and then click on the card in My Hand, you should see:&lt;br /&gt;
  on playCard 42&lt;br /&gt;
printed on the console&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note : You need to be the active player to have rights to play a card and so log your message in the console&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Game Database and Game Initialisation ==&lt;br /&gt;
&lt;br /&gt;
Next step, you want to design a game database and setup a new game (on the server side).&lt;br /&gt;
For that we need to a) modify the database schema to add our cards data b) add some global variables into&lt;br /&gt;
the existing globals table.&lt;br /&gt;
&lt;br /&gt;
To modify the schema, first exit your existing game(s). Open &#039;&#039;&#039;dbmodel.sql&#039;&#039;&#039; file and uncomment the card table creation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the &amp;quot;card&amp;quot; table which will be managed by the Deck php class.&lt;br /&gt;
&lt;br /&gt;
In addition we want a little piece of information in the players table:&lt;br /&gt;
&lt;br /&gt;
  -- add info about first player&lt;br /&gt;
  ALTER TABLE `player` ADD `player_first` BOOLEAN NOT NULL DEFAULT &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
Not sure why they put this into the player table, as we could use a global db variable to hold first player as easily.&lt;br /&gt;
But I am just following the existing code more-or-less.&lt;br /&gt;
&lt;br /&gt;
Next we finally get into .game.php class, where the main logic and db interaction would be. Find php constructor which should be &lt;br /&gt;
  function __construct( )&lt;br /&gt;
This is first function in a file. Add this code to constructor.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        self::initGameStateLabels( array( &lt;br /&gt;
                         &amp;quot;currentHandType&amp;quot; =&amp;gt; 10, &lt;br /&gt;
                         &amp;quot;trickColor&amp;quot; =&amp;gt; 11, &lt;br /&gt;
                         &amp;quot;alreadyPlayedHearts&amp;quot; =&amp;gt; 12,&lt;br /&gt;
                          ) );&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;cards = self::getNew( &amp;quot;module.common.deck&amp;quot; );&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;init( &amp;quot;card&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we are initializing three &amp;quot;Game State Variables&amp;quot; which are variables stored in the database. They are integers.&lt;br /&gt;
It must start with values higher or equal to 10 since values lower than 10 are reserved. These values are stored by numeric ids&lt;br /&gt;
in the database, but in the php we associate them with string labels for convenience of access. The variables are &amp;quot;trickColor&amp;quot;: numbers from 1 to 4 that map to card suit (not sure why it&#039;s called color; maybe it&#039;s a translation from French); &amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick; &amp;quot;currentHandType&amp;quot;: stores the value to indicate who to give cards to during exchange.&lt;br /&gt;
&lt;br /&gt;
The next 2 lines are creating $this-&amp;gt;cards object and associating it with &amp;quot;card&amp;quot; table in the the database.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;If we called db table &#039;foo&#039; instead of &#039;card&#039; the last statement would have been  $this-&amp;gt;cards-&amp;gt;init( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point I would start a new game and make sure it starts, then exit. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;&lt;br /&gt;
If you made a mistake&lt;br /&gt;
in the .sql or php constructor the game won&#039;t start, and good luck debugging it. (That is why it&#039;s important to check&lt;br /&gt;
once in a while to make sure it still starts while you remember what you have changed.)&lt;br /&gt;
&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Code Rev [https://github.com/elaskavaia/bga-heartsla/tree/e3a049257b592ff6167688d4d344f8a83d349b08]&lt;br /&gt;
&lt;br /&gt;
Now we can go to game initialization &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; in game.php. This method is called only once when the game is created.&lt;br /&gt;
&lt;br /&gt;
In your template project you should have code that deals with player table, just leave it as is. Start inserting the&lt;br /&gt;
other code after &amp;quot;Start the game initialization&amp;quot; comment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Init global values with their initial values&lt;br /&gt;
&lt;br /&gt;
        // Note: hand types: 0 = give 3 cards to player on the left&lt;br /&gt;
        //                   1 = give 3 cards to player on the right&lt;br /&gt;
        //                   2 = give 3 cards to player opposite&lt;br /&gt;
        //                   3 = keep cards&lt;br /&gt;
        self::setGameStateInitialValue( &#039;currentHandType&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Set current trick color to zero (= no trick color)&lt;br /&gt;
        self::setGameStateInitialValue( &#039;trickColor&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Mark if we already played hearts during this hand&lt;br /&gt;
        self::setGameStateInitialValue( &#039;alreadyPlayedHearts&#039;, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we initialize all the globals to 0.&lt;br /&gt;
&lt;br /&gt;
Next is to create our cards in the database. We have one deck of cards so it&#039;s pretty simple.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Create cards&lt;br /&gt;
        $cards = array ();&lt;br /&gt;
        foreach ( $this-&amp;gt;colors as $color_id =&amp;gt; $color ) {&lt;br /&gt;
            // spade, heart, diamond, club&lt;br /&gt;
            for ($value = 2; $value &amp;lt;= 14; $value ++) {&lt;br /&gt;
                //  2, 3, 4, ... K, A&lt;br /&gt;
                $cards [] = array (&#039;type&#039; =&amp;gt; $color_id,&#039;type_arg&#039; =&amp;gt; $value,&#039;nbr&#039; =&amp;gt; 1 );&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;createCards( $cards, &#039;deck&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code that will create one of each card. But don&#039;t run it yet, because we missing $this-&amp;gt;colors.&lt;br /&gt;
So we have state of the game in the database, but there is some static game information which never changes.&lt;br /&gt;
This information should be stored in material.inc.php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
We will edit this file now by adding these lines&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;colors = array(&lt;br /&gt;
    1 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;spade&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;spade&#039;) ),&lt;br /&gt;
    2 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;heart&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;heart&#039;) ),&lt;br /&gt;
    3 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;club&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;club&#039;) ),&lt;br /&gt;
    4 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;diamond&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;diamond&#039;) )&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
$this-&amp;gt;values_label = array(&lt;br /&gt;
    2 =&amp;gt;&#039;2&#039;,&lt;br /&gt;
    3 =&amp;gt; &#039;3&#039;,&lt;br /&gt;
    4 =&amp;gt; &#039;4&#039;,&lt;br /&gt;
    5 =&amp;gt; &#039;5&#039;,&lt;br /&gt;
    6 =&amp;gt; &#039;6&#039;,&lt;br /&gt;
    7 =&amp;gt; &#039;7&#039;,&lt;br /&gt;
    8 =&amp;gt; &#039;8&#039;,&lt;br /&gt;
    9 =&amp;gt; &#039;9&#039;,&lt;br /&gt;
    10 =&amp;gt; &#039;10&#039;,&lt;br /&gt;
    11 =&amp;gt; clienttranslate(&#039;J&#039;),&lt;br /&gt;
    12 =&amp;gt; clienttranslate(&#039;Q&#039;),&lt;br /&gt;
    13 =&amp;gt; clienttranslate(&#039;K&#039;),&lt;br /&gt;
    14 =&amp;gt; clienttranslate(&#039;A&#039;)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where $this-&amp;gt;colors will define Suit labels and $this-&amp;gt;values_label will define value labels.&lt;br /&gt;
If you noticed, we have two of each label for suits. This is because sometimes we need translated values on the php&lt;br /&gt;
side and sometimes we don&#039;t. In this case &#039;&#039;&#039;nametr&#039;&#039;&#039; will return a translated value in php, which is only useful when you throw exceptions to show the right strings. If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. &#039;clienttranslate&#039; marks the value for translation but does not actually change it for php. For more about this wonderful translation stuff see [[Translations]].&lt;br /&gt;
&lt;br /&gt;
== Full game model synchronisation ==&lt;br /&gt;
&lt;br /&gt;
Now at any point in the game we need to make sure that database information can be reflected back in the UI, so we must fix the &#039;&#039;&#039;getAllDatas&#039;&#039;&#039; function&lt;br /&gt;
to return all possible data we need to reconstruct the game. This is in the game.php file. The template for getAllDatas() already takes care of player info. Let&#039;s just&lt;br /&gt;
add hand and tableau data before we return a result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Cards in player hand&lt;br /&gt;
        $result[&#039;hand&#039;] = $this-&amp;gt;cards-&amp;gt;getCardsInLocation( &#039;hand&#039;, $current_player_id );&lt;br /&gt;
        &lt;br /&gt;
        // Cards played on the table&lt;br /&gt;
        $result[&#039;cardsontable&#039;] = $this-&amp;gt;cards-&amp;gt;getCardsInLocation( &#039;cardsontable&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now on the client side we should display this data, so in your .js file in the setup function (which is the receiver of getAllDatas) replace our hack of putting 5 of Hearts directly into the hand with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Cards in player&#039;s hand&lt;br /&gt;
            for ( var i in this.gamedatas.hand) {&lt;br /&gt;
                var card = this.gamedatas.hand[i];&lt;br /&gt;
                var color = card.type;&lt;br /&gt;
                var value = card.type_arg;&lt;br /&gt;
                this.playerHand.addToStockWithId(this.getCardUniqueId(color, value), card.id);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Cards played on table&lt;br /&gt;
            for (i in this.gamedatas.cardsontable) {&lt;br /&gt;
                var card = this.gamedatas.cardsontable[i];&lt;br /&gt;
                var color = card.type;&lt;br /&gt;
                var value = card.type_arg;&lt;br /&gt;
                var player_id = card.location_arg;&lt;br /&gt;
                this.playCardOnTable(player_id, color, value, card.id);&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This should show hand and tableau cards now, except we are missing the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function. So find the &#039;&#039;&#039;getCardUniqueId&#039;&#039;&#039; function which&lt;br /&gt;
should be in the utilities section and add this after it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        playCardOnTable : function(player_id, color, value, card_id) {&lt;br /&gt;
            // player_id =&amp;gt; direction&lt;br /&gt;
            dojo.place(this.format_block(&#039;jstpl_cardontable&#039;, {&lt;br /&gt;
                x : this.cardwidth * (value - 2),&lt;br /&gt;
                y : this.cardheight * (color - 1),&lt;br /&gt;
                player_id : player_id&lt;br /&gt;
            }), &#039;playertablecard_&#039; + player_id);&lt;br /&gt;
&lt;br /&gt;
            if (player_id != this.player_id) {&lt;br /&gt;
                // Some opponent played a card&lt;br /&gt;
                // Move card from player panel&lt;br /&gt;
                this.placeOnObject(&#039;cardontable_&#039; + player_id, &#039;overall_player_board_&#039; + player_id);&lt;br /&gt;
            } else {&lt;br /&gt;
                // You played a card. If it exists in your hand, move card from there and remove&lt;br /&gt;
                // corresponding item&lt;br /&gt;
&lt;br /&gt;
                if ($(&#039;myhand_item_&#039; + card_id)) {&lt;br /&gt;
                    this.placeOnObject(&#039;cardontable_&#039; + player_id, &#039;myhand_item_&#039; + card_id);&lt;br /&gt;
                    this.playerHand.removeFromStockById(card_id);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // In any case: move it to its final destination&lt;br /&gt;
            this.slideToObject(&#039;cardontable_&#039; + player_id, &#039;playertablecard_&#039; + player_id).play();&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work we also need to add a card template in the .tpl file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Javascript HTML templates&lt;br /&gt;
&lt;br /&gt;
var jstpl_cardontable = &#039;&amp;lt;div class=&amp;quot;cardontable&amp;quot; id=&amp;quot;cardontable_${player_id}&amp;quot; style=&amp;quot;background-position:-${x}px -${y}px&amp;quot;&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;
&lt;br /&gt;
What this does is basically create another card object, because if it is not our card it&#039;s not in our hand (Stock) so&lt;br /&gt;
we have to create it out of thin air. The technique to do that is to implement a Javascript template object defined in the .tpl file with some&lt;br /&gt;
parameters, which will basically create a &amp;quot;div&amp;quot; string (yes you could have used string concatenation but it would not be fancy).&lt;br /&gt;
Now dojo.place places it (the div) on top of a placeholder. Now we have an object with an id of &#039;cardontable_&#039; + player_id. Depending&lt;br /&gt;
on who is playing it we either place it on the player miniboard or in hand (and remove it from hand stock). Then we animate the card move.&lt;br /&gt;
&lt;br /&gt;
We also should fix our .css file now to add style for cardontable and REMOVE background for playertablecard which really is a placeholder div and not a card. (Don&#039;t miss the remove step; it will be all screwy if you do!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.playertablecard {&lt;br /&gt;
    display: inline-block;&lt;br /&gt;
    position: relative;&lt;br /&gt;
    margin-top: 5px;&lt;br /&gt;
    width: 72px;&lt;br /&gt;
    height: 96px;&lt;br /&gt;
    /* we remove background-image here */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*** cards on table ***/&lt;br /&gt;
&lt;br /&gt;
.cardontable {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    width: 72px;&lt;br /&gt;
    height: 96px;&lt;br /&gt;
    background-image: url(&#039;img/cards.jpg&#039;); &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now to test that it actually works let&#039;s deal cards to players during game initialization:&lt;br /&gt;
&lt;br /&gt;
Add this after createCards in setupNewGame function in the game.php file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Shuffle deck&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;shuffle(&#039;deck&#039;);&lt;br /&gt;
        // Deal 13 cards to each players&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player ) {&lt;br /&gt;
            $cards = $this-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
        } &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now when you start the game you should see 13 cards in your hand!&lt;br /&gt;
&lt;br /&gt;
We just need to hook-up clicking on card and test if our playCardOnTable works.&lt;br /&gt;
&lt;br /&gt;
Find onPlayerHandSelectionChanged function in the JS file, we should have logging there like  console.log(&amp;quot;on playCard &amp;quot;+card_id);&lt;br /&gt;
So after that insert this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                    console.log(&amp;quot;on playCard &amp;quot;+card_id);&lt;br /&gt;
                    // type is (color - 1) * 13 + (value - 2)&lt;br /&gt;
                    var type = items[0].type;&lt;br /&gt;
                    var color = Math.floor(type / 13) + 1;&lt;br /&gt;
                    var value = type % 13 + 2;&lt;br /&gt;
                    &lt;br /&gt;
                    this.playCardOnTable(this.player_id,color,value,card_id);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: this code is for testing we will replace it with server interaction after we test it.&lt;br /&gt;
&lt;br /&gt;
Now if you force reload (because we changed .css before) you should be able to click on card from your hand and see it moving,&lt;br /&gt;
you can click on few cards this way. When you done enjoying the animation, press F5 to get your hand back.&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-sync.png]]&lt;br /&gt;
&lt;br /&gt;
Code Rev [https://github.com/elaskavaia/bga-heartsla/tree/01d4e2f595fd14c2adcc97a957d21bb2766f78a8]&lt;br /&gt;
&lt;br /&gt;
== State Machine ==&lt;br /&gt;
&lt;br /&gt;
Now we need to create a game state machine. So the states are:&lt;br /&gt;
&lt;br /&gt;
* Cards are dealt to all players (lets call it &amp;quot;newHand&amp;quot;)&lt;br /&gt;
* Player is selected who will start a new trick (&amp;quot;newTrick&amp;quot;)&lt;br /&gt;
* Player start or respond to played card (&amp;quot;playerTurn&amp;quot;)&lt;br /&gt;
* Game control is passed to next player or trick is ended (&amp;quot;nextPlayer&amp;quot;)&lt;br /&gt;
* End of hand processing (scoring and check for end of game) (&amp;quot;nextHand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
In addition players can exchange cards so we need two more states for that but we will skip it for now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The state handling spread across 4 files, so you have to make sure all pieces are connected together.&lt;br /&gt;
The state machine states.php defines all the states, and function handlers on php side in a form of string,&lt;br /&gt;
and if any of these functions are not implemented it would be very hard to debug because it will break in random places.&lt;br /&gt;
&lt;br /&gt;
So .states.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
    // The initial state. Please do not modify.&lt;br /&gt;
    1 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Game setup&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    /// New hand&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;newHand&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stNewHand&amp;quot;,&lt;br /&gt;
        &amp;quot;updateGameProgression&amp;quot; =&amp;gt; true,   &lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 30 )&lt;br /&gt;
    ),    &lt;br /&gt;
&lt;br /&gt;
    21 =&amp;gt; array(       &lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;giveCards&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Some players must choose 3 cards to give to ${direction}&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must choose 3 cards to give to ${direction}&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;multipleactiveplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGiveCards&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argGiveCards&amp;quot;,&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;giveCards&amp;quot; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;giveCards&amp;quot; =&amp;gt; 22, &amp;quot;skip&amp;quot; =&amp;gt; 22 )        &lt;br /&gt;
    ), &lt;br /&gt;
    &lt;br /&gt;
    22 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;takeCards&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stTakeCards&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;startHand&amp;quot; =&amp;gt; 30, &amp;quot;skip&amp;quot; =&amp;gt; 30  )&lt;br /&gt;
    ),        &lt;br /&gt;
      &lt;br /&gt;
    &lt;br /&gt;
    // Trick&lt;br /&gt;
    &lt;br /&gt;
    30 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;newTrick&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stNewTrick&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 31 )&lt;br /&gt;
    ),       &lt;br /&gt;
    31 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a card&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; =&amp;gt; 32 )&lt;br /&gt;
    ), &lt;br /&gt;
    32 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;nextPlayer&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stNextPlayer&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextPlayer&amp;quot; =&amp;gt; 31, &amp;quot;nextTrick&amp;quot; =&amp;gt; 30, &amp;quot;endHand&amp;quot; =&amp;gt; 40 )&lt;br /&gt;
    ), &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    // End of the hand (scoring, etc...)&lt;br /&gt;
    40 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;endHand&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stEndHand&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextHand&amp;quot; =&amp;gt; 2, &amp;quot;endGame&amp;quot; =&amp;gt; 99 )&lt;br /&gt;
    ),     &lt;br /&gt;
   &lt;br /&gt;
    // Final state.&lt;br /&gt;
    // Please do not modify.&lt;br /&gt;
    99 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameEnd&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;End of game&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameEnd&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argGameEnd&amp;quot;&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The full details on these fields are in [[Your_game_state_machine:_states.inc.php]].&lt;br /&gt;
&lt;br /&gt;
But basically we have Player states, in which a human player has to perform an &amp;quot;action&amp;quot; by pressing some button in the UI or selecting some game item, which will trigger js handler, which will do an ajax call to the server into API defined&lt;br /&gt;
by .action.php file. All functions in this file are API between client and server and have very simple&lt;br /&gt;
and repetitive structures. In this case there are only two actions player can do - play a card or pass cards to other player. So these 2 functions go into .action.php file, we will only define one now since we have not implemented card passing states yet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function playCard() {&lt;br /&gt;
        self::setAjaxMode();&lt;br /&gt;
        $card_id = self::getArg(&amp;quot;id&amp;quot;, AT_posint, true);&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;playCard($card_id);&lt;br /&gt;
        self::ajaxResponse();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make it run we have to define all the handler functions that we referenced in states, which are - one function for state arguments argGiveCards, 4 functions for robot states (where the game performs some action)&lt;br /&gt;
and 1 function for player actions handling.&lt;br /&gt;
In .game.php, find &#039;Game state arguments&#039; section and paste this in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argGiveCards() {&lt;br /&gt;
        return array ();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This normally passes some parameters to states, but we don&#039;t need anything yet. It&#039;s good to have a placeholder there anyway, so we can fix it later.&lt;br /&gt;
Important: even when it&#039;s a stub, this function must return an array not a scalar.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s do stubs for other functions, find the game state actions section in .game.php file and insert these&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stNewHand() {&lt;br /&gt;
        // Take back all cards (from any location =&amp;gt; null) to deck&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(null, &amp;quot;deck&amp;quot;);&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;shuffle(&#039;deck&#039;);&lt;br /&gt;
        // Deal 13 cards to each players&lt;br /&gt;
        // Create deck, shuffle it and give 13 initial cards&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player ) {&lt;br /&gt;
            $cards = $this-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
            // Notify player about his cards&lt;br /&gt;
            self::notifyPlayer($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        self::setGameStateValue(&#039;alreadyPlayedHearts&#039;, 0);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function stNewTrick() {&lt;br /&gt;
        // New trick: active the player who wins the last trick, or the player who own the club-2 card&lt;br /&gt;
        // Reset trick color to 0 (= no color)&lt;br /&gt;
        self::setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function stNextPlayer() {&lt;br /&gt;
        // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
        if ($this-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;cardsontable&#039;) == 4) {&lt;br /&gt;
            // This is the end of the trick&lt;br /&gt;
            // Move all cards to &amp;quot;cardswon&amp;quot; of the given player&lt;br /&gt;
            $best_value_player_id = self::activeNextPlayer(); // TODO figure out winner of trick&lt;br /&gt;
            $this-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
        &lt;br /&gt;
            if ($this-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;hand&#039;) == 0) {&lt;br /&gt;
                // End of the hand&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;endHand&amp;quot;);&lt;br /&gt;
            } else {&lt;br /&gt;
                // End of the trick&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;nextTrick&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            // Standard case (not the end of the trick)&lt;br /&gt;
            // =&amp;gt; just active the next player&lt;br /&gt;
            $player_id = self::activeNextPlayer();&lt;br /&gt;
            self::giveExtraTime($player_id);&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;nextPlayer&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function stEndHand() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;nextHand&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Important: All state actions game or player must end with state transition (or thrown exception). Also make sure it&#039;s ONLY one state transition,&lt;br /&gt;
if you accidentally fall through after state transition and do another one it will be a real mess and head scratching for long time.&lt;br /&gt;
&lt;br /&gt;
Now find &#039;player actions&#039; section and paste this code there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function playCard($card_id) {&lt;br /&gt;
        self::checkAction(&amp;quot;playCard&amp;quot;);&lt;br /&gt;
        $player_id = self::getActivePlayerId();&lt;br /&gt;
        throw new BgaUserException(self::_(&amp;quot;Not implemented: &amp;quot;) . &amp;quot;$player_id plays $card_id&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We won&#039;t implement it yet but throw an exception which we will see if interaction is working properly&lt;br /&gt;
&lt;br /&gt;
Now the game should start but it would not be any different than before because we have to implement actual interactions.&lt;br /&gt;
It&#039;s good to check if it&#039;s still working though (and if it was running before you have to exit because we changed state machine and normally it will break stuff)&lt;br /&gt;
&lt;br /&gt;
== Client - Server interactions ==&lt;br /&gt;
&lt;br /&gt;
Now to implement things for real we have hook UI actions to ajax calls, and process notifications sent by the server.&lt;br /&gt;
So previously we hooked playCardOnTable right into js handler which caused client animation, in real game its a two&lt;br /&gt;
step operation. When user clicks on game element js client sends an ajax call to server, server processes it and updates database, server sends&lt;br /&gt;
notification in response, client hooks animations to server notification.&lt;br /&gt;
&lt;br /&gt;
So in .js code replace onPlayerHandSelectionChanged with&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onPlayerHandSelectionChanged : function() {&lt;br /&gt;
            var items = this.playerHand.getSelectedItems();&lt;br /&gt;
&lt;br /&gt;
            if (items.length &amp;gt; 0) {&lt;br /&gt;
                var action = &#039;playCard&#039;;&lt;br /&gt;
                if (this.checkAction(action, true)) {&lt;br /&gt;
                    // Can play a card&lt;br /&gt;
                    var card_id = items[0].id;                    &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;, {&lt;br /&gt;
                        id : card_id,&lt;br /&gt;
                        lock : true&lt;br /&gt;
                    }, this, function(result) {&lt;br /&gt;
                    }, function(is_error) {&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;giveCards&#039;)) {&lt;br /&gt;
                    // Can give cards =&amp;gt; let the player select some cards&lt;br /&gt;
                } else {&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now when you click on card you should get a server response: Not implemented...&lt;br /&gt;
&lt;br /&gt;
Lets implement it, in .game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function playCard($card_id) {&lt;br /&gt;
        self::checkAction(&amp;quot;playCard&amp;quot;);&lt;br /&gt;
        $player_id = self::getActivePlayerId();&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;moveCard($card_id, &#039;cardsontable&#039;, $player_id);&lt;br /&gt;
        // XXX check rules here&lt;br /&gt;
        $currentCard = $this-&amp;gt;cards-&amp;gt;getCard($card_id);&lt;br /&gt;
        // And notify&lt;br /&gt;
        self::notifyAllPlayers(&#039;playCard&#039;, clienttranslate(&#039;${player_name} plays ${value_displayed} ${color_displayed}&#039;), array (&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array (&#039;color_displayed&#039;,&#039;value_displayed&#039; ),&#039;card_id&#039; =&amp;gt; $card_id,&#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; $this-&amp;gt;values_label [$currentCard [&#039;type_arg&#039;]],&#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; $this-&amp;gt;colors [$currentCard [&#039;type&#039;]] [&#039;name&#039;] ));&lt;br /&gt;
        // Next player&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;playCard&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We get the card from client, we move it to the table (moveCard is hooked to database directly, its part of deck class),&lt;br /&gt;
we notify all players and we change state. What we are missing here is bunch of checks (rule enforcements), we will add it later.&lt;br /&gt;
&lt;br /&gt;
Interesting part about this notify is that we use i18n array for strings that needs to be translated by client, so&lt;br /&gt;
they are sent as English text in notification, then client has to know which parameters needs translating.&lt;br /&gt;
&lt;br /&gt;
On the client side .js we have to implement a notification handler to do the animation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setupNotifications : function() {&lt;br /&gt;
            console.log(&#039;notifications subscriptions setup&#039;);&lt;br /&gt;
&lt;br /&gt;
            dojo.subscribe(&#039;newHand&#039;, this, &amp;quot;notif_newHand&amp;quot;);&lt;br /&gt;
            dojo.subscribe(&#039;playCard&#039;, this, &amp;quot;notif_playCard&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        notif_newHand : function(notif) {&lt;br /&gt;
            // We received a new full hand of 13 cards.&lt;br /&gt;
            this.playerHand.removeAll();&lt;br /&gt;
&lt;br /&gt;
            for ( var i in notif.args.cards) {&lt;br /&gt;
                var card = notif.args.cards[i];&lt;br /&gt;
                var color = card.type;&lt;br /&gt;
                var value = card.type_arg;&lt;br /&gt;
                this.playerHand.addToStockWithId(this.getCardUniqueId(color, value), card.id);&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        notif_playCard : function(notif) {&lt;br /&gt;
            // Play a card on the table&lt;br /&gt;
            this.playCardOnTable(notif.args.player_id, notif.args.color, notif.args.value, notif.args.card_id);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now it actually works through the server when you click on card - the move is recorded. If you test it now you will notice&lt;br /&gt;
after trick is done all cards remains on the table, but if you press F5 they would disappear, this is because&lt;br /&gt;
we updated database to pick-up the cards but did not send notification about it, so we need to send notification about it&lt;br /&gt;
and have a handler for it&lt;br /&gt;
&lt;br /&gt;
So in .game.php file add notification in stNextPlayer function after moveAllCardsInLocation call:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Notify&lt;br /&gt;
            // Note: we use 2 notifications here in order we can pause the display during the first notification&lt;br /&gt;
            //  before we move all cards to the winner (during the second)&lt;br /&gt;
            $players = self::loadPlayersBasicInfos();&lt;br /&gt;
            self::notifyAllPlayers( &#039;trickWin&#039;, clienttranslate(&#039;${player_name} wins the trick&#039;), array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $best_value_player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; $players[ $best_value_player_id ][&#039;player_name&#039;]&lt;br /&gt;
            ) );            &lt;br /&gt;
            self::notifyAllPlayers( &#039;giveAllCardsToPlayer&#039;,&#039;&#039;, array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $best_value_player_id&lt;br /&gt;
            ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And in .js file add 2 more notification handlers.&lt;br /&gt;
&lt;br /&gt;
This is to subscribe in setupNotifications function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            dojo.subscribe( &#039;trickWin&#039;, this, &amp;quot;notif_trickWin&amp;quot; );&lt;br /&gt;
            this.notifqueue.setSynchronous( &#039;trickWin&#039;, 1000 );&lt;br /&gt;
            dojo.subscribe( &#039;giveAllCardsToPlayer&#039;, this, &amp;quot;notif_giveAllCardsToPlayer&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And these are handlers&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        notif_trickWin : function(notif) {&lt;br /&gt;
            // We do nothing here (just wait in order players can view the 4 cards played before they&#039;re gone.&lt;br /&gt;
        },&lt;br /&gt;
        notif_giveAllCardsToPlayer : function(notif) {&lt;br /&gt;
            // Move all cards on table to given table, then destroy them&lt;br /&gt;
            var winner_id = notif.args.player_id;&lt;br /&gt;
            for ( var player_id in this.gamedatas.players) {&lt;br /&gt;
                var anim = this.slideToObject(&#039;cardontable_&#039; + player_id, &#039;overall_player_board_&#039; + winner_id);&lt;br /&gt;
                dojo.connect(anim, &#039;onEnd&#039;, function(node) {&lt;br /&gt;
                    dojo.destroy(node);&lt;br /&gt;
                });&lt;br /&gt;
                anim.play();&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So &#039;trickWin&#039; notification does not do much except it will delay the processing of next notification by 1 second (1000 ms)&lt;br /&gt;
and it will log the message (that happens independently of what handler does).&lt;br /&gt;
&amp;lt;i&amp;gt;Note: if on the other hand you don&#039;t want to log but want to do something else, send an empty message&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now after the trick you see all cards move towards the &amp;quot;player&#039;s stash&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Scoring and End of game handling ==&lt;br /&gt;
&lt;br /&gt;
Now we should calculate scoring and for that we need to actually track who wins the trick.&lt;br /&gt;
Trick is won by the player with highest card (no trump). We just need to remember what is trick suite.&lt;br /&gt;
For which we will use state variable &#039;trickColor&#039; which we already conveniently created.&lt;br /&gt;
&lt;br /&gt;
In .game.php file find playCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = self::getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            self::setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember first suit being played, now to use it modify stNextPlayer function to fix our TODO comment&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stNextPlayer() {&lt;br /&gt;
        // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
        if ($this-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;cardsontable&#039;) == 4) {&lt;br /&gt;
            // This is the end of the trick&lt;br /&gt;
            $cards_on_table = $this-&amp;gt;cards-&amp;gt;getCardsInLocation(&#039;cardsontable&#039;);&lt;br /&gt;
            $best_value = 0;&lt;br /&gt;
            $best_value_player_id = null;&lt;br /&gt;
            $currentTrickColor = self::getGameStateValue(&#039;trickColor&#039;);&lt;br /&gt;
            foreach ( $cards_on_table as $card ) {&lt;br /&gt;
                // Note: type = card color&lt;br /&gt;
                if ($card [&#039;type&#039;] == $currentTrickColor) {&lt;br /&gt;
                    if ($best_value_player_id === null || $card [&#039;type_arg&#039;] &amp;gt; $best_value) {&lt;br /&gt;
                        $best_value_player_id = $card [&#039;location_arg&#039;]; // Note: location_arg = player who played this card on table&lt;br /&gt;
                        $best_value = $card [&#039;type_arg&#039;]; // Note: type_arg = value of the card&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            // Active this player =&amp;gt; he&#039;s the one who starts the next trick&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer( $best_value_player_id );&lt;br /&gt;
            &lt;br /&gt;
            // Move all cards to &amp;quot;cardswon&amp;quot; of the given player&lt;br /&gt;
            $this-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
        &lt;br /&gt;
            // Notify&lt;br /&gt;
            // ... same code here as before&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The scoring rule in the studio example code is huge multi-page function, for this tutorial we will make simplier.&lt;br /&gt;
Lets score -1 point per heart and call it a day. And game will end when somebody goes -100 or below.&lt;br /&gt;
&lt;br /&gt;
As UI goes for scoring, the main thing to update is the scoring on the mini boards represented by stars, also&lt;br /&gt;
we want to show that in the log. &lt;br /&gt;
In addition scoring can be shown in [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialog]] using tableWindow notification, but it is a tutorial on its own and you can do it as homework (it is part of original heart game).&lt;br /&gt;
&lt;br /&gt;
In .js file we need to add one more subscription and notification handler:&lt;br /&gt;
            dojo.subscribe( &#039;newScores&#039;, this, &amp;quot;notif_newScores&amp;quot; );&lt;br /&gt;
in setupNotifications&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
        notif_newScores : function(notif) {&lt;br /&gt;
            // Update players&#039; scores&lt;br /&gt;
            for ( var player_id in notif.args.newScores) {&lt;br /&gt;
                this.scoreCtrl[player_id].toValue(notif.args.newScores[player_id]);&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
somewhere after. this.scoreCtrl is pre-existing object that shows the scoring and this function will update score values per player from notification argument&lt;br /&gt;
&lt;br /&gt;
so in .game.php our stEndHand function will look like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stEndHand() {&lt;br /&gt;
            // Count and score points, then end the game or go to the next hand.&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        // Gets all &amp;quot;hearts&amp;quot; + queen of spades&lt;br /&gt;
&lt;br /&gt;
        $player_to_points = array ();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player ) {&lt;br /&gt;
            $player_to_points [$player_id] = 0;&lt;br /&gt;
        }&lt;br /&gt;
        $cards = $this-&amp;gt;cards-&amp;gt;getCardsInLocation(&amp;quot;cardswon&amp;quot;);&lt;br /&gt;
        foreach ( $cards as $card ) {&lt;br /&gt;
            $player_id = $card [&#039;location_arg&#039;];&lt;br /&gt;
            // Note: 2 = heart&lt;br /&gt;
            if ($card [&#039;type&#039;] == 2) {&lt;br /&gt;
                $player_to_points [$player_id] ++;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        // Apply scores to player&lt;br /&gt;
        foreach ( $player_to_points as $player_id =&amp;gt; $points ) {&lt;br /&gt;
            if ($points != 0) {&lt;br /&gt;
                $sql = &amp;quot;UPDATE player SET player_score=player_score-$points  WHERE player_id=&#039;$player_id&#039;&amp;quot;;&lt;br /&gt;
                self::DbQuery($sql);&lt;br /&gt;
                $heart_number = $player_to_points [$player_id];&lt;br /&gt;
                self::notifyAllPlayers(&amp;quot;points&amp;quot;, clienttranslate(&#039;${player_name} gets ${nbr} hearts and looses ${nbr} points&#039;), array (&lt;br /&gt;
                        &#039;player_id&#039; =&amp;gt; $player_id,&#039;player_name&#039; =&amp;gt; $players [$player_id] [&#039;player_name&#039;],&lt;br /&gt;
                        &#039;nbr&#039; =&amp;gt; $heart_number ));&lt;br /&gt;
            } else {&lt;br /&gt;
                // No point lost (just notify)&lt;br /&gt;
                self::notifyAllPlayers(&amp;quot;points&amp;quot;, clienttranslate(&#039;${player_name} did not get any hearts&#039;), array (&lt;br /&gt;
                        &#039;player_id&#039; =&amp;gt; $player_id,&#039;player_name&#039; =&amp;gt; $players [$player_id] [&#039;player_name&#039;] ));&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        $newScores = self::getCollectionFromDb(&amp;quot;SELECT player_id, player_score FROM player&amp;quot;, true );&lt;br /&gt;
        self::notifyAllPlayers( &amp;quot;newScores&amp;quot;, &#039;&#039;, array( &#039;newScores&#039; =&amp;gt; $newScores ) );&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        foreach ( $newScores as $player_id =&amp;gt; $score ) {&lt;br /&gt;
            if ($score &amp;lt;= -100) {&lt;br /&gt;
                // Trigger the end of the game !&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;endGame&amp;quot;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;nextHand&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So it should more less work now, including end of game condition. Try to play it!&lt;br /&gt;
&lt;br /&gt;
== Additional stuff ==&lt;br /&gt;
&lt;br /&gt;
The following things were not implemented and can add them yourself by looking at the code of original hearts game:&lt;br /&gt;
&lt;br /&gt;
* Remove debug code from setupNewGame to deal cards, cards are now dealt in stNewHand state handler&lt;br /&gt;
* Rule checking and rule enforcements in playCard function&lt;br /&gt;
* Start scoring with 100 points each and end when &amp;lt;= 0&lt;br /&gt;
* Fix scoring rules with Q of spades and 26 point reverse scoring&lt;br /&gt;
* First player one with 2 club&lt;br /&gt;
* Add progress handling&lt;br /&gt;
* Add statistics&lt;br /&gt;
* Add card exchange states&lt;br /&gt;
* Add game option to start with 75 points instead of 100&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Xmakina</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=18821</id>
		<title>Tutorial hearts</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tutorial_hearts&amp;diff=18821"/>
		<updated>2023-11-10T08:39:50Z</updated>

		<summary type="html">&lt;p&gt;Xmakina: /* Layout and Graphics */ add direct link to github&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Studio_Framework_Navigation}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
Using this tutorial, you can build a complete working game on the BGA environment: Hearts.&lt;br /&gt;
&lt;br /&gt;
Before you read this tutorial, you must:&lt;br /&gt;
* Read the overall presentations of the BGA Framework ([[Studio|see here]]).&lt;br /&gt;
* Know the rules for Hearts&lt;br /&gt;
* Some-what know the languages used on BGA: PHP, SQL, HTML, CSS, Javascript&lt;br /&gt;
* Set up your development environment [http://en.doc.boardgamearena.com/First_steps_with_BGA_Studio First Steps with BGA Studio]&lt;br /&gt;
* As part of setup you have to have access to your ftp home folder in studio, which would have the full &#039;hearts&#039; game source code. We will be using some resources of this game in this tutorial, so copy it over to local disk if you have not done so.&lt;br /&gt;
&lt;br /&gt;
If you are stuck or have question about this tutorial, post on [https://forum.boardgamearena.com/viewforum.php?f=12 BGA Developers forum]&lt;br /&gt;
&lt;br /&gt;
== Create your first game ==&lt;br /&gt;
&lt;br /&gt;
If you have not already, you have to create a project in BGA Studio. For this tutorial you can create a project heartsYOURNAME where&lt;br /&gt;
YOURNAME is your developer login name. You can also re-use the project you have created for the &amp;quot;First Steps&amp;quot; tutorial above.&lt;br /&gt;
With the initial skeleton of code provided, you can already start a game from the BGA Studio. &lt;br /&gt;
&lt;br /&gt;
1. Find and express start the game in turn-based mode with 4 players. Make sure it works. If you want to see the game as 2nd player press red arrow button on the player panel to switch to that player. More details can be found in [[First_steps_with_BGA_Studio]]&lt;br /&gt;
&lt;br /&gt;
2. Modify the text in heartsYOURNAME_heartsYOURNAME.tpl, reload the page in the browser and make sure your ftp sync works as expected.&lt;br /&gt;
Note: if you have not setup auto-sync do it now, manually copying files is a no-starter.&lt;br /&gt;
&lt;br /&gt;
3. Express stop from settings menu (the gear icon).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Note: please do &#039;&#039;&#039;not&#039;&#039;&#039; use the hearts project code as a base. This tutorial assumes you started with a TEMPLATE project with no prior modifications. Using the hearts project as a base will be very confusing and you won&#039;t be able to follow all the steps.&lt;br /&gt;
&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Attention!!!&amp;lt;/b&amp;gt; Very important note about reloading, if you don&#039;t remember this you may spent hours debugging. Browser caches .css files and images. If you change any of these files you have to do &amp;quot;full reload&amp;quot; which is usually Ctrl+F5 (or Ctrl+reload button on browser) not just a regular reload.&lt;br /&gt;
&lt;br /&gt;
== Hook version control system ==&lt;br /&gt;
&lt;br /&gt;
For a real game, or even for this tutorial, we recommend committing the code to version control right from the start. You are going to find yourself in a situation where the game doesn&#039;t even start anymore and no way of debugging it, unless you have a way to revert. That is where version control becomes very handy. If you are not familiar with version control (e.g. [https://git-scm.com/docs/gittutorial git]) then at least back up your files after each major change. Start now.&lt;br /&gt;
&lt;br /&gt;
Code for this tutorial available is on github: https://github.com/elaskavaia/bga-heartsla&lt;br /&gt;
&lt;br /&gt;
Different revisions represent different steps along the process, starting from original template to a PARTIAL game. The full game can be found in your FTP home folder.&lt;br /&gt;
&lt;br /&gt;
== Update game infos and box graphics ==&lt;br /&gt;
&lt;br /&gt;
Even it does nothing yet, always start by making sure the game looks decent in the game selector, meaning it has nice box graphics and its information is correct. For that we need to edit [[Game_meta-information: gameinfos.inc.php|gameinfos.inc.php]].&lt;br /&gt;
&lt;br /&gt;
For a real game, you would go to [http://boardgamegeek.com BoardGameGeek], find the game, and use the information from BGG to fill in the gameinfos.&lt;br /&gt;
&lt;br /&gt;
So let&#039;s do that. Find &amp;quot;hearts&amp;quot; on BoardGameGeek. (Hint: Original release 1850 :))&lt;br /&gt;
&lt;br /&gt;
You can fill in the year of publishing and bgg id, put &#039;&#039;Public Domain&#039;&#039; under publisher (for a real game, leave an empty string so it won&#039;t be displayed), and a publisher id of 171 for public domain. And as designer and author you can just put your own name just for fun. Set number of players to 4.&lt;br /&gt;
&lt;br /&gt;
  // Players configuration that can be played (ex: 2 to 4 players)&lt;br /&gt;
  &#039;players&#039; =&amp;gt; array( 4 ),  &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Important step&#039;&#039;&#039;: you have to refresh the information in the Studio website through the control panel. So go to Control Panel -&amp;gt; Manage Games -&amp;gt; heartsYOURNAME&lt;br /&gt;
and press Reload for &#039;Reload game informations&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The next step would be to replace &#039;&#039;&#039;game_box.png&#039;&#039;&#039; with nicer images. This can be done from the [[Game metadata manager]]. &lt;br /&gt;
&lt;br /&gt;
Now try to start the game again. If you somehow introduced a syntax error in the gameinfos file it may not work (the game won&#039;t start).&lt;br /&gt;
Always use the &amp;quot;Express Start&amp;quot; button to start the game. You should see a standard state prompt from the template. You should see 4 players on the right: testdude0 .. testdude3.&lt;br /&gt;
To switch between them press the red arrow button near their names, it will open another tab. This way you don&#039;t need to login and logout from multiple accounts!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Note: if you had run the game before with less than 4 players there is a bug that will prevent you from running it with 4 only (if you did not run it before or run it with 4 players as instructed stop reading this note), to workaround revert back to original players array (i.e. 1,2,3,4), reload game options, then create a table with 4 players, exit that game table, then change gameoptions to 4 only as above, reload game options, create table again.&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Code Rev [https://github.com/elaskavaia/bga-heartsla/tree/4b3a73eeb5acae961ade18473af119e8ce8d1a8f]&lt;br /&gt;
&lt;br /&gt;
== Layout and Graphics ==&lt;br /&gt;
&lt;br /&gt;
In this section we will do graphics of the game, and main layout of the game.&lt;br /&gt;
&lt;br /&gt;
First copy a sprite with cards image from [https://github.com/elaskavaia/bga-heartsla/blob/4b3a73eeb5acae961ade18473af119e8ce8d1a8f/img/cards.jpg hearts img/cards.jpg]  into img/ folder of your project. Project hearts is mounted to your home directory on bga server.&lt;br /&gt;
&amp;lt;blockquote&amp;gt;There are better quality deck of cards image at https://en.doc.boardgamearena.com/Common_board_game_elements_image_resources&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Details about images can be found here: [[Game art: img directory]].&lt;br /&gt;
&lt;br /&gt;
Edit .tpl to add some divs to represent player table and hand area&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;myhand_wrap&amp;quot; class=&amp;quot;whiteblock&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3&amp;gt;My Hand&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you refresh you should see now white area with My Hand title.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-tpl2.png]]&lt;br /&gt;
&lt;br /&gt;
Now lets add a card into the hand, just so you can feel it. Edit .tpl and a playertablecard div inside a hand div&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
       &amp;lt;div class=&amp;quot;playertablecard&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Edit .css file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.playertablecard {&lt;br /&gt;
    display: inline-block;&lt;br /&gt;
    position: relative;&lt;br /&gt;
    margin-top: 5px;&lt;br /&gt;
    width: 72px;&lt;br /&gt;
    height: 96px;&lt;br /&gt;
    background-image: url(&#039;img/cards.jpg&#039;); /* temp hack to see it */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you edit CSS remember that you have to FORCE-reload page, i.e. Ctrl-F5, otherwise its cached.&lt;br /&gt;
&amp;lt;i&amp;gt;Same when you change existing graphics files&amp;lt;/i&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
You should see this:&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-tpl3.png]]&lt;br /&gt;
&lt;br /&gt;
Awesome! Now lets do the rest of layout.&lt;br /&gt;
&lt;br /&gt;
There are few ways of how html could have been generated, you could have start with nothing and generate&lt;br /&gt;
all by java script. Or you could have started with complete game markup in html and make java script just hide and move pieces around. BGA framework provides also a third way which is mix of both plus template engine to generate HTML using php. So lets do that.&lt;br /&gt;
&lt;br /&gt;
Change .tpl file to have this inside&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;playertables&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;!-- BEGIN player --&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;playertable whiteblock playertable_{DIR}&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablename&amp;quot; style=&amp;quot;color:#{PLAYER_COLOR}&amp;quot;&amp;gt;&lt;br /&gt;
            {PLAYER_NAME}&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;div class=&amp;quot;playertablecard&amp;quot; id=&amp;quot;playertablecard_{PLAYER_ID}&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;!-- END player --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;myhand_wrap&amp;quot; class=&amp;quot;whiteblock&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;h3&amp;gt;{MY_HAND}&amp;lt;/h3&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;myhand&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What we did is we added &amp;quot;block&amp;quot; player, it is marked up using html comments. {VAR} notation is used&lt;br /&gt;
to inject variables and &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
  &amp;lt;!-- BEGIN xxx --&amp;gt; &lt;br /&gt;
   inside &lt;br /&gt;
  &amp;lt;!-- END xxx --&amp;gt; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
effectively allows us to do template loops.&lt;br /&gt;
&lt;br /&gt;
In .view.php insert this code after &#039;Place your code below&#039; comment&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        $template = self::getGameName() . &amp;quot;_&amp;quot; . self::getGameName();&lt;br /&gt;
        &lt;br /&gt;
        $directions = array( &#039;S&#039;, &#039;W&#039;, &#039;N&#039;, &#039;E&#039; );&lt;br /&gt;
        &lt;br /&gt;
        // this will inflate our player block with actual players data&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;begin_block($template, &amp;quot;player&amp;quot;);&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $info ) {&lt;br /&gt;
            $dir = array_shift($directions);&lt;br /&gt;
            $this-&amp;gt;page-&amp;gt;insert_block(&amp;quot;player&amp;quot;, array (&amp;quot;PLAYER_ID&amp;quot; =&amp;gt; $player_id,&lt;br /&gt;
                    &amp;quot;PLAYER_NAME&amp;quot; =&amp;gt; $players [$player_id] [&#039;player_name&#039;],&lt;br /&gt;
                    &amp;quot;PLAYER_COLOR&amp;quot; =&amp;gt; $players [$player_id] [&#039;player_color&#039;],&lt;br /&gt;
                    &amp;quot;DIR&amp;quot; =&amp;gt; $dir ));&lt;br /&gt;
        }&lt;br /&gt;
        // this will make our My Hand text translatable&lt;br /&gt;
        $this-&amp;gt;tpl[&#039;MY_HAND&#039;] = self::_(&amp;quot;My hand&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What it does is for each player we have it will replicate the html between &amp;lt;!-- BEGIN player --&amp;gt; and &amp;lt;!-- END player --&amp;gt; tags, substituting the variable denoted by {XXX}&lt;br /&gt;
with the values you provide. The DIR variable in this case we pulling from directions array (where array_shift will take first element and remove it from the array).&lt;br /&gt;
&lt;br /&gt;
Reload. If everything went well you should see this:&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-tpl4.png]]&lt;br /&gt;
&lt;br /&gt;
These are &amp;quot;tableau&amp;quot; areas for 4 players plus My hand visible only to one player.&lt;br /&gt;
They are not exactly how we wanted them to be because we did not edit .css yet.&lt;br /&gt;
&lt;br /&gt;
Now edit .css, add these lines after import before our previous definition&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/** Table layout **/&lt;br /&gt;
&lt;br /&gt;
#playertables {&lt;br /&gt;
    position: relative;&lt;br /&gt;
    width: 710px;&lt;br /&gt;
    height: 340px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.playertablename {&lt;br /&gt;
    font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.playertable {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    text-align: center;&lt;br /&gt;
    width: 180px;&lt;br /&gt;
    height: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.playertable_N {&lt;br /&gt;
    left: 50%;&lt;br /&gt;
    top: 0px;&lt;br /&gt;
    margin-left: -90px; /* half of 180 */&lt;br /&gt;
}&lt;br /&gt;
.playertable_S {&lt;br /&gt;
    left: 50%;&lt;br /&gt;
    bottom: 0px;&lt;br /&gt;
    margin-left: -90px; /* half of 180 */&lt;br /&gt;
}&lt;br /&gt;
.playertable_W {&lt;br /&gt;
    left: 0px;&lt;br /&gt;
    top: 50%;&lt;br /&gt;
    margin-top: -55px; /* half of 130 */&lt;br /&gt;
}&lt;br /&gt;
.playertable_E {&lt;br /&gt;
    right: 0px;&lt;br /&gt;
    top: 50%;&lt;br /&gt;
    margin-top: -55px; /* half of 130 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now you force Reload and you should see this:&lt;br /&gt;
[[File:Heartsla-tpl5.png]]&lt;br /&gt;
&lt;br /&gt;
This is almost all we need for graphics and layout, there are few tweaks left there but lets do some more heavy lifting now.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Note: if you did not see changes you may have not force reloaded, force means you use Ctrl+F5 or Cltr+Shift-R, if you don&#039;t &amp;quot;force&amp;quot; browser will use cached version of .css and images! Which is not what you just changed&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;Another Note: In general if you have auto-sync you don&#039;t need to reload if you change game.php file, you need normal reload if you change js, and force reload for css and images. If you changed state machine or database you likely need to restart the game.&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Game Interface JS Stock ==&lt;br /&gt;
&lt;br /&gt;
The BGA framework provides a few out of the box classes to deal with cards. The client side&lt;br /&gt;
contains a class called [[Stock]] and it can be used for any dynamic html &amp;quot;pieces&amp;quot; management that uses&lt;br /&gt;
common sprite images. On the server side we will use the [[Deck]] class which we discuss later.&lt;br /&gt;
&lt;br /&gt;
If you open cards.jpg in an image viewer you will see that it is a &amp;quot;sprite&amp;quot; image - a 13x4 grid of images stitched together,&lt;br /&gt;
which is a very efficient way to transport images. So we will use the Stock class to mark up these images and create&lt;br /&gt;
&amp;quot;card&amp;quot; divs for us.&lt;br /&gt;
&lt;br /&gt;
First, we need to add &#039;&#039;&#039;ebg/stock&#039;&#039;&#039; as a dependency in the hearts.js file:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
define([&lt;br /&gt;
    &amp;quot;dojo&amp;quot;,&amp;quot;dojo/_base/declare&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/core/gamegui&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/counter&amp;quot;,&lt;br /&gt;
    &amp;quot;ebg/stock&amp;quot;     /// &amp;lt;==== HERE&lt;br /&gt;
],&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then add this to the Javascript constructor, this will define size of our cards&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            console.log(&#039;hearts constructor&#039;);&lt;br /&gt;
            this.cardwidth = 72;&lt;br /&gt;
            this.cardheight = 96;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The stock is initialized in the Javascript &amp;quot;setup&amp;quot; method like this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    // TODO: Set up your game interface here, according to &amp;quot;gamedatas&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    // Player hand&lt;br /&gt;
    this.playerHand = new ebg.stock(); // new stock object for hand&lt;br /&gt;
    this.playerHand.create( this, $(&#039;myhand&#039;), this.cardwidth, this.cardheight );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As parameters of the &amp;quot;create&amp;quot; method, we provided the width/height of an item (a card), and the container div &amp;quot;myhand&amp;quot; - which is an id of &amp;quot;div&amp;quot; element from our .tpl file representing a player hand.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then, we must tell the stock what items it is going to display during its life: the 52 cards of a standard card game from a CSS sprite image named &amp;quot;cards.jpg&amp;quot; with all the cards arranged in 4 rows and 13 columns.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how we tell stock what item types to display:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            this.playerHand.image_items_per_row = 13; // 13 images per row&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
            // Create cards types:&lt;br /&gt;
            for (var color = 1; color &amp;lt;= 4; color++) {&lt;br /&gt;
                for (var value = 2; value &amp;lt;= 14; value++) {&lt;br /&gt;
                    // Build card type id&lt;br /&gt;
                    var card_type_id = this.getCardUniqueId(color, value);&lt;br /&gt;
                    this.playerHand.addItemType(card_type_id, card_type_id, g_gamethemeurl + &#039;img/cards.jpg&#039;, card_type_id);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And add this function to the utilities section&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Get card unique identifier based on its color and value&lt;br /&gt;
        getCardUniqueId : function(color, value) {&lt;br /&gt;
            return (color - 1) * 13 + (value - 2);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Explanations:&lt;br /&gt;
* At first, we tell the stock component that our CSS sprite contains 13 items per row. This way, it can find the correct image for each card type id.&lt;br /&gt;
* Then for the 4x13 cards, we call the &#039;&#039;&#039;addItemType&#039;&#039;&#039; method that creates the type. The arguments are the type id, the weight of the card (for sorting purpose), the URL of our CSS sprite, and the position of our card image in the CSS sprite. It happens to be the same number in our case.&lt;br /&gt;
&lt;br /&gt;
Note: we need to generate a unique ID for each type of card based on its color and value.  For that we create a function &#039;&#039;&#039;getCardUniqueId&#039;&#039;&#039;. The type is the unique identifier of the TYPE of the card, e.g., the queen of spades encoded as an integer. If our deck had 2 standard card decks we would have had 2 queens of spades; they would share the same type and the same image but would have different ids. NOTE: It&#039;s unfortunate that they named this &#039;&#039;&#039;getCardUniqueId&#039;&#039;&#039;; it should have been &#039;&#039;&#039;getCardUniqueType&#039;&#039;&#039;, because it really isn&#039;t an id, but a TYPE of card. The type of the item should either be a reversible function of its properties (i.e., kind of suite * 13 + value) or just an enumerator described in material.inc.php. In this specific case it&#039;s a synthetic type id, which also the same as the number of the card in the sprite image (i.e., if you enumerate each image in sprite going left to right, then top to bottom).&lt;br /&gt;
&lt;br /&gt;
Now let&#039;s add the 5 of Hearts to the player&#039;s hand just for fun (this code will go in setup method after types initialization):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// 2 = hearts, 5 is 5, and 42 is the card id, which normally would come from db&lt;br /&gt;
this.playerHand.addToStockWithId( this.getCardUniqueId( 2, 5 ), 42 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This will add the card with id 42 and type 16 ( (2-1)*13+(5-2)=16 ). &lt;br /&gt;
&lt;br /&gt;
Note that number 16 would not be something you can see in database, Deck database will have separate field for type and type_arg where type is suite and type_arg is number, so its not the same thing, but you can use same formula to convert. Number 42 on the other hand would be id field in database. But we get to database in the later section.&lt;br /&gt;
&lt;br /&gt;
If you reload now you should see the 5 of hearts in &amp;quot;your hand&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Stock control can handle clicking on items and forms the selection. You can immediately react to selection&lt;br /&gt;
or you can query it later; for example when user presses some other button.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s hook it up. Add this in the setup method in .js file, after this.playerHand is initialised:&lt;br /&gt;
&lt;br /&gt;
     dojo.connect( this.playerHand, &#039;onChangeSelection&#039;, this, &#039;onPlayerHandSelectionChanged&#039; );&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Then find the Player&#039;s action comment section in .js file and add a handler after the comment:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onPlayerHandSelectionChanged: function() {&lt;br /&gt;
            var items = this.playerHand.getSelectedItems();&lt;br /&gt;
&lt;br /&gt;
            if (items.length &amp;gt; 0) {&lt;br /&gt;
                if (this.checkAction(&#039;playCard&#039;, true)) {&lt;br /&gt;
                    // Can play a card&lt;br /&gt;
&lt;br /&gt;
                    var card_id = items[0].id;&lt;br /&gt;
                    console.log(&amp;quot;on playCard &amp;quot;+card_id);&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;giveCards&#039;)) {&lt;br /&gt;
                    // Can give cards =&amp;gt; let the player select some cards&lt;br /&gt;
                } else {&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The function name of the handler is 4th parameter of the dojo.connect function. Make sure you spell it correctly or there will be unpredictable effects.&lt;br /&gt;
&lt;br /&gt;
Now if you reload, open the Javascript Console (F12), and then click on the card in My Hand, you should see:&lt;br /&gt;
  on playCard 42&lt;br /&gt;
printed on the console&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note : You need to be the active player to have rights to play a card and so log your message in the console&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Game Database and Game Initialisation ==&lt;br /&gt;
&lt;br /&gt;
Next step, you want to design a game database and setup a new game (on the server side).&lt;br /&gt;
For that we need to a) modify the database schema to add our cards data b) add some global variables into&lt;br /&gt;
the existing globals table.&lt;br /&gt;
&lt;br /&gt;
To modify the schema, first exit your existing game(s). Open &#039;&#039;&#039;dbmodel.sql&#039;&#039;&#039; file and uncomment the card table creation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE IF NOT EXISTS `card` (&lt;br /&gt;
  `card_id` int(10) unsigned NOT NULL AUTO_INCREMENT,&lt;br /&gt;
  `card_type` varchar(16) NOT NULL,&lt;br /&gt;
  `card_type_arg` int(11) NOT NULL,&lt;br /&gt;
  `card_location` varchar(16) NOT NULL,&lt;br /&gt;
  `card_location_arg` int(11) NOT NULL,&lt;br /&gt;
  PRIMARY KEY (`card_id`)&lt;br /&gt;
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the &amp;quot;card&amp;quot; table which will be managed by the Deck php class.&lt;br /&gt;
&lt;br /&gt;
In addition we want a little piece of information in the players table:&lt;br /&gt;
&lt;br /&gt;
  -- add info about first player&lt;br /&gt;
  ALTER TABLE `player` ADD `player_first` BOOLEAN NOT NULL DEFAULT &#039;0&#039;;&lt;br /&gt;
&lt;br /&gt;
Not sure why they put this into the player table, as we could use a global db variable to hold first player as easily.&lt;br /&gt;
But I am just following the existing code more-or-less.&lt;br /&gt;
&lt;br /&gt;
Next we finally get into .game.php class, where the main logic and db interaction would be. Find php constructor which should be &lt;br /&gt;
  function __construct( )&lt;br /&gt;
This is first function in a file. Add this code to constructor.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        parent::__construct();&lt;br /&gt;
        self::initGameStateLabels( array( &lt;br /&gt;
                         &amp;quot;currentHandType&amp;quot; =&amp;gt; 10, &lt;br /&gt;
                         &amp;quot;trickColor&amp;quot; =&amp;gt; 11, &lt;br /&gt;
                         &amp;quot;alreadyPlayedHearts&amp;quot; =&amp;gt; 12,&lt;br /&gt;
                          ) );&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;cards = self::getNew( &amp;quot;module.common.deck&amp;quot; );&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;init( &amp;quot;card&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we are initializing three &amp;quot;Game State Variables&amp;quot; which are variables stored in the database. They are integers.&lt;br /&gt;
It must start with values higher or equal to 10 since values lower than 10 are reserved. These values are stored by numeric ids&lt;br /&gt;
in the database, but in the php we associate them with string labels for convenience of access. The variables are &amp;quot;trickColor&amp;quot;: numbers from 1 to 4 that map to card suit (not sure why it&#039;s called color; maybe it&#039;s a translation from French); &amp;quot;alreadyPlayedHearts&amp;quot;: a boolean flag (0 or 1) indicating whether somebody used hearts on the trick; &amp;quot;currentHandType&amp;quot;: stores the value to indicate who to give cards to during exchange.&lt;br /&gt;
&lt;br /&gt;
The next 2 lines are creating $this-&amp;gt;cards object and associating it with &amp;quot;card&amp;quot; table in the the database.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;If we called db table &#039;foo&#039; instead of &#039;card&#039; the last statement would have been  $this-&amp;gt;cards-&amp;gt;init( &amp;quot;foo&amp;quot; )&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
At this point I would start a new game and make sure it starts, then exit. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;i&amp;gt;&lt;br /&gt;
If you made a mistake&lt;br /&gt;
in the .sql or php constructor the game won&#039;t start, and good luck debugging it. (That is why it&#039;s important to check&lt;br /&gt;
once in a while to make sure it still starts while you remember what you have changed.)&lt;br /&gt;
&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Code Rev [https://github.com/elaskavaia/bga-heartsla/tree/e3a049257b592ff6167688d4d344f8a83d349b08]&lt;br /&gt;
&lt;br /&gt;
Now we can go to game initialization &#039;&#039;&#039;setupNewGame&#039;&#039;&#039; in game.php. This method is called only once when the game is created.&lt;br /&gt;
&lt;br /&gt;
In your template project you should have code that deals with player table, just leave it as is. Start inserting the&lt;br /&gt;
other code after &amp;quot;Start the game initialization&amp;quot; comment.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Init global values with their initial values&lt;br /&gt;
&lt;br /&gt;
        // Note: hand types: 0 = give 3 cards to player on the left&lt;br /&gt;
        //                   1 = give 3 cards to player on the right&lt;br /&gt;
        //                   2 = give 3 cards to player opposite&lt;br /&gt;
        //                   3 = keep cards&lt;br /&gt;
        self::setGameStateInitialValue( &#039;currentHandType&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Set current trick color to zero (= no trick color)&lt;br /&gt;
        self::setGameStateInitialValue( &#039;trickColor&#039;, 0 );&lt;br /&gt;
        &lt;br /&gt;
        // Mark if we already played hearts during this hand&lt;br /&gt;
        self::setGameStateInitialValue( &#039;alreadyPlayedHearts&#039;, 0 );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we initialize all the globals to 0.&lt;br /&gt;
&lt;br /&gt;
Next is to create our cards in the database. We have one deck of cards so it&#039;s pretty simple.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Create cards&lt;br /&gt;
        $cards = array ();&lt;br /&gt;
        foreach ( $this-&amp;gt;colors as $color_id =&amp;gt; $color ) {&lt;br /&gt;
            // spade, heart, diamond, club&lt;br /&gt;
            for ($value = 2; $value &amp;lt;= 14; $value ++) {&lt;br /&gt;
                //  2, 3, 4, ... K, A&lt;br /&gt;
                $cards [] = array (&#039;type&#039; =&amp;gt; $color_id,&#039;type_arg&#039; =&amp;gt; $value,&#039;nbr&#039; =&amp;gt; 1 );&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;createCards( $cards, &#039;deck&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code that will create one of each card. But don&#039;t run it yet, because we missing $this-&amp;gt;colors.&lt;br /&gt;
So we have state of the game in the database, but there is some static game information which never changes.&lt;br /&gt;
This information should be stored in material.inc.php and this way it can be accessed from all .php files (and .js if you send it via getAllDatas()).&lt;br /&gt;
We will edit this file now by adding these lines&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;colors = array(&lt;br /&gt;
    1 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;spade&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;spade&#039;) ),&lt;br /&gt;
    2 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;heart&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;heart&#039;) ),&lt;br /&gt;
    3 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;club&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;club&#039;) ),&lt;br /&gt;
    4 =&amp;gt; array( &#039;name&#039; =&amp;gt; clienttranslate(&#039;diamond&#039;),&lt;br /&gt;
                &#039;nametr&#039; =&amp;gt; self::_(&#039;diamond&#039;) )&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
$this-&amp;gt;values_label = array(&lt;br /&gt;
    2 =&amp;gt;&#039;2&#039;,&lt;br /&gt;
    3 =&amp;gt; &#039;3&#039;,&lt;br /&gt;
    4 =&amp;gt; &#039;4&#039;,&lt;br /&gt;
    5 =&amp;gt; &#039;5&#039;,&lt;br /&gt;
    6 =&amp;gt; &#039;6&#039;,&lt;br /&gt;
    7 =&amp;gt; &#039;7&#039;,&lt;br /&gt;
    8 =&amp;gt; &#039;8&#039;,&lt;br /&gt;
    9 =&amp;gt; &#039;9&#039;,&lt;br /&gt;
    10 =&amp;gt; &#039;10&#039;,&lt;br /&gt;
    11 =&amp;gt; clienttranslate(&#039;J&#039;),&lt;br /&gt;
    12 =&amp;gt; clienttranslate(&#039;Q&#039;),&lt;br /&gt;
    13 =&amp;gt; clienttranslate(&#039;K&#039;),&lt;br /&gt;
    14 =&amp;gt; clienttranslate(&#039;A&#039;)&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where $this-&amp;gt;colors will define Suit labels and $this-&amp;gt;values_label will define value labels.&lt;br /&gt;
If you noticed, we have two of each label for suits. This is because sometimes we need translated values on the php&lt;br /&gt;
side and sometimes we don&#039;t. In this case &#039;&#039;&#039;nametr&#039;&#039;&#039; will return a translated value in php, which is only useful when you throw exceptions to show the right strings. If you pass a value to the client via notification you should always use untranslated strings, and the client will translate it. &#039;clienttranslate&#039; marks the value for translation but does not actually change it for php. For more about this wonderful translation stuff see [[Translations]].&lt;br /&gt;
&lt;br /&gt;
== Full game model synchronisation ==&lt;br /&gt;
&lt;br /&gt;
Now at any point in the game we need to make sure that database information can be reflected back in the UI, so we must fix the &#039;&#039;&#039;getAllDatas&#039;&#039;&#039; function&lt;br /&gt;
to return all possible data we need to reconstruct the game. This is in the game.php file. The template for getAllDatas() already takes care of player info. Let&#039;s just&lt;br /&gt;
add hand and tableau data before we return a result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Cards in player hand&lt;br /&gt;
        $result[&#039;hand&#039;] = $this-&amp;gt;cards-&amp;gt;getCardsInLocation( &#039;hand&#039;, $current_player_id );&lt;br /&gt;
        &lt;br /&gt;
        // Cards played on the table&lt;br /&gt;
        $result[&#039;cardsontable&#039;] = $this-&amp;gt;cards-&amp;gt;getCardsInLocation( &#039;cardsontable&#039; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now on the client side we should display this data, so in your .js file in the setup function (which is the receiver of getAllDatas) replace our hack of putting 5 of Hearts directly into the hand with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Cards in player&#039;s hand&lt;br /&gt;
            for ( var i in this.gamedatas.hand) {&lt;br /&gt;
                var card = this.gamedatas.hand[i];&lt;br /&gt;
                var color = card.type;&lt;br /&gt;
                var value = card.type_arg;&lt;br /&gt;
                this.playerHand.addToStockWithId(this.getCardUniqueId(color, value), card.id);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // Cards played on table&lt;br /&gt;
            for (i in this.gamedatas.cardsontable) {&lt;br /&gt;
                var card = this.gamedatas.cardsontable[i];&lt;br /&gt;
                var color = card.type;&lt;br /&gt;
                var value = card.type_arg;&lt;br /&gt;
                var player_id = card.location_arg;&lt;br /&gt;
                this.playCardOnTable(player_id, color, value, card.id);&lt;br /&gt;
            }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This should show hand and tableau cards now, except we are missing the &#039;&#039;&#039;playCardOnTable&#039;&#039;&#039; function. So find the &#039;&#039;&#039;getCardUniqueId&#039;&#039;&#039; function which&lt;br /&gt;
should be in the utilities section and add this after it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        playCardOnTable : function(player_id, color, value, card_id) {&lt;br /&gt;
            // player_id =&amp;gt; direction&lt;br /&gt;
            dojo.place(this.format_block(&#039;jstpl_cardontable&#039;, {&lt;br /&gt;
                x : this.cardwidth * (value - 2),&lt;br /&gt;
                y : this.cardheight * (color - 1),&lt;br /&gt;
                player_id : player_id&lt;br /&gt;
            }), &#039;playertablecard_&#039; + player_id);&lt;br /&gt;
&lt;br /&gt;
            if (player_id != this.player_id) {&lt;br /&gt;
                // Some opponent played a card&lt;br /&gt;
                // Move card from player panel&lt;br /&gt;
                this.placeOnObject(&#039;cardontable_&#039; + player_id, &#039;overall_player_board_&#039; + player_id);&lt;br /&gt;
            } else {&lt;br /&gt;
                // You played a card. If it exists in your hand, move card from there and remove&lt;br /&gt;
                // corresponding item&lt;br /&gt;
&lt;br /&gt;
                if ($(&#039;myhand_item_&#039; + card_id)) {&lt;br /&gt;
                    this.placeOnObject(&#039;cardontable_&#039; + player_id, &#039;myhand_item_&#039; + card_id);&lt;br /&gt;
                    this.playerHand.removeFromStockById(card_id);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // In any case: move it to its final destination&lt;br /&gt;
            this.slideToObject(&#039;cardontable_&#039; + player_id, &#039;playertablecard_&#039; + player_id).play();&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For this to work we also need to add a card template in the .tpl file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Javascript HTML templates&lt;br /&gt;
&lt;br /&gt;
var jstpl_cardontable = &#039;&amp;lt;div class=&amp;quot;cardontable&amp;quot; id=&amp;quot;cardontable_${player_id}&amp;quot; style=&amp;quot;background-position:-${x}px -${y}px&amp;quot;&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;
&lt;br /&gt;
What this does is basically create another card object, because if it is not our card it&#039;s not in our hand (Stock) so&lt;br /&gt;
we have to create it out of thin air. The technique to do that is to implement a Javascript template object defined in the .tpl file with some&lt;br /&gt;
parameters, which will basically create a &amp;quot;div&amp;quot; string (yes you could have used string concatenation but it would not be fancy).&lt;br /&gt;
Now dojo.place places it (the div) on top of a placeholder. Now we have an object with an id of &#039;cardontable_&#039; + player_id. Depending&lt;br /&gt;
on who is playing it we either place it on the player miniboard or in hand (and remove it from hand stock). Then we animate the card move.&lt;br /&gt;
&lt;br /&gt;
We also should fix our .css file now to add style for cardontable and REMOVE background for playertablecard which really is a placeholder div and not a card. (Don&#039;t miss the remove step; it will be all screwy if you do!)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
.playertablecard {&lt;br /&gt;
    display: inline-block;&lt;br /&gt;
    position: relative;&lt;br /&gt;
    margin-top: 5px;&lt;br /&gt;
    width: 72px;&lt;br /&gt;
    height: 96px;&lt;br /&gt;
    /* we remove background-image here */&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*** cards on table ***/&lt;br /&gt;
&lt;br /&gt;
.cardontable {&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    width: 72px;&lt;br /&gt;
    height: 96px;&lt;br /&gt;
    background-image: url(&#039;img/cards.jpg&#039;); &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now to test that it actually works let&#039;s deal cards to players during game initialization:&lt;br /&gt;
&lt;br /&gt;
Add this after createCards in setupNewGame function in the game.php file&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Shuffle deck&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;shuffle(&#039;deck&#039;);&lt;br /&gt;
        // Deal 13 cards to each players&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player ) {&lt;br /&gt;
            $cards = $this-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
        } &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now when you start the game you should see 13 cards in your hand!&lt;br /&gt;
&lt;br /&gt;
We just need to hook-up clicking on card and test if our playCardOnTable works.&lt;br /&gt;
&lt;br /&gt;
Find onPlayerHandSelectionChanged function in the JS file, we should have logging there like  console.log(&amp;quot;on playCard &amp;quot;+card_id);&lt;br /&gt;
So after that insert this:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                    console.log(&amp;quot;on playCard &amp;quot;+card_id);&lt;br /&gt;
                    // type is (color - 1) * 13 + (value - 2)&lt;br /&gt;
                    var type = items[0].type;&lt;br /&gt;
                    var color = Math.floor(type / 13) + 1;&lt;br /&gt;
                    var value = type % 13 + 2;&lt;br /&gt;
                    &lt;br /&gt;
                    this.playCardOnTable(this.player_id,color,value,card_id);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note: this code is for testing we will replace it with server interaction after we test it.&lt;br /&gt;
&lt;br /&gt;
Now if you force reload (because we changed .css before) you should be able to click on card from your hand and see it moving,&lt;br /&gt;
you can click on few cards this way. When you done enjoying the animation, press F5 to get your hand back.&lt;br /&gt;
&lt;br /&gt;
[[File:Heartsla-sync.png]]&lt;br /&gt;
&lt;br /&gt;
Code Rev [https://github.com/elaskavaia/bga-heartsla/tree/01d4e2f595fd14c2adcc97a957d21bb2766f78a8]&lt;br /&gt;
&lt;br /&gt;
== State Machine ==&lt;br /&gt;
&lt;br /&gt;
Now we need to create a game state machine. So the states are:&lt;br /&gt;
&lt;br /&gt;
* Cards are dealt to all players (lets call it &amp;quot;newHand&amp;quot;)&lt;br /&gt;
* Player is selected who will start a new trick (&amp;quot;newTrick&amp;quot;)&lt;br /&gt;
* Player start or respond to played card (&amp;quot;playerTurn&amp;quot;)&lt;br /&gt;
* Game control is passed to next player or trick is ended (&amp;quot;nextPlayer&amp;quot;)&lt;br /&gt;
* End of hand processing (scoring and check for end of game) (&amp;quot;nextHand&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
In addition players can exchange cards so we need two more states for that but we will skip it for now.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The state handling spread across 4 files, so you have to make sure all pieces are connected together.&lt;br /&gt;
The state machine states.php defines all the states, and function handlers on php side in a form of string,&lt;br /&gt;
and if any of these functions are not implemented it would be very hard to debug because it will break in random places.&lt;br /&gt;
&lt;br /&gt;
So .states.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$machinestates = array(&lt;br /&gt;
&lt;br /&gt;
    // The initial state. Please do not modify.&lt;br /&gt;
    1 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;Game setup&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameSetup&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 2 )&lt;br /&gt;
    ),&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    /// New hand&lt;br /&gt;
    2 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;newHand&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stNewHand&amp;quot;,&lt;br /&gt;
        &amp;quot;updateGameProgression&amp;quot; =&amp;gt; true,   &lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 30 )&lt;br /&gt;
    ),    &lt;br /&gt;
&lt;br /&gt;
    21 =&amp;gt; array(       &lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;giveCards&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;Some players must choose 3 cards to give to ${direction}&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must choose 3 cards to give to ${direction}&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;multipleactiveplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGiveCards&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argGiveCards&amp;quot;,&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;giveCards&amp;quot; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;giveCards&amp;quot; =&amp;gt; 22, &amp;quot;skip&amp;quot; =&amp;gt; 22 )        &lt;br /&gt;
    ), &lt;br /&gt;
    &lt;br /&gt;
    22 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;takeCards&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stTakeCards&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;startHand&amp;quot; =&amp;gt; 30, &amp;quot;skip&amp;quot; =&amp;gt; 30  )&lt;br /&gt;
    ),        &lt;br /&gt;
      &lt;br /&gt;
    &lt;br /&gt;
    // Trick&lt;br /&gt;
    &lt;br /&gt;
    30 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;newTrick&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stNewTrick&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;&amp;quot; =&amp;gt; 31 )&lt;br /&gt;
    ),       &lt;br /&gt;
    31 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;playerTurn&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&#039;${actplayer} must play a card&#039;),&lt;br /&gt;
        &amp;quot;descriptionmyturn&amp;quot; =&amp;gt; clienttranslate(&#039;${you} must play a card&#039;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;activeplayer&amp;quot;,&lt;br /&gt;
        &amp;quot;possibleactions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; ),&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;playCard&amp;quot; =&amp;gt; 32 )&lt;br /&gt;
    ), &lt;br /&gt;
    32 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;nextPlayer&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stNextPlayer&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextPlayer&amp;quot; =&amp;gt; 31, &amp;quot;nextTrick&amp;quot; =&amp;gt; 30, &amp;quot;endHand&amp;quot; =&amp;gt; 40 )&lt;br /&gt;
    ), &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    // End of the hand (scoring, etc...)&lt;br /&gt;
    40 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;endHand&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;game&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stEndHand&amp;quot;,&lt;br /&gt;
        &amp;quot;transitions&amp;quot; =&amp;gt; array( &amp;quot;nextHand&amp;quot; =&amp;gt; 2, &amp;quot;endGame&amp;quot; =&amp;gt; 99 )&lt;br /&gt;
    ),     &lt;br /&gt;
   &lt;br /&gt;
    // Final state.&lt;br /&gt;
    // Please do not modify.&lt;br /&gt;
    99 =&amp;gt; array(&lt;br /&gt;
        &amp;quot;name&amp;quot; =&amp;gt; &amp;quot;gameEnd&amp;quot;,&lt;br /&gt;
        &amp;quot;description&amp;quot; =&amp;gt; clienttranslate(&amp;quot;End of game&amp;quot;),&lt;br /&gt;
        &amp;quot;type&amp;quot; =&amp;gt; &amp;quot;manager&amp;quot;,&lt;br /&gt;
        &amp;quot;action&amp;quot; =&amp;gt; &amp;quot;stGameEnd&amp;quot;,&lt;br /&gt;
        &amp;quot;args&amp;quot; =&amp;gt; &amp;quot;argGameEnd&amp;quot;&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The full details on these fields are in [[Your_game_state_machine:_states.inc.php]].&lt;br /&gt;
&lt;br /&gt;
But basically we have Player states, in which a human player has to perform an &amp;quot;action&amp;quot; by pressing some button in the UI or selecting some game item, which will trigger js handler, which will do an ajax call to the server into API defined&lt;br /&gt;
by .action.php file. All functions in this file are API between client and server and have very simple&lt;br /&gt;
and repetitive structures. In this case there are only two actions player can do - play a card or pass cards to other player. So these 2 functions go into .action.php file, we will only define one now since we have not implemented card passing states yet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function playCard() {&lt;br /&gt;
        self::setAjaxMode();&lt;br /&gt;
        $card_id = self::getArg(&amp;quot;id&amp;quot;, AT_posint, true);&lt;br /&gt;
        $this-&amp;gt;game-&amp;gt;playCard($card_id);&lt;br /&gt;
        self::ajaxResponse();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now to make it run we have to define all the handler functions that we referenced in states, which are - one function for state arguments argGiveCards, 4 functions for robot states (where the game performs some action)&lt;br /&gt;
and 1 function for player actions handling.&lt;br /&gt;
In .game.php, find &#039;Game state arguments&#039; section and paste this in:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function argGiveCards() {&lt;br /&gt;
        return array ();&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This normally passes some parameters to states, but we don&#039;t need anything yet. It&#039;s good to have a placeholder there anyway, so we can fix it later.&lt;br /&gt;
Important: even when it&#039;s a stub, this function must return an array not a scalar.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s do stubs for other functions, find the game state actions section in .game.php file and insert these&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stNewHand() {&lt;br /&gt;
        // Take back all cards (from any location =&amp;gt; null) to deck&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(null, &amp;quot;deck&amp;quot;);&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;shuffle(&#039;deck&#039;);&lt;br /&gt;
        // Deal 13 cards to each players&lt;br /&gt;
        // Create deck, shuffle it and give 13 initial cards&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player ) {&lt;br /&gt;
            $cards = $this-&amp;gt;cards-&amp;gt;pickCards(13, &#039;deck&#039;, $player_id);&lt;br /&gt;
            // Notify player about his cards&lt;br /&gt;
            self::notifyPlayer($player_id, &#039;newHand&#039;, &#039;&#039;, array (&#039;cards&#039; =&amp;gt; $cards ));&lt;br /&gt;
        }&lt;br /&gt;
        self::setGameStateValue(&#039;alreadyPlayedHearts&#039;, 0);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function stNewTrick() {&lt;br /&gt;
        // New trick: active the player who wins the last trick, or the player who own the club-2 card&lt;br /&gt;
        // Reset trick color to 0 (= no color)&lt;br /&gt;
        self::setGameStateInitialValue(&#039;trickColor&#039;, 0);&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function stNextPlayer() {&lt;br /&gt;
        // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
        if ($this-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;cardsontable&#039;) == 4) {&lt;br /&gt;
            // This is the end of the trick&lt;br /&gt;
            // Move all cards to &amp;quot;cardswon&amp;quot; of the given player&lt;br /&gt;
            $best_value_player_id = self::activeNextPlayer(); // TODO figure out winner of trick&lt;br /&gt;
            $this-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
        &lt;br /&gt;
            if ($this-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;hand&#039;) == 0) {&lt;br /&gt;
                // End of the hand&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;endHand&amp;quot;);&lt;br /&gt;
            } else {&lt;br /&gt;
                // End of the trick&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;nextTrick&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            // Standard case (not the end of the trick)&lt;br /&gt;
            // =&amp;gt; just active the next player&lt;br /&gt;
            $player_id = self::activeNextPlayer();&lt;br /&gt;
            self::giveExtraTime($player_id);&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;nextPlayer&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function stEndHand() {&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;nextHand&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Important: All state actions game or player must end with state transition (or thrown exception). Also make sure it&#039;s ONLY one state transition,&lt;br /&gt;
if you accidentally fall through after state transition and do another one it will be a real mess and head scratching for long time.&lt;br /&gt;
&lt;br /&gt;
Now find &#039;player actions&#039; section and paste this code there&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function playCard($card_id) {&lt;br /&gt;
        self::checkAction(&amp;quot;playCard&amp;quot;);&lt;br /&gt;
        $player_id = self::getActivePlayerId();&lt;br /&gt;
        throw new BgaUserException(self::_(&amp;quot;Not implemented: &amp;quot;) . &amp;quot;$player_id plays $card_id&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
We won&#039;t implement it yet but throw an exception which we will see if interaction is working properly&lt;br /&gt;
&lt;br /&gt;
Now the game should start but it would not be any different than before because we have to implement actual interactions.&lt;br /&gt;
It&#039;s good to check if it&#039;s still working though (and if it was running before you have to exit because we changed state machine and normally it will break stuff)&lt;br /&gt;
&lt;br /&gt;
== Client - Server interactions ==&lt;br /&gt;
&lt;br /&gt;
Now to implement things for real we have hook UI actions to ajax calls, and process notifications sent by the server.&lt;br /&gt;
So previously we hooked playCardOnTable right into js handler which caused client animation, in real game its a two&lt;br /&gt;
step operation. When user clicks on game element js client sends an ajax call to server, server processes it and updates database, server sends&lt;br /&gt;
notification in response, client hooks animations to server notification.&lt;br /&gt;
&lt;br /&gt;
So in .js code replace onPlayerHandSelectionChanged with&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        onPlayerHandSelectionChanged : function() {&lt;br /&gt;
            var items = this.playerHand.getSelectedItems();&lt;br /&gt;
&lt;br /&gt;
            if (items.length &amp;gt; 0) {&lt;br /&gt;
                var action = &#039;playCard&#039;;&lt;br /&gt;
                if (this.checkAction(action, true)) {&lt;br /&gt;
                    // Can play a card&lt;br /&gt;
                    var card_id = items[0].id;                    &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;, {&lt;br /&gt;
                        id : card_id,&lt;br /&gt;
                        lock : true&lt;br /&gt;
                    }, this, function(result) {&lt;br /&gt;
                    }, function(is_error) {&lt;br /&gt;
                    });&lt;br /&gt;
&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                } else if (this.checkAction(&#039;giveCards&#039;)) {&lt;br /&gt;
                    // Can give cards =&amp;gt; let the player select some cards&lt;br /&gt;
                } else {&lt;br /&gt;
                    this.playerHand.unselectAll();&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now when you click on card you should get a server response: Not implemented...&lt;br /&gt;
&lt;br /&gt;
Lets implement it, in .game.php&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function playCard($card_id) {&lt;br /&gt;
        self::checkAction(&amp;quot;playCard&amp;quot;);&lt;br /&gt;
        $player_id = self::getActivePlayerId();&lt;br /&gt;
        $this-&amp;gt;cards-&amp;gt;moveCard($card_id, &#039;cardsontable&#039;, $player_id);&lt;br /&gt;
        // XXX check rules here&lt;br /&gt;
        $currentCard = $this-&amp;gt;cards-&amp;gt;getCard($card_id);&lt;br /&gt;
        // And notify&lt;br /&gt;
        self::notifyAllPlayers(&#039;playCard&#039;, clienttranslate(&#039;${player_name} plays ${value_displayed} ${color_displayed}&#039;), array (&lt;br /&gt;
                &#039;i18n&#039; =&amp;gt; array (&#039;color_displayed&#039;,&#039;value_displayed&#039; ),&#039;card_id&#039; =&amp;gt; $card_id,&#039;player_id&#039; =&amp;gt; $player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; self::getActivePlayerName(),&#039;value&#039; =&amp;gt; $currentCard [&#039;type_arg&#039;],&lt;br /&gt;
                &#039;value_displayed&#039; =&amp;gt; $this-&amp;gt;values_label [$currentCard [&#039;type_arg&#039;]],&#039;color&#039; =&amp;gt; $currentCard [&#039;type&#039;],&lt;br /&gt;
                &#039;color_displayed&#039; =&amp;gt; $this-&amp;gt;colors [$currentCard [&#039;type&#039;]] [&#039;name&#039;] ));&lt;br /&gt;
        // Next player&lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&#039;playCard&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We get the card from client, we move it to the table (moveCard is hooked to database directly, its part of deck class),&lt;br /&gt;
we notify all players and we change state. What we are missing here is bunch of checks (rule enforcements), we will add it later.&lt;br /&gt;
&lt;br /&gt;
Interesting part about this notify is that we use i18n array for strings that needs to be translated by client, so&lt;br /&gt;
they are sent as English text in notification, then client has to know which parameters needs translating.&lt;br /&gt;
&lt;br /&gt;
On the client side .js we have to implement a notification handler to do the animation&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        setupNotifications : function() {&lt;br /&gt;
            console.log(&#039;notifications subscriptions setup&#039;);&lt;br /&gt;
&lt;br /&gt;
            dojo.subscribe(&#039;newHand&#039;, this, &amp;quot;notif_newHand&amp;quot;);&lt;br /&gt;
            dojo.subscribe(&#039;playCard&#039;, this, &amp;quot;notif_playCard&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        notif_newHand : function(notif) {&lt;br /&gt;
            // We received a new full hand of 13 cards.&lt;br /&gt;
            this.playerHand.removeAll();&lt;br /&gt;
&lt;br /&gt;
            for ( var i in notif.args.cards) {&lt;br /&gt;
                var card = notif.args.cards[i];&lt;br /&gt;
                var color = card.type;&lt;br /&gt;
                var value = card.type_arg;&lt;br /&gt;
                this.playerHand.addToStockWithId(this.getCardUniqueId(color, value), card.id);&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&lt;br /&gt;
        notif_playCard : function(notif) {&lt;br /&gt;
            // Play a card on the table&lt;br /&gt;
            this.playCardOnTable(notif.args.player_id, notif.args.color, notif.args.value, notif.args.card_id);&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now it actually works through the server when you click on card - the move is recorded. If you test it now you will notice&lt;br /&gt;
after trick is done all cards remains on the table, but if you press F5 they would disappear, this is because&lt;br /&gt;
we updated database to pick-up the cards but did not send notification about it, so we need to send notification about it&lt;br /&gt;
and have a handler for it&lt;br /&gt;
&lt;br /&gt;
So in .game.php file add notification in stNextPlayer function after moveAllCardsInLocation call:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            // Notify&lt;br /&gt;
            // Note: we use 2 notifications here in order we can pause the display during the first notification&lt;br /&gt;
            //  before we move all cards to the winner (during the second)&lt;br /&gt;
            $players = self::loadPlayersBasicInfos();&lt;br /&gt;
            self::notifyAllPlayers( &#039;trickWin&#039;, clienttranslate(&#039;${player_name} wins the trick&#039;), array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $best_value_player_id,&lt;br /&gt;
                &#039;player_name&#039; =&amp;gt; $players[ $best_value_player_id ][&#039;player_name&#039;]&lt;br /&gt;
            ) );            &lt;br /&gt;
            self::notifyAllPlayers( &#039;giveAllCardsToPlayer&#039;,&#039;&#039;, array(&lt;br /&gt;
                &#039;player_id&#039; =&amp;gt; $best_value_player_id&lt;br /&gt;
            ) );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And in .js file add 2 more notification handlers.&lt;br /&gt;
&lt;br /&gt;
This is to subscribe in setupNotifications function&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
            dojo.subscribe( &#039;trickWin&#039;, this, &amp;quot;notif_trickWin&amp;quot; );&lt;br /&gt;
            this.notifqueue.setSynchronous( &#039;trickWin&#039;, 1000 );&lt;br /&gt;
            dojo.subscribe( &#039;giveAllCardsToPlayer&#039;, this, &amp;quot;notif_giveAllCardsToPlayer&amp;quot; );&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And these are handlers&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        notif_trickWin : function(notif) {&lt;br /&gt;
            // We do nothing here (just wait in order players can view the 4 cards played before they&#039;re gone.&lt;br /&gt;
        },&lt;br /&gt;
        notif_giveAllCardsToPlayer : function(notif) {&lt;br /&gt;
            // Move all cards on table to given table, then destroy them&lt;br /&gt;
            var winner_id = notif.args.player_id;&lt;br /&gt;
            for ( var player_id in this.gamedatas.players) {&lt;br /&gt;
                var anim = this.slideToObject(&#039;cardontable_&#039; + player_id, &#039;overall_player_board_&#039; + winner_id);&lt;br /&gt;
                dojo.connect(anim, &#039;onEnd&#039;, function(node) {&lt;br /&gt;
                    dojo.destroy(node);&lt;br /&gt;
                });&lt;br /&gt;
                anim.play();&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So &#039;trickWin&#039; notification does not do much except it will delay the processing of next notification by 1 second (1000 ms)&lt;br /&gt;
and it will log the message (that happens independently of what handler does).&lt;br /&gt;
&amp;lt;i&amp;gt;Note: if on the other hand you don&#039;t want to log but want to do something else, send an empty message&amp;lt;/i&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now after the trick you see all cards move towards the &amp;quot;player&#039;s stash&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Scoring and End of game handling ==&lt;br /&gt;
&lt;br /&gt;
Now we should calculate scoring and for that we need to actually track who wins the trick.&lt;br /&gt;
Trick is won by the player with highest card (no trump). We just need to remember what is trick suite.&lt;br /&gt;
For which we will use state variable &#039;trickColor&#039; which we already conveniently created.&lt;br /&gt;
&lt;br /&gt;
In .game.php file find playCard function and add this before notify functions&lt;br /&gt;
        $currentTrickColor = self::getGameStateValue( &#039;trickColor&#039; ) ;&lt;br /&gt;
        if( $currentTrickColor == 0 )&lt;br /&gt;
            self::setGameStateValue( &#039;trickColor&#039;, $currentCard[&#039;type&#039;] );&lt;br /&gt;
&lt;br /&gt;
This will make sure we remember first suit being played, now to use it modify stNextPlayer function to fix our TODO comment&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stNextPlayer() {&lt;br /&gt;
        // Active next player OR end the trick and go to the next trick OR end the hand&lt;br /&gt;
        if ($this-&amp;gt;cards-&amp;gt;countCardInLocation(&#039;cardsontable&#039;) == 4) {&lt;br /&gt;
            // This is the end of the trick&lt;br /&gt;
            $cards_on_table = $this-&amp;gt;cards-&amp;gt;getCardsInLocation(&#039;cardsontable&#039;);&lt;br /&gt;
            $best_value = 0;&lt;br /&gt;
            $best_value_player_id = null;&lt;br /&gt;
            $currentTrickColor = self::getGameStateValue(&#039;trickColor&#039;);&lt;br /&gt;
            foreach ( $cards_on_table as $card ) {&lt;br /&gt;
                // Note: type = card color&lt;br /&gt;
                if ($card [&#039;type&#039;] == $currentTrickColor) {&lt;br /&gt;
                    if ($best_value_player_id === null || $card [&#039;type_arg&#039;] &amp;gt; $best_value) {&lt;br /&gt;
                        $best_value_player_id = $card [&#039;location_arg&#039;]; // Note: location_arg = player who played this card on table&lt;br /&gt;
                        $best_value = $card [&#039;type_arg&#039;]; // Note: type_arg = value of the card&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            // Active this player =&amp;gt; he&#039;s the one who starts the next trick&lt;br /&gt;
            $this-&amp;gt;gamestate-&amp;gt;changeActivePlayer( $best_value_player_id );&lt;br /&gt;
            &lt;br /&gt;
            // Move all cards to &amp;quot;cardswon&amp;quot; of the given player&lt;br /&gt;
            $this-&amp;gt;cards-&amp;gt;moveAllCardsInLocation(&#039;cardsontable&#039;, &#039;cardswon&#039;, null, $best_value_player_id);&lt;br /&gt;
        &lt;br /&gt;
            // Notify&lt;br /&gt;
            // ... same code here as before&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The scoring rule in the studio example code is huge multi-page function, for this tutorial we will make simplier.&lt;br /&gt;
Lets score -1 point per heart and call it a day. And game will end when somebody goes -100 or below.&lt;br /&gt;
&lt;br /&gt;
As UI goes for scoring, the main thing to update is the scoring on the mini boards represented by stars, also&lt;br /&gt;
we want to show that in the log. &lt;br /&gt;
In addition scoring can be shown in [[Game_interface_logic:_yourgamename.js#Scoring_dialogs|Scoring Dialog]] using tableWindow notification, but it is a tutorial on its own and you can do it as homework (it is part of original heart game).&lt;br /&gt;
&lt;br /&gt;
In .js file we need to add one more subscription and notification handler:&lt;br /&gt;
            dojo.subscribe( &#039;newScores&#039;, this, &amp;quot;notif_newScores&amp;quot; );&lt;br /&gt;
in setupNotifications&lt;br /&gt;
&lt;br /&gt;
and &lt;br /&gt;
        notif_newScores : function(notif) {&lt;br /&gt;
            // Update players&#039; scores&lt;br /&gt;
            for ( var player_id in notif.args.newScores) {&lt;br /&gt;
                this.scoreCtrl[player_id].toValue(notif.args.newScores[player_id]);&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
somewhere after. this.scoreCtrl is pre-existing object that shows the scoring and this function will update score values per player from notification argument&lt;br /&gt;
&lt;br /&gt;
so in .game.php our stEndHand function will look like&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    function stEndHand() {&lt;br /&gt;
            // Count and score points, then end the game or go to the next hand.&lt;br /&gt;
        $players = self::loadPlayersBasicInfos();&lt;br /&gt;
        // Gets all &amp;quot;hearts&amp;quot; + queen of spades&lt;br /&gt;
&lt;br /&gt;
        $player_to_points = array ();&lt;br /&gt;
        foreach ( $players as $player_id =&amp;gt; $player ) {&lt;br /&gt;
            $player_to_points [$player_id] = 0;&lt;br /&gt;
        }&lt;br /&gt;
        $cards = $this-&amp;gt;cards-&amp;gt;getCardsInLocation(&amp;quot;cardswon&amp;quot;);&lt;br /&gt;
        foreach ( $cards as $card ) {&lt;br /&gt;
            $player_id = $card [&#039;location_arg&#039;];&lt;br /&gt;
            // Note: 2 = heart&lt;br /&gt;
            if ($card [&#039;type&#039;] == 2) {&lt;br /&gt;
                $player_to_points [$player_id] ++;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        // Apply scores to player&lt;br /&gt;
        foreach ( $player_to_points as $player_id =&amp;gt; $points ) {&lt;br /&gt;
            if ($points != 0) {&lt;br /&gt;
                $sql = &amp;quot;UPDATE player SET player_score=player_score-$points  WHERE player_id=&#039;$player_id&#039;&amp;quot;;&lt;br /&gt;
                self::DbQuery($sql);&lt;br /&gt;
                $heart_number = $player_to_points [$player_id];&lt;br /&gt;
                self::notifyAllPlayers(&amp;quot;points&amp;quot;, clienttranslate(&#039;${player_name} gets ${nbr} hearts and looses ${nbr} points&#039;), array (&lt;br /&gt;
                        &#039;player_id&#039; =&amp;gt; $player_id,&#039;player_name&#039; =&amp;gt; $players [$player_id] [&#039;player_name&#039;],&lt;br /&gt;
                        &#039;nbr&#039; =&amp;gt; $heart_number ));&lt;br /&gt;
            } else {&lt;br /&gt;
                // No point lost (just notify)&lt;br /&gt;
                self::notifyAllPlayers(&amp;quot;points&amp;quot;, clienttranslate(&#039;${player_name} did not get any hearts&#039;), array (&lt;br /&gt;
                        &#039;player_id&#039; =&amp;gt; $player_id,&#039;player_name&#039; =&amp;gt; $players [$player_id] [&#039;player_name&#039;] ));&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        $newScores = self::getCollectionFromDb(&amp;quot;SELECT player_id, player_score FROM player&amp;quot;, true );&lt;br /&gt;
        self::notifyAllPlayers( &amp;quot;newScores&amp;quot;, &#039;&#039;, array( &#039;newScores&#039; =&amp;gt; $newScores ) );&lt;br /&gt;
&lt;br /&gt;
        ///// Test if this is the end of the game&lt;br /&gt;
        foreach ( $newScores as $player_id =&amp;gt; $score ) {&lt;br /&gt;
            if ($score &amp;lt;= -100) {&lt;br /&gt;
                // Trigger the end of the game !&lt;br /&gt;
                $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;endGame&amp;quot;);&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
        $this-&amp;gt;gamestate-&amp;gt;nextState(&amp;quot;nextHand&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
So it should more less work now, including end of game condition. Try to play it!&lt;br /&gt;
&lt;br /&gt;
== Additional stuff ==&lt;br /&gt;
&lt;br /&gt;
The following things were not implemented and can add them yourself by looking at the code of original hearts game:&lt;br /&gt;
&lt;br /&gt;
* Remove debug code from setupNewGame to deal cards, cards are now dealt in stNewHand state handler&lt;br /&gt;
* Rule checking and rule enforcements in playCard function&lt;br /&gt;
* Start scoring with 100 points each and end when &amp;lt;= 0&lt;br /&gt;
* Fix scoring rules with Q of spades and 26 point reverse scoring&lt;br /&gt;
* First player one with 2 club&lt;br /&gt;
* Add progress handling&lt;br /&gt;
* Add statistics&lt;br /&gt;
* Add card exchange states&lt;br /&gt;
* Add game option to start with 75 points instead of 100&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Studio]]&lt;/div&gt;</summary>
		<author><name>Xmakina</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_eminentdomain&amp;diff=17791</id>
		<title>Tips eminentdomain</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_eminentdomain&amp;diff=17791"/>
		<updated>2023-08-14T18:50:31Z</updated>

		<summary type="html">&lt;p&gt;Xmakina: /* Tips from the Pros */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Base Game ==&lt;br /&gt;
Take the time to learn the Base Game before you add in the Escalation expansion.&lt;br /&gt;
&lt;br /&gt;
Pick either Warfare of Colonise for taking control of planets, don&#039;t try to use both.&lt;br /&gt;
&lt;br /&gt;
Use the Research Action to remove the cards you don&#039;t plan on using. If you ever discard a card at the end of your round, ask yourself if you even want it in your deck.&lt;br /&gt;
&lt;br /&gt;
Survey early to find planets which complement each other.&lt;br /&gt;
&lt;br /&gt;
Try to get 3 planets of the same kind and push for the level 3 technology (7 research icons). These technologies give you game breaking abilities.&lt;br /&gt;
&lt;br /&gt;
Remember that the planets don&#039;t have the level 1 technology that should match with them (Fertile does not have Improved Colonise, Advanced does not have Advanced Research and Metallic does not have Advanced Warfare)&lt;br /&gt;
&lt;br /&gt;
Planets with a Colony symbol are a permanent discount to all colonisation costs instead of an extra icon when the role is chosen.&lt;br /&gt;
&lt;br /&gt;
Planets which increase hand size will give you a lot more options each turn.&lt;br /&gt;
&lt;br /&gt;
Keep an eye on how many cards are left in each role; if you&#039;re ahead consider taking a less efficient role to finish the game faster.&lt;br /&gt;
&lt;br /&gt;
== Escalation Expansion ==&lt;br /&gt;
Annex can really mess with colonisers.&lt;br /&gt;
&lt;br /&gt;
You can buy research with fighters, destroyers and battlecruisers. If you Warfare, you can get game end tech without needing to lead Research roles.&lt;br /&gt;
&lt;br /&gt;
Diverse Planets are now an option, especially with Oversight Committee consider pushing for one-of-each&lt;br /&gt;
&lt;br /&gt;
== Tips from the Pros ==&lt;br /&gt;
&lt;br /&gt;
=== SMoslim ===&lt;br /&gt;
This is a Victory Point game the main source of VP&#039;s are your roles. You are allowed only one necessary 0 VP role, the one when you get your first tech. Next you should always get points in your roles. The main method to do that is to go for survey each time you cannot get points otherwise, especially in the beginning. A lot of beginners waist time in getting multiple level 1 tech that is useless because it is not worth the role you pay for them. You can however get them if you are following, not leading.&lt;br /&gt;
&lt;br /&gt;
A tip I learned from analysing the top player is at the very beginning of the game; if you have first turn and you choose the Survey role, do not use any of your Survey cards. Keep them so you can use them to follow your opponent&#039;s Survey role.&lt;br /&gt;
&lt;br /&gt;
If you get an Advanced Planet with a Research symbol early, consider skipping getting a Level 1 tech and get your fourth Research symbol from exchanging Politics for Research. This should be especially true if the Advanced world only needs 3 colonies to Settle.&lt;br /&gt;
&lt;br /&gt;
In Escalation, Warfare is a big risk/big reward strategy. Most top players avoid it because of the risk. Skilled players can mix Warfare and Colonize mid game, but a player needs very specific circumstances and skills to make this work, so I do no advise this strategy for beginners. I would only go for Warfare in Escalation if I start with a metallic planet, and I Survey&#039;d a metallic planet that only needs 4 fighters to attack, and preferably with a warfare symbol.&lt;br /&gt;
&lt;br /&gt;
Not all tech cards are created equal, some of them are really powerful and should always be picked if they&#039;re available. Pay attention to what the top players choose. As your experience grows, and you can start paying attention to what your opponent is going for, you may get a less optimal technology just to prevent your opponent from getting it, since it fits perfectly into their strategy.&lt;br /&gt;
&lt;br /&gt;
The Eminent Domain community on BGA is small, so it might be subject to &amp;quot;group think&amp;quot;. Once you have became a strong player, you need to start experimenting with different strategies. Pay attention to what other players do that is unusual. Even when I thought I was an expert, I learned a lot from weaker players that were using unusual strategies.&lt;br /&gt;
&lt;br /&gt;
I see a lot of players getting stuck in low levels even though they played a lot of games. The main reason, I believe, is because they never change their playing style and always do what they are used to. I am now a master, and I still think about a few strategies in the opening phases of the game that I figured weren&#039;t that optimal. So, you need to always keep evolving. I also asked some top players about the different tech cards and their strategies, however they never used them. That&#039;s a big mistake since it limits your growth, and although those players are great, they hit the limit of the potential of their limited strategies.&lt;br /&gt;
&lt;br /&gt;
The main reason is one of two; they play on auto mode so they don&#039;t get out of their confort zone. Or, they don&#039;t want to risk experimenting because losing comes at a great punishment, which I, personally, understand. The main solution to this is to play lots of Scenario games since they force new strategies on you while you are still a Good or Strong player since losing isn&#039;t that big of a deal that those levels. Now that I&#039;m at a master ranking, losing any game absolutely destroys my ELO rating.&lt;br /&gt;
&lt;br /&gt;
If you are really serious about the game, you need to start analysing high level player games and critique their decisions and compare them to yours. However, don&#039;t follow these games blindly, high level players aren&#039;t perfect, and also they don&#039;t always tale the game super seriously, and sometimes make a worse decision because it us more fun.&lt;br /&gt;
&lt;br /&gt;
One of the most successful strategies that I use now is the Heavy Survey/Remove Cards opening strategy. I use this strategy because during a game, sometimes you get the perfect colonize hand but no Face Down planets, or more colonize cards than needed for the planets you have, so you are forced to play a suboptimal role. You never have this problem if you have an abundance of Face Down planets, so get a lot of planets in the early game so you can always have optimal turns and a lot of options to where you want to take the game according to your circumstance. When I first discovered this strategy, I quickly found it has a huge flaw, it fills your deck with Survey cards that are, generally, useless in the mid to late game. So, the Heavy Remove cards from the game strategy is needed as well. You need to keep removing those Survey cards from your deck, using the Research action, to keep your deck compact.&lt;br /&gt;
&lt;br /&gt;
Another strategy that comes with this one. Is that you try to get at least one follow. Either by following Survey or Colonise. To that you need to keep your hand prepared for those. Following is main source of extra points in high level games. To have the ability to follow you need to keep cheking your opponents discard pile so you can predict their next move. To do that you might need, from time to time, to use the wait option before the clean up phase to see if your opponents follows you. Just don&#039;t be the guy that use it all the time, especially in turn based games. I encountered a few of those players and it just slows down the game a lot for no reason.&lt;br /&gt;
&lt;br /&gt;
Deck balance: a lot of rookies and some times top players go for heavy warfare or heavy survey without paying attention to their deck balance. Although it seems perfect at the start, they later start getting a lot of cards they don&#039;t need, or take roles they dont want to take, and it only gets worse and removing cards frome your deck mid game is really suboptimal. So you need to avoid it. Unless you are using Oversight Commitee tech card, which is not as bad. Your deck needs to always be balanced so don&#039;t mess it up at the opening stage.&lt;br /&gt;
&lt;br /&gt;
Discard pile: as previously said, pay attention to your opponents discard pile to predict if he is going to follow you or what is he going to play next turn.but another very important discard pile is the planets discard pile. When you became a strong player you should know all the planets of the game. so use the discard pile to predict what you might get. Although you cannot see the cards in the planets deck you can have perfect information just by looking at cards in colonies and the discard pile. Some times you give up on your perfect role just to play or follow a surveil role to get the top Planet because it is woth it for you or too good to let your opponent get it.&lt;br /&gt;
&lt;br /&gt;
Bad tech cards are extremely powerful in some strategies: if you are going for a strategy double down on it in the tech cards have your entire deck go for it instead of having a diversified strat. It might seem simple as a tip but no very few players go for this because they are swayed buy the shiny good tech card. Because they are used to choosing it. Especially that this adviced cannot always be used to the fullest since it is a circumstances specific. The the real tip hiding behind this obvious one is always pay attention to your go-to moves yes they are the best in 90% of the times but not in 100% of them and this is way a lot of players never played some tech cards because they missed the opportunity to use them when the rare circumstance to use them optimally comes up.&lt;br /&gt;
&lt;br /&gt;
Your action: most average to strong players don&#039;t understand how important this one is because roles are the source of points and the optimal action is most of the time obvious. But what they dont realise is that the action should be prepared. In the previous turn so you are not forced to an action.&lt;br /&gt;
&lt;br /&gt;
One of the wosrt actions is the draw action it simply give you 0 point. It is only realy useful when you are in a race against your opponent to get a tech card first. Or to have a realy big role. But I a realy big one not to complete a normal one. Because when used to accomplish a big role it means&lt;br /&gt;
&lt;br /&gt;
it made you play 2 roles in 1and that is not a common situation. By the way getting a lvl 3 tech card isn&#039;t a big role that is just a normal role. I mean by big a 1.5 to 2 roles in one. In other terms wining points. Another wast of an action is the remove cards from hand one once you are no longer in the opening phase.&lt;br /&gt;
&lt;br /&gt;
So you only have as a good action the suttel/attack or a tech that doesn&#039;t what a role doses or win points. Otherwise you are wasting an action.&lt;br /&gt;
&lt;br /&gt;
This tip however is top teir one don&#039;t pay attention to it if you are an average player because it needs high lvl hand management. Otherwise your action is foced any way.&lt;br /&gt;
&lt;br /&gt;
Deck cycle:&lt;br /&gt;
&lt;br /&gt;
Much more tips to come this just the generalities. I&#039;m tired now. If you are a native English speaker you might need to rephrase an reorganize most of this. If you find a tip not clear or if you don&#039;t agree with it. Tell me so I clarify or have a discussion so we converge or agree to disagree       &lt;/div&gt;</summary>
		<author><name>Xmakina</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_eminentdomain&amp;diff=17044</id>
		<title>Tips eminentdomain</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_eminentdomain&amp;diff=17044"/>
		<updated>2023-05-30T18:53:09Z</updated>

		<summary type="html">&lt;p&gt;Xmakina: Added tips from SMoslim&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Base Game ==&lt;br /&gt;
Take the time to learn the Base Game before you add in the Escalation expansion.&lt;br /&gt;
&lt;br /&gt;
Pick either Warfare of Colonise for taking control of planets, don&#039;t try to use both.&lt;br /&gt;
&lt;br /&gt;
Use the Research Action to remove the cards you don&#039;t plan on using. If you ever discard a card at the end of your round, ask yourself if you even want it in your deck.&lt;br /&gt;
&lt;br /&gt;
Survey early to find planets which complement each other.&lt;br /&gt;
&lt;br /&gt;
Try to get 3 planets of the same kind and push for the level 3 technology (7 research icons). These technologies give you game breaking abilities.&lt;br /&gt;
&lt;br /&gt;
Remember that the planets don&#039;t have the level 1 technology that should match with them (Fertile does not have Improved Colonise, Advanced does not have Advanced Research and Metallic does not have Advanced Warfare)&lt;br /&gt;
&lt;br /&gt;
Planets with a Colony symbol are a permanent discount to all colonisation costs instead of an extra icon when the role is chosen.&lt;br /&gt;
&lt;br /&gt;
Planets which increase hand size will give you a lot more options each turn.&lt;br /&gt;
&lt;br /&gt;
Keep an eye on how many cards are left in each role; if you&#039;re ahead consider taking a less efficient role to finish the game faster.&lt;br /&gt;
&lt;br /&gt;
== Escalation Expansion ==&lt;br /&gt;
Annex can really mess with colonisers.&lt;br /&gt;
&lt;br /&gt;
You can buy research with fighters, destroyers and battlecruisers. If you Warfare, you can get game end tech without needing to lead Research roles.&lt;br /&gt;
&lt;br /&gt;
Diverse Planets are now an option, especially with Oversight Committee consider pushing for one-of-each&lt;br /&gt;
&lt;br /&gt;
== Tips from the Pros ==&lt;br /&gt;
&lt;br /&gt;
=== SMoslim ===&lt;br /&gt;
This is a Victory Point game the main source of VP&#039;s are your roles. You are allowed only one necessary 0 VP role, the one when you get your first tech. Next you should always get points in your roles. The main method to do that is to go for survey each time you cannot get points otherwise, especially in the beginning. A lot of beginners waist time in getting multiple level 1 tech that is useless because it is not worth the role you pay for them. You can however get them if you are following, not leading.&lt;br /&gt;
&lt;br /&gt;
A tip I learned from analysing the top player is at the very beginning of the game; if you have first turn and you choose the Survey role, do not use any of your Survey cards. Keep them so you can use them to follow your opponent&#039;s Survey role.&lt;br /&gt;
&lt;br /&gt;
If you get an Advanced Planet with a Research symbol early, consider skipping getting a Level 1 tech and get your fourth Research symbol from exchanging Politics for Research. This should be especially true if the Advanced world only needs 3 colonies to Settle.&lt;br /&gt;
&lt;br /&gt;
In Escalation, Warfare is a big risk/big reward strategy. Most top players avoid it because of the risk. Skilled players can mix Warfare and Colonize mid game, but a player needs very specific circumstances and skills to make this work, so I do no advise this strategy for beginners. I would only go for Warfare in Escalation if I start with a metallic planet, and I Survey&#039;d a metallic planet that only needs 4 fighters to attack, and preferably with a warfare symbol.&lt;/div&gt;</summary>
		<author><name>Xmakina</name></author>
	</entry>
	<entry>
		<id>https://en.doc.boardgamearena.com/index.php?title=Tips_eminentdomain&amp;diff=17041</id>
		<title>Tips eminentdomain</title>
		<link rel="alternate" type="text/html" href="https://en.doc.boardgamearena.com/index.php?title=Tips_eminentdomain&amp;diff=17041"/>
		<updated>2023-05-30T11:02:09Z</updated>

		<summary type="html">&lt;p&gt;Xmakina: Added some hints&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Base Game ==&lt;br /&gt;
Take the time to learn the Base Game before you add in the Escalation expansion.&lt;br /&gt;
&lt;br /&gt;
Pick either Warfare of Colonise for taking control of planets, don&#039;t try to use both.&lt;br /&gt;
&lt;br /&gt;
Use the Research Action to remove the cards you don&#039;t plan on using. If you ever discard a card at the end of your round, ask yourself if you even want it in your deck.&lt;br /&gt;
&lt;br /&gt;
Survey early to find planets which complement each other.&lt;br /&gt;
&lt;br /&gt;
Try to get 3 planets of the same kind and push for the level 3 technology (7 research icons). These technologies give you game breaking abilities.&lt;br /&gt;
&lt;br /&gt;
Remember that the planets don&#039;t have the level 1 technology that should match with them (Fertile does not have Improved Colonise, Advanced does not have Advanced Research and Metallic does not have Advanced Warfare)&lt;br /&gt;
&lt;br /&gt;
Planets with a Colony symbol are a permanent discount to all colonisation costs instead of an extra icon when the role is chosen.&lt;br /&gt;
&lt;br /&gt;
Planets which increase hand size will give you a lot more options each turn.&lt;br /&gt;
&lt;br /&gt;
Keep an eye on how many cards are left in each role; if you&#039;re ahead consider taking a less efficient role to finish the game faster.&lt;br /&gt;
&lt;br /&gt;
== Escalation Expansion ==&lt;br /&gt;
Annex can really mess with colonisers.&lt;br /&gt;
&lt;br /&gt;
You can buy research with fighters, destroyers and battlecruisers. If you Warfare, you can get game end tech without needing to lead Research roles.&lt;br /&gt;
&lt;br /&gt;
Diverse Planets are now an option, especially with Oversight Committee consider pushing for one-of-each&lt;/div&gt;</summary>
		<author><name>Xmakina</name></author>
	</entry>
</feed>